ntdll: Separate image relocation from NtMapViewOfSection. Resend.
Dmitry Timoshkov
dmitry at baikal.ru
Mon Mar 19 00:36:07 CDT 2012
---
dlls/kernel32/tests/loader.c | 10 -----
dlls/ntdll/loader.c | 88 +++++++++++++++++++++++++++++++++++++++++-
dlls/ntdll/virtual.c | 44 +--------------------
3 files changed, 88 insertions(+), 54 deletions(-)
diff --git a/dlls/kernel32/tests/loader.c b/dlls/kernel32/tests/loader.c
index e98ebc1..2868250 100644
--- a/dlls/kernel32/tests/loader.c
+++ b/dlls/kernel32/tests/loader.c
@@ -606,15 +606,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");
@@ -668,7 +659,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 5dc7911..a1cfdb2 100644
--- a/dlls/ntdll/loader.c
+++ b/dlls/ntdll/loader.c
@@ -1508,6 +1508,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_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;
+ }
+
+ 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 );
+
+ 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)
@@ -1533,7 +1612,14 @@ 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)
+ {
+ if (module) NtUnmapViewOfSection( NtCurrentProcess(), module );
+ goto done;
+ }
/* create the MODREF */
diff --git a/dlls/ntdll/virtual.c b/dlls/ntdll/virtual.c
index 5271d18..5baeee2 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, *header_start;
- INT_PTR delta = 0;
/* zero-map the whole range */
@@ -1302,47 +1301,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 );
@@ -1380,7 +1338,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.9.4
More information about the wine-patches
mailing list