diff --git a/dlls/kernel32/tests/loader.c b/dlls/kernel32/tests/loader.c index 89feeb9f7d0..25b7b081a22 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 d15b140cda2..4404938c224 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 fe175184240..4d4bc3bc6b3 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;