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> 2009-10-07 Corinna Vinschen <corinna@vinschen.de>
* syscalls.cc (seteuid32): Call set_cygwin_privileges on primary token * syscalls.cc (seteuid32): Call set_cygwin_privileges on primary token

View File

@ -1,6 +1,9 @@
/* pseudo-reloc.c /* 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 SOFTWARE IS NOT COPYRIGHTED
This source code is offered for use in the public domain. You may This source code is offered for use in the public domain. You may
@ -13,33 +16,356 @@
*/ */
#include <windows.h> #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__;
extern char __RUNTIME_PSEUDO_RELOC_LIST_END__; extern char __RUNTIME_PSEUDO_RELOC_LIST_END__;
extern char _image_base__; extern char _image_base__;
typedef struct /* v1 relocation is basically:
{ * *(base + .target) += .addend
DWORD addend; * where (base + .target) is always assumed to point
DWORD target; * to a DWORD (4 bytes).
} */
runtime_pseudo_reloc; typedef struct {
DWORD addend;
DWORD target;
} runtime_pseudo_reloc_item_v1;
void /* v2 relocation is more complex. In effect, it is
do_pseudo_reloc (void* start, void* end, void* base) * *(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; char buf[SHORT_MSG_BUF_SZ];
runtime_pseudo_reloc* r; wchar_t module[MAX_PATH];
for (r = (runtime_pseudo_reloc*) start; r < (runtime_pseudo_reloc*) end; r++) 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; rVal = WriteFile (errh, (PCVOID)posix_module,
*((DWORD*) reloc_target) += r->addend; 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 void
_pei386_runtime_relocator () _pei386_runtime_relocator ()
{ {
static NO_COPY int was_init = 0;
if (was_init)
return;
++was_init;
do_pseudo_reloc (&__RUNTIME_PSEUDO_RELOC_LIST__, do_pseudo_reloc (&__RUNTIME_PSEUDO_RELOC_LIST__,
&__RUNTIME_PSEUDO_RELOC_LIST_END__, &__RUNTIME_PSEUDO_RELOC_LIST_END__,
&_image_base__); &_image_base__);

View File

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

View File

@ -128,6 +128,10 @@ status_exit (DWORD x)
x = 127; x = 127;
} }
break; 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: default:
x = 127; x = 127;
} }

View File

@ -1,6 +1,9 @@
/* pseudo-reloc.c /* 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 SOFTWARE IS NOT COPYRIGHTED
This source code is offered for use in the public domain. You may This source code is offered for use in the public domain. You may
@ -13,33 +16,356 @@
*/ */
#include <windows.h> #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__;
extern char __RUNTIME_PSEUDO_RELOC_LIST_END__; extern char __RUNTIME_PSEUDO_RELOC_LIST_END__;
extern char _image_base__; extern char _image_base__;
typedef struct /* v1 relocation is basically:
{ * *(base + .target) += .addend
DWORD addend; * where (base + .target) is always assumed to point
DWORD target; * to a DWORD (4 bytes).
} */
runtime_pseudo_reloc; typedef struct {
DWORD addend;
DWORD target;
} runtime_pseudo_reloc_item_v1;
void /* v2 relocation is more complex. In effect, it is
do_pseudo_reloc (void* start, void* end, void* base) * *(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; char buf[SHORT_MSG_BUF_SZ];
runtime_pseudo_reloc* r; wchar_t module[MAX_PATH];
for (r = (runtime_pseudo_reloc*) start; r < (runtime_pseudo_reloc*) end; r++) 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; rVal = WriteFile (errh, (PCVOID)posix_module,
*((DWORD*) reloc_target) += r->addend; 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 void
_pei386_runtime_relocator () _pei386_runtime_relocator ()
{ {
static NO_COPY int was_init = 0;
if (was_init)
return;
++was_init;
do_pseudo_reloc (&__RUNTIME_PSEUDO_RELOC_LIST__, do_pseudo_reloc (&__RUNTIME_PSEUDO_RELOC_LIST__,
&__RUNTIME_PSEUDO_RELOC_LIST_END__, &__RUNTIME_PSEUDO_RELOC_LIST_END__,
&_image_base__); &_image_base__);

View File

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