diff --git a/i386-gen.c b/i386-gen.c index 7aebc5cd8..b95c0adb3 100644 --- a/i386-gen.c +++ b/i386-gen.c @@ -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) diff --git a/tcc.h b/tcc.h index 547ca9a94..84429ac1d 100644 --- a/tcc.h +++ b/tcc.h @@ -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 */ diff --git a/tccgen.c b/tccgen.c index 9da4a028c..22d42bfe0 100644 --- a/tccgen.c +++ b/tccgen.c @@ -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('('); diff --git a/tcctok.h b/tcctok.h index 699b67bb1..08890e1d0 100644 --- a/tcctok.h +++ b/tcctok.h @@ -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") diff --git a/tests/thiscall/thiscall-test.c b/tests/thiscall/thiscall-test.c new file mode 100644 index 000000000..a13b9a407 --- /dev/null +++ b/tests/thiscall/thiscall-test.c @@ -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; +} \ No newline at end of file