Commit 2203a856 authored by Evan Tang's avatar Evan Tang Committed by Alexandre Julliard

kernel32/tests: Add test verifying that tls init functions are called.

parent 18338874
...@@ -2134,14 +2134,38 @@ static void test_import_resolution(void) ...@@ -2134,14 +2134,38 @@ static void test_import_resolution(void)
char module[16]; char module[16];
struct { WORD hint; char name[32]; } function; struct { WORD hint; char name[32]; } function;
IMAGE_TLS_DIRECTORY tls; IMAGE_TLS_DIRECTORY tls;
UINT_PTR tls_init_fn_list[2];
char tls_data[16]; char tls_data[16];
SHORT tls_index; SHORT tls_index;
SHORT tls_index_hi;
UCHAR tls_init_fn[64]; /* Note: Uses rip-relative address of tls_index, don't separate */
} data, *ptr; } data, *ptr;
IMAGE_NT_HEADERS nt; IMAGE_NT_HEADERS nt;
IMAGE_SECTION_HEADER section; IMAGE_SECTION_HEADER section;
int test; int test;
#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 */
};
#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 */
};
#else
static const UCHAR tls_init_code[] = { 0x00 };
#endif
for (test = 0; test < 3; test++) for (test = 0; test < 4; test++)
{ {
#define DATA_RVA(ptr) (page_size + ((char *)(ptr) - (char *)&data)) #define DATA_RVA(ptr) (page_size + ((char *)(ptr) - (char *)&data))
nt = nt_header_template; nt = nt_header_template;
...@@ -2175,6 +2199,15 @@ static void test_import_resolution(void) ...@@ -2175,6 +2199,15 @@ static void test_import_resolution(void)
data.tls.AddressOfIndex = nt.OptionalHeader.ImageBase + DATA_RVA( &data.tls_index ); data.tls.AddressOfIndex = nt.OptionalHeader.ImageBase + DATA_RVA( &data.tls_index );
strcpy( data.tls_data, "hello world" ); strcpy( data.tls_data, "hello world" );
data.tls_index = 9999; data.tls_index = 9999;
data.tls_index_hi = 9999;
if (test == 3 && sizeof(tls_init_code) > 1)
{
assert(sizeof(tls_init_code) <= sizeof(data.tls_init_fn));
memcpy(data.tls_init_fn, tls_init_code, sizeof(tls_init_code));
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);
}
GetTempPathA(MAX_PATH, temp_path); GetTempPathA(MAX_PATH, temp_path);
GetTempFileNameA(temp_path, "ldr", 0, dll_name); GetTempFileNameA(temp_path, "ldr", 0, dll_name);
...@@ -2189,6 +2222,7 @@ static void test_import_resolution(void) ...@@ -2189,6 +2222,7 @@ static void test_import_resolution(void)
section.Misc.VirtualSize = sizeof(data); section.Misc.VirtualSize = sizeof(data);
section.SizeOfRawData = sizeof(data); section.SizeOfRawData = sizeof(data);
section.Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE; section.Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE;
if (test == 3) section.Characteristics |= IMAGE_SCN_MEM_EXECUTE;
WriteFile(hfile, &dos_header, sizeof(dos_header), &dummy, NULL); WriteFile(hfile, &dos_header, sizeof(dos_header), &dummy, NULL);
WriteFile(hfile, &nt, sizeof(nt), &dummy, NULL); WriteFile(hfile, &nt, sizeof(nt), &dummy, NULL);
...@@ -2215,6 +2249,7 @@ static void test_import_resolution(void) ...@@ -2215,6 +2249,7 @@ static void test_import_resolution(void)
{ {
str = ((char **)NtCurrentTeb()->ThreadLocalStoragePointer)[ptr->tls_index]; 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 );
ok(ptr->tls_index_hi == 0, "TLS Index written as a short, high half: %d\n", ptr->tls_index_hi);
} }
FreeLibrary( mod ); FreeLibrary( mod );
break; break;
...@@ -2245,6 +2280,20 @@ static void test_import_resolution(void) ...@@ -2245,6 +2280,20 @@ static void test_import_resolution(void)
ok( ptr->tls_index == 9999, "wrong tls index %d\n", ptr->tls_index ); ok( ptr->tls_index == 9999, "wrong tls index %d\n", ptr->tls_index );
FreeLibrary( mod ); FreeLibrary( mod );
break; break;
case 3: /* load with tls init function */
mod = LoadLibraryA( dll_name );
ok( mod != NULL, "failed to load err %lu\n", GetLastError() );
if (!mod) break;
ptr = (struct imports *)((char *)mod + page_size);
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 );
}
FreeLibrary( mod );
} }
DeleteFileA( dll_name ); DeleteFileA( dll_name );
#undef DATA_RVA #undef DATA_RVA
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment