implemented thiscall by copying logic from fastcall
implemented improved thiscall by using mov ecx instead of pop ecx include __thiscall and __thiscall__ as aliases remove fake line in test
This commit is contained in:
parent
8cd21e91cc
commit
3b943bec5d
5 changed files with 51 additions and 3 deletions
26
i386-gen.c
26
i386-gen.c
|
@ -410,6 +410,8 @@ ST_FUNC void gfunc_call(int nb_args)
|
||||||
{
|
{
|
||||||
int size, align, r, args_size, i, func_call;
|
int size, align, r, args_size, i, func_call;
|
||||||
Sym *func_sym;
|
Sym *func_sym;
|
||||||
|
// Look ahead to the function on the stack to get the function call type
|
||||||
|
int func_call2 = ((vtop - nb_args)->type.ref)->f.func_call;
|
||||||
|
|
||||||
#ifdef CONFIG_TCC_BCHECK
|
#ifdef CONFIG_TCC_BCHECK
|
||||||
if (tcc_state->do_bounds_check)
|
if (tcc_state->do_bounds_check)
|
||||||
|
@ -418,6 +420,12 @@ ST_FUNC void gfunc_call(int nb_args)
|
||||||
|
|
||||||
args_size = 0;
|
args_size = 0;
|
||||||
for(i = 0;i < nb_args; i++) {
|
for(i = 0;i < nb_args; i++) {
|
||||||
|
if (func_call2 == FUNC_THISCALL && i == (nb_args - 1)) {
|
||||||
|
// If thiscall, zap the last push, as it is `this`. Instead, mov into ecx
|
||||||
|
size = 0;
|
||||||
|
load(get_reg(RC_ECX), vtop);
|
||||||
|
}
|
||||||
|
else
|
||||||
if ((vtop->type.t & VT_BTYPE) == VT_STRUCT) {
|
if ((vtop->type.t & VT_BTYPE) == VT_STRUCT) {
|
||||||
size = type_size(&vtop->type, &align);
|
size = type_size(&vtop->type, &align);
|
||||||
/* align to stack align size */
|
/* align to stack align size */
|
||||||
|
@ -503,7 +511,7 @@ ST_FUNC void gfunc_call(int nb_args)
|
||||||
|
|
||||||
gcall_or_jmp(0);
|
gcall_or_jmp(0);
|
||||||
|
|
||||||
if (args_size && func_call != FUNC_STDCALL && func_call != FUNC_FASTCALLW)
|
if (args_size && func_call != FUNC_STDCALL && func_call != FUNC_THISCALL && func_call != FUNC_FASTCALLW)
|
||||||
gadd_sp(args_size);
|
gadd_sp(args_size);
|
||||||
vtop--;
|
vtop--;
|
||||||
}
|
}
|
||||||
|
@ -523,6 +531,7 @@ ST_FUNC void gfunc_prolog(Sym *func_sym)
|
||||||
const uint8_t *fastcall_regs_ptr;
|
const uint8_t *fastcall_regs_ptr;
|
||||||
Sym *sym;
|
Sym *sym;
|
||||||
CType *type;
|
CType *type;
|
||||||
|
int thiscall_nb_regs;
|
||||||
|
|
||||||
sym = func_type->ref;
|
sym = func_type->ref;
|
||||||
func_call = sym->f.func_call;
|
func_call = sym->f.func_call;
|
||||||
|
@ -540,6 +549,11 @@ ST_FUNC void gfunc_prolog(Sym *func_sym)
|
||||||
fastcall_nb_regs = 0;
|
fastcall_nb_regs = 0;
|
||||||
fastcall_regs_ptr = NULL;
|
fastcall_regs_ptr = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (func_call == FUNC_THISCALL) {
|
||||||
|
thiscall_nb_regs = 1;
|
||||||
|
}
|
||||||
|
|
||||||
param_index = 0;
|
param_index = 0;
|
||||||
|
|
||||||
ind += FUNC_PROLOG_SIZE;
|
ind += FUNC_PROLOG_SIZE;
|
||||||
|
@ -575,6 +589,14 @@ ST_FUNC void gfunc_prolog(Sym *func_sym)
|
||||||
o(0x89); /* movl */
|
o(0x89); /* movl */
|
||||||
gen_modrm(fastcall_regs_ptr[param_index], VT_LOCAL, NULL, loc);
|
gen_modrm(fastcall_regs_ptr[param_index], VT_LOCAL, NULL, loc);
|
||||||
param_addr = loc;
|
param_addr = loc;
|
||||||
|
}
|
||||||
|
else if(param_index < thiscall_nb_regs) {
|
||||||
|
/* Why ? */
|
||||||
|
/* save THISCALL register; ECX */
|
||||||
|
loc -= 4;
|
||||||
|
o(0x89); /* movl */
|
||||||
|
gen_modrm(TREG_ECX, VT_LOCAL, NULL, loc);
|
||||||
|
param_addr = loc;
|
||||||
} else {
|
} else {
|
||||||
param_addr = addr;
|
param_addr = addr;
|
||||||
addr += size;
|
addr += size;
|
||||||
|
@ -585,7 +607,7 @@ ST_FUNC void gfunc_prolog(Sym *func_sym)
|
||||||
}
|
}
|
||||||
func_ret_sub = 0;
|
func_ret_sub = 0;
|
||||||
/* pascal type call or fastcall ? */
|
/* pascal type call or fastcall ? */
|
||||||
if (func_call == FUNC_STDCALL || func_call == FUNC_FASTCALLW)
|
if (func_call == FUNC_STDCALL || func_call == FUNC_FASTCALLW || func_call == FUNC_THISCALL)
|
||||||
func_ret_sub = addr - 8;
|
func_ret_sub = addr - 8;
|
||||||
#if !defined(TCC_TARGET_PE) && !TARGETOS_FreeBSD || TARGETOS_OpenBSD
|
#if !defined(TCC_TARGET_PE) && !TARGETOS_FreeBSD || TARGETOS_OpenBSD
|
||||||
else if (func_vc)
|
else if (func_vc)
|
||||||
|
|
1
tcc.h
1
tcc.h
|
@ -634,6 +634,7 @@ typedef struct DLLReference {
|
||||||
#define FUNC_FASTCALL2 3 /* first parameters in %eax, %edx */
|
#define FUNC_FASTCALL2 3 /* first parameters in %eax, %edx */
|
||||||
#define FUNC_FASTCALL3 4 /* first parameter in %eax, %edx, %ecx */
|
#define FUNC_FASTCALL3 4 /* first parameter in %eax, %edx, %ecx */
|
||||||
#define FUNC_FASTCALLW 5 /* first parameter in %ecx, %edx */
|
#define FUNC_FASTCALLW 5 /* first parameter in %ecx, %edx */
|
||||||
|
#define FUNC_THISCALL 6 /* first param in %ecx */
|
||||||
|
|
||||||
/* field 'Sym.t' for macros */
|
/* field 'Sym.t' for macros */
|
||||||
#define MACRO_OBJ 0 /* object like macro */
|
#define MACRO_OBJ 0 /* object like macro */
|
||||||
|
|
7
tccgen.c
7
tccgen.c
|
@ -3974,7 +3974,12 @@ redo:
|
||||||
case TOK_FASTCALL2:
|
case TOK_FASTCALL2:
|
||||||
case TOK_FASTCALL3:
|
case TOK_FASTCALL3:
|
||||||
ad->f.func_call = FUNC_FASTCALLW;
|
ad->f.func_call = FUNC_FASTCALLW;
|
||||||
break;
|
break;
|
||||||
|
case TOK_THISCALL1:
|
||||||
|
case TOK_THISCALL2:
|
||||||
|
case TOK_THISCALL3:
|
||||||
|
ad->f.func_call = FUNC_THISCALL;
|
||||||
|
break;
|
||||||
#endif
|
#endif
|
||||||
case TOK_MODE:
|
case TOK_MODE:
|
||||||
skip('(');
|
skip('(');
|
||||||
|
|
3
tcctok.h
3
tcctok.h
|
@ -135,6 +135,9 @@
|
||||||
DEF(TOK_FASTCALL1, "fastcall")
|
DEF(TOK_FASTCALL1, "fastcall")
|
||||||
DEF(TOK_FASTCALL2, "__fastcall")
|
DEF(TOK_FASTCALL2, "__fastcall")
|
||||||
DEF(TOK_FASTCALL3, "__fastcall__")
|
DEF(TOK_FASTCALL3, "__fastcall__")
|
||||||
|
DEF(TOK_THISCALL1, "thiscall")
|
||||||
|
DEF(TOK_THISCALL2, "__thiscall")
|
||||||
|
DEF(TOK_THISCALL3, "__thiscall__")
|
||||||
DEF(TOK_REGPARM1, "regparm")
|
DEF(TOK_REGPARM1, "regparm")
|
||||||
DEF(TOK_REGPARM2, "__regparm__")
|
DEF(TOK_REGPARM2, "__regparm__")
|
||||||
DEF(TOK_CLEANUP1, "cleanup")
|
DEF(TOK_CLEANUP1, "cleanup")
|
||||||
|
|
17
tests/thiscall/thiscall-test.c
Normal file
17
tests/thiscall/thiscall-test.c
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
#ifndef __thiscall
|
||||||
|
#define __thiscall __attribute__((thiscall))
|
||||||
|
#endif
|
||||||
|
#ifndef __cdecl
|
||||||
|
#define __cdecl __attribute__((cdecl))
|
||||||
|
#endif
|
||||||
|
#ifndef __stdcall
|
||||||
|
#define __stdcall __attribute__((stdcall))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void ( __thiscall * const thisCall1 ) ( void * _this, int a ) = ( void ( __thiscall * ) ( void * _this, int a ) ) 0x4788a0;
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
thisCall1((void*) 0xDEADBEEF, 1000);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
Loading…
Reference in a new issue