📄 utils.c
字号:
/* $Id: utils.c 25365 2007-01-08 07:43:18Z ion $
*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
* FILE: lib/ntdll/ldr/utils.c
* PURPOSE: Process startup for PE executables
* PROGRAMMERS: Jean Michault
* Rex Jolliff (rex@lvcablemodem.com)
*/
/*
* TODO:
* - Handle loading flags correctly
* - Handle errors correctly (unload dll's)
* - Implement a faster way to find modules (hash table)
* - any more ??
*/
/* INCLUDES *****************************************************************/
#include <ntdll.h>
#define NDEBUG
#include <debug.h>
#define LDRP_PROCESS_CREATION_TIME 0x8000000
/* GLOBALS *******************************************************************/
#ifdef NDEBUG
#if defined(__GNUC__)
#define TRACE_LDR(args...) if (RtlGetNtGlobalFlags() & FLG_SHOW_LDR_SNAPS) { DbgPrint("(LDR:%s:%d) ",__FILE__,__LINE__); DbgPrint(args); }
#else
#endif /* __GNUC__ */
#else
#define TRACE_LDR(args...) do { DbgPrint("(LDR:%s:%d) ",__FILE__,__LINE__); DbgPrint(args); } while(0)
#endif
typedef struct _TLS_DATA
{
PVOID StartAddressOfRawData;
DWORD TlsDataSize;
DWORD TlsZeroSize;
PIMAGE_TLS_CALLBACK TlsAddressOfCallBacks;
PLDR_DATA_TABLE_ENTRY Module;
} TLS_DATA, *PTLS_DATA;
static PTLS_DATA LdrpTlsArray = NULL;
static ULONG LdrpTlsCount = 0;
static ULONG LdrpTlsSize = 0;
static HANDLE LdrpKnownDllsDirHandle = NULL;
static UNICODE_STRING LdrpKnownDllPath = {0, 0, NULL};
static PLDR_DATA_TABLE_ENTRY LdrpLastModule = NULL;
extern PLDR_DATA_TABLE_ENTRY ExeModule;
/* PROTOTYPES ****************************************************************/
static NTSTATUS LdrFindEntryForName(PUNICODE_STRING Name, PLDR_DATA_TABLE_ENTRY *Module, BOOLEAN Ref);
static PVOID LdrFixupForward(PCHAR ForwardName);
static PVOID LdrGetExportByName(PVOID BaseAddress, PUCHAR SymbolName, USHORT Hint);
static NTSTATUS LdrpLoadModule(IN PWSTR SearchPath OPTIONAL,
IN ULONG LoadFlags,
IN PUNICODE_STRING Name,
OUT PLDR_DATA_TABLE_ENTRY *Module,
OUT PVOID *BaseAddress OPTIONAL);
static NTSTATUS LdrpAttachProcess(VOID);
static VOID LdrpDetachProcess(BOOLEAN UnloadAll);
/* FUNCTIONS *****************************************************************/
#if defined(DBG) || defined(KDBG)
VOID
LdrpLoadUserModuleSymbols(PLDR_DATA_TABLE_ENTRY LdrModule)
{
NtSystemDebugControl(
SysDbgQueryVersion,
(PVOID)LdrModule,
0,
NULL,
0,
NULL);
}
#endif /* DBG || KDBG */
BOOLEAN
LdrMappedAsDataFile(PVOID *BaseAddress)
{
if (0 != ((DWORD_PTR) *BaseAddress & (PAGE_SIZE - 1)))
{
*BaseAddress = (PVOID) ((DWORD_PTR) *BaseAddress & ~ ((DWORD_PTR) PAGE_SIZE - 1));
return TRUE;
}
return FALSE;
}
static __inline LONG LdrpDecrementLoadCount(PLDR_DATA_TABLE_ENTRY Module, BOOLEAN Locked)
{
LONG LoadCount;
if (!Locked)
{
RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock);
}
LoadCount = Module->LoadCount;
if (Module->LoadCount > 0 && Module->LoadCount != 0xFFFF)
{
Module->LoadCount--;
}
if (!Locked)
{
RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock);
}
return LoadCount;
}
static __inline LONG LdrpIncrementLoadCount(PLDR_DATA_TABLE_ENTRY Module, BOOLEAN Locked)
{
LONG LoadCount;
if (!Locked)
{
RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock);
}
LoadCount = Module->LoadCount;
if (Module->LoadCount != 0xFFFF)
{
Module->LoadCount++;
}
if (!Locked)
{
RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock);
}
return LoadCount;
}
static __inline VOID LdrpAcquireTlsSlot(PLDR_DATA_TABLE_ENTRY Module, ULONG Size, BOOLEAN Locked)
{
if (!Locked)
{
RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock);
}
Module->TlsIndex = (SHORT)LdrpTlsCount;
LdrpTlsCount++;
LdrpTlsSize += Size;
if (!Locked)
{
RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock);
}
}
static __inline VOID LdrpTlsCallback(PLDR_DATA_TABLE_ENTRY Module, ULONG dwReason)
{
PIMAGE_TLS_CALLBACK TlsCallback;
if (Module->TlsIndex != 0xFFFF && Module->LoadCount == 0xFFFF)
{
TlsCallback = LdrpTlsArray[Module->TlsIndex].TlsAddressOfCallBacks;
if (TlsCallback)
{
while (*TlsCallback)
{
TRACE_LDR("%wZ - Calling tls callback at %x\n",
&Module->BaseDllName, TlsCallback);
TlsCallback(Module->DllBase, dwReason, NULL);
TlsCallback = (PIMAGE_TLS_CALLBACK)((ULONG_PTR)TlsCallback + sizeof(PVOID));
}
}
}
}
static BOOLEAN LdrpCallDllEntry(PLDR_DATA_TABLE_ENTRY Module, DWORD dwReason, PVOID lpReserved)
{
if (!(Module->Flags & LDRP_IMAGE_DLL) ||
Module->EntryPoint == 0)
{
return TRUE;
}
LdrpTlsCallback(Module, dwReason);
return ((PDLLMAIN_FUNC)Module->EntryPoint)(Module->DllBase, dwReason, lpReserved);
}
static NTSTATUS
LdrpInitializeTlsForThread(VOID)
{
PVOID* TlsPointers;
PTLS_DATA TlsInfo;
PVOID TlsData;
ULONG i;
PTEB Teb = NtCurrentTeb();
DPRINT("LdrpInitializeTlsForThread() called for %wZ\n", &ExeModule->BaseDllName);
Teb->StaticUnicodeString.Length = 0;
Teb->StaticUnicodeString.MaximumLength = sizeof(Teb->StaticUnicodeBuffer);
Teb->StaticUnicodeString.Buffer = Teb->StaticUnicodeBuffer;
if (LdrpTlsCount > 0)
{
TlsPointers = RtlAllocateHeap(RtlGetProcessHeap(),
0,
LdrpTlsCount * sizeof(PVOID) + LdrpTlsSize);
if (TlsPointers == NULL)
{
DPRINT1("failed to allocate thread tls data\n");
return STATUS_NO_MEMORY;
}
TlsData = (PVOID)((ULONG_PTR)TlsPointers + LdrpTlsCount * sizeof(PVOID));
Teb->ThreadLocalStoragePointer = TlsPointers;
TlsInfo = LdrpTlsArray;
for (i = 0; i < LdrpTlsCount; i++, TlsInfo++)
{
TRACE_LDR("Initialize tls data for %wZ\n", &TlsInfo->Module->BaseDllName);
TlsPointers[i] = TlsData;
if (TlsInfo->TlsDataSize)
{
memcpy(TlsData, TlsInfo->StartAddressOfRawData, TlsInfo->TlsDataSize);
TlsData = (PVOID)((ULONG_PTR)TlsData + TlsInfo->TlsDataSize);
}
if (TlsInfo->TlsZeroSize)
{
memset(TlsData, 0, TlsInfo->TlsZeroSize);
TlsData = (PVOID)((ULONG_PTR)TlsData + TlsInfo->TlsZeroSize);
}
}
}
DPRINT("LdrpInitializeTlsForThread() done\n");
return STATUS_SUCCESS;
}
static NTSTATUS
LdrpInitializeTlsForProccess(VOID)
{
PLIST_ENTRY ModuleListHead;
PLIST_ENTRY Entry;
PLDR_DATA_TABLE_ENTRY Module;
PIMAGE_TLS_DIRECTORY TlsDirectory;
PTLS_DATA TlsData;
ULONG Size;
DPRINT("LdrpInitializeTlsForProccess() called for %wZ\n", &ExeModule->BaseDllName);
if (LdrpTlsCount > 0)
{
LdrpTlsArray = RtlAllocateHeap(RtlGetProcessHeap(),
0,
LdrpTlsCount * sizeof(TLS_DATA));
if (LdrpTlsArray == NULL)
{
DPRINT1("Failed to allocate global tls data\n");
return STATUS_NO_MEMORY;
}
ModuleListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
Entry = ModuleListHead->Flink;
while (Entry != ModuleListHead)
{
Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
if (Module->LoadCount == 0xFFFF &&
Module->TlsIndex != 0xFFFF)
{
TlsDirectory = (PIMAGE_TLS_DIRECTORY)
RtlImageDirectoryEntryToData(Module->DllBase,
TRUE,
IMAGE_DIRECTORY_ENTRY_TLS,
&Size);
ASSERT(Module->TlsIndex < LdrpTlsCount);
TlsData = &LdrpTlsArray[Module->TlsIndex];
TlsData->StartAddressOfRawData = (PVOID)TlsDirectory->StartAddressOfRawData;
TlsData->TlsDataSize = TlsDirectory->EndAddressOfRawData - TlsDirectory->StartAddressOfRawData;
TlsData->TlsZeroSize = TlsDirectory->SizeOfZeroFill;
if (TlsDirectory->AddressOfCallBacks)
TlsData->TlsAddressOfCallBacks = *(PIMAGE_TLS_CALLBACK*)TlsDirectory->AddressOfCallBacks;
else
TlsData->TlsAddressOfCallBacks = NULL;
TlsData->Module = Module;
#if 0
DbgPrint("TLS directory for %wZ\n", &Module->BaseDllName);
DbgPrint("StartAddressOfRawData: %x\n", TlsDirectory->StartAddressOfRawData);
DbgPrint("EndAddressOfRawData: %x\n", TlsDirectory->EndAddressOfRawData);
DbgPrint("SizeOfRawData: %d\n", TlsDirectory->EndAddressOfRawData - TlsDirectory->StartAddressOfRawData);
DbgPrint("AddressOfIndex: %x\n", TlsDirectory->AddressOfIndex);
DbgPrint("AddressOfCallBacks: %x (%x)\n", TlsDirectory->AddressOfCallBacks, *TlsDirectory->AddressOfCallBacks);
DbgPrint("SizeOfZeroFill: %d\n", TlsDirectory->SizeOfZeroFill);
DbgPrint("Characteristics: %x\n", TlsDirectory->Characteristics);
#endif
/*
* FIXME:
* Is this region allways writable ?
*/
*(PULONG)TlsDirectory->AddressOfIndex = Module->TlsIndex;
}
Entry = Entry->Flink;
}
}
DPRINT("LdrpInitializeTlsForProccess() done\n");
return STATUS_SUCCESS;
}
VOID
LdrpInitLoader(VOID)
{
OBJECT_ATTRIBUTES ObjectAttributes;
UNICODE_STRING LinkTarget;
UNICODE_STRING Name;
HANDLE LinkHandle;
ULONG Length;
NTSTATUS Status;
DPRINT("LdrpInitLoader() called for %wZ\n", &ExeModule->BaseDllName);
/* Get handle to the 'KnownDlls' directory */
RtlInitUnicodeString(&Name,
L"\\KnownDlls");
InitializeObjectAttributes(&ObjectAttributes,
&Name,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
Status = NtOpenDirectoryObject(&LdrpKnownDllsDirHandle,
DIRECTORY_QUERY | DIRECTORY_TRAVERSE,
&ObjectAttributes);
if (!NT_SUCCESS(Status))
{
DPRINT("NtOpenDirectoryObject() failed (Status %lx)\n", Status);
LdrpKnownDllsDirHandle = NULL;
return;
}
/* Allocate target name string */
LinkTarget.Length = 0;
LinkTarget.MaximumLength = MAX_PATH * sizeof(WCHAR);
LinkTarget.Buffer = RtlAllocateHeap(RtlGetProcessHeap(),
0,
MAX_PATH * sizeof(WCHAR));
if (LinkTarget.Buffer == NULL)
{
NtClose(LdrpKnownDllsDirHandle);
LdrpKnownDllsDirHandle = NULL;
return;
}
RtlInitUnicodeString(&Name,
L"KnownDllPath");
InitializeObjectAttributes(&ObjectAttributes,
&Name,
OBJ_CASE_INSENSITIVE,
LdrpKnownDllsDirHandle,
NULL);
Status = NtOpenSymbolicLinkObject(&LinkHandle,
SYMBOLIC_LINK_ALL_ACCESS,
&ObjectAttributes);
if (!NT_SUCCESS(Status))
{
RtlFreeUnicodeString(&LinkTarget);
NtClose(LdrpKnownDllsDirHandle);
LdrpKnownDllsDirHandle = NULL;
return;
}
Status = NtQuerySymbolicLinkObject(LinkHandle,
&LinkTarget,
&Length);
NtClose(LinkHandle);
if (!NT_SUCCESS(Status))
{
RtlFreeUnicodeString(&LinkTarget);
NtClose(LdrpKnownDllsDirHandle);
LdrpKnownDllsDirHandle = NULL;
}
RtlCreateUnicodeString(&LdrpKnownDllPath,
LinkTarget.Buffer);
RtlFreeUnicodeString(&LinkTarget);
DPRINT("LdrpInitLoader() done\n");
}
/***************************************************************************
* NAME LOCAL
* LdrAdjustDllName
*
* DESCRIPTION
* Adjusts the name of a dll to a fully qualified name.
*
* ARGUMENTS
* FullDllName: Pointer to caller supplied storage for the fully
* qualified dll name.
* DllName: Pointer to the dll name.
* BaseName: TRUE: Only the file name is passed to FullDllName
* FALSE: The full path is preserved in FullDllName
*
* RETURN VALUE
* None
*
* REVISIONS
*
* NOTE
* A given path is not affected by the adjustment, but the file
* name only:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -