1 /* Add an uninitialized data section to an executable.
2 Copyright (C) 1999 Free Software Foundation, Inc.
4 This file is part of GNU Emacs.
6 GNU Emacs is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
11 GNU Emacs is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Emacs; see the file COPYING. If not, write to
18 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA.
21 Andrew Innes <andrewi@harlequin.co.uk> 04-Jan-1999
22 based on code from unexw32.c
31 /* Include relevant definitions from IMAGEHLP.H, which can be found
32 in \\win32sdk\mstools\samples\image\include\imagehlp.h. */
35 (__stdcall
* pfnCheckSumMappedFile
) (LPVOID BaseAddress
,
42 #define min(x, y) (((x) < (y)) ? (x) : (y))
43 #define max(x, y) (((x) > (y)) ? (x) : (y))
48 typedef struct file_data
{
53 unsigned char *file_base
;
57 open_input_file (file_data
*p_file
, char *filename
)
62 unsigned long size
, upper_size
;
64 file
= CreateFile (filename
, GENERIC_READ
, FILE_SHARE_READ
, NULL
,
65 OPEN_EXISTING
, FILE_ATTRIBUTE_NORMAL
, 0);
66 if (file
== INVALID_HANDLE_VALUE
)
69 size
= GetFileSize (file
, &upper_size
);
70 file_mapping
= CreateFileMapping (file
, NULL
, PAGE_READONLY
,
75 file_base
= MapViewOfFile (file_mapping
, FILE_MAP_READ
, 0, 0, size
);
79 p_file
->name
= filename
;
82 p_file
->file_mapping
= file_mapping
;
83 p_file
->file_base
= file_base
;
89 open_output_file (file_data
*p_file
, char *filename
, unsigned long size
)
95 file
= CreateFile (filename
, GENERIC_READ
| GENERIC_WRITE
, 0, NULL
,
96 CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, 0);
97 if (file
== INVALID_HANDLE_VALUE
)
100 file_mapping
= CreateFileMapping (file
, NULL
, PAGE_READWRITE
,
105 file_base
= MapViewOfFile (file_mapping
, FILE_MAP_WRITE
, 0, 0, size
);
109 p_file
->name
= filename
;
112 p_file
->file_mapping
= file_mapping
;
113 p_file
->file_base
= file_base
;
118 /* Close the system structures associated with the given file. */
120 close_file_data (file_data
*p_file
)
122 UnmapViewOfFile (p_file
->file_base
);
123 CloseHandle (p_file
->file_mapping
);
124 /* For the case of output files, set final size. */
125 SetFilePointer (p_file
->file
, p_file
->size
, NULL
, FILE_BEGIN
);
126 SetEndOfFile (p_file
->file
);
127 CloseHandle (p_file
->file
);
131 /* Routines to manipulate NT executable file sections. */
134 get_unrounded_section_size (PIMAGE_SECTION_HEADER p_section
)
136 /* The true section size, before rounding, for an initialized data or
137 code section. (Supposedly some linkers swap the meaning of these
139 return min (p_section
->SizeOfRawData
,
140 p_section
->Misc
.VirtualSize
);
143 /* Return pointer to section header for named section. */
144 IMAGE_SECTION_HEADER
*
145 find_section (char * name
, IMAGE_NT_HEADERS
* nt_header
)
147 PIMAGE_SECTION_HEADER section
;
150 section
= IMAGE_FIRST_SECTION (nt_header
);
152 for (i
= 0; i
< nt_header
->FileHeader
.NumberOfSections
; i
++)
154 if (strcmp (section
->Name
, name
) == 0)
161 /* Return pointer to section header for section containing the given
162 relative virtual address. */
163 IMAGE_SECTION_HEADER
*
164 rva_to_section (DWORD rva
, IMAGE_NT_HEADERS
* nt_header
)
166 PIMAGE_SECTION_HEADER section
;
169 section
= IMAGE_FIRST_SECTION (nt_header
);
171 for (i
= 0; i
< nt_header
->FileHeader
.NumberOfSections
; i
++)
173 /* Some linkers (eg. the NT SDK linker I believe) swapped the
174 meaning of these two values - or rather, they ignored
175 VirtualSize entirely and always set it to zero. This affects
176 some very old exes (eg. gzip dated Dec 1993). Since
177 w32_executable_type relies on this function to work reliably,
178 we need to cope with this. */
179 DWORD real_size
= max (section
->SizeOfRawData
,
180 section
->Misc
.VirtualSize
);
181 if (rva
>= section
->VirtualAddress
182 && rva
< section
->VirtualAddress
+ real_size
)
189 /* Return pointer to section header for section containing the given
190 offset in its raw data area. */
191 IMAGE_SECTION_HEADER
*
192 offset_to_section (DWORD offset
, IMAGE_NT_HEADERS
* nt_header
)
194 PIMAGE_SECTION_HEADER section
;
197 section
= IMAGE_FIRST_SECTION (nt_header
);
199 for (i
= 0; i
< nt_header
->FileHeader
.NumberOfSections
; i
++)
201 if (offset
>= section
->PointerToRawData
202 && offset
< section
->PointerToRawData
+ section
->SizeOfRawData
)
209 /* Return offset to an object in dst, given offset in src. We assume
210 there is at least one section in both src and dst images, and that
211 the some sections may have been added to dst (after sections in src). */
213 relocate_offset (DWORD offset
,
214 IMAGE_NT_HEADERS
* src_nt_header
,
215 IMAGE_NT_HEADERS
* dst_nt_header
)
217 PIMAGE_SECTION_HEADER src_section
= IMAGE_FIRST_SECTION (src_nt_header
);
218 PIMAGE_SECTION_HEADER dst_section
= IMAGE_FIRST_SECTION (dst_nt_header
);
221 while (offset
>= src_section
->PointerToRawData
)
223 if (offset
< src_section
->PointerToRawData
+ src_section
->SizeOfRawData
)
226 if (i
== src_nt_header
->FileHeader
.NumberOfSections
)
228 /* Handle offsets after the last section. */
229 dst_section
= IMAGE_FIRST_SECTION (dst_nt_header
);
230 dst_section
+= dst_nt_header
->FileHeader
.NumberOfSections
- 1;
231 while (dst_section
->PointerToRawData
== 0)
233 while (src_section
->PointerToRawData
== 0)
236 + (dst_section
->PointerToRawData
+ dst_section
->SizeOfRawData
)
237 - (src_section
->PointerToRawData
+ src_section
->SizeOfRawData
);
243 (dst_section
->PointerToRawData
- src_section
->PointerToRawData
);
246 #define OFFSET_TO_RVA(offset, section) \
247 (section->VirtualAddress + ((DWORD)(offset) - section->PointerToRawData))
249 #define RVA_TO_OFFSET(rva, section) \
250 (section->PointerToRawData + ((DWORD)(rva) - section->VirtualAddress))
252 #define RVA_TO_SECTION_OFFSET(rva, section) \
253 ((DWORD)(rva) - section->VirtualAddress)
255 /* Convert address in executing image to RVA. */
256 #define PTR_TO_RVA(ptr) ((DWORD)(ptr) - (DWORD) GetModuleHandle (NULL))
258 #define PTR_TO_OFFSET(ptr, pfile_data) \
259 ((char *)(ptr) - (pfile_data)->file_base)
261 #define OFFSET_TO_PTR(offset, pfile_data) \
262 ((pfile_data)->file_base + (DWORD)(offset))
264 #define ROUND_UP(p, align) (((DWORD)(p) + (align)-1) & ~((align)-1))
265 #define ROUND_DOWN(p, align) ((DWORD)(p) & ~((align)-1))
269 copy_executable_and_add_section (file_data
*p_infile
,
270 file_data
*p_outfile
,
271 char *new_section_name
,
272 DWORD new_section_size
)
275 PIMAGE_DOS_HEADER dos_header
;
276 PIMAGE_NT_HEADERS nt_header
;
277 PIMAGE_NT_HEADERS dst_nt_header
;
278 PIMAGE_SECTION_HEADER section
;
279 PIMAGE_SECTION_HEADER dst_section
;
283 #define COPY_CHUNK(message, src, size) \
285 unsigned char *s = (void *)(src); \
286 unsigned long count = (size); \
287 printf ("%s\n", (message)); \
288 printf ("\t0x%08x Offset in input file.\n", s - p_infile->file_base); \
289 printf ("\t0x%08x Offset in output file.\n", dst - p_outfile->file_base); \
290 printf ("\t0x%08x Size in bytes.\n", count); \
291 memcpy (dst, s, count); \
295 #define DST_TO_OFFSET() PTR_TO_OFFSET (dst, p_outfile)
296 #define ROUND_UP_DST(align) \
297 (dst = p_outfile->file_base + ROUND_UP (DST_TO_OFFSET (), (align)))
299 /* Copy the source image sequentially, ie. section by section after
300 copying the headers and section table, to simplify the process of
301 adding an extra section table entry (which might force the raw
302 section data to be relocated).
304 Note that dst is updated implicitly by each COPY_CHUNK. */
306 dos_header
= (PIMAGE_DOS_HEADER
) p_infile
->file_base
;
307 nt_header
= (PIMAGE_NT_HEADERS
) (((unsigned long) dos_header
) +
308 dos_header
->e_lfanew
);
309 section
= IMAGE_FIRST_SECTION (nt_header
);
311 dst
= (unsigned char *) p_outfile
->file_base
;
313 COPY_CHUNK ("Copying DOS header...", dos_header
,
314 (DWORD
) nt_header
- (DWORD
) dos_header
);
315 dst_nt_header
= (PIMAGE_NT_HEADERS
) dst
;
316 COPY_CHUNK ("Copying NT header...", nt_header
,
317 (DWORD
) section
- (DWORD
) nt_header
);
318 dst_section
= (PIMAGE_SECTION_HEADER
) dst
;
319 COPY_CHUNK ("Copying section table...", section
,
320 nt_header
->FileHeader
.NumberOfSections
* sizeof (*section
));
322 /* To improve the efficiency of demand loading, make the file
323 alignment match the section alignment (VC++ 6.0 does this by
325 dst_nt_header
->OptionalHeader
.FileAlignment
=
326 dst_nt_header
->OptionalHeader
.SectionAlignment
;
328 /* Add an uninitialized data section at the end, of the specified name
330 if (find_section (new_section_name
, nt_header
) == NULL
)
331 /* Leave room for extra section table entry; filled in below. */
332 dst
+= sizeof (*section
);
334 new_section_name
= NULL
;
336 for (i
= 0; i
< nt_header
->FileHeader
.NumberOfSections
; i
++)
339 sprintf (msg
, "Copying raw data for %s...", section
->Name
);
341 /* Align the section's raw data area. */
342 ROUND_UP_DST (dst_nt_header
->OptionalHeader
.FileAlignment
);
344 /* Update the file-relative offset for this section's raw data (if
345 it has any) in case things have been relocated; we will update
346 the other offsets below once we know where everything is. */
347 if (dst_section
->PointerToRawData
)
348 dst_section
->PointerToRawData
= DST_TO_OFFSET ();
350 /* Can always copy the original raw data. */
352 (msg
, OFFSET_TO_PTR (section
->PointerToRawData
, p_infile
),
353 section
->SizeOfRawData
);
355 /* Round up the raw data size to the new alignment. */
356 dst_section
->SizeOfRawData
=
357 ROUND_UP (dst_section
->SizeOfRawData
,
358 dst_nt_header
->OptionalHeader
.FileAlignment
);
364 /* Pad out the final section raw data area. */
365 ROUND_UP_DST (dst_nt_header
->OptionalHeader
.FileAlignment
);
367 /* Add the extra section entry (which adds no raw data). */
368 if (new_section_name
!= NULL
)
370 dst_nt_header
->FileHeader
.NumberOfSections
++;
371 dst_nt_header
->OptionalHeader
.SizeOfImage
+= new_section_size
;
372 strncpy (dst_section
->Name
, new_section_name
, sizeof (dst_section
->Name
));
373 dst_section
->VirtualAddress
=
374 section
[-1].VirtualAddress
375 + ROUND_UP (section
[-1].Misc
.VirtualSize
,
376 dst_nt_header
->OptionalHeader
.SectionAlignment
);
377 dst_section
->Misc
.VirtualSize
= new_section_size
;
378 dst_section
->PointerToRawData
= 0;
379 dst_section
->SizeOfRawData
= 0;
380 dst_section
->Characteristics
=
381 IMAGE_SCN_CNT_UNINITIALIZED_DATA
383 | IMAGE_SCN_MEM_WRITE
;
386 /* Copy remainder of source image. */
388 offset
= ROUND_UP (section
->PointerToRawData
+ section
->SizeOfRawData
,
389 nt_header
->OptionalHeader
.FileAlignment
);
391 ("Copying remainder of executable...",
392 OFFSET_TO_PTR (offset
, p_infile
),
393 p_infile
->size
- offset
);
395 /* Final size for new image. */
396 p_outfile
->size
= DST_TO_OFFSET ();
398 /* Now patch up remaining file-relative offsets. */
399 section
= IMAGE_FIRST_SECTION (nt_header
);
400 dst_section
= IMAGE_FIRST_SECTION (dst_nt_header
);
402 #define ADJUST_OFFSET(var) \
405 (var) = relocate_offset ((var), nt_header, dst_nt_header); \
408 dst_nt_header
->OptionalHeader
.SizeOfInitializedData
= 0;
409 dst_nt_header
->OptionalHeader
.SizeOfUninitializedData
= 0;
410 for (i
= 0; i
< dst_nt_header
->FileHeader
.NumberOfSections
; i
++)
412 /* Recompute data sizes for completeness. */
413 if (dst_section
[i
].Characteristics
& IMAGE_SCN_CNT_INITIALIZED_DATA
)
414 dst_nt_header
->OptionalHeader
.SizeOfInitializedData
+=
415 ROUND_UP (dst_section
[i
].Misc
.VirtualSize
, dst_nt_header
->OptionalHeader
.FileAlignment
);
416 else if (dst_section
[i
].Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
)
417 dst_nt_header
->OptionalHeader
.SizeOfUninitializedData
+=
418 ROUND_UP (dst_section
[i
].Misc
.VirtualSize
, dst_nt_header
->OptionalHeader
.FileAlignment
);
420 ADJUST_OFFSET (dst_section
[i
].PointerToLinenumbers
);
423 ADJUST_OFFSET (dst_nt_header
->FileHeader
.PointerToSymbolTable
);
425 /* Update offsets in debug directory entries. */
427 IMAGE_DATA_DIRECTORY debug_dir
=
428 dst_nt_header
->OptionalHeader
.DataDirectory
[IMAGE_DIRECTORY_ENTRY_DEBUG
];
429 PIMAGE_DEBUG_DIRECTORY debug_entry
;
431 section
= rva_to_section (debug_dir
.VirtualAddress
, dst_nt_header
);
434 debug_entry
= (PIMAGE_DEBUG_DIRECTORY
)
435 (RVA_TO_OFFSET (debug_dir
.VirtualAddress
, section
) + p_outfile
->file_base
);
436 debug_dir
.Size
/= sizeof (IMAGE_DEBUG_DIRECTORY
);
438 for (i
= 0; i
< debug_dir
.Size
; i
++, debug_entry
++)
439 ADJUST_OFFSET (debug_entry
->PointerToRawData
);
446 main (int argc
, char **argv
)
448 file_data in_file
, out_file
;
449 char out_filename
[MAX_PATH
], in_filename
[MAX_PATH
];
451 PIMAGE_DOS_HEADER dos_header
;
452 PIMAGE_NT_HEADERS nt_header
;
454 #define OLD_NAME argv[1]
455 #define NEW_NAME argv[2]
456 #define SECTION_NAME argv[3]
457 #define SECTION_SIZE argv[4]
459 strcpy (in_filename
, OLD_NAME
);
460 strcpy (out_filename
, NEW_NAME
);
462 printf ("Dumping from %s\n", in_filename
);
463 printf (" to %s\n", out_filename
);
465 /* Open the undumped executable file. */
466 if (!open_input_file (&in_file
, in_filename
))
468 printf ("Failed to open %s (%d)...bailing.\n",
469 in_filename
, GetLastError ());
472 dos_header
= (PIMAGE_DOS_HEADER
) in_file
.file_base
;
473 nt_header
= (PIMAGE_NT_HEADERS
) ((char *) dos_header
+ dos_header
->e_lfanew
);
474 /* Allow for expansion due to increasing file align to section align.
475 We can overestimate here, since close_file_data will update the
478 + nt_header
->OptionalHeader
.SectionAlignment
479 * nt_header
->FileHeader
.NumberOfSections
;
480 if (!open_output_file (&out_file
, out_filename
, size
))
482 printf ("Failed to open %s (%d)...bailing.\n",
483 out_filename
, GetLastError ());
487 copy_executable_and_add_section (&in_file
, &out_file
,
489 atoi (SECTION_SIZE
) * 1024 * 1024);
491 /* Patch up header fields; profiler is picky about this. */
493 HANDLE hImagehelp
= LoadLibrary ("imagehlp.dll");
497 dos_header
= (PIMAGE_DOS_HEADER
) out_file
.file_base
;
498 nt_header
= (PIMAGE_NT_HEADERS
) ((char *) dos_header
+ dos_header
->e_lfanew
);
500 nt_header
->OptionalHeader
.CheckSum
= 0;
501 // nt_header->FileHeader.TimeDateStamp = time (NULL);
502 // dos_header->e_cp = size / 512;
503 // nt_header->OptionalHeader.SizeOfImage = size;
505 pfnCheckSumMappedFile
= (void *) GetProcAddress (hImagehelp
, "CheckSumMappedFile");
506 if (pfnCheckSumMappedFile
)
508 // nt_header->FileHeader.TimeDateStamp = time (NULL);
509 pfnCheckSumMappedFile (out_file
.file_base
,
513 nt_header
->OptionalHeader
.CheckSum
= checksum
;
515 FreeLibrary (hImagehelp
);
518 close_file_data (&in_file
);
519 close_file_data (&out_file
);