diff --git a/patches/ntdll-HashLinks/0001-ntdll-Implement-HashLinks-field-in-LDR-module-data.patch b/patches/ntdll-HashLinks/0001-ntdll-Implement-HashLinks-field-in-LDR-module-data.patch new file mode 100644 index 00000000..b6f8efdd --- /dev/null +++ b/patches/ntdll-HashLinks/0001-ntdll-Implement-HashLinks-field-in-LDR-module-data.patch @@ -0,0 +1,280 @@ +From e9ae5fa171bfea7b44946f6ac3d3205d53a72904 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: ntdll: Implement HashLinks field in LDR module data. + +--- + dlls/kernel32/tests/loader.c | 75 ++++++++++++++++++++++++++++++++++++++++++++ + dlls/ntdll/loader.c | 63 +++++++++++++++++++++++++++++++++++-- + include/winternl.h | 6 ++-- + 3 files changed, 140 insertions(+), 4 deletions(-) + +diff --git a/dlls/kernel32/tests/loader.c b/dlls/kernel32/tests/loader.c +index a74647b3d4..dc7b92deae 100644 +--- a/dlls/kernel32/tests/loader.c ++++ b/dlls/kernel32/tests/loader.c +@@ -28,6 +28,7 @@ + #include "windef.h" + #include "winbase.h" + #include "winternl.h" ++#include "winuser.h" + #include "wine/test.h" + #include "delayloadhandler.h" + +@@ -3043,6 +3044,79 @@ static void test_InMemoryOrderModuleList(void) + ok(entry2 == mark2, "expected entry2 == mark2, got %p and %p\n", entry2, mark2); + } + ++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_MODULE *module; ++ BOOL found; ++ ++ entry = &NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList; ++ entry = entry->Flink; ++ ++ module = CONTAINING_RECORD(entry, LDR_MODULE, InLoadOrderModuleList); ++ 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_MODULE, 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_MODULE, HashLinks); ++ if (!lstrcmpiW(module->BaseDllName.Buffer, kernel32W)) ++ { ++ found = TRUE; ++ break; ++ } ++ } ++ ok(found, "Could not find kernel32\n"); ++} ++ + START_TEST(loader) + { + int argc; +@@ -3104,4 +3178,5 @@ START_TEST(loader) + test_import_resolution(); + test_ExitProcess(); + test_InMemoryOrderModuleList(); ++ test_HashLinks(); + } +diff --git a/dlls/ntdll/loader.c b/dlls/ntdll/loader.c +index 97cde88354..d9b6b7d1c7 100644 +--- a/dlls/ntdll/loader.c ++++ b/dlls/ntdll/loader.c +@@ -82,6 +82,9 @@ static const char * const reason_names[] = + + static const WCHAR dllW[] = {'.','d','l','l',0}; + ++#define HASH_MAP_SIZE 32 ++static LIST_ENTRY hash_table[HASH_MAP_SIZE]; ++ + /* internal representation of 32bit modules. per process. */ + typedef struct _wine_modref + { +@@ -159,7 +162,6 @@ static inline void ascii_to_unicode( WCHAR *dst, const char *src, size_t len ) + while (len--) *dst++ = (unsigned char)*src++; + } + +- + /************************************************************************* + * call_dll_entry_point + * +@@ -424,6 +426,51 @@ static BOOL load_mscoree( void ) + return TRUE; + } + ++/************************************************************************* ++ * 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 + toupperW(*basename); ++ } ++ else if (version == 0x0601) ++ { ++ for (; *basename; basename++) ++ hash = hash + 65599 * toupperW(*basename); ++ } ++ else ++ hash = toupperW(basename[0]) - 'A'; ++ ++ return hash & (HASH_MAP_SIZE-1); ++} ++ ++/************************************************************************* ++ * recompute_hash_maps ++ * ++ * Recomputes the LDR hash map (necessary when windows version changes). ++ */ ++static void recompute_hash_map(void) ++{ ++ PLIST_ENTRY mark, entry; ++ PLDR_MODULE mod; ++ ++ mark = &NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList; ++ for (entry = mark->Flink; entry != mark; entry = entry->Flink) ++ { ++ mod = CONTAINING_RECORD(entry, LDR_MODULE, InLoadOrderModuleList); ++ RemoveEntryList( &mod->HashLinks ); ++ InsertTailList( &hash_table[hash_basename(mod->BaseDllName.Buffer)], &mod->HashLinks ); ++ } ++} + + /************************************************************************* + * get_modref +@@ -1054,7 +1101,6 @@ static WINE_MODREF *alloc_module( HMODULE hModule, LPCWSTR filename, LPCWSTR fak + wm->ldr.TlsIndex = -1; + wm->ldr.LoadCount = 1; + wm->ldr.SectionHandle = NULL; +- wm->ldr.CheckSum = 0; + wm->ldr.TimeDateStamp = 0; + wm->ldr.ActivationContext = 0; + +@@ -1075,6 +1121,8 @@ static WINE_MODREF *alloc_module( HMODULE hModule, LPCWSTR filename, LPCWSTR fak + &wm->ldr.InLoadOrderModuleList); + InsertTailList(&NtCurrentTeb()->Peb->LdrData->InMemoryOrderModuleList, + &wm->ldr.InMemoryOrderModuleList); ++ InsertTailList(&hash_table[hash_basename(wm->ldr.BaseDllName.Buffer)], ++ &wm->ldr.HashLinks); + + /* wait until init is called for inserting into this list */ + wm->ldr.InInitializationOrderModuleList.Flink = NULL; +@@ -1877,6 +1925,7 @@ static void load_builtin_callback( void *module, const char *filename ) + /* the module has only be inserted in the load & memory order lists */ + RemoveEntryList(&wm->ldr.InLoadOrderModuleList); + RemoveEntryList(&wm->ldr.InMemoryOrderModuleList); ++ RemoveEntryList(&wm->ldr.HashLinks); + /* FIXME: free the modref */ + builtin_load_info->status = STATUS_DLL_NOT_FOUND; + return; +@@ -2091,6 +2140,7 @@ static NTSTATUS load_native_dll( LPCWSTR load_path, LPCWSTR name, LPCWSTR fakemo + /* the module has only be inserted in the load & memory order lists */ + RemoveEntryList(&wm->ldr.InLoadOrderModuleList); + RemoveEntryList(&wm->ldr.InMemoryOrderModuleList); ++ RemoveEntryList(&wm->ldr.HashLinks); + + /* FIXME: there are several more dangling references + * left. Including dlls loaded by this dll before the +@@ -3217,6 +3267,7 @@ static void free_modref( WINE_MODREF *wm ) + { + RemoveEntryList(&wm->ldr.InLoadOrderModuleList); + RemoveEntryList(&wm->ldr.InMemoryOrderModuleList); ++ RemoveEntryList(&wm->ldr.HashLinks); + if (wm->ldr.InInitializationOrderModuleList.Flink) + RemoveEntryList(&wm->ldr.InInitializationOrderModuleList); + +@@ -3507,6 +3558,9 @@ void WINAPI LdrInitializeThunk( void *kernel_start, ULONG_PTR unknown2, + RemoveEntryList( &wm->ldr.InMemoryOrderModuleList ); + InsertHeadList( &peb->LdrData->InMemoryOrderModuleList, &wm->ldr.InMemoryOrderModuleList ); + ++ /* the windows version was not set yet when ntdll and kernel32 were loaded */ ++ recompute_hash_map(); ++ + if ((status = virtual_alloc_thread_stack( NtCurrentTeb(), 0, 0 )) != STATUS_SUCCESS) goto error; + if ((status = server_init_process_done()) != STATUS_SUCCESS) goto error; + +@@ -3710,6 +3764,7 @@ void __wine_process_init(void) + NTSTATUS status; + ANSI_STRING func_name; + void (* DECLSPEC_NORETURN CDECL init_func)(void); ++ DWORD i; + + main_exe_file = thread_init(); + +@@ -3719,6 +3774,10 @@ void __wine_process_init(void) + + load_global_options(); + ++ /* initialize hash table */ ++ for (i = 0; i < HASH_MAP_SIZE; i++) ++ InitializeListHead(&hash_table[i]); ++ + /* setup the load callback and create ntdll modref */ + wine_dll_set_callback( load_builtin_callback ); + +diff --git a/include/winternl.h b/include/winternl.h +index 2685137d6a..d6f47ad3ba 100644 +--- a/include/winternl.h ++++ b/include/winternl.h +@@ -2171,8 +2171,7 @@ typedef struct _LDR_MODULE + ULONG Flags; + SHORT LoadCount; + SHORT TlsIndex; +- HANDLE SectionHandle; +- ULONG CheckSum; ++ LIST_ENTRY HashLinks; + ULONG TimeDateStamp; + HANDLE ActivationContext; + PVOID PatchInformation; +@@ -2182,6 +2181,9 @@ typedef struct _LDR_MODULE + PVOID ContextInformation; + ULONG_PTR OriginalBase; + LARGE_INTEGER LoadTime; ++ ++ /* Not part of Win7 but used by Wine */ ++ HANDLE SectionHandle; + } LDR_MODULE, *PLDR_MODULE; + + /* those defines are (some of the) regular LDR_MODULE.Flags values */ +-- +2.11.0 + diff --git a/patches/ntdll-HashLinks/0002-ntdll-Use-HashLinks-when-searching-for-a-dll-using-t.patch b/patches/ntdll-HashLinks/0002-ntdll-Use-HashLinks-when-searching-for-a-dll-using-t.patch new file mode 100644 index 00000000..8589df2e --- /dev/null +++ b/patches/ntdll-HashLinks/0002-ntdll-Use-HashLinks-when-searching-for-a-dll-using-t.patch @@ -0,0 +1,29 @@ +From bcf36a9100a2452469c0058798073a72e1dba8f9 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Michael=20M=C3=BCller?= +Date: Mon, 3 Apr 2017 05:56:19 +0200 +Subject: ntdll: Use HashLinks when searching for a dll using the basename. + +--- + dlls/ntdll/loader.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/dlls/ntdll/loader.c b/dlls/ntdll/loader.c +index d9b6b7d1c7..7f0d2e7375 100644 +--- a/dlls/ntdll/loader.c ++++ b/dlls/ntdll/loader.c +@@ -509,10 +509,10 @@ static WINE_MODREF *find_basename_module( LPCWSTR name ) + if (cached_modref && !strcmpiW( name, cached_modref->ldr.BaseDllName.Buffer )) + return cached_modref; + +- mark = &NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList; ++ mark = &hash_table[hash_basename(name)]; + for (entry = mark->Flink; entry != mark; entry = entry->Flink) + { +- LDR_MODULE *mod = CONTAINING_RECORD(entry, LDR_MODULE, InLoadOrderModuleList); ++ LDR_MODULE *mod = CONTAINING_RECORD(entry, LDR_MODULE, HashLinks); + if (!strcmpiW( name, mod->BaseDllName.Buffer )) + { + cached_modref = CONTAINING_RECORD(mod, WINE_MODREF, ldr); +-- +2.11.0 + diff --git a/patches/ntdll-HashLinks/definition b/patches/ntdll-HashLinks/definition new file mode 100644 index 00000000..3303059a --- /dev/null +++ b/patches/ntdll-HashLinks/definition @@ -0,0 +1,3 @@ +Fixes: Implement and use hash links when looking up LDR module +Depends: ntdll-LDR_MODULE +Depends: ntdll-CLI_Images diff --git a/patches/patchinstall.sh b/patches/patchinstall.sh index c78989aa..4d79f602 100755 --- a/patches/patchinstall.sh +++ b/patches/patchinstall.sh @@ -233,6 +233,7 @@ patch_enable_all () enable_ntdll_FileNameInformation="$1" enable_ntdll_Fix_Alignment="$1" enable_ntdll_Grow_Virtual_Heap="$1" + enable_ntdll_HashLinks="$1" enable_ntdll_Heap_FreeLists="$1" enable_ntdll_Hide_Wine_Exports="$1" enable_ntdll_Interrupt_0x2e="$1" @@ -928,6 +929,9 @@ patch_enable () ntdll-Grow_Virtual_Heap) enable_ntdll_Grow_Virtual_Heap="$2" ;; + ntdll-HashLinks) + enable_ntdll_HashLinks="$2" + ;; ntdll-Heap_FreeLists) enable_ntdll_Heap_FreeLists="$2" ;; @@ -2370,6 +2374,17 @@ if test "$enable_ntdll_Hide_Wine_Exports" -eq 1; then enable_ntdll_ThreadTime=1 fi +if test "$enable_ntdll_HashLinks" -eq 1; then + if test "$enable_ntdll_CLI_Images" -gt 1; then + abort "Patchset ntdll-CLI_Images disabled, but ntdll-HashLinks depends on that." + fi + if test "$enable_ntdll_LDR_MODULE" -gt 1; then + abort "Patchset ntdll-LDR_MODULE disabled, but ntdll-HashLinks depends on that." + fi + enable_ntdll_CLI_Images=1 + enable_ntdll_LDR_MODULE=1 +fi + if test "$enable_ntdll_DllRedirects" -eq 1; then if test "$enable_ntdll_Attach_Process_DLLs" -gt 1; then abort "Patchset ntdll-Attach_Process_DLLs disabled, but ntdll-DllRedirects depends on that." @@ -5393,6 +5408,37 @@ if test "$enable_ntdll_Grow_Virtual_Heap" -eq 1; then ) >> "$patchlist" fi +# Patchset ntdll-LDR_MODULE +# | +# | Modified files: +# | * dlls/ntdll/thread.c, include/winternl.h +# | +if test "$enable_ntdll_LDR_MODULE" -eq 1; then + patch_apply ntdll-LDR_MODULE/0001-ntdll-Mark-LDR-data-as-initialized.patch + patch_apply ntdll-LDR_MODULE/0002-include-Update-LDR_MODULE-to-more-recent-windows-ver.patch + ( + printf '%s\n' '+ { "Michael Müller", "ntdll: Mark LDR data as initialized.", 1 },'; + printf '%s\n' '+ { "Michael Müller", "include: Update LDR_MODULE to more recent windows versions.", 1 },'; + ) >> "$patchlist" +fi + +# Patchset ntdll-HashLinks +# | +# | This patchset has the following (direct or indirect) dependencies: +# | * mscoree-CorValidateImage, ntdll-CLI_Images, ntdll-LDR_MODULE +# | +# | Modified files: +# | * dlls/kernel32/tests/loader.c, dlls/ntdll/loader.c, include/winternl.h +# | +if test "$enable_ntdll_HashLinks" -eq 1; then + patch_apply ntdll-HashLinks/0001-ntdll-Implement-HashLinks-field-in-LDR-module-data.patch + patch_apply ntdll-HashLinks/0002-ntdll-Use-HashLinks-when-searching-for-a-dll-using-t.patch + ( + printf '%s\n' '+ { "Michael Müller", "ntdll: Implement HashLinks field in LDR module data.", 1 },'; + printf '%s\n' '+ { "Michael Müller", "ntdll: Use HashLinks when searching for a dll using the basename.", 1 },'; + ) >> "$patchlist" +fi + # Patchset ntdll-Heap_FreeLists # | # | Modified files: @@ -5510,20 +5556,6 @@ if test "$enable_ntdll_Junction_Points" -eq 1; then ) >> "$patchlist" fi -# Patchset ntdll-LDR_MODULE -# | -# | Modified files: -# | * dlls/ntdll/thread.c, include/winternl.h -# | -if test "$enable_ntdll_LDR_MODULE" -eq 1; then - patch_apply ntdll-LDR_MODULE/0001-ntdll-Mark-LDR-data-as-initialized.patch - patch_apply ntdll-LDR_MODULE/0002-include-Update-LDR_MODULE-to-more-recent-windows-ver.patch - ( - printf '%s\n' '+ { "Michael Müller", "ntdll: Mark LDR data as initialized.", 1 },'; - printf '%s\n' '+ { "Michael Müller", "include: Update LDR_MODULE to more recent windows versions.", 1 },'; - ) >> "$patchlist" -fi - # Patchset ntdll-RtlQueryPackageIdentity # | # | Modified files: