Changeset 1671

Show
Ignore:
Timestamp:
02/17/98 01:45:17 (11 years ago)
Author:
himi
Message:

FSF GNU Emacs 20.3 98/8/21 Release.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • branches/GNU/src/unexw32.c

    r1665 r1671  
    5656 
    5757/* Basically, our "initialized" flag.  */ 
    58 BOOL using_dynamic_heap = FALSE; 
     58BOOL need_to_recreate_heap = FALSE; 
     59 
     60/* So we can find our heap in the file to recreate it.  */ 
     61unsigned long heap_index_in_executable = 0; 
    5962 
    6063int open_input_file (file_data *p_file, char *name); 
     
    6366 
    6467void get_section_info (file_data *p_file); 
    65 void copy_executable_and_dump_data (file_data *, file_data *); 
     68void copy_executable_and_dump_data_section (file_data *, file_data *); 
    6669void dump_bss_and_heap (file_data *p_infile, file_data *p_outfile); 
    6770 
    6871/* Cached info about the .data section in the executable.  */ 
    69 PIMAGE_SECTION_HEADER data_section
    70 PUCHAR data_start = 0; 
     72PUCHAR data_start_va = 0
     73DWORD  data_start_file = 0; 
    7174DWORD  data_size = 0; 
    7275 
    7376/* Cached info about the .bss section in the executable.  */ 
    74 PIMAGE_SECTION_HEADER bss_section; 
    7577PUCHAR bss_start = 0; 
    7678DWORD  bss_size = 0; 
    77 DWORD  extra_bss_size = 0; 
    78 /* bss data that is static might be discontiguous from non-static.  */ 
    79 PIMAGE_SECTION_HEADER bss_section_static; 
    80 PUCHAR bss_start_static = 0; 
    81 DWORD  bss_size_static = 0; 
    82 DWORD  extra_bss_size_static = 0; 
    83  
    84 PIMAGE_SECTION_HEADER heap_section; 
    8579 
    8680#ifdef HAVE_NTGUI 
     
    110104  cache_system_info (); 
    111105 
    112   /* Grab our malloc arena space now, before CRT starts up. */ 
    113   init_heap (); 
     106  /* If we're a dumped version of emacs then we need to recreate 
     107     our heap and play tricks with our .bss section.  Do this before 
     108     start up.  (WARNING:  Do not put any code before this section 
     109     that relies upon malloc () and runs in the dumped version.  It 
     110     won't work.)  */ 
     111  if (need_to_recreate_heap)  
     112    { 
     113      char executable_path[MAX_PATH]; 
     114 
     115      if (GetModuleFileName (NULL, executable_path, MAX_PATH) == 0)  
     116        { 
     117          printf ("Failed to find path for executable.\n"); 
     118          exit (1); 
     119        } 
     120 
     121#if 1 
     122      /* To allow profiling, make sure executable_path names the .exe 
     123         file, not the ._xe file created by the profiler which contains 
     124         extra code that makes the stored exe offsets incorrect.  (This 
     125         will not be necessary when unexec properly extends the .bss (or 
     126         .data as appropriate) section to include the dumped bss data, 
     127         and dumps the heap into a proper section of its own.)  */ 
     128      { 
     129        char * p = strrchr (executable_path, '.'); 
     130        if (p && p[1] == '_') 
     131          p[1] = 'e'; 
     132      } 
     133 
     134      /* Using HiProf profiler, exe name is different still. */ 
     135      { 
     136        char * p = strrchr (executable_path, '\\'); 
     137        strcpy (p, "\\emacs.exe"); 
     138      } 
     139#endif 
     140 
     141      recreate_heap (executable_path); 
     142      need_to_recreate_heap = FALSE; 
     143    } 
     144  else 
     145    { 
     146      /* Grab our malloc arena space now, before CRT starts up. */ 
     147      sbrk (0); 
     148    } 
    114149 
    115150  /* The default behavior is to treat files as binary and patch up 
     
    120155     having us exit.  */ 
    121156  SetConsoleCtrlHandler ((PHANDLER_ROUTINE) ctrl_c_handler, TRUE); 
    122  
    123   /* Prevent Emacs from being locked up (eg. in batch mode) when 
    124      accessing devices that aren't mounted (eg. removable media drives).  */ 
    125   SetErrorMode (SEM_FAILCRITICALERRORS); 
    126157 
    127158  /* Invoke the NT CRT startup routine now that our housecleaning 
     
    136167} 
    137168 
    138  
    139 /* File handling.  */ 
    140  
    141 int 
    142 open_input_file (file_data *p_file, char *filename) 
    143 { 
    144   HANDLE file; 
    145   HANDLE file_mapping; 
    146   void  *file_base; 
    147   unsigned long size, upper_size; 
    148  
    149   file = CreateFile (filename, GENERIC_READ, FILE_SHARE_READ, NULL, 
    150                      OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); 
    151   if (file == INVALID_HANDLE_VALUE)  
    152     return FALSE; 
    153  
    154   size = GetFileSize (file, &upper_size); 
    155   file_mapping = CreateFileMapping (file, NULL, PAGE_READONLY,  
    156                                     0, size, NULL); 
    157   if (!file_mapping)  
    158     return FALSE; 
    159  
    160   file_base = MapViewOfFile (file_mapping, FILE_MAP_READ, 0, 0, size); 
    161   if (file_base == 0)  
    162     return FALSE; 
    163  
    164   p_file->name = filename; 
    165   p_file->size = size; 
    166   p_file->file = file; 
    167   p_file->file_mapping = file_mapping; 
    168   p_file->file_base = file_base; 
    169  
    170   return TRUE; 
    171 } 
    172  
    173 int 
    174 open_output_file (file_data *p_file, char *filename, unsigned long size) 
    175 { 
    176   HANDLE file; 
    177   HANDLE file_mapping; 
    178   void  *file_base; 
    179  
    180   file = CreateFile (filename, GENERIC_READ | GENERIC_WRITE, 0, NULL, 
    181                      CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); 
    182   if (file == INVALID_HANDLE_VALUE)  
    183     return FALSE; 
    184  
    185   file_mapping = CreateFileMapping (file, NULL, PAGE_READWRITE,  
    186                                     0, size, NULL); 
    187   if (!file_mapping)  
    188     return FALSE; 
    189    
    190   file_base = MapViewOfFile (file_mapping, FILE_MAP_WRITE, 0, 0, size); 
    191   if (file_base == 0)  
    192     return FALSE; 
    193    
    194   p_file->name = filename; 
    195   p_file->size = size; 
    196   p_file->file = file; 
    197   p_file->file_mapping = file_mapping; 
    198   p_file->file_base = file_base; 
    199  
    200   return TRUE; 
    201 } 
    202  
    203 /* Close the system structures associated with the given file.  */ 
    204 void 
    205 close_file_data (file_data *p_file) 
    206 { 
    207   UnmapViewOfFile (p_file->file_base); 
    208   CloseHandle (p_file->file_mapping); 
    209   /* For the case of output files, set final size.  */ 
    210   SetFilePointer (p_file->file, p_file->size, NULL, FILE_BEGIN); 
    211   SetEndOfFile (p_file->file); 
    212   CloseHandle (p_file->file); 
    213 } 
    214  
    215  
    216 /* Routines to manipulate NT executable file sections.  */ 
    217  
    218 /* Return pointer to section header for named section. */ 
    219 IMAGE_SECTION_HEADER * 
    220 find_section (char * name, IMAGE_NT_HEADERS * nt_header) 
    221 { 
    222   PIMAGE_SECTION_HEADER section; 
    223   int i; 
    224  
    225   section = IMAGE_FIRST_SECTION (nt_header); 
    226  
    227   for (i = 0; i < nt_header->FileHeader.NumberOfSections; i++) 
    228     { 
    229       if (strcmp (section->Name, name) == 0) 
    230         return section; 
    231       section++; 
    232     } 
    233   return NULL; 
    234 } 
    235  
    236 /* Return pointer to section header for section containing the given 
    237    relative virtual address. */ 
    238 IMAGE_SECTION_HEADER * 
    239 rva_to_section (DWORD rva, IMAGE_NT_HEADERS * nt_header) 
    240 { 
    241   PIMAGE_SECTION_HEADER section; 
    242   int i; 
    243  
    244   section = IMAGE_FIRST_SECTION (nt_header); 
    245  
    246   for (i = 0; i < nt_header->FileHeader.NumberOfSections; i++) 
    247     { 
    248       /* Some linkers (eg. the NT SDK linker I believe) swapped the 
    249          meaning of these two values - or rather, they ignored 
    250          VirtualSize entirely and always set it to zero.  This affects 
    251          some very old exes (eg. gzip dated Dec 1993).  Since 
    252          w32_executable_type relies on this function to work reliably, 
    253          we need to cope with this.  */ 
    254       DWORD real_size = max (section->SizeOfRawData, 
    255                              section->Misc.VirtualSize); 
    256       if (rva >= section->VirtualAddress 
    257           && rva < section->VirtualAddress + real_size) 
    258         return section; 
    259       section++; 
    260     } 
    261   return NULL; 
    262 } 
    263  
    264 /* Return pointer to section header for section containing the given 
    265    offset in its raw data area. */ 
    266 IMAGE_SECTION_HEADER * 
    267 offset_to_section (DWORD offset, IMAGE_NT_HEADERS * nt_header) 
    268 { 
    269   PIMAGE_SECTION_HEADER section; 
    270   int i; 
    271  
    272   section = IMAGE_FIRST_SECTION (nt_header); 
    273  
    274   for (i = 0; i < nt_header->FileHeader.NumberOfSections; i++) 
    275     { 
    276       if (offset >= section->PointerToRawData 
    277           && offset < section->PointerToRawData + section->SizeOfRawData) 
    278         return section; 
    279       section++; 
    280     } 
    281   return NULL; 
    282 } 
    283  
    284 /* Return offset to an object in dst, given offset in src.  We assume 
    285    there is at least one section in both src and dst images, and that 
    286    the some sections may have been added to dst (after sections in src).  */ 
    287 static DWORD 
    288 relocate_offset (DWORD offset, 
    289                  IMAGE_NT_HEADERS * src_nt_header, 
    290                  IMAGE_NT_HEADERS * dst_nt_header) 
    291 { 
    292   PIMAGE_SECTION_HEADER src_section = IMAGE_FIRST_SECTION (src_nt_header); 
    293   PIMAGE_SECTION_HEADER dst_section = IMAGE_FIRST_SECTION (dst_nt_header); 
    294   int i = 0; 
    295  
    296   while (offset >= src_section->PointerToRawData) 
    297     { 
    298       if (offset < src_section->PointerToRawData + src_section->SizeOfRawData) 
    299         break; 
    300       i++; 
    301       if (i == src_nt_header->FileHeader.NumberOfSections) 
    302         { 
    303           /* Handle offsets after the last section.  */ 
    304           dst_section = IMAGE_FIRST_SECTION (dst_nt_header); 
    305           dst_section += dst_nt_header->FileHeader.NumberOfSections - 1; 
    306           while (dst_section->PointerToRawData == 0) 
    307             dst_section--; 
    308           while (src_section->PointerToRawData == 0) 
    309             src_section--; 
    310           return offset 
    311             + (dst_section->PointerToRawData + dst_section->SizeOfRawData) 
    312             - (src_section->PointerToRawData + src_section->SizeOfRawData); 
    313         } 
    314       src_section++; 
    315       dst_section++; 
    316     } 
    317   return offset + 
    318     (dst_section->PointerToRawData - src_section->PointerToRawData); 
    319 } 
    320  
    321 #define OFFSET_TO_RVA(offset, section) \ 
    322           (section->VirtualAddress + ((DWORD)(offset) - section->PointerToRawData)) 
    323  
    324 #define RVA_TO_OFFSET(rva, section) \ 
    325           (section->PointerToRawData + ((DWORD)(rva) - section->VirtualAddress)) 
    326  
    327 #define RVA_TO_SECTION_OFFSET(rva, section) \ 
    328           ((DWORD)(rva) - section->VirtualAddress) 
    329  
    330 /* Convert address in executing image to RVA.  */ 
    331 #define PTR_TO_RVA(ptr) ((DWORD)(ptr) - (DWORD) GetModuleHandle (NULL)) 
    332  
    333 #define PTR_TO_OFFSET(ptr, pfile_data) \ 
    334           ((char *)(ptr) - (pfile_data)->file_base) 
    335  
    336 #define OFFSET_TO_PTR(offset, pfile_data) \ 
    337           ((pfile_data)->file_base + (DWORD)(offset)) 
    338  
    339  
    340 /* Flip through the executable and cache the info necessary for dumping.  */ 
    341 static void 
    342 get_section_info (file_data *p_infile) 
    343 { 
    344   PIMAGE_DOS_HEADER dos_header; 
    345   PIMAGE_NT_HEADERS nt_header; 
    346   PIMAGE_SECTION_HEADER section; 
    347   int overlap; 
    348    
    349   dos_header = (PIMAGE_DOS_HEADER) p_infile->file_base; 
    350   if (dos_header->e_magic != IMAGE_DOS_SIGNATURE)  
    351     { 
    352       printf ("Unknown EXE header in %s...bailing.\n", p_infile->name); 
    353       exit (1); 
    354     } 
    355   nt_header = (PIMAGE_NT_HEADERS) (((unsigned long) dos_header) +  
    356                                    dos_header->e_lfanew); 
    357   if (nt_header == NULL)  
    358     { 
    359       printf ("Failed to find IMAGE_NT_HEADER in %s...bailing.\n",  
    360              p_infile->name); 
    361       exit (1); 
    362     } 
    363  
    364   /* Check the NT header signature ...  */ 
    365   if (nt_header->Signature != IMAGE_NT_SIGNATURE)  
    366     { 
    367       printf ("Invalid IMAGE_NT_SIGNATURE 0x%x in %s...bailing.\n", 
    368               nt_header->Signature, p_infile->name); 
    369       exit (1); 
    370     } 
    371  
    372   /* Locate the ".data" and ".bss" sections for Emacs.  (Note that the 
    373      actual section names are probably different from these, and might 
    374      actually be the same section.) 
    375  
    376      We do this as follows: first we determine the virtual address 
    377      ranges in this process for the data and bss variables that we wish 
    378      to preserve.  Then we map these VAs to the section entries in the 
    379      source image.  Finally, we determine the new size of the raw data 
    380      area for the bss section, so we can make the new image the correct 
    381      size.  */ 
    382  
    383   data_start = my_begdata; 
    384   data_size = my_edata - my_begdata; 
    385   data_section = rva_to_section (PTR_TO_RVA (my_begdata), nt_header); 
    386   if (data_section != rva_to_section (PTR_TO_RVA (my_edata), nt_header)) 
    387     { 
    388       printf ("Initialized data is not in a single section...bailing\n"); 
    389       exit (1); 
    390     } 
    391  
    392   /* As noted in lastfile.c, the Alpha (but not the Intel) MSVC linker 
    393      globally segregates all static and public bss data (ie. across all 
    394      linked modules, not just per module), so we must take both static 
    395      and public bss areas into account to determine the true extent of 
    396      the bss area used by Emacs. 
    397  
    398      To be strictly correct, we dump the static and public bss areas 
    399      used by Emacs separately if non-overlapping (since otherwise we are 
    400      dumping bss data belonging to system libraries, eg. the static bss 
    401      system data on the Alpha).  */ 
    402  
    403   bss_start = my_begbss; 
    404   bss_size = my_endbss - my_begbss; 
    405   bss_section = rva_to_section (PTR_TO_RVA (my_begbss), nt_header); 
    406   if (bss_section != rva_to_section (PTR_TO_RVA (my_endbss), nt_header)) 
    407     { 
    408       printf ("Uninitialized data is not in a single section...bailing\n"); 
    409       exit (1); 
    410     } 
    411   /* Compute how much the .bss section's raw data will grow.  */ 
    412   extra_bss_size = 
    413     ROUND_UP (RVA_TO_SECTION_OFFSET (PTR_TO_RVA (my_endbss), bss_section), 
    414               nt_header->OptionalHeader.FileAlignment) 
    415     - bss_section->SizeOfRawData; 
    416  
    417   bss_start_static = my_begbss_static; 
    418   bss_size_static = my_endbss_static - my_begbss_static; 
    419   bss_section_static = rva_to_section (PTR_TO_RVA (my_begbss_static), nt_header); 
    420   if (bss_section_static != rva_to_section (PTR_TO_RVA (my_endbss_static), nt_header)) 
    421     { 
    422       printf ("Uninitialized static data is not in a single section...bailing\n"); 
    423       exit (1); 
    424     } 
    425   /* Compute how much the static .bss section's raw data will grow.  */ 
    426   extra_bss_size_static = 
    427     ROUND_UP (RVA_TO_SECTION_OFFSET (PTR_TO_RVA (my_endbss_static), bss_section_static), 
    428               nt_header->OptionalHeader.FileAlignment) 
    429     - bss_section_static->SizeOfRawData; 
    430  
    431   /* Combine the bss sections into one if they overlap.  */ 
    432   overlap = 0; 
    433   if (bss_start < bss_start_static) 
    434     { 
    435       if (bss_start_static < bss_start + bss_size) 
    436         overlap = 1; 
    437     } 
    438   else 
    439     { 
    440       if (bss_start < bss_start_static + bss_size_static) 
    441         overlap = 1; 
    442     } 
    443   if (overlap) 
    444     { 
    445       if (bss_section != bss_section_static) 
    446         { 
    447           printf ("BSS data not in a single section...bailing\n"); 
    448           exit (1); 
    449         } 
    450       bss_start = min (bss_start, bss_start_static); 
    451       bss_size = max (my_endbss, my_endbss_static) - bss_start; 
    452       bss_section_static = 0; 
    453       extra_bss_size_static = 0; 
    454     } 
    455  
    456   heap_section = rva_to_section (PTR_TO_RVA (get_heap_start ()), nt_header); 
    457 } 
    458  
    459  
    460 /* The dump routines.  */ 
    461  
    462 static void 
    463 copy_executable_and_dump_data (file_data *p_infile,  
    464                                file_data *p_outfile) 
    465 { 
    466   unsigned char *dst, *dst_save; 
    467   PIMAGE_DOS_HEADER dos_header; 
    468   PIMAGE_NT_HEADERS nt_header; 
    469   PIMAGE_NT_HEADERS dst_nt_header; 
    470   PIMAGE_SECTION_HEADER section; 
    471   PIMAGE_SECTION_HEADER dst_section; 
    472   DWORD offset; 
    473   int i; 
    474  
    475 #define COPY_CHUNK(message, src, size)                                          \ 
    476   do {                                                                          \ 
    477     unsigned char *s = (void *)(src);                                           \ 
    478     unsigned long count = (size);                                               \ 
    479     printf ("%s\n", (message));                                                 \ 
    480     printf ("\t0x%08x Offset in input file.\n", s - p_infile->file_base);       \ 
    481     printf ("\t0x%08x Offset in output file.\n", dst - p_outfile->file_base);   \ 
    482     printf ("\t0x%08x Size in bytes.\n", count);                                \ 
    483     memcpy (dst, s, count);                                                     \ 
    484     dst += count;                                                               \ 
    485   } while (0) 
    486  
    487 #define COPY_PROC_CHUNK(message, src, size)                                     \ 
    488   do {                                                                          \ 
    489     unsigned char *s = (void *)(src);                                           \ 
    490     unsigned long count = (size);                                               \ 
    491     printf ("%s\n", (message));                                                 \ 
    492     printf ("\t0x%08x Address in process.\n", s);                               \ 
    493     printf ("\t0x%08x Offset in output file.\n", dst - p_outfile->file_base);   \ 
    494     printf ("\t0x%08x Size in bytes.\n", count);                                \ 
    495     memcpy (dst, s, count);                                                     \ 
    496     dst += count;                                                               \ 
    497   } while (0) 
    498  
    499 #define DST_TO_OFFSET()  PTR_TO_OFFSET (dst, p_outfile) 
    500 #define ROUND_UP_DST(align) \ 
    501   (dst = p_outfile->file_base + ROUND_UP (DST_TO_OFFSET (), (align))) 
    502  
    503   /* Copy the source image sequentially, ie. section by section after 
    504      copying the headers and section table, to simplify the process of 
    505      dumping the raw data for the bss and heap sections. 
    506  
    507      Note that dst is updated implicitly by each COPY_CHUNK.  */ 
    508  
    509   dos_header = (PIMAGE_DOS_HEADER) p_infile->file_base; 
    510   nt_header = (PIMAGE_NT_HEADERS) (((unsigned long) dos_header) +  
    511                                    dos_header->e_lfanew); 
    512   section = IMAGE_FIRST_SECTION (nt_header); 
    513   
    514   dst = (unsigned char *) p_outfile->file_base; 
    515  
    516   COPY_CHUNK ("Copying DOS header...", dos_header, 
    517               (DWORD) nt_header - (DWORD) dos_header); 
    518   dst_nt_header = (PIMAGE_NT_HEADERS) dst; 
    519   COPY_CHUNK ("Copying NT header...", nt_header, 
    520               (DWORD) section - (DWORD) nt_header); 
    521   dst_section = (PIMAGE_SECTION_HEADER) dst; 
    522   COPY_CHUNK ("Copying section table...", section, 
    523               nt_header->FileHeader.NumberOfSections * sizeof (*section)); 
    524  
    525   for (i = 0; i < nt_header->FileHeader.NumberOfSections; i++) 
    526     { 
    527       char msg[100]; 
    528       sprintf (msg, "Copying raw data for %s...", section->Name); 
    529  
    530       /* Align the section's raw data area.  */ 
    531       ROUND_UP_DST (dst_nt_header->OptionalHeader.FileAlignment); 
    532       dst_save = dst; 
    533  
    534       /* Update the file-relative offset for this section's raw data (if 
    535          it has any) in case things have been relocated; we will update 
    536          the other offsets below once we know where everything is.  */ 
    537       if (dst_section->PointerToRawData) 
    538         dst_section->PointerToRawData = DST_TO_OFFSET (); 
    539  
    540       /* Can always copy the original raw data.  */ 
    541       COPY_CHUNK 
    542         (msg, OFFSET_TO_PTR (section->PointerToRawData, p_infile), 
    543          section->SizeOfRawData); 
    544  
    545       /* Note that various sections below may be aliases.  */ 
    546       if (section == data_section) 
    547         { 
    548           dst = dst_save 
    549             + RVA_TO_SECTION_OFFSET (PTR_TO_RVA (data_start), dst_section); 
    550           COPY_PROC_CHUNK ("Dumping initialized data...", data_start, data_size); 
    551           dst = dst_save + dst_section->SizeOfRawData; 
    552         } 
    553       if (section == bss_section) 
    554         { 
    555           /* Dump contents of bss variables, adjusting the section's raw 
    556              data size as necessary.  */ 
    557           dst = dst_save 
    558             + RVA_TO_SECTION_OFFSET (PTR_TO_RVA (bss_start), dst_section); 
    559           COPY_PROC_CHUNK ("Dumping bss data...", bss_start, bss_size); 
    560           ROUND_UP_DST (dst_nt_header->OptionalHeader.FileAlignment); 
    561           dst_section->PointerToRawData = PTR_TO_OFFSET (dst_save, p_outfile); 
    562           /* Determine new size of raw data area.  */ 
    563           dst = max (dst, dst_save + dst_section->SizeOfRawData); 
    564           dst_section->SizeOfRawData = dst - dst_save; 
    565           dst_section->Characteristics &= ~IMAGE_SCN_CNT_UNINITIALIZED_DATA; 
    566           dst_section->Characteristics |= IMAGE_SCN_CNT_INITIALIZED_DATA; 
    567         } 
    568       if (section == bss_section_static) 
    569         { 
    570           /* Dump contents of static bss variables, adjusting the 
    571              section's raw data size as necessary.  */ 
    572           dst = dst_save 
    573             + RVA_TO_SECTION_OFFSET (PTR_TO_RVA (bss_start_static), dst_section); 
    574           COPY_PROC_CHUNK ("Dumping static bss data...", bss_start_static, bss_size_static); 
    575           ROUND_UP_DST (dst_nt_header->OptionalHeader.FileAlignment); 
    576           dst_section->PointerToRawData = PTR_TO_OFFSET (dst_save, p_outfile); 
    577           /* Determine new size of raw data area.  */ 
    578           dst = max (dst, dst_save + dst_section->SizeOfRawData); 
    579           dst_section->SizeOfRawData = dst - dst_save; 
    580           dst_section->Characteristics &= ~IMAGE_SCN_CNT_UNINITIALIZED_DATA; 
    581           dst_section->Characteristics |= IMAGE_SCN_CNT_INITIALIZED_DATA; 
    582         } 
    583       if (section == heap_section) 
    584         { 
    585           DWORD heap_start = get_heap_start (); 
    586           DWORD heap_size = get_committed_heap_size (); 
    587  
    588           /* Dump the used portion of the predump heap, adjusting the 
    589              section's size to the appropriate size.  */ 
    590           dst = dst_save 
    591             + RVA_TO_SECTION_OFFSET (PTR_TO_RVA (heap_start), dst_section); 
    592           COPY_PROC_CHUNK ("Dumping heap...", heap_start, heap_size); 
    593           ROUND_UP_DST (dst_nt_header->OptionalHeader.FileAlignment); 
    594           dst_section->PointerToRawData = PTR_TO_OFFSET (dst_save, p_outfile); 
    595           /* Determine new size of raw data area.  */ 
    596           dst = max (dst, dst_save + dst_section->SizeOfRawData); 
    597           dst_section->SizeOfRawData = dst - dst_save; 
    598           /* Reduce the size of the heap section to fit (must be last 
    599              section).  */ 
    600           dst_nt_header->OptionalHeader.SizeOfImage -= 
    601             dst_section->Misc.VirtualSize 
    602             - ROUND_UP (dst_section->SizeOfRawData, 
    603                         dst_nt_header->OptionalHeader.SectionAlignment); 
    604           dst_section->Misc.VirtualSize = 
    605             ROUND_UP (dst_section->SizeOfRawData, 
    606                       dst_nt_header->OptionalHeader.SectionAlignment); 
    607           dst_section->Characteristics &= ~IMAGE_SCN_CNT_UNINITIALIZED_DATA; 
    608           dst_section->Characteristics |= IMAGE_SCN_CNT_INITIALIZED_DATA; 
    609         } 
    610  
    611       section++; 
    612       dst_section++; 
    613     } 
    614  
    615   /* Pad out the final section raw data area.  */ 
    616   ROUND_UP_DST (dst_nt_header->OptionalHeader.FileAlignment); 
    617  
    618   /* Copy remainder of source image.  */ 
    619   do 
    620     section--; 
    621   while (section->PointerToRawData == 0); 
    622   offset = ROUND_UP (section->PointerToRawData + section->SizeOfRawData, 
    623                      nt_header->OptionalHeader.FileAlignment); 
    624   COPY_CHUNK 
    625     ("Copying remainder of executable...", 
    626      OFFSET_TO_PTR (offset, p_infile), 
    627      p_infile->size - offset); 
    628  
    629   /* Final size for new image.  */ 
    630   p_outfile->size = DST_TO_OFFSET (); 
    631  
    632   /* Now patch up remaining file-relative offsets.  */ 
    633   section = IMAGE_FIRST_SECTION (nt_header); 
    634   dst_section = IMAGE_FIRST_SECTION (dst_nt_header); 
    635  
    636 #define ADJUST_OFFSET(var)                                              \ 
    637   do {                                                                  \ 
    638     if ((var) != 0)                                                     \ 
    639       (var) = relocate_offset ((var), nt_header, dst_nt_header);        \ 
    640   } while (0) 
    641  
    642   dst_nt_header->OptionalHeader.SizeOfInitializedData = 0; 
    643   dst_nt_header->OptionalHeader.SizeOfUninitializedData = 0; 
    644   for (i = 0; i < dst_nt_header->FileHeader.NumberOfSections; i++) 
    645     { 
    646       /* Recompute data sizes for completeness.  */ 
    647       if (dst_section[i].Characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA) 
    648         dst_nt_header->OptionalHeader.SizeOfInitializedData += 
    649           ROUND_UP (dst_section[i].Misc.VirtualSize, dst_nt_header->OptionalHeader.FileAlignment); 
    650       else if (dst_section[i].Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA) 
    651         dst_nt_header->OptionalHeader.SizeOfUninitializedData += 
    652           ROUND_UP (dst_section[i].Misc.VirtualSize, dst_nt_header->OptionalHeader.FileAlignment); 
    653  
    654       ADJUST_OFFSET (dst_section[i].PointerToLinenumbers); 
    655     } 
    656  
    657   ADJUST_OFFSET (dst_nt_header->FileHeader.PointerToSymbolTable); 
    658  
    659   /* Update offsets in debug directory entries. */ 
    660   { 
    661     IMAGE_DATA_DIRECTORY debug_dir = 
    662       dst_nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG]; 
    663     PIMAGE_DEBUG_DIRECTORY debug_entry; 
    664  
    665     section = rva_to_section (debug_dir.VirtualAddress, dst_nt_header); 
    666     if (section) 
    667       { 
    668         debug_entry = (PIMAGE_DEBUG_DIRECTORY) 
    669           (RVA_TO_OFFSET (debug_dir.VirtualAddress, section) + p_outfile->file_base); 
    670         debug_dir.Size /= sizeof (IMAGE_DEBUG_DIRECTORY); 
    671  
    672         for (i = 0; i < debug_dir.Size; i++, debug_entry++) 
    673           ADJUST_OFFSET (debug_entry->PointerToRawData); 
    674       } 
    675   } 
    676 } 
    677  
    678  
    679169/* Dump out .data and .bss sections into a new executable.  */ 
    680170void 
     
    702192  printf ("          to %s\n", out_filename); 
    703193 
    704   /* We need to round off our heap to NT's page size.  */ 
    705   round_heap (get_page_size ()); 
     194  /* We need to round off our heap to NT's allocation unit (64KB).  */ 
     195  round_heap (get_allocation_unit ()); 
    706196 
    707197  /* Open the undumped executable file.  */ 
     
    718208  /* The size of the dumped executable is the size of the original 
    719209     executable plus the size of the heap and the size of the .bss section.  */ 
    720   size = in_file.size + 
    721     get_committed_heap_size () + 
    722     extra_bss_size + 
    723     extra_bss_size_static; 
     210  heap_index_in_executable = (unsigned long) 
     211    round_to_next ((unsigned char *) in_file.size, get_allocation_unit ()); 
     212  size = heap_index_in_executable + get_committed_heap_size () + bss_size; 
    724213  if (!open_output_file (&out_file, out_filename, size)) 
    725214    { 
     
    730219 
    731220  /* Set the flag (before dumping).  */ 
    732   using_dynamic_heap = TRUE; 
    733  
    734   copy_executable_and_dump_data (&in_file, &out_file); 
     221  need_to_recreate_heap = TRUE; 
     222 
     223  copy_executable_and_dump_data_section (&in_file, &out_file); 
     224  dump_bss_and_heap (&in_file, &out_file); 
    735225 
    736226  /* Patch up header fields; profiler is picky about this. */ 
     
    767257} 
    768258 
    769 /* eof */ 
     259 
     260/* File handling.  */ 
     261 
     262 
     263int 
     264open_input_file (file_data *p_file, char *filename) 
     265
     266  HANDLE file; 
     267  HANDLE file_mapping; 
     268  void  *file_base; 
     269  unsigned long size, upper_size; 
     270 
     271  file = CreateFile (filename, GENERIC_READ, FILE_SHARE_READ, NULL, 
     272                     OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); 
     273  if (file == INVALID_HANDLE_VALUE)  
     274    return FALSE; 
     275 
     276  size = GetFileSize (file, &upper_size); 
     277  file_mapping = CreateFileMapping (file, NULL, PAGE_READONLY,  
     278                                    0, size, NULL); 
     279  if (!file_mapping)  
     280    return FALSE; 
     281 
     282  file_base = MapViewOfFile (file_mapping, FILE_MAP_READ, 0, 0, size); 
     283  if (file_base == 0)  
     284    return FALSE; 
     285 
     286  p_file->name = filename; 
     287  p_file->size = size; 
     288  p_file->file = file; 
     289  p_file->file_mapping = file_mapping; 
     290  p_file->file_base = file_base; 
     291 
     292  return TRUE; 
     293
     294 
     295int 
     296open_output_file (file_data *p_file, char *filename, unsigned long size) 
     297
     298  HANDLE file; 
     299  HANDLE file_mapping; 
     300  void  *file_base; 
     301 
     302  file = CreateFile (filename, GENERIC_READ | GENERIC_WRITE, 0, NULL, 
     303                     CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); 
     304  if (file == INVALID_HANDLE_VALUE)  
     305    return FALSE; 
     306 
     307  file_mapping = CreateFileMapping (file, NULL, PAGE_READWRITE,  
     308                                    0, size, NULL); 
     309  if (!file_mapping)  
     310    return FALSE; 
     311   
     312  file_base = MapViewOfFile (file_mapping, FILE_MAP_WRITE, 0, 0, size); 
     313  if (file_base == 0)  
     314    return FALSE; 
     315   
     316  p_file->name = filename; 
     317  p_file->size = size; 
     318  p_file->file = file; 
     319  p_file->file_mapping = file_mapping; 
     320  p_file->file_base = file_base; 
     321 
     322  return TRUE; 
     323
     324 
     325/* Close the system structures associated with the given file.  */ 
     326void 
     327close_file_data (file_data *p_file) 
     328
     329    UnmapViewOfFile (p_file->file_base); 
     330    CloseHandle (p_file->file_mapping); 
     331    CloseHandle (p_file->file); 
     332
     333 
     334 
     335/* Routines to manipulate NT executable file sections.  */ 
     336 
     337#ifdef SEPARATE_BSS_SECTION 
     338static void 
     339get_bss_info_from_map_file (file_data *p_infile, PUCHAR *p_bss_start,  
     340                            DWORD *p_bss_size) 
     341
     342  int n, start, len; 
     343  char map_filename[MAX_PATH]; 
     344  char buffer[256]; 
     345  FILE *map; 
     346 
     347  /* Overwrite the .exe extension on the executable file name with 
     348     the .map extension.  */ 
     349  strcpy (map_filename, p_infile->name); 
     350  n = strlen (map_filename) - 3; 
     351  strcpy (&map_filename[n], "map"); 
     352 
     353  map = fopen (map_filename, "r"); 
     354  if (!map) 
     355    { 
     356      printf ("Failed to open map file %s, error %d...bailing out.\n", 
     357              map_filename, GetLastError ()); 
     358      exit (-1); 
     359    } 
     360 
     361  while (fgets (buffer, sizeof (buffer), map)) 
     362    { 
     363      if (!(strstr (buffer, ".bss") && strstr (buffer, "DATA"))) 
     364        continue; 
     365      n = sscanf (buffer, " %*d:%x %x", &start, &len); 
     366      if (n != 2) 
     367        { 
     368          printf ("Failed to scan the .bss section line:\n%s", buffer); 
     369          exit (-1); 
     370        } 
     371      break; 
     372    } 
     373  *p_bss_start = (PUCHAR) start; 
     374  *p_bss_size = (DWORD) len; 
     375
     376#endif 
     377 
     378unsigned long 
     379get_section_size (PIMAGE_SECTION_HEADER p_section) 
     380
     381  /* The true section size, before rounding.  Some linkers swap the 
     382     meaning of these two values.  */ 
     383  return min (p_section->SizeOfRawData, 
     384              p_section->Misc.VirtualSize); 
     385
     386 
     387/* Return pointer to section header for named section. */ 
     388IMAGE_SECTION_HEADER * 
     389find_section (char * name, IMAGE_NT_HEADERS * nt_header) 
     390
     391  PIMAGE_SECTION_HEADER section; 
     392  int i; 
     393 
     394  section = IMAGE_FIRST_SECTION (nt_header); 
     395 
     396  for (i = 0; i < nt_header->FileHeader.NumberOfSections; i++) 
     397    { 
     398      if (strcmp (section->Name, name) == 0) 
     399        return section; 
     400      section++; 
     401    } 
     402  return NULL; 
     403
     404 
     405/* Return pointer to section header for section containing the given 
     406   relative virtual address. */ 
     407IMAGE_SECTION_HEADER * 
     408rva_to_section (DWORD rva, IMAGE_NT_HEADERS * nt_header) 
     409
     410  PIMAGE_SECTION_HEADER section; 
     411  int i; 
     412 
     413  section = IMAGE_FIRST_SECTION (nt_header); 
     414 
     415  for (i = 0; i < nt_header->FileHeader.NumberOfSections; i++) 
     416    { 
     417      if (rva >= section->VirtualAddress 
     418          && rva < section->VirtualAddress + section->SizeOfRawData) 
     419        return section; 
     420      section++; 
     421    } 
     422  return NULL; 
     423
     424 
     425 
     426/* Flip through the executable and cache the info necessary for dumping.  */ 
     427static void 
     428get_section_info (file_data *p_infile) 
     429
     430  PIMAGE_DOS_HEADER dos_header; 
     431  PIMAGE_NT_HEADERS nt_header; 
     432  PIMAGE_SECTION_HEADER section, data_section; 
     433  unsigned char *ptr; 
     434  int i; 
     435   
     436  dos_header = (PIMAGE_DOS_HEADER) p_infile->file_base; 
     437  if (dos_header->e_magic != IMAGE_DOS_SIGNATURE)  
     438    { 
     439      printf ("Unknown EXE header in %s...bailing.\n", p_infile->name); 
     440      exit (1); 
     441    } 
     442  nt_header = (PIMAGE_NT_HEADERS) (((unsigned long) dos_header) +  
     443                                   dos_header->e_lfanew); 
     444  if (nt_header == NULL)  
     445    { 
     446      printf ("Failed to find IMAGE_NT_HEADER in %s...bailing.\n",  
     447             p_infile->name); 
     448      exit (1); 
     449    } 
     450 
     451  /* Check the NT header signature ...  */ 
     452  if (nt_header->Signature != IMAGE_NT_SIGNATURE)  
     453    { 
     454      printf ("Invalid IMAGE_NT_SIGNATURE 0x%x in %s...bailing.\n", 
     455              nt_header->Signature, p_infile->name); 
     456    } 
     457 
     458  /* Flip through the sections for .data and .bss ...  */ 
     459  section = (PIMAGE_SECTION_HEADER) IMAGE_FIRST_SECTION (nt_header); 
     460  for (i = 0; i < nt_header->FileHeader.NumberOfSections; i++)  
     461    { 
     462#ifdef SEPARATE_BSS_SECTION 
     463      if (!strcmp (section->Name, ".bss"))  
     464        { 
     465          /* The .bss section.  */ 
     466          ptr = (char *) nt_header->OptionalHeader.ImageBase + 
     467            section->VirtualAddress; 
     468          bss_start = ptr; 
     469          bss_size = get_section_size (section); 
     470        } 
     471#endif 
     472#if 0 
     473      if (!strcmp (section->Name, ".data"))  
     474        { 
     475          /* From lastfile.c  */ 
     476          extern char my_edata[]; 
     477 
     478          /* The .data section.  */ 
     479          data_section = section; 
     480          ptr = (char *) nt_header->OptionalHeader.ImageBase + 
     481            section->VirtualAddress; 
     482          data_start_va = ptr; 
     483          data_start_file = section->PointerToRawData; 
     484 
     485          /* We want to only write Emacs data back to the executable, 
     486             not any of the library data (if library data is included, 
     487             then a dumped Emacs won't run on system versions other 
     488             than the one Emacs was dumped on).  */ 
     489          data_size = my_edata - data_start_va; 
     490        } 
     491#else 
     492      if (!strcmp (section->Name, "EMDATA"))  
     493        { 
     494          /* The Emacs initialized data section.  */ 
     495          data_section = section; 
     496          ptr = (char *) nt_header->OptionalHeader.ImageBase + 
     497            section->VirtualAddress; 
     498          data_start_va = ptr; 
     499          data_start_file = section->PointerToRawData; 
     500 
     501          /* Write back the full section.  */ 
     502          data_size = get_section_size (section); 
     503        } 
     504#endif 
     505      section++; 
     506    } 
     507 
     508#ifdef SEPARATE_BSS_SECTION 
     509  if (bss_start == UNINIT_PTR && bss_size == UNINIT_LONG) 
     510    { 
     511      /* Starting with MSVC 4.0, the .bss section has been eliminated 
     512         and appended virtually to the end of the .data section.  Our 
     513         only hint about where the .bss section starts in the address 
     514         comes from the SizeOfRawData field in the .data section 
     515         header.  Unfortunately, this field is only approximate, as it 
     516         is a rounded number and is typically rounded just beyond the 
     517         start of the .bss section.  To find the start and size of the 
     518         .bss section exactly, we have to peek into the map file.  */ 
     519      get_bss_info_from_map_file (p_infile, &ptr, &bss_size); 
     520      bss_start = ptr + nt_header->OptionalHeader.ImageBase 
     521        + data_section->VirtualAddress; 
     522    } 
     523#else 
     524/* As noted in lastfile.c, the Alpha (but not the Intel) MSVC linker 
     525   globally segregates all static and public bss data (ie. across all 
     526   linked modules, not just per module), so we must take both static and 
     527   public bss areas into account to determine the true extent of the bss 
     528   area used by Emacs. 
     529 
     530   To be strictly correct, we should dump the static and public bss 
     531   areas used by Emacs separately if non-overlapping (since otherwise we 
     532   are dumping bss data belonging to system libraries, eg. the static 
     533   bss system data on the Alpha).  However, in practice this doesn't 
     534   seem to matter, since presumably the system libraries always 
     535   reinitialize their bss variables.  */ 
     536  bss_start = min (my_begbss, my_begbss_static); 
     537  bss_size = max (my_endbss, my_endbss_static) - bss_start; 
     538#endif 
     539
     540 
     541 
     542/* The dump routines.  */ 
     543 
     544static void 
     545copy_executable_and_dump_data_section (file_data *p_infile,  
     546                                       file_data *p_outfile) 
     547
     548  unsigned char *data_file, *data_va; 
     549  unsigned long size, index; 
     550   
     551  /* Get a pointer to where the raw data should go in the executable file.  */ 
     552  data_file = (char *) p_outfile->file_base + data_start_file; 
     553 
     554  /* Get a pointer to the raw data in our address space.  */ 
     555  data_va = data_start_va; 
     556     
     557  size = (DWORD) data_file - (DWORD) p_outfile->file_base; 
     558  printf ("Copying executable up to data section...\n"); 
     559  printf ("\t0x%08x Offset in input file.\n", 0); 
     560  printf ("\t0x%08x Offset in output file.\n", 0); 
     561  printf ("\t0x%08x Size in bytes.\n", size); 
     562  memcpy (p_outfile->file_base, p_infile->file_base, size); 
     563   
     564  size = data_size; 
     565  printf ("Dumping .data section...\n"); 
     566  printf ("\t0x%08x Address in process.\n", data_va); 
     567  printf ("\t0x%08x Offset in output file.\n",  
     568          data_file - p_outfile->file_base); 
     569  printf ("\t0x%08x Size in bytes.\n", size); 
     570  memcpy (data_file, data_va, size); 
     571   
     572  index = (DWORD) data_file + size - (DWORD) p_outfile->file_base; 
     573  size = p_infile->size - index; 
     574  printf ("Copying rest of executable...\n"); 
     575  printf ("\t0x%08x Offset in input file.\n", index); 
     576  printf ("\t0x%08x Offset in output file.\n", index); 
     577  printf ("\t0x%08x Size in bytes.\n", size); 
     578  memcpy ((char *) p_outfile->file_base + index,  
     579          (char *) p_infile->file_base + index, size); 
     580
     581 
     582static void 
     583dump_bss_and_heap (file_data *p_infile, file_data *p_outfile) 
     584
     585    unsigned char *heap_data, *bss_data; 
     586    unsigned long size, index; 
     587 
     588    printf ("Dumping heap into executable...\n"); 
     589 
     590    index = heap_index_in_executable; 
     591    size = get_committed_heap_size (); 
     592    heap_data = get_heap_start (); 
     593 
     594    printf ("\t0x%08x Heap start in process.\n", heap_data); 
     595    printf ("\t0x%08x Heap offset in executable.\n", index); 
     596    printf ("\t0x%08x Heap size in bytes.\n", size); 
     597 
     598    memcpy ((PUCHAR) p_outfile->file_base + index, heap_data, size); 
     599 
     600    printf ("Dumping .bss into executable...\n"); 
     601     
     602    index += size; 
     603    size = bss_size; 
     604    bss_data = bss_start; 
     605     
     606    printf ("\t0x%08x BSS start in process.\n", bss_data); 
     607    printf ("\t0x%08x BSS offset in executable.\n", index); 
     608    printf ("\t0x%08x BSS size in bytes.\n", size); 
     609    memcpy ((char *) p_outfile->file_base + index, bss_data, size); 
     610
     611 
     612 
     613/* Reload and remap routines.  */ 
     614 
     615void 
     616w32_fatal_reload_error (char *step) 
     617
     618  int error = GetLastError (); 
     619  char *buffer = alloca (4096); 
     620 
     621  sprintf (buffer,  
     622           "Emacs failed to load its dumped heap back into its address space.\n" 
     623           "The error occurred during the following step:\n\n" 
     624           "%s\n\n" 
     625           "GetLastError = %d\n\n" 
     626           "Heap start:  0x%08x\n" 
     627           "Heap commit:  0x%08x\n" 
     628           "Heap end:  0x%08x\n\n" 
     629           "This error typically happens when the system loads a DLL into\n" 
     630           "the middle of Emacs' address space, preventing Emacs from\n" 
     631           "loading its heap there.  If this happens only occasionally, then\n" 
     632           "you can probably ignore it.  But if it happens so often that\n" 
     633