~ubuntu-branches/ubuntu/vivid/gcl/vivid

« back to all changes in this revision

Viewing changes to o/unexnt.c

  • Committer: Bazaar Package Importer
  • Author(s): Camm Maguire
  • Date: 2002-03-04 14:29:59 UTC
  • Revision ID: james.westby@ubuntu.com-20020304142959-dey14w08kr7lldu3
Tags: upstream-2.5.0.cvs20020219
ImportĀ upstreamĀ versionĀ 2.5.0.cvs20020219

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* unexec for GNU Emacs on Windows NT.
 
2
   Copyright (C) 1994 Free Software Foundation, Inc.
 
3
 
 
4
This file is part of GNU Emacs.
 
5
 
 
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)
 
9
any later version.
 
10
 
 
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.
 
15
 
 
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.
 
20
 
 
21
   Geoff Voelker (voelker@cs.washington.edu)                         8-12-94
 
22
*/
 
23
#ifndef UNIXSAVE
 
24
#include <config.h>
 
25
#endif
 
26
/* #include <stdlib.h> */       /* _fmode */
 
27
/* in case the include of config.h defined it */
 
28
#undef va_start
 
29
#include <stdio.h>
 
30
#include <fcntl.h>
 
31
#include <time.h>
 
32
#include <windows.h>
 
33
#include <string.h>   /* strrchr */
 
34
 
 
35
#ifdef _GNU_H_WINDOWS_H 
 
36
#include "cyglacks.h"
 
37
#endif
 
38
 
 
39
/* Include relevant definitions from IMAGEHLP.H, which can be found
 
40
   in \\win32sdk\mstools\samples\image\include\imagehlp.h. */
 
41
 
 
42
 
 
43
 
 
44
PIMAGE_NT_HEADERS
 
45
(__stdcall * pfnCheckSumMappedFile) (LPVOID BaseAddress,
 
46
                                    DWORD FileLength,
 
47
                                    LPDWORD HeaderSum,
 
48
                                    LPDWORD CheckSum);
 
49
 
 
50
 
 
51
 
 
52
#include <stdlib.h>
 
53
#include <stdio.h>
 
54
 
 
55
#include "ntheap.h"
 
56
 
 
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;
 
63
 
 
64
extern BOOL ctrl_c_handler (unsigned long type);
 
65
 
 
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;
 
72
 
 
73
#include "ntheap.h"
 
74
 
 
75
enum {
 
76
  HEAP_UNINITIALIZED = 1,
 
77
  HEAP_UNLOADED,
 
78
  HEAP_LOADED
 
79
};
 
80
 
 
81
/* Basically, our "initialized" flag.  */
 
82
int heap_state = HEAP_UNINITIALIZED;
 
83
 
 
84
/* So we can find our heap in the file to recreate it.  */
 
85
unsigned long heap_index_in_executable = UNINIT_LONG;
 
86
 
 
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);
 
90
 
 
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;
 
95
 
 
96
/* Cached info about the .bss section in the executable.  */
 
97
PUCHAR bss_start = UNINIT_PTR;
 
98
DWORD  bss_size = UNINIT_LONG;
 
99
 
 
100
void recreate_heap1()
 
101
{
 
102
  char executable_path[MAX_PATH];
 
103
  
 
104
  if (heap_state == HEAP_UNLOADED) { 
 
105
  if (GetModuleFileName (NULL, executable_path, MAX_PATH) == 0) 
 
106
    {
 
107
      printf ("Failed to find path for executable.\n");
 
108
      exit (1);
 
109
    }
 
110
 
 
111
    recreate_heap (executable_path);
 
112
  }
 
113
  heap_state = HEAP_LOADED;
 
114
 
 
115
}
 
116
 
 
117
 
 
118
#ifdef HAVE_NTGUI
 
119
HINSTANCE hinst = NULL;
 
120
HINSTANCE hprevinst = NULL;
 
121
LPSTR lpCmdLine = "";
 
122
int nCmdShow = 0;
 
123
#endif /* HAVE_NTGUI */
 
124
 
 
125
#ifndef UNIXSAVE
 
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 ()).  */
 
130
void
 
131
_start (void)
 
132
{
 
133
  extern void mainCRTStartup (void);
 
134
 
 
135
#if 0
 
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)
 
139
    DebugBreak ();
 
140
#endif
 
141
 
 
142
  /* Cache system info, e.g., the NT page size.  */
 
143
  cache_system_info ();
 
144
 
 
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
 
149
     won't work.)  */
 
150
  if (heap_state == HEAP_UNLOADED) 
 
151
    {
 
152
      char executable_path[MAX_PATH];
 
153
 
 
154
      if (GetModuleFileName (NULL, executable_path, MAX_PATH) == 0) 
 
155
        {
 
156
          printf ("Failed to find path for executable.\n");
 
157
          exit (1);
 
158
        }
 
159
 
 
160
#if 1
 
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.)  */
 
167
      {
 
168
        char * p = strrchr (executable_path, '.');
 
169
        if (p && p[1] == '_')
 
170
          p[1] = 'e';
 
171
      }
 
172
 
 
173
      /* Using HiProf profiler, exe name is different still. */
 
174
      {
 
175
        char * p = strrchr (executable_path, '\\');
 
176
        strcpy (p, "\\emacs.exe");
 
177
      }
 
178
#endif
 
179
 
 
180
      recreate_heap (executable_path);
 
181
      heap_state = HEAP_LOADED;
 
182
    }
 
183
  else
 
184
    {
 
185
      /* Grab our malloc arena space now, before CRT starts up. */
 
186
      sbrk (0);
 
187
    }
 
188
 
 
189
  /* The default behavior is to treat files as binary and patch up
 
190
     text files appropriately, in accordance with the MSDOS code.  */
 
191
  _fmode = O_BINARY;
 
192
 
 
193
  /* This prevents ctrl-c's in shells running while we're suspended from
 
194
     having us exit.  */
 
195
  SetConsoleCtrlHandler ((PHANDLER_ROUTINE) ctrl_c_handler, TRUE);
 
196
 
 
197
  /* Invoke the NT CRT startup routine now that our housecleaning
 
198
     is finished.  */
 
199
#ifdef HAVE_NTGUI
 
200
  /* determine WinMain args like crt0.c does */
 
201
  hinst = GetModuleHandle(NULL);
 
202
  lpCmdLine = GetCommandLine();
 
203
  nCmdShow = SW_SHOWDEFAULT;
 
204
#endif
 
205
  mainCRTStartup ();
 
206
}
 
207
#endif /* UNIXSAVE */
 
208
 
 
209
/* Dump out .data and .bss sections into a new executable.  */
 
210
void
 
211
unexec (char *new_name, char *old_name, void *start_data, void *start_bss,
 
212
        void *entry_address)
 
213
{
 
214
  file_data in_file, out_file;
 
215
  char out_filename[MAX_PATH], in_filename[MAX_PATH];
 
216
  char filename[MAX_PATH];
 
217
  unsigned long size;
 
218
  char *ptr;
 
219
 
 
220
  fflush (stdin);
 
221
  /* copy_stdin = *stdin; */
 
222
    setvbuf(stdin,0,_IONBF,0);
 
223
    setvbuf(stdout,0,_IONBF,0);
 
224
    
 
225
  /* stdin->_data->__sdidinit = 0;
 
226
   */
 
227
  
 
228
 
 
229
  if (!get_allocation_unit())
 
230
    cache_system_info ();
 
231
  
 
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);
 
238
 
 
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);
 
243
 
 
244
  printf ("Dumping from %s\n", in_filename);
 
245
  printf ("          to %s\n", out_filename);
 
246
 
 
247
  /* We need to round off our heap to NT's allocation unit (64KB).  */
 
248
  round_heap (get_allocation_unit ());
 
249
 
 
250
  /* Open the undumped executable file.  */
 
251
  if (!open_input_file (&in_file, in_filename))
 
252
    {
 
253
      printf ("Failed to open %s (%d)...bailing.\n", 
 
254
              in_filename, GetLastError ());
 
255
      exit (1);
 
256
    }
 
257
 
 
258
  /* Get the interesting section info, like start and size of .bss...  */
 
259
  get_section_info (&in_file);
 
260
 
 
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 */
 
266
#ifdef IN_UNIXSAVE
 
267
  data_region_end = round_to_next(core_end,0x10000);
 
268
  real_data_region_end = data_region_end;
 
269
#endif  
 
270
  size = heap_index_in_executable + get_committed_heap_size () + bss_size;
 
271
  if (!open_output_file (&out_file, out_filename, size))
 
272
    {
 
273
      printf ("Failed to open %s (%d)...bailing.\n", 
 
274
              out_filename, GetLastError ());
 
275
      exit (1);
 
276
    }
 
277
 
 
278
  /* Set the flag (before dumping).  */
 
279
  heap_state = HEAP_UNLOADED;
 
280
 
 
281
  copy_executable_and_dump_data_section (&in_file, &out_file);
 
282
  dump_bss_and_heap (&in_file, &out_file);
 
283
 
 
284
  /* Patch up header fields; profiler is picky about this. */
 
285
 
 
286
  {
 
287
    PIMAGE_DOS_HEADER dos_header;
 
288
    PIMAGE_NT_HEADERS nt_header;
 
289
    HANDLE hImagehelp = LoadLibrary ("imagehlp.dll");
 
290
    DWORD  headersum;
 
291
    DWORD  checksum;
 
292
 
 
293
    dos_header = (PIMAGE_DOS_HEADER) out_file.file_base;
 
294
    nt_header = (PIMAGE_NT_HEADERS) ((char *) dos_header + dos_header->e_lfanew);
 
295
 
 
296
    
 
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;
 
301
 
 
302
    pfnCheckSumMappedFile = (void *) GetProcAddress (hImagehelp, "CheckSumMappedFile");
 
303
    if (pfnCheckSumMappedFile)
 
304
      {
 
305
//      nt_header->FileHeader.TimeDateStamp = time (NULL);
 
306
        pfnCheckSumMappedFile (out_file.file_base,
 
307
                               out_file.size,
 
308
                               &headersum,
 
309
                               &checksum);
 
310
        nt_header->OptionalHeader.CheckSum = checksum;
 
311
      }
 
312
    FreeLibrary (hImagehelp);
 
313
  }
 
314
 
 
315
  close_file_data (&in_file);
 
316
  close_file_data (&out_file);
 
317
}
 
318
 
 
319
 
 
320
/* File handling.  */
 
321
 
 
322
 
 
323
int
 
324
open_input_file (file_data *p_file, char *filename)
 
325
{
 
326
  HANDLE file;
 
327
  HANDLE file_mapping;
 
328
  void  *file_base;
 
329
  DWORD size, upper_size;
 
330
 
 
331
  file = CreateFile (filename, GENERIC_READ, FILE_SHARE_READ, NULL,
 
332
                     OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
 
333
  if (file == INVALID_HANDLE_VALUE) 
 
334
    return FALSE;
 
335
 
 
336
  size = GetFileSize (file, &upper_size);
 
337
  file_mapping = CreateFileMapping (file, NULL, PAGE_READONLY, 
 
338
                                    0, size, NULL);
 
339
  if (!file_mapping) 
 
340
    return FALSE;
 
341
 
 
342
  file_base = MapViewOfFile (file_mapping, FILE_MAP_READ, 0, 0, size);
 
343
  if (file_base == 0) 
 
344
    return FALSE;
 
345
 
 
346
  p_file->name = filename;
 
347
  p_file->size = size;
 
348
  p_file->file = file;
 
349
  p_file->file_mapping = file_mapping;
 
350
  p_file->file_base = file_base;
 
351
 
 
352
  return TRUE;
 
353
}
 
354
 
 
355
int
 
356
open_output_file (file_data *p_file, char *filename, unsigned long size)
 
357
{
 
358
  HANDLE file;
 
359
  HANDLE file_mapping;
 
360
  void  *file_base;
 
361
 
 
362
  file = CreateFile (filename, GENERIC_READ | GENERIC_WRITE, 0, NULL,
 
363
                     CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
 
364
  if (file == INVALID_HANDLE_VALUE) 
 
365
    return FALSE;
 
366
 
 
367
  file_mapping = CreateFileMapping (file, NULL, PAGE_READWRITE, 
 
368
                                    0, size, NULL);
 
369
  if (!file_mapping) 
 
370
    return FALSE;
 
371
  
 
372
  file_base = MapViewOfFile (file_mapping, FILE_MAP_WRITE, 0, 0, size);
 
373
  if (file_base == 0) 
 
374
    return FALSE;
 
375
  
 
376
  p_file->name = filename;
 
377
  p_file->size = size;
 
378
  p_file->file = file;
 
379
  p_file->file_mapping = file_mapping;
 
380
  p_file->file_base = file_base;
 
381
 
 
382
  return TRUE;
 
383
}
 
384
 
 
385
/* Close the system structures associated with the given file.  */
 
386
void
 
387
close_file_data (file_data *p_file)
 
388
{
 
389
    UnmapViewOfFile (p_file->file_base);
 
390
    CloseHandle (p_file->file_mapping);
 
391
    CloseHandle (p_file->file);
 
392
}
 
393
 
 
394
 
 
395
/* Routines to manipulate NT executable file sections.  */
 
396
 
 
397
#ifdef SEPARATE_BSS_SECTION
 
398
static void
 
399
get_bss_info_from_map_file (file_data *p_infile, PUCHAR *p_bss_start, 
 
400
                            DWORD *p_bss_size)
 
401
{
 
402
  int n, start, len;
 
403
  char map_filename[MAX_PATH];
 
404
  char buffer[256];
 
405
  FILE *map;
 
406
 
 
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");
 
412
 
 
413
  map = fopen (map_filename, "r");
 
414
  if (!map)
 
415
    {
 
416
      printf ("Failed to open map file %s, error %d...bailing out.\n",
 
417
              map_filename, GetLastError ());
 
418
      exit (-1);
 
419
    }
 
420
 
 
421
  while (fgets (buffer, sizeof (buffer), map))
 
422
    {
 
423
      if (!(strstr (buffer, ".bss") && strstr (buffer, "DATA")))
 
424
        continue;
 
425
      n = sscanf (buffer, " %*d:%x %x", &start, &len);
 
426
      if (n != 2)
 
427
        {
 
428
          printf ("Failed to scan the .bss section line:\n%s", buffer);
 
429
          exit (-1);
 
430
        }
 
431
      break;
 
432
    }
 
433
  *p_bss_start = (PUCHAR) start;
 
434
  *p_bss_size = (DWORD) len;
 
435
}
 
436
#endif
 
437
 
 
438
unsigned long
 
439
get_section_size (PIMAGE_SECTION_HEADER p_section)
 
440
{
 
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);
 
445
}
 
446
 
 
447
/* Return pointer to section header for named section. */
 
448
IMAGE_SECTION_HEADER *
 
449
find_section (char * name, IMAGE_NT_HEADERS * nt_header)
 
450
{
 
451
  PIMAGE_SECTION_HEADER section;
 
452
  int i;
 
453
 
 
454
  section = IMAGE_FIRST_SECTION (nt_header);
 
455
 
 
456
  for (i = 0; i < nt_header->FileHeader.NumberOfSections; i++)
 
457
    {
 
458
      if (strcmp (section->Name, name) == 0)
 
459
        return section;
 
460
      section++;
 
461
    }
 
462
  return NULL;
 
463
}
 
464
 
 
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)
 
469
{
 
470
  PIMAGE_SECTION_HEADER section;
 
471
  int i;
 
472
 
 
473
  section = IMAGE_FIRST_SECTION (nt_header);
 
474
 
 
475
  for (i = 0; i < nt_header->FileHeader.NumberOfSections; i++)
 
476
    {
 
477
      if (rva >= section->VirtualAddress &&
 
478
          rva < section->VirtualAddress + section->SizeOfRawData)
 
479
        return section;
 
480
      section++;
 
481
    }
 
482
  return NULL;
 
483
}
 
484
 
 
485
 
 
486
/* Flip through the executable and cache the info necessary for dumping.  */
 
487
static void
 
488
get_section_info (file_data *p_infile)
 
489
{
 
490
  PIMAGE_DOS_HEADER dos_header;
 
491
  PIMAGE_NT_HEADERS nt_header;
 
492
  PIMAGE_SECTION_HEADER section, data_section;
 
493
  unsigned char *ptr;
 
494
  int i;
 
495
  
 
496
  dos_header = (PIMAGE_DOS_HEADER) p_infile->file_base;
 
497
  if (dos_header->e_magic != IMAGE_DOS_SIGNATURE) 
 
498
    {
 
499
      printf ("Unknown EXE header in %s...bailing.\n", p_infile->name);
 
500
      exit (1);
 
501
    }
 
502
  nt_header = (PIMAGE_NT_HEADERS) (((unsigned long) dos_header) + 
 
503
                                   dos_header->e_lfanew);
 
504
  if (nt_header == NULL) 
 
505
    {
 
506
      printf ("Failed to find IMAGE_NT_HEADER in %s...bailing.\n", 
 
507
             p_infile->name);
 
508
      exit (1);
 
509
    }
 
510
 
 
511
  /* Check the NT header signature ...  */
 
512
  if (nt_header->Signature != IMAGE_NT_SIGNATURE) 
 
513
    {
 
514
      printf ("Invalid IMAGE_NT_SIGNATURE 0x%x in %s...bailing.\n",
 
515
              nt_header->Signature, p_infile->name);
 
516
    }
 
517
 
 
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++) 
 
521
    {
 
522
#ifdef SEPARATE_BSS_SECTION
 
523
      if (!strcmp (section->Name, ".bss")) 
 
524
        {
 
525
          /* The .bss section.  */
 
526
          ptr = (char *) nt_header->OptionalHeader.ImageBase +
 
527
            section->VirtualAddress;
 
528
          bss_start = ptr;
 
529
          bss_size = get_section_size (section);
 
530
        }
 
531
#endif
 
532
#if 0
 
533
      if (!strcmp (section->Name, ".data")) 
 
534
        {
 
535
          /* From lastfile.c  */
 
536
          extern char my_edata[];
 
537
 
 
538
          /* The .data section.  */
 
539
          data_section = section;
 
540
          ptr = (char *) nt_header->OptionalHeader.ImageBase +
 
541
            section->VirtualAddress;
 
542
          data_start_va = ptr;
 
543
          data_start_file = section->PointerToRawData;
 
544
 
 
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;
 
550
        }
 
551
#else
 
552
#ifdef emacs
 
553
 #define DATA_SECTION "EMDATA"
 
554
#else
 
555
#define DATA_SECTION ".data"
 
556
#endif      
 
557
      if (!strcmp (section->Name, DATA_SECTION)) 
 
558
        {
 
559
          /* The Emacs initialized data section.  */
 
560
          data_section = section;
 
561
          ptr = (char *) nt_header->OptionalHeader.ImageBase +
 
562
            section->VirtualAddress;
 
563
          data_start_va = ptr;
 
564
          data_start_file = section->PointerToRawData;
 
565
 
 
566
          /* Write back the full section.  */
 
567
          data_size = get_section_size (section);
 
568
        }
 
569
#endif
 
570
      section++;
 
571
    }
 
572
 
 
573
#ifdef SEPARATE_BSS_SECTION
 
574
  if (bss_start == UNINIT_PTR && bss_size == UNINIT_LONG)
 
575
    {
 
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;
 
587
    }
 
588
#else
 
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
 
593
   area used by Emacs.
 
594
 
 
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;
 
603
 
 
604
#endif
 
605
}
 
606
 
 
607
 
 
608
/* The dump routines.  */
 
609
 
 
610
static void
 
611
copy_executable_and_dump_data_section (file_data *p_infile, 
 
612
                                       file_data *p_outfile)
 
613
{
 
614
  unsigned char *data_file, *data_va;
 
615
  unsigned long size, index;
 
616
  
 
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;
 
619
 
 
620
  /* Get a pointer to the raw data in our address space.  */
 
621
  data_va = data_start_va;
 
622
    
 
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);
 
629
  
 
630
  size = data_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);
 
637
  
 
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);
 
646
}
 
647
 
 
648
static void
 
649
dump_bss_and_heap (file_data *p_infile, file_data *p_outfile)
 
650
{
 
651
    unsigned char *heap_data, *bss_data;
 
652
    unsigned long size, index;
 
653
 
 
654
    printf ("Dumping heap into executable...\n");
 
655
 
 
656
    index = heap_index_in_executable;
 
657
    size = get_committed_heap_size ();
 
658
    heap_data = get_heap_start ();
 
659
 
 
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);
 
663
 
 
664
    memcpy ((PUCHAR) p_outfile->file_base + index, heap_data, size);
 
665
 
 
666
    printf ("Dumping .bss into executable...\n");
 
667
    
 
668
    index += size;
 
669
    size = bss_size;
 
670
    bss_data = bss_start;
 
671
    
 
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);
 
676
}
 
677
 
 
678
 
 
679
/* Reload and remap routines.  */
 
680
 
 
681
 
 
682
/* Load the dumped .bss section into the .bss area of our address space.  */
 
683
void
 
684
read_in_bss (char *filename)
 
685
{
 
686
  HANDLE file;
 
687
  DWORD size, index, n_read, total_read;
 
688
  char   buffer[512], *bss;
 
689
  int    i;
 
690
 
 
691
  file = CreateFile (filename, GENERIC_READ, FILE_SHARE_READ, NULL,
 
692
                     OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
 
693
  if (file == INVALID_HANDLE_VALUE) 
 
694
    {
 
695
      i = GetLastError ();
 
696
      exit (1);
 
697
    }
 
698
 
 
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) 
 
702
    {
 
703
      i = GetLastError ();
 
704
      exit (1);
 
705
    }
 
706
 
 
707
  
 
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))
 
711
    {
 
712
      i = GetLastError ();
 
713
      exit (1);
 
714
    }
 
715
 
 
716
  CloseHandle (file);
 
717
}
 
718
 
 
719
/* Map the heap dumped into the executable file into our address space.  */
 
720
void 
 
721
map_in_heap (char *filename)
 
722
{
 
723
  HANDLE file;
 
724
  HANDLE file_mapping;
 
725
  void  *file_base;
 
726
  DWORD size, upper_size, n_read;
 
727
  int    i;
 
728
 
 
729
  file = CreateFile (filename, GENERIC_READ, FILE_SHARE_READ, NULL,
 
730
                     OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
 
731
  if (file == INVALID_HANDLE_VALUE) 
 
732
    {
 
733
      i = GetLastError ();
 
734
      exit (1);
 
735
    }
 
736
  
 
737
  size = GetFileSize (file, &upper_size);
 
738
  file_mapping = CreateFileMapping (file, NULL, PAGE_WRITECOPY, 
 
739
                                    0, size, NULL);
 
740
  if (!file_mapping) 
 
741
    {
 
742
      i = GetLastError ();
 
743
      exit (1);
 
744
    }
 
745
    
 
746
  size = get_committed_heap_size ();
 
747
  file_base = MapViewOfFileEx (file_mapping, FILE_MAP_COPY, 0, 
 
748
                               heap_index_in_executable, size,
 
749
                               get_heap_start ());
 
750
  if (file_base != 0) 
 
751
    {
 
752
      return;
 
753
    }
 
754
 
 
755
  /* If we don't succeed with the mapping, then copy from the 
 
756
     data into the heap.  */
 
757
 
 
758
  CloseHandle (file_mapping);
 
759
 
 
760
  if (VirtualAlloc (get_heap_start (), get_committed_heap_size (),
 
761
                    MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE) == NULL)
 
762
    {
 
763
      i = GetLastError ();
 
764
      exit (1);
 
765
    }
 
766
 
 
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)
 
770
    {
 
771
      i = GetLastError ();
 
772
      exit (1);
 
773
    }
 
774
 
 
775
  /* Read in the data.  */
 
776
  if (!ReadFile (file, get_heap_start (), 
 
777
                 get_committed_heap_size (), &n_read, (void *)NULL))
 
778
    {
 
779
      i = GetLastError ();
 
780
      exit (1);
 
781
    }
 
782
 
 
783
  CloseHandle (file);
 
784
}
 
785
 
 
786
/* ntheap.c */
 
787
/* Heap management routines for GNU Emacs on Windows NT.
 
788
   Copyright (C) 1994 Free Software Foundation, Inc.
 
789
 
 
790
This file is part of GNU Emacs.
 
791
 
 
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)
 
795
any later version.
 
796
 
 
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.
 
801
 
 
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.
 
806
 
 
807
   Geoff Voelker (voelker@cs.washington.edu)                         7-29-94
 
808
*/
 
809
/*
 
810
 
 
811
*/
 
812
/* #include "lisp.h" */  /* for VALMASK */
 
813
#define VALMASK -1
 
814
/* try for 500 MB of address space */
 
815
#define VALBITS 29
 
816
 
 
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;
 
820
 
 
821
/* These are defined to get Emacs to compile, but are not used.  */
 
822
int edata;
 
823
int etext;
 
824
 
 
825
/* The major and minor versions of NT.  */
 
826
int nt_major_version;
 
827
int nt_minor_version;
 
828
 
 
829
/* Distinguish between Windows NT and Windows 95.  */
 
830
int os_subtype;
 
831
 
 
832
/* Cache information describing the NT system for later use.  */
 
833
void
 
834
cache_system_info (void)
 
835
{
 
836
  union 
 
837
    {
 
838
      struct info 
 
839
        {
 
840
          char  major;
 
841
          char  minor;
 
842
          short platform;
 
843
        } info;
 
844
      DWORD data;
 
845
    } version;
 
846
 
 
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;
 
851
 
 
852
  if (version.info.platform & 0x8000)
 
853
    os_subtype = OS_WIN95;
 
854
  else
 
855
    os_subtype = OS_NT;
 
856
 
 
857
  /* Cache page size, allocation unit, processor type, etc.  */
 
858
  GetSystemInfo (&sysinfo_cache);
 
859
  syspage_mask = sysinfo_cache.dwPageSize - 1;
 
860
}
 
861
 
 
862
/* Round ADDRESS up to be aligned with ALIGN.  */
 
863
unsigned char *
 
864
round_to_next (unsigned char *address, unsigned long align)
 
865
{
 
866
  unsigned long tmp;
 
867
 
 
868
  tmp = (unsigned long) address;
 
869
  tmp = (tmp + align - 1) / align;
 
870
 
 
871
  return (unsigned char *) (tmp * align);
 
872
}
 
873
 
 
874
 
 
875
/* The start of the data segment.  */
 
876
unsigned char *
 
877
get_data_start (void)
 
878
{
 
879
  return data_region_base;
 
880
}
 
881
 
 
882
/* The end of the data segment.  */
 
883
unsigned char *
 
884
get_data_end (void)
 
885
{
 
886
  return data_region_end;
 
887
}
 
888
 
 
889
static char *
 
890
allocate_heap (void)
 
891
{
 
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).
 
899
 
 
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
 
908
     segments.
 
909
 
 
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.
 
913
 
 
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.
 
920
 
 
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!  */
 
927
 
 
928
  unsigned long base = DBEGIN;   /*  27MB */
 
929
  /*   unsigned long base = 0x01B00000; */  /*  27MB */
 
930
  unsigned long end  = 1 << VALBITS; /* 256MB */
 
931
  void *ptr = NULL;
 
932
 
 
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))
 
937
    {
 
938
      reserved_heap_size = end - base;
 
939
      ptr = VirtualAlloc ((void *) base,
 
940
                          get_reserved_heap_size (),
 
941
                          MEM_RESERVE,
 
942
                          PAGE_NOACCESS);
 
943
      base += 0x00100000;  /* 1MB increment */
 
944
    }
 
945
#else
 
946
  reserved_heap_size = end - base;
 
947
  ptr = VirtualAlloc ((void *) base,
 
948
                      get_reserved_heap_size (),
 
949
                      MEM_RESERVE,
 
950
                      PAGE_NOACCESS);
 
951
#endif
 
952
 
 
953
  return ptr;
 
954
}
 
955
 
 
956
 
 
957
/* Emulate Unix sbrk.  */
 
958
void *
 
959
sbrk (unsigned long increment)
 
