From adb532903c6b0a3b1360d2e4105b8d2c25878e21 Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Wed, 14 May 2003 19:51:14 +0000 Subject: [PATCH] Rewrote module TLS support and moved it to ntdll. --- dlls/ntdll/loader.c | 138 ++++++++++++++++++++++++++++++++++++++++++++-------- include/module.h | 5 +- loader/pe_image.c | 53 -------------------- scheduler/process.c | 1 - scheduler/thread.c | 1 - 5 files changed, 120 insertions(+), 78 deletions(-) diff --git a/dlls/ntdll/loader.c b/dlls/ntdll/loader.c index e7dd55158f2..660d0945913 100644 --- a/dlls/ntdll/loader.c +++ b/dlls/ntdll/loader.c @@ -63,6 +63,10 @@ static const char * const reason_names[] = "THREAD_DETACH" }; +static UINT tls_module_count; /* number of modules with TLS directory */ +static UINT tls_total_size; /* total size of TLS storage */ +static const IMAGE_TLS_DIRECTORY **tls_dirs; /* array of TLS directories */ + static CRITICAL_SECTION loader_section = CRITICAL_SECTION_INIT( "loader_section" ); static WINE_MODREF *cached_modref; static WINE_MODREF *current_modref; @@ -399,6 +403,92 @@ WINE_MODREF *MODULE_AllocModRef( HMODULE hModule, LPCSTR filename ) /************************************************************************* + * alloc_process_tls + * + * Allocate the process-wide structure for module TLS storage. + */ +static NTSTATUS alloc_process_tls(void) +{ + WINE_MODREF *wm; + IMAGE_TLS_DIRECTORY *dir; + ULONG size, i; + + for (wm = MODULE_modref_list; wm; wm = wm->next) + { + if (!(dir = RtlImageDirectoryEntryToData( wm->ldr.BaseAddress, TRUE, + IMAGE_DIRECTORY_ENTRY_TLS, &size ))) + continue; + size = (dir->EndAddressOfRawData - dir->StartAddressOfRawData) + dir->SizeOfZeroFill; + if (!size) continue; + tls_total_size += size; + tls_module_count++; + } + if (!tls_module_count) return STATUS_SUCCESS; + + TRACE( "count %u size %u\n", tls_module_count, tls_total_size ); + + tls_dirs = RtlAllocateHeap( ntdll_get_process_heap(), 0, tls_module_count * sizeof(*tls_dirs) ); + if (!tls_dirs) return STATUS_NO_MEMORY; + + for (i = 0, wm = MODULE_modref_list; wm; wm = wm->next) + { + if (!(dir = RtlImageDirectoryEntryToData( wm->ldr.BaseAddress, TRUE, + IMAGE_DIRECTORY_ENTRY_TLS, &size ))) + continue; + tls_dirs[i] = dir; + *dir->AddressOfIndex = i; + wm->ldr.TlsIndex = i; + wm->ldr.LoadCount = -1; /* can't unload it */ + i++; + } + return STATUS_SUCCESS; +} + + +/************************************************************************* + * alloc_thread_tls + * + * Allocate the per-thread structure for module TLS storage. + */ +static NTSTATUS alloc_thread_tls(void) +{ + void **pointers; + char *data; + UINT i; + + if (!tls_module_count) return STATUS_SUCCESS; + + if (!(pointers = RtlAllocateHeap( ntdll_get_process_heap(), 0, + tls_module_count * sizeof(*pointers) ))) + return STATUS_NO_MEMORY; + + if (!(data = RtlAllocateHeap( ntdll_get_process_heap(), 0, tls_total_size ))) + { + RtlFreeHeap( ntdll_get_process_heap(), 0, pointers ); + return STATUS_NO_MEMORY; + } + + for (i = 0; i < tls_module_count; i++) + { + const IMAGE_TLS_DIRECTORY *dir = tls_dirs[i]; + ULONG size = dir->EndAddressOfRawData - dir->StartAddressOfRawData; + + TRACE( "thread %04lx idx %d: %ld/%ld bytes from %p to %p\n", + GetCurrentThreadId(), i, size, dir->SizeOfZeroFill, + (void *)dir->StartAddressOfRawData, data ); + + pointers[i] = data; + memcpy( data, (void *)dir->StartAddressOfRawData, size ); + data += size; + memset( data, 0, dir->SizeOfZeroFill ); + data += dir->SizeOfZeroFill; + } + NtCurrentTeb()->tls_ptr = pointers; + return STATUS_SUCCESS; +} + + +/************************************************************************* * call_tls_callbacks */ static void call_tls_callbacks( HMODULE module, UINT reason ) @@ -492,9 +582,9 @@ static BOOL MODULE_InitDLL( WINE_MODREF *wm, UINT reason, LPVOID lpReserved ) * detach notifications are called in the reverse of the sequence the attach * notifications *returned*. */ -BOOL MODULE_DllProcessAttach( WINE_MODREF *wm, LPVOID lpReserved ) +NTSTATUS MODULE_DllProcessAttach( WINE_MODREF *wm, LPVOID lpReserved ) { - BOOL retv = TRUE; + NTSTATUS status = STATUS_SUCCESS; int i; RtlEnterCriticalSection( &loader_section ); @@ -502,7 +592,9 @@ BOOL MODULE_DllProcessAttach( WINE_MODREF *wm, LPVOID lpReserved ) if (!wm) { wm = exe_modref; - PE_InitTls(); + wm->ldr.LoadCount = -1; /* can't unload main exe */ + if ((status = alloc_process_tls()) != STATUS_SUCCESS) goto done; + if ((status = alloc_thread_tls()) != STATUS_SUCCESS) goto done; } assert( wm ); @@ -517,22 +609,26 @@ BOOL MODULE_DllProcessAttach( WINE_MODREF *wm, LPVOID lpReserved ) wm->ldr.Flags |= LDR_LOAD_IN_PROGRESS; /* Recursively attach all DLLs this one depends on */ - for ( i = 0; retv && i < wm->nDeps; i++ ) - if ( wm->deps[i] ) - retv = MODULE_DllProcessAttach( wm->deps[i], lpReserved ); + for ( i = 0; i < wm->nDeps; i++ ) + { + if (!wm->deps[i]) continue; + if ((status = MODULE_DllProcessAttach( wm->deps[i], lpReserved )) != STATUS_SUCCESS) break; + } /* Call DLL entry point */ - if ( retv ) + if (status == STATUS_SUCCESS) { WINE_MODREF *prev = current_modref; current_modref = wm; - retv = MODULE_InitDLL( wm, DLL_PROCESS_ATTACH, lpReserved ); - if (retv) wm->ldr.Flags |= LDR_PROCESS_ATTACHED; + if (MODULE_InitDLL( wm, DLL_PROCESS_ATTACH, lpReserved )) + wm->ldr.Flags |= LDR_PROCESS_ATTACHED; + else + status = STATUS_DLL_INIT_FAILED; current_modref = prev; } /* Re-insert MODREF at head of list */ - if ( retv && wm->prev ) + if (status == STATUS_SUCCESS && wm->prev ) { wm->prev->next = wm->next; if ( wm->next ) wm->next->prev = wm->prev; @@ -547,10 +643,9 @@ BOOL MODULE_DllProcessAttach( WINE_MODREF *wm, LPVOID lpReserved ) TRACE("(%s,%p) - END\n", wm->modname, lpReserved ); - done: RtlLeaveCriticalSection( &loader_section ); - return retv; + return status; } /************************************************************************* @@ -573,7 +668,7 @@ static void MODULE_DllProcessDetach( BOOL bForceDetach, LPVOID lpReserved ) /* Check whether to detach this DLL */ if ( !(wm->ldr.Flags & LDR_PROCESS_ATTACHED) ) continue; - if ( wm->ldr.LoadCount > 0 && !bForceDetach ) + if ( wm->ldr.LoadCount && !bForceDetach ) continue; /* Call detach notification */ @@ -596,17 +691,18 @@ static void MODULE_DllProcessDetach( BOOL bForceDetach, LPVOID lpReserved ) * reverse sequence of process detach notification. * */ -void MODULE_DllThreadAttach( LPVOID lpReserved ) +NTSTATUS MODULE_DllThreadAttach( LPVOID lpReserved ) { WINE_MODREF *wm; + NTSTATUS status; /* don't do any attach calls if process is exiting */ - if (process_detaching) return; + if (process_detaching) return STATUS_SUCCESS; /* FIXME: there is still a race here */ RtlEnterCriticalSection( &loader_section ); - PE_InitTls(); + if ((status = alloc_thread_tls()) != STATUS_SUCCESS) goto done; for ( wm = MODULE_modref_list; wm; wm = wm->next ) if ( !wm->next ) @@ -622,7 +718,9 @@ void MODULE_DllThreadAttach( LPVOID lpReserved ) MODULE_InitDLL( wm, DLL_THREAD_ATTACH, lpReserved ); } +done: RtlLeaveCriticalSection( &loader_section ); + return status; } /****************************************************************** @@ -922,8 +1020,8 @@ static NTSTATUS load_dll( LPCSTR libname, DWORD flags, WINE_MODREF** pwm ) } if (*pwm) { - (*pwm)->ldr.LoadCount++; - + if ((*pwm)->ldr.LoadCount != -1) (*pwm)->ldr.LoadCount++; + if (((*pwm)->ldr.Flags & LDR_DONT_RESOLVE_REFS) && !(flags & DONT_RESOLVE_DLL_REFERENCES)) { @@ -1022,11 +1120,11 @@ NTSTATUS WINAPI LdrLoadDll(LPCWSTR path_name, DWORD flags, PUNICODE_STRING libna switch (nts = load_dll( str.Buffer, flags, &wm )) { case STATUS_SUCCESS: - if ( !MODULE_DllProcessAttach( wm, NULL ) ) + nts = MODULE_DllProcessAttach( wm, NULL ); + if (nts != STATUS_SUCCESS) { WARN("Attach failed for module '%s'.\n", str.Buffer); LdrUnloadDll(wm->ldr.BaseAddress); - nts = STATUS_DLL_INIT_FAILED; wm = NULL; } break; diff --git a/include/module.h b/include/module.h index 96837185fe6..0bea5928f31 100644 --- a/include/module.h +++ b/include/module.h @@ -181,8 +181,8 @@ enum binary_type }; /* module.c */ -extern BOOL MODULE_DllProcessAttach( WINE_MODREF *wm, LPVOID lpReserved ); -extern void MODULE_DllThreadAttach( LPVOID lpReserved ); +extern NTSTATUS MODULE_DllProcessAttach( WINE_MODREF *wm, LPVOID lpReserved ); +extern NTSTATUS MODULE_DllThreadAttach( LPVOID lpReserved ); extern WINE_MODREF *MODULE_FindModule( LPCSTR path ); extern HMODULE16 MODULE_CreateDummyModule( LPCSTR filename, HMODULE module32 ); extern enum binary_type MODULE_GetBinaryType( HANDLE hfile ); @@ -224,7 +224,6 @@ extern NTSTATUS PE_LoadLibraryExA(LPCSTR, DWORD, WINE_MODREF**); extern HMODULE PE_LoadImage( HANDLE hFile, LPCSTR filename, DWORD flags ); extern WINE_MODREF *PE_CreateModule( HMODULE hModule, LPCSTR filename, DWORD flags, HANDLE hFile, BOOL builtin ); -extern void PE_InitTls(void); extern DWORD PE_fixup_imports(WINE_MODREF *wm); /* loader/loadorder.c */ diff --git a/loader/pe_image.c b/loader/pe_image.c index deffca76253..c74fe2d24ed 100644 --- a/loader/pe_image.c +++ b/loader/pe_image.c @@ -371,56 +371,3 @@ NTSTATUS PE_LoadLibraryExA (LPCSTR name, DWORD flags, WINE_MODREF** pwm) CloseHandle( hFile ); return STATUS_SUCCESS; } - - -/************************************************************************ - * PE_InitTls (internal) - * - * If included, initialises the thread local storages of modules. - * Pointers in those structs are not RVAs but real pointers which have been - * relocated by do_relocations() already. - */ -static LPVOID -_fixup_address(PIMAGE_OPTIONAL_HEADER opt,int delta,LPVOID addr) { - if ( ((DWORD)addr>opt->ImageBase) && - ((DWORD)addrImageBase+opt->SizeOfImage) - ) - /* the address has not been relocated! */ - return (LPVOID)(((DWORD)addr)+delta); - else - /* the address has been relocated already */ - return addr; -} - -void PE_InitTls( void ) -{ - WINE_MODREF *wm; - IMAGE_NT_HEADERS *peh; - DWORD size,datasize,dirsize; - LPVOID mem; - PIMAGE_TLS_DIRECTORY pdir; - int delta; - - for (wm = MODULE_modref_list;wm;wm=wm->next) { - peh = RtlImageNtHeader(wm->ldr.BaseAddress); - pdir = RtlImageDirectoryEntryToData( wm->ldr.BaseAddress, TRUE, - IMAGE_DIRECTORY_ENTRY_TLS, &dirsize ); - if (!pdir) continue; - delta = (char *)wm->ldr.BaseAddress - (char *)peh->OptionalHeader.ImageBase; - - if ( wm->ldr.TlsIndex == -1 ) { - LPDWORD xaddr; - wm->ldr.TlsIndex = TlsAlloc(); - xaddr = _fixup_address(&(peh->OptionalHeader),delta, - pdir->AddressOfIndex - ); - *xaddr=wm->ldr.TlsIndex; - } - datasize= pdir->EndAddressOfRawData-pdir->StartAddressOfRawData; - size = datasize + pdir->SizeOfZeroFill; - NtAllocateVirtualMemory( GetCurrentProcess(), &mem, NULL, &size, - MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE ); - memcpy(mem,_fixup_address(&(peh->OptionalHeader),delta,(LPVOID)pdir->StartAddressOfRawData),datasize); - TlsSetValue( wm->ldr.TlsIndex, mem ); - } -} diff --git a/scheduler/process.c b/scheduler/process.c index 72c8a809472..410a6ffb26c 100644 --- a/scheduler/process.c +++ b/scheduler/process.c @@ -539,7 +539,6 @@ static void start_process(void) /* create the main modref and load dependencies */ if (!(wm = PE_CreateModule( current_process.module, main_exe_name, 0, 0, FALSE ))) goto error; - wm->ldr.LoadCount++; if (main_exe_file) CloseHandle( main_exe_file ); /* we no longer need it */ diff --git a/scheduler/thread.c b/scheduler/thread.c index 87e312eeb01..a485ce66850 100644 --- a/scheduler/thread.c +++ b/scheduler/thread.c @@ -96,7 +96,6 @@ static BOOL THREAD_InitTEB( TEB *teb ) teb->except = (void *)~0UL; teb->self = teb; teb->tibflags = TEBF_WIN32; - teb->tls_ptr = teb->tls_array; teb->exit_code = STILL_ACTIVE; teb->request_fd = -1; teb->reply_fd = -1; -- 2.11.4.GIT