comparison src/unexnt.c @ 298:70ad99077275 r21-0b47

Import from CVS: tag r21-0b47
author cvs
date Mon, 13 Aug 2007 10:39:40 +0200
parents 57709be46d1b
children c6de09ad3017
comparison
equal deleted inserted replaced
297:deca3c1083ac 298:70ad99077275
20 20
21 Geoff Voelker (voelker@cs.washington.edu) 8-12-94 */ 21 Geoff Voelker (voelker@cs.washington.edu) 8-12-94 */
22 22
23 /* Adapted for XEmacs by David Hobley <david@spook-le0.cia.com.au> */ 23 /* Adapted for XEmacs by David Hobley <david@spook-le0.cia.com.au> */
24 24
25 /* The linkers that come with MSVC >= 4.0 merge .bss into .data and reorder
26 * uninitialised data so that the .data section looks like:
27 *
28 * crt0 initialised data
29 * emacs initialised data
30 * <my_edata>
31 * library initialised data
32 * <start of bss part of .data>
33 * emacs static uninitialised data
34 * library static uninitialised data
35 * emacs global uninitialised data
36 * <my_ebss>
37 * library global uninitialised data
38 *
39 * This means that we can't use the normal my_ebss in lastfile.c trick to
40 * differentiate between unitialised data that belongs to emacs and
41 * uninitialised data that belongs to system libraries. This is bad because
42 * we do want to initialise the emacs data, but we don't want to initialise
43 * the system library data.
44 *
45 * To solve this problem using MSVC >= 5.0 we use a pragma directive to tell
46 * the compiler to put emacs's data (both initialised and uninitialised) in
47 * a separate section in the executable, and we only dump that section. This
48 * means that all files that define initialized data must include config.h
49 * to pick up the pragma. We don't try to make any part of that section
50 * read-only.
51 *
52 * This pragma directive isn't supported by the MSVC 4.x compiler. Instead,
53 * we dump crt0 initialised data and library static uninitialised data in
54 * addition to the emacs data. This is wrong, but we appear to be able to
55 * get away with it. A proper fix might involve the introduction of a static
56 * version of my_ebss in lastfile.c and a new firstfile.c file. jhar */
57
58 #include <config.h>
25 #include <stdlib.h> /* _fmode */ 59 #include <stdlib.h> /* _fmode */
26 #include <stdio.h> 60 #include <stdio.h>
27 #include <fcntl.h> 61 #include <fcntl.h>
28 #include <windows.h> 62 #include <windows.h>
63
64 /* From IMAGEHLP.H which is not installed by default by MSVC < 5 */
65 /* The IMAGEHLP.DLL library is not distributed by default with Windows95 */
66 PIMAGE_NT_HEADERS
67 (__stdcall * pfnCheckSumMappedFile) (LPVOID BaseAddress, DWORD FileLength,
68 LPDWORD HeaderSum, LPDWORD CheckSum);
29 69
30 #if 0 70 #if 0
31 extern BOOL ctrl_c_handler (unsigned long type); 71 extern BOOL ctrl_c_handler (unsigned long type);
32 #endif 72 #endif
33 73
55 PUCHAR data_start_va = UNINIT_PTR; 95 PUCHAR data_start_va = UNINIT_PTR;
56 DWORD data_start_file = UNINIT_LONG; 96 DWORD data_start_file = UNINIT_LONG;
57 DWORD data_size = UNINIT_LONG; 97 DWORD data_size = UNINIT_LONG;
58 98
59 /* Cached info about the .bss section in the executable. */ 99 /* Cached info about the .bss section in the executable. */
60 PUCHAR bss_start = UNINIT_PTR; 100 #ifndef DUMP_SEPARATE_SECTION
61 DWORD bss_size = UNINIT_LONG; 101 PUCHAR bss_start = 0;
102 DWORD bss_size = 0;
103 #endif
62 104
63 #ifdef HAVE_NTGUI 105 #ifdef HAVE_NTGUI
64 HINSTANCE hinst = NULL; 106 HINSTANCE hinst = NULL;
65 HINSTANCE hprevinst = NULL; 107 HINSTANCE hprevinst = NULL;
66 LPSTR lpCmdLine = ""; 108 LPSTR lpCmdLine = "";
72 address space before we can actually hand off control to the startup 114 address space before we can actually hand off control to the startup
73 code supplied by NT (primarily because that code relies upon malloc ()). */ 115 code supplied by NT (primarily because that code relies upon malloc ()). */
74 void 116 void
75 _start (void) 117 _start (void)
76 { 118 {
119 char * p;
77 extern void mainCRTStartup (void); 120 extern void mainCRTStartup (void);
78 121
79 /* Cache system info, e.g., the NT page size. */ 122 /* Cache system info, e.g., the NT page size. */
80 cache_system_info (); 123 cache_system_info ();
81 124
90 133
91 if (GetModuleFileName (NULL, executable_path, MAX_PATH) == 0) 134 if (GetModuleFileName (NULL, executable_path, MAX_PATH) == 0)
92 { 135 {
93 exit (1); 136 exit (1);
94 } 137 }
138
139 /* To allow profiling, make sure executable_path names the .exe
140 file, not the file created by the profiler */
141 p = strrchr (executable_path, '\\');
142 strcpy (p+1, PATH_PROGNAME ".exe");
143
95 recreate_heap (executable_path); 144 recreate_heap (executable_path);
96 heap_state = HEAP_LOADED; 145 heap_state = HEAP_LOADED;
97 } 146 }
98 147
99 /* The default behavior is to treat files as binary and patch up 148 /* The default behavior is to treat files as binary and patch up
124 { 173 {
125 file_data in_file, out_file; 174 file_data in_file, out_file;
126 char out_filename[MAX_PATH], in_filename[MAX_PATH]; 175 char out_filename[MAX_PATH], in_filename[MAX_PATH];
127 unsigned long size; 176 unsigned long size;
128 char *ptr; 177 char *ptr;
178 HANDLE hImagehelp;
129 179
130 /* Make sure that the input and output filenames have the 180 /* Make sure that the input and output filenames have the
131 ".exe" extension...patch them up if they don't. */ 181 ".exe" extension...patch them up if they don't. */
132 strcpy (in_filename, old_name); 182 strcpy (in_filename, old_name);
133 ptr = in_filename + strlen (in_filename) - 4; 183 ptr = in_filename + strlen (in_filename) - 4;
172 heap_state = HEAP_UNLOADED; 222 heap_state = HEAP_UNLOADED;
173 223
174 copy_executable_and_dump_data_section (&in_file, &out_file); 224 copy_executable_and_dump_data_section (&in_file, &out_file);
175 dump_bss_and_heap (&in_file, &out_file); 225 dump_bss_and_heap (&in_file, &out_file);
176 226
227 /* Patch up header fields; profiler is picky about this. */
228 hImagehelp = LoadLibrary ("imagehlp.dll");
229 if (hImagehelp)
230 {
231 PIMAGE_DOS_HEADER dos_header;
232 PIMAGE_NT_HEADERS nt_header;
233 DWORD headersum;
234 DWORD checksum;
235
236 dos_header = (PIMAGE_DOS_HEADER) out_file.file_base;
237 nt_header = (PIMAGE_NT_HEADERS) ((char *) dos_header + dos_header->e_lfanew);
238
239 nt_header->OptionalHeader.CheckSum = 0;
240 // nt_header->FileHeader.TimeDateStamp = time (NULL);
241 // dos_header->e_cp = size / 512;
242 // nt_header->OptionalHeader.SizeOfImage = size;
243
244 pfnCheckSumMappedFile = (void *) GetProcAddress (hImagehelp, "CheckSumMappedFile");
245 if (pfnCheckSumMappedFile)
246 {
247 // nt_header->FileHeader.TimeDateStamp = time (NULL);
248 pfnCheckSumMappedFile (out_file.file_base,
249 out_file.size,
250 &headersum,
251 &checksum);
252 nt_header->OptionalHeader.CheckSum = checksum;
253 }
254 FreeLibrary (hImagehelp);
255 }
256
177 close_file_data (&in_file); 257 close_file_data (&in_file);
178 close_file_data (&out_file); 258 close_file_data (&out_file);
179 } 259 }
180 260
181 261
223 303
224 file = CreateFile (filename, GENERIC_READ | GENERIC_WRITE, 0, NULL, 304 file = CreateFile (filename, GENERIC_READ | GENERIC_WRITE, 0, NULL,
225 CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); 305 CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
226 if (file == INVALID_HANDLE_VALUE) 306 if (file == INVALID_HANDLE_VALUE)
227 return FALSE; 307 return FALSE;
228 308
229 file_mapping = CreateFileMapping (file, NULL, PAGE_READWRITE, 309 file_mapping = CreateFileMapping (file, NULL, PAGE_READWRITE,
230 0, size, NULL); 310 0, size, NULL);
231 if (!file_mapping) 311 if (!file_mapping)
232 return FALSE; 312 return FALSE;
233 313
254 } 334 }
255 335
256 336
257 /* Routines to manipulate NT executable file sections. */ 337 /* Routines to manipulate NT executable file sections. */
258 338
339 #ifndef DUMP_SEPARATE_SECTION
259 static void 340 static void
260 get_bss_info_from_map_file (file_data *p_infile, PUCHAR *p_bss_start, 341 get_bss_info_from_map_file (file_data *p_infile, PUCHAR *p_bss_start,
261 DWORD *p_bss_size) 342 DWORD *p_bss_size)
262 { 343 {
263 int n, start, len; 344 int n, start, len;
292 break; 373 break;
293 } 374 }
294 *p_bss_start = (PUCHAR) start; 375 *p_bss_start = (PUCHAR) start;
295 *p_bss_size = (DWORD) len; 376 *p_bss_size = (DWORD) len;
296 } 377 }
297 378 #endif
298 /* Return pointer to section header for named section. */
299 IMAGE_SECTION_HEADER *
300 find_section (char * name, IMAGE_NT_HEADERS * nt_header)
301 {
302 PIMAGE_SECTION_HEADER section;
303 int i;
304
305 section = IMAGE_FIRST_SECTION (nt_header);
306
307 for (i = 0; i < nt_header->FileHeader.NumberOfSections; i++)
308 {
309 if (strcmp (section->Name, name) == 0)
310 return section;
311 section++;
312 }
313 return NULL;
314 }
315 379
316 /* Return pointer to section header for section containing the given 380 /* Return pointer to section header for section containing the given
317 relative virtual address. */ 381 relative virtual address. */
318 IMAGE_SECTION_HEADER * 382 IMAGE_SECTION_HEADER *
319 rva_to_section (DWORD rva, IMAGE_NT_HEADERS * nt_header) 383 rva_to_section (DWORD rva, IMAGE_NT_HEADERS * nt_header)
323 387
324 section = IMAGE_FIRST_SECTION (nt_header); 388 section = IMAGE_FIRST_SECTION (nt_header);
325 389
326 for (i = 0; i < nt_header->FileHeader.NumberOfSections; i++) 390 for (i = 0; i < nt_header->FileHeader.NumberOfSections; i++)
327 { 391 {
328 if (rva >= section->VirtualAddress && 392 if (rva >= section->VirtualAddress
329 rva < section->VirtualAddress + section->SizeOfRawData) 393 && rva < section->VirtualAddress + section->SizeOfRawData)
330 return section; 394 return section;
331 section++; 395 section++;
332 } 396 }
333 return NULL; 397 return NULL;
334 } 398 }
335 399
336 static unsigned long
337 get_section_size (PIMAGE_SECTION_HEADER p_section)
338 {
339 /* The section size is in different locations in the different versions. */
340 switch (get_nt_minor_version ())
341 {
342 case 10:
343 return p_section->SizeOfRawData;
344 default:
345 return p_section->Misc.VirtualSize;
346 }
347 }
348 400
349 /* Flip through the executable and cache the info necessary for dumping. */ 401 /* Flip through the executable and cache the info necessary for dumping. */
350 static void 402 static void
351 get_section_info (file_data *p_infile) 403 get_section_info (file_data *p_infile)
352 { 404 {
380 432
381 /* Flip through the sections for .data and .bss ... */ 433 /* Flip through the sections for .data and .bss ... */
382 section = (PIMAGE_SECTION_HEADER) IMAGE_FIRST_SECTION (nt_header); 434 section = (PIMAGE_SECTION_HEADER) IMAGE_FIRST_SECTION (nt_header);
383 for (i = 0; i < nt_header->FileHeader.NumberOfSections; i++) 435 for (i = 0; i < nt_header->FileHeader.NumberOfSections; i++)
384 { 436 {
437 #ifndef DUMP_SEPARATE_SECTION
385 if (!strcmp (section->Name, ".bss")) 438 if (!strcmp (section->Name, ".bss"))
386 { 439 {
387 /* The .bss section. */ 440 extern int my_ebss; /* From lastfile.c */
441
388 ptr = (char *) nt_header->OptionalHeader.ImageBase + 442 ptr = (char *) nt_header->OptionalHeader.ImageBase +
389 section->VirtualAddress; 443 section->VirtualAddress;
390 bss_start = ptr; 444 bss_start = ptr;
391 bss_size = get_section_size (section); 445 bss_size = (char*)&my_ebss - (char*)bss_start;
392 } 446 }
447
393 if (!strcmp (section->Name, ".data")) 448 if (!strcmp (section->Name, ".data"))
449 #else
450 if (!strcmp (section->Name, "xdata"))
451 #endif
394 { 452 {
395 /* From lastfile.c */ 453 extern char my_edata[]; /* From lastfile.c */
396 extern char my_edata[];
397 454
398 /* The .data section. */ 455 /* The .data section. */
399 data_section = section; 456 data_section = section;
400 ptr = (char *) nt_header->OptionalHeader.ImageBase + 457 ptr = (char *) nt_header->OptionalHeader.ImageBase +
401 section->VirtualAddress; 458 section->VirtualAddress;
402 data_start_va = ptr; 459 data_start_va = ptr;
403 data_start_file = section->PointerToRawData; 460 data_start_file = section->PointerToRawData;
404 461
405 /* We want to only write Emacs data back to the executable, 462 #ifndef DUMP_SEPARATE_SECTION
406 not any of the library data (if library data is included, 463 /* Write only the part of the section that contains emacs data. */
407 then a dumped Emacs won't run on system versions other
408 than the one Emacs was dumped on). */
409 data_size = my_edata - data_start_va; 464 data_size = my_edata - data_start_va;
465 #else
466 /* Write back the full section. */
467 data_size = section->SizeOfRawData;
468
469 /* This code doesn't know how to grow the raw size of a section. */
470 if (section->SizeOfRawData < section->Misc.VirtualSize)
471 {
472 printf ("The emacs data section is smaller than expected"
473 "...bailing.\n");
474 exit (1);
475 }
476 #endif
410 } 477 }
411 section++; 478 section++;
412 } 479 }
413 480
414 if (bss_start == UNINIT_PTR && bss_size == UNINIT_LONG) 481 #ifndef DUMP_SEPARATE_SECTION
482 if (!bss_start)
415 { 483 {
416 /* Starting with MSVC 4.0, the .bss section has been eliminated 484 /* Starting with MSVC 4.0, the .bss section has been eliminated
417 and appended virtually to the end of the .data section. Our 485 and appended virtually to the end of the .data section. Our
418 only hint about where the .bss section starts in the address 486 only hint about where the .bss section starts in the address
419 comes from the SizeOfRawData field in the .data section 487 comes from the SizeOfRawData field in the .data section
420 header. Unfortunately, this field is only approximate, as it 488 header. Unfortunately, this field is only approximate, as it
421 is a rounded number and is typically rounded just beyond the 489 is a rounded number and is typically rounded just beyond the
422 start of the .bss section. To find the start and size of the 490 start of the .bss section. To find the start and size of the
423 .bss section exactly, we have to peek into the map file. */ 491 .bss section exactly, we have to peek into the map file. */
492 extern int my_ebss;
493
424 get_bss_info_from_map_file (p_infile, &ptr, &bss_size); 494 get_bss_info_from_map_file (p_infile, &ptr, &bss_size);
425 bss_start = ptr + nt_header->OptionalHeader.ImageBase 495 bss_start = ptr + nt_header->OptionalHeader.ImageBase
426 + data_section->VirtualAddress; 496 + data_section->VirtualAddress;
427 } 497 bss_size = (char*)&my_ebss - (char*)bss_start;
498 }
499 #endif
428 } 500 }
429 501
430 502
431 /* The dump routines. */ 503 /* The dump routines. */
432 504
455 DUMP_MSG (("\t0x%08x Offset in output file.\n", 0)); 527 DUMP_MSG (("\t0x%08x Offset in output file.\n", 0));
456 DUMP_MSG (("\t0x%08x Size in bytes.\n", size)); 528 DUMP_MSG (("\t0x%08x Size in bytes.\n", size));
457 memcpy (p_outfile->file_base, p_infile->file_base, size); 529 memcpy (p_outfile->file_base, p_infile->file_base, size);
458 530
459 size = data_size; 531 size = data_size;
460 DUMP_MSG (("Dumping .data section...\n")); 532 DUMP_MSG (("Dumping data section...\n"));
461 DUMP_MSG (("\t0x%08x Address in process.\n", data_va)); 533 DUMP_MSG (("\t0x%08x Address in process.\n", data_va));
462 DUMP_MSG (("\t0x%08x Offset in output file.\n", 534 DUMP_MSG (("\t0x%08x Offset in output file.\n",
463 data_file - p_outfile->file_base)); 535 data_file - p_outfile->file_base));
464 DUMP_MSG (("\t0x%08x Size in bytes.\n", size)); 536 DUMP_MSG (("\t0x%08x Size in bytes.\n", size));
465 memcpy (data_file, data_va, size); 537 memcpy (data_file, data_va, size);
478 dump_bss_and_heap (file_data *p_infile, file_data *p_outfile) 550 dump_bss_and_heap (file_data *p_infile, file_data *p_outfile)
479 { 551 {
480 unsigned char *heap_data, *bss_data; 552 unsigned char *heap_data, *bss_data;
481 unsigned long size, index; 553 unsigned long size, index;
482 554
483 DUMP_MSG (("Dumping heap into executable...\n")); 555 DUMP_MSG (("Dumping heap onto end of executable...\n"));
484 556
485 index = heap_index_in_executable; 557 index = heap_index_in_executable;
486 size = get_committed_heap_size (); 558 size = get_committed_heap_size ();
487 heap_data = get_heap_start (); 559 heap_data = get_heap_start ();
488 560
490 DUMP_MSG (("\t0x%08x Heap offset in executable.\n", index)); 562 DUMP_MSG (("\t0x%08x Heap offset in executable.\n", index));
491 DUMP_MSG (("\t0x%08x Heap size in bytes.\n", size)); 563 DUMP_MSG (("\t0x%08x Heap size in bytes.\n", size));
492 564
493 memcpy ((PUCHAR) p_outfile->file_base + index, heap_data, size); 565 memcpy ((PUCHAR) p_outfile->file_base + index, heap_data, size);
494 566
495 DUMP_MSG (("Dumping .bss into executable...\n")); 567 #ifndef DUMP_SEPARATE_SECTION
568 printf ("Dumping bss onto end of executable...\n");
496 569
497 index += size; 570 index += size;
498 size = bss_size; 571 size = bss_size;
499 bss_data = bss_start; 572 bss_data = bss_start;
500 573
501 DUMP_MSG (("\t0x%08x BSS start in process.\n", bss_data)); 574 DUMP_MSG (("\t0x%08x BSS start in process.\n", bss_data));
502 DUMP_MSG (("\t0x%08x BSS offset in executable.\n", index)); 575 DUMP_MSG (("\t0x%08x BSS offset in executable.\n", index));
503 DUMP_MSG (("\t0x%08x BSS size in bytes.\n", size)); 576 DUMP_MSG (("\t0x%08x BSS size in bytes.\n", size));
504 memcpy ((char *) p_outfile->file_base + index, bss_data, size); 577 memcpy ((char *) p_outfile->file_base + index, bss_data, size);
578 #endif
505 } 579 }
506 580
507 #undef DUMP_MSG 581 #undef DUMP_MSG
508 582
509 /* Reload and remap routines. */ 583 /* Reload and remap routines. */
510 584
511 585
512 /* Load the dumped .bss section into the .bss area of our address space. */ 586 /* Load the dumped .bss section into the .bss area of our address space. */
587 /* Already done if the .bss was part of a separate emacs data section */
513 void 588 void
514 read_in_bss (char *filename) 589 read_in_bss (char *filename)
515 { 590 {
591 #ifndef DUMP_SEPARATE_SECTION
516 HANDLE file; 592 HANDLE file;
517 unsigned long index, n_read; 593 unsigned long index, n_read;
518 594
519 file = CreateFile (filename, GENERIC_READ, FILE_SHARE_READ, NULL, 595 file = CreateFile (filename, GENERIC_READ, FILE_SHARE_READ, NULL,
520 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); 596 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
530 uninitialized variables. */ 606 uninitialized variables. */
531 if (!ReadFile (file, bss_start, bss_size, &n_read, NULL)) 607 if (!ReadFile (file, bss_start, bss_size, &n_read, NULL))
532 abort (); 608 abort ();
533 609
534 CloseHandle (file); 610 CloseHandle (file);
611 #endif
535 } 612 }
536 613
537 /* Map the heap dumped into the executable file into our address space. */ 614 /* Map the heap dumped into the executable file into our address space. */
538 void 615 void
539 map_in_heap (char *filename) 616 map_in_heap (char *filename)