- Rewritten relocation code to not make invalid assumptions (".reloc" section name) and to not unprotect second page (not needed really).

svn path=/trunk/; revision=9884
This commit is contained in:
Filip Navara 2004-06-26 14:37:05 +00:00
parent e4c1673f80
commit 399da20296

View file

@ -1,4 +1,4 @@
/* $Id: utils.c,v 1.93 2004/06/26 11:23:32 ekohl Exp $ /* $Id: utils.c,v 1.94 2004/06/26 14:37:05 navaraf Exp $
* *
* COPYRIGHT: See COPYING in the top level directory * COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel * PROJECT: ReactOS kernel
@ -1224,187 +1224,88 @@ static NTSTATUS
LdrPerformRelocations(PIMAGE_NT_HEADERS NTHeaders, LdrPerformRelocations(PIMAGE_NT_HEADERS NTHeaders,
PVOID ImageBase) PVOID ImageBase)
{ {
USHORT NumberOfEntries;
PUSHORT pValue16;
ULONG RelocationRVA;
ULONG Delta32;
ULONG Offset;
PULONG pValue32;
PRELOCATION_DIRECTORY RelocationDir;
PRELOCATION_ENTRY RelocationBlock;
int i;
PIMAGE_DATA_DIRECTORY RelocationDDir; PIMAGE_DATA_DIRECTORY RelocationDDir;
ULONG OldProtect; PIMAGE_BASE_RELOCATION RelocationDir, RelocationEnd;
PVOID ProtectBase; ULONG Count, ProtectSize, OldProtect, i;
ULONG ProtectSize; PVOID Page, ProtectPage;
ULONG OldProtect2; PWORD TypeOffset;
PVOID ProtectBase2; ULONG Delta = (ULONG_PTR)ImageBase - NTHeaders->OptionalHeader.ImageBase;
ULONG ProtectSize2;
NTSTATUS Status; NTSTATUS Status;
PIMAGE_SECTION_HEADER Sections;
ULONG MaxExtend;
ULONG RelocationBlockOffset;
ULONG RelocationSectionSize;
if (NTHeaders->FileHeader.Characteristics & IMAGE_FILE_RELOCS_STRIPPED) if (NTHeaders->FileHeader.Characteristics & IMAGE_FILE_RELOCS_STRIPPED)
{ {
return STATUS_UNSUCCESSFUL; return STATUS_UNSUCCESSFUL;
} }
Sections =
(PIMAGE_SECTION_HEADER)((PVOID)NTHeaders + sizeof(IMAGE_NT_HEADERS));
MaxExtend = 0;
RelocationSectionSize = 0;
for (i = 0; i < NTHeaders->FileHeader.NumberOfSections; i++)
{
if (!(Sections[i].Characteristics & IMAGE_SECTION_NOLOAD))
{
ULONG Extend;
Extend =
(ULONG)(Sections[i].VirtualAddress + Sections[i].Misc.VirtualSize);
MaxExtend = max(MaxExtend, Extend);
}
if (!memcmp(Sections[i].Name,".reloc", 6))
{
RelocationSectionSize = Sections[i].Misc.VirtualSize;
DPRINT("Relocation section size: %lx\n", RelocationSectionSize);
}
}
RelocationDDir = RelocationDDir =
&NTHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC]; &NTHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
RelocationRVA = RelocationDDir->VirtualAddress;
if (RelocationRVA) if (RelocationDDir->VirtualAddress == 0 || RelocationDDir->Size == 0)
{ {
RelocationDir = return STATUS_SUCCESS;
(PRELOCATION_DIRECTORY)((PCHAR)ImageBase + RelocationRVA); }
ProtectSize = PAGE_SIZE;
RelocationDir = (IMAGE_BASE_RELOCATION*)((ULONG_PTR)ImageBase +
RelocationDDir->VirtualAddress);
RelocationEnd = (IMAGE_BASE_RELOCATION*)((ULONG_PTR)ImageBase +
RelocationDDir->VirtualAddress + RelocationDDir->Size);
while (RelocationDir < RelocationEnd &&
RelocationDir->SizeOfBlock > 0)
{
Count = (RelocationDir->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) /
sizeof(WORD);
Page = ImageBase + RelocationDir->VirtualAddress;
TypeOffset = (PWORD)(RelocationDir + 1);
RelocationBlockOffset = 0; /* Unprotect the page we're about to relocate. */
while (RelocationBlockOffset < RelocationSectionSize) ProtectPage = Page;
Status = NtProtectVirtualMemory(NtCurrentProcess(),
&ProtectPage,
&ProtectSize,
PAGE_READWRITE,
&OldProtect);
if (!NT_SUCCESS(Status))
{ {
if (RelocationDir->VirtualAddress > MaxExtend) DPRINT1("Failed to unprotect relocation target.\n");
{ return(Status);
RelocationRVA += RelocationDir->SizeOfBlock;
RelocationDir =
(PRELOCATION_DIRECTORY) (ImageBase + RelocationRVA);
RelocationBlockOffset += RelocationDir->SizeOfBlock;
continue;
}
Delta32 = (ULONG)(ImageBase - NTHeaders->OptionalHeader.ImageBase);
RelocationBlock =
(PRELOCATION_ENTRY) (RelocationRVA + ImageBase +
sizeof (RELOCATION_DIRECTORY));
NumberOfEntries =
RelocationDir->SizeOfBlock - sizeof (RELOCATION_DIRECTORY);
NumberOfEntries = NumberOfEntries / sizeof (RELOCATION_ENTRY);
ProtectBase = ImageBase + RelocationDir->VirtualAddress;
ProtectSize = PAGE_SIZE;
Status = NtProtectVirtualMemory(NtCurrentProcess(),
&ProtectBase,
&ProtectSize,
PAGE_READWRITE,
&OldProtect);
if (!NT_SUCCESS(Status))
{
DPRINT1("Failed to unprotect relocation target.\n");
return(Status);
}
if (RelocationDir->VirtualAddress + PAGE_SIZE < MaxExtend)
{
ProtectBase2 = ImageBase + RelocationDir->VirtualAddress + PAGE_SIZE;
ProtectSize2 = PAGE_SIZE;
Status = NtProtectVirtualMemory(NtCurrentProcess(),
&ProtectBase2,
&ProtectSize2,
PAGE_READWRITE,
&OldProtect2);
if (!NT_SUCCESS(Status))
{
DPRINT1("Failed to unprotect relocation target (2).\n");
NtProtectVirtualMemory(NtCurrentProcess(),
&ProtectBase,
&ProtectSize,
OldProtect,
&OldProtect);
return(Status);
}
}
for (i = 0; i < NumberOfEntries; i++)
{
Offset = (RelocationBlock[i].TypeOffset & 0xfff);
Offset += (ULONG)(RelocationDir->VirtualAddress + ImageBase);
/*
* What kind of relocations should we perform
* for the current entry?
*/
switch (RelocationBlock[i].TypeOffset >> 12)
{
case TYPE_RELOC_ABSOLUTE:
break;
case TYPE_RELOC_HIGH:
pValue16 = (PUSHORT)Offset;
*pValue16 += Delta32 >> 16;
break;
case TYPE_RELOC_LOW:
pValue16 = (PUSHORT)Offset;
*pValue16 += Delta32 & 0xffff;
break;
case TYPE_RELOC_HIGHLOW:
pValue32 = (PULONG)Offset;
*pValue32 += Delta32;
break;
case TYPE_RELOC_HIGHADJ:
/* FIXME: do the highadjust fixup */
DPRINT("TYPE_RELOC_HIGHADJ fixup not implemented, sorry\n");
return STATUS_UNSUCCESSFUL;
default:
DPRINT("unexpected fixup type\n");
return STATUS_UNSUCCESSFUL;
}
}
Status = NtProtectVirtualMemory(NtCurrentProcess(),
&ProtectBase,
&ProtectSize,
OldProtect,
&OldProtect);
if (!NT_SUCCESS(Status))
{
DPRINT1("Failed to protect relocation target.\n");
return(Status);
}
if (RelocationDir->VirtualAddress + PAGE_SIZE < MaxExtend)
{
Status = NtProtectVirtualMemory(NtCurrentProcess(),
&ProtectBase2,
&ProtectSize2,
OldProtect2,
&OldProtect2);
if (!NT_SUCCESS(Status))
{
DPRINT1("Failed to protect relocation target2.\n");
return(Status);
}
}
RelocationRVA += RelocationDir->SizeOfBlock;
RelocationDir =
(PRELOCATION_DIRECTORY) (ImageBase + RelocationRVA);
RelocationBlockOffset += RelocationDir->SizeOfBlock;
} }
/* Patch the page. */
for (i = 0; i < Count; i++)
{
SHORT Offset = TypeOffset[i] & 0xFFF;
USHORT Type = TypeOffset[i] >> 12;
switch (Type)
{
case IMAGE_REL_BASED_ABSOLUTE:
break;
case IMAGE_REL_BASED_HIGH:
*(PUSHORT)(Page + Offset) += HIWORD(Delta);
break;
case IMAGE_REL_BASED_LOW:
*(PUSHORT)(Page + Offset) += LOWORD(Delta);
break;
case IMAGE_REL_BASED_HIGHLOW:
*(PULONG)(Page + Offset) += Delta;
break;
case IMAGE_REL_BASED_HIGHADJ:
default:
DPRINT("Unknown/unsupported fixup type %d.\n", type);
return STATUS_UNSUCCESSFUL;
}
}
/* Restore old page protection. */
NtProtectVirtualMemory(NtCurrentProcess(),
&ProtectPage,
&ProtectSize,
OldProtect,
&OldProtect);
RelocationDir = (IMAGE_BASE_RELOCATION*)((ULONG_PTR)RelocationDir +
RelocationDir->SizeOfBlock);
} }
return STATUS_SUCCESS; return STATUS_SUCCESS;