/* COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS system libraries * FILE: lib/rtl/image.c * PURPOSE: Image handling functions * Relocate functions were previously located in * ntoskrnl/ldr/loader.c and * dll/ntdll/ldr/utils.c files * PROGRAMMER: Eric Kohl + original authors from loader.c and utils.c file * Aleksey Bragin */ /* INCLUDES *****************************************************************/ #include #define NDEBUG #include /* FUNCTIONS *****************************************************************/ BOOLEAN NTAPI LdrVerifyMappedImageMatchesChecksum(IN PVOID BaseAddress, IN ULONG NumberOfBytes, IN ULONG FileLength) { /* FIXME: TODO */ return TRUE; } /* * @implemented */ PIMAGE_NT_HEADERS NTAPI RtlImageNtHeader (IN PVOID BaseAddress) { PIMAGE_NT_HEADERS NtHeader; PIMAGE_DOS_HEADER DosHeader = (PIMAGE_DOS_HEADER)BaseAddress; if (DosHeader && SWAPW(DosHeader->e_magic) != IMAGE_DOS_SIGNATURE) { DPRINT1("DosHeader->e_magic %x\n", SWAPW(DosHeader->e_magic)); DPRINT1("NtHeader 0x%lx\n", ((ULONG_PTR)BaseAddress + SWAPD(DosHeader->e_lfanew))); } if (DosHeader && SWAPW(DosHeader->e_magic) == IMAGE_DOS_SIGNATURE) { NtHeader = (PIMAGE_NT_HEADERS)((ULONG_PTR)BaseAddress + SWAPD(DosHeader->e_lfanew)); if (SWAPD(NtHeader->Signature) == IMAGE_NT_SIGNATURE) return NtHeader; } return NULL; } /* * @implemented */ PVOID NTAPI RtlImageDirectoryEntryToData(PVOID BaseAddress, BOOLEAN MappedAsImage, USHORT Directory, PULONG Size) { PIMAGE_NT_HEADERS NtHeader; ULONG Va; /* Magic flag for non-mapped images. */ if ((ULONG_PTR)BaseAddress & 1) { BaseAddress = (PVOID)((ULONG_PTR)BaseAddress & ~1); MappedAsImage = FALSE; } NtHeader = RtlImageNtHeader (BaseAddress); if (NtHeader == NULL) return NULL; if (Directory >= SWAPD(NtHeader->OptionalHeader.NumberOfRvaAndSizes)) return NULL; Va = SWAPD(NtHeader->OptionalHeader.DataDirectory[Directory].VirtualAddress); if (Va == 0) return NULL; *Size = SWAPD(NtHeader->OptionalHeader.DataDirectory[Directory].Size); if (MappedAsImage || Va < SWAPD(NtHeader->OptionalHeader.SizeOfHeaders)) return (PVOID)((ULONG_PTR)BaseAddress + Va); /* image mapped as ordinary file, we must find raw pointer */ return RtlImageRvaToVa (NtHeader, BaseAddress, Va, NULL); } /* * @implemented */ PIMAGE_SECTION_HEADER NTAPI RtlImageRvaToSection ( PIMAGE_NT_HEADERS NtHeader, PVOID BaseAddress, ULONG Rva ) { PIMAGE_SECTION_HEADER Section; ULONG Va; ULONG Count; Count = SWAPW(NtHeader->FileHeader.NumberOfSections); Section = IMAGE_FIRST_SECTION(NtHeader); while (Count--) { Va = SWAPD(Section->VirtualAddress); if ((Va <= Rva) && (Rva < Va + SWAPD(Section->Misc.VirtualSize))) return Section; Section++; } return NULL; } /* * @implemented */ PVOID NTAPI RtlImageRvaToVa ( PIMAGE_NT_HEADERS NtHeader, PVOID BaseAddress, ULONG Rva, PIMAGE_SECTION_HEADER *SectionHeader ) { PIMAGE_SECTION_HEADER Section = NULL; if (SectionHeader) Section = *SectionHeader; if (Section == NULL || Rva < SWAPD(Section->VirtualAddress) || Rva >= SWAPD(Section->VirtualAddress) + SWAPD(Section->Misc.VirtualSize)) { Section = RtlImageRvaToSection (NtHeader, BaseAddress, Rva); if (Section == NULL) return 0; if (SectionHeader) *SectionHeader = Section; } return (PVOID)((ULONG_PTR)BaseAddress + Rva + SWAPD(Section->PointerToRawData) - (ULONG_PTR)SWAPD(Section->VirtualAddress)); } PIMAGE_BASE_RELOCATION NTAPI LdrProcessRelocationBlockLongLong( IN ULONG_PTR Address, IN ULONG Count, IN PUSHORT TypeOffset, IN LONGLONG Delta ) { SHORT Offset; USHORT Type; USHORT i; PUSHORT ShortPtr; PULONG LongPtr; for (i = 0; i < Count; i++) { Offset = SWAPW(*TypeOffset) & 0xFFF; Type = SWAPW(*TypeOffset) >> 12; ShortPtr = (PUSHORT)(RVA(Address, Offset)); /* * Don't relocate within the relocation section itself. * GCC/LD generates sometimes relocation records for the relocation section. * This is a bug in GCC/LD. * Fix for it disabled, since it was only in ntoskrnl and not in ntdll */ /* if ((ULONG_PTR)ShortPtr < (ULONG_PTR)RelocationDir || (ULONG_PTR)ShortPtr >= (ULONG_PTR)RelocationEnd) {*/ switch (Type) { /* case IMAGE_REL_BASED_SECTION : */ /* case IMAGE_REL_BASED_REL32 : */ case IMAGE_REL_BASED_ABSOLUTE: break; case IMAGE_REL_BASED_HIGH: *ShortPtr = HIWORD(MAKELONG(0, *ShortPtr) + (LONG)Delta); break; case IMAGE_REL_BASED_LOW: *ShortPtr = SWAPW(*ShortPtr) + LOWORD(Delta); break; case IMAGE_REL_BASED_HIGHLOW: LongPtr = (PULONG)RVA(Address, Offset); *LongPtr = SWAPD(*LongPtr) + (ULONG)Delta; break; case IMAGE_REL_BASED_HIGHADJ: case IMAGE_REL_BASED_MIPS_JMPADDR: default: DPRINT1("Unknown/unsupported fixup type %hu.\n", Type); DPRINT1("Address %x, Current %d, Count %d, *TypeOffset %x\n", Address, i, Count, SWAPW(*TypeOffset)); return (PIMAGE_BASE_RELOCATION)NULL; } TypeOffset++; } return (PIMAGE_BASE_RELOCATION)TypeOffset; } ULONG NTAPI LdrRelocateImageWithBias( IN PVOID BaseAddress, IN LONGLONG AdditionalBias, IN PCCH LoaderName, IN ULONG Success, IN ULONG Conflict, IN ULONG Invalid ) { PIMAGE_NT_HEADERS NtHeaders; PIMAGE_DATA_DIRECTORY RelocationDDir; PIMAGE_BASE_RELOCATION RelocationDir, RelocationEnd; ULONG Count; ULONG_PTR Address; PUSHORT TypeOffset; LONGLONG Delta; NtHeaders = RtlImageNtHeader(BaseAddress); if (NtHeaders == NULL) return Invalid; if (SWAPW(NtHeaders->FileHeader.Characteristics) & IMAGE_FILE_RELOCS_STRIPPED) { return Conflict; } RelocationDDir = &NtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC]; if (SWAPD(RelocationDDir->VirtualAddress) == 0 || SWAPD(RelocationDDir->Size) == 0) { return Success; } Delta = (ULONG_PTR)BaseAddress - SWAPD(NtHeaders->OptionalHeader.ImageBase) + AdditionalBias; RelocationDir = (PIMAGE_BASE_RELOCATION)((ULONG_PTR)BaseAddress + SWAPD(RelocationDDir->VirtualAddress)); RelocationEnd = (PIMAGE_BASE_RELOCATION)((ULONG_PTR)RelocationDir + SWAPD(RelocationDDir->Size)); while (RelocationDir < RelocationEnd && SWAPW(RelocationDir->SizeOfBlock) > 0) { Count = (SWAPW(RelocationDir->SizeOfBlock) - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(USHORT); Address = (ULONG_PTR)RVA(BaseAddress, SWAPD(RelocationDir->VirtualAddress)); TypeOffset = (PUSHORT)(RelocationDir + 1); RelocationDir = LdrProcessRelocationBlockLongLong(Address, Count, TypeOffset, Delta); if (RelocationDir == NULL) { DPRINT1("Error during call to LdrProcessRelocationBlockLongLong()!\n"); return Invalid; } } return Success; } /* EOF */