root/trunk/nt/addsection.c

Revision 4220, 17.1 kB (checked in by miyoshi, 6 months ago)

Sync up with Emacs22.2.

  • Property svn:eol-style set to native
Line 
1 /* Add an uninitialized data section to an executable.
2    Copyright (C) 1999, 2001, 2002, 2003, 2004, 2005,
3       2006, 2007, 2008  Free Software Foundation, Inc.
4
5 This file is part of GNU Emacs.
6
7 GNU Emacs is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3, or (at your option)
10 any later version.
11
12 GNU Emacs is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GNU Emacs; see the file COPYING.  If not, write to
19 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 Boston, MA 02110-1301, USA.
21
22    Andrew Innes <andrewi@harlequin.co.uk>       04-Jan-1999
23      based on code from unexw32.c
24 */
25
26 #include <stdlib.h>
27 #include <stdio.h>
28 #include <fcntl.h>
29 #include <time.h>
30 #ifdef __GNUC__
31 #define _ANONYMOUS_UNION
32 #define _ANONYMOUS_STRUCT
33 #endif
34 #include <windows.h>
35
36 /* Include relevant definitions from IMAGEHLP.H, which can be found
37    in \\win32sdk\mstools\samples\image\include\imagehlp.h. */
38
39 PIMAGE_NT_HEADERS
40 (__stdcall * pfnCheckSumMappedFile) (LPVOID BaseAddress,
41                                     DWORD FileLength,
42                                     LPDWORD HeaderSum,
43                                     LPDWORD CheckSum);
44
45 #undef min
46 #undef max
47 #define min(x, y) (((x) < (y)) ? (x) : (y))
48 #define max(x, y) (((x) > (y)) ? (x) : (y))
49
50
51 /* File handling.  */
52
53 typedef struct file_data {
54     char          *name;
55     unsigned long  size;
56     HANDLE         file;
57     HANDLE         file_mapping;
58     unsigned char *file_base;
59 } file_data;
60
61 int
62 open_input_file (file_data *p_file, char *filename)
63 {
64   HANDLE file;
65   HANDLE file_mapping;
66   void  *file_base;
67   unsigned long size, upper_size;
68
69   file = CreateFile (filename, GENERIC_READ, FILE_SHARE_READ, NULL,
70                      OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
71   if (file == INVALID_HANDLE_VALUE)
72     return FALSE;
73
74   size = GetFileSize (file, &upper_size);
75   file_mapping = CreateFileMapping (file, NULL, PAGE_READONLY,
76                                     0, size, NULL);
77   if (!file_mapping)
78     return FALSE;
79
80   file_base = MapViewOfFile (file_mapping, FILE_MAP_READ, 0, 0, size);
81   if (file_base == 0)
82     return FALSE;
83
84   p_file->name = filename;
85   p_file->size = size;
86   p_file->file = file;
87   p_file->file_mapping = file_mapping;
88   p_file->file_base = file_base;
89
90   return TRUE;
91 }
92
93 int
94 open_output_file (file_data *p_file, char *filename, unsigned long size)
95 {
96   HANDLE file;
97   HANDLE file_mapping;
98   void  *file_base;
99
100   file = CreateFile (filename, GENERIC_READ | GENERIC_WRITE, 0, NULL,
101                      CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
102   if (file == INVALID_HANDLE_VALUE)
103     return FALSE;
104
105   file_mapping = CreateFileMapping (file, NULL, PAGE_READWRITE,
106                                     0, size, NULL);
107   if (!file_mapping)
108     return FALSE;
109
110   file_base = MapViewOfFile (file_mapping, FILE_MAP_WRITE, 0, 0, size);
111   if (file_base == 0)
112     return FALSE;
113
114   p_file->name = filename;
115   p_file->size = size;
116   p_file->file = file;
117   p_file->file_mapping = file_mapping;
118   p_file->file_base = file_base;
119
120   return TRUE;
121 }
122
123 /* Close the system structures associated with the given file.  */
124 void
125 close_file_data (file_data *p_file)
126 {
127   UnmapViewOfFile (p_file->file_base);
128   CloseHandle (p_file->file_mapping);
129   /* For the case of output files, set final size.  */
130   SetFilePointer (p_file->file, p_file->size, NULL, FILE_BEGIN);
131   SetEndOfFile (p_file->file);
132   CloseHandle (p_file->file);
133 }
134
135
136 /* Routines to manipulate NT executable file sections.  */
137
138 unsigned long
139 get_unrounded_section_size (PIMAGE_SECTION_HEADER p_section)
140 {
141   /* The true section size, before rounding, for an initialized data or
142      code section.  (Supposedly some linkers swap the meaning of these
143      two values.)  */
144   return min (p_section->SizeOfRawData,
145               p_section->Misc.VirtualSize);
146 }
147
148 /* Return pointer to section header for named section. */
149 IMAGE_SECTION_HEADER *
150 find_section (char * name, IMAGE_NT_HEADERS * nt_header)
151 {
152   PIMAGE_SECTION_HEADER section;
153   int i;
154
155   section = IMAGE_FIRST_SECTION (nt_header);
156
157   for (i = 0; i < nt_header->FileHeader.NumberOfSections; i++)
158     {
159       if (strcmp (section->Name, name) == 0)
160         return section;
161       section++;
162     }
163   return NULL;
164 }
165
166 /* Return pointer to section header for section containing the given
167    relative virtual address. */
168 IMAGE_SECTION_HEADER *
169 rva_to_section (DWORD rva, IMAGE_NT_HEADERS * nt_header)
170 {
171   PIMAGE_SECTION_HEADER section;
172   int i;
173
174   section = IMAGE_FIRST_SECTION (nt_header);
175
176   for (i = 0; i < nt_header->FileHeader.NumberOfSections; i++)
177     {
178       /* Some linkers (eg. the NT SDK linker I believe) swapped the
179          meaning of these two values - or rather, they ignored
180          VirtualSize entirely and always set it to zero.  This affects
181          some very old exes (eg. gzip dated Dec 1993).  Since
182          w32_executable_type relies on this function to work reliably,
183          we need to cope with this.  */
184       DWORD real_size = max (section->SizeOfRawData,
185                              section->Misc.VirtualSize);
186       if (rva >= section->VirtualAddress
187           && rva < section->VirtualAddress + real_size)
188         return section;
189       section++;
190     }
191   return NULL;
192 }
193
194 /* Return pointer to section header for section containing the given
195    offset in its raw data area. */
196 IMAGE_SECTION_HEADER *
197 offset_to_section (DWORD offset, IMAGE_NT_HEADERS * nt_header)
198 {
199   PIMAGE_SECTION_HEADER section;
200   int i;
201
202   section = IMAGE_FIRST_SECTION (nt_header);
203
204   for (i = 0; i < nt_header->FileHeader.NumberOfSections; i++)
205     {
206       if (offset >= section->PointerToRawData
207           && offset < section->PointerToRawData + section->SizeOfRawData)
208         return section;
209       section++;
210     }
211   return NULL;
212 }
213
214 /* Return offset to an object in dst, given offset in src.  We assume
215    there is at least one section in both src and dst images, and that
216    the some sections may have been added to dst (after sections in src).  */
217 static DWORD
218 relocate_offset (DWORD offset,
219                  IMAGE_NT_HEADERS * src_nt_header,
220                  IMAGE_NT_HEADERS * dst_nt_header)
221 {
222   PIMAGE_SECTION_HEADER src_section = IMAGE_FIRST_SECTION (src_nt_header);
223   PIMAGE_SECTION_HEADER dst_section = IMAGE_FIRST_SECTION (dst_nt_header);
224   int i = 0;
225
226   while (offset >= src_section->PointerToRawData)
227     {
228       if (offset < src_section->PointerToRawData + src_section->SizeOfRawData)
229         break;
230       i++;
231       if (i == src_nt_header->FileHeader.NumberOfSections)
232         {
233           /* Handle offsets after the last section.  */
234           dst_section = IMAGE_FIRST_SECTION (dst_nt_header);
235           dst_section += dst_nt_header->FileHeader.NumberOfSections - 1;
236           while (dst_section->PointerToRawData == 0)
237             dst_section--;
238           while (src_section->PointerToRawData == 0)
239             src_section--;
240           return offset
241             + (dst_section->PointerToRawData + dst_section->SizeOfRawData)
242             - (src_section->PointerToRawData + src_section->SizeOfRawData);
243         }
244       src_section++;
245       dst_section++;
246     }
247   return offset +
248     (dst_section->PointerToRawData - src_section->PointerToRawData);
249 }
250
251 #define OFFSET_TO_RVA(offset, section) \
252           (section->VirtualAddress + ((DWORD)(offset) - section->PointerToRawData))
253
254 #define RVA_TO_OFFSET(rva, section) \
255           (section->PointerToRawData + ((DWORD)(rva) - section->VirtualAddress))
256
257 #define RVA_TO_SECTION_OFFSET(rva, section) \
258           ((DWORD)(rva) - section->VirtualAddress)
259
260 /* Convert address in executing image to RVA.  */
261 #define PTR_TO_RVA(ptr) ((DWORD)(ptr) - (DWORD) GetModuleHandle (NULL))
262
263 #define PTR_TO_OFFSET(ptr, pfile_data) \
264           ((unsigned char *)(ptr) - (pfile_data)->file_base)
265
266 #define OFFSET_TO_PTR(offset, pfile_data) \
267           ((pfile_data)->file_base + (DWORD)(offset))
268
269 #define ROUND_UP(p, align)   (((DWORD)(p) + (align)-1) & ~((align)-1))
270 #define ROUND_DOWN(p, align) ((DWORD)(p) & ~((align)-1))
271
272
273 static void
274 copy_executable_and_add_section (file_data *p_infile,
275                                  file_data *p_outfile,
276                                  char *new_section_name,
277                                  DWORD new_section_size)
278 {
279   unsigned char *dst;
280   PIMAGE_DOS_HEADER dos_header;
281   PIMAGE_NT_HEADERS nt_header;
282   PIMAGE_NT_HEADERS dst_nt_header;
283   PIMAGE_SECTION_HEADER section;
284   PIMAGE_SECTION_HEADER dst_section;
285   DWORD offset;
286   int i;
287   int be_verbose = GetEnvironmentVariable ("DEBUG_DUMP", NULL, 0) > 0;
288
289 #define COPY_CHUNK(message, src, size, verbose)                                 \
290   do {                                                                          \
291     unsigned char *s = (void *)(src);                                           \
292     unsigned long count = (size);                                               \
293     if (verbose)                                                                \
294       {                                                                         \
295         printf ("%s\n", (message));                                             \
296         printf ("\t0x%08x Offset in input file.\n", s - p_infile->file_base);   \
297         printf ("\t0x%08x Offset in output file.\n", dst - p_outfile->file_base); \
298         printf ("\t0x%08x Size in bytes.\n", count);                            \
299       }                                                                         \
300     memcpy (dst, s, count);                                                     \
301     dst += count;                                                               \
302   } while (0)
303
304 #define DST_TO_OFFSET()  PTR_TO_OFFSET (dst, p_outfile)
305 #define ROUND_UP_DST_AND_ZERO(align)                                            \
306   do {                                                                          \
307     unsigned char *newdst = p_outfile->file_base                                \
308       + ROUND_UP (DST_TO_OFFSET (), (align));                                   \
309     /* Zero the alignment slop; it may actually initialize real data.  */       \
310     memset (dst, 0, newdst - dst);                                              \
311     dst = newdst;                                                               \
312   } while (0)
313
314   /* Copy the source image sequentially, ie. section by section after
315      copying the headers and section table, to simplify the process of
316      adding an extra section table entry (which might force the raw
317      section data to be relocated).
318
319      Note that dst is updated implicitly by each COPY_CHUNK.  */
320
321   dos_header = (PIMAGE_DOS_HEADER) p_infile->file_base;
322   nt_header = (PIMAGE_NT_HEADERS) (((unsigned long) dos_header) +
323                                    dos_header->e_lfanew);
324   section = IMAGE_FIRST_SECTION (nt_header);
325
326   dst = (unsigned char *) p_outfile->file_base;
327
328   COPY_CHUNK ("Copying DOS header...", dos_header,
329               (DWORD) nt_header - (DWORD) dos_header, be_verbose);
330   dst_nt_header = (PIMAGE_NT_HEADERS) dst;
331   COPY_CHUNK ("Copying NT header...", nt_header,
332               (DWORD) section - (DWORD) nt_header, be_verbose);
333   dst_section = (PIMAGE_SECTION_HEADER) dst;
334   COPY_CHUNK ("Copying section table...", section,
335               nt_header->FileHeader.NumberOfSections * sizeof (*section),
336               be_verbose);
337
338   /* To improve the efficiency of demand loading, make the file
339      alignment match the section alignment (VC++ 6.0 does this by
340      default anyway).  */
341   dst_nt_header->OptionalHeader.FileAlignment =
342     dst_nt_header->OptionalHeader.SectionAlignment;
343
344   /* Add an uninitialized data section at the end, of the specified name
345      and virtual size.  */
346   if (find_section (new_section_name, nt_header) == NULL)
347     /* Leave room for extra section table entry; filled in below.  */
348     dst += sizeof (*section);
349   else
350     new_section_name = NULL;
351
352   /* Align the first section's raw data area, and set the header size
353      field accordingly.  */
354   ROUND_UP_DST_AND_ZERO (dst_nt_header->OptionalHeader.FileAlignment);
355   dst_nt_header->OptionalHeader.SizeOfHeaders = DST_TO_OFFSET ();
356
357   for (i = 0; i < nt_header->FileHeader.NumberOfSections; i++)
358     {
359       char msg[100];
360       /* Windows section names are fixed 8-char strings, only
361          zero-terminated if the name is shorter than 8 characters.  */
362       sprintf (msg, "Copying raw data for %.8s...", section->Name);
363
364       /* Update the file-relative offset for this section's raw data (if
365          it has any) in case things have been relocated; we will update
366          the other offsets below once we know where everything is.  */
367       if (dst_section->PointerToRawData)
368         dst_section->PointerToRawData = DST_TO_OFFSET ();
369
370       /* Can always copy the original raw data.  */
371       COPY_CHUNK
372         (msg, OFFSET_TO_PTR (section->PointerToRawData, p_infile),
373          section->SizeOfRawData, be_verbose);
374
375       /* Round up the raw data size to the new alignment.  */
376       dst_section->SizeOfRawData =
377         ROUND_UP (dst_section->SizeOfRawData,
378                   dst_nt_header->OptionalHeader.FileAlignment);
379
380       /* Align the next section's raw data area.  */
381       ROUND_UP_DST_AND_ZERO (dst_nt_header->OptionalHeader.FileAlignment);
382
383       section++;
384       dst_section++;
385     }
386
387   /* Add the extra section entry (which adds no raw data).  */
388   if (new_section_name != NULL)
389     {
390       dst_nt_header->FileHeader.NumberOfSections++;
391       dst_nt_header->OptionalHeader.SizeOfImage += new_section_size;
392       strncpy (dst_section->Name, new_section_name, sizeof (dst_section->Name));
393       dst_section->VirtualAddress =
394         section[-1].VirtualAddress
395         + ROUND_UP (section[-1].Misc.VirtualSize,
396                     dst_nt_header->OptionalHeader.SectionAlignment);
397       dst_section->Misc.VirtualSize = new_section_size;
398       dst_section->PointerToRawData = 0;
399       dst_section->SizeOfRawData = 0;
400       dst_section->Characteristics =
401         IMAGE_SCN_CNT_UNINITIALIZED_DATA
402         | IMAGE_SCN_MEM_READ
403         | IMAGE_SCN_MEM_WRITE;
404     }
405
406   /* Copy remainder of source image.  */
407   section--;
408   offset = ROUND_UP (section->PointerToRawData + section->SizeOfRawData,
409                      nt_header->OptionalHeader.FileAlignment);
410   COPY_CHUNK
411     ("Copying remainder of executable...",
412      OFFSET_TO_PTR (offset, p_infile),
413      p_infile->size - offset, be_verbose);
414
415   /* Final size for new image.  */
416   p_outfile->size = DST_TO_OFFSET ();
417
418   /* Now patch up remaining file-relative offsets.  */
419   section = IMAGE_FIRST_SECTION (nt_header);
420   dst_section = IMAGE_FIRST_SECTION (dst_nt_header);
421
422 #define ADJUST_OFFSET(var)                                              \
423   do {                                                                  \
424     if ((var) != 0)                                                     \
425       (var) = relocate_offset ((var), nt_header, dst_nt_header);        \
426   } while (0)
427
428   dst_nt_header->OptionalHeader.SizeOfInitializedData = 0;
429   dst_nt_header->OptionalHeader.SizeOfUninitializedData = 0;
430   for (i = 0; i < dst_nt_header->FileHeader.NumberOfSections; i++)
431     {
432       /* Recompute data sizes for completeness.  */
433       if (dst_section[i].Characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA)
434         dst_nt_header->OptionalHeader.SizeOfInitializedData +=
435           ROUND_UP (dst_section[i].Misc.VirtualSize, dst_nt_header->OptionalHeader.FileAlignment);
436       else if (dst_section[i].Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA)
437         dst_nt_header->OptionalHeader.SizeOfUninitializedData +=
438           ROUND_UP (dst_section[i].Misc.VirtualSize, dst_nt_header->OptionalHeader.FileAlignment);
439
440       ADJUST_OFFSET (dst_section[i].PointerToLinenumbers);
441     }
442
443   ADJUST_OFFSET (dst_nt_header->FileHeader.PointerToSymbolTable);
444
445   /* Update offsets in debug directory entries. */
446   {
447     IMAGE_DATA_DIRECTORY debug_dir =
448       dst_nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG];
449     PIMAGE_DEBUG_DIRECTORY debug_entry;
450
451     section = rva_to_section (debug_dir.VirtualAddress, dst_nt_header);
452     if (section)
453       {
454         debug_entry = (PIMAGE_DEBUG_DIRECTORY)
455           (RVA_TO_OFFSET (debug_dir.VirtualAddress, section) + p_outfile->file_base);
456         debug_dir.Size /= sizeof (IMAGE_DEBUG_DIRECTORY);
457
458         for (i = 0; i < debug_dir.Size; i++, debug_entry++)
459           ADJUST_OFFSET (debug_entry->PointerToRawData);
460       }
461   }
462 }
463
464
465 int
466 main (int argc, char **argv)
467 {
468   file_data in_file, out_file;
469   char out_filename[MAX_PATH], in_filename[MAX_PATH];
470   unsigned long size;
471   PIMAGE_DOS_HEADER dos_header;
472   PIMAGE_NT_HEADERS nt_header;
473
474 #define OLD_NAME        argv[1]
475 #define NEW_NAME        argv[2]
476 #define SECTION_NAME    argv[3]
477 #define SECTION_SIZE    argv[4]
478
479   strcpy (in_filename, OLD_NAME);
480   strcpy (out_filename, NEW_NAME);
481
482   printf ("Dumping from %s\n", in_filename);
483   printf ("          to %s\n", out_filename);
484
485   /* Open the undumped executable file.  */
486   if (!open_input_file (&in_file, in_filename))
487     {
488       printf ("Failed to open %s (%d)...bailing.\n",
489               in_filename, GetLastError ());
490       exit (1);
491     }
492   dos_header = (PIMAGE_DOS_HEADER) in_file.file_base;
493   nt_header = (PIMAGE_NT_HEADERS) ((char *) dos_header + dos_header->e_lfanew);
494   /* Allow for expansion due to increasing file align to section align.
495      We can overestimate here, since close_file_data will update the
496      size exactly.  */
497   size = in_file.size
498     + nt_header->OptionalHeader.SectionAlignment
499     * nt_header->FileHeader.NumberOfSections;
500   if (!open_output_file (&out_file, out_filename, size))
501     {
502       printf ("Failed to open %s (%d)...bailing.\n",
503               out_filename, GetLastError ());
504       exit (1);
505     }
506
507   copy_executable_and_add_section (&in_file, &out_file,
508                                    SECTION_NAME,
509                                    atoi (SECTION_SIZE) * 1024 * 1024);
510
511   /* Patch up header fields; profiler is picky about this. */
512   {
513     HANDLE hImagehelp = LoadLibrary ("imagehlp.dll");
514     DWORD  headersum;
515     DWORD  checksum;
516
517     dos_header = (PIMAGE_DOS_HEADER) out_file.file_base;
518     nt_header = (PIMAGE_NT_HEADERS) ((char *) dos_header + dos_header->e_lfanew);
519
520     nt_header->OptionalHeader.CheckSum = 0;
521 //    nt_header->FileHeader.TimeDateStamp = time (NULL);
522 //    dos_header->e_cp = size / 512;
523 //    nt_header->OptionalHeader.SizeOfImage = size;
524
525     pfnCheckSumMappedFile = (void *) GetProcAddress (hImagehelp, "CheckSumMappedFile");
526     if (pfnCheckSumMappedFile)
527       {
528 //      nt_header->FileHeader.TimeDateStamp = time (NULL);
529         pfnCheckSumMappedFile (out_file.file_base,
530                                out_file.size,
531                                &headersum,
532                                &checksum);
533         nt_header->OptionalHeader.CheckSum = checksum;
534       }
535     FreeLibrary (hImagehelp);
536   }
537
538   close_file_data (&in_file);
539   close_file_data (&out_file);
540
541   return 0;
542 }
543
544 /* eof */
545
546 /* arch-tag: 17e2b0aa-8c17-4bd1-b24b-1cda689245fa
547    (do not change this comment) */
Note: See TracBrowser for help on using the browser.