/* $Id$ * * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS kernel * FILE: ntoskrnl/ldr/loader.c * PURPOSE: Loader utilities * PROGRAMMERS: Jean Michault * Rex Jolliff (rex@lvcablemodem.com) */ /* INCLUDES *****************************************************************/ #include #include #include #include #include #include #define NDEBUG #include /* FUNCTIONS ****************************************************************/ PIMAGE_NT_HEADERS STDCALL RtlImageNtHeader (IN PVOID BaseAddress) { PIMAGE_DOS_HEADER DosHeader; PIMAGE_NT_HEADERS NTHeaders; DosHeader = (PIMAGE_DOS_HEADER)BaseAddress; NTHeaders = (PIMAGE_NT_HEADERS)(BaseAddress + DosHeader->e_lfanew); if ((DosHeader->e_magic != IMAGE_DOS_MAGIC) || (DosHeader->e_lfanew == 0L) || (*(PULONG) NTHeaders != IMAGE_PE_MAGIC)) { return(NULL); } return(NTHeaders); } PVOID STDCALL RtlImageDirectoryEntryToData (IN PVOID BaseAddress, IN BOOLEAN ImageLoaded, IN ULONG Directory, OUT PULONG Size) { PIMAGE_NT_HEADERS NtHeader; PIMAGE_SECTION_HEADER SectionHeader; ULONG Va; ULONG Count; NtHeader = RtlImageNtHeader (BaseAddress); if (NtHeader == NULL) return NULL; if (Directory >= NtHeader->OptionalHeader.NumberOfRvaAndSizes) return NULL; Va = NtHeader->OptionalHeader.DataDirectory[Directory].VirtualAddress; if (Va == 0) return NULL; if (Size) *Size = NtHeader->OptionalHeader.DataDirectory[Directory].Size; if (ImageLoaded) return (PVOID)(BaseAddress + Va); /* image mapped as ordinary file, we must find raw pointer */ SectionHeader = (PIMAGE_SECTION_HEADER)(NtHeader + 1); Count = NtHeader->FileHeader.NumberOfSections; while (Count--) { if (SectionHeader->VirtualAddress == Va) return (PVOID)(BaseAddress + SectionHeader->PointerToRawData); SectionHeader++; } return NULL; } #ifndef LIBCAPTIVE PIMAGE_SECTION_HEADER STDCALL RtlImageRvaToSection ( PIMAGE_NT_HEADERS NtHeader, PVOID BaseAddress, ULONG Rva ) { PIMAGE_SECTION_HEADER Section; ULONG Va; ULONG Count; Count = NtHeader->FileHeader.NumberOfSections; Section = (PIMAGE_SECTION_HEADER)((ULONG)&NtHeader->OptionalHeader + NtHeader->FileHeader.SizeOfOptionalHeader); while (Count) { Va = Section->VirtualAddress; if ((Va <= Rva) && (Rva < Va + Section->SizeOfRawData)) return Section; Section++; } return NULL; } ULONG STDCALL 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 < Section->VirtualAddress || Rva >= Section->VirtualAddress + Section->SizeOfRawData) { Section = RtlImageRvaToSection (NtHeader, BaseAddress, Rva); if (Section == NULL) return 0; if (SectionHeader) *SectionHeader = Section; } return (ULONG)(BaseAddress + Rva + Section->PointerToRawData - Section->VirtualAddress); } #define RVA(m, b) ((ULONG)b + m) NTSTATUS STDCALL LdrGetProcedureAddress (IN PVOID BaseAddress, IN PANSI_STRING Name, IN ULONG Ordinal, OUT PVOID *ProcedureAddress) { PIMAGE_EXPORT_DIRECTORY ExportDir; PUSHORT OrdinalPtr; PULONG NamePtr; PULONG AddressPtr; ULONG i = 0; /* get the pointer to the export directory */ ExportDir = (PIMAGE_EXPORT_DIRECTORY) RtlImageDirectoryEntryToData (BaseAddress, TRUE, IMAGE_DIRECTORY_ENTRY_EXPORT, &i); if (!ExportDir || !i || !ProcedureAddress) { return(STATUS_INVALID_PARAMETER); } AddressPtr = (PULONG)RVA(BaseAddress, ExportDir->AddressOfFunctions); if (Name && Name->Length) { ULONG minn, maxn; /* by name */ OrdinalPtr = (PUSHORT)RVA(BaseAddress, ExportDir->AddressOfNameOrdinals); NamePtr = (PULONG)RVA(BaseAddress, ExportDir->AddressOfNames); minn = 0; maxn = ExportDir->NumberOfNames; while (minn <= maxn) { ULONG mid; LONG res; mid = (minn + maxn) / 2; res = _strnicmp(Name->Buffer, (PCH)RVA(BaseAddress, NamePtr[mid]), Name->Length); if (res == 0) { *ProcedureAddress = (PVOID)RVA(BaseAddress, AddressPtr[OrdinalPtr[mid]]); return(STATUS_SUCCESS); } else if (res > 0) { maxn = mid - 1; } else { minn = mid + 1; } } for (i = 0; i < ExportDir->NumberOfNames; i++, NamePtr++, OrdinalPtr++) { if (!_strnicmp(Name->Buffer, (char*)(BaseAddress + *NamePtr), Name->Length)) { *ProcedureAddress = (PVOID)((ULONG)BaseAddress + (ULONG)AddressPtr[*OrdinalPtr]); return STATUS_SUCCESS; } } CPRINT("LdrGetProcedureAddress: Can't resolve symbol '%Z'\n", Name); } else { /* by ordinal */ Ordinal &= 0x0000FFFF; if (Ordinal - ExportDir->Base < ExportDir->NumberOfFunctions) { *ProcedureAddress = (PVOID)((ULONG)BaseAddress + (ULONG)AddressPtr[Ordinal - ExportDir->Base]); return STATUS_SUCCESS; } CPRINT("LdrGetProcedureAddress: Can't resolve symbol @%d\n", Ordinal); } return STATUS_PROCEDURE_NOT_FOUND; } #endif /* LIBCAPTIVE */ /* EOF */