From d1f5c52e07bce357d3b471e839db2a6f7a72fa86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20M=C3=BCller?= Date: Mon, 3 Apr 2017 05:30:27 +0200 Subject: [PATCH] ntdll: Implement HashLinks field in LDR module data. --- dlls/kernel32/tests/loader.c | 75 ++++++++++++++++++++++++++++++++++++ dlls/ntdll/loader.c | 42 ++++++++++++++++++++ 2 files changed, 117 insertions(+) diff --git a/dlls/kernel32/tests/loader.c b/dlls/kernel32/tests/loader.c index 9b0f8f6bff2..747dfb0afa6 100644 --- a/dlls/kernel32/tests/loader.c +++ b/dlls/kernel32/tests/loader.c @@ -28,6 +28,7 @@ #include "winbase.h" #include "winternl.h" #include "winnls.h" +#include "winuser.h" #include "wine/test.h" #include "delayloadhandler.h" @@ -4651,6 +4652,79 @@ static void test_Wow64Transition(void) debugstr_wn(name->SectionFileName.Buffer, name->SectionFileName.Length / sizeof(WCHAR))); } +static inline WCHAR toupperW(WCHAR c) +{ + WCHAR tmp = c; + CharUpperBuffW(&tmp, 1); + return tmp; +} + +static ULONG hash_basename(const WCHAR *basename) +{ + WORD version = MAKEWORD(NtCurrentTeb()->Peb->OSMinorVersion, + NtCurrentTeb()->Peb->OSMajorVersion); + ULONG hash = 0; + + if (version >= 0x0602) + { + for (; *basename; basename++) + hash = hash * 65599 + toupperW(*basename); + } + else if (version == 0x0601) + { + for (; *basename; basename++) + hash = hash + 65599 * toupperW(*basename); + } + else + hash = toupperW(basename[0]) - 'A'; + + return hash & 31; +} + +static void test_HashLinks(void) +{ + static WCHAR ntdllW[] = {'n','t','d','l','l','.','d','l','l',0}; + static WCHAR kernel32W[] = {'k','e','r','n','e','l','3','2','.','d','l','l',0}; + + LIST_ENTRY *hash_map, *entry, *mark; + LDR_DATA_TABLE_ENTRY *module; + BOOL found; + + entry = &NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList; + entry = entry->Flink; + + module = CONTAINING_RECORD(entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks); + entry = module->HashLinks.Blink; + + hash_map = entry - hash_basename(module->BaseDllName.Buffer); + + mark = &hash_map[hash_basename(ntdllW)]; + found = FALSE; + for (entry = mark->Flink; entry != mark; entry = entry->Flink) + { + module = CONTAINING_RECORD(entry, LDR_DATA_TABLE_ENTRY, HashLinks); + if (!lstrcmpiW(module->BaseDllName.Buffer, ntdllW)) + { + found = TRUE; + break; + } + } + ok(found, "Could not find ntdll\n"); + + mark = &hash_map[hash_basename(kernel32W)]; + found = FALSE; + for (entry = mark->Flink; entry != mark; entry = entry->Flink) + { + module = CONTAINING_RECORD(entry, LDR_DATA_TABLE_ENTRY, HashLinks); + if (!lstrcmpiW(module->BaseDllName.Buffer, kernel32W)) + { + found = TRUE; + break; + } + } + ok(found, "Could not find kernel32\n"); +} + START_TEST(loader) { int argc; @@ -4734,6 +4808,7 @@ START_TEST(loader) test_InMemoryOrderModuleList(); test_LoadPackagedLibrary(); test_wow64_redirection(); + test_HashLinks(); test_dll_file( "ntdll.dll" ); test_dll_file( "kernel32.dll" ); test_dll_file( "advapi32.dll" ); diff --git a/dlls/ntdll/loader.c b/dlls/ntdll/loader.c index 0ed37ad390c..94610a82a65 100644 --- a/dlls/ntdll/loader.c +++ b/dlls/ntdll/loader.c @@ -128,6 +128,9 @@ struct file_id BYTE ObjectId[16]; }; +#define HASH_MAP_SIZE 32 +static LIST_ENTRY hash_table[HASH_MAP_SIZE]; + /* internal representation of loaded modules */ typedef struct _wine_modref { @@ -603,6 +606,33 @@ static int base_address_compare( const void *key, const RTL_BALANCED_NODE *entry return 0; } +/************************************************************************* + * hash_basename + * + * Calculates the bucket index of a dll using the basename. + */ +static ULONG hash_basename(const WCHAR *basename) +{ + WORD version = MAKEWORD(NtCurrentTeb()->Peb->OSMinorVersion, + NtCurrentTeb()->Peb->OSMajorVersion); + ULONG hash = 0; + + if (version >= 0x0602) + { + for (; *basename; basename++) + hash = hash * 65599 + towupper(*basename); + } + else if (version == 0x0601) + { + for (; *basename; basename++) + hash = hash + 65599 * towupper(*basename); + } + else + hash = towupper(basename[0]) - 'A'; + + return hash & (HASH_MAP_SIZE-1); +} + /************************************************************************* * get_modref * @@ -1599,9 +1629,14 @@ static WINE_MODREF *alloc_module( HMODULE hModule, const UNICODE_STRING *nt_name &wm->ldr.InLoadOrderLinks); InsertTailList(&NtCurrentTeb()->Peb->LdrData->InMemoryOrderModuleList, &wm->ldr.InMemoryOrderLinks); + InsertTailList(&hash_table[hash_basename(wm->ldr.BaseDllName.Buffer)], + &wm->ldr.HashLinks); if (rtl_rb_tree_put( &base_address_index_tree, wm->ldr.DllBase, &wm->ldr.BaseAddressIndexNode, base_address_compare )) ERR( "rtl_rb_tree_put failed.\n" ); + /* wait until init is called for inserting into InInitializationOrderModuleList */ + wm->ldr.InInitializationOrderLinks.Flink = NULL; + wm->ldr.InInitializationOrderLinks.Blink = NULL; if (!(nt->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_NX_COMPAT)) { @@ -2299,6 +2334,7 @@ static NTSTATUS build_module( LPCWSTR load_path, const UNICODE_STRING *nt_name, /* the module has only be inserted in the load & memory order lists */ RemoveEntryList(&wm->ldr.InLoadOrderLinks); RemoveEntryList(&wm->ldr.InMemoryOrderLinks); + RemoveEntryList(&wm->ldr.HashLinks); RtlRbRemoveNode( &base_address_index_tree, &wm->ldr.BaseAddressIndexNode ); /* FIXME: there are several more dangling references @@ -3963,6 +3999,7 @@ static void free_modref( WINE_MODREF *wm ) RemoveEntryList(&wm->ldr.InLoadOrderLinks); RemoveEntryList(&wm->ldr.InMemoryOrderLinks); + RemoveEntryList(&wm->ldr.HashLinks); RtlRbRemoveNode( &base_address_index_tree, &wm->ldr.BaseAddressIndexNode ); if (wm->ldr.InInitializationOrderLinks.Flink) RemoveEntryList(&wm->ldr.InInitializationOrderLinks); @@ -4384,6 +4421,7 @@ void loader_init( CONTEXT *context, void **entry ) ANSI_STRING ctrl_routine = RTL_CONSTANT_STRING( "CtrlRoutine" ); WINE_MODREF *kernel32; PEB *peb = NtCurrentTeb()->Peb; + unsigned int i; peb->LdrData = &ldr; peb->FastPebLock = &peb_lock; @@ -4402,6 +4440,10 @@ void loader_init( CONTEXT *context, void **entry ) if (!(tls_dirs = RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY, tls_module_count * sizeof(*tls_dirs) ))) NtTerminateProcess( GetCurrentProcess(), STATUS_NO_MEMORY ); + /* initialize hash table */ + for (i = 0; i < HASH_MAP_SIZE; i++) + InitializeListHead( &hash_table[i] ); + init_user_process_params(); load_global_options(); version_init(); -- 2.45.2