Support pseudo-reloc version 2

This commit is contained in:
Charles Wilson 2009-10-07 15:47:38 +00:00
parent dfbf36f8db
commit dc4e4aabba
6 changed files with 717 additions and 28 deletions

View File

@ -1,3 +1,32 @@
2009-10-07 Charles Wilson <cygwin@cwilson.fastmail.fm>
Additional pseudo-reloc-v2 support
* ntdll.h: Add custom NTSTATUS value for pseudo-reloc
errors STATUS_ILLEGAL_DLL_PSEUDO_RELOCATION.
* pinfo.cc (status_exit): Map custom pseudo-reloc
error value STATUS_ILLEGAL_DLL_PSEUDO_RELOCATION to 127.
* sigproc.cc (child_info::proc_retry): Return exit code when
STATUS_ILLEGAL_DLL_PSEUDO_RELOCATION.
Cygwin modifications to pseudo-reloc.c
* lib/pseudo-reloc.c: Added comments throughout and various
whitespace fixes. Exploit cygwin_internal(CW_EXIT_PROCESS,...)
for fatal error handling that is consistent with cygwin process
life-cycle. Ensure state variable (in _pei386_runtime_relocator)
is unique to each address space, across fork().
(__print_reloc_error): New function for reporting errors in a
manner supported by cygwin at this early stage of the process
life-cycle.
(_pei386_runtime_relocator): Ensure relocations performed
only once for each address space, but are repeated after fork()
in the new address space.
only once for each address space (e.g. across fork()).
(__write_memory) [MINGW]: Ensure that b is always initialized
by call to VirtualQuery, even if -DNDEBUG.
* lib/pseudo-reloc.c: Import new implementation to support
v2 pseudo-relocs implemented by Kai Tietz from mingw.
2009-10-07 Corinna Vinschen <corinna@vinschen.de>
* syscalls.cc (seteuid32): Call set_cygwin_privileges on primary token

View File

@ -1,6 +1,9 @@
/* pseudo-reloc.c
Written by Egor Duda <deo@logos-m.ru>
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
@ -13,33 +16,356 @@
*/
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#if defined(__CYGWIN__)
#include <wchar.h>
#include <ntdef.h>
#include <stdarg.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)
#else
# define NO_COPY
#endif
extern char __RUNTIME_PSEUDO_RELOC_LIST__;
extern char __RUNTIME_PSEUDO_RELOC_LIST_END__;
extern char _image_base__;
typedef struct
{
DWORD addend;
DWORD target;
}
runtime_pseudo_reloc;
/* 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;
void
do_pseudo_reloc (void* start, void* end, void* base)
/* 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;
#if defined(__CYGWIN__)
#define SHORT_MSG_BUF_SZ 128
/* 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.
*/
static BOOL
__print_reloc_error (const char *fmt, ...)
{
DWORD reloc_target;
runtime_pseudo_reloc* r;
for (r = (runtime_pseudo_reloc*) start; r < (runtime_pseudo_reloc*) end; r++)
char buf[SHORT_MSG_BUF_SZ];
wchar_t module[MAX_PATH];
char * posix_module = NULL;
BOOL rVal = FALSE;
static const char * UNKNOWN_MODULE = "<unknown module>: ";
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)
return FALSE;
if (modulelen > 0)
posix_module = cygwin_create_path (CCP_WIN_W_TO_POSIX, module);
va_start (args, fmt);
len = (DWORD) vsnprintf (buf, SHORT_MSG_BUF_SZ, fmt, args);
va_end (args);
buf[SHORT_MSG_BUF_SZ-1] = '\0'; /* paranoia */
if (posix_module)
{
reloc_target = (DWORD) base + r->target;
*((DWORD*) reloc_target) += r->addend;
rVal = 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
{
rVal = WriteFile (errh, (PCVOID)UNKNOWN_MODULE,
sizeof(UNKNOWN_MODULE), &done, NULL) &&
WriteFile (errh, (PCVOID)buf, len, &done, NULL);
}
return rVal;
}
#endif /* __CYGWIN__ */
/* 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;
SIZE_T memsz;
if (!len)
return;
memsz = VirtualQuery (addr, &b, sizeof(b));
#if defined(__CYGWIN__)
/* CYGWIN: If error, print error message and die. */
if (memsz == 0)
{
__print_reloc_error (
"error while loading shared libraries: bad address specified 0x%08x.\n",
addr);
cygwin_internal (CW_EXIT_PROCESS,
STATUS_ILLEGAL_DLL_PSEUDO_RELOCATION,
1);
}
#else
/* MINGW: If error, die. assert() may print error message when !NDEBUG */
assert (memsz);
#endif
/* 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)
{
#if defined(__CYGWIN__)
/* CYGWIN: Print error message and die, even when !DEBUGGING */
__print_reloc_error (
"error while loading shared libraries: invalid pseudo_reloc version %d.\n",
(int) v2_hdr->version);
cygwin_internal (CW_EXIT_PROCESS,
STATUS_ILLEGAL_DLL_PSEUDO_RELOCATION,
1);
#else
# if defined(DEBUG)
/* MINGW: Don't die; just return to caller. If DEBUG, print error message. */
fprintf (stderr, "internal mingw runtime error:"
"psuedo_reloc version %d is unknown to this runtime.\n",
(int) v2_hdr->version);
# endif
#endif
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;
#if defined(__CYGWIN__)
/* Print error message and die, even when !DEBUGGING */
__print_reloc_error (
"error while loading shared libraries: unknown pseudo_reloc bit size %d.\n",
(int) (r->flags & 0xff));
cygwin_internal (CW_EXIT_PROCESS,
STATUS_ILLEGAL_DLL_PSEUDO_RELOCATION,
1);
#else
# ifdef DEBUG
/* MINGW: If error, don't die; just print message if DEBUG */
fprintf(stderr, "internal mingw runtime error: "
"unknown pseudo_reloc bit size %d\n",
(int) (r->flags & 0xff));
# endif
#endif
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 ()
{
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__,
&_image_base__);

View File

@ -46,6 +46,8 @@
#define STATUS_ENTRYPOINT_NOT_FOUND ((NTSTATUS) 0xc0000139)
#define STATUS_BAD_DLL_ENTRYPOINT ((NTSTATUS) 0xc0000251)
#define STATUS_ILLEGAL_DLL_RELOCATION ((NTSTATUS) 0xc0000269)
/* custom status code: */
#define STATUS_ILLEGAL_DLL_PSEUDO_RELOCATION ((NTSTATUS) 0xe0000269)
#define PDI_MODULES 0x01
#define PDI_HEAPS 0x04

View File

@ -128,6 +128,10 @@ status_exit (DWORD x)
x = 127;
}
break;
case STATUS_ILLEGAL_DLL_PSEUDO_RELOCATION: /* custom error value */
/* We've already printed the error message in pseudo-reloc.c */
x = 127;
break;
default:
x = 127;
}

View File

@ -1,6 +1,9 @@
/* pseudo-reloc.c
Written by Egor Duda <deo@logos-m.ru>
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
@ -13,33 +16,356 @@
*/
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#if defined(__CYGWIN__)
#include <wchar.h>
#include <ntdef.h>
#include <stdarg.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)
#else
# define NO_COPY
#endif
extern char __RUNTIME_PSEUDO_RELOC_LIST__;
extern char __RUNTIME_PSEUDO_RELOC_LIST_END__;
extern char _image_base__;
typedef struct
{
DWORD addend;
DWORD target;
}
runtime_pseudo_reloc;
/* 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;
void
do_pseudo_reloc (void* start, void* end, void* base)
/* 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;
#if defined(__CYGWIN__)
#define SHORT_MSG_BUF_SZ 128
/* 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.
*/
static BOOL
__print_reloc_error (const char *fmt, ...)
{
DWORD reloc_target;
runtime_pseudo_reloc* r;
for (r = (runtime_pseudo_reloc*) start; r < (runtime_pseudo_reloc*) end; r++)
char buf[SHORT_MSG_BUF_SZ];
wchar_t module[MAX_PATH];
char * posix_module = NULL;
BOOL rVal = FALSE;
static const char * UNKNOWN_MODULE = "<unknown module>: ";
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)
return FALSE;
if (modulelen > 0)
posix_module = cygwin_create_path (CCP_WIN_W_TO_POSIX, module);
va_start (args, fmt);
len = (DWORD) vsnprintf (buf, SHORT_MSG_BUF_SZ, fmt, args);
va_end (args);
buf[SHORT_MSG_BUF_SZ-1] = '\0'; /* paranoia */
if (posix_module)
{
reloc_target = (DWORD) base + r->target;
*((DWORD*) reloc_target) += r->addend;
rVal = 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
{
rVal = WriteFile (errh, (PCVOID)UNKNOWN_MODULE,
sizeof(UNKNOWN_MODULE), &done, NULL) &&
WriteFile (errh, (PCVOID)buf, len, &done, NULL);
}
return rVal;
}
#endif /* __CYGWIN__ */
/* 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;
SIZE_T memsz;
if (!len)
return;
memsz = VirtualQuery (addr, &b, sizeof(b));
#if defined(__CYGWIN__)
/* CYGWIN: If error, print error message and die. */
if (memsz == 0)
{
__print_reloc_error (
"error while loading shared libraries: bad address specified 0x%08x.\n",
addr);
cygwin_internal (CW_EXIT_PROCESS,
STATUS_ILLEGAL_DLL_PSEUDO_RELOCATION,
1);
}
#else
/* MINGW: If error, die. assert() may print error message when !NDEBUG */
assert (memsz);
#endif
/* 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)
{
#if defined(__CYGWIN__)
/* CYGWIN: Print error message and die, even when !DEBUGGING */
__print_reloc_error (
"error while loading shared libraries: invalid pseudo_reloc version %d.\n",
(int) v2_hdr->version);
cygwin_internal (CW_EXIT_PROCESS,
STATUS_ILLEGAL_DLL_PSEUDO_RELOCATION,
1);
#else
# if defined(DEBUG)
/* MINGW: Don't die; just return to caller. If DEBUG, print error message. */
fprintf (stderr, "internal mingw runtime error:"
"psuedo_reloc version %d is unknown to this runtime.\n",
(int) v2_hdr->version);
# endif
#endif
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;
#if defined(__CYGWIN__)
/* Print error message and die, even when !DEBUGGING */
__print_reloc_error (
"error while loading shared libraries: unknown pseudo_reloc bit size %d.\n",
(int) (r->flags & 0xff));
cygwin_internal (CW_EXIT_PROCESS,
STATUS_ILLEGAL_DLL_PSEUDO_RELOCATION,
1);
#else
# ifdef DEBUG
/* MINGW: If error, don't die; just print message if DEBUG */
fprintf(stderr, "internal mingw runtime error: "
"unknown pseudo_reloc bit size %d\n",
(int) (r->flags & 0xff));
# endif
#endif
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 ()
{
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__,
&_image_base__);

View File

@ -923,6 +923,8 @@ child_info::proc_retry (HANDLE h)
break;
case STATUS_DLL_NOT_FOUND:
return exit_code;
case STATUS_ILLEGAL_DLL_PSEUDO_RELOCATION: /* pseudo-reloc.c specific */
return exit_code;
case STATUS_CONTROL_C_EXIT:
if (saw_ctrl_c ())
return EXITCODE_OK;