Commit 99cdacb9 authored by Alexandre Julliard's avatar Alexandre Julliard

msvcp90/tests: Dynamically generate a thunk to call thiscall functions.

It's not possible to do this correctly with inline assembly.
parent 718c6149
...@@ -65,97 +65,43 @@ static void __cdecl test_invalid_parameter_handler(const wchar_t *expression, ...@@ -65,97 +65,43 @@ static void __cdecl test_invalid_parameter_handler(const wchar_t *expression,
/* Emulate a __thiscall */ /* Emulate a __thiscall */
#ifdef __i386__ #ifdef __i386__
#ifdef _MSC_VER
static inline void* do_call_func1(void *func, void *_this)
{
volatile void* retval = 0;
__asm
{
push ecx
mov ecx, _this
call func
mov retval, eax
pop ecx
}
return (void*)retval;
}
static inline void* do_call_func2(void *func, void *_this, const void *arg) #include "pshpack1.h"
struct thiscall_thunk
{ {
volatile void* retval = 0; BYTE pop_eax; /* popl %eax (ret addr) */
__asm BYTE pop_edx; /* popl %edx (func) */
{ BYTE pop_ecx; /* popl %ecx (this) */
push ecx BYTE push_eax; /* pushl %eax */
push arg WORD jmp_edx; /* jmp *%edx */
mov ecx, _this };
call func #include "poppack.h"
mov retval, eax
pop ecx static void * (WINAPI *call_thiscall_func1)( void *func, void *this );
} static void * (WINAPI *call_thiscall_func2)( void *func, void *this, const void *a );
return (void*)retval; static void * (WINAPI *call_thiscall_func3)( void *func, void *this, const void *a, const void *b );
}
static void init_thiscall_thunk(void)
static inline void* do_call_func3(void *func, void *_this,
const void *arg1, const void *arg2)
{ {
volatile void* retval = 0; struct thiscall_thunk *thunk = VirtualAlloc( NULL, sizeof(*thunk),
__asm MEM_COMMIT, PAGE_EXECUTE_READWRITE );
{ thunk->pop_eax = 0x58; /* popl %eax */
push ecx thunk->pop_edx = 0x5a; /* popl %edx */
push arg1 thunk->pop_ecx = 0x59; /* popl %ecx */
push arg2 thunk->push_eax = 0x50; /* pushl %eax */
mov ecx, _this thunk->jmp_edx = 0xe2ff; /* jmp *%edx */
call func call_thiscall_func1 = (void *)thunk;
mov retval, eax call_thiscall_func2 = (void *)thunk;
pop ecx call_thiscall_func3 = (void *)thunk;
}
return (void*)retval;
} }
#else
static void* do_call_func1(void *func, void *_this)
{
void *ret, *dummy;
__asm__ __volatile__ (
"call *%2"
: "=a" (ret), "=c" (dummy)
: "g" (func), "1" (_this)
: "edx", "memory"
);
return ret;
}
static void* do_call_func2(void *func, void *_this, const void *arg)
{
void *ret, *dummy;
__asm__ __volatile__ (
"pushl %3\n\tcall *%2"
: "=a" (ret), "=c" (dummy)
: "r" (func), "r" (arg), "1" (_this)
: "edx", "memory"
);
return ret;
}
static void* do_call_func3(void *func, void *_this,
const void *arg1, const void *arg2)
{
void *ret, *dummy;
__asm__ __volatile__ (
"pushl %4\n\tpushl %3\n\tcall *%2"
: "=a" (ret), "=c" (dummy)
: "r" (func), "r" (arg1), "r" (arg2), "1" (_this)
: "edx", "memory"
);
return ret;
}
#endif
#define call_func1(func,_this) do_call_func1(func,_this) #define call_func1(func,_this) call_thiscall_func1(func,_this)
#define call_func2(func,_this,a) do_call_func2(func,_this,(const void*)a) #define call_func2(func,_this,a) call_thiscall_func2(func,_this,(const void*)a)
#define call_func3(func,_this,a,b) do_call_func3(func,_this,(const void*)a,(const void*)b) #define call_func3(func,_this,a,b) call_thiscall_func3(func,_this,(const void*)a,(const void*)b)
#else #else
#define init_thiscall_thunk()
#define call_func1(func,_this) func(_this) #define call_func1(func,_this) func(_this)
#define call_func2(func,_this,a) func(_this,a) #define call_func2(func,_this,a) func(_this,a)
#define call_func3(func,_this,a,b) func(_this,a,b) #define call_func3(func,_this,a,b) func(_this,a,b)
...@@ -217,6 +163,7 @@ static BOOL init(void) ...@@ -217,6 +163,7 @@ static BOOL init(void)
SET(p_char_max_size, "?max_size@?$allocator@D@std@@QBEIXZ"); SET(p_char_max_size, "?max_size@?$allocator@D@std@@QBEIXZ");
} }
init_thiscall_thunk();
return TRUE; return TRUE;
} }
......
...@@ -127,201 +127,58 @@ static void __cdecl test_invalid_parameter_handler(const wchar_t *expression, ...@@ -127,201 +127,58 @@ static void __cdecl test_invalid_parameter_handler(const wchar_t *expression,
/* Emulate a __thiscall */ /* Emulate a __thiscall */
#ifdef __i386__ #ifdef __i386__
#ifdef _MSC_VER
static inline void* do_call_func1(void *func, void *_this)
{
volatile void* retval = 0;
__asm
{
push ecx
mov ecx, _this
call func
mov retval, eax
pop ecx
}
return (void*)retval;
}
static inline void* do_call_func2(void *func, void *_this, const void *arg)
{
volatile void* retval = 0;
__asm
{
push ecx
push arg
mov ecx, _this
call func
mov retval, eax
pop ecx
}
return (void*)retval;
}
static inline void* do_call_func3(void *func, void *_this,
const void *arg1, const void *arg2)
{
volatile void* retval = 0;
__asm
{
push ecx
push arg1
push arg2
mov ecx, _this
call func
mov retval, eax
pop ecx
}
return (void*)retval;
}
static inline void* do_call_func4(void *func, void *_this,
const void *arg1, const void *arg2, const void *arg3)
{
volatile void* retval = 0;
__asm
{
push ecx
push arg1
push arg2
push arg3
mov ecx, _this
call func
mov retval, eax
pop ecx
}
return (void*)retval;
}
static inline void* do_call_func5(void *func, void *_this,
const void *arg1, const void *arg2, const void *arg3, const void *arg4)
{
volatile void* retval = 0;
__asm
{
push ecx
push arg1
push arg2
push arg3
push arg4
mov ecx, _this
call func
mov retval, eax
pop ecx
}
return (void*)retval;
}
static inline void* do_call_func6(void *func, void *_this, #include "pshpack1.h"
const void *arg1, const void *arg2, const void *arg3, struct thiscall_thunk
const void *arg4, const void *arg5)
{ {
volatile void* retval = 0; BYTE pop_eax; /* popl %eax (ret addr) */
__asm BYTE pop_edx; /* popl %edx (func) */
{ BYTE pop_ecx; /* popl %ecx (this) */
push ecx BYTE push_eax; /* pushl %eax */
push arg1 WORD jmp_edx; /* jmp *%edx */
push arg2 };
push arg3 #include "poppack.h"
push arg4
push arg5 static void * (WINAPI *call_thiscall_func1)( void *func, void *this );
mov ecx, _this static void * (WINAPI *call_thiscall_func2)( void *func, void *this, const void *a );
call func static void * (WINAPI *call_thiscall_func3)( void *func, void *this, const void *a, const void *b );
mov retval, eax static void * (WINAPI *call_thiscall_func4)( void *func, void *this, const void *a, const void *b,
pop ecx const void *c );
} static void * (WINAPI *call_thiscall_func5)( void *func, void *this, const void *a, const void *b,
return (void*)retval; const void *c, const void *d );
} static void * (WINAPI *call_thiscall_func6)( void *func, void *this, const void *a, const void *b,
#else const void *c, const void *d, const void *e );
static void* do_call_func1(void *func, void *_this)
{ static void init_thiscall_thunk(void)
void *ret, *dummy;
__asm__ __volatile__ (
"call *%2"
: "=a" (ret), "=c" (dummy)
: "g" (func), "1" (_this)
: "edx", "memory"
);
return ret;
}
static void* do_call_func2(void *func, void *_this, const void *arg)
{ {
void *ret, *dummy; struct thiscall_thunk *thunk = VirtualAlloc( NULL, sizeof(*thunk),
__asm__ __volatile__ ( MEM_COMMIT, PAGE_EXECUTE_READWRITE );
"pushl %3\n\tcall *%2" thunk->pop_eax = 0x58; /* popl %eax */
: "=a" (ret), "=c" (dummy) thunk->pop_edx = 0x5a; /* popl %edx */
: "r" (func), "r" (arg), "1" (_this) thunk->pop_ecx = 0x59; /* popl %ecx */
: "edx", "memory" thunk->push_eax = 0x50; /* pushl %eax */
); thunk->jmp_edx = 0xe2ff; /* jmp *%edx */
return ret; call_thiscall_func1 = (void *)thunk;
call_thiscall_func2 = (void *)thunk;
call_thiscall_func3 = (void *)thunk;
call_thiscall_func4 = (void *)thunk;
call_thiscall_func5 = (void *)thunk;
call_thiscall_func6 = (void *)thunk;
} }
static void* do_call_func3(void *func, void *_this, #define call_func1(func,_this) call_thiscall_func1(func,_this)
const void *arg1, const void *arg2) #define call_func2(func,_this,a) call_thiscall_func2(func,_this,(const void*)a)
{ #define call_func3(func,_this,a,b) call_thiscall_func3(func,_this,(const void*)a,(const void*)b)
void *ret, *dummy; #define call_func4(func,_this,a,b,c) call_thiscall_func4(func,_this,(const void*)a,\
__asm__ __volatile__ (
"pushl %4\n\tpushl %3\n\tcall *%2"
: "=a" (ret), "=c" (dummy)
: "r" (func), "r" (arg1), "r" (arg2), "1" (_this)
: "edx", "memory"
);
return ret;
}
static void* do_call_func4(void *func, void *_this,
const void *arg1, const void *arg2, const void *arg3)
{
void *ret, *dummy;
__asm__ __volatile__ (
"pushl %5\n\tpushl %4\n\tpushl %3\n\tcall *%2"
: "=a" (ret), "=c" (dummy)
: "r" (func), "r" (arg1), "r" (arg2), "m" (arg3), "1" (_this)
: "edx", "memory"
);
return ret;
}
static void* do_call_func5(void *func, void *_this,
const void *arg1, const void *arg2, const void *arg3, const void *arg4)
{
void *ret, *dummy;
__asm__ __volatile__ (
"pushl %6\n\tpushl %5\n\tpushl %4\n\tpushl %3\n\tcall *%2"
: "=a" (ret), "=c" (dummy)
: "r" (func), "r" (arg1), "r" (arg2), "m" (arg3), "m" (arg4), "1" (_this)
: "edx", "memory"
);
return ret;
}
static void* do_call_func6(void *func, void *_this,
const void *arg1, const void *arg2, const void *arg3,
const void *arg4, const void *arg5)
{
void *ret, *dummy;
__asm__ __volatile__ (
"pushl %7\n\tpushl %6\n\tpushl %5\n\tpushl %4\n\tpushl %3\n\tcall *%2"
: "=a" (ret), "=c" (dummy)
: "r" (func), "r" (arg1), "r" (arg2), "m" (arg3), "m" (arg4), "m" (arg5), "1" (_this)
: "edx", "memory"
);
return ret;
}
#endif
#define call_func1(func,_this) do_call_func1(func,_this)
#define call_func2(func,_this,a) do_call_func2(func,_this,(const void*)a)
#define call_func3(func,_this,a,b) do_call_func3(func,_this,(const void*)a,(const void*)b)
#define call_func4(func,_this,a,b,c) do_call_func4(func,_this,(const void*)a,\
(const void*)b,(const void*)c) (const void*)b,(const void*)c)
#define call_func5(func,_this,a,b,c,d) do_call_func5(func,_this,(const void*)a,\ #define call_func5(func,_this,a,b,c,d) call_thiscall_func5(func,_this,(const void*)a,\
(const void*)b,(const void*)c,(const void*)d) (const void*)b,(const void*)c,(const void*)d)
#define call_func6(func,_this,a,b,c,d,e) do_call_func6(func,_this,(const void*)a,\ #define call_func6(func,_this,a,b,c,d,e) call_thiscall_func6(func,_this,(const void*)a,\
(const void*)b,(const void*)c,(const void*)d,(const void*)e) (const void*)b,(const void*)c,(const void*)d,(const void*)e)
#else #else
#define init_thiscall_thunk()
#define call_func1(func,_this) func(_this) #define call_func1(func,_this) func(_this)
#define call_func2(func,_this,a) func(_this,a) #define call_func2(func,_this,a) func(_this,a)
#define call_func3(func,_this,a,b) func(_this,a,b) #define call_func3(func,_this,a,b) func(_this,a,b)
...@@ -472,6 +329,7 @@ static BOOL init(void) ...@@ -472,6 +329,7 @@ static BOOL init(void)
"?swap@?$basic_string@_WU?$char_traits@_W@std@@V?$allocator@_W@2@@std@@QAEXAAV12@@Z"); "?swap@?$basic_string@_WU?$char_traits@_W@std@@V?$allocator@_W@2@@std@@QAEXAAV12@@Z");
} }
init_thiscall_thunk();
return TRUE; return TRUE;
} }
......
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