#define max(x, y) (((x) > (y)) ? (x) : (y))
/* Basically, our "initialized" flag. */
-BOOL need_to_recreate_heap = FALSE;
-
-/* So we can find our heap in the file to recreate it. */
-unsigned long heap_index_in_executable = 0;
+BOOL using_dynamic_heap = FALSE;
int open_input_file (file_data *p_file, char *name);
int open_output_file (file_data *p_file, char *name, unsigned long size);
void close_file_data (file_data *p_file);
void get_section_info (file_data *p_file);
-void copy_executable_and_dump_data_section (file_data *, file_data *);
+void copy_executable_and_dump_data (file_data *, file_data *);
void dump_bss_and_heap (file_data *p_infile, file_data *p_outfile);
/* Cached info about the .data section in the executable. */
-PUCHAR data_start_va = 0;
-DWORD data_start_file = 0;
+PIMAGE_SECTION_HEADER data_section;
+PUCHAR data_start = 0;
DWORD data_size = 0;
/* Cached info about the .bss section in the executable. */
+PIMAGE_SECTION_HEADER bss_section;
PUCHAR bss_start = 0;
DWORD bss_size = 0;
+DWORD extra_bss_size = 0;
+/* bss data that is static might be discontiguous from non-static. */
+PIMAGE_SECTION_HEADER bss_section_static;
+PUCHAR bss_start_static = 0;
+DWORD bss_size_static = 0;
+DWORD extra_bss_size_static = 0;
+
+PIMAGE_SECTION_HEADER heap_section;
#ifdef HAVE_NTGUI
HINSTANCE hinst = NULL;
/* Cache system info, e.g., the NT page size. */
cache_system_info ();
- /* If we're a dumped version of emacs then we need to recreate
- our heap and play tricks with our .bss section. Do this before
- start up. (WARNING: Do not put any code before this section
- that relies upon malloc () and runs in the dumped version. It
- won't work.) */
- if (need_to_recreate_heap)
- {
- char executable_path[MAX_PATH];
-
- if (GetModuleFileName (NULL, executable_path, MAX_PATH) == 0)
- {
- printf ("Failed to find path for executable.\n");
- exit (1);
- }
-
-#if 1
- /* To allow profiling, make sure executable_path names the .exe
- file, not the ._xe file created by the profiler which contains
- extra code that makes the stored exe offsets incorrect. (This
- will not be necessary when unexec properly extends the .bss (or
- .data as appropriate) section to include the dumped bss data,
- and dumps the heap into a proper section of its own.) */
- {
- char * p = strrchr (executable_path, '.');
- if (p && p[1] == '_')
- p[1] = 'e';
- }
-
- /* Using HiProf profiler, exe name is different still. */
- {
- char * p = strrchr (executable_path, '\\');
- strcpy (p, "\\emacs.exe");
- }
-#endif
-
- recreate_heap (executable_path);
- need_to_recreate_heap = FALSE;
- }
- else
- {
- /* Grab our malloc arena space now, before CRT starts up. */
- sbrk (0);
- }
+ /* Grab our malloc arena space now, before CRT starts up. */
+ init_heap ();
/* The default behavior is to treat files as binary and patch up
text files appropriately, in accordance with the MSDOS code. */
mainCRTStartup ();
}
-/* Dump out .data and .bss sections into a new executable. */
-void
-unexec (char *new_name, char *old_name, void *start_data, void *start_bss,
- void *entry_address)
-{
- file_data in_file, out_file;
- char out_filename[MAX_PATH], in_filename[MAX_PATH];
- unsigned long size;
- char *ptr;
-
- /* Make sure that the input and output filenames have the
- ".exe" extension...patch them up if they don't. */
- strcpy (in_filename, old_name);
- ptr = in_filename + strlen (in_filename) - 4;
- if (strcmp (ptr, ".exe"))
- strcat (in_filename, ".exe");
-
- strcpy (out_filename, new_name);
- ptr = out_filename + strlen (out_filename) - 4;
- if (strcmp (ptr, ".exe"))
- strcat (out_filename, ".exe");
-
- printf ("Dumping from %s\n", in_filename);
- printf (" to %s\n", out_filename);
-
- /* We need to round off our heap to NT's allocation unit (64KB). */
- round_heap (get_allocation_unit ());
-
- /* Open the undumped executable file. */
- if (!open_input_file (&in_file, in_filename))
- {
- printf ("Failed to open %s (%d)...bailing.\n",
- in_filename, GetLastError ());
- exit (1);
- }
-
- /* Get the interesting section info, like start and size of .bss... */
- get_section_info (&in_file);
-
- /* 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. */
- heap_index_in_executable = (unsigned long)
- round_to_next ((unsigned char *) in_file.size, get_allocation_unit ());
- size = heap_index_in_executable + get_committed_heap_size () + bss_size;
- if (!open_output_file (&out_file, out_filename, size))
- {
- printf ("Failed to open %s (%d)...bailing.\n",
- out_filename, GetLastError ());
- exit (1);
- }
-
- /* Set the flag (before dumping). */
- need_to_recreate_heap = TRUE;
-
- copy_executable_and_dump_data_section (&in_file, &out_file);
- dump_bss_and_heap (&in_file, &out_file);
-
- /* 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;
-
- dos_header = (PIMAGE_DOS_HEADER) out_file.file_base;
- nt_header = (PIMAGE_NT_HEADERS) ((char *) dos_header + dos_header->e_lfanew);
-
- 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);
- }
-
- close_file_data (&in_file);
- close_file_data (&out_file);
-}
-
/* File handling. */
-
int
open_input_file (file_data *p_file, char *filename)
{
void
close_file_data (file_data *p_file)
{
- UnmapViewOfFile (p_file->file_base);
- CloseHandle (p_file->file_mapping);
- CloseHandle (p_file->file);
+ UnmapViewOfFile (p_file->file_base);
+ CloseHandle (p_file->file_mapping);
+ /* For the case of output files, set final size. */
+ SetFilePointer (p_file->file, p_file->size, NULL, FILE_BEGIN);
+ SetEndOfFile (p_file->file);
+ CloseHandle (p_file->file);
}
/* Routines to manipulate NT executable file sections. */
-#ifdef SEPARATE_BSS_SECTION
-static void
-get_bss_info_from_map_file (file_data *p_infile, PUCHAR *p_bss_start,
- DWORD *p_bss_size)
-{
- int n, start, len;
- char map_filename[MAX_PATH];
- char buffer[256];
- FILE *map;
-
- /* Overwrite the .exe extension on the executable file name with
- the .map extension. */
- strcpy (map_filename, p_infile->name);
- n = strlen (map_filename) - 3;
- strcpy (&map_filename[n], "map");
-
- map = fopen (map_filename, "r");
- if (!map)
- {
- printf ("Failed to open map file %s, error %d...bailing out.\n",
- map_filename, GetLastError ());
- exit (-1);
- }
-
- while (fgets (buffer, sizeof (buffer), map))
- {
- if (!(strstr (buffer, ".bss") && strstr (buffer, "DATA")))
- continue;
- n = sscanf (buffer, " %*d:%x %x", &start, &len);
- if (n != 2)
- {
- printf ("Failed to scan the .bss section line:\n%s", buffer);
- exit (-1);
- }
- break;
- }
- *p_bss_start = (PUCHAR) start;
- *p_bss_size = (DWORD) len;
-}
-#endif
-
-unsigned long
-get_section_size (PIMAGE_SECTION_HEADER p_section)
-{
- /* The true section size, before rounding. Some linkers swap the
- meaning of these two values. */
- return min (p_section->SizeOfRawData,
- p_section->Misc.VirtualSize);
-}
-
/* Return pointer to section header for named section. */
IMAGE_SECTION_HEADER *
find_section (char * name, IMAGE_NT_HEADERS * nt_header)
for (i = 0; i < nt_header->FileHeader.NumberOfSections; i++)
{
+ /* Some linkers (eg. the NT SDK linker I believe) swapped the
+ meaning of these two values - or rather, they ignored
+ VirtualSize entirely and always set it to zero. This affects
+ some very old exes (eg. gzip dated Dec 1993). Since
+ w32_executable_type relies on this function to work reliably,
+ we need to cope with this. */
+ DWORD real_size = max (section->SizeOfRawData,
+ section->Misc.VirtualSize);
if (rva >= section->VirtualAddress
- && rva < section->VirtualAddress + section->SizeOfRawData)
+ && rva < section->VirtualAddress + real_size)
+ return section;
+ section++;
+ }
+ return NULL;
+}
+
+/* Return pointer to section header for section containing the given
+ offset in its raw data area. */
+IMAGE_SECTION_HEADER *
+offset_to_section (DWORD offset, IMAGE_NT_HEADERS * nt_header)
+{
+ 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)
return section;
section++;
}
return NULL;
}
+/* 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). */
+static DWORD
+relocate_offset (DWORD offset,
+ 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 OFFSET_TO_RVA(offset, section) \
+ (section->VirtualAddress + ((DWORD)(offset) - section->PointerToRawData))
+
+#define RVA_TO_OFFSET(rva, section) \
+ (section->PointerToRawData + ((DWORD)(rva) - section->VirtualAddress))
+
+#define RVA_TO_SECTION_OFFSET(rva, section) \
+ ((DWORD)(rva) - section->VirtualAddress)
+
+/* Convert address in executing image to RVA. */
+#define PTR_TO_RVA(ptr) ((DWORD)(ptr) - (DWORD) GetModuleHandle (NULL))
+
+#define PTR_TO_OFFSET(ptr, pfile_data) \
+ ((char *)(ptr) - (pfile_data)->file_base)
+
+#define OFFSET_TO_PTR(offset, pfile_data) \
+ ((pfile_data)->file_base + (DWORD)(offset))
+
/* Flip through the executable and cache the info necessary for dumping. */
static void
{
PIMAGE_DOS_HEADER dos_header;
PIMAGE_NT_HEADERS nt_header;
- PIMAGE_SECTION_HEADER section, data_section;
- unsigned char *ptr;
- int i;
+ PIMAGE_SECTION_HEADER section;
+ int overlap;
dos_header = (PIMAGE_DOS_HEADER) p_infile->file_base;
if (dos_header->e_magic != IMAGE_DOS_SIGNATURE)
{
printf ("Invalid IMAGE_NT_SIGNATURE 0x%x in %s...bailing.\n",
nt_header->Signature, p_infile->name);
+ exit (1);
}
- /* Flip through the sections for .data and .bss ... */
- section = (PIMAGE_SECTION_HEADER) IMAGE_FIRST_SECTION (nt_header);
- for (i = 0; i < nt_header->FileHeader.NumberOfSections; i++)
+ /* 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. */
+
+ 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))
{
-#ifdef SEPARATE_BSS_SECTION
- if (!strcmp (section->Name, ".bss"))
+ printf ("Initialized data is not in a single section...bailing\n");
+ exit (1);
+ }
+
+ /* 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. */
+ overlap = 0;
+ 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)
{
- /* The .bss section. */
- ptr = (char *) nt_header->OptionalHeader.ImageBase +
- section->VirtualAddress;
- bss_start = ptr;
- bss_size = get_section_size (section);
+ printf ("BSS data not in a single section...bailing\n");
+ exit (1);
}
-#endif
-#if 0
- if (!strcmp (section->Name, ".data"))
+ bss_start = min (bss_start, bss_start_static);
+ bss_size = max (my_endbss, my_endbss_static) - bss_start;
+ bss_section_static = 0;
+ extra_bss_size_static = 0;
+ }
+
+ heap_section = rva_to_section (PTR_TO_RVA (get_heap_start ()), nt_header);
+}
+
+
+/* The dump routines. */
+
+static void
+copy_executable_and_dump_data (file_data *p_infile,
+ 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;
+ DWORD offset;
+ int i;
+
+#define COPY_CHUNK(message, src, size) \
+ do { \
+ unsigned char *s = (void *)(src); \
+ unsigned long count = (size); \
+ printf ("%s\n", (message)); \
+ printf ("\t0x%08x Offset in input file.\n", s - p_infile->file_base); \
+ printf ("\t0x%08x Offset in output file.\n", dst - p_outfile->file_base); \
+ printf ("\t0x%08x Size in bytes.\n", count); \
+ memcpy (dst, s, count); \
+ dst += count; \
+ } while (0)
+
+#define COPY_PROC_CHUNK(message, src, size) \
+ do { \
+ unsigned char *s = (void *)(src); \
+ unsigned long count = (size); \
+ printf ("%s\n", (message)); \
+ printf ("\t0x%08x Address in process.\n", s); \
+ printf ("\t0x%08x Offset in output file.\n", dst - p_outfile->file_base); \
+ printf ("\t0x%08x Size in bytes.\n", count); \
+ 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)))
+
+ /* 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;
+ nt_header = (PIMAGE_NT_HEADERS) (((unsigned long) dos_header) +
+ dos_header->e_lfanew);
+ section = IMAGE_FIRST_SECTION (nt_header);
+
+ dst = (unsigned char *) p_outfile->file_base;
+
+ COPY_CHUNK ("Copying DOS header...", dos_header,
+ (DWORD) nt_header - (DWORD) dos_header);
+ dst_nt_header = (PIMAGE_NT_HEADERS) dst;
+ COPY_CHUNK ("Copying NT header...", nt_header,
+ (DWORD) section - (DWORD) nt_header);
+ dst_section = (PIMAGE_SECTION_HEADER) dst;
+ COPY_CHUNK ("Copying section table...", section,
+ nt_header->FileHeader.NumberOfSections * sizeof (*section));
+
+ for (i = 0; i < nt_header->FileHeader.NumberOfSections; i++)
+ {
+ char msg[100];
+ sprintf (msg, "Copying raw data for %s...", section->Name);
+
+ /* Align the section's raw data area. */
+ ROUND_UP_DST (dst_nt_header->OptionalHeader.FileAlignment);
+ 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),
+ section->SizeOfRawData);
+
+ /* Note that various sections below may be aliases. */
+ if (section == data_section)
{
- /* From lastfile.c */
- extern char my_edata[];
-
- /* The .data section. */
- data_section = section;
- ptr = (char *) nt_header->OptionalHeader.ImageBase +
- section->VirtualAddress;
- data_start_va = ptr;
- data_start_file = section->PointerToRawData;
-
- /* We want to only write Emacs data back to the executable,
- not any of the library data (if library data is included,
- then a dumped Emacs won't run on system versions other
- than the one Emacs was dumped on). */
- data_size = my_edata - data_start_va;
+ dst = dst_save
+ + RVA_TO_SECTION_OFFSET (PTR_TO_RVA (data_start), dst_section);
+ COPY_PROC_CHUNK ("Dumping initialized data...", data_start, data_size);
+ dst = dst_save + dst_section->SizeOfRawData;
}
-#else
- if (!strcmp (section->Name, "EMDATA"))
+ if (section == bss_section)
{
- /* The Emacs initialized data section. */
- data_section = section;
- ptr = (char *) nt_header->OptionalHeader.ImageBase +
- section->VirtualAddress;
- data_start_va = ptr;
- data_start_file = section->PointerToRawData;
-
- /* Write back the full section. */
- data_size = get_section_size (section);
+ /* 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);
+ COPY_PROC_CHUNK ("Dumping bss data...", bss_start, bss_size);
+ 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;
}
-#endif
+ 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);
+ COPY_PROC_CHUNK ("Dumping static bss data...", bss_start_static, bss_size_static);
+ 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;
+ }
+ if (section == heap_section)
+ {
+ DWORD heap_start = get_heap_start ();
+ DWORD heap_size = get_committed_heap_size ();
+
+ /* Dump the used portion of the predump heap, adjusting the
+ section's size to the appropriate size. */
+ dst = dst_save
+ + RVA_TO_SECTION_OFFSET (PTR_TO_RVA (heap_start), dst_section);
+ COPY_PROC_CHUNK ("Dumping heap...", heap_start, heap_size);
+ 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;
+ /* Reduce the size of the heap section to fit (must be last
+ section). */
+ dst_nt_header->OptionalHeader.SizeOfImage -=
+ dst_section->Misc.VirtualSize
+ - ROUND_UP (dst_section->SizeOfRawData,
+ dst_nt_header->OptionalHeader.SectionAlignment);
+ dst_section->Misc.VirtualSize =
+ ROUND_UP (dst_section->SizeOfRawData,
+ dst_nt_header->OptionalHeader.SectionAlignment);
+ dst_section->Characteristics &= ~IMAGE_SCN_CNT_UNINITIALIZED_DATA;
+ dst_section->Characteristics |= IMAGE_SCN_CNT_INITIALIZED_DATA;
+ }
+
section++;
+ dst_section++;
}
-#ifdef SEPARATE_BSS_SECTION
- if (bss_start == UNINIT_PTR && bss_size == UNINIT_LONG)
+ /* Pad out the final section raw data area. */
+ ROUND_UP_DST (dst_nt_header->OptionalHeader.FileAlignment);
+
+ /* 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),
+ p_infile->size - offset);
+
+ /* 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++)
{
- /* Starting with MSVC 4.0, the .bss section has been eliminated
- and appended virtually to the end of the .data section. Our
- only hint about where the .bss section starts in the address
- comes from the SizeOfRawData field in the .data section
- header. Unfortunately, this field is only approximate, as it
- is a rounded number and is typically rounded just beyond the
- start of the .bss section. To find the start and size of the
- .bss section exactly, we have to peek into the map file. */
- get_bss_info_from_map_file (p_infile, &ptr, &bss_size);
- bss_start = ptr + nt_header->OptionalHeader.ImageBase
- + data_section->VirtualAddress;
+ /* 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);
}
-#else
-/* 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 should 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). However, in practice this doesn't
- seem to matter, since presumably the system libraries always
- reinitialize their bss variables. */
- bss_start = min (my_begbss, my_begbss_static);
- bss_size = max (my_endbss, my_endbss_static) - bss_start;
-#endif
-}
+ ADJUST_OFFSET (dst_nt_header->FileHeader.PointerToSymbolTable);
-/* The dump routines. */
+ /* 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;
-static void
-copy_executable_and_dump_data_section (file_data *p_infile,
- file_data *p_outfile)
-{
- unsigned char *data_file, *data_va;
- unsigned long size, index;
-
- /* Get a pointer to where the raw data should go in the executable file. */
- data_file = (char *) p_outfile->file_base + data_start_file;
-
- /* Get a pointer to the raw data in our address space. */
- data_va = data_start_va;
-
- size = (DWORD) data_file - (DWORD) p_outfile->file_base;
- printf ("Copying executable up to data section...\n");
- printf ("\t0x%08x Offset in input file.\n", 0);
- printf ("\t0x%08x Offset in output file.\n", 0);
- printf ("\t0x%08x Size in bytes.\n", size);
- memcpy (p_outfile->file_base, p_infile->file_base, size);
-
- size = data_size;
- printf ("Dumping .data section...\n");
- printf ("\t0x%08x Address in process.\n", data_va);
- printf ("\t0x%08x Offset in output file.\n",
- data_file - p_outfile->file_base);
- printf ("\t0x%08x Size in bytes.\n", size);
- memcpy (data_file, data_va, size);
-
- index = (DWORD) data_file + size - (DWORD) p_outfile->file_base;
- size = p_infile->size - index;
- printf ("Copying rest of executable...\n");
- printf ("\t0x%08x Offset in input file.\n", index);
- printf ("\t0x%08x Offset in output file.\n", index);
- printf ("\t0x%08x Size in bytes.\n", size);
- memcpy ((char *) p_outfile->file_base + index,
- (char *) p_infile->file_base + index, size);
-}
+ 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);
-static void
-dump_bss_and_heap (file_data *p_infile, file_data *p_outfile)
-{
- unsigned char *heap_data, *bss_data;
- unsigned long size, index;
-
- printf ("Dumping heap into executable...\n");
-
- index = heap_index_in_executable;
- size = get_committed_heap_size ();
- heap_data = get_heap_start ();
-
- printf ("\t0x%08x Heap start in process.\n", heap_data);
- printf ("\t0x%08x Heap offset in executable.\n", index);
- printf ("\t0x%08x Heap size in bytes.\n", size);
-
- memcpy ((PUCHAR) p_outfile->file_base + index, heap_data, size);
-
- printf ("Dumping .bss into executable...\n");
-
- index += size;
- size = bss_size;
- bss_data = bss_start;
-
- printf ("\t0x%08x BSS start in process.\n", bss_data);
- printf ("\t0x%08x BSS offset in executable.\n", index);
- printf ("\t0x%08x BSS size in bytes.\n", size);
- memcpy ((char *) p_outfile->file_base + index, bss_data, size);
+ for (i = 0; i < debug_dir.Size; i++, debug_entry++)
+ ADJUST_OFFSET (debug_entry->PointerToRawData);
+ }
+ }
}
-/* Reload and remap routines. */
-
+/* Dump out .data and .bss sections into a new executable. */
void
-w32_fatal_reload_error (char *step)
+unexec (char *new_name, char *old_name, void *start_data, void *start_bss,
+ void *entry_address)
{
- int error = GetLastError ();
- char *buffer = alloca (4096);
-
- sprintf (buffer,
- "Emacs failed to load its dumped heap back into its address space.\n"
- "The error occurred during the following step:\n\n"
- "%s\n\n"
- "GetLastError = %d\n\n"
- "Heap start: 0x%08x\n"
- "Heap commit: 0x%08x\n"
- "Heap end: 0x%08x\n\n"
- "This error typically happens when the system loads a DLL into\n"
- "the middle of Emacs' address space, preventing Emacs from\n"
- "loading its heap there. If this happens only occasionally, then\n"
- "you can probably ignore it. But if it happens so often that\n"
- "you cannot get Emacs to start reliably, and you think that Emacs\n"
- "is installed correctly, then you have a couple of options:\n\n"
- "Emacs correctly, then you have two options:\n\n"
- "1) You can dump Emacs yourself. By doing this, you ensure that\n"
- "Emacs' heap fits around the DLLs in your system. To dump Emacs,\n"
- "download the emacs-(version)-undump-(arch) distribution file\n"
- "from the site where you downloaded the executable distribution.\n\n"
- "2) You can build Emacs from source. This is just another way\n"
- "to dump Emacs on your system.",
- step,
- error,
- get_heap_start (),
- get_heap_start () + get_committed_heap_size (),
- get_heap_end ());
-
- MessageBox (NULL,
- buffer,
- "Emacs Abort Dialog",
- MB_OK | MB_ICONEXCLAMATION | MB_TASKMODAL);
-
- exit (-1);
-}
+ file_data in_file, out_file;
+ char out_filename[MAX_PATH], in_filename[MAX_PATH];
+ unsigned long size;
+ char *ptr;
+
+ /* Make sure that the input and output filenames have the
+ ".exe" extension...patch them up if they don't. */
+ strcpy (in_filename, old_name);
+ ptr = in_filename + strlen (in_filename) - 4;
+ if (strcmp (ptr, ".exe"))
+ strcat (in_filename, ".exe");
-/* Load the dumped .bss section into the .bss area of our address space. */
-void
-read_in_bss (char *filename)
-{
- HANDLE file;
- unsigned long size, index, n_read, total_read;
- char buffer[512], *bss;
- int i;
+ strcpy (out_filename, new_name);
+ ptr = out_filename + strlen (out_filename) - 4;
+ if (strcmp (ptr, ".exe"))
+ strcat (out_filename, ".exe");
- file = CreateFile (filename, GENERIC_READ, FILE_SHARE_READ, NULL,
- OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
- if (file == INVALID_HANDLE_VALUE)
- w32_fatal_reload_error ("Opening Emacs executable file for .bss.");
+ printf ("Dumping from %s\n", in_filename);
+ printf (" to %s\n", out_filename);
- /* Seek to where the .bss section is tucked away after the heap... */
- index = heap_index_in_executable + get_committed_heap_size ();
- if (SetFilePointer (file, index, NULL, FILE_BEGIN) == 0xFFFFFFFF)
- w32_fatal_reload_error ("Seeking to the saved .bss section.");
-
- /* Ok, read in the saved .bss section and initialize all
- uninitialized variables. */
- if (!ReadFile (file, bss_start, bss_size, &n_read, NULL))
- w32_fatal_reload_error ("Reading the saved .bss section.");
+ /* We need to round off our heap to NT's page size. */
+ round_heap (get_page_size ());
- CloseHandle (file);
-}
+ /* Open the undumped executable file. */
+ if (!open_input_file (&in_file, in_filename))
+ {
+ printf ("Failed to open %s (%d)...bailing.\n",
+ in_filename, GetLastError ());
+ exit (1);
+ }
-/* Map the heap dumped into the executable file into our address space. */
-void
-map_in_heap (char *filename)
-{
- HANDLE file;
- HANDLE file_mapping;
- void *file_base;
- unsigned long size, upper_size, n_read;
- int i;
+ /* Get the interesting section info, like start and size of .bss... */
+ get_section_info (&in_file);
- file = CreateFile (filename, GENERIC_READ, FILE_SHARE_READ, NULL,
- OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
- if (file == INVALID_HANDLE_VALUE)
- w32_fatal_reload_error ("Opening Emacs executable file for heap.");
-
- size = GetFileSize (file, &upper_size);
- file_mapping = CreateFileMapping (file, NULL, PAGE_WRITECOPY,
- 0, size, NULL);
- if (!file_mapping)
- w32_fatal_reload_error ("Creating file mapping to heap in executable.");
-
- size = get_committed_heap_size ();
- file_base = MapViewOfFileEx (file_mapping, FILE_MAP_COPY, 0,
- heap_index_in_executable, size,
- get_heap_start ());
- if (file_base != 0)
+ /* 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 +
+ get_committed_heap_size () +
+ extra_bss_size +
+ extra_bss_size_static;
+ if (!open_output_file (&out_file, out_filename, size))
{
- return;
+ printf ("Failed to open %s (%d)...bailing.\n",
+ out_filename, GetLastError ());
+ exit (1);
}
- /* If we don't succeed with the mapping, then copy from the
- data into the heap. */
+ /* Set the flag (before dumping). */
+ using_dynamic_heap = TRUE;
- CloseHandle (file_mapping);
+ copy_executable_and_dump_data (&in_file, &out_file);
- if (VirtualAlloc (get_heap_start (), get_committed_heap_size (),
- MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE) == NULL)
- w32_fatal_reload_error ("Allocating heap address space.");
+ /* 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;
- /* Seek to the location of the heap data in the executable. */
- i = heap_index_in_executable;
- if (SetFilePointer (file, i, NULL, FILE_BEGIN) == 0xFFFFFFFF)
- w32_fatal_reload_error ("Seeking to saved heap in executable file.");
+ dos_header = (PIMAGE_DOS_HEADER) out_file.file_base;
+ nt_header = (PIMAGE_NT_HEADERS) ((char *) dos_header + dos_header->e_lfanew);
- /* Read in the data. */
- if (!ReadFile (file, get_heap_start (),
- get_committed_heap_size (), &n_read, NULL))
- w32_fatal_reload_error ("Reading saved heap from executable file.");
+ 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);
+ }
- CloseHandle (file);
+ close_file_data (&in_file);
+ close_file_data (&out_file);
}
+
+/* eof */