diff --git a/dlls/kernel32/tests/loader.c b/dlls/kernel32/tests/loader.c index 90e6d09740a..19f112efcd8 100644 --- a/dlls/kernel32/tests/loader.c +++ b/dlls/kernel32/tests/loader.c @@ -2144,6 +2144,19 @@ static void check_tls_index(HANDLE dll, BOOL tls_initialized) ok(found_dll, "Couldn't find dll %p in module list\n", dll); } +static int tls_init_fn_output; + +static DWORD WINAPI tls_thread_fn(void* tlsidx_v) +{ + int tls_index = (int)(DWORD_PTR)(tlsidx_v); + const char* str = ((char **)NtCurrentTeb()->ThreadLocalStoragePointer)[tls_index]; + ok( !strcmp( str, "hello world" ), "wrong tls data '%s' at %p\n", str, str ); + ok( tls_init_fn_output == DLL_THREAD_ATTACH, + "tls init function didn't run or got wrong reason: %d instead of %d\n", tls_init_fn_output, DLL_THREAD_ATTACH ); + tls_init_fn_output = 9999; + return 0; +} + static void test_import_resolution(void) { char temp_path[MAX_PATH]; @@ -2165,31 +2178,41 @@ static void test_import_resolution(void) char tls_data[16]; SHORT tls_index; SHORT tls_index_hi; - UCHAR tls_init_fn[64]; /* Note: Uses rip-relative address of tls_index, don't separate */ + int* tls_init_fn_output; + UCHAR tls_init_fn[64]; /* Note: Uses rip-relative address of tls_init_fn_output, don't separate */ + UCHAR entry_point_fn[16]; } data, *ptr; IMAGE_NT_HEADERS nt; IMAGE_SECTION_HEADER section; - int test; + int test, tls_index_save; #if defined(__i386__) static const UCHAR tls_init_code[] = { - 0xE8, 0x00, 0x00, 0x00, 0x00, /* call 1f */ - 0x59, /* 1: pop ecx */ - 0x8B, 0x49, 0xF7, /* mov ecx, [ecx - 9] ; mov ecx, [tls_index] */ - 0x64, 0x8B, 0x15, 0x2C, 0x00, 0x00, 0x00, /* mov edx, fs:0x2c */ - 0x8B, 0x14, 0x8A, /* mov edx, [edx + edx * 4] */ - 0xC6, 0x42, 0x05, 0x21, /* mov byte [edx + 5], 0x21 */ - 0xC2, 0x0C, 0x00, /* ret 12 */ + 0xE8, 0x00, 0x00, 0x00, 0x00, /* call 1f */ + 0x59, /* 1: pop ecx */ + 0x8B, 0x49, 0xF7, /* mov ecx, [ecx - 9] ; mov ecx, [tls_init_fn_output] */ + 0x8B, 0x54, 0x24, 0x08, /* mov edx, [esp + 8] */ + 0x89, 0x11, /* mov [ecx], edx */ + 0xB8, 0x01, 0x00, 0x00, 0x00, /* mov eax, 1 */ + 0xC2, 0x0C, 0x00, /* ret 12 */ + }; + static const UCHAR entry_point_code[] = { + 0xB8, 0x01, 0x00, 0x00, 0x00, /* mov eax, 1 */ + 0xC2, 0x0C, 0x00, /* ret 12 */ }; #elif defined(__x86_64__) static const UCHAR tls_init_code[] = { - 0x8B, 0x0D, 0xF6, 0xFF, 0xFF, 0xFF, /* mov ecx, [rip + tls_index] */ - 0x65, 0x48, 0x8B, 0x14, 0x25, 0x58, 0x00, 0x00, 0x00, /* mov rdx, gs:0x58 */ - 0x48, 0x8B, 0x14, 0xCA, /* mov rdx, [rdx + rcx * 8] */ - 0xC6, 0x42, 0x05, 0x21, /* mov byte [rdx + 5], 0x21 */ - 0xC3, /* ret */ + 0x48, 0x8B, 0x0D, 0xF1, 0xFF, 0xFF, 0xFF, /* mov rcx, [rip + tls_init_fn_output] */ + 0x89, 0x11, /* mov [rcx], edx */ + 0xB8, 0x01, 0x00, 0x00, 0x00, /* mov eax, 1 */ + 0xC3, /* ret */ + }; + static const UCHAR entry_point_code[] = { + 0xB8, 0x01, 0x00, 0x00, 0x00, /* mov eax, 1 */ + 0xC3, /* ret */ }; #else static const UCHAR tls_init_code[] = { 0x00 }; + static const UCHAR entry_point_code[] = { 0x00 }; #endif for (test = 0; test < 4; test++) @@ -2230,10 +2253,16 @@ static void test_import_resolution(void) if (test == 3 && sizeof(tls_init_code) > 1) { + /* Windows doesn't consistently call tls init functions on dlls without entry points */ assert(sizeof(tls_init_code) <= sizeof(data.tls_init_fn)); + assert(sizeof(entry_point_code) <= sizeof(data.entry_point_fn)); memcpy(data.tls_init_fn, tls_init_code, sizeof(tls_init_code)); + memcpy(data.entry_point_fn, entry_point_code, sizeof(entry_point_code)); + tls_init_fn_output = 9999; + data.tls_init_fn_output = &tls_init_fn_output; data.tls_init_fn_list[0] = nt.OptionalHeader.ImageBase + DATA_RVA(&data.tls_init_fn); data.tls.AddressOfCallBacks = nt.OptionalHeader.ImageBase + DATA_RVA(&data.tls_init_fn_list); + nt.OptionalHeader.AddressOfEntryPoint = DATA_RVA(&data.entry_point_fn); } GetTempPathA(MAX_PATH, temp_path); @@ -2315,16 +2344,27 @@ static void test_import_resolution(void) ok( mod != NULL, "failed to load err %lu\n", GetLastError() ); if (!mod) break; ptr = (struct imports *)((char *)mod + page_size); + tls_index_save = ptr->tls_index; ok( ptr->tls_index < 32 || broken(ptr->tls_index == 9999), /* before vista */ "wrong tls index %d\n", ptr->tls_index ); if (ptr->tls_index != 9999 && sizeof(tls_init_code) > 1) { - /* tls init function will write an '!' over the space in "hello world" */ str = ((char **)NtCurrentTeb()->ThreadLocalStoragePointer)[ptr->tls_index]; - ok( !strcmp( str, "hello!world" ), "wrong tls data '%s' at %p\n", str, str ); + ok( !strcmp( str, "hello world" ), "wrong tls data '%s' at %p\n", str, str ); + /* tls init function will write the reason to *tls_init_fn_output */ + ok( tls_init_fn_output == DLL_PROCESS_ATTACH, + "tls init function didn't run or got wrong reason: %d instead of %d\n", tls_init_fn_output, DLL_PROCESS_ATTACH ); + tls_init_fn_output = 9999; + WaitForSingleObject(CreateThread(NULL, 0, tls_thread_fn, (void*)(DWORD_PTR)ptr->tls_index, 0, NULL), INFINITE); + ok( tls_init_fn_output == DLL_THREAD_DETACH, + "tls init function didn't run or got wrong reason: %d instead of %d\n", tls_init_fn_output, DLL_THREAD_DETACH ); } check_tls_index(mod, ptr->tls_index != 9999); + tls_init_fn_output = 9999; FreeLibrary( mod ); + if (tls_index_save != 9999 && sizeof(tls_init_code) > 1) + ok( tls_init_fn_output == DLL_PROCESS_DETACH, + "tls init function didn't run or got wrong reason: %d instead of %d\n", tls_init_fn_output, DLL_PROCESS_DETACH ); } DeleteFileA( dll_name ); #undef DATA_RVA