]> code.delx.au - gnu-emacs/blob - nt/addsection.c
(xscheme-insert-expression): Use add-to-history.
[gnu-emacs] / nt / addsection.c
1 /* Add an uninitialized data section to an executable.
2 Copyright (C) 1999, 2002, 2003, 2004, 2005,
3 2006 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 2, 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) */