unexw32.c 22.9 KB
Newer Older
1
/* unexec for GNU Emacs on Windows NT.
Paul Eggert's avatar
Paul Eggert committed
2
   Copyright (C) 1994, 2001-2020 Free Software Foundation, Inc.
Karl Heuer's avatar
Karl Heuer committed
3

4
This file is part of GNU Emacs.
Karl Heuer's avatar
Karl Heuer committed
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 9
the Free Software Foundation, either version 3 of the License, or (at
your option) any later version.
Karl Heuer's avatar
Karl Heuer committed
10

11 12 13 14
GNU Emacs is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.
Karl Heuer's avatar
Karl Heuer committed
15

16
You should have received a copy of the GNU General Public License
17
along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.  */
Karl Heuer's avatar
Karl Heuer committed
18

19
/*
Karl Heuer's avatar
Karl Heuer committed
20 21 22
   Geoff Voelker (voelker@cs.washington.edu)                         8-12-94
*/

Geoff Voelker's avatar
Geoff Voelker committed
23
#include <config.h>
24
#include "unexec.h"
25
#include "lisp.h"
Daniel Colascione's avatar
Daniel Colascione committed
26
#include "w32common.h"
27
#include "w32.h"
Geoff Voelker's avatar
Geoff Voelker committed
28

Karl Heuer's avatar
Karl Heuer committed
29 30
#include <stdio.h>
#include <fcntl.h>
Geoff Voelker's avatar
Geoff Voelker committed
31
#include <time.h>
Karl Heuer's avatar
Karl Heuer committed
32 33
#include <windows.h>

Geoff Voelker's avatar
Geoff Voelker committed
34 35
/* Include relevant definitions from IMAGEHLP.H, which can be found
   in \\win32sdk\mstools\samples\image\include\imagehlp.h. */
Karl Heuer's avatar
Karl Heuer committed
36

37 38 39 40
PIMAGE_NT_HEADERS (__stdcall * pfnCheckSumMappedFile) (LPVOID BaseAddress,
						       DWORD FileLength,
						       LPDWORD HeaderSum,
						       LPDWORD CheckSum);
Karl Heuer's avatar
Karl Heuer committed
41

Geoff Voelker's avatar
Geoff Voelker committed
42 43
extern char my_begdata[];
extern char my_begbss[];
44
extern char *my_begbss_static;
Karl Heuer's avatar
Karl Heuer committed
45

Geoff Voelker's avatar
Geoff Voelker committed
46
#include "w32heap.h"
47

Karl Heuer's avatar
Karl Heuer committed
48
void get_section_info (file_data *p_file);
49
void copy_executable_and_dump_data (file_data *, file_data *);
Karl Heuer's avatar
Karl Heuer committed
50 51 52
void dump_bss_and_heap (file_data *p_infile, file_data *p_outfile);

/* Cached info about the .data section in the executable.  */
53
PIMAGE_SECTION_HEADER data_section;
Andrew Innes's avatar
Andrew Innes committed
54
PCHAR  data_start = 0;
55
DWORD_PTR  data_size = 0;
Karl Heuer's avatar
Karl Heuer committed
56 57

/* Cached info about the .bss section in the executable.  */
58
PIMAGE_SECTION_HEADER bss_section;
Andrew Innes's avatar
Andrew Innes committed
59
PCHAR  bss_start = 0;
60 61
DWORD_PTR  bss_size = 0;
DWORD_PTR  extra_bss_size = 0;
62 63
/* bss data that is static might be discontiguous from non-static.  */
PIMAGE_SECTION_HEADER bss_section_static;
Andrew Innes's avatar
Andrew Innes committed
64
PCHAR  bss_start_static = 0;
65 66
DWORD_PTR  bss_size_static = 0;
DWORD_PTR  extra_bss_size_static = 0;
67

Karl Heuer's avatar
Karl Heuer committed
68 69
/* File handling.  */

70 71
/* Implementation note: this and the next functions work with ANSI
   codepage encoded file names!  */
Karl Heuer's avatar
Karl Heuer committed
72

Geoff Voelker's avatar
Geoff Voelker committed
73
int
Karl Heuer's avatar
Karl Heuer committed
74 75 76 77 78
open_output_file (file_data *p_file, char *filename, unsigned long size)
{
  HANDLE file;
  HANDLE file_mapping;
  void  *file_base;
79

80 81 82 83 84 85 86
  /* We delete any existing FILENAME because loadup.el will create a
     hard link to it under the name emacs-XX.YY.ZZ.nn.exe.  Evidently,
     overwriting a file on Unix breaks any hard links to it, but that
     doesn't happen on Windows.  If we don't delete the file before
     creating it, all the emacs-XX.YY.ZZ.nn.exe end up being hard
     links to the same file, which defeats the purpose of these hard
     links: being able to run previous builds.  */
87 88 89
  DeleteFileA (filename);
  file = CreateFileA (filename, GENERIC_READ | GENERIC_WRITE, 0, NULL,
		      CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
90
  if (file == INVALID_HANDLE_VALUE)
Geoff Voelker's avatar
Geoff Voelker committed
91 92
    return FALSE;

93
  file_mapping = CreateFileMapping (file, NULL, PAGE_READWRITE,
Karl Heuer's avatar
Karl Heuer committed
94
				    0, size, NULL);
95
  if (!file_mapping)
Geoff Voelker's avatar
Geoff Voelker committed
96
    return FALSE;
97

Karl Heuer's avatar
Karl Heuer committed
98
  file_base = MapViewOfFile (file_mapping, FILE_MAP_WRITE, 0, 0, size);
99
  if (file_base == 0)
Geoff Voelker's avatar
Geoff Voelker committed
100
    return FALSE;
101

Karl Heuer's avatar
Karl Heuer committed
102 103 104 105 106
  p_file->name = filename;
  p_file->size = size;
  p_file->file = file;
  p_file->file_mapping = file_mapping;
  p_file->file_base = file_base;
Geoff Voelker's avatar
Geoff Voelker committed
107 108

  return TRUE;
Karl Heuer's avatar
Karl Heuer committed
109 110 111 112 113
}


/* Routines to manipulate NT executable file sections.  */

Geoff Voelker's avatar
Geoff Voelker committed
114 115
/* Return pointer to section header for named section. */
IMAGE_SECTION_HEADER *
116
find_section (const char * name, IMAGE_NT_HEADERS * nt_header)
Geoff Voelker's avatar
Geoff Voelker committed
117 118 119 120 121 122 123 124
{
  PIMAGE_SECTION_HEADER section;
  int i;

  section = IMAGE_FIRST_SECTION (nt_header);

  for (i = 0; i < nt_header->FileHeader.NumberOfSections; i++)
    {
125
      if (strcmp ((char *)section->Name, name) == 0)
Geoff Voelker's avatar
Geoff Voelker committed
126 127 128 129 130 131
	return section;
      section++;
    }
  return NULL;
}

132
#if 0	/* unused */
133 134
/* Return pointer to section header for section containing the given
   offset in its raw data area. */
135
static IMAGE_SECTION_HEADER *
136
offset_to_section (DWORD_PTR offset, IMAGE_NT_HEADERS * nt_header)
137 138 139 140 141 142 143 144 145 146
{
  PIMAGE_SECTION_HEADER section;
  int i;

  section = IMAGE_FIRST_SECTION (nt_header);

  for (i = 0; i < nt_header->FileHeader.NumberOfSections; i++)
    {
      if (offset >= section->PointerToRawData
	  && offset < section->PointerToRawData + section->SizeOfRawData)
Geoff Voelker's avatar
Geoff Voelker committed
147 148
	return section;
      section++;
Karl Heuer's avatar
Karl Heuer committed
149
    }
Geoff Voelker's avatar
Geoff Voelker committed
150
  return NULL;
Karl Heuer's avatar
Karl Heuer committed
151
}
152
#endif
Karl Heuer's avatar
Karl Heuer committed
153

154 155 156
/* Return offset to an object in dst, given offset in src.  We assume
   there is at least one section in both src and dst images, and that
   the some sections may have been added to dst (after sections in src).  */
157
static DWORD_PTR
158
relocate_offset (DWORD_PTR offset,
159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191
		 IMAGE_NT_HEADERS * src_nt_header,
		 IMAGE_NT_HEADERS * dst_nt_header)
{
  PIMAGE_SECTION_HEADER src_section = IMAGE_FIRST_SECTION (src_nt_header);
  PIMAGE_SECTION_HEADER dst_section = IMAGE_FIRST_SECTION (dst_nt_header);
  int i = 0;

  while (offset >= src_section->PointerToRawData)
    {
      if (offset < src_section->PointerToRawData + src_section->SizeOfRawData)
	break;
      i++;
      if (i == src_nt_header->FileHeader.NumberOfSections)
	{
	  /* Handle offsets after the last section.  */
	  dst_section = IMAGE_FIRST_SECTION (dst_nt_header);
	  dst_section += dst_nt_header->FileHeader.NumberOfSections - 1;
	  while (dst_section->PointerToRawData == 0)
	    dst_section--;
	  while (src_section->PointerToRawData == 0)
	    src_section--;
	  return offset
	    + (dst_section->PointerToRawData + dst_section->SizeOfRawData)
	    - (src_section->PointerToRawData + src_section->SizeOfRawData);
	}
      src_section++;
      dst_section++;
    }
  return offset +
    (dst_section->PointerToRawData - src_section->PointerToRawData);
}

#define RVA_TO_OFFSET(rva, section) \
192
  ((section)->PointerToRawData + ((DWORD_PTR)(rva) - (section)->VirtualAddress))
193 194

#define RVA_TO_SECTION_OFFSET(rva, section) \
195
  ((DWORD_PTR)(rva) - (section)->VirtualAddress)
196 197

/* Convert address in executing image to RVA.  */
198
#define PTR_TO_RVA(ptr) ((DWORD_PTR)(ptr) - (DWORD_PTR) GetModuleHandle (NULL))
199 200

#define PTR_TO_OFFSET(ptr, pfile_data) \
Andrew Innes's avatar
Andrew Innes committed
201
          ((unsigned char *)(ptr) - (pfile_data)->file_base)
202 203

#define OFFSET_TO_PTR(offset, pfile_data) \
204
          ((pfile_data)->file_base + (DWORD_PTR)(offset))
205

206 207 208 209 210 211 212 213
#if 0	/* unused */
#define OFFSET_TO_RVA(offset, section) \
  ((section)->VirtualAddress + ((DWORD_PTR)(offset) - (section)->PointerToRawData))

#define RVA_TO_PTR(var,section,filedata) \
	  ((unsigned char *)(RVA_TO_OFFSET (var,section) + (filedata).file_base))
#endif

Geoff Voelker's avatar
Geoff Voelker committed
214

Karl Heuer's avatar
Karl Heuer committed
215
/* Flip through the executable and cache the info necessary for dumping.  */
Andrew Innes's avatar
Andrew Innes committed
216
void
Karl Heuer's avatar
Karl Heuer committed
217 218 219 220
get_section_info (file_data *p_infile)
{
  PIMAGE_DOS_HEADER dos_header;
  PIMAGE_NT_HEADERS nt_header;
221
  int overlap;
222

Karl Heuer's avatar
Karl Heuer committed
223
  dos_header = (PIMAGE_DOS_HEADER) p_infile->file_base;
224
  if (dos_header->e_magic != IMAGE_DOS_SIGNATURE)
Karl Heuer's avatar
Karl Heuer committed
225 226 227 228
    {
      printf ("Unknown EXE header in %s...bailing.\n", p_infile->name);
      exit (1);
    }
229
  nt_header = (PIMAGE_NT_HEADERS) (((DWORD_PTR) dos_header) +
Karl Heuer's avatar
Karl Heuer committed
230
				   dos_header->e_lfanew);
231
  if (nt_header == NULL)
Karl Heuer's avatar
Karl Heuer committed
232
    {
233
      printf ("Failed to find IMAGE_NT_HEADER in %s...bailing.\n",
Karl Heuer's avatar
Karl Heuer committed
234 235 236 237 238
	     p_infile->name);
      exit (1);
    }

  /* Check the NT header signature ...  */
239
  if (nt_header->Signature != IMAGE_NT_SIGNATURE)
Karl Heuer's avatar
Karl Heuer committed
240
    {
241
      printf ("Invalid IMAGE_NT_SIGNATURE 0x%lx in %s...bailing.\n",
Karl Heuer's avatar
Karl Heuer committed
242
	      nt_header->Signature, p_infile->name);
243
      exit (1);
Karl Heuer's avatar
Karl Heuer committed
244 245
    }

246 247 248 249 250 251 252 253 254 255 256
  /* Locate the ".data" and ".bss" sections for Emacs.  (Note that the
     actual section names are probably different from these, and might
     actually be the same section.)

     We do this as follows: first we determine the virtual address
     ranges in this process for the data and bss variables that we wish
     to preserve.  Then we map these VAs to the section entries in the
     source image.  Finally, we determine the new size of the raw data
     area for the bss section, so we can make the new image the correct
     size.  */

257 258 259 260 261 262 263 264
  /* We arrange for the Emacs initialized data to be in a separate
     section if possible, because we cannot rely on my_begdata and
     my_edata marking out the full extent of the initialized data, at
     least on the Alpha where the linker freely reorders variables
     across libraries.  If we can arrange for this, all we need to do is
     find the start and size of the EMDATA section.  */
  data_section = find_section ("EMDATA", nt_header);
  if (data_section)
Karl Heuer's avatar
Karl Heuer committed
265
    {
266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281
      data_start = (char *) nt_header->OptionalHeader.ImageBase +
	data_section->VirtualAddress;
      data_size = data_section->Misc.VirtualSize;
    }
  else
    {
      /* Fallback on the old method if compiler doesn't support the
         data_set #pragma (or its equivalent).  */
      data_start = my_begdata;
      data_size = my_edata - my_begdata;
      data_section = rva_to_section (PTR_TO_RVA (my_begdata), nt_header);
      if (data_section != rva_to_section (PTR_TO_RVA (my_edata), nt_header))
	{
	  printf ("Initialized data is not in a single section...bailing\n");
	  exit (1);
	}
282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323
    }

  /* As noted in lastfile.c, the Alpha (but not the Intel) MSVC linker
     globally segregates all static and public bss data (ie. across all
     linked modules, not just per module), so we must take both static
     and public bss areas into account to determine the true extent of
     the bss area used by Emacs.

     To be strictly correct, we dump the static and public bss areas
     used by Emacs separately if non-overlapping (since otherwise we are
     dumping bss data belonging to system libraries, eg. the static bss
     system data on the Alpha).  */

  bss_start = my_begbss;
  bss_size = my_endbss - my_begbss;
  bss_section = rva_to_section (PTR_TO_RVA (my_begbss), nt_header);
  if (bss_section != rva_to_section (PTR_TO_RVA (my_endbss), nt_header))
    {
      printf ("Uninitialized data is not in a single section...bailing\n");
      exit (1);
    }
  /* Compute how much the .bss section's raw data will grow.  */
  extra_bss_size =
    ROUND_UP (RVA_TO_SECTION_OFFSET (PTR_TO_RVA (my_endbss), bss_section),
	      nt_header->OptionalHeader.FileAlignment)
    - bss_section->SizeOfRawData;

  bss_start_static = my_begbss_static;
  bss_size_static = my_endbss_static - my_begbss_static;
  bss_section_static = rva_to_section (PTR_TO_RVA (my_begbss_static), nt_header);
  if (bss_section_static != rva_to_section (PTR_TO_RVA (my_endbss_static), nt_header))
    {
      printf ("Uninitialized static data is not in a single section...bailing\n");
      exit (1);
    }
  /* Compute how much the static .bss section's raw data will grow.  */
  extra_bss_size_static =
    ROUND_UP (RVA_TO_SECTION_OFFSET (PTR_TO_RVA (my_endbss_static), bss_section_static),
	      nt_header->OptionalHeader.FileAlignment)
    - bss_section_static->SizeOfRawData;

  /* Combine the bss sections into one if they overlap.  */
324 325 326
#ifdef _ALPHA_
  overlap = 1;			/* force all bss data to be dumped */
#else
327
  overlap = 0;
328
#endif
329 330 331 332 333 334 335 336 337 338 339 340 341
  if (bss_start < bss_start_static)
    {
      if (bss_start_static < bss_start + bss_size)
	overlap = 1;
    }
  else
    {
      if (bss_start < bss_start_static + bss_size_static)
	overlap = 1;
    }
  if (overlap)
    {
      if (bss_section != bss_section_static)
Karl Heuer's avatar
Karl Heuer committed
342
	{
343 344
	  printf ("BSS data not in a single section...bailing\n");
	  exit (1);
Karl Heuer's avatar
Karl Heuer committed
345
	}
346 347 348
      bss_start = min (bss_start, bss_start_static);
      bss_size = max (my_endbss, my_endbss_static) - bss_start;
      bss_section_static = 0;
349
      extra_bss_size = max (extra_bss_size, extra_bss_size_static);
350 351 352 353
      extra_bss_size_static = 0;
    }
}

354
/* Format to print a DWORD_PTR value.  */
355
#if defined MINGW_W64 && defined _WIN64
356 357 358 359
# define pDWP  "16llx"
#else
# define pDWP  "08lx"
#endif
360 361 362

/* The dump routines.  */

Andrew Innes's avatar
Andrew Innes committed
363
void
364
copy_executable_and_dump_data (file_data *p_infile,
365 366 367 368 369 370 371 372
			       file_data *p_outfile)
{
  unsigned char *dst, *dst_save;
  PIMAGE_DOS_HEADER dos_header;
  PIMAGE_NT_HEADERS nt_header;
  PIMAGE_NT_HEADERS dst_nt_header;
  PIMAGE_SECTION_HEADER section;
  PIMAGE_SECTION_HEADER dst_section;
373
  DWORD_PTR offset;
374
  int i;
375
  int be_verbose = GetEnvironmentVariable ("DEBUG_DUMP", NULL, 0) > 0;
376

377
#define COPY_CHUNK(message, src, size, verbose)					\
378 379
  do {										\
    unsigned char *s = (void *)(src);						\
380
    DWORD_PTR count = (size);						\
381 382 383
    if (verbose)								\
      {										\
	printf ("%s\n", (message));						\
384 385
	printf ("\t0x%"pDWP" Offset in input file.\n", (DWORD_PTR)(s - p_infile->file_base)); \
	printf ("\t0x%"pDWP" Offset in output file.\n", (DWORD_PTR)(dst - p_outfile->file_base)); \
386
	printf ("\t0x%"pDWP" Size in bytes.\n", count);				\
387
      }										\
388 389 390 391
    memcpy (dst, s, count);							\
    dst += count;								\
  } while (0)

392
#define COPY_PROC_CHUNK(message, src, size, verbose)				\
393 394
  do {										\
    unsigned char *s = (void *)(src);						\
395
    DWORD_PTR count = (size);						\
396 397 398
    if (verbose)								\
      {										\
	printf ("%s\n", (message));						\
399 400
	printf ("\t0x%p Address in process.\n", s);				\
	printf ("\t0x%p Base       output file.\n", p_outfile->file_base); \
401
	printf ("\t0x%"pDWP" Offset  in output file.\n", (DWORD_PTR)(dst - p_outfile->file_base)); \
402
	printf ("\t0x%p Address in output file.\n", dst); \
403
	printf ("\t0x%"pDWP" Size in bytes.\n", count);				\
404
      }										\
405 406 407 408 409 410 411
    memcpy (dst, s, count);							\
    dst += count;								\
  } while (0)

#define DST_TO_OFFSET()  PTR_TO_OFFSET (dst, p_outfile)
#define ROUND_UP_DST(align) \
  (dst = p_outfile->file_base + ROUND_UP (DST_TO_OFFSET (), (align)))
412 413 414 415 416 417 418 419
#define ROUND_UP_DST_AND_ZERO(align)						\
  do {										\
    unsigned char *newdst = p_outfile->file_base				\
      + ROUND_UP (DST_TO_OFFSET (), (align));					\
    /* Zero the alignment slop; it may actually initialize real data.  */	\
    memset (dst, 0, newdst - dst);						\
    dst = newdst;								\
  } while (0)
420 421 422 423 424 425 426 427

  /* Copy the source image sequentially, ie. section by section after
     copying the headers and section table, to simplify the process of
     dumping the raw data for the bss and heap sections.

     Note that dst is updated implicitly by each COPY_CHUNK.  */

  dos_header = (PIMAGE_DOS_HEADER) p_infile->file_base;
428
  nt_header = (PIMAGE_NT_HEADERS) (((DWORD_PTR) dos_header) +
429 430
				   dos_header->e_lfanew);
  section = IMAGE_FIRST_SECTION (nt_header);
431

432 433 434
  dst = (unsigned char *) p_outfile->file_base;

  COPY_CHUNK ("Copying DOS header...", dos_header,
435
	      (DWORD_PTR) nt_header - (DWORD_PTR) dos_header, be_verbose);
436 437
  dst_nt_header = (PIMAGE_NT_HEADERS) dst;
  COPY_CHUNK ("Copying NT header...", nt_header,
438
	      (DWORD_PTR) section - (DWORD_PTR) nt_header, be_verbose);
439 440
  dst_section = (PIMAGE_SECTION_HEADER) dst;
  COPY_CHUNK ("Copying section table...", section,
441 442
	      nt_header->FileHeader.NumberOfSections * sizeof (*section),
	      be_verbose);
443

444 445 446 447 448
  /* Align the first section's raw data area, and set the header size
     field accordingly.  */
  ROUND_UP_DST_AND_ZERO (dst_nt_header->OptionalHeader.FileAlignment);
  dst_nt_header->OptionalHeader.SizeOfHeaders = DST_TO_OFFSET ();

449 450 451
  for (i = 0; i < nt_header->FileHeader.NumberOfSections; i++)
    {
      char msg[100];
452 453 454
      /* Windows section names are fixed 8-char strings, only
	 zero-terminated if the name is shorter than 8 characters.  */
      sprintf (msg, "Copying raw data for %.8s...", section->Name);
455 456 457 458 459 460 461 462 463 464 465 466

      dst_save = dst;

      /* Update the file-relative offset for this section's raw data (if
         it has any) in case things have been relocated; we will update
         the other offsets below once we know where everything is.  */
      if (dst_section->PointerToRawData)
	dst_section->PointerToRawData = DST_TO_OFFSET ();

      /* Can always copy the original raw data.  */
      COPY_CHUNK
	(msg, OFFSET_TO_PTR (section->PointerToRawData, p_infile),
467
	 section->SizeOfRawData, be_verbose);
468 469
      /* Ensure alignment slop is zeroed.  */
      ROUND_UP_DST_AND_ZERO (dst_nt_header->OptionalHeader.FileAlignment);
470 471 472

      /* Note that various sections below may be aliases.  */
      if (section == data_section)
Karl Heuer's avatar
Karl Heuer committed
473
	{
474 475
	  dst = dst_save
	    + RVA_TO_SECTION_OFFSET (PTR_TO_RVA (data_start), dst_section);
476 477
	  COPY_PROC_CHUNK ("Dumping initialized data...",
			   data_start, data_size, be_verbose);
478
	  dst = dst_save + dst_section->SizeOfRawData;
Karl Heuer's avatar
Karl Heuer committed
479
	}
480
      if (section == bss_section)
Geoff Voelker's avatar
Geoff Voelker committed
481
	{
482 483 484 485
	  /* Dump contents of bss variables, adjusting the section's raw
             data size as necessary.  */
	  dst = dst_save
	    + RVA_TO_SECTION_OFFSET (PTR_TO_RVA (bss_start), dst_section);
486 487
	  COPY_PROC_CHUNK ("Dumping bss data...", bss_start,
			   bss_size, be_verbose);
488 489 490 491 492 493 494
	  ROUND_UP_DST (dst_nt_header->OptionalHeader.FileAlignment);
	  dst_section->PointerToRawData = PTR_TO_OFFSET (dst_save, p_outfile);
	  /* Determine new size of raw data area.  */
	  dst = max (dst, dst_save + dst_section->SizeOfRawData);
	  dst_section->SizeOfRawData = dst - dst_save;
	  dst_section->Characteristics &= ~IMAGE_SCN_CNT_UNINITIALIZED_DATA;
	  dst_section->Characteristics |= IMAGE_SCN_CNT_INITIALIZED_DATA;
Geoff Voelker's avatar
Geoff Voelker committed
495
	}
496 497 498 499 500 501
      if (section == bss_section_static)
	{
	  /* Dump contents of static bss variables, adjusting the
             section's raw data size as necessary.  */
	  dst = dst_save
	    + RVA_TO_SECTION_OFFSET (PTR_TO_RVA (bss_start_static), dst_section);
502 503
	  COPY_PROC_CHUNK ("Dumping static bss data...", bss_start_static,
			   bss_size_static, be_verbose);
504 505 506 507 508 509 510 511 512
	  ROUND_UP_DST (dst_nt_header->OptionalHeader.FileAlignment);
	  dst_section->PointerToRawData = PTR_TO_OFFSET (dst_save, p_outfile);
	  /* Determine new size of raw data area.  */
	  dst = max (dst, dst_save + dst_section->SizeOfRawData);
	  dst_section->SizeOfRawData = dst - dst_save;
	  dst_section->Characteristics &= ~IMAGE_SCN_CNT_UNINITIALIZED_DATA;
	  dst_section->Characteristics |= IMAGE_SCN_CNT_INITIALIZED_DATA;
	}

513 514 515
      /* Align the section's raw data area.  */
      ROUND_UP_DST (dst_nt_header->OptionalHeader.FileAlignment);

Karl Heuer's avatar
Karl Heuer committed
516
      section++;
517
      dst_section++;
Karl Heuer's avatar
Karl Heuer committed
518
    }
519

520 521 522 523 524 525 526 527 528
  /* Copy remainder of source image.  */
  do
    section--;
  while (section->PointerToRawData == 0);
  offset = ROUND_UP (section->PointerToRawData + section->SizeOfRawData,
		     nt_header->OptionalHeader.FileAlignment);
  COPY_CHUNK
    ("Copying remainder of executable...",
     OFFSET_TO_PTR (offset, p_infile),
529
     p_infile->size - offset, be_verbose);
530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546

  /* Final size for new image.  */
  p_outfile->size = DST_TO_OFFSET ();

  /* Now patch up remaining file-relative offsets.  */
  section = IMAGE_FIRST_SECTION (nt_header);
  dst_section = IMAGE_FIRST_SECTION (dst_nt_header);

#define ADJUST_OFFSET(var)						\
  do {									\
    if ((var) != 0)							\
      (var) = relocate_offset ((var), nt_header, dst_nt_header);	\
  } while (0)

  dst_nt_header->OptionalHeader.SizeOfInitializedData = 0;
  dst_nt_header->OptionalHeader.SizeOfUninitializedData = 0;
  for (i = 0; i < dst_nt_header->FileHeader.NumberOfSections; i++)
547
    {
548 549 550 551 552 553 554 555 556
      /* Recompute data sizes for completeness.  */
      if (dst_section[i].Characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA)
	dst_nt_header->OptionalHeader.SizeOfInitializedData +=
	  ROUND_UP (dst_section[i].Misc.VirtualSize, dst_nt_header->OptionalHeader.FileAlignment);
      else if (dst_section[i].Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA)
	dst_nt_header->OptionalHeader.SizeOfUninitializedData +=
	  ROUND_UP (dst_section[i].Misc.VirtualSize, dst_nt_header->OptionalHeader.FileAlignment);

      ADJUST_OFFSET (dst_section[i].PointerToLinenumbers);
557
    }
Karl Heuer's avatar
Karl Heuer committed
558

559
  ADJUST_OFFSET (dst_nt_header->FileHeader.PointerToSymbolTable);
Karl Heuer's avatar
Karl Heuer committed
560

561 562 563 564 565
  /* Update offsets in debug directory entries. */
  {
    IMAGE_DATA_DIRECTORY debug_dir =
      dst_nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG];
    PIMAGE_DEBUG_DIRECTORY debug_entry;
Karl Heuer's avatar
Karl Heuer committed
566

567 568 569 570 571 572
    section = rva_to_section (debug_dir.VirtualAddress, dst_nt_header);
    if (section)
      {
	debug_entry = (PIMAGE_DEBUG_DIRECTORY)
	  (RVA_TO_OFFSET (debug_dir.VirtualAddress, section) + p_outfile->file_base);
	debug_dir.Size /= sizeof (IMAGE_DEBUG_DIRECTORY);
Karl Heuer's avatar
Karl Heuer committed
573

574 575 576 577
	for (i = 0; i < debug_dir.Size; i++, debug_entry++)
	  ADJUST_OFFSET (debug_entry->PointerToRawData);
      }
  }
Karl Heuer's avatar
Karl Heuer committed
578 579 580
}


