ntdll: Separate image relocation from NtMapViewOfSection.

Dmitry Timoshkov dmitry at baikal.ru
Tue Feb 21 03:40:52 CST 2012


This patch fixes the problem reported in the bug 29899.
---
 dlls/kernel32/tests/loader.c |   12 +-----
 dlls/ntdll/loader.c          |   84 +++++++++++++++++++++++++++++++++++++++++-
 dlls/ntdll/virtual.c         |   44 +---------------------
 3 files changed, 85 insertions(+), 55 deletions(-)

diff --git a/dlls/kernel32/tests/loader.c b/dlls/kernel32/tests/loader.c
index 9c969c2..e25e6d3 100644
--- a/dlls/kernel32/tests/loader.c
+++ b/dlls/kernel32/tests/loader.c
@@ -606,18 +606,8 @@ static void test_image_mapping(const char *dll_name, DWORD scn_page_access)
     size = 0;
     status = pNtMapViewOfSection(hmap, GetCurrentProcess(), &addr2, 0, 0, &offset,
                                  &size, 1 /* ViewShare */, 0, PAGE_READONLY);
-    /* FIXME: remove once Wine is fixed */
-    if (status != STATUS_IMAGE_NOT_AT_BASE)
-    {
-        todo_wine {
-        ok(status == STATUS_IMAGE_NOT_AT_BASE, "expected STATUS_IMAGE_NOT_AT_BASE, got %x\n", status);
-        ok(addr2 != 0, "mapped address should be valid\n");
-        }
-        goto wine_is_broken;
-    }
     ok(status == STATUS_IMAGE_NOT_AT_BASE, "expected STATUS_IMAGE_NOT_AT_BASE, got %x\n", status);
     ok(addr2 != 0, "mapped address should be valid\n");
-
     ok(addr2 != addr1, "mapped addresses should be different\n");
 
     SetLastError(0xdeadbeef);
@@ -635,6 +625,7 @@ static void test_image_mapping(const char *dll_name, DWORD scn_page_access)
     ok(status == STATUS_SUCCESS, "NtUnmapViewOfSection error %x\n", status);
 
     addr2 = MapViewOfFile(hmap, 0, 0, 0, 0);
+    ok(addr2 != 0, "mapped address should be valid\n");
     ok(addr2 != addr1, "mapped addresses should be different\n");
 
     SetLastError(0xdeadbeef);
@@ -650,7 +641,6 @@ static void test_image_mapping(const char *dll_name, DWORD scn_page_access)
 
     UnmapViewOfFile(addr2);
 
-wine_is_broken:
     status = pNtUnmapViewOfSection(GetCurrentProcess(), addr1);
     ok(status == STATUS_SUCCESS, "NtUnmapViewOfSection error %x\n", status);
 
diff --git a/dlls/ntdll/loader.c b/dlls/ntdll/loader.c
index 381e2ac..1d7f108 100644
--- a/dlls/ntdll/loader.c
+++ b/dlls/ntdll/loader.c
@@ -1467,6 +1467,85 @@ static void load_builtin_callback( void *module, const char *filename )
     if (TRACE_ON(relay)) RELAY_SetupDLL( module );
 }
 
+static NTSTATUS perform_relocations( void *module )
+{
+    IMAGE_NT_HEADERS *nt;
+    char *base;
+    IMAGE_BASE_RELOCATION *rel, *end;
+    const IMAGE_DATA_DIRECTORY *relocs;
+    const IMAGE_SECTION_HEADER *sec;
+    INT_PTR delta;
+    SIZE_T total_size;
+    ULONG *protect_old, i;
+
+    nt = RtlImageNtHeader( module );
+    base = (char *)nt->OptionalHeader.ImageBase;
+
+    assert(module != base);
+
+    if (nt->FileHeader.Characteristics & IMAGE_FILE_RELOCS_STRIPPED)
+    {
+        WARN( "Need to relocate module from %p to %p, but there are no relocation records\n",
+              base, module );
+        return STATUS_CONFLICTING_ADDRESSES;
+    }
+
+    protect_old = RtlAllocateHeap( GetProcessHeap(), 0, nt->FileHeader.NumberOfSections * sizeof(*protect_old) );
+    if (!protect_old) return STATUS_NO_MEMORY;
+
+    sec = (const IMAGE_SECTION_HEADER *)((const char *)&nt->OptionalHeader +
+                                        nt->FileHeader.SizeOfOptionalHeader);
+    for (i = 0; i < nt->FileHeader.NumberOfSections; i++)
+    {
+        void *addr = get_rva( module, sec[i].VirtualAddress );
+        total_size = sec[i].SizeOfRawData;
+        NtProtectVirtualMemory( NtCurrentProcess(), &addr,
+                                &total_size, PAGE_READWRITE, &protect_old[i] );
+    }
+
+    total_size = nt->OptionalHeader.SizeOfImage;
+    TRACE( "relocating from %p-%p to %p-%p\n",
+           base, base + total_size, module, (char *)module + total_size );
+
+    relocs = &nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
+    if (!relocs->VirtualAddress || !relocs->Size)
+    {
+        RtlFreeHeap( GetProcessHeap(), 0, protect_old );
+        return STATUS_INVALID_IMAGE_FORMAT;
+    }
+    rel = (IMAGE_BASE_RELOCATION *)((char *)module + relocs->VirtualAddress);
+    end = (IMAGE_BASE_RELOCATION *)((char *)module + relocs->VirtualAddress + relocs->Size);
+    delta = (char *)module - base;
+
+    while (rel < end - 1 && rel->SizeOfBlock)
+    {
+        if (rel->VirtualAddress >= total_size)
+        {
+            WARN( "invalid address %p in relocation %p\n", (char *)module + rel->VirtualAddress, rel );
+            return STATUS_ACCESS_VIOLATION;
+        }
+        rel = LdrProcessRelocationBlock( (char *)module + rel->VirtualAddress,
+                                         (rel->SizeOfBlock - sizeof(*rel)) / sizeof(USHORT),
+                                         (USHORT *)(rel + 1), delta );
+        if (!rel)
+        {
+            RtlFreeHeap( GetProcessHeap(), 0, protect_old );
+            return STATUS_INVALID_IMAGE_FORMAT;
+        }
+    }
+
+    for (i = 0; i < nt->FileHeader.NumberOfSections; i++)
+    {
+        void *addr = get_rva( module, sec[i].VirtualAddress );
+        total_size = sec[i].SizeOfRawData;
+        NtProtectVirtualMemory( NtCurrentProcess(), &addr,
+                                &total_size, protect_old[i], NULL );
+    }
+
+    RtlFreeHeap( GetProcessHeap(), 0, protect_old );
+
+    return STATUS_SUCCESS;
+}
 
 /******************************************************************************
  *	load_native_dll  (internal)
@@ -1492,7 +1571,10 @@ static NTSTATUS load_native_dll( LPCWSTR load_path, LPCWSTR name, HANDLE file,
     module = NULL;
     status = NtMapViewOfSection( mapping, NtCurrentProcess(),
                                  &module, 0, 0, &size, &len, ViewShare, 0, PAGE_EXECUTE_READ );
-    if (status < 0) goto done;
+    /* perform base relocation, if necessary */
+    if (status == STATUS_IMAGE_NOT_AT_BASE)
+        status = perform_relocations( module );
+    if (status != STATUS_SUCCESS) goto done;
 
     /* create the MODREF */
 
