ntdll: Separate image relocation from NtMapViewOfSection.

This commit is contained in:
Dmitry Timoshkov 2015-08-18 15:25:40 +08:00 committed by Alexandre Julliard
parent 9e8b58ee18
commit e67a00b466
3 changed files with 87 additions and 54 deletions

View File

@ -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);

View File

@ -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 */

View File

@ -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;