Merge from trunk.
[emacs.git] / src / unexw32.c
blob52b2ec4bf2b1cb27635913323bab2841375af001
1 /* unexec for GNU Emacs on Windows NT.
2 Copyright (C) 1994, 2001-2012 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 3 of the License, or
9 (at your option) any later version.
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. If not, see <http://www.gnu.org/licenses/>. */
20 Geoff Voelker (voelker@cs.washington.edu) 8-12-94
23 #include <config.h>
24 #include "unexec.h"
26 #include <stdio.h>
27 #include <fcntl.h>
28 #include <time.h>
29 #include <windows.h>
31 /* Include relevant definitions from IMAGEHLP.H, which can be found
32 in \\win32sdk\mstools\samples\image\include\imagehlp.h. */
34 PIMAGE_NT_HEADERS
35 (__stdcall * pfnCheckSumMappedFile) (LPVOID BaseAddress,
36 DWORD FileLength,
37 LPDWORD HeaderSum,
38 LPDWORD CheckSum);
40 extern BOOL ctrl_c_handler (unsigned long type);
42 extern char my_begdata[];
43 extern char my_edata[];
44 extern char my_begbss[];
45 extern char my_endbss[];
46 extern char *my_begbss_static;
47 extern char *my_endbss_static;
49 #include "w32heap.h"
51 #undef min
52 #undef max
53 #define min(x, y) (((x) < (y)) ? (x) : (y))
54 #define max(x, y) (((x) > (y)) ? (x) : (y))
56 /* Basically, our "initialized" flag. */
57 BOOL using_dynamic_heap = FALSE;
59 int open_input_file (file_data *p_file, char *name);
60 int open_output_file (file_data *p_file, char *name, unsigned long size);
61 void close_file_data (file_data *p_file);
63 void get_section_info (file_data *p_file);
64 void copy_executable_and_dump_data (file_data *, file_data *);
65 void dump_bss_and_heap (file_data *p_infile, file_data *p_outfile);
67 /* Cached info about the .data section in the executable. */
68 PIMAGE_SECTION_HEADER data_section;
69 PCHAR data_start = 0;
70 DWORD data_size = 0;
72 /* Cached info about the .bss section in the executable. */
73 PIMAGE_SECTION_HEADER bss_section;
74 PCHAR bss_start = 0;
75 DWORD bss_size = 0;
76 DWORD extra_bss_size = 0;
77 /* bss data that is static might be discontiguous from non-static. */
78 PIMAGE_SECTION_HEADER bss_section_static;
79 PCHAR bss_start_static = 0;
80 DWORD bss_size_static = 0;
81 DWORD extra_bss_size_static = 0;
83 PIMAGE_SECTION_HEADER heap_section;
85 #ifdef HAVE_NTGUI
86 HINSTANCE hinst = NULL;
87 HINSTANCE hprevinst = NULL;
88 LPSTR lpCmdLine = "";
89 int nCmdShow = 0;
90 #endif /* HAVE_NTGUI */
92 /* Startup code for running on NT. When we are running as the dumped
93 version, we need to bootstrap our heap and .bss section into our
94 address space before we can actually hand off control to the startup
95 code supplied by NT (primarily because that code relies upon malloc ()). */
96 void
97 _start (void)
99 extern void mainCRTStartup (void);
101 #if 1
102 /* Give us a way to debug problems with crashes on startup when
103 running under the MSVC profiler. */
104 if (GetEnvironmentVariable ("EMACS_DEBUG", NULL, 0) > 0)
105 DebugBreak ();
106 #endif
108 /* Cache system info, e.g., the NT page size. */
109 cache_system_info ();
111 /* Grab our malloc arena space now, before CRT starts up. */
112 init_heap ();
114 /* This prevents ctrl-c's in shells running while we're suspended from
115 having us exit. */
116 SetConsoleCtrlHandler ((PHANDLER_ROUTINE) ctrl_c_handler, TRUE);
118 /* Prevent Emacs from being locked up (eg. in batch mode) when
119 accessing devices that aren't mounted (eg. removable media drives). */
120 SetErrorMode (SEM_FAILCRITICALERRORS);
122 /* Invoke the NT CRT startup routine now that our housecleaning
123 is finished. */
124 #ifdef HAVE_NTGUI
125 /* determine WinMain args like crt0.c does */
126 hinst = GetModuleHandle (NULL);
127 lpCmdLine = GetCommandLine ();
128 nCmdShow = SW_SHOWDEFAULT;
129 #endif
130 mainCRTStartup ();
134 /* File handling. */
137 open_input_file (file_data *p_file, char *filename)
139 HANDLE file;
140 HANDLE file_mapping;
141 void *file_base;
142 unsigned long size, upper_size;
144 file = CreateFile (filename, GENERIC_READ, FILE_SHARE_READ, NULL,
145 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
146 if (file == INVALID_HANDLE_VALUE)
147 return FALSE;
149 size = GetFileSize (file, &upper_size);
150 file_mapping = CreateFileMapping (file, NULL, PAGE_READONLY,
151 0, size, NULL);
152 if (!file_mapping)
153 return FALSE;
155 file_base = MapViewOfFile (file_mapping, FILE_MAP_READ, 0, 0, size);
156 if (file_base == 0)
157 return FALSE;
159 p_file->name = filename;
160 p_file->size = size;
161 p_file->file = file;
162 p_file->file_mapping = file_mapping;
163 p_file->file_base = file_base;
165 return TRUE;
169 open_output_file (file_data *p_file, char *filename, unsigned long size)
171 HANDLE file;
172 HANDLE file_mapping;
173 void *file_base;
175 file = CreateFile (filename, GENERIC_READ | GENERIC_WRITE, 0, NULL,
176 CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
177 if (file == INVALID_HANDLE_VALUE)
178 return FALSE;
180 file_mapping = CreateFileMapping (file, NULL, PAGE_READWRITE,
181 0, size, NULL);
182 if (!file_mapping)
183 return FALSE;
185 file_base = MapViewOfFile (file_mapping, FILE_MAP_WRITE, 0, 0, size);
186 if (file_base == 0)
187 return FALSE;
189 p_file->name = filename;
190 p_file->size = size;
191 p_file->file = file;
192 p_file->file_mapping = file_mapping;
193 p_file->file_base = file_base;
195 return TRUE;
198 /* Close the system structures associated with the given file. */
199 void
200 close_file_data (file_data *p_file)
202 UnmapViewOfFile (p_file->file_base);
203 CloseHandle (p_file->file_mapping);
204 /* For the case of output files, set final size. */
205 SetFilePointer (p_file->file, p_file->size, NULL, FILE_BEGIN);
206 SetEndOfFile (p_file->file);
207 CloseHandle (p_file->file);
211 /* Routines to manipulate NT executable file sections. */
213 /* Return pointer to section header for named section. */
214 IMAGE_SECTION_HEADER *
215 find_section (char * name, IMAGE_NT_HEADERS * nt_header)
217 PIMAGE_SECTION_HEADER section;
218 int i;
220 section = IMAGE_FIRST_SECTION (nt_header);
222 for (i = 0; i < nt_header->FileHeader.NumberOfSections; i++)
224 if (strcmp (section->Name, name) == 0)
225 return section;
226 section++;
228 return NULL;
231 /* Return pointer to section header for section containing the given
232 relative virtual address. */
233 IMAGE_SECTION_HEADER *
234 rva_to_section (DWORD rva, IMAGE_NT_HEADERS * nt_header)
236 PIMAGE_SECTION_HEADER section;
237 int i;
239 section = IMAGE_FIRST_SECTION (nt_header);
241 for (i = 0; i < nt_header->FileHeader.NumberOfSections; i++)
243 /* Some linkers (eg. the NT SDK linker I believe) swapped the
244 meaning of these two values - or rather, they ignored
245 VirtualSize entirely and always set it to zero. This affects
246 some very old exes (eg. gzip dated Dec 1993). Since
247 w32_executable_type relies on this function to work reliably,
248 we need to cope with this. */
249 DWORD real_size = max (section->SizeOfRawData,
250 section->Misc.VirtualSize);
251 if (rva >= section->VirtualAddress
252 && rva < section->VirtualAddress + real_size)
253 return section;
254 section++;
256 return NULL;
259 /* Return pointer to section header for section containing the given
260 offset in its raw data area. */
261 IMAGE_SECTION_HEADER *
262 offset_to_section (DWORD offset, IMAGE_NT_HEADERS * nt_header)
264 PIMAGE_SECTION_HEADER section;
265 int i;
267 section = IMAGE_FIRST_SECTION (nt_header);
269 for (i = 0; i < nt_header->FileHeader.NumberOfSections; i++)
271 if (offset >= section->PointerToRawData
272 && offset < section->PointerToRawData + section->SizeOfRawData)
273 return section;
274 section++;
276 return NULL;
279 /* Return offset to an object in dst, given offset in src. We assume
280 there is at least one section in both src and dst images, and that
281 the some sections may have been added to dst (after sections in src). */
282 DWORD
283 relocate_offset (DWORD offset,
284 IMAGE_NT_HEADERS * src_nt_header,
285 IMAGE_NT_HEADERS * dst_nt_header)
287 PIMAGE_SECTION_HEADER src_section = IMAGE_FIRST_SECTION (src_nt_header);
288 PIMAGE_SECTION_HEADER dst_section = IMAGE_FIRST_SECTION (dst_nt_header);
289 int i = 0;
291 while (offset >= src_section->PointerToRawData)
293 if (offset < src_section->PointerToRawData + src_section->SizeOfRawData)
294 break;
295 i++;
296 if (i == src_nt_header->FileHeader.NumberOfSections)
298 /* Handle offsets after the last section. */
299 dst_section = IMAGE_FIRST_SECTION (dst_nt_header);
300 dst_section += dst_nt_header->FileHeader.NumberOfSections - 1;
301 while (dst_section->PointerToRawData == 0)
302 dst_section--;
303 while (src_section->PointerToRawData == 0)
304 src_section--;
305 return offset
306 + (dst_section->PointerToRawData + dst_section->SizeOfRawData)
307 - (src_section->PointerToRawData + src_section->SizeOfRawData);
309 src_section++;
310 dst_section++;
312 return offset +
313 (dst_section->PointerToRawData - src_section->PointerToRawData);
316 #define OFFSET_TO_RVA(offset, section) \
317 (section->VirtualAddress + ((DWORD)(offset) - section->PointerToRawData))
319 #define RVA_TO_OFFSET(rva, section) \
320 (section->PointerToRawData + ((DWORD)(rva) - section->VirtualAddress))
322 #define RVA_TO_SECTION_OFFSET(rva, section) \
323 ((DWORD)(rva) - section->VirtualAddress)
325 /* Convert address in executing image to RVA. */
326 #define PTR_TO_RVA(ptr) ((DWORD)(ptr) - (DWORD) GetModuleHandle (NULL))
328 #define RVA_TO_PTR(var,section,filedata) \
329 ((void *)(RVA_TO_OFFSET (var,section) + (filedata).file_base))
331 #define PTR_TO_OFFSET(ptr, pfile_data) \
332 ((unsigned char *)(ptr) - (pfile_data)->file_base)
334 #define OFFSET_TO_PTR(offset, pfile_data) \
335 ((pfile_data)->file_base + (DWORD)(offset))
338 /* Flip through the executable and cache the info necessary for dumping. */
339 void
340 get_section_info (file_data *p_infile)
342 PIMAGE_DOS_HEADER dos_header;
343 PIMAGE_NT_HEADERS nt_header;
344 int overlap;
346 dos_header = (PIMAGE_DOS_HEADER) p_infile->file_base;
347 if (dos_header->e_magic != IMAGE_DOS_SIGNATURE)
349 printf ("Unknown EXE header in %s...bailing.\n", p_infile->name);
350 exit (1);
352 nt_header = (PIMAGE_NT_HEADERS) (((unsigned long) dos_header) +
353 dos_header->e_lfanew);
354 if (nt_header == NULL)
356 printf ("Failed to find IMAGE_NT_HEADER in %s...bailing.\n",
357 p_infile->name);
358 exit (1);
361 /* Check the NT header signature ... */
362 if (nt_header->Signature != IMAGE_NT_SIGNATURE)
364 printf ("Invalid IMAGE_NT_SIGNATURE 0x%x in %s...bailing.\n",
365 nt_header->Signature, p_infile->name);
366 exit (1);
369 /* Locate the ".data" and ".bss" sections for Emacs. (Note that the
370 actual section names are probably different from these, and might
371 actually be the same section.)
373 We do this as follows: first we determine the virtual address
374 ranges in this process for the data and bss variables that we wish
375 to preserve. Then we map these VAs to the section entries in the
376 source image. Finally, we determine the new size of the raw data
377 area for the bss section, so we can make the new image the correct
378 size. */
380 /* We arrange for the Emacs initialized data to be in a separate
381 section if possible, because we cannot rely on my_begdata and
382 my_edata marking out the full extent of the initialized data, at
383 least on the Alpha where the linker freely reorders variables
384 across libraries. If we can arrange for this, all we need to do is
385 find the start and size of the EMDATA section. */
386 data_section = find_section ("EMDATA", nt_header);
387 if (data_section)
389 data_start = (char *) nt_header->OptionalHeader.ImageBase +
390 data_section->VirtualAddress;
391 data_size = data_section->Misc.VirtualSize;
393 else
395 /* Fallback on the old method if compiler doesn't support the
396 data_set #pragma (or its equivalent). */
397 data_start = my_begdata;
398 data_size = my_edata - my_begdata;
399 data_section = rva_to_section (PTR_TO_RVA (my_begdata), nt_header);
400 if (data_section != rva_to_section (PTR_TO_RVA (my_edata), nt_header))
402 printf ("Initialized data is not in a single section...bailing\n");
403 exit (1);
407 /* As noted in lastfile.c, the Alpha (but not the Intel) MSVC linker
408 globally segregates all static and public bss data (ie. across all
409 linked modules, not just per module), so we must take both static
410 and public bss areas into account to determine the true extent of
411 the bss area used by Emacs.
413 To be strictly correct, we dump the static and public bss areas
414 used by Emacs separately if non-overlapping (since otherwise we are
415 dumping bss data belonging to system libraries, eg. the static bss
416 system data on the Alpha). */
418 bss_start = my_begbss;
419 bss_size = my_endbss - my_begbss;
420 bss_section = rva_to_section (PTR_TO_RVA (my_begbss), nt_header);
421 if (bss_section != rva_to_section (PTR_TO_RVA (my_endbss), nt_header))
423 printf ("Uninitialized data is not in a single section...bailing\n");
424 exit (1);
426 /* Compute how much the .bss section's raw data will grow. */
427 extra_bss_size =
428 ROUND_UP (RVA_TO_SECTION_OFFSET (PTR_TO_RVA (my_endbss), bss_section),
429 nt_header->OptionalHeader.FileAlignment)
430 - bss_section->SizeOfRawData;
432 bss_start_static = my_begbss_static;
433 bss_size_static = my_endbss_static - my_begbss_static;
434 bss_section_static = rva_to_section (PTR_TO_RVA (my_begbss_static), nt_header);
435 if (bss_section_static != rva_to_section (PTR_TO_RVA (my_endbss_static), nt_header))
437 printf ("Uninitialized static data is not in a single section...bailing\n");
438 exit (1);
440 /* Compute how much the static .bss section's raw data will grow. */
441 extra_bss_size_static =
442 ROUND_UP (RVA_TO_SECTION_OFFSET (PTR_TO_RVA (my_endbss_static), bss_section_static),
443 nt_header->OptionalHeader.FileAlignment)
444 - bss_section_static->SizeOfRawData;
446 /* Combine the bss sections into one if they overlap. */
447 #ifdef _ALPHA_
448 overlap = 1; /* force all bss data to be dumped */
449 #else
450 overlap = 0;
451 #endif
452 if (bss_start < bss_start_static)
454 if (bss_start_static < bss_start + bss_size)
455 overlap = 1;
457 else
459 if (bss_start < bss_start_static + bss_size_static)
460 overlap = 1;
462 if (overlap)
464 if (bss_section != bss_section_static)
466 printf ("BSS data not in a single section...bailing\n");
467 exit (1);
469 bss_start = min (bss_start, bss_start_static);
470 bss_size = max (my_endbss, my_endbss_static) - bss_start;
471 bss_section_static = 0;
472 extra_bss_size_static = 0;
475 heap_section = rva_to_section (PTR_TO_RVA (get_heap_start ()), nt_header);
479 /* The dump routines. */
481 void
482 copy_executable_and_dump_data (file_data *p_infile,
483 file_data *p_outfile)
485 unsigned char *dst, *dst_save;
486 PIMAGE_DOS_HEADER dos_header;
487 PIMAGE_NT_HEADERS nt_header;
488 PIMAGE_NT_HEADERS dst_nt_header;
489 PIMAGE_SECTION_HEADER section;
490 PIMAGE_SECTION_HEADER dst_section;
491 DWORD offset;
492 int i;
493 int be_verbose = GetEnvironmentVariable ("DEBUG_DUMP", NULL, 0) > 0;
495 #define COPY_CHUNK(message, src, size, verbose) \
496 do { \
497 unsigned char *s = (void *)(src); \
498 unsigned long count = (size); \
499 if (verbose) \
501 printf ("%s\n", (message)); \
502 printf ("\t0x%08x Offset in input file.\n", s - p_infile->file_base); \
503 printf ("\t0x%08x Offset in output file.\n", dst - p_outfile->file_base); \
504 printf ("\t0x%08x Size in bytes.\n", count); \
506 memcpy (dst, s, count); \
507 dst += count; \
508 } while (0)
510 #define COPY_PROC_CHUNK(message, src, size, verbose) \
511 do { \
512 unsigned char *s = (void *)(src); \
513 unsigned long count = (size); \
514 if (verbose) \
516 printf ("%s\n", (message)); \
517 printf ("\t0x%08x Address in process.\n", s); \
518 printf ("\t0x%08x Offset in output file.\n", dst - p_outfile->file_base); \
519 printf ("\t0x%08x Size in bytes.\n", count); \
521 memcpy (dst, s, count); \
522 dst += count; \
523 } while (0)
525 #define DST_TO_OFFSET() PTR_TO_OFFSET (dst, p_outfile)
526 #define ROUND_UP_DST(align) \
527 (dst = p_outfile->file_base + ROUND_UP (DST_TO_OFFSET (), (align)))
528 #define ROUND_UP_DST_AND_ZERO(align) \
529 do { \
530 unsigned char *newdst = p_outfile->file_base \
531 + ROUND_UP (DST_TO_OFFSET (), (align)); \
532 /* Zero the alignment slop; it may actually initialize real data. */ \
533 memset (dst, 0, newdst - dst); \
534 dst = newdst; \
535 } while (0)
537 /* Copy the source image sequentially, ie. section by section after
538 copying the headers and section table, to simplify the process of
539 dumping the raw data for the bss and heap sections.
541 Note that dst is updated implicitly by each COPY_CHUNK. */
543 dos_header = (PIMAGE_DOS_HEADER) p_infile->file_base;
544 nt_header = (PIMAGE_NT_HEADERS) (((unsigned long) dos_header) +
545 dos_header->e_lfanew);
546 section = IMAGE_FIRST_SECTION (nt_header);
548 dst = (unsigned char *) p_outfile->file_base;
550 COPY_CHUNK ("Copying DOS header...", dos_header,
551 (DWORD) nt_header - (DWORD) dos_header, be_verbose);
552 dst_nt_header = (PIMAGE_NT_HEADERS) dst;
553 COPY_CHUNK ("Copying NT header...", nt_header,
554 (DWORD) section - (DWORD) nt_header, be_verbose);
555 dst_section = (PIMAGE_SECTION_HEADER) dst;
556 COPY_CHUNK ("Copying section table...", section,
557 nt_header->FileHeader.NumberOfSections * sizeof (*section),
558 be_verbose);
560 /* Align the first section's raw data area, and set the header size
561 field accordingly. */
562 ROUND_UP_DST_AND_ZERO (dst_nt_header->OptionalHeader.FileAlignment);
563 dst_nt_header->OptionalHeader.SizeOfHeaders = DST_TO_OFFSET ();
565 for (i = 0; i < nt_header->FileHeader.NumberOfSections; i++)
567 char msg[100];
568 /* Windows section names are fixed 8-char strings, only
569 zero-terminated if the name is shorter than 8 characters. */
570 sprintf (msg, "Copying raw data for %.8s...", section->Name);
572 dst_save = dst;
574 /* Update the file-relative offset for this section's raw data (if
575 it has any) in case things have been relocated; we will update
576 the other offsets below once we know where everything is. */
577 if (dst_section->PointerToRawData)
578 dst_section->PointerToRawData = DST_TO_OFFSET ();
580 /* Can always copy the original raw data. */
581 COPY_CHUNK
582 (msg, OFFSET_TO_PTR (section->PointerToRawData, p_infile),
583 section->SizeOfRawData, be_verbose);
584 /* Ensure alignment slop is zeroed. */
585 ROUND_UP_DST_AND_ZERO (dst_nt_header->OptionalHeader.FileAlignment);
587 /* Note that various sections below may be aliases. */
588 if (section == data_section)
590 dst = dst_save
591 + RVA_TO_SECTION_OFFSET (PTR_TO_RVA (data_start), dst_section);
592 COPY_PROC_CHUNK ("Dumping initialized data...",
593 data_start, data_size, be_verbose);
594 dst = dst_save + dst_section->SizeOfRawData;
596 if (section == bss_section)
598 /* Dump contents of bss variables, adjusting the section's raw
599 data size as necessary. */
600 dst = dst_save
601 + RVA_TO_SECTION_OFFSET (PTR_TO_RVA (bss_start), dst_section);
602 COPY_PROC_CHUNK ("Dumping bss data...", bss_start,
603 bss_size, be_verbose);
604 ROUND_UP_DST (dst_nt_header->OptionalHeader.FileAlignment);
605 dst_section->PointerToRawData = PTR_TO_OFFSET (dst_save, p_outfile);
606 /* Determine new size of raw data area. */
607 dst = max (dst, dst_save + dst_section->SizeOfRawData);
608 dst_section->SizeOfRawData = dst - dst_save;
609 dst_section->Characteristics &= ~IMAGE_SCN_CNT_UNINITIALIZED_DATA;
610 dst_section->Characteristics |= IMAGE_SCN_CNT_INITIALIZED_DATA;
612 if (section == bss_section_static)
614 /* Dump contents of static bss variables, adjusting the
615 section's raw data size as necessary. */
616 dst = dst_save
617 + RVA_TO_SECTION_OFFSET (PTR_TO_RVA (bss_start_static), dst_section);
618 COPY_PROC_CHUNK ("Dumping static bss data...", bss_start_static,
619 bss_size_static, be_verbose);
620 ROUND_UP_DST (dst_nt_header->OptionalHeader.FileAlignment);
621 dst_section->PointerToRawData = PTR_TO_OFFSET (dst_save, p_outfile);
622 /* Determine new size of raw data area. */
623 dst = max (dst, dst_save + dst_section->SizeOfRawData);
624 dst_section->SizeOfRawData = dst - dst_save;
625 dst_section->Characteristics &= ~IMAGE_SCN_CNT_UNINITIALIZED_DATA;
626 dst_section->Characteristics |= IMAGE_SCN_CNT_INITIALIZED_DATA;
628 if (section == heap_section)
630 DWORD heap_start = (DWORD) get_heap_start ();
631 DWORD heap_size = get_committed_heap_size ();
633 /* Dump the used portion of the predump heap, adjusting the
634 section's size to the appropriate size. */
635 dst = dst_save
636 + RVA_TO_SECTION_OFFSET (PTR_TO_RVA (heap_start), dst_section);
637 COPY_PROC_CHUNK ("Dumping heap...", heap_start, heap_size,
638 be_verbose);
639 ROUND_UP_DST (dst_nt_header->OptionalHeader.FileAlignment);
640 dst_section->PointerToRawData = PTR_TO_OFFSET (dst_save, p_outfile);
641 /* Determine new size of raw data area. */
642 dst = max (dst, dst_save + dst_section->SizeOfRawData);
643 dst_section->SizeOfRawData = dst - dst_save;
644 /* Reduce the size of the heap section to fit (must be last
645 section). */
646 dst_nt_header->OptionalHeader.SizeOfImage -=
647 dst_section->Misc.VirtualSize
648 - ROUND_UP (dst_section->SizeOfRawData,
649 dst_nt_header->OptionalHeader.SectionAlignment);
650 dst_section->Misc.VirtualSize =
651 ROUND_UP (dst_section->SizeOfRawData,
652 dst_nt_header->OptionalHeader.SectionAlignment);
653 dst_section->Characteristics &= ~IMAGE_SCN_CNT_UNINITIALIZED_DATA;
654 dst_section->Characteristics |= IMAGE_SCN_CNT_INITIALIZED_DATA;
657 /* Align the section's raw data area. */
658 ROUND_UP_DST (dst_nt_header->OptionalHeader.FileAlignment);
660 section++;
661 dst_section++;
664 /* Copy remainder of source image. */
666 section--;
667 while (section->PointerToRawData == 0);
668 offset = ROUND_UP (section->PointerToRawData + section->SizeOfRawData,
669 nt_header->OptionalHeader.FileAlignment);
670 COPY_CHUNK
671 ("Copying remainder of executable...",
672 OFFSET_TO_PTR (offset, p_infile),
673 p_infile->size - offset, be_verbose);
675 /* Final size for new image. */
676 p_outfile->size = DST_TO_OFFSET ();
678 /* Now patch up remaining file-relative offsets. */
679 section = IMAGE_FIRST_SECTION (nt_header);
680 dst_section = IMAGE_FIRST_SECTION (dst_nt_header);
682 #define ADJUST_OFFSET(var) \
683 do { \
684 if ((var) != 0) \
685 (var) = relocate_offset ((var), nt_header, dst_nt_header); \
686 } while (0)
688 dst_nt_header->OptionalHeader.SizeOfInitializedData = 0;
689 dst_nt_header->OptionalHeader.SizeOfUninitializedData = 0;
690 for (i = 0; i < dst_nt_header->FileHeader.NumberOfSections; i++)
692 /* Recompute data sizes for completeness. */
693 if (dst_section[i].Characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA)
694 dst_nt_header->OptionalHeader.SizeOfInitializedData +=
695 ROUND_UP (dst_section[i].Misc.VirtualSize, dst_nt_header->OptionalHeader.FileAlignment);
696 else if (dst_section[i].Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA)
697 dst_nt_header->OptionalHeader.SizeOfUninitializedData +=
698 ROUND_UP (dst_section[i].Misc.VirtualSize, dst_nt_header->OptionalHeader.FileAlignment);
700 ADJUST_OFFSET (dst_section[i].PointerToLinenumbers);
703 ADJUST_OFFSET (dst_nt_header->FileHeader.PointerToSymbolTable);
705 /* Update offsets in debug directory entries. */
707 IMAGE_DATA_DIRECTORY debug_dir =
708 dst_nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG];
709 PIMAGE_DEBUG_DIRECTORY debug_entry;
711 section = rva_to_section (debug_dir.VirtualAddress, dst_nt_header);
712 if (section)
714 debug_entry = (PIMAGE_DEBUG_DIRECTORY)
715 (RVA_TO_OFFSET (debug_dir.VirtualAddress, section) + p_outfile->file_base);
716 debug_dir.Size /= sizeof (IMAGE_DEBUG_DIRECTORY);
718 for (i = 0; i < debug_dir.Size; i++, debug_entry++)
719 ADJUST_OFFSET (debug_entry->PointerToRawData);
725 /* Dump out .data and .bss sections into a new executable. */
726 void
727 unexec (const char *new_name, const char *old_name)
729 file_data in_file, out_file;
730 char out_filename[MAX_PATH], in_filename[MAX_PATH];
731 unsigned long size;
732 char *p;
733 char *q;
735 /* Ignore old_name, and get our actual location from the OS. */
736 if (!GetModuleFileName (NULL, in_filename, MAX_PATH))
737 abort ();
738 dostounix_filename (in_filename);
739 strcpy (out_filename, in_filename);
741 /* Change the base of the output filename to match the requested name. */
742 if ((p = strrchr (out_filename, '/')) == NULL)
743 abort ();
744 /* The filenames have already been expanded, and will be in Unix
745 format, so it is safe to expect an absolute name. */
746 if ((q = strrchr (new_name, '/')) == NULL)
747 abort ();
748 strcpy (p, q);
750 /* Make sure that the output filename has the ".exe" extension...patch
751 it up if not. */
752 p = out_filename + strlen (out_filename) - 4;
753 if (strcmp (p, ".exe"))
754 strcat (out_filename, ".exe");
756 printf ("Dumping from %s\n", in_filename);
757 printf (" to %s\n", out_filename);
759 /* We need to round off our heap to NT's page size. */
760 round_heap (get_page_size ());
762 /* Open the undumped executable file. */
763 if (!open_input_file (&in_file, in_filename))
765 printf ("Failed to open %s (%d)...bailing.\n",
766 in_filename, GetLastError ());
767 exit (1);
770 /* Get the interesting section info, like start and size of .bss... */
771 get_section_info (&in_file);
773 /* The size of the dumped executable is the size of the original
774 executable plus the size of the heap and the size of the .bss section. */
775 size = in_file.size +
776 get_committed_heap_size () +
777 extra_bss_size +
778 extra_bss_size_static;
779 if (!open_output_file (&out_file, out_filename, size))
781 printf ("Failed to open %s (%d)...bailing.\n",
782 out_filename, GetLastError ());
783 exit (1);
786 /* Set the flag (before dumping). */
787 using_dynamic_heap = TRUE;
789 copy_executable_and_dump_data (&in_file, &out_file);
791 /* Patch up header fields; profiler is picky about this. */
793 PIMAGE_DOS_HEADER dos_header;
794 PIMAGE_NT_HEADERS nt_header;
795 HANDLE hImagehelp = LoadLibrary ("imagehlp.dll");
796 DWORD headersum;
797 DWORD checksum;
799 dos_header = (PIMAGE_DOS_HEADER) out_file.file_base;
800 nt_header = (PIMAGE_NT_HEADERS) ((char *) dos_header + dos_header->e_lfanew);
802 nt_header->OptionalHeader.CheckSum = 0;
803 // nt_header->FileHeader.TimeDateStamp = time (NULL);
804 // dos_header->e_cp = size / 512;
805 // nt_header->OptionalHeader.SizeOfImage = size;
807 pfnCheckSumMappedFile = (void *) GetProcAddress (hImagehelp, "CheckSumMappedFile");
808 if (pfnCheckSumMappedFile)
810 // nt_header->FileHeader.TimeDateStamp = time (NULL);
811 pfnCheckSumMappedFile (out_file.file_base,
812 out_file.size,
813 &headersum,
814 &checksum);
815 nt_header->OptionalHeader.CheckSum = checksum;
817 FreeLibrary (hImagehelp);
820 close_file_data (&in_file);
821 close_file_data (&out_file);
824 /* eof */