From 27f564e9a3c8c81e95d8bfa195c0a3edadb35127 Mon Sep 17 00:00:00 2001 From: Christopher Faylor Date: Fri, 7 May 2010 21:25:19 +0000 Subject: [PATCH] * Makefile.in (DLL_OFILES): Add pseudo-reloc.o. * dcrt0.cc (child_info_fork::handle_fork): Call _pei386_runtime_relocator here. (dll_crt0_1): Ditto for non-fork case. * dll_init.cc (dll::init): Complain more in comment. Clean up slightly. (dll_dllcrt0_1): Call _pei386_runtime_relocator when we know we have a filled-in per_process structure. * globals.cc (__cygwin_user_data): Accommodate new fields for _pei386_runtime_relocator. * pseudo-reloc.cc: New file adapted from old lib/pseudo-reloc.c. Include winsup.h directly. Collapse #ifdef __CYGWIN__ into one block. Perform minor whitespace code reformatting. (__report_error): Use small_printf to output error. (_pei386_runtime_relocator): Conditionalize for cygwin to take per_process pointer parameter. * winsup.h (_pei386_runtime_relocator): Declare. * include/cygwin/version.h (CYGWIN_VERSION_PER_PROCESS_API_VERSION_COMBINED): New macro. (CYGWIN_VERSION_USER_API_VERSION_COMBINED): Use above macro. (CYGWIN_VERSION_USE_PSEUDO_RELOC_IN_DLL): New macro. (CYGWIN_VERSION_API_MINOR): Bump to 227. * include/sys/cygwin.h: Remove obsolete comment. (per_process::unused2): Shorten. (per_process::pseudo_reloc_start): New field. (per_process::pseudo_reloc_end): Ditto. (per_process::image_base): Ditto. * lib/_cygwin_crt0_common.cc: Declare pseudo runtime externs needed for per_process structure. (_cygwin_crt0_common): Fill in pseudo_reloc runtime constants. * lib/pseudo-reloc-dummy.c: New file. Dummy function to satisify ld. * lib/pseudo-reloc.c: Delete. --- winsup/cygwin/ChangeLog | 35 +++ winsup/cygwin/Makefile.in | 16 +- winsup/cygwin/dcrt0.cc | 12 +- winsup/cygwin/dll_init.cc | 9 +- winsup/cygwin/globals.cc | 11 +- winsup/cygwin/include/cygwin/version.h | 11 +- winsup/cygwin/include/sys/cygwin.h | 9 +- winsup/cygwin/lib/_cygwin_crt0_common.cc | 12 +- winsup/cygwin/lib/pseudo-reloc-dummy.c | 10 + winsup/cygwin/lib/pseudo-reloc.c | 367 ----------------------- winsup/cygwin/pseudo-reloc.cc | 160 +++++----- winsup/cygwin/winsup.h | 2 + 12 files changed, 172 insertions(+), 482 deletions(-) create mode 100644 winsup/cygwin/lib/pseudo-reloc-dummy.c delete mode 100644 winsup/cygwin/lib/pseudo-reloc.c diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index ec2a931ce..a2d40a9f6 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,38 @@ +2010-05-07 Christopher Faylor + + * Makefile.in (DLL_OFILES): Add pseudo-reloc.o. + * dcrt0.cc (child_info_fork::handle_fork): Call + _pei386_runtime_relocator here. + (dll_crt0_1): Ditto for non-fork case. + * dll_init.cc (dll::init): Complain more in comment. Clean up + slightly. + (dll_dllcrt0_1): Call _pei386_runtime_relocator when we know we have + a filled-in per_process structure. + * globals.cc (__cygwin_user_data): Accommodate new fields for + _pei386_runtime_relocator. + * pseudo-reloc.cc: New file adapted from old lib/pseudo-reloc.c. + Include winsup.h directly. Collapse #ifdef __CYGWIN__ into one block. + Perform minor whitespace code reformatting. + (__report_error): Use small_printf to output error. + (_pei386_runtime_relocator): Conditionalize for cygwin to take + per_process pointer parameter. + * winsup.h (_pei386_runtime_relocator): Declare. + * include/cygwin/version.h + (CYGWIN_VERSION_PER_PROCESS_API_VERSION_COMBINED): New macro. + (CYGWIN_VERSION_USER_API_VERSION_COMBINED): Use above macro. + (CYGWIN_VERSION_USE_PSEUDO_RELOC_IN_DLL): New macro. + (CYGWIN_VERSION_API_MINOR): Bump to 227. + * include/sys/cygwin.h: Remove obsolete comment. + (per_process::unused2): Shorten. + (per_process::pseudo_reloc_start): New field. + (per_process::pseudo_reloc_end): Ditto. + (per_process::image_base): Ditto. + * lib/_cygwin_crt0_common.cc: Declare pseudo runtime externs needed for + per_process structure. + (_cygwin_crt0_common): Fill in pseudo_reloc runtime constants. + * lib/pseudo-reloc-dummy.c: New file. Dummy function to satisify ld. + * lib/pseudo-reloc.c: Delete. + 2010-05-07 Corinna Vinschen * fhandler_tty.cc (fhandler_tty_slave::init): Disable grabbing diff --git a/winsup/cygwin/Makefile.in b/winsup/cygwin/Makefile.in index 0499a5cc7..3f4c0044f 100644 --- a/winsup/cygwin/Makefile.in +++ b/winsup/cygwin/Makefile.in @@ -149,14 +149,14 @@ DLL_OFILES:=assert.o autoload.o bsdlib.o ctype.o cxx.o cygheap.o cygthread.o \ init.o ioctl.o ipc.o kernel32.o libstdcxx_wrapper.o localtime.o lsearch.o \ malloc_wrapper.o minires-os-if.o minires.o miscfuncs.o mktemp.o mmap.o msg.o \ mount.o net.o netdb.o nfs.o nftw.o nlsfuncs.o ntea.o passwd.o path.o \ - pinfo.o pipe.o poll.o posix_ipc.o pthread.o random.o regcomp.o \ - regerror.o regexec.o regfree.o registry.o resource.o rexec.o rcmd.o \ - scandir.o sched.o sec_acl.o sec_auth.o sec_helper.o security.o select.o \ - sem.o setlsapwd.o shared.o shm.o sigfe.o signal.o sigproc.o smallprint.o \ - spawn.o strace.o strfmon.o strfuncs.o strptime.o strsep.o strsig.o sync.o \ - syscalls.o sysconf.o syslog.o termios.o thread.o timer.o times.o \ - tls_pbuf.o tty.o uinfo.o uname.o wait.o wincap.o window.o winf.o \ - xsique.o \ + pinfo.o pipe.o poll.o posix_ipc.o pseudo-reloc.o pthread.o random.o \ + regcomp.o regerror.o regexec.o regfree.o registry.o resource.o rexec.o \ + rcmd.o scandir.o sched.o sec_acl.o sec_auth.o sec_helper.o security.o \ + select.o sem.o setlsapwd.o shared.o shm.o sigfe.o signal.o sigproc.o \ + smallprint.o spawn.o strace.o strfmon.o strfuncs.o strptime.o strsep.o \ + strsig.o sync.o syscalls.o sysconf.o syslog.o termios.o thread.o \ + timer.o times.o tls_pbuf.o tty.o uinfo.o uname.o wait.o wincap.o \ + window.o winf.o xsique.o \ $(EXTRA_DLL_OFILES) $(EXTRA_OFILES) $(MALLOC_OFILES) $(MT_SAFE_OBJECTS) EXCLUDE_STATIC_OFILES:=$(addprefix --exclude=,\ diff --git a/winsup/cygwin/dcrt0.cc b/winsup/cygwin/dcrt0.cc index 76b89517b..d32ff22c9 100644 --- a/winsup/cygwin/dcrt0.cc +++ b/winsup/cygwin/dcrt0.cc @@ -41,7 +41,6 @@ details. */ #define PREMAIN_LEN (sizeof (user_data->premain) / sizeof (user_data->premain[0])) - extern "C" void cygwin_exit (int) __attribute__ ((noreturn)); extern "C" void __sinit (_reent *); @@ -592,6 +591,12 @@ child_info_fork::handle_fork () "dll bss", dll_bss_start, dll_bss_end, "user heap", cygheap->user_heap.base, cygheap->user_heap.ptr, NULL); + + /* Do the relocations here. These will actually likely be overwritten by the + below child_copy but we do them here in case there is a read-only section + which does not get copied by fork. */ + _pei386_runtime_relocator (user_data); + /* step 2 now that the dll has its heap filled in, we can fill in the user's data and bss since user_data is now filled out. */ child_copy (parent, false, @@ -794,7 +799,10 @@ dll_crt0_1 (void *) /* Initialize pthread mainthread when not forked and it is safe to call new, otherwise it is reinitalized in fixup_after_fork */ if (!in_forkee) - pthread::init_mainthread (); + { + pthread::init_mainthread (); + _pei386_runtime_relocator (user_data); + } #ifdef DEBUGGING strace.microseconds (); diff --git a/winsup/cygwin/dll_init.cc b/winsup/cygwin/dll_init.cc index c2b141362..ec1132434 100644 --- a/winsup/cygwin/dll_init.cc +++ b/winsup/cygwin/dll_init.cc @@ -75,7 +75,7 @@ dll::init () { int ret = 1; - /* Why didn't we just import this variable? */ + /* This should be a no-op. Why didn't we just import this variable? */ *(p.envptr) = __cygwin_environ; /* Don't run constructors or the "main" if we've forked. */ @@ -86,7 +86,7 @@ dll::init () /* entry point of dll (use main of per_process with null args...) */ if (p.main) - ret = (*(p.main)) (0, 0, 0); + ret = p.main (0, 0, 0); } return ret; @@ -333,7 +333,10 @@ dll_dllcrt0_1 (VOID *x) if (p == NULL) p = &__cygwin_user_data; else - *(p->impure_ptr_ptr) = __cygwin_user_data.impure_ptr; + { + *(p->impure_ptr_ptr) = __cygwin_user_data.impure_ptr; + _pei386_runtime_relocator (p); + } bool linked = !in_forkee && !cygwin_finished_initializing; diff --git a/winsup/cygwin/globals.cc b/winsup/cygwin/globals.cc index 0baa96e3a..6060edcf3 100644 --- a/winsup/cygwin/globals.cc +++ b/winsup/cygwin/globals.cc @@ -147,12 +147,15 @@ extern "C" /* calloc */ calloc, /* premain */ {NULL, NULL, NULL, NULL}, /* run_ctors_p */ 0, - /* unused */ {0, 0, 0, 0, 0, 0, 0}, + /* unused */ {}, /* cxx_malloc */ &default_cygwin_cxx_malloc, /* hmodule */ NULL, - /* api_major */ CYGWIN_VERSION_API_MAJOR, - /* api_minor */ CYGWIN_VERSION_API_MINOR, - /* unused2 */ {0, 0, 0, 0, 0, 0}, + /* api_major */ 0, + /* api_minor */ 0, + /* unused2 */ {}, + /* pseudo_reloc_start */ NULL, + /* pseudo_reloc_end */ NULL, + /* image_base */ NULL, /* threadinterface */ &_mtinterf, /* impure_ptr */ _GLOBAL_REENT, }; diff --git a/winsup/cygwin/include/cygwin/version.h b/winsup/cygwin/include/cygwin/version.h index fb9ce136b..08ffebcf2 100644 --- a/winsup/cygwin/include/cygwin/version.h +++ b/winsup/cygwin/include/cygwin/version.h @@ -62,8 +62,11 @@ details. */ /* Every version of cygwin <= this uses an old, incorrect method to determine signal masks. */ +#define CYGWIN_VERSION_PER_PROCESS_API_VERSION_COMBINED(u) \ + CYGWIN_VERSION_DLL_MAKE_COMBINED ((u)->api_major, (u)->api_minor) + #define CYGWIN_VERSION_USER_API_VERSION_COMBINED \ - CYGWIN_VERSION_DLL_MAKE_COMBINED (user_data->api_major, user_data->api_minor) + CYGWIN_VERSION_PER_PROCESS_API_VERSION_COMBINED (user_data) /* API versions <= this had a termios structure whose members were too small to accomodate modern settings. */ @@ -98,6 +101,9 @@ details. */ #define CYGWIN_VERSION_CHECK_FOR_OLD_CTYPE \ (CYGWIN_VERSION_USER_API_VERSION_COMBINED <= 209) +#define CYGWIN_VERSION_USE_PSEUDO_RELOC_IN_DLL(u) \ + (CYGWIN_VERSION_PER_PROCESS_API_VERSION_COMBINED (u) >= 227) + #define CYGWIN_VERSION_CYGWIN_CONV 181 /* API_MAJOR 0.0: Initial version. API_MINOR changes: @@ -380,12 +386,13 @@ details. */ 224: Export xdr* functions. 225: Export __xdr* functions. 226: Export __locale_mb_cur_max. + 227: Add pseudo_reloc_start, pseudo_reloc_end, image_base to per_process */ /* Note that we forgot to bump the api for ualarm, strtoll, strtoull */ #define CYGWIN_VERSION_API_MAJOR 0 -#define CYGWIN_VERSION_API_MINOR 226 +#define CYGWIN_VERSION_API_MINOR 227 /* There is also a compatibity version number associated with the shared memory regions. It is incremented when incompatible diff --git a/winsup/cygwin/include/sys/cygwin.h b/winsup/cygwin/include/sys/cygwin.h index 425fd82fd..dcf61b081 100644 --- a/winsup/cygwin/include/sys/cygwin.h +++ b/winsup/cygwin/include/sys/cygwin.h @@ -244,10 +244,6 @@ struct per_process /* For future expansion of values set by the app. */ void (*premain[4]) (int, char **, struct per_process *); - /* The rest are *internal* to cygwin.dll. - Those that are here because we want the child to inherit the value from - the parent (which happens when bss is copied) are marked as such. */ - /* non-zero of ctors have been run. Inherited from parent. */ int run_ctors_p; @@ -262,7 +258,10 @@ struct per_process DWORD api_minor; /* linked with */ /* For future expansion, so apps won't have to be relinked if we add an item. */ - DWORD unused2[6]; + DWORD unused2[3]; + void *pseudo_reloc_start; + void *pseudo_reloc_end; + void *image_base; #if defined (__INSIDE_CYGWIN__) && defined (__cplusplus) MTinterface *threadinterface; diff --git a/winsup/cygwin/lib/_cygwin_crt0_common.cc b/winsup/cygwin/lib/_cygwin_crt0_common.cc index b8586e557..222f159e1 100644 --- a/winsup/cygwin/lib/_cygwin_crt0_common.cc +++ b/winsup/cygwin/lib/_cygwin_crt0_common.cc @@ -49,7 +49,11 @@ extern "C" { char **environ; int _fmode; -void _pei386_runtime_relocator (); +void _pei386_runtime_relocator (void); + +extern char __RUNTIME_PSEUDO_RELOC_LIST__; +extern char __RUNTIME_PSEUDO_RELOC_LIST_END__; +extern char _image_base__; struct per_process_cxx_malloc __cygwin_cxx_malloc = { @@ -146,7 +150,11 @@ _cygwin_crt0_common (MainFunc f, per_process *u) u->data_end = &_data_end__; u->bss_start = &_bss_start__; u->bss_end = &_bss_end__; - + u->pseudo_reloc_start = &__RUNTIME_PSEUDO_RELOC_LIST__; + u->pseudo_reloc_end = &__RUNTIME_PSEUDO_RELOC_LIST_END__; + u->image_base = &_image_base__; + /* This is actually a dummy call to force the linker to load this + symbol for older apps which need it. */ _pei386_runtime_relocator (); return 1; } diff --git a/winsup/cygwin/lib/pseudo-reloc-dummy.c b/winsup/cygwin/lib/pseudo-reloc-dummy.c new file mode 100644 index 000000000..0cd8c4eb4 --- /dev/null +++ b/winsup/cygwin/lib/pseudo-reloc-dummy.c @@ -0,0 +1,10 @@ +/* pseudo-reloc.c + + Stub for older binaries. +*/ + +void +_pei386_runtime_relocator () +{ + return; +} diff --git a/winsup/cygwin/lib/pseudo-reloc.c b/winsup/cygwin/lib/pseudo-reloc.c deleted file mode 100644 index 77f041114..000000000 --- a/winsup/cygwin/lib/pseudo-reloc.c +++ /dev/null @@ -1,367 +0,0 @@ -/* pseudo-reloc.c - - Contributed by Egor Duda - Modified by addition of runtime_pseudo_reloc version 2 - by Kai Tietz - - THIS SOFTWARE IS NOT COPYRIGHTED - - This source code is offered for use in the public domain. You may - use, modify or distribute it freely. - - This code is distributed in the hope that it will be useful but - WITHOUT ANY WARRANTY. ALL WARRENTIES, EXPRESS OR IMPLIED ARE HEREBY - DISCLAMED. This includes but is not limited to warrenties of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -*/ - -#include -#include -#include -#include -#include - -#if defined(__CYGWIN__) -#include -#include -#include -/* copied from winsup.h */ -# define NO_COPY __attribute__((nocommon)) __attribute__((section(".data_cygwin_nocopy"))) -/* custom status code: */ -#define STATUS_ILLEGAL_DLL_PSEUDO_RELOCATION ((NTSTATUS) 0xe0000269) -#define SHORT_MSG_BUF_SZ 128 -#else -# define NO_COPY -#endif - -#ifdef __GNUC__ -#define ATTRIBUTE_NORETURN __attribute__ ((noreturn)) -#else -#define ATTRIBUTE_NORETURN -#endif - -#ifndef __MINGW_LSYMBOL -#define __MINGW_LSYMBOL(sym) sym -#endif - -extern char __RUNTIME_PSEUDO_RELOC_LIST__; -extern char __RUNTIME_PSEUDO_RELOC_LIST_END__; -extern char __MINGW_LSYMBOL(_image_base__); - -void _pei386_runtime_relocator (void); - -/* v1 relocation is basically: - * *(base + .target) += .addend - * where (base + .target) is always assumed to point - * to a DWORD (4 bytes). - */ -typedef struct { - DWORD addend; - DWORD target; -} runtime_pseudo_reloc_item_v1; - -/* v2 relocation is more complex. In effect, it is - * *(base + .target) += *(base + .sym) - (base + .sym) - * with care taken in both reading, sign extension, and writing - * because .flags may indicate that (base + .target) may point - * to a BYTE, WORD, DWORD, or QWORD (w64). - */ -typedef struct { - DWORD sym; - DWORD target; - DWORD flags; -} runtime_pseudo_reloc_item_v2; - -typedef struct { - DWORD magic1; - DWORD magic2; - DWORD version; -} runtime_pseudo_reloc_v2; - -static void ATTRIBUTE_NORETURN -__report_error (const char *msg, ...) -{ -#ifdef __CYGWIN__ - /* This function is used to print short error messages - * to stderr, which may occur during DLL initialization - * while fixing up 'pseudo' relocations. This early, we - * may not be able to use cygwin stdio functions, so we - * use the win32 WriteFile api. This should work with both - * normal win32 console IO handles, redirected ones, and - * cygwin ptys. - */ - char buf[SHORT_MSG_BUF_SZ]; - wchar_t module[MAX_PATH]; - char * posix_module = NULL; - static const char UNKNOWN_MODULE[] = ": "; - static const size_t UNKNOWN_MODULE_LEN = sizeof (UNKNOWN_MODULE) - 1; - static const char CYGWIN_FAILURE_MSG[] = "Cygwin runtime failure: "; - static const size_t CYGWIN_FAILURE_MSG_LEN = sizeof (CYGWIN_FAILURE_MSG) - 1; - DWORD len; - DWORD done; - va_list args; - HANDLE errh = GetStdHandle (STD_ERROR_HANDLE); - ssize_t modulelen = GetModuleFileNameW (NULL, module, sizeof (module)); - - if (errh == INVALID_HANDLE_VALUE) - cygwin_internal (CW_EXIT_PROCESS, - STATUS_ILLEGAL_DLL_PSEUDO_RELOCATION, - 1); - - if (modulelen > 0) - posix_module = cygwin_create_path (CCP_WIN_W_TO_POSIX, module); - - va_start (args, msg); - len = (DWORD) vsnprintf (buf, SHORT_MSG_BUF_SZ, msg, args); - va_end (args); - buf[SHORT_MSG_BUF_SZ-1] = '\0'; /* paranoia */ - - if (posix_module) - { - WriteFile (errh, (PCVOID)CYGWIN_FAILURE_MSG, - CYGWIN_FAILURE_MSG_LEN, &done, NULL); - WriteFile (errh, (PCVOID)posix_module, - strlen(posix_module), &done, NULL); - WriteFile (errh, (PCVOID)": ", 2, &done, NULL); - WriteFile (errh, (PCVOID)buf, len, &done, NULL); - free (posix_module); - } - else - { - WriteFile (errh, (PCVOID)CYGWIN_FAILURE_MSG, - CYGWIN_FAILURE_MSG_LEN, &done, NULL); - WriteFile (errh, (PCVOID)UNKNOWN_MODULE, - UNKNOWN_MODULE_LEN, &done, NULL); - WriteFile (errh, (PCVOID)buf, len, &done, NULL); - } - WriteFile (errh, (PCVOID)"\n", 1, &done, NULL); - - cygwin_internal (CW_EXIT_PROCESS, - STATUS_ILLEGAL_DLL_PSEUDO_RELOCATION, - 1); - /* not reached, but silences noreturn warning */ - abort (); -#else - va_list argp; - va_start (argp, msg); -# ifdef __MINGW64_VERSION_MAJOR - fprintf (stderr, "Mingw-w64 runtime failure:\n"); -# else - fprintf (stderr, "Mingw runtime failure:\n"); -# endif - vfprintf (stderr, msg, argp); - va_end (argp); - abort (); -#endif -} - -/* This function temporarily marks the page containing addr - * writable, before copying len bytes from *src to *addr, and - * then restores the original protection settings to the page. - * - * Using this function eliminates the requirement with older - * pseudo-reloc implementations, that sections containing - * pseudo-relocs (such as .text and .rdata) be permanently - * marked writable. This older behavior sabotaged any memory - * savings achieved by shared libraries on win32 -- and was - * slower, too. However, on cygwin as of binutils 2.20 the - * .text section is still marked writable, and the .rdata section - * is folded into the (writable) .data when --enable-auto-import. - */ -static void -__write_memory (void *addr, const void *src, size_t len) -{ - MEMORY_BASIC_INFORMATION b; - DWORD oldprot; - - if (!len) - return; - - if (!VirtualQuery (addr, &b, sizeof(b))) - { - __report_error (" VirtualQuery failed for %d bytes at address %p", - (int) sizeof(b), addr); - } - - /* Temporarily allow write access to read-only protected memory. */ - if (b.Protect != PAGE_EXECUTE_READWRITE && b.Protect != PAGE_READWRITE) - VirtualProtect (b.BaseAddress, b.RegionSize, PAGE_EXECUTE_READWRITE, - &oldprot); - /* write the data. */ - memcpy (addr, src, len); - /* Restore original protection. */ - if (b.Protect != PAGE_EXECUTE_READWRITE && b.Protect != PAGE_READWRITE) - VirtualProtect (b.BaseAddress, b.RegionSize, oldprot, &oldprot); -} - -#define RP_VERSION_V1 0 -#define RP_VERSION_V2 1 - -static void -do_pseudo_reloc (void * start, void * end, void * base) -{ - ptrdiff_t addr_imp, reldata; - ptrdiff_t reloc_target = (ptrdiff_t) ((char *)end - (char*)start); - runtime_pseudo_reloc_v2 *v2_hdr = (runtime_pseudo_reloc_v2 *) start; - runtime_pseudo_reloc_item_v2 *r; - - /* A valid relocation list will contain at least one entry, and - * one v1 data structure (the smallest one) requires two DWORDs. - * So, if the relocation list is smaller than 8 bytes, bail. - */ - if (reloc_target < 8) - return; - - /* Check if this is the old pseudo relocation version. */ - /* There are two kinds of v1 relocation lists: - * 1) With a (v2-style) version header. In this case, the - * first entry in the list is a 3-DWORD structure, with - * value: - * { 0, 0, RP_VERSION_V1 } - * In this case, we skip to the next entry in the list, - * knowing that all elements after the head item can - * be cast to runtime_pseudo_reloc_item_v1. - * 2) Without a (v2-style) version header. In this case, the - * first element in the list IS an actual v1 relocation - * record, which is two DWORDs. Because there will never - * be a case where a v1 relocation record has both - * addend == 0 and target == 0, this case will not be - * confused with the prior one. - * All current binutils, when generating a v1 relocation list, - * use the second (e.g. original) form -- that is, without the - * v2-style version header. - */ - if (reloc_target >= 12 - && v2_hdr->magic1 == 0 && v2_hdr->magic2 == 0 - && v2_hdr->version == RP_VERSION_V1) - { - /* We have a list header item indicating that the rest - * of the list contains v1 entries. Move the pointer to - * the first true v1 relocation record. By definition, - * that v1 element will not have both addend == 0 and - * target == 0 (and thus, when interpreted as a - * runtime_pseudo_reloc_v2, it will not have both - * magic1 == 0 and magic2 == 0). - */ - v2_hdr++; - } - - if (v2_hdr->magic1 != 0 || v2_hdr->magic2 != 0) - { - /************************* - * Handle v1 relocations * - *************************/ - runtime_pseudo_reloc_item_v1 * o; - for (o = (runtime_pseudo_reloc_item_v1 *) v2_hdr; - o < (runtime_pseudo_reloc_item_v1 *)end; - o++) - { - DWORD newval; - reloc_target = (ptrdiff_t) base + o->target; - newval = (*((DWORD*) reloc_target)) + o->addend; - __write_memory ((void *) reloc_target, &newval, sizeof(DWORD)); - } - return; - } - - /* If we got this far, then we have relocations of version 2 or newer */ - - /* Check if this is a known version. */ - if (v2_hdr->version != RP_VERSION_V2) - { - __report_error (" Unknown pseudo relocation protocol version %d.\n", - (int) v2_hdr->version); - return; - } - - /************************* - * Handle v2 relocations * - *************************/ - - /* Walk over header. */ - r = (runtime_pseudo_reloc_item_v2 *) &v2_hdr[1]; - - for (; r < (runtime_pseudo_reloc_item_v2 *) end; r++) - { - /* location where new address will be written */ - reloc_target = (ptrdiff_t) base + r->target; - - /* get sym pointer. It points either to the iat entry - * of the referenced element, or to the stub function. - */ - addr_imp = (ptrdiff_t) base + r->sym; - addr_imp = *((ptrdiff_t *) addr_imp); - - /* read existing relocation value from image, casting to the - * bitsize indicated by the 8 LSBs of flags. If the value is - * negative, manually sign-extend to ptrdiff_t width. Raise an - * error if the bitsize indicated by the 8 LSBs of flags is not - * supported. - */ - switch ((r->flags & 0xff)) - { - case 8: - reldata = (ptrdiff_t) (*((unsigned char *)reloc_target)); - if ((reldata & 0x80) != 0) - reldata |= ~((ptrdiff_t) 0xff); - break; - case 16: - reldata = (ptrdiff_t) (*((unsigned short *)reloc_target)); - if ((reldata & 0x8000) != 0) - reldata |= ~((ptrdiff_t) 0xffff); - break; - case 32: - reldata = (ptrdiff_t) (*((unsigned int *)reloc_target)); -#ifdef _WIN64 - if ((reldata & 0x80000000) != 0) - reldata |= ~((ptrdiff_t) 0xffffffff); -#endif - break; -#ifdef _WIN64 - case 64: - reldata = (ptrdiff_t) (*((unsigned long long *)reloc_target)); - break; -#endif - default: - reldata=0; - __report_error (" Unknown pseudo relocation bit size %d.\n", - (int) (r->flags & 0xff)); - break; - } - - /* Adjust the relocation value */ - reldata -= ((ptrdiff_t) base + r->sym); - reldata += addr_imp; - - /* Write the new relocation value back to *reloc_target */ - switch ((r->flags & 0xff)) - { - case 8: - __write_memory ((void *) reloc_target, &reldata, 1); - break; - case 16: - __write_memory ((void *) reloc_target, &reldata, 2); - break; - case 32: - __write_memory ((void *) reloc_target, &reldata, 4); - break; -#ifdef _WIN64 - case 64: - __write_memory ((void *) reloc_target, &reldata, 8); - break; -#endif - } - } -} - -void -_pei386_runtime_relocator (void) -{ - static NO_COPY int was_init = 0; - if (was_init) - return; - ++was_init; - do_pseudo_reloc (&__RUNTIME_PSEUDO_RELOC_LIST__, - &__RUNTIME_PSEUDO_RELOC_LIST_END__, - &__MINGW_LSYMBOL(_image_base__)); -} diff --git a/winsup/cygwin/pseudo-reloc.cc b/winsup/cygwin/pseudo-reloc.cc index 77f041114..290c1a838 100644 --- a/winsup/cygwin/pseudo-reloc.cc +++ b/winsup/cygwin/pseudo-reloc.cc @@ -15,25 +15,23 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. */ -#include +#ifndef __CYGWIN__ +# include "windows.h" +# define NO_COPY +#else +# include "winsup.h" +# include +# include +# include +/* custom status code: */ +# define STATUS_ILLEGAL_DLL_PSEUDO_RELOCATION ((NTSTATUS) 0xe0000269) +#endif + #include #include #include #include -#if defined(__CYGWIN__) -#include -#include -#include -/* copied from winsup.h */ -# define NO_COPY __attribute__((nocommon)) __attribute__((section(".data_cygwin_nocopy"))) -/* custom status code: */ -#define STATUS_ILLEGAL_DLL_PSEUDO_RELOCATION ((NTSTATUS) 0xe0000269) -#define SHORT_MSG_BUF_SZ 128 -#else -# define NO_COPY -#endif - #ifdef __GNUC__ #define ATTRIBUTE_NORETURN __attribute__ ((noreturn)) #else @@ -48,8 +46,6 @@ extern char __RUNTIME_PSEUDO_RELOC_LIST__; extern char __RUNTIME_PSEUDO_RELOC_LIST_END__; extern char __MINGW_LSYMBOL(_image_base__); -void _pei386_runtime_relocator (void); - /* v1 relocation is basically: * *(base + .target) += .addend * where (base + .target) is always assumed to point @@ -90,55 +86,32 @@ __report_error (const char *msg, ...) * normal win32 console IO handles, redirected ones, and * cygwin ptys. */ - char buf[SHORT_MSG_BUF_SZ]; + char buf[128]; wchar_t module[MAX_PATH]; char * posix_module = NULL; - static const char UNKNOWN_MODULE[] = ": "; - static const size_t UNKNOWN_MODULE_LEN = sizeof (UNKNOWN_MODULE) - 1; - static const char CYGWIN_FAILURE_MSG[] = "Cygwin runtime failure: "; - static const size_t CYGWIN_FAILURE_MSG_LEN = sizeof (CYGWIN_FAILURE_MSG) - 1; - DWORD len; - DWORD done; - va_list args; + static const char UNKNOWN_MODULE[] = ": "; + static const char CYGWIN_FAILURE_MSG[] = "Cygwin runtime failure: "; HANDLE errh = GetStdHandle (STD_ERROR_HANDLE); ssize_t modulelen = GetModuleFileNameW (NULL, module, sizeof (module)); + va_list args; + /* FIXME: cleanup further to avoid old use of cygwin_internal */ if (errh == INVALID_HANDLE_VALUE) - cygwin_internal (CW_EXIT_PROCESS, - STATUS_ILLEGAL_DLL_PSEUDO_RELOCATION, - 1); + cygwin_internal (CW_EXIT_PROCESS, STATUS_ILLEGAL_DLL_PSEUDO_RELOCATION, 1); if (modulelen > 0) - posix_module = cygwin_create_path (CCP_WIN_W_TO_POSIX, module); + posix_module = (char *) cygwin_create_path (CCP_WIN_W_TO_POSIX, module); va_start (args, msg); - len = (DWORD) vsnprintf (buf, SHORT_MSG_BUF_SZ, msg, args); + vsnprintf (buf, sizeof (buf), msg, args); va_end (args); - buf[SHORT_MSG_BUF_SZ-1] = '\0'; /* paranoia */ + buf[sizeof (buf) - 1] = '\0'; /* paranoia */ + small_printf ("%s%s: %s\n", CYGWIN_FAILURE_MSG, posix_module ?: UNKNOWN_MODULE, buf); if (posix_module) - { - WriteFile (errh, (PCVOID)CYGWIN_FAILURE_MSG, - CYGWIN_FAILURE_MSG_LEN, &done, NULL); - WriteFile (errh, (PCVOID)posix_module, - strlen(posix_module), &done, NULL); - WriteFile (errh, (PCVOID)": ", 2, &done, NULL); - WriteFile (errh, (PCVOID)buf, len, &done, NULL); - free (posix_module); - } - else - { - WriteFile (errh, (PCVOID)CYGWIN_FAILURE_MSG, - CYGWIN_FAILURE_MSG_LEN, &done, NULL); - WriteFile (errh, (PCVOID)UNKNOWN_MODULE, - UNKNOWN_MODULE_LEN, &done, NULL); - WriteFile (errh, (PCVOID)buf, len, &done, NULL); - } - WriteFile (errh, (PCVOID)"\n", 1, &done, NULL); + free (posix_module); - cygwin_internal (CW_EXIT_PROCESS, - STATUS_ILLEGAL_DLL_PSEUDO_RELOCATION, - 1); + cygwin_internal (CW_EXIT_PROCESS, STATUS_ILLEGAL_DLL_PSEUDO_RELOCATION, 1); /* not reached, but silences noreturn warning */ abort (); #else @@ -177,10 +150,10 @@ __write_memory (void *addr, const void *src, size_t len) if (!len) return; - if (!VirtualQuery (addr, &b, sizeof(b))) + if (!VirtualQuery (addr, &b, sizeof (b))) { __report_error (" VirtualQuery failed for %d bytes at address %p", - (int) sizeof(b), addr); + (int) sizeof (b), addr); } /* Temporarily allow write access to read-only protected memory. */ @@ -259,7 +232,7 @@ do_pseudo_reloc (void * start, void * end, void * base) DWORD newval; reloc_target = (ptrdiff_t) base + o->target; newval = (*((DWORD*) reloc_target)) + o->addend; - __write_memory ((void *) reloc_target, &newval, sizeof(DWORD)); + __write_memory ((void *) reloc_target, &newval, sizeof (DWORD)); } return; } @@ -300,33 +273,33 @@ do_pseudo_reloc (void * start, void * end, void * base) */ switch ((r->flags & 0xff)) { - case 8: - reldata = (ptrdiff_t) (*((unsigned char *)reloc_target)); - if ((reldata & 0x80) != 0) - reldata |= ~((ptrdiff_t) 0xff); - break; - case 16: - reldata = (ptrdiff_t) (*((unsigned short *)reloc_target)); - if ((reldata & 0x8000) != 0) - reldata |= ~((ptrdiff_t) 0xffff); - break; - case 32: - reldata = (ptrdiff_t) (*((unsigned int *)reloc_target)); + case 8: + reldata = (ptrdiff_t) (*((unsigned char *)reloc_target)); + if ((reldata & 0x80) != 0) + reldata |= ~((ptrdiff_t) 0xff); + break; + case 16: + reldata = (ptrdiff_t) (*((unsigned short *)reloc_target)); + if ((reldata & 0x8000) != 0) + reldata |= ~((ptrdiff_t) 0xffff); + break; + case 32: + reldata = (ptrdiff_t) (*((unsigned int *)reloc_target)); #ifdef _WIN64 - if ((reldata & 0x80000000) != 0) - reldata |= ~((ptrdiff_t) 0xffffffff); + if ((reldata & 0x80000000) != 0) + reldata |= ~((ptrdiff_t) 0xffffffff); #endif - break; + break; #ifdef _WIN64 - case 64: - reldata = (ptrdiff_t) (*((unsigned long long *)reloc_target)); - break; + case 64: + reldata = (ptrdiff_t) (*((unsigned long long *)reloc_target)); + break; #endif - default: - reldata=0; - __report_error (" Unknown pseudo relocation bit size %d.\n", - (int) (r->flags & 0xff)); - break; + default: + reldata=0; + __report_error (" Unknown pseudo relocation bit size %d.\n", + (int) (r->flags & 0xff)); + break; } /* Adjust the relocation value */ @@ -336,25 +309,33 @@ do_pseudo_reloc (void * start, void * end, void * base) /* Write the new relocation value back to *reloc_target */ switch ((r->flags & 0xff)) { - case 8: - __write_memory ((void *) reloc_target, &reldata, 1); - break; - case 16: - __write_memory ((void *) reloc_target, &reldata, 2); - break; - case 32: - __write_memory ((void *) reloc_target, &reldata, 4); - break; + case 8: + __write_memory ((void *) reloc_target, &reldata, 1); + break; + case 16: + __write_memory ((void *) reloc_target, &reldata, 2); + break; + case 32: + __write_memory ((void *) reloc_target, &reldata, 4); + break; #ifdef _WIN64 - case 64: - __write_memory ((void *) reloc_target, &reldata, 8); - break; + case 64: + __write_memory ((void *) reloc_target, &reldata, 8); + break; #endif } } } +#ifdef __CYGWIN__ void +_pei386_runtime_relocator (per_process *u) +{ + if (CYGWIN_VERSION_USE_PSEUDO_RELOC_IN_DLL (u)) + do_pseudo_reloc (u->pseudo_reloc_start, u->pseudo_reloc_end, u->image_base); +} +#else +extern "C" void _pei386_runtime_relocator (void) { static NO_COPY int was_init = 0; @@ -365,3 +346,4 @@ _pei386_runtime_relocator (void) &__RUNTIME_PSEUDO_RELOC_LIST_END__, &__MINGW_LSYMBOL(_image_base__)); } +#endif diff --git a/winsup/cygwin/winsup.h b/winsup/cygwin/winsup.h index 7f0377ef8..efcdf6dee 100644 --- a/winsup/cygwin/winsup.h +++ b/winsup/cygwin/winsup.h @@ -179,6 +179,8 @@ int spawn_guts (const char * prog_arg, const char *const *argv, /* dynamically loaded dll initialization */ extern "C" int dll_dllcrt0 (HMODULE, per_process *); +void _pei386_runtime_relocator (per_process *); + /* dynamically loaded dll initialization for non-cygwin apps */ extern "C" int dll_noncygwin_dllcrt0 (HMODULE, per_process *); void __stdcall do_exit (int) __attribute__ ((regparm (1), noreturn)); -- 2.43.5