msvcp90/tests: Dynamically generate a thunk to call thiscall functions.
It's not possible to do this correctly with inline assembly.
This commit is contained in:
parent
718c614937
commit
99cdacb93b
|
@ -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)
|
#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 */
|
||||||
mov ecx, _this
|
WORD jmp_edx; /* jmp *%edx */
|
||||||
call func
|
};
|
||||||
mov retval, eax
|
#include "poppack.h"
|
||||||
pop ecx
|
|
||||||
}
|
static void * (WINAPI *call_thiscall_func1)( void *func, void *this );
|
||||||
return (void*)retval;
|
static void * (WINAPI *call_thiscall_func2)( void *func, void *this, const void *a );
|
||||||
|
static void * (WINAPI *call_thiscall_func3)( void *func, void *this, const void *a, const void *b );
|
||||||
|
|
||||||
|
static void init_thiscall_thunk(void)
|
||||||
|
{
|
||||||
|
struct thiscall_thunk *thunk = VirtualAlloc( NULL, sizeof(*thunk),
|
||||||
|
MEM_COMMIT, PAGE_EXECUTE_READWRITE );
|
||||||
|
thunk->pop_eax = 0x58; /* popl %eax */
|
||||||
|
thunk->pop_edx = 0x5a; /* popl %edx */
|
||||||
|
thunk->pop_ecx = 0x59; /* popl %ecx */
|
||||||
|
thunk->push_eax = 0x50; /* pushl %eax */
|
||||||
|
thunk->jmp_edx = 0xe2ff; /* jmp *%edx */
|
||||||
|
call_thiscall_func1 = (void *)thunk;
|
||||||
|
call_thiscall_func2 = (void *)thunk;
|
||||||
|
call_thiscall_func3 = (void *)thunk;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void* do_call_func2(void *func, void *_this, const void *arg)
|
#define call_func1(func,_this) call_thiscall_func1(func,_this)
|
||||||
{
|
#define call_func2(func,_this,a) call_thiscall_func2(func,_this,(const void*)a)
|
||||||
volatile void* retval = 0;
|
#define call_func3(func,_this,a,b) call_thiscall_func3(func,_this,(const void*)a,(const void*)b)
|
||||||
__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;
|
|
||||||
}
|
|
||||||
#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_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)
|
|
||||||
|
|
||||||
#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)
|
||||||
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,
|
||||||
|
|
||||||
/* Emulate a __thiscall */
|
/* Emulate a __thiscall */
|
||||||
#ifdef __i386__
|
#ifdef __i386__
|
||||||
#ifdef _MSC_VER
|
|
||||||
static inline void* do_call_func1(void *func, void *_this)
|
#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 */
|
||||||
mov ecx, _this
|
WORD jmp_edx; /* jmp *%edx */
|
||||||
call func
|
};
|
||||||
mov retval, eax
|
#include "poppack.h"
|
||||||
pop ecx
|
|
||||||
}
|
static void * (WINAPI *call_thiscall_func1)( void *func, void *this );
|
||||||
return (void*)retval;
|
static void * (WINAPI *call_thiscall_func2)( void *func, void *this, const void *a );
|
||||||
|
static void * (WINAPI *call_thiscall_func3)( void *func, void *this, const void *a, const void *b );
|
||||||
|
static void * (WINAPI *call_thiscall_func4)( void *func, void *this, const void *a, const void *b,
|
||||||
|
const void *c );
|
||||||
|
static void * (WINAPI *call_thiscall_func5)( void *func, void *this, const void *a, const void *b,
|
||||||
|
const void *c, const void *d );
|
||||||
|
static void * (WINAPI *call_thiscall_func6)( void *func, void *this, const void *a, const void *b,
|
||||||
|
const void *c, const void *d, const void *e );
|
||||||
|
|
||||||
|
static void init_thiscall_thunk(void)
|
||||||
|
{
|
||||||
|
struct thiscall_thunk *thunk = VirtualAlloc( NULL, sizeof(*thunk),
|
||||||
|
MEM_COMMIT, PAGE_EXECUTE_READWRITE );
|
||||||
|
thunk->pop_eax = 0x58; /* popl %eax */
|
||||||
|
thunk->pop_edx = 0x5a; /* popl %edx */
|
||||||
|
thunk->pop_ecx = 0x59; /* popl %ecx */
|
||||||
|
thunk->push_eax = 0x50; /* pushl %eax */
|
||||||
|
thunk->jmp_edx = 0xe2ff; /* jmp *%edx */
|
||||||
|
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 inline void* do_call_func2(void *func, void *_this, const void *arg)
|
#define call_func1(func,_this) call_thiscall_func1(func,_this)
|
||||||
{
|
#define call_func2(func,_this,a) call_thiscall_func2(func,_this,(const void*)a)
|
||||||
volatile void* retval = 0;
|
#define call_func3(func,_this,a,b) call_thiscall_func3(func,_this,(const void*)a,(const void*)b)
|
||||||
__asm
|
#define call_func4(func,_this,a,b,c) call_thiscall_func4(func,_this,(const void*)a,\
|
||||||
{
|
|
||||||
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,
|
|
||||||
const void *arg1, const void *arg2, const void *arg3,
|
|
||||||
const void *arg4, const void *arg5)
|
|
||||||
{
|
|
||||||
volatile void* retval = 0;
|
|
||||||
__asm
|
|
||||||
{
|
|
||||||
push ecx
|
|
||||||
push arg1
|
|
||||||
push arg2
|
|
||||||
push arg3
|
|
||||||
push arg4
|
|
||||||
push arg5
|
|
||||||
mov ecx, _this
|
|
||||||
call func
|
|
||||||
mov retval, eax
|
|
||||||
pop ecx
|
|
||||||
}
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
||||||
"?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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue