CVS: winex/memory virtual.c,1.38,1.39

[email protected] 31 Jul 2007 19:49:41 -0000
Newsgroups gmane.comp.emulators.winex.cvs
Message-ID <[email protected]>
Subject: winex/memory virtual.c,1.38,1.39Update of /var/lib/cvsd/cvsroot/winex/memory
In directory agravaine:/tmp/cvs-serv918/memory

Modified Files:
	virtual.c 
Log Message:

- modify segment permissions to allow import fixups to be done
- do relocations prior to setting segment permissions


Index: virtual.c
===================================================================
RCS file: /var/lib/cvsd/cvsroot/winex/memory/virtual.c,v
retrieving revision 1.38
retrieving revision 1.39
diff -u -d -r1.38 -r1.39
--- virtual.c	31 Jul 2007 19:49:15 -0000	1.38
+++ virtual.c	31 Jul 2007 19:49:39 -0000	1.39
@@ -791,6 +791,89 @@
 
 
 /***********************************************************************
+ *           do_relocations
+ *
+ * Apply the relocations to a mapped PE image
+ */
+static int do_relocations( char *base, const IMAGE_NT_HEADERS *nt )
+{
+    const IMAGE_DATA_DIRECTORY *dir;
+    const IMAGE_BASE_RELOCATION *rel;
+    int delta = base - (char *)nt->OptionalHeader.ImageBase;
+
+    dir = &nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
+    rel = (IMAGE_BASE_RELOCATION *)(base + dir->VirtualAddress);
+
+    WARN_(module)("Info: base relocations needed\n");
+    if (!dir->VirtualAddress || !dir->Size)
+    {
+        if (nt->OptionalHeader.ImageBase == 0x400000)
+            ERR("Standard load address for a Win32 program (0x00400000) not available - security-patched kernel ?\n");
+        ERR( "FATAL: Need to relocate, but no relocation records present (%s). Try to run the file directly !\n",
+             (nt->FileHeader.Characteristics&IMAGE_FILE_RELOCS_STRIPPED)?
+             "stripped during link" : "unknown reason" );
+        return 0;
+    }
+
+    /* FIXME: If we need to relocate a system DLL (base > 2GB) we should
+     *        really make sure that the *new* base address is also > 2GB.
+     *        Some DLLs really check the MSB of the module handle :-/
+     */
+    if ((nt->OptionalHeader.ImageBase & 0x80000000) && !((DWORD)base & 0x80000000))
+        ERR( "Forced to relocate system DLL (base > 2GB). This is not good.\n" );
+
+    for ( ; ((char *)rel < base + dir->VirtualAddress + dir->Size) && rel->SizeOfBlock;
+          rel = (IMAGE_BASE_RELOCATION*)((char*)rel + rel->SizeOfBlock))
+    {
+        char *page = base + rel->VirtualAddress;
+        WORD *TypeOffset = (WORD *)(rel + 1);
+        int i, count = (rel->SizeOfBlock - sizeof(*rel)) / sizeof(*TypeOffset);
+
+        TRACE_(module) ("Count: %d\n", count);
+        if (!count) continue;
+
+        /* sanity checks */
+        if ((char *)rel + rel->SizeOfBlock > base + dir->VirtualAddress + dir->Size ||
+            page > base + nt->OptionalHeader.SizeOfImage)
+        {
+            ERR_(module)("invalid relocation %p,%lx,%ld at %p,%lx,%lx\n",
+                         rel, rel->VirtualAddress, rel->SizeOfBlock,
+                         base, dir->VirtualAddress, dir->Size );
+            return 0;
+        }
+
+        TRACE_(module)("%ld relocations for page %lx\n", rel->SizeOfBlock, rel->VirtualAddress);
+
+        /* patching in reverse order */
+        for (i = 0 ; i < count; i++)
+        {
+            int offset = TypeOffset[i] & 0xFFF;
+            int type = TypeOffset[i] >> 12;
+            switch(type)
+            {
+            case IMAGE_REL_BASED_ABSOLUTE:
+                break;
+            case IMAGE_REL_BASED_HIGH:
+                *(short*)(page+offset) += HIWORD(delta);
+                break;
+            case IMAGE_REL_BASED_LOW:
+                *(short*)(page+offset) += LOWORD(delta);
+                break;
+            case IMAGE_REL_BASED_HIGHLOW:
+                *(int*)(page+offset) += delta;
+                /* FIXME: if this is an exported address, fire up enhanced logic */
+                break;
+            default:
+                FIXME_(module)("Unknown/unsupported fixup type %d.\n", type);
+                break;
+            }
+        }
+    }
+    return 1;
+}
+
+
+/***********************************************************************
  *           map_image
  *
  * Map an executable (PE format) image into memory.
@@ -947,6 +1030,10 @@
         }
     }
 
+    /* Do relocations if necessary */
+    if (ptr != base)
+       do_relocations (ptr, nt);
+
     /* Set the protection on the PE header READONLY rather than what we just set when we created the view */
     VIRTUAL_SetProt( view, ptr, header_size, VPROT_READ|VPROT_COMMITTED );