1
/* unexec for GNU Emacs on Windows NT.
2
Copyright (C) 1994 Free Software Foundation, Inc.
4
This file is part of GNU Emacs.
6
GNU Emacs is free software; you can redistribute it and/or modify
7
it under the terms of the GNU General Public License as published by
8
the Free Software Foundation; either version 2, or (at your option)
11
GNU Emacs is distributed in the hope that it will be useful,
12
but WITHOUT ANY WARRANTY; without even the implied warranty of
13
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
GNU General Public License for more details.
16
You should have received a copy of the GNU General Public License
17
along with GNU Emacs; see the file COPYING. If not, write to
18
the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19
Boston, MA 02111-1307, USA.
21
Geoff Voelker (voelker@cs.washington.edu) 8-12-94
26
/* #include <stdlib.h> */ /* _fmode */
27
/* in case the include of config.h defined it */
33
#include <string.h> /* strrchr */
35
#ifdef _GNU_H_WINDOWS_H
39
/* Include relevant definitions from IMAGEHLP.H, which can be found
40
in \\win32sdk\mstools\samples\image\include\imagehlp.h. */
45
(__stdcall * pfnCheckSumMappedFile) (LPVOID BaseAddress,
57
/* Info for keeping track of our heap. */
58
unsigned char *data_region_base = UNINIT_PTR;
59
unsigned char *data_region_end = UNINIT_PTR;
60
unsigned char *real_data_region_end = UNINIT_PTR;
61
unsigned long data_region_size = UNINIT_LONG;
62
unsigned long reserved_heap_size = UNINIT_LONG;
64
extern BOOL ctrl_c_handler (unsigned long type);
66
extern char my_begdata[];
67
extern char my_edata[];
68
extern char my_begbss[];
69
extern char my_endbss[];
70
extern char *my_begbss_static;
71
extern char *my_endbss_static;
76
HEAP_UNINITIALIZED = 1,
81
/* Basically, our "initialized" flag. */
82
int heap_state = HEAP_UNINITIALIZED;
84
/* So we can find our heap in the file to recreate it. */
85
unsigned long heap_index_in_executable = UNINIT_LONG;
87
static void get_section_info (file_data *p_file);
88
static void copy_executable_and_dump_data_section (file_data *, file_data *);
89
static void dump_bss_and_heap (file_data *p_infile, file_data *p_outfile);
91
/* Cached info about the .data section in the executable. */
92
PUCHAR data_start_va = UNINIT_PTR;
93
DWORD data_start_file = UNINIT_LONG;
94
DWORD data_size = UNINIT_LONG;
96
/* Cached info about the .bss section in the executable. */
97
PUCHAR bss_start = UNINIT_PTR;
98
DWORD bss_size = UNINIT_LONG;
100
void recreate_heap1()
102
char executable_path[MAX_PATH];
104
if (heap_state == HEAP_UNLOADED) {
105
if (GetModuleFileName (NULL, executable_path, MAX_PATH) == 0)
107
printf ("Failed to find path for executable.\n");
111
recreate_heap (executable_path);
113
heap_state = HEAP_LOADED;
119
HINSTANCE hinst = NULL;
120
HINSTANCE hprevinst = NULL;
121
LPSTR lpCmdLine = "";
123
#endif /* HAVE_NTGUI */
126
/* Startup code for running on NT. When we are running as the dumped
127
version, we need to bootstrap our heap and .bss section into our
128
address space before we can actually hand off control to the startup
129
code supplied by NT (primarily because that code relies upon malloc ()). */
133
extern void mainCRTStartup (void);
136
/* Give us a way to debug problems with crashes on startup when
137
running under the MSVC profiler. */
138
if (GetEnvironmentVariable ("EMACS_DEBUG", NULL, 0) > 0)
142
/* Cache system info, e.g., the NT page size. */
143
cache_system_info ();
145
/* If we're a dumped version of emacs then we need to recreate
146
our heap and play tricks with our .bss section. Do this before
147
start up. (WARNING: Do not put any code before this section
148
that relies upon malloc () and runs in the dumped version. It
150
if (heap_state == HEAP_UNLOADED)
152
char executable_path[MAX_PATH];
154
if (GetModuleFileName (NULL, executable_path, MAX_PATH) == 0)
156
printf ("Failed to find path for executable.\n");
161
/* To allow profiling, make sure executable_path names the .exe
162
file, not the ._xe file created by the profiler which contains
163
extra code that makes the stored exe offsets incorrect. (This
164
will not be necessary when unexec properly extends the .bss (or
165
.data as appropriate) section to include the dumped bss data,
166
and dumps the heap into a proper section of its own.) */
168
char * p = strrchr (executable_path, '.');
169
if (p && p[1] == '_')
173
/* Using HiProf profiler, exe name is different still. */
175
char * p = strrchr (executable_path, '\\');
176
strcpy (p, "\\emacs.exe");
180
recreate_heap (executable_path);
181
heap_state = HEAP_LOADED;
185
/* Grab our malloc arena space now, before CRT starts up. */
189
/* The default behavior is to treat files as binary and patch up
190
text files appropriately, in accordance with the MSDOS code. */
193
/* This prevents ctrl-c's in shells running while we're suspended from
195
SetConsoleCtrlHandler ((PHANDLER_ROUTINE) ctrl_c_handler, TRUE);
197
/* Invoke the NT CRT startup routine now that our housecleaning
200
/* determine WinMain args like crt0.c does */
201
hinst = GetModuleHandle(NULL);
202
lpCmdLine = GetCommandLine();
203
nCmdShow = SW_SHOWDEFAULT;
207
#endif /* UNIXSAVE */
209
/* Dump out .data and .bss sections into a new executable. */
211
unexec (char *new_name, char *old_name, void *start_data, void *start_bss,
214
file_data in_file, out_file;
215
char out_filename[MAX_PATH], in_filename[MAX_PATH];
216
char filename[MAX_PATH];
221
/* copy_stdin = *stdin; */
222
setvbuf(stdin,0,_IONBF,0);
223
setvbuf(stdout,0,_IONBF,0);
225
/* stdin->_data->__sdidinit = 0;
229
if (!get_allocation_unit())
230
cache_system_info ();
232
/* Make sure that the input and output filenames have the
233
".exe" extension...patch them up if they don't. */
234
ptr = old_name + strlen (old_name) - 4;
235
strcpy(filename, old_name);
236
strcat(filename, (strcmp (ptr, ".exe") && strcmp (ptr, ".EXE"))?".exe":"");
237
cygwin_conv_to_full_win32_path(filename,in_filename);
239
ptr = new_name + strlen (new_name) - 4;
240
strcpy(filename, new_name);
241
strcat(filename, (strcmp (ptr, ".exe") && strcmp (ptr, ".EXE"))?".exe":"");
242
cygwin_conv_to_full_win32_path(filename,out_filename);
244
printf ("Dumping from %s\n", in_filename);
245
printf (" to %s\n", out_filename);
247
/* We need to round off our heap to NT's allocation unit (64KB). */
248
round_heap (get_allocation_unit ());
250
/* Open the undumped executable file. */
251
if (!open_input_file (&in_file, in_filename))
253
printf ("Failed to open %s (%d)...bailing.\n",
254
in_filename, GetLastError ());
258
/* Get the interesting section info, like start and size of .bss... */
259
get_section_info (&in_file);
261
/* The size of the dumped executable is the size of the original
262
executable plus the size of the heap and the size of the .bss section. */
263
heap_index_in_executable = (unsigned long)
264
round_to_next ((unsigned char *) in_file.size, get_allocation_unit ());
265
/* from lisp we know what to use */
267
data_region_end = round_to_next(core_end,0x10000);
268
real_data_region_end = data_region_end;
270
size = heap_index_in_executable + get_committed_heap_size () + bss_size;
271
if (!open_output_file (&out_file, out_filename, size))
273
printf ("Failed to open %s (%d)...bailing.\n",
274
out_filename, GetLastError ());
278
/* Set the flag (before dumping). */
279
heap_state = HEAP_UNLOADED;
281
copy_executable_and_dump_data_section (&in_file, &out_file);
282
dump_bss_and_heap (&in_file, &out_file);
284
/* Patch up header fields; profiler is picky about this. */
287
PIMAGE_DOS_HEADER dos_header;
288
PIMAGE_NT_HEADERS nt_header;
289
HANDLE hImagehelp = LoadLibrary ("imagehlp.dll");
293
dos_header = (PIMAGE_DOS_HEADER) out_file.file_base;
294
nt_header = (PIMAGE_NT_HEADERS) ((char *) dos_header + dos_header->e_lfanew);
297
nt_header->OptionalHeader.CheckSum = 0;
298
// nt_header->FileHeader.TimeDateStamp = time (NULL);
299
// dos_header->e_cp = size / 512;
300
// nt_header->OptionalHeader.SizeOfImage = size;
302
pfnCheckSumMappedFile = (void *) GetProcAddress (hImagehelp, "CheckSumMappedFile");
303
if (pfnCheckSumMappedFile)
305
// nt_header->FileHeader.TimeDateStamp = time (NULL);
306
pfnCheckSumMappedFile (out_file.file_base,
310
nt_header->OptionalHeader.CheckSum = checksum;
312
FreeLibrary (hImagehelp);
315
close_file_data (&in_file);
316
close_file_data (&out_file);
324
open_input_file (file_data *p_file, char *filename)
329
DWORD size, upper_size;
331
file = CreateFile (filename, GENERIC_READ, FILE_SHARE_READ, NULL,
332
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
333
if (file == INVALID_HANDLE_VALUE)
336
size = GetFileSize (file, &upper_size);
337
file_mapping = CreateFileMapping (file, NULL, PAGE_READONLY,
342
file_base = MapViewOfFile (file_mapping, FILE_MAP_READ, 0, 0, size);
346
p_file->name = filename;
349
p_file->file_mapping = file_mapping;
350
p_file->file_base = file_base;
356
open_output_file (file_data *p_file, char *filename, unsigned long size)
362
file = CreateFile (filename, GENERIC_READ | GENERIC_WRITE, 0, NULL,
363
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
364
if (file == INVALID_HANDLE_VALUE)
367
file_mapping = CreateFileMapping (file, NULL, PAGE_READWRITE,
372
file_base = MapViewOfFile (file_mapping, FILE_MAP_WRITE, 0, 0, size);
376
p_file->name = filename;
379
p_file->file_mapping = file_mapping;
380
p_file->file_base = file_base;
385
/* Close the system structures associated with the given file. */
387
close_file_data (file_data *p_file)
389
UnmapViewOfFile (p_file->file_base);
390
CloseHandle (p_file->file_mapping);
391
CloseHandle (p_file->file);
395
/* Routines to manipulate NT executable file sections. */
397
#ifdef SEPARATE_BSS_SECTION
399
get_bss_info_from_map_file (file_data *p_infile, PUCHAR *p_bss_start,
403
char map_filename[MAX_PATH];
407
/* Overwrite the .exe extension on the executable file name with
408
the .map extension. */
409
strcpy (map_filename, p_infile->name);
410
n = strlen (map_filename) - 3;
411
strcpy (&map_filename[n], "map");
413
map = fopen (map_filename, "r");
416
printf ("Failed to open map file %s, error %d...bailing out.\n",
417
map_filename, GetLastError ());
421
while (fgets (buffer, sizeof (buffer), map))
423
if (!(strstr (buffer, ".bss") && strstr (buffer, "DATA")))
425
n = sscanf (buffer, " %*d:%x %x", &start, &len);
428
printf ("Failed to scan the .bss section line:\n%s", buffer);
433
*p_bss_start = (PUCHAR) start;
434
*p_bss_size = (DWORD) len;
439
get_section_size (PIMAGE_SECTION_HEADER p_section)
441
/* The true section size, before rounding. Some linkers swap the
442
meaning of these two values. */
443
return min (p_section->SizeOfRawData,
444
p_section->Misc.VirtualSize);
447
/* Return pointer to section header for named section. */
448
IMAGE_SECTION_HEADER *
449
find_section (char * name, IMAGE_NT_HEADERS * nt_header)
451
PIMAGE_SECTION_HEADER section;
454
section = IMAGE_FIRST_SECTION (nt_header);
456
for (i = 0; i < nt_header->FileHeader.NumberOfSections; i++)
458
if (strcmp (section->Name, name) == 0)
465
/* Return pointer to section header for section containing the given
466
relative virtual address. */
467
IMAGE_SECTION_HEADER *
468
rva_to_section (DWORD rva, IMAGE_NT_HEADERS * nt_header)
470
PIMAGE_SECTION_HEADER section;
473
section = IMAGE_FIRST_SECTION (nt_header);
475
for (i = 0; i < nt_header->FileHeader.NumberOfSections; i++)
477
if (rva >= section->VirtualAddress &&
478
rva < section->VirtualAddress + section->SizeOfRawData)
486
/* Flip through the executable and cache the info necessary for dumping. */
488
get_section_info (file_data *p_infile)
490
PIMAGE_DOS_HEADER dos_header;
491
PIMAGE_NT_HEADERS nt_header;
492
PIMAGE_SECTION_HEADER section, data_section;
496
dos_header = (PIMAGE_DOS_HEADER) p_infile->file_base;
497
if (dos_header->e_magic != IMAGE_DOS_SIGNATURE)
499
printf ("Unknown EXE header in %s...bailing.\n", p_infile->name);
502
nt_header = (PIMAGE_NT_HEADERS) (((unsigned long) dos_header) +
503
dos_header->e_lfanew);
504
if (nt_header == NULL)
506
printf ("Failed to find IMAGE_NT_HEADER in %s...bailing.\n",
511
/* Check the NT header signature ... */
512
if (nt_header->Signature != IMAGE_NT_SIGNATURE)
514
printf ("Invalid IMAGE_NT_SIGNATURE 0x%x in %s...bailing.\n",
515
nt_header->Signature, p_infile->name);
518
/* Flip through the sections for .data and .bss ... */
519
section = (PIMAGE_SECTION_HEADER) IMAGE_FIRST_SECTION (nt_header);
520
for (i = 0; i < nt_header->FileHeader.NumberOfSections; i++)
522
#ifdef SEPARATE_BSS_SECTION
523
if (!strcmp (section->Name, ".bss"))
525
/* The .bss section. */
526
ptr = (char *) nt_header->OptionalHeader.ImageBase +
527
section->VirtualAddress;
529
bss_size = get_section_size (section);
533
if (!strcmp (section->Name, ".data"))
535
/* From lastfile.c */
536
extern char my_edata[];
538
/* The .data section. */
539
data_section = section;
540
ptr = (char *) nt_header->OptionalHeader.ImageBase +
541
section->VirtualAddress;
543
data_start_file = section->PointerToRawData;
545
/* We want to only write Emacs data back to the executable,
546
not any of the library data (if library data is included,
547
then a dumped Emacs won't run on system versions other
548
than the one Emacs was dumped on). */
549
data_size = my_edata - data_start_va;
553
#define DATA_SECTION "EMDATA"
555
#define DATA_SECTION ".data"
557
if (!strcmp (section->Name, DATA_SECTION))
559
/* The Emacs initialized data section. */
560
data_section = section;
561
ptr = (char *) nt_header->OptionalHeader.ImageBase +
562
section->VirtualAddress;
564
data_start_file = section->PointerToRawData;
566
/* Write back the full section. */
567
data_size = get_section_size (section);
573
#ifdef SEPARATE_BSS_SECTION
574
if (bss_start == UNINIT_PTR && bss_size == UNINIT_LONG)
576
/* Starting with MSVC 4.0, the .bss section has been eliminated
577
and appended virtually to the end of the .data section. Our
578
only hint about where the .bss section starts in the address
579
comes from the SizeOfRawData field in the .data section
580
header. Unfortunately, this field is only approximate, as it
581
is a rounded number and is typically rounded just beyond the
582
start of the .bss section. To find the start and size of the
583
.bss section exactly, we have to peek into the map file. */
584
get_bss_info_from_map_file (p_infile, &ptr, &bss_size);
585
bss_start = ptr + nt_header->OptionalHeader.ImageBase
586
+ data_section->VirtualAddress;
589
/* As noted in lastfile.c, the Alpha (but not the Intel) MSVC linker
590
globally segregates all static and public bss data (ie. across all
591
linked modules, not just per module), so we must take both static and
592
public bss areas into account to determine the true extent of the bss
595
To be strictly correct, we should dump the static and public bss
596
areas used by Emacs separately if non-overlapping (since otherwise we
597
are dumping bss data belonging to system libraries, eg. the static
598
bss system data on the Alpha). However, in practice this doesn't
599
seem to matter, since presumably the system libraries always
600
reinitialize their bss variables. */
601
bss_start = min (my_begbss, my_begbss_static);
602
bss_size = max ((char *)my_endbss, (char *) my_endbss_static) - (char *) bss_start;
608
/* The dump routines. */
611
copy_executable_and_dump_data_section (file_data *p_infile,
612
file_data *p_outfile)
614
unsigned char *data_file, *data_va;
615
unsigned long size, index;
617
/* Get a pointer to where the raw data should go in the executable file. */
618
data_file = (char *) p_outfile->file_base + data_start_file;
620
/* Get a pointer to the raw data in our address space. */
621
data_va = data_start_va;
623
size = (DWORD) data_file - (DWORD) p_outfile->file_base;
624
printf ("Copying executable up to data section...\n");
625
printf ("\t0x%08x Offset in input file.\n", 0);
626
printf ("\t0x%08x Offset in output file.\n", 0);
627
printf ("\t0x%08x Size in bytes.\n", size);
628
memcpy (p_outfile->file_base, p_infile->file_base, size);
631
printf ("Dumping .data section...\n");
632
printf ("\t0x%08x Address in process.\n", data_va);
633
printf ("\t0x%08x Offset in output file.\n",
634
data_file - p_outfile->file_base);
635
printf ("\t0x%08x Size in bytes.\n", size);
636
memcpy (data_file, data_va, size);
638
index = (DWORD) data_file + size - (DWORD) p_outfile->file_base;
639
size = p_infile->size - index;
640
printf ("Copying rest of executable...\n");
641
printf ("\t0x%08x Offset in input file.\n", index);
642
printf ("\t0x%08x Offset in output file.\n", index);
643
printf ("\t0x%08x Size in bytes.\n", size);
644
memcpy ((char *) p_outfile->file_base + index,
645
(char *) p_infile->file_base + index, size);
649
dump_bss_and_heap (file_data *p_infile, file_data *p_outfile)
651
unsigned char *heap_data, *bss_data;
652
unsigned long size, index;
654
printf ("Dumping heap into executable...\n");
656
index = heap_index_in_executable;
657
size = get_committed_heap_size ();
658
heap_data = get_heap_start ();
660
printf ("\t0x%08x Heap start in process.\n", heap_data);
661
printf ("\t0x%08x Heap offset in executable.\n", index);
662
printf ("\t0x%08x Heap size in bytes.\n", size);
664
memcpy ((PUCHAR) p_outfile->file_base + index, heap_data, size);
666
printf ("Dumping .bss into executable...\n");
670
bss_data = bss_start;
672
printf ("\t0x%08x BSS start in process.\n", bss_data);
673
printf ("\t0x%08x BSS offset in executable.\n", index);
674
printf ("\t0x%08x BSS size in bytes.\n", size);
675
memcpy ((char *) p_outfile->file_base + index, bss_data, size);
679
/* Reload and remap routines. */
682
/* Load the dumped .bss section into the .bss area of our address space. */
684
read_in_bss (char *filename)
687
DWORD size, index, n_read, total_read;
688
char buffer[512], *bss;
691
file = CreateFile (filename, GENERIC_READ, FILE_SHARE_READ, NULL,
692
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
693
if (file == INVALID_HANDLE_VALUE)
699
/* Seek to where the .bss section is tucked away after the heap... */
700
index = heap_index_in_executable + get_committed_heap_size ();
701
if (SetFilePointer (file, index, NULL, FILE_BEGIN) == 0xFFFFFFFF)
708
/* Ok, read in the saved .bss section and initialize all
709
uninitialized variables. */
710
if (!ReadFile (file, bss_start, bss_size, &n_read, (void *)NULL))
719
/* Map the heap dumped into the executable file into our address space. */
721
map_in_heap (char *filename)
726
DWORD size, upper_size, n_read;
729
file = CreateFile (filename, GENERIC_READ, FILE_SHARE_READ, NULL,
730
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
731
if (file == INVALID_HANDLE_VALUE)
737
size = GetFileSize (file, &upper_size);
738
file_mapping = CreateFileMapping (file, NULL, PAGE_WRITECOPY,
746
size = get_committed_heap_size ();
747
file_base = MapViewOfFileEx (file_mapping, FILE_MAP_COPY, 0,
748
heap_index_in_executable, size,
755
/* If we don't succeed with the mapping, then copy from the
756
data into the heap. */
758
CloseHandle (file_mapping);
760
if (VirtualAlloc (get_heap_start (), get_committed_heap_size (),
761
MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE) == NULL)
767
/* Seek to the location of the heap data in the executable. */
768
i = heap_index_in_executable;
769
if (SetFilePointer (file, i, NULL, FILE_BEGIN) == 0xFFFFFFFF)
775
/* Read in the data. */
776
if (!ReadFile (file, get_heap_start (),
777
get_committed_heap_size (), &n_read, (void *)NULL))
787
/* Heap management routines for GNU Emacs on Windows NT.
788
Copyright (C) 1994 Free Software Foundation, Inc.
790
This file is part of GNU Emacs.
792
GNU Emacs is free software; you can redistribute it and/or modify
793
it under the terms of the GNU General Public License as published by
794
the Free Software Foundation; either version 2, or (at your option)
797
GNU Emacs is distributed in the hope that it will be useful,
798
but WITHOUT ANY WARRANTY; without even the implied warranty of
799
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
800
GNU General Public License for more details.
802
You should have received a copy of the GNU General Public License
803
along with GNU Emacs; see the file COPYING. If not, write to
804
the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
805
Boston, MA 02111-1307, USA.
807
Geoff Voelker (voelker@cs.washington.edu) 7-29-94
812
/* #include "lisp.h" */ /* for VALMASK */
814
/* try for 500 MB of address space */
817
/* This gives us the page size and the size of the allocation unit on NT. */
818
SYSTEM_INFO sysinfo_cache;
819
unsigned long syspage_mask = 0;
821
/* These are defined to get Emacs to compile, but are not used. */
825
/* The major and minor versions of NT. */
826
int nt_major_version;
827
int nt_minor_version;
829
/* Distinguish between Windows NT and Windows 95. */
832
/* Cache information describing the NT system for later use. */
834
cache_system_info (void)
847
/* Cache the version of the operating system. */
848
version.data = GetVersion ();
849
nt_major_version = version.info.major;
850
nt_minor_version = version.info.minor;
852
if (version.info.platform & 0x8000)
853
os_subtype = OS_WIN95;
857
/* Cache page size, allocation unit, processor type, etc. */
858
GetSystemInfo (&sysinfo_cache);
859
syspage_mask = sysinfo_cache.dwPageSize - 1;
862
/* Round ADDRESS up to be aligned with ALIGN. */
864
round_to_next (unsigned char *address, unsigned long align)
868
tmp = (unsigned long) address;
869
tmp = (tmp + align - 1) / align;
871
return (unsigned char *) (tmp * align);
875
/* The start of the data segment. */
877
get_data_start (void)
879
return data_region_base;
882
/* The end of the data segment. */
886
return data_region_end;
892
/* The base address for our GNU malloc heap is chosen in conjuction
893
with the link settings for temacs.exe which control the stack size,
894
the initial default process heap size and the executable image base
895
address. The link settings and the malloc heap base below must all
896
correspond; the relationship between these values depends on how NT
897
and Win95 arrange the virtual address space for a process (and on
898
the size of the code and data segments in temacs.exe).
900
The most important thing is to make base address for the executable
901
image high enough to leave enough room between it and the 4MB floor
902
of the process address space on Win95 for the primary thread stack,
903
the process default heap, and other assorted odds and ends
904
(eg. environment strings, private system dll memory etc) that are
905
allocated before temacs has a chance to grab its malloc arena. The
906
malloc heap base can then be set several MB higher than the
907
executable image base, leaving enough room for the code and data
910
Because some parts of Emacs can use rather a lot of stack space
911
(for instance, the regular expression routines can potentially
912
allocate several MB of stack space) we allow 8MB for the stack.
914
Allowing 1MB for the default process heap, and 1MB for odds and
915
ends, we can base the executable at 16MB and still have a generous
916
safety margin. At the moment, the executable has about 810KB of
917
code (for x86) and about 550KB of data - on RISC platforms the code
918
size could be roughly double, so if we allow 4MB for the executable
919
we will have plenty of room for expansion.
921
Thus we would like to set the malloc heap base to 20MB. However,
922
Win95 refuses to allocate the heap starting at this address, so we
923
set the base to 27MB to make it happy. Since Emacs now leaves
924
28 bits available for pointers, this lets us use the remainder of
925
the region below the 256MB line for our malloc arena - 229MB is
926
still a pretty decent arena to play in! */
928
unsigned long base = DBEGIN; /* 27MB */
929
/* unsigned long base = 0x01B00000; */ /* 27MB */
930
unsigned long end = 1 << VALBITS; /* 256MB */
933
#define NTHEAP_PROBE_BASE 1
934
#if NTHEAP_PROBE_BASE /* This is never normally defined */
935
/* Try various addresses looking for one the kernel will let us have. */
936
while (!ptr && (base < end))
938
reserved_heap_size = end - base;
939
ptr = VirtualAlloc ((void *) base,
940
get_reserved_heap_size (),
943
base += 0x00100000; /* 1MB increment */
946
reserved_heap_size = end - base;
947
ptr = VirtualAlloc ((void *) base,
948
get_reserved_heap_size (),
957
/* Emulate Unix sbrk. */
959
sbrk (unsigned long increment)
962
long size = (long) increment;
964
/* Allocate our heap if we haven't done so already. */
965
if (data_region_base == UNINIT_PTR)
967
data_region_base = allocate_heap ();
968
if (!data_region_base)
971
/* Ensure that the addresses don't use the upper tag bits since
972
the Lisp type goes there. */
973
if (((unsigned long) data_region_base & ~VALMASK) != 0)
975
printf ("Error: The heap was allocated in upper memory.\n");
979
data_region_end = data_region_base;
980
real_data_region_end = data_region_end;
981
data_region_size = get_reserved_heap_size ();
984
result = data_region_end;
986
/* If size is negative, shrink the heap by decommitting pages. */
990
unsigned char *new_data_region_end;
995
if ((data_region_end - size) < data_region_base)
998
/* We can only decommit full pages, so allow for
999
partial deallocation [cga]. */
1000
new_data_region_end = (data_region_end - size);
1001
new_data_region_end = (unsigned char *)
1002
((long) (new_data_region_end + syspage_mask) & ~syspage_mask);
1003
new_size = real_data_region_end - new_data_region_end;
1004
real_data_region_end = new_data_region_end;
1007
/* Decommit size bytes from the end of the heap. */
1008
if (!VirtualFree (real_data_region_end, new_size, MEM_DECOMMIT))
1012
data_region_end -= size;
1014
/* If size is positive, grow the heap by committing reserved pages. */
1017
/* Sanity checks. */
1018
if ((data_region_end + size) >
1019
(data_region_base + get_reserved_heap_size ()))
1022
/* Commit more of our heap. */
1023
if (VirtualAlloc (data_region_end, size, MEM_COMMIT,
1024
PAGE_READWRITE) == NULL)
1026
data_region_end += size;
1028
/* We really only commit full pages, so record where
1029
the real end of committed memory is [cga]. */
1030
real_data_region_end = (unsigned char *)
1031
((long) (data_region_end + syspage_mask) & ~syspage_mask);
1037
/* Recreate the heap from the data that was dumped to the executable.
1038
EXECUTABLE_PATH tells us where to find the executable. */
1040
recreate_heap (char *executable_path)
1044
/* First reserve the upper part of our heap. (We reserve first
1045
because there have been problems in the past where doing the
1046
mapping first has loaded DLLs into the VA space of our heap.) */
1047
tmp = VirtualAlloc ((void *) get_heap_end (),
1048
get_reserved_heap_size () - get_committed_heap_size (),
1054
/* We read in the data for the .bss section from the executable
1055
first and map in the heap from the executable second to prevent
1056
any funny interactions between file I/O and file mapping. */
1058
read_in_bss (executable_path);
1060
map_in_heap (executable_path);
1062
/* Update system version information to match current system. */
1063
cache_system_info ();
1066
/* Round the heap up to the given alignment. */
1068
round_heap (unsigned long align)
1070
unsigned long needs_to_be;
1071
unsigned long need_to_alloc;
1073
needs_to_be = (unsigned long) round_to_next (get_heap_end (), align);
1074
need_to_alloc = needs_to_be - (unsigned long) get_heap_end ();
1077
sbrk (need_to_alloc);
1080
#if (_MSC_VER >= 1000)
1082
/* MSVC 4.2 invokes these functions from mainCRTStartup to initialize
1083
a heap via HeapCreate. They are normally defined by the runtime,
1084
but we override them here so that the unnecessary HeapCreate call
1085
is not performed. */
1090
/* Stepping through the assembly indicates that mainCRTStartup is
1091
expecting a nonzero success return value. */
1103
BOOL ctrl_c_handler (unsigned long type)