From 949e33eb58bad2e17a16da28f8c011a080c7a3fe Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Tue, 13 Feb 2018 18:33:11 +0200 Subject: [PATCH] Fix MS-Windows MinGW build Most of the fixes are portability related. Some functions were moved from unexw32.c to w32proc.c, because they are needed even if unexec is not used. After these fixes, Emacs builds without warnings (GCC 6.3.0), dumps itself, but then crashes when it tries to compile the first Lisp file. --- src/Makefile.in | 2 +- src/alloc.c | 2 + src/buffer.c | 2 +- src/emacs.c | 23 +++++++--- src/pdumper.c | 33 +++++++++----- src/sysdep.c | 2 +- src/unexw32.c | 116 ----------------------------------------------- src/w32heap.c | 7 +++ src/w32proc.c | 117 ++++++++++++++++++++++++++++++++++++++++++++++++ 9 files changed, 168 insertions(+), 136 deletions(-) diff --git a/src/Makefile.in b/src/Makefile.in index 888ce81457b..5fad672bf8a 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -619,7 +619,7 @@ $(libsrc)/make-fingerprint$(EXEEXT): $(libsrc)/make-fingerprint.c $(lib)/libgnu. $(MAKE) -C $(libsrc) make-fingerprint$(EXEEXT) fingerprint.c: temacs.in$(EXEEXT) $(libsrc)/make-fingerprint$(EXEEXT) - $(libsrc)/make-fingerprint$(EXEEXT) temacs.in$(EEXIST) > fingerprint.c + $(libsrc)/make-fingerprint$(EXEEXT) temacs.in$(EXEEXT) > fingerprint.c ## We have to create $(etc) here because init_cmdargs tests its ## existence when setting Vinstallation_directory (FIXME?). diff --git a/src/alloc.c b/src/alloc.c index de933b92112..be34371eabe 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -561,6 +561,7 @@ XFLOAT_INIT (Lisp_Object f, double n) XFLOAT (f)->u.data = n; } +#ifdef DOUG_LEA_MALLOC static bool pointers_fit_in_lispobj_p (void) { @@ -577,6 +578,7 @@ mmap_lisp_allowed_p (void) regions. */ return pointers_fit_in_lispobj_p () && !will_dump_with_unexec_p (); } +#endif /* Head of a circularly-linked list of extant finalizers. */ struct Lisp_Finalizer finalizers; diff --git a/src/buffer.c b/src/buffer.c index 9fa5b891f0e..0702c2c6056 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -5351,7 +5351,7 @@ init_buffer (void) ptrdiff_t len; #ifdef USE_MMAP_FOR_BUFFERS - if (dumped_with_unexec) + if (dumped_with_unexec_p ()) { struct buffer *b; diff --git a/src/emacs.c b/src/emacs.c index 99a12991dcc..d8ebdaf76a4 100644 --- a/src/emacs.c +++ b/src/emacs.c @@ -662,9 +662,9 @@ close_output_streams (void) ATTRIBUTE_UNUSED static bool -string_starts_with_p(const char* string, const char* prefix) +string_starts_with_p (const char* string, const char* prefix) { - return strncmp(string, prefix, strlen(prefix)) == 0; + return strncmp (string, prefix, strlen (prefix)) == 0; } #ifdef HAVE_PDUMPER @@ -833,8 +833,21 @@ main (int argc, char **argv) /* Figure out where we are. Fancy filesystem functions aren't available at this point, so use pure text manipulation. */ const char *argv0_base = strrchr (argv[0], DIRECTORY_SEP); +#ifdef WINDOWSNT + /* Consider backslashes and the .exe extension. */ + const char *argv0_alt = strrchr (argv[0], '\\'); + + if (argv0_alt > argv0_base) + argv0_base = argv0_alt; + argv0_base = argv0_base ? argv0_base + 1 : argv[0]; + bool is_temacs = + c_strncasecmp ("temacs", argv0_base, 6) == 0 + && strlen (argv0_base) >= 4 + && c_strcasecmp (argv0_base + strlen (argv0_base) - 4, ".exe") == 0; +#else argv0_base = argv0_base ? argv0_base + 1 : argv[0]; bool is_temacs = strcmp ("temacs", argv0_base) == 0; +#endif const char *loaded_dump = NULL; const char *dump_mode = NULL; @@ -1353,7 +1366,7 @@ Using an Emacs configured with --with-x-toolkit=lucid does not have this problem that causes an infinite recursive loop with FreeBSD. See Bug#14569. The part of this bug involving Cygwin is no longer relevant, now that Cygwin defines HYBRID_MALLOC. */ - if (!noninteractive || !will_dump) + if (!noninteractive || !will_dump_p ()) malloc_enable_thread (); #endif @@ -1444,7 +1457,7 @@ Using an Emacs configured with --with-x-toolkit=lucid does not have this problem bool module_assertions = argmatch (argv, argc, "-module-assertions", "--module-assertions", 15, NULL, &skip_args); - if (dumping && module_assertions) + if (will_dump_p () && module_assertions) { fputs ("Module assertions are not supported during dumping\n", stderr); exit (1); @@ -1595,7 +1608,7 @@ Using an Emacs configured with --with-x-toolkit=lucid does not have this problem variables from the parent process without modifications from Emacs. */ init_environment (argv); - init_ntproc (will_dump); /* must precede init_editfns. */ + init_ntproc (will_dump_p ()); /* must precede init_editfns. */ #endif /* AIX crashes are reported in system versions 3.2.3 and 3.2.4 diff --git a/src/pdumper.c b/src/pdumper.c index be33011a207..6007f4a23d4 100644 --- a/src/pdumper.c +++ b/src/pdumper.c @@ -79,6 +79,10 @@ # define MAP_POPULATE 0 # endif #elif defined (WINDOWSNT) + /* Use a float infinity, to avoid compiler warnings in comparing vs + candidates' score. */ +# undef INFINITY +# define INFINITY __builtin_inff () # include # define VM_SUPPORTED VM_MS_WINDOWS #else @@ -3031,7 +3035,7 @@ dump_charset_table (struct dump_context *ctx) dump_emacs_reloc_to_dump_ptr_raw (ctx, &charset_table, offset); dump_emacs_reloc_immediate_int ( ctx, &charset_table_used, charset_table_used); - dump_emacs_reloc_immediate_emacs_int ( + dump_emacs_reloc_immediate_ptrdiff_t ( ctx, &charset_table_size, charset_table_used); return offset; } @@ -4090,10 +4094,13 @@ dump_map_file_w32 ( HANDLE file; uint64_t full_offset = offset; - uint32_t size_high = (uint32_t) (full_offset >> 32); - uint32_t size_low = (uint32_t) full_offset; + uint32_t offset_high = (uint32_t) (full_offset >> 32); + uint32_t offset_low = (uint32_t) (full_offset & 0xffffffff); - file = (HANDLE) __get_osfhandle (fd); + int error; + DWORD map_access; + + file = (HANDLE) _get_osfhandle (fd); if (file == INVALID_HANDLE_VALUE) goto out; @@ -4110,8 +4117,6 @@ dump_map_file_w32 ( goto out; } - DWORD map_access; - switch (protection) { case DUMP_MEMORY_ACCESS_NONE: @@ -4132,7 +4137,7 @@ dump_map_file_w32 ( size, base); - int error = GetLastError (); + error = GetLastError (); if (ret == NULL) errno = (error == ERROR_INVALID_ADDRESS ? EBUSY : EPERM); out: @@ -4422,11 +4427,15 @@ dump_mmap_contiguous_vm ( if (resv) dump_anonymous_release (resv, total_size); if (!ret) - for (int i = 0; i < nr_maps; ++i) - if (VM_SUPPORTED == VM_MS_WINDOWS) - dump_mmap_reset (&maps[i]); - else - dump_mmap_release (&maps[i]); + { + for (int i = 0; i < nr_maps; ++i) + { + if (VM_SUPPORTED == VM_MS_WINDOWS) + dump_mmap_reset (&maps[i]); + else + dump_mmap_release (&maps[i]); + } + } return ret; } diff --git a/src/sysdep.c b/src/sysdep.c index ce86504d4df..de9186add52 100644 --- a/src/sysdep.c +++ b/src/sysdep.c @@ -1900,7 +1900,7 @@ init_sigsegv (void) #else /* not HAVE_STACK_OVERFLOW_HANDLING or WINDOWSNT */ -static bool +bool init_sigsegv (void) { return 0; diff --git a/src/unexw32.c b/src/unexw32.c index 41d6ccfb6ed..abb0e159fcf 100644 --- a/src/unexw32.c +++ b/src/unexw32.c @@ -39,8 +39,6 @@ PIMAGE_NT_HEADERS (__stdcall * pfnCheckSumMappedFile) (LPVOID BaseAddress, LPDWORD HeaderSum, LPDWORD CheckSum); -extern BOOL ctrl_c_handler (unsigned long type); - extern char my_begdata[]; extern char my_begbss[]; extern char *my_begbss_static; @@ -70,84 +68,10 @@ PCHAR bss_start_static = 0; DWORD_PTR bss_size_static = 0; DWORD_PTR extra_bss_size_static = 0; -/* MinGW64 doesn't add a leading underscore to external symbols, - whereas configure.ac sets up LD_SWITCH_SYSTEM_TEMACS to force the - entry point at __start, with two underscores. */ -#ifdef __MINGW64__ -#define _start __start -#endif - -extern void mainCRTStartup (void); - -/* Startup code for running on NT. When we are running as the dumped - version, we need to bootstrap our heap and .bss section into our - address space before we can actually hand off control to the startup - code supplied by NT (primarily because that code relies upon malloc ()). */ -void _start (void); - -void -_start (void) -{ - -#if 1 - /* Give us a way to debug problems with crashes on startup when - running under the MSVC profiler. */ - if (GetEnvironmentVariable ("EMACS_DEBUG", NULL, 0) > 0) - DebugBreak (); -#endif - - /* Cache system info, e.g., the NT page size. */ - cache_system_info (); - - /* Grab our malloc arena space now, before CRT starts up. */ - init_heap (); - - /* This prevents ctrl-c's in shells running while we're suspended from - having us exit. */ - SetConsoleCtrlHandler ((PHANDLER_ROUTINE) ctrl_c_handler, TRUE); - - /* Prevent Emacs from being locked up (eg. in batch mode) when - accessing devices that aren't mounted (eg. removable media drives). */ - SetErrorMode (SEM_FAILCRITICALERRORS); - mainCRTStartup (); -} - - /* File handling. */ /* Implementation note: this and the next functions work with ANSI codepage encoded file names! */ -int -open_input_file (file_data *p_file, char *filename) -{ - HANDLE file; - HANDLE file_mapping; - void *file_base; - unsigned long size, upper_size; - - file = CreateFileA (filename, GENERIC_READ, FILE_SHARE_READ, NULL, - OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); - if (file == INVALID_HANDLE_VALUE) - return FALSE; - - size = GetFileSize (file, &upper_size); - file_mapping = CreateFileMapping (file, NULL, PAGE_READONLY, - 0, size, NULL); - if (!file_mapping) - return FALSE; - - file_base = MapViewOfFile (file_mapping, FILE_MAP_READ, 0, 0, size); - if (file_base == 0) - return FALSE; - - p_file->name = filename; - p_file->size = size; - p_file->file = file; - p_file->file_mapping = file_mapping; - p_file->file_base = file_base; - - return TRUE; -} int open_output_file (file_data *p_file, char *filename, unsigned long size) @@ -187,18 +111,6 @@ open_output_file (file_data *p_file, char *filename, unsigned long size) return TRUE; } -/* Close the system structures associated with the given file. */ -void -close_file_data (file_data *p_file) -{ - UnmapViewOfFile (p_file->file_base); - CloseHandle (p_file->file_mapping); - /* For the case of output files, set final size. */ - SetFilePointer (p_file->file, p_file->size, NULL, FILE_BEGIN); - SetEndOfFile (p_file->file); - CloseHandle (p_file->file); -} - /* Routines to manipulate NT executable file sections. */ @@ -220,34 +132,6 @@ find_section (const char * name, IMAGE_NT_HEADERS * nt_header) return NULL; } -/* Return pointer to section header for section containing the given - relative virtual address. */ -IMAGE_SECTION_HEADER * -rva_to_section (DWORD_PTR rva, IMAGE_NT_HEADERS * nt_header) -{ - PIMAGE_SECTION_HEADER section; - int i; - - section = IMAGE_FIRST_SECTION (nt_header); - - for (i = 0; i < nt_header->FileHeader.NumberOfSections; i++) - { - /* Some linkers (eg. the NT SDK linker I believe) swapped the - meaning of these two values - or rather, they ignored - VirtualSize entirely and always set it to zero. This affects - some very old exes (eg. gzip dated Dec 1993). Since - w32_executable_type relies on this function to work reliably, - we need to cope with this. */ - DWORD_PTR real_size = max (section->SizeOfRawData, - section->Misc.VirtualSize); - if (rva >= section->VirtualAddress - && rva < section->VirtualAddress + real_size) - return section; - section++; - } - return NULL; -} - #if 0 /* unused */ /* Return pointer to section header for section containing the given offset in its raw data area. */ diff --git a/src/w32heap.c b/src/w32heap.c index a3f87bfc7e6..e64b88c33f4 100644 --- a/src/w32heap.c +++ b/src/w32heap.c @@ -223,9 +223,16 @@ typedef enum _HEAP_INFORMATION_CLASS { typedef WINBASEAPI BOOL (WINAPI * HeapSetInformation_Proc)(HANDLE,HEAP_INFORMATION_CLASS,PVOID,SIZE_T); #endif +#ifdef HAVE_PDUMPER +BOOL using_dynamic_heap = FALSE; +#endif + void init_heap (void) { +#ifdef HAVE_PDUMPER + using_dynamic_heap = TRUE; +#endif if (using_dynamic_heap) { #ifndef MINGW_W64 diff --git a/src/w32proc.c b/src/w32proc.c index 28d7b6611f6..f67c5c80e8f 100644 --- a/src/w32proc.c +++ b/src/w32proc.c @@ -81,6 +81,51 @@ static sigset_t sig_mask; static CRITICAL_SECTION crit_sig; + +extern BOOL ctrl_c_handler (unsigned long type); + +/* MinGW64 doesn't add a leading underscore to external symbols, + whereas configure.ac sets up LD_SWITCH_SYSTEM_TEMACS to force the + entry point at __start, with two underscores. */ +#ifdef __MINGW64__ +#define _start __start +#endif + +extern void mainCRTStartup (void); + +/* Startup code for running on NT. When we are running as the dumped + version, we need to bootstrap our heap and .bss section into our + address space before we can actually hand off control to the startup + code supplied by NT (primarily because that code relies upon malloc ()). */ +void _start (void); + +void +_start (void) +{ + +#if 1 + /* Give us a way to debug problems with crashes on startup when + running under the MSVC profiler. */ + if (GetEnvironmentVariable ("EMACS_DEBUG", NULL, 0) > 0) + DebugBreak (); +#endif + + /* Cache system info, e.g., the NT page size. */ + cache_system_info (); + + /* Grab our malloc arena space now, before CRT starts up. */ + init_heap (); + + /* This prevents ctrl-c's in shells running while we're suspended from + having us exit. */ + SetConsoleCtrlHandler ((PHANDLER_ROUTINE) ctrl_c_handler, TRUE); + + /* Prevent Emacs from being locked up (eg. in batch mode) when + accessing devices that aren't mounted (eg. removable media drives). */ + SetErrorMode (SEM_FAILCRITICALERRORS); + mainCRTStartup (); +} + /* Improve on the CRT 'signal' implementation so that we could record the SIGCHLD handler and fake interval timers. */ signal_handler @@ -1529,6 +1574,78 @@ waitpid (pid_t pid, int *status, int options) return pid; } +int +open_input_file (file_data *p_file, char *filename) +{ + HANDLE file; + HANDLE file_mapping; + void *file_base; + unsigned long size, upper_size; + + file = CreateFileA (filename, GENERIC_READ, FILE_SHARE_READ, NULL, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); + if (file == INVALID_HANDLE_VALUE) + return FALSE; + + size = GetFileSize (file, &upper_size); + file_mapping = CreateFileMapping (file, NULL, PAGE_READONLY, + 0, size, NULL); + if (!file_mapping) + return FALSE; + + file_base = MapViewOfFile (file_mapping, FILE_MAP_READ, 0, 0, size); + if (file_base == 0) + return FALSE; + + p_file->name = filename; + p_file->size = size; + p_file->file = file; + p_file->file_mapping = file_mapping; + p_file->file_base = file_base; + + return TRUE; +} + +/* Return pointer to section header for section containing the given + relative virtual address. */ +IMAGE_SECTION_HEADER * +rva_to_section (DWORD_PTR rva, IMAGE_NT_HEADERS * nt_header) +{ + PIMAGE_SECTION_HEADER section; + int i; + + section = IMAGE_FIRST_SECTION (nt_header); + + for (i = 0; i < nt_header->FileHeader.NumberOfSections; i++) + { + /* Some linkers (eg. the NT SDK linker I believe) swapped the + meaning of these two values - or rather, they ignored + VirtualSize entirely and always set it to zero. This affects + some very old exes (eg. gzip dated Dec 1993). Since + w32_executable_type relies on this function to work reliably, + we need to cope with this. */ + DWORD_PTR real_size = max (section->SizeOfRawData, + section->Misc.VirtualSize); + if (rva >= section->VirtualAddress + && rva < section->VirtualAddress + real_size) + return section; + section++; + } + return NULL; +} + +/* Close the system structures associated with the given file. */ +void +close_file_data (file_data *p_file) +{ + UnmapViewOfFile (p_file->file_base); + CloseHandle (p_file->file_mapping); + /* For the case of output files, set final size. */ + SetFilePointer (p_file->file, p_file->size, NULL, FILE_BEGIN); + SetEndOfFile (p_file->file); + CloseHandle (p_file->file); +} + /* Old versions of w32api headers don't have separate 32-bit and 64-bit defines, but the one they have matches the 32-bit variety. */ #ifndef IMAGE_NT_OPTIONAL_HDR32_MAGIC -- 2.39.5