* 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.
This commit is contained in:
parent
186bcf2a17
commit
27f564e9a3
|
@ -1,3 +1,38 @@
|
|||
2010-05-07 Christopher Faylor <me+cygwin@cgf.cx>
|
||||
|
||||
* 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 <corinna@vinschen.de>
|
||||
|
||||
* fhandler_tty.cc (fhandler_tty_slave::init): Disable grabbing
|
||||
|
|
|
@ -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=,\
|
||||
|
|
|
@ -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 ();
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
/* pseudo-reloc.c
|
||||
|
||||
Stub for older binaries.
|
||||
*/
|
||||
|
||||
void
|
||||
_pei386_runtime_relocator ()
|
||||
{
|
||||
return;
|
||||
}
|
|
@ -1,367 +0,0 @@
|
|||
/* pseudo-reloc.c
|
||||
|
||||
Contributed by Egor Duda <deo@logos-m.ru>
|
||||
Modified by addition of runtime_pseudo_reloc version 2
|
||||
by Kai Tietz <kai.tietz@onevision.com>
|
||||
|
||||
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 <windows.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <memory.h>
|
||||
|
||||
#if defined(__CYGWIN__)
|
||||
#include <wchar.h>
|
||||
#include <ntdef.h>
|
||||
#include <sys/cygwin.h>
|
||||
/* 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[] = "<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__));
|
||||
}
|
|
@ -15,25 +15,23 @@
|
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*/
|
||||
|
||||
#include <windows.h>
|
||||
#ifndef __CYGWIN__
|
||||
# include "windows.h"
|
||||
# define NO_COPY
|
||||
#else
|
||||
# include "winsup.h"
|
||||
# include <wchar.h>
|
||||
# include <ntdef.h>
|
||||
# include <sys/cygwin.h>
|
||||
/* custom status code: */
|
||||
# define STATUS_ILLEGAL_DLL_PSEUDO_RELOCATION ((NTSTATUS) 0xe0000269)
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <memory.h>
|
||||
|
||||
#if defined(__CYGWIN__)
|
||||
#include <wchar.h>
|
||||
#include <ntdef.h>
|
||||
#include <sys/cygwin.h>
|
||||
/* 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[] = "<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[] = "<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
|
||||
|
|
|
@ -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));
|
||||
|
|
Loading…
Reference in New Issue