Welcome to mirror list, hosted at ThFree Co, Russian Federation.

cygwin.com/git/newlib-cygwin.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Sutcliffe <ir0nh34d@users.sourceforge.net>2009-03-05 17:48:38 +0300
committerChris Sutcliffe <ir0nh34d@users.sourceforge.net>2009-03-05 17:48:38 +0300
commit6e0e5a4fc20a1de8124c454a5c14c616c68e4653 (patch)
treebfc2339fc99f2be2d96bfabb2f72835d37ac12f9 /winsup/mingw
parent06281845fbd395b232779dbc5213fbfcf6c428d1 (diff)
2009-03-05 Kai Tietz <kai.tietz@onevision.com>
* pseudo-reloc.c: Rewrite to enable pseudo_reloc version 2.
Diffstat (limited to 'winsup/mingw')
-rw-r--r--winsup/mingw/ChangeLog4
-rw-r--r--winsup/mingw/pseudo-reloc.c170
2 files changed, 156 insertions, 18 deletions
diff --git a/winsup/mingw/ChangeLog b/winsup/mingw/ChangeLog
index 1a8d264c7..51d473fe7 100644
--- a/winsup/mingw/ChangeLog
+++ b/winsup/mingw/ChangeLog
@@ -1,3 +1,7 @@
+2009-03-05 Kai Tietz <kai.tietz@onevision.com>
+
+ * pseudo-reloc.c: Rewrite to enable pseudo_reloc version 2.
+
2009-02-08 Keith Marshall <keithmarshall@users.sourceforge.net>
MinGW-Feature-Request [2222263]: Make getopt() GNU / BSD compatibile.
diff --git a/winsup/mingw/pseudo-reloc.c b/winsup/mingw/pseudo-reloc.c
index 9fe607d2c..ea9f37631 100644
--- a/winsup/mingw/pseudo-reloc.c
+++ b/winsup/mingw/pseudo-reloc.c
@@ -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,164 @@
*/
#include <windows.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+ 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_item_v1;
-extern char __RUNTIME_PSEUDO_RELOC_LIST__;
-extern char __RUNTIME_PSEUDO_RELOC_LIST_END__;
-extern char _image_base__;
+typedef struct {
+ DWORD sym;
+ DWORD target;
+ DWORD flags;
+} runtime_pseudo_reloc_item_v2;
-typedef struct
- {
- DWORD addend;
- DWORD target;
- }
-runtime_pseudo_reloc;
+typedef struct {
+ DWORD magic1;
+ DWORD magic2;
+ DWORD version;
+} runtime_pseudo_reloc_v2;
static void
-do_pseudo_reloc (void* start, void* end, void* base)
+__write_memory (void *addr,const void *src,size_t len)
{
- DWORD reloc_target;
- runtime_pseudo_reloc* r;
- for (r = (runtime_pseudo_reloc*) start; r < (runtime_pseudo_reloc*) end; r++)
+ MEMORY_BASIC_INFORMATION b;
+ DWORD oldprot;
+ if (!len)
+ return;
+ assert (VirtualQuery (addr, &b, sizeof(b)));
+ /* 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);
+ memcpy (addr, src, len);
+ 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;
+
+ 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)
{
- reloc_target = (DWORD) base + r->target;
- *((DWORD*) reloc_target) += r->addend;
+ 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;
}
-}
+ /* Check if this is a known version. */
+ if (v2_hdr->version != RP_VERSION_V2)
+ {
+#ifdef DEBUG
+ fprintf (stderr, "internal mingw runtime error:"
+ "psuedo_reloc version %d is unknown to this runtime.\n",
+ (int) v2_hdr->version);
+#endif
+ return;
+ }
+
+ /* Walk over header. */
+ r = (runtime_pseudo_reloc_item_v2 *) &v2_hdr[1];
+
+ for (; r < (runtime_pseudo_reloc_item_v2 *) end; r++)
+ {
+ reloc_target = (ptrdiff_t) base + r->target;
+ 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;
+#ifdef DEBUG
+ fprintf(stderr, "internal mingw runtime error: "
+ "unknown pseudo_reloc bit size %d\n",
+ (int) (r->flags & 0xff));
+#endif
+ break;
+ }
+ reldata -= ((ptrdiff_t) base + r->sym);
+ reldata += addr_imp;
+ 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 ()
+ _pei386_runtime_relocator ()
{
+ static int was_init = 0;
+ if (was_init)
+ return;
+ ++was_init;
do_pseudo_reloc (&__RUNTIME_PSEUDO_RELOC_LIST__,
&__RUNTIME_PSEUDO_RELOC_LIST_END__,
&_image_base__);