Mercurial > hg > xemacs-beta
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) |