581
/* Dump out .data and .bss sections into a new executable.  */
582
void
583
unexec (const char *new_name, const char *old_name)
584
{
585
  file_data in_file, out_file;
586
  char out_filename[MAX_PATH], in_filename[MAX_PATH], new_name_a[MAX_PATH];
587
  unsigned long size;
Andrew Innes's avatar
Andrew Innes committed
588 589 590 591
  char *p;
  char *q;

  /* Ignore old_name, and get our actual location from the OS.  */
592
  if (!GetModuleFileNameA (NULL, in_filename, MAX_PATH))
Andrew Innes's avatar
Andrew Innes committed
593
    abort ();
594 595 596 597 598 599 600

  /* Can't use dostounix_filename here, since that needs its file name
     argument encoded in UTF-8.  */
  for (p = in_filename; *p; p = CharNextA (p))
    if (*p == '\\')
      *p = '/';

Andrew Innes's avatar
Andrew Innes committed
601
  strcpy (out_filename, in_filename);
602
  filename_to_ansi (new_name, new_name_a);
Andrew Innes's avatar
Andrew Innes committed
603 604 605 606 607 608

  /* Change the base of the output filename to match the requested name.  */
  if ((p = strrchr (out_filename, '/')) == NULL)
    abort ();
  /* The filenames have already been expanded, and will be in Unix
     format, so it is safe to expect an absolute name.  */
609
  if ((q = strrchr (new_name_a, '/')) == NULL)
Andrew Innes's avatar
Andrew Innes committed
610 611
    abort ();
  strcpy (p, q);
612

613 614 615 616
#ifdef ENABLE_CHECKING
  report_temacs_memory_usage ();
#endif

Andrew Innes's avatar
Andrew Innes committed
617 618 619 620
  /* Make sure that the output filename has the ".exe" extension...patch
     it up if not.  */
  p = out_filename + strlen (out_filename) - 4;
  if (strcmp (p, ".exe"))
621
    strcat (out_filename, ".exe");
Karl Heuer's avatar
Karl Heuer committed
622

623 624
  printf ("Dumping from %s\n", in_filename);
  printf ("          to %s\n", out_filename);
Karl Heuer's avatar
Karl Heuer committed
625

626 627 628
  /* Open the undumped executable file.  */
  if (!open_input_file (&in_file, in_filename))
    {
629
      printf ("Failed to open %s (%lu)...bailing.\n",
630 631 632
	      in_filename, GetLastError ());
      exit (1);
    }
Karl Heuer's avatar
Karl Heuer committed
633

634 635
  /* Get the interesting section info, like start and size of .bss...  */
  get_section_info (&in_file);
Karl Heuer's avatar
Karl Heuer committed
636

637 638 639 640 641 642
  /* The size of the dumped executable is the size of the original
     executable plus the size of the heap and the size of the .bss section.  */
  size = in_file.size +
    extra_bss_size +
    extra_bss_size_static;
  if (!open_output_file (&out_file, out_filename, size))
643
    {
644
      printf ("Failed to open %s (%lu)...bailing.\n",
645 646
	      out_filename, GetLastError ());
      exit (1);
647 648
    }

649
  copy_executable_and_dump_data (&in_file, &out_file);
650

651 652 653 654 655 656 657
  /* Patch up header fields; profiler is picky about this. */
  {
    PIMAGE_DOS_HEADER dos_header;
    PIMAGE_NT_HEADERS nt_header;
    HANDLE hImagehelp = LoadLibrary ("imagehlp.dll");
    DWORD  headersum;
    DWORD  checksum;
658

659 660
    dos_header = (PIMAGE_DOS_HEADER) out_file.file_base;
    nt_header = (PIMAGE_NT_HEADERS) ((char *) dos_header + dos_header->e_lfanew);
661

662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678
    nt_header->OptionalHeader.CheckSum = 0;
//    nt_header->FileHeader.TimeDateStamp = time (NULL);
//    dos_header->e_cp = size / 512;
//    nt_header->OptionalHeader.SizeOfImage = size;

    pfnCheckSumMappedFile = (void *) GetProcAddress (hImagehelp, "CheckSumMappedFile");
    if (pfnCheckSumMappedFile)
      {
//	nt_header->FileHeader.TimeDateStamp = time (NULL);
	pfnCheckSumMappedFile (out_file.file_base,
			       out_file.size,
			       &headersum,
			       &checksum);
	nt_header->OptionalHeader.CheckSum = checksum;
      }
    FreeLibrary (hImagehelp);
  }
679

680 681
  close_file_data (&in_file);
  close_file_data (&out_file);
Karl Heuer's avatar
Karl Heuer committed
682
}
683 684

/* eof */