960
{
 
961
  void *result;
 
962
  long size = (long) increment;
 
963
  
 
964
  /* Allocate our heap if we haven't done so already.  */
 
965
  if (data_region_base == UNINIT_PTR) 
 
966
    {
 
967
      data_region_base = allocate_heap ();
 
968
      if (!data_region_base)
 
969
        return NULL;
 
970
 
 
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) 
 
974
        {
 
975
          printf ("Error: The heap was allocated in upper memory.\n");
 
976
          exit (1);
 
977
        }
 
978
 
 
979
      data_region_end = data_region_base;
 
980
      real_data_region_end = data_region_end;
 
981
      data_region_size = get_reserved_heap_size ();
 
982
    }
 
983
  
 
984
  result = data_region_end;
 
985
  
 
986
  /* If size is negative, shrink the heap by decommitting pages.  */
 
987
  if (size < 0) 
 
988
    {
 
989
      int new_size;
 
990
      unsigned char *new_data_region_end;
 
991
 
 
992
      size = -size;
 
993
 
 
994
      /* Sanity checks.  */
 
995
      if ((data_region_end - size) < data_region_base)
 
996
        return NULL;
 
997
 
 
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;
 
1005
      if (new_size > 0) 
 
1006
        {
 
1007
          /* Decommit size bytes from the end of the heap.  */
 
1008
          if (!VirtualFree (real_data_region_end, new_size, MEM_DECOMMIT))
 
1009
            return NULL;
 
1010
        }
 
1011
 
 
1012
      data_region_end -= size;
 
1013
    } 
 
1014
  /* If size is positive, grow the heap by committing reserved pages.  */
 
1015
  else if (size > 0) 
 
1016
    {
 
1017
      /* Sanity checks.  */
 
1018
      if ((data_region_end + size) >
 
1019
          (data_region_base + get_reserved_heap_size ()))
 
1020
        return NULL;
 
1021
 
 
1022
      /* Commit more of our heap. */
 
1023
      if (VirtualAlloc (data_region_end, size, MEM_COMMIT,
 
1024
                        PAGE_READWRITE) == NULL)
 
1025
        return NULL;
 
1026
      data_region_end += size;
 
1027
 
 
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);
 
1032
    }
 
1033
  
 
1034
  return result;
 
1035
}
 
1036
 
 
1037
/* Recreate the heap from the data that was dumped to the executable.
 
1038
   EXECUTABLE_PATH tells us where to find the executable.  */
 
1039
void
 
1040
recreate_heap (char *executable_path)
 
1041
{
 
1042
  unsigned char *tmp;
 
1043
 
 
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 (),
 
1049
                      MEM_RESERVE,
 
1050
                      PAGE_NOACCESS);
 
1051
  if (!tmp)
 
1052
    exit (1);
 
1053
 
 
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.  */
 
1057
 
 
1058
  read_in_bss (executable_path);
 
1059
 
 
1060
  map_in_heap (executable_path);
 
1061
 
 
1062
  /* Update system version information to match current system.  */
 
1063
  cache_system_info ();
 
1064
}
 
1065
 
 
1066
/* Round the heap up to the given alignment.  */
 
1067
void
 
1068
round_heap (unsigned long align)
 
1069
{
 
1070
  unsigned long needs_to_be;
 
1071
  unsigned long need_to_alloc;
 
1072
  
 
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 ();
 
1075
  
 
1076
  if (need_to_alloc) 
 
1077
    sbrk (need_to_alloc);
 
1078
}
 
1079
 
 
1080
#if (_MSC_VER >= 1000)
 
1081
 
 
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.  */
 
1086
 
 
1087
int __cdecl
 
1088
_heap_init (void)
 
1089
{
 
1090
  /* Stepping through the assembly indicates that mainCRTStartup is
 
1091
     expecting a nonzero success return value.  */
 
1092
  return 1;
 
1093
}
 
1094
 
 
1095
void __cdecl
 
1096
_heap_term (void)
 
1097
 
 
1098
#endif
 
1099
 
 
1100
 
 
1101
 
 
1102
#ifdef UNIXSAVE
 
1103
BOOL ctrl_c_handler (unsigned long type)
 
1104
{
 
1105
  sigint();
 
1106
  return 0;
 
1107
 
 
1108
}
 
1109
#include "save.c"
 
1110
#endif