Dmitry Timoshkov : ntdll: Separate image relocation from NtMapViewOfSection.

Alexandre Julliard julliard at wine.codeweavers.com
Tue Aug 18 09:22:17 CDT 2015


Module: wine
Branch: master
Commit: e67a00b46694625e3c40386008affac42e7e3847
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=e67a00b46694625e3c40386008affac42e7e3847

Author: Dmitry Timoshkov <dmitry at baikal.ru>
Date:   Tue Aug 18 15:25:40 2015 +0800

ntdll: Separate image relocation from NtMapViewOfSection.

---

 dlls/kernel32/tests/loader.c | 10 -----
 dlls/ntdll/loader.c          | 87 +++++++++++++++++++++++++++++++++++++++++++-
 dlls/ntdll/virtual.c         | 44 +---------------------
 3 files changed, 87 insertions(+), 54 deletions(-)

diff --git a/dlls/kernel32/tests/loader.c b/dlls/kernel32/tests/loader.c
index 89feeb9..25b7b08 100644
--- a/dlls/kernel32/tests/loader.c
+++ b/dlls/kernel32/tests/loader.c
@@ -799,15 +799,6 @@ static void test_image_mapping(const char *dll_name, DWORD scn_page_access, BOOL
     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");
@@ -861,7 +852,6 @@ static void test_image_mapping(const char *dll_name, DWORD scn_page_access, BOOL
         ok(ret, "FreeLibrary error %d\n", GetLastError());
     }
 
-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 d15b140..4404938 100644
--- a/dlls/ntdll/loader.c
+++ b/dlls/ntdll/loader.c
@@ -1656,6 +1656,81 @@ static void set_security_cookie( void *module, SIZE_T len )
     }
 }
 
+static NTSTATUS perform_relocations( void *module, SIZE_T len )
+{
+    IMAGE_NT_HEADERS *nt;
+    char *base;
+    IMAGE_BASE_RELOCATION *rel, *end;
+    const IMAGE_DATA_DIRECTORY *relocs;
+    const IMAGE_SECTION_HEADER *sec;
+    INT_PTR delta;
+    ULONG protect_old[96], i;
+
+    nt = RtlImageNtHeader( module );
+    base = (char *)nt->OptionalHeader.ImageBase;
+
+    assert( module != base );
+
+    /* no relocations are performed on non page-aligned binaries */
+    if (nt->OptionalHeader.SectionAlignment < page_size)
+        return STATUS_SUCCESS;
+
+    if (!(nt->FileHeader.Characteristics & IMAGE_FILE_DLL) && NtCurrentTeb()->Peb->ImageBaseAddress)
+        return STATUS_SUCCESS;
+
+    relocs = &nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
+
+    if ((nt->FileHeader.Characteristics & IMAGE_FILE_RELOCS_STRIPPED) ||
+        !relocs->VirtualAddress || !relocs->Size)
+    {
+        WARN( "Need to relocate module from %p to %p, but there are no relocation records\n",
+              base, module );
+        return STATUS_CONFLICTING_ADDRESSES;
+    }
+
+    if (nt->FileHeader.NumberOfSections > sizeof(protect_old)/sizeof(protect_old[0]))
+        return STATUS_INVALID_IMAGE_FORMAT;
+
+    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 );
+        SIZE_T size = sec[i].SizeOfRawData;
+        NtProtectVirtualMemory( NtCurrentProcess(), &addr,
+                                &size, PAGE_READWRITE, &protect_old[i] );
+    }
+
+    TRACE( "relocating from %p-%p to %p-%p\n",
+           base, base + len, module, (char *)module + len );
+
+    rel = get_rva( module, relocs->VirtualAddress );
+    end = get_rva( module, relocs->VirtualAddress + relocs->Size );
+    delta = (char *)module - base;
+
+    while (rel < end - 1 && rel->SizeOfBlock)
+    {
+        if (rel->VirtualAddress >= len)
+        {
+            WARN( "invalid address %p in relocation %p\n", get_rva( module, rel->VirtualAddress ), rel );
+            return STATUS_ACCESS_VIOLATION;
+        }
+        rel = LdrProcessRelocationBlock( get_rva( module, rel->VirtualAddress ),
+                                         (rel->SizeOfBlock - sizeof(*rel)) / sizeof(USHORT),
+                                         (USHORT *)(rel + 1), delta );
+        if (!rel) return STATUS_INVALID_IMAGE_FORMAT;
+    }
+
+    for (i = 0; i < nt->FileHeader.NumberOfSections; i++)
+    {
+        void *addr = get_rva( module, sec[i].VirtualAddress );
+        SIZE_T size = sec[i].SizeOfRawData;
+        NtProtectVirtualMemory( NtCurrentProcess(), &addr,
+                                &size, protect_old[i], &protect_old[i] );
+    }
+
+    return STATUS_SUCCESS;
+}
 
 /******************************************************************************
  *	load_native_dll  (internal)
@@ -1681,7 +1756,17 @@ 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, len );
+
+    if (status != STATUS_SUCCESS)
+    {
+        if (module) NtUnmapViewOfSection( NtCurrentProcess(), module );
+        goto done;
+    }
 
     /* create the MODREF */
 
diff --git a/dlls/ntdll/virtual.c b/dlls/ntdll/virtual.c
index fe17518..4d4bc3b 100644
--- a/dlls/ntdll/virtual.c
+++ b/dlls/ntdll/virtual.c
@@ -1073,7 +1073,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, *header_start;
-    INT_PTR delta = 0;
 
     /* zero-map the whole range */
 
@@ -1236,47 +1235,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 );
@@ -1313,7 +1271,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;




More information about the wine-cvs mailing list