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