OSDN Git Service

2009-03-05 Kai Tietz <kai.tietz@onevision.com>
authorironhead <ironhead>
Thu, 5 Mar 2009 14:48:38 +0000 (14:48 +0000)
committerironhead <ironhead>
Thu, 5 Mar 2009 14:48:38 +0000 (14:48 +0000)
        * pseudo-reloc.c: Rewrite to enable pseudo_reloc version 2.

winsup/mingw/ChangeLog
winsup/mingw/pseudo-reloc.c

index 1a8d264..51d473f 100644 (file)
@@ -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.
index 9fe607d..ea9f376 100644 (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
 */
 
 #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__);