diff --git a/dlls/ntdll/virtual.c b/dlls/ntdll/virtual.c
index 717917d..e7c656a 100644
--- a/dlls/ntdll/virtual.c
+++ b/dlls/ntdll/virtual.c
@@ -1131,7 +1131,6 @@ static NTSTATUS map_image( HANDLE hmapping, int fd, char *base, SIZE_T total_siz
     struct stat st;
     struct file_view *view = NULL;
     char *ptr, *header_end;
-    INT_PTR delta = 0;
 
     /* zero-map the whole range */
 
@@ -1293,47 +1292,6 @@ static NTSTATUS map_image( HANDLE hmapping, int fd, char *base, SIZE_T total_siz
         }
     }
 
-
-    /* perform base relocation, if necessary */
-
-    if (ptr != base &&
-        ((nt->FileHeader.Characteristics & IMAGE_FILE_DLL) ||
-          !NtCurrentTeb()->Peb->ImageBaseAddress) )
-    {
-        IMAGE_BASE_RELOCATION *rel, *end;
-        const IMAGE_DATA_DIRECTORY *relocs;
-
-        if (nt->FileHeader.Characteristics & IMAGE_FILE_RELOCS_STRIPPED)
-        {
-            WARN_(module)( "Need to relocate module from %p to %p, but there are no relocation records\n",
-                           base, ptr );
-            status = STATUS_CONFLICTING_ADDRESSES;
-            goto error;
-        }
-
-        TRACE_(module)( "relocating from %p-%p to %p-%p\n",
-                        base, base + total_size, ptr, ptr + total_size );
-
-        relocs = &nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
-        rel = (IMAGE_BASE_RELOCATION *)(ptr + relocs->VirtualAddress);
-        end = (IMAGE_BASE_RELOCATION *)(ptr + relocs->VirtualAddress + relocs->Size);
-        delta = ptr - base;
-
-        while (rel < end - 1 && rel->SizeOfBlock)
-        {
-            if (rel->VirtualAddress >= total_size)
-            {
-                WARN_(module)( "invalid address %p in relocation %p\n", ptr + rel->VirtualAddress, rel );
-                status = STATUS_ACCESS_VIOLATION;
-                goto error;
-            }
-            rel = LdrProcessRelocationBlock( ptr + rel->VirtualAddress,
-                                             (rel->SizeOfBlock - sizeof(*rel)) / sizeof(USHORT),
-                                             (USHORT *)(rel + 1), delta );
-            if (!rel) goto error;
-        }
-    }
-
     /* set the image protections */
 
     VIRTUAL_SetProt( view, ptr, ROUND_SIZE( 0, header_size ), VPROT_COMMITTED | VPROT_READ );
@@ -1370,7 +1328,7 @@ static NTSTATUS map_image( HANDLE hmapping, int fd, char *base, SIZE_T total_siz
 
     *addr_ptr = ptr;
 #ifdef VALGRIND_LOAD_PDB_DEBUGINFO
-    VALGRIND_LOAD_PDB_DEBUGINFO(fd, ptr, total_size, delta);
+    VALGRIND_LOAD_PDB_DEBUGINFO(fd, ptr, total_size, ptr - base);
 #endif
     if (ptr != base) return STATUS_IMAGE_NOT_AT_BASE;
     return STATUS_SUCCESS;
-- 
1.7.8.4




More information about the wine-patches mailing list