Skip to content

Commit

Permalink
implemented thiscall by copying logic from fastcall
Browse files Browse the repository at this point in the history
implemented improved thiscall by using mov ecx instead of pop ecx

include __thiscall and __thiscall__ as aliases

remove fake line in test
  • Loading branch information
gynt committed Jun 3, 2024
1 parent 8cd21e9 commit 3b943be
Show file tree
Hide file tree
Showing 5 changed files with 51 additions and 3 deletions.
26 changes: 24 additions & 2 deletions i386-gen.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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 */
Expand Down Expand Up @@ -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--;
}
Expand All @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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)
Expand Down
1 change: 1 addition & 0 deletions tcc.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down
7 changes: 6 additions & 1 deletion tccgen.c
Original file line number Diff line number Diff line change
Expand Up @@ -3974,7 +3974,12 @@ static void parse_attribute(AttributeDef *ad)
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('(');
Expand Down
3 changes: 3 additions & 0 deletions tcctok.h
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down
17 changes: 17 additions & 0 deletions tests/thiscall/thiscall-test.c
Original file line number Diff line number Diff line change
@@ -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;
}

0 comments on commit 3b943be

Please sign in to comment.