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:
Gynt 2024-06-03 13:52:34 +02:00
parent 8cd21e91cc
commit 3b943bec5d
5 changed files with 51 additions and 3 deletions

View File

@ -410,6 +410,8 @@ ST_FUNC void gfunc_call(int nb_args)
{
int size, align, r, args_size, i, func_call;
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
if (tcc_state->do_bounds_check)
@ -418,6 +420,12 @@ ST_FUNC void gfunc_call(int nb_args)
args_size = 0;
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) {
size = type_size(&vtop->type, &align);
/* align to stack align size */
@ -503,7 +511,7 @@ ST_FUNC void gfunc_call(int nb_args)
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);
vtop--;
}
@ -523,6 +531,7 @@ ST_FUNC void gfunc_prolog(Sym *func_sym)
const uint8_t *fastcall_regs_ptr;
Sym *sym;
CType *type;
int thiscall_nb_regs;
sym = func_type->ref;
func_call = sym->f.func_call;
@ -540,6 +549,11 @@ ST_FUNC void gfunc_prolog(Sym *func_sym)
fastcall_nb_regs = 0;
fastcall_regs_ptr = NULL;
}
if (func_call == FUNC_THISCALL) {
thiscall_nb_regs = 1;
}
param_index = 0;
ind += FUNC_PROLOG_SIZE;
@ -575,6 +589,14 @@ ST_FUNC void gfunc_prolog(Sym *func_sym)
o(0x89); /* movl */
gen_modrm(fastcall_regs_ptr[param_index], VT_LOCAL, NULL, 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 {
param_addr = addr;
addr += size;
@ -585,7 +607,7 @@ ST_FUNC void gfunc_prolog(Sym *func_sym)
}
func_ret_sub = 0;
/* 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;
#if !defined(TCC_TARGET_PE) && !TARGETOS_FreeBSD || TARGETOS_OpenBSD
else if (func_vc)

1
tcc.h
View File

@ -634,6 +634,7 @@ typedef struct DLLReference {
#define FUNC_FASTCALL2 3 /* first parameters in %eax, %edx */
#define FUNC_FASTCALL3 4 /* first parameter in %eax, %edx, %ecx */
#define FUNC_FASTCALLW 5 /* first parameter in %ecx, %edx */
#define FUNC_THISCALL 6 /* first param in %ecx */
/* field 'Sym.t' for macros */
#define MACRO_OBJ 0 /* object like macro */

View File

@ -3974,7 +3974,12 @@ redo:
case TOK_FASTCALL2:
case TOK_FASTCALL3:
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
case TOK_MODE:
skip('(');

View File

@ -135,6 +135,9 @@
DEF(TOK_FASTCALL1, "fastcall")
DEF(TOK_FASTCALL2, "__fastcall")
DEF(TOK_FASTCALL3, "__fastcall__")
DEF(TOK_THISCALL1, "thiscall")
DEF(TOK_THISCALL2, "__thiscall")
DEF(TOK_THISCALL3, "__thiscall__")
DEF(TOK_REGPARM1, "regparm")
DEF(TOK_REGPARM2, "__regparm__")
DEF(TOK_CLEANUP1, "cleanup")

View 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;
}