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