2009-03-14 00:50:23 +00:00
|
|
|
/**
|
|
|
|
* This file has no copyright assigned and is placed in the Public Domain.
|
|
|
|
* This file is part of the w64 mingw-runtime package.
|
|
|
|
* No warranty is given; refer to the file DISCLAIMER within this package.
|
|
|
|
*/
|
|
|
|
|
2006-09-06 20:00:41 +00:00
|
|
|
#include <windows.h>
|
2008-12-13 21:28:05 +00:00
|
|
|
#include <stdio.h>
|
2009-03-14 00:50:23 +00:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <memory.h>
|
2006-09-06 20:00:41 +00:00
|
|
|
|
|
|
|
extern char __RUNTIME_PSEUDO_RELOC_LIST__;
|
|
|
|
extern char __RUNTIME_PSEUDO_RELOC_LIST_END__;
|
|
|
|
extern char _image_base__;
|
|
|
|
|
2008-12-13 21:28:05 +00:00
|
|
|
typedef struct {
|
|
|
|
DWORD addend;
|
|
|
|
DWORD target;
|
|
|
|
} runtime_pseudo_reloc_item_v1;
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
2009-03-14 00:50:23 +00:00
|
|
|
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)))
|
|
|
|
abort ();
|
|
|
|
// Protect
|
|
|
|
if (b.Protect != PAGE_EXECUTE_READWRITE && b.Protect != PAGE_READWRITE)
|
|
|
|
VirtualProtect (b.BaseAddress, b.RegionSize, PAGE_EXECUTE_READWRITE,
|
|
|
|
&oldprot);
|
|
|
|
memcpy (addr, src, len);
|
|
|
|
if (b.Protect != PAGE_EXECUTE_READWRITE && b.Protect != PAGE_READWRITE)
|
|
|
|
VirtualProtect (b.BaseAddress, b.RegionSize, oldprot, &oldprot);
|
|
|
|
}
|
|
|
|
|
2008-12-13 21:28:05 +00:00
|
|
|
#define RP_VERSION_V1 0
|
|
|
|
#define RP_VERSION_V2 1
|
2006-09-06 20:00:41 +00:00
|
|
|
|
|
|
|
static void
|
2008-12-13 21:28:05 +00:00
|
|
|
do_pseudo_reloc (void* start,void *end,void *base)
|
2006-09-06 20:00:41 +00:00
|
|
|
{
|
2008-12-13 21:28:05 +00:00
|
|
|
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;
|
|
|
|
|
|
|
|
if (reloc_target < 8)
|
|
|
|
return;
|
|
|
|
/* Check if this is old version pseudo relocation version. */
|
|
|
|
if (reloc_target >= 12
|
|
|
|
&& v2_hdr->magic1 == 0 && v2_hdr->magic2 == 0
|
|
|
|
&& v2_hdr->version == RP_VERSION_V1)
|
|
|
|
v2_hdr++;
|
|
|
|
if (v2_hdr->magic1 != 0 || v2_hdr->magic2 != 0)
|
|
|
|
{
|
|
|
|
runtime_pseudo_reloc_item_v1 *o;
|
|
|
|
for (o = (runtime_pseudo_reloc_item_v1 *) v2_hdr; o < (runtime_pseudo_reloc_item_v1 *)end; o++)
|
|
|
|
{
|
2009-03-14 00:50:23 +00:00
|
|
|
DWORD newval;
|
2008-12-13 21:28:05 +00:00
|
|
|
reloc_target = (ptrdiff_t) base + o->target;
|
2009-03-14 00:50:23 +00:00
|
|
|
newval = (*((DWORD*) reloc_target)) + o->addend;
|
|
|
|
__write_memory ((void *) reloc_target, &newval, sizeof(DWORD));
|
2008-12-13 21:28:05 +00:00
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
/* Check if this is a known version. */
|
|
|
|
if (v2_hdr->version != RP_VERSION_V2)
|
|
|
|
{
|
|
|
|
fprintf (stderr, "pseudo_relocation protocol version %d is unknown to this runtime.\n",
|
|
|
|
(int) v2_hdr->version);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
/* Walk over header. */
|
|
|
|
r = (runtime_pseudo_reloc_item_v2 *) &v2_hdr[1];
|
|
|
|
|
|
|
|
for (; r < (runtime_pseudo_reloc_item_v2 *) end; r++)
|
2006-09-06 20:00:41 +00:00
|
|
|
{
|
2008-08-27 03:59:24 +00:00
|
|
|
reloc_target = (ptrdiff_t) base + r->target;
|
2008-12-13 21:28:05 +00:00
|
|
|
addr_imp = (ptrdiff_t) base + r->sym;
|
|
|
|
addr_imp = *((ptrdiff_t *) addr_imp);
|
|
|
|
|
|
|
|
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;
|
|
|
|
fprintf(stderr, "Unknown pseudo relocation bit size %d\n",(int) (r->flags & 0xff));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
reldata -= ((ptrdiff_t) base + r->sym);
|
|
|
|
reldata += addr_imp;
|
|
|
|
switch ((r->flags & 0xff))
|
|
|
|
{
|
|
|
|
case 8:
|
2009-03-14 00:50:23 +00:00
|
|
|
__write_memory ((void *) reloc_target, &reldata, 1);
|
2008-12-13 21:28:05 +00:00
|
|
|
break;
|
|
|
|
case 16:
|
2009-03-14 00:50:23 +00:00
|
|
|
__write_memory ((void *) reloc_target, &reldata, 2);
|
2008-12-13 21:28:05 +00:00
|
|
|
break;
|
|
|
|
case 32:
|
2009-03-14 00:50:23 +00:00
|
|
|
__write_memory ((void *) reloc_target, &reldata, 4);
|
2008-12-13 21:28:05 +00:00
|
|
|
break;
|
|
|
|
#ifdef _WIN64
|
|
|
|
case 64:
|
2009-03-14 00:50:23 +00:00
|
|
|
__write_memory ((void *) reloc_target, &reldata, 8);
|
2008-12-13 21:28:05 +00:00
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
}
|
2006-09-06 20:00:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
_pei386_runtime_relocator ()
|
|
|
|
{
|
2009-03-14 00:50:23 +00:00
|
|
|
static int was_init = 0;
|
|
|
|
if (was_init)
|
|
|
|
return;
|
|
|
|
++was_init;
|
2008-12-13 21:28:05 +00:00
|
|
|
do_pseudo_reloc (&__RUNTIME_PSEUDO_RELOC_LIST__,&__RUNTIME_PSEUDO_RELOC_LIST_END__,&_image_base__);
|
2006-09-06 20:00:41 +00:00
|
|
|
}
|