custom-buffer-style doc fix
[emacs.git] / src / unexw32.c
blob15aa7263bf8ff50d2bd32a6141fb1b66ae11f1e7
1 /* unexec for GNU Emacs on Windows NT.
2 Copyright (C) 1994, 2001-2016 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 (at
9 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"
25 #include "lisp.h"
26 #include "w32common.h"
27 #include "w32.h"
29 #include <stdio.h>
30 #include <fcntl.h>
31 #include <time.h>
32 #include <windows.h>
34 /* Include relevant definitions from IMAGEHLP.H, which can be found
35 in \\win32sdk\mstools\samples\image\include\imagehlp.h. */
37 PIMAGE_NT_HEADERS (__stdcall * pfnCheckSumMappedFile) (LPVOID BaseAddress,
38 DWORD FileLength,
39 LPDWORD HeaderSum,
40 LPDWORD CheckSum);
42 extern BOOL ctrl_c_handler (unsigned long type);
44 extern char my_begdata[];
45 extern char my_begbss[];
46 extern char *my_begbss_static;
48 #include "w32heap.h"
50 /* Basically, our "initialized" flag. */
51 BOOL using_dynamic_heap = FALSE;
53 int open_input_file (file_data *p_file, char *name);
54 int open_output_file (file_data *p_file, char *name, unsigned long size);
55 void close_file_data (file_data *p_file);
57 void get_section_info (file_data *p_file);
58 void copy_executable_and_dump_data (file_data *, file_data *);
59 void dump_bss_and_heap (file_data *p_infile, file_data *p_outfile);
61 /* Cached info about the .data section in the executable. */
62 PIMAGE_SECTION_HEADER data_section;
63 PCHAR data_start = 0;
64 DWORD_PTR data_size = 0;
66 /* Cached info about the .bss section in the executable. */
67 PIMAGE_SECTION_HEADER bss_section;
68 PCHAR bss_start = 0;
69 DWORD_PTR bss_size = 0;
70 DWORD_PTR extra_bss_size = 0;
71 /* bss data that is static might be discontiguous from non-static. */
72 PIMAGE_SECTION_HEADER bss_section_static;
73 PCHAR bss_start_static = 0;
74 DWORD_PTR bss_size_static = 0;
75 DWORD_PTR extra_bss_size_static = 0;
77 /* MinGW64 doesn't add a leading underscore to external symbols,
78 whereas configure.ac sets up LD_SWITCH_SYSTEM_TEMACS to force the
79 entry point at __start, with two underscores. */
80 #ifdef __MINGW64__
81 #define _start __start
82 #endif
84 /* Startup code for running on NT. When we are running as the dumped
85 version, we need to bootstrap our heap and .bss section into our
86 address space before we can actually hand off control to the startup
87 code supplied by NT (primarily because that code relies upon malloc ()). */
88 void
89 _start (void)
91 extern void mainCRTStartup (void);
93 #if 1
94 /* Give us a way to debug problems with crashes on startup when
95 running under the MSVC profiler. */
96 if (GetEnvironmentVariable ("EMACS_DEBUG", NULL, 0) > 0)
97 DebugBreak ();
98 #endif
100 /* Cache system info, e.g., the NT page size. */
101 cache_system_info ();
103 /* Grab our malloc arena space now, before CRT starts up. */
104 init_heap ();
106 /* This prevents ctrl-c's in shells running while we're suspended from
107 having us exit. */
108 SetConsoleCtrlHandler ((PHANDLER_ROUTINE) ctrl_c_handler, TRUE);
110 /* Prevent Emacs from being locked up (eg. in batch mode) when
111 accessing devices that aren't mounted (eg. removable media drives). */
112 SetErrorMode (SEM_FAILCRITICALERRORS);
113 mainCRTStartup ();
117 /* File handling. */
119 /* Implementation note: this and the next functions work with ANSI
120 codepage encoded file names! */
122 open_input_file (file_data *p_file, char *filename)
124 HANDLE file;
125 HANDLE file_mapping;
126 void *file_base;
127 unsigned long size, upper_size;
129 file = CreateFileA (filename, GENERIC_READ, FILE_SHARE_READ, NULL,
130 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
131 if (file == INVALID_HANDLE_VALUE)
132 return FALSE;
134 size = GetFileSize (file, &upper_size);
135 file_mapping = CreateFileMapping (file, NULL, PAGE_READONLY,
136 0, size, NULL);
137 if (!file_mapping)
138 return FALSE;
140 file_base = MapViewOfFile (file_mapping, FILE_MAP_READ, 0, 0, size);
141 if (file_base == 0)
142 return FALSE;
144 p_file->name = filename;
145 p_file->size = size;
146 p_file->file = file;
147 p_file->file_mapping = file_mapping;
148 p_file->file_base = file_base;
150 return TRUE;
154 open_output_file (file_data *p_file, char *filename, unsigned long size)
156 HANDLE file;
157 HANDLE file_mapping;
158 void *file_base;
160 /* We delete any existing FILENAME because loadup.el will create a
161 hard link to it under the name emacs-XX.YY.ZZ.nn.exe. Evidently,
162 overwriting a file on Unix breaks any hard links to it, but that
163 doesn't happen on Windows. If we don't delete the file before
164 creating it, all the emacs-XX.YY.ZZ.nn.exe end up being hard
165 links to the same file, which defeats the purpose of these hard
166 links: being able to run previous builds. */
167 DeleteFileA (filename);
168 file = CreateFileA (filename, GENERIC_READ | GENERIC_WRITE, 0, NULL,
169 CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
170 if (file == INVALID_HANDLE_VALUE)
171 return FALSE;
173 file_mapping = CreateFileMapping (file, NULL, PAGE_READWRITE,
174 0, size, NULL);
175 if (!file_mapping)
176 return FALSE;
178 file_base = MapViewOfFile (file_mapping, FILE_MAP_WRITE, 0, 0, size);
179 if (file_base == 0)
180 return FALSE;
182 p_file->name = filename;
183 p_file->size = size;
184 p_file->file = file;
185 p_file->file_mapping = file_mapping;
186 p_file->file_base = file_base;
188 return TRUE;
191 /* Close the system structures associated with the given file. */
192 void
193 close_file_data (file_data *p_file)
195 UnmapViewOfFile (p_file->file_base);
196 CloseHandle (p_file->file_mapping);
197 /* For the case of output files, set final size. */
198 SetFilePointer (p_file->file, p_file->size, NULL, FILE_BEGIN);
199 SetEndOfFile (p_file->file);
200 CloseHandle (p_file->file);
204 /* Routines to manipulate NT executable file sections. */
206 /* Return pointer to section header for named section. */
207 IMAGE_SECTION_HEADER *
208 find_section (char * name, IMAGE_NT_HEADERS * nt_header)
210 PIMAGE_SECTION_HEADER section;
211 int i;
213 section = IMAGE_FIRST_SECTION (nt_header);
215 for (i = 0; i < nt_header->FileHeader.NumberOfSections; i++)
217 if (strcmp (section->Name, name) == 0)
218 return section;
219 section++;
221 return NULL;
224 /* Return pointer to section header for section containing the given
225 relative virtual address. */
226 IMAGE_SECTION_HEADER *
227 rva_to_section (DWORD_PTR rva, IMAGE_NT_HEADERS * nt_header)
229 PIMAGE_SECTION_HEADER section;
230 int i;
232 section = IMAGE_FIRST_SECTION (nt_header);
234 for (i = 0; i < nt_header->FileHeader.NumberOfSections; i++)
236 /* Some linkers (eg. the NT SDK linker I believe) swapped the
237 meaning of these two values - or rather, they ignored
238 VirtualSize entirely and always set it to zero. This affects
239 some very old exes (eg. gzip dated Dec 1993). Since
240 w32_executable_type relies on this function to work reliably,
241 we need to cope with this. */
242 DWORD_PTR real_size = max (section->SizeOfRawData,
243 section->Misc.VirtualSize);
244 if (rva >= section->VirtualAddress
245 && rva < section->VirtualAddress + real_size)
246 return section;
247 section++;
249 return NULL;
252 /* Return pointer to section header for section containing the given
253 offset in its raw data area. */
254 IMAGE_SECTION_HEADER *
255 offset_to_section (DWORD_PTR offset, IMAGE_NT_HEADERS * nt_header)
257 PIMAGE_SECTION_HEADER section;
258 int i;
260 section = IMAGE_FIRST_SECTION (nt_header);
262 for (i = 0; i < nt_header->FileHeader.NumberOfSections; i++)
264 if (offset >= section->PointerToRawData
265 && offset < section->PointerToRawData + section->SizeOfRawData)
266 return section;
267 section++;
269 return NULL;
272 /* Return offset to an object in dst, given offset in src. We assume
273 there is at least one section in both src and dst images, and that
274 the some sections may have been added to dst (after sections in src). */
275 DWORD_PTR
276 relocate_offset (DWORD_PTR offset,
277 IMAGE_NT_HEADERS * src_nt_header,
278 IMAGE_NT_HEADERS * dst_nt_header)
280 PIMAGE_SECTION_HEADER src_section = IMAGE_FIRST_SECTION (src_nt_header);
281 PIMAGE_SECTION_HEADER dst_section = IMAGE_FIRST_SECTION (dst_nt_header);
282 int i = 0;
284 while (offset >= src_section->PointerToRawData)
286 if (offset < src_section->PointerToRawData + src_section->SizeOfRawData)
287 break;
288 i++;
289 if (i == src_nt_header->FileHeader.NumberOfSections)
291 /* Handle offsets after the last section. */
292 dst_section = IMAGE_FIRST_SECTION (dst_nt_header);
293 dst_section += dst_nt_header->FileHeader.NumberOfSections - 1;
294 while (dst_section->PointerToRawData == 0)
295 dst_section--;
296 while (src_section->PointerToRawData == 0)
297 src_section--;
298 return offset
299 + (dst_section->PointerToRawData + dst_section->SizeOfRawData)
300 - (src_section->PointerToRawData + src_section->SizeOfRawData);
302 src_section++;
303 dst_section++;
305 return offset +
306 (dst_section->PointerToRawData - src_section->PointerToRawData);
309 #define OFFSET_TO_RVA(offset, section) \
310 ((section)->VirtualAddress + ((DWORD_PTR)(offset) - (section)->PointerToRawData))
312 #define RVA_TO_OFFSET(rva, section) \
313 ((section)->PointerToRawData + ((DWORD_PTR)(rva) - (section)->VirtualAddress))
315 #define RVA_TO_SECTION_OFFSET(rva, section) \
316 ((DWORD_PTR)(rva) - (section)->VirtualAddress)
318 /* Convert address in executing image to RVA. */
319 #define PTR_TO_RVA(ptr) ((DWORD_PTR)(ptr) - (DWORD_PTR) GetModuleHandle (NULL))
321 #define RVA_TO_PTR(var,section,filedata) \
322 ((unsigned char *)(RVA_TO_OFFSET (var,section) + (filedata).file_base))
324 #define PTR_TO_OFFSET(ptr, pfile_data) \
325 ((unsigned char *)(ptr) - (pfile_data)->file_base)
327 #define OFFSET_TO_PTR(offset, pfile_data) \
328 ((pfile_data)->file_base + (DWORD_PTR)(offset))
331 /* Flip through the executable and cache the info necessary for dumping. */
332 void
333 get_section_info (file_data *p_infile)
335 PIMAGE_DOS_HEADER dos_header;
336 PIMAGE_NT_HEADERS nt_header;
337 int overlap;
339 dos_header = (PIMAGE_DOS_HEADER) p_infile->file_base;
340 if (dos_header->e_magic != IMAGE_DOS_SIGNATURE)
342 printf ("Unknown EXE header in %s...bailing.\n", p_infile->name);
343 exit (1);
345 nt_header = (PIMAGE_NT_HEADERS) (((DWORD_PTR) dos_header) +
346 dos_header->e_lfanew);
347 if (nt_header == NULL)
349 printf ("Failed to find IMAGE_NT_HEADER in %s...bailing.\n",
350 p_infile->name);
351 exit (1);
354 /* Check the NT header signature ... */
355 if (nt_header->Signature != IMAGE_NT_SIGNATURE)
357 printf ("Invalid IMAGE_NT_SIGNATURE 0x%x in %s...bailing.\n",
358 nt_header->Signature, p_infile->name);
359 exit (1);
362 /* Locate the ".data" and ".bss" sections for Emacs. (Note that the
363 actual section names are probably different from these, and might
364 actually be the same section.)
366 We do this as follows: first we determine the virtual address
367 ranges in this process for the data and bss variables that we wish
368 to preserve. Then we map these VAs to the section entries in the
369 source image. Finally, we determine the new size of the raw data
370 area for the bss section, so we can make the new image the correct
371 size. */
373 /* We arrange for the Emacs initialized data to be in a separate
374 section if possible, because we cannot rely on my_begdata and
375 my_edata marking out the full extent of the initialized data, at
376 least on the Alpha where the linker freely reorders variables
377 across libraries. If we can arrange for this, all we need to do is
378 find the start and size of the EMDATA section. */
379 data_section = find_section ("EMDATA", nt_header);
380 if (data_section)
382 data_start = (char *) nt_header->OptionalHeader.ImageBase +
383 data_section->VirtualAddress;
384 data_size = data_section->Misc.VirtualSize;
386 else
388 /* Fallback on the old method if compiler doesn't support the
389 data_set #pragma (or its equivalent). */
390 data_start = my_begdata;
391 data_size = my_edata - my_begdata;
392 data_section = rva_to_section (PTR_TO_RVA (my_begdata), nt_header);
393 if (data_section != rva_to_section (PTR_TO_RVA (my_edata), nt_header))
395 printf ("Initialized data is not in a single section...bailing\n");
396 exit (1);
400 /* As noted in lastfile.c, the Alpha (but not the Intel) MSVC linker
401 globally segregates all static and public bss data (ie. across all
402 linked modules, not just per module), so we must take both static
403 and public bss areas into account to determine the true extent of
404 the bss area used by Emacs.
406 To be strictly correct, we dump the static and public bss areas
407 used by Emacs separately if non-overlapping (since otherwise we are
408 dumping bss data belonging to system libraries, eg. the static bss
409 system data on the Alpha). */
411 bss_start = my_begbss;
412 bss_size = my_endbss - my_begbss;
413 bss_section = rva_to_section (PTR_TO_RVA (my_begbss), nt_header);
414 if (bss_section != rva_to_section (PTR_TO_RVA (my_endbss), nt_header))
416 printf ("Uninitialized data is not in a single section...bailing\n");
417 exit (1);
419 /* Compute how much the .bss section's raw data will grow. */
420 extra_bss_size =
421 ROUND_UP (RVA_TO_SECTION_OFFSET (PTR_TO_RVA (my_endbss), bss_section),
422 nt_header->OptionalHeader.FileAlignment)
423 - bss_section->SizeOfRawData;
425 bss_start_static = my_begbss_static;
426 bss_size_static = my_endbss_static - my_begbss_static;
427 bss_section_static = rva_to_section (PTR_TO_RVA (my_begbss_static), nt_header);
428 if (bss_section_static != rva_to_section (PTR_TO_RVA (my_endbss_static), nt_header))
430 printf ("Uninitialized static data is not in a single section...bailing\n");
431 exit (1);
433 /* Compute how much the static .bss section's raw data will grow. */
434 extra_bss_size_static =
435 ROUND_UP (RVA_TO_SECTION_OFFSET (PTR_TO_RVA (my_endbss_static), bss_section_static),
436 nt_header->OptionalHeader.FileAlignment)
437 - bss_section_static->SizeOfRawData;
439 /* Combine the bss sections into one if they overlap. */
440 #ifdef _ALPHA_
441 overlap = 1; /* force all bss data to be dumped */
442 #else
443 overlap = 0;
444 #endif
445 if (bss_start < bss_start_static)
447 if (bss_start_static < bss_start + bss_size)
448 overlap = 1;
450 else
452 if (bss_start < bss_start_static + bss_size_static)
453 overlap = 1;
455 if (overlap)
457 if (bss_section != bss_section_static)
459 printf ("BSS data not in a single section...bailing\n");
460 exit (1);
462 bss_start = min (bss_start, bss_start_static);
463 bss_size = max (my_endbss, my_endbss_static) - bss_start;
464 bss_section_static = 0;
465 extra_bss_size_static = 0;
470 /* The dump routines. */
472 void
473 copy_executable_and_dump_data (file_data *p_infile,
474 file_data *p_outfile)
476 unsigned char *dst, *dst_save;
477 PIMAGE_DOS_HEADER dos_header;
478 PIMAGE_NT_HEADERS nt_header;
479 PIMAGE_NT_HEADERS dst_nt_header;
480 PIMAGE_SECTION_HEADER section;
481 PIMAGE_SECTION_HEADER dst_section;
482 DWORD_PTR offset;
483 int i;
484 int be_verbose = GetEnvironmentVariable ("DEBUG_DUMP", NULL, 0) > 0;
486 #define COPY_CHUNK(message, src, size, verbose) \
487 do { \
488 unsigned char *s = (void *)(src); \
489 unsigned long count = (size); \
490 if (verbose) \
492 printf ("%s\n", (message)); \
493 printf ("\t0x%08x Offset in input file.\n", s - p_infile->file_base); \
494 printf ("\t0x%08x Offset in output file.\n", dst - p_outfile->file_base); \
495 printf ("\t0x%08x Size in bytes.\n", count); \
497 memcpy (dst, s, count); \
498 dst += count; \
499 } while (0)
501 #define COPY_PROC_CHUNK(message, src, size, verbose) \
502 do { \
503 unsigned char *s = (void *)(src); \
504 unsigned long count = (size); \
505 if (verbose) \
507 printf ("%s\n", (message)); \
508 printf ("\t0x%p Address in process.\n", s); \
509 printf ("\t0x%p Base output file.\n", p_outfile->file_base); \
510 printf ("\t0x%p Offset in output file.\n", dst - p_outfile->file_base); \
511 printf ("\t0x%p Address in output file.\n", dst); \
512 printf ("\t0x%p Size in bytes.\n", count); \
514 memcpy (dst, s, count); \
515 dst += count; \
516 } while (0)
518 #define DST_TO_OFFSET() PTR_TO_OFFSET (dst, p_outfile)
519 #define ROUND_UP_DST(align) \
520 (dst = p_outfile->file_base + ROUND_UP (DST_TO_OFFSET (), (align)))
521 #define ROUND_UP_DST_AND_ZERO(align) \
522 do { \
523 unsigned char *newdst = p_outfile->file_base \
524 + ROUND_UP (DST_TO_OFFSET (), (align)); \
525 /* Zero the alignment slop; it may actually initialize real data. */ \
526 memset (dst, 0, newdst - dst); \
527 dst = newdst; \
528 } while (0)
530 /* Copy the source image sequentially, ie. section by section after
531 copying the headers and section table, to simplify the process of
532 dumping the raw data for the bss and heap sections.
534 Note that dst is updated implicitly by each COPY_CHUNK. */
536 dos_header = (PIMAGE_DOS_HEADER) p_infile->file_base;
537 nt_header = (PIMAGE_NT_HEADERS) (((DWORD_PTR) dos_header) +
538 dos_header->e_lfanew);
539 section = IMAGE_FIRST_SECTION (nt_header);
541 dst = (unsigned char *) p_outfile->file_base;
543 COPY_CHUNK ("Copying DOS header...", dos_header,
544 (DWORD_PTR) nt_header - (DWORD_PTR) dos_header, be_verbose);
545 dst_nt_header = (PIMAGE_NT_HEADERS) dst;
546 COPY_CHUNK ("Copying NT header...", nt_header,
547 (DWORD_PTR) section - (DWORD_PTR) nt_header, be_verbose);
548 dst_section = (PIMAGE_SECTION_HEADER) dst;
549 COPY_CHUNK ("Copying section table...", section,
550 nt_header->FileHeader.NumberOfSections * sizeof (*section),
551 be_verbose);
553 /* Align the first section's raw data area, and set the header size
554 field accordingly. */
555 ROUND_UP_DST_AND_ZERO (dst_nt_header->OptionalHeader.FileAlignment);
556 dst_nt_header->OptionalHeader.SizeOfHeaders = DST_TO_OFFSET ();
558 for (i = 0; i < nt_header->FileHeader.NumberOfSections; i++)
560 char msg[100];
561 /* Windows section names are fixed 8-char strings, only
562 zero-terminated if the name is shorter than 8 characters. */
563 sprintf (msg, "Copying raw data for %.8s...", section->Name);
565 dst_save = dst;
567 /* Update the file-relative offset for this section's raw data (if
568 it has any) in case things have been relocated; we will update
569 the other offsets below once we know where everything is. */
570 if (dst_section->PointerToRawData)
571 dst_section->PointerToRawData = DST_TO_OFFSET ();
573 /* Can always copy the original raw data. */
574 COPY_CHUNK
575 (msg, OFFSET_TO_PTR (section->PointerToRawData, p_infile),
576 section->SizeOfRawData, be_verbose);
577 /* Ensure alignment slop is zeroed. */
578 ROUND_UP_DST_AND_ZERO (dst_nt_header->OptionalHeader.FileAlignment);
580 /* Note that various sections below may be aliases. */
581 if (section == data_section)
583 dst = dst_save
584 + RVA_TO_SECTION_OFFSET (PTR_TO_RVA (data_start), dst_section);
585 COPY_PROC_CHUNK ("Dumping initialized data...",
586 data_start, data_size, be_verbose);
587 dst = dst_save + dst_section->SizeOfRawData;
589 if (section == bss_section)
591 /* Dump contents of bss variables, adjusting the section's raw
592 data size as necessary. */
593 dst = dst_save
594 + RVA_TO_SECTION_OFFSET (PTR_TO_RVA (bss_start), dst_section);
595 COPY_PROC_CHUNK ("Dumping bss data...", bss_start,
596 bss_size, be_verbose);
597 ROUND_UP_DST (dst_nt_header->OptionalHeader.FileAlignment);
598 dst_section->PointerToRawData = PTR_TO_OFFSET (dst_save, p_outfile);
599 /* Determine new size of raw data area. */
600 dst = max (dst, dst_save + dst_section->SizeOfRawData);
601 dst_section->SizeOfRawData = dst - dst_save;
602 dst_section->Characteristics &= ~IMAGE_SCN_CNT_UNINITIALIZED_DATA;
603 dst_section->Characteristics |= IMAGE_SCN_CNT_INITIALIZED_DATA;
605 if (section == bss_section_static)
607 /* Dump contents of static bss variables, adjusting the
608 section's raw data size as necessary. */
609 dst = dst_save
610 + RVA_TO_SECTION_OFFSET (PTR_TO_RVA (bss_start_static), dst_section);
611 COPY_PROC_CHUNK ("Dumping static bss data...", bss_start_static,
612 bss_size_static, be_verbose);
613 ROUND_UP_DST (dst_nt_header->OptionalHeader.FileAlignment);
614 dst_section->PointerToRawData = PTR_TO_OFFSET (dst_save, p_outfile);
615 /* Determine new size of raw data area. */
616 dst = max (dst, dst_save + dst_section->SizeOfRawData);
617 dst_section->SizeOfRawData = dst - dst_save;
618 dst_section->Characteristics &= ~IMAGE_SCN_CNT_UNINITIALIZED_DATA;
619 dst_section->Characteristics |= IMAGE_SCN_CNT_INITIALIZED_DATA;
622 /* Align the section's raw data area. */
623 ROUND_UP_DST (dst_nt_header->OptionalHeader.FileAlignment);
625 section++;
626 dst_section++;
629 /* Copy remainder of source image. */
631 section--;
632 while (section->PointerToRawData == 0);
633 offset = ROUND_UP (section->PointerToRawData + section->SizeOfRawData,
634 nt_header->OptionalHeader.FileAlignment);
635 COPY_CHUNK
636 ("Copying remainder of executable...",
637 OFFSET_TO_PTR (offset, p_infile),
638 p_infile->size - offset, be_verbose);
640 /* Final size for new image. */
641 p_outfile->size = DST_TO_OFFSET ();
643 /* Now patch up remaining file-relative offsets. */
644 section = IMAGE_FIRST_SECTION (nt_header);
645 dst_section = IMAGE_FIRST_SECTION (dst_nt_header);
647 #define ADJUST_OFFSET(var) \
648 do { \
649 if ((var) != 0) \
650 (var) = relocate_offset ((var), nt_header, dst_nt_header); \
651 } while (0)
653 dst_nt_header->OptionalHeader.SizeOfInitializedData = 0;
654 dst_nt_header->OptionalHeader.SizeOfUninitializedData = 0;
655 for (i = 0; i < dst_nt_header->FileHeader.NumberOfSections; i++)
657 /* Recompute data sizes for completeness. */
658 if (dst_section[i].Characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA)
659 dst_nt_header->OptionalHeader.SizeOfInitializedData +=
660 ROUND_UP (dst_section[i].Misc.VirtualSize, dst_nt_header->OptionalHeader.FileAlignment);
661 else if (dst_section[i].Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA)
662 dst_nt_header->OptionalHeader.SizeOfUninitializedData +=
663 ROUND_UP (dst_section[i].Misc.VirtualSize, dst_nt_header->OptionalHeader.FileAlignment);
665 ADJUST_OFFSET (dst_section[i].PointerToLinenumbers);
668 ADJUST_OFFSET (dst_nt_header->FileHeader.PointerToSymbolTable);
670 /* Update offsets in debug directory entries. */
672 IMAGE_DATA_DIRECTORY debug_dir =
673 dst_nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG];
674 PIMAGE_DEBUG_DIRECTORY debug_entry;
676 section = rva_to_section (debug_dir.VirtualAddress, dst_nt_header);
677 if (section)
679 debug_entry = (PIMAGE_DEBUG_DIRECTORY)
680 (RVA_TO_OFFSET (debug_dir.VirtualAddress, section) + p_outfile->file_base);
681 debug_dir.Size /= sizeof (IMAGE_DEBUG_DIRECTORY);
683 for (i = 0; i < debug_dir.Size; i++, debug_entry++)
684 ADJUST_OFFSET (debug_entry->PointerToRawData);
690 /* Dump out .data and .bss sections into a new executable. */
691 void
692 unexec (const char *new_name, const char *old_name)
694 file_data in_file, out_file;
695 char out_filename[MAX_PATH], in_filename[MAX_PATH], new_name_a[MAX_PATH];
696 unsigned long size;
697 char *p;
698 char *q;
700 /* Ignore old_name, and get our actual location from the OS. */
701 if (!GetModuleFileNameA (NULL, in_filename, MAX_PATH))
702 abort ();
704 /* Can't use dostounix_filename here, since that needs its file name
705 argument encoded in UTF-8. */
706 for (p = in_filename; *p; p = CharNextA (p))
707 if (*p == '\\')
708 *p = '/';
710 strcpy (out_filename, in_filename);
711 filename_to_ansi (new_name, new_name_a);
713 /* Change the base of the output filename to match the requested name. */
714 if ((p = strrchr (out_filename, '/')) == NULL)
715 abort ();
716 /* The filenames have already been expanded, and will be in Unix
717 format, so it is safe to expect an absolute name. */
718 if ((q = strrchr (new_name_a, '/')) == NULL)
719 abort ();
720 strcpy (p, q);
722 #ifdef ENABLE_CHECKING
723 report_temacs_memory_usage ();
724 #endif
726 /* Make sure that the output filename has the ".exe" extension...patch
727 it up if not. */
728 p = out_filename + strlen (out_filename) - 4;
729 if (strcmp (p, ".exe"))
730 strcat (out_filename, ".exe");
732 printf ("Dumping from %s\n", in_filename);
733 printf (" to %s\n", out_filename);
735 /* Open the undumped executable file. */
736 if (!open_input_file (&in_file, in_filename))
738 printf ("Failed to open %s (%d)...bailing.\n",
739 in_filename, GetLastError ());
740 exit (1);
743 /* Get the interesting section info, like start and size of .bss... */
744 get_section_info (&in_file);
746 /* The size of the dumped executable is the size of the original
747 executable plus the size of the heap and the size of the .bss section. */
748 size = in_file.size +
749 extra_bss_size +
750 extra_bss_size_static;
751 if (!open_output_file (&out_file, out_filename, size))
753 printf ("Failed to open %s (%d)...bailing.\n",
754 out_filename, GetLastError ());
755 exit (1);
758 /* Set the flag (before dumping). */
759 using_dynamic_heap = TRUE;
761 copy_executable_and_dump_data (&in_file, &out_file);
763 /* Unset it because it is plain wrong to keep it after dumping.
764 Malloc can still occur! */
765 using_dynamic_heap = FALSE;
767 /* Patch up header fields; profiler is picky about this. */
769 PIMAGE_DOS_HEADER dos_header;
770 PIMAGE_NT_HEADERS nt_header;
771 HANDLE hImagehelp = LoadLibrary ("imagehlp.dll");
772 DWORD headersum;
773 DWORD checksum;
775 dos_header = (PIMAGE_DOS_HEADER) out_file.file_base;
776 nt_header = (PIMAGE_NT_HEADERS) ((char *) dos_header + dos_header->e_lfanew);
778 nt_header->OptionalHeader.CheckSum = 0;
779 // nt_header->FileHeader.TimeDateStamp = time (NULL);
780 // dos_header->e_cp = size / 512;
781 // nt_header->OptionalHeader.SizeOfImage = size;
783 pfnCheckSumMappedFile = (void *) GetProcAddress (hImagehelp, "CheckSumMappedFile");
784 if (pfnCheckSumMappedFile)
786 // nt_header->FileHeader.TimeDateStamp = time (NULL);
787 pfnCheckSumMappedFile (out_file.file_base,
788 out_file.size,
789 &headersum,
790 &checksum);
791 nt_header->OptionalHeader.CheckSum = checksum;
793 FreeLibrary (hImagehelp);
796 close_file_data (&in_file);
797 close_file_data (&out_file);
800 /* eof */