// tcc -m32 minimal.c #include void printf_stack_pointer(int ln) { unsigned int i; asm("\t movl %%esp,%0" : "=r"(i)); printf("At line %i, SP is %u\n", ln, i); } #define PRINTF_STACK_POINTER printf_stack_pointer(__LINE__); __stdcall int some_stdcall_func(int foo, int bar, int baz) { printf("Hello from stdcall: %i\n", foo); return 12; } int main() { PRINTF_STACK_POINTER // Baseline stack pointer for comparison. some_stdcall_func(1, 0, 0); PRINTF_STACK_POINTER // No problem. Stack pointer is unchanged, as it should be. ((int __stdcall (*)(int, int, int))some_stdcall_func) (2, 0, 0); PRINTF_STACK_POINTER // Still no problem. ((int(*__stdcall)(int, int, int))some_stdcall_func) (3, 0, 0); PRINTF_STACK_POINTER // Still no problem. ((int(__stdcall*)(int, int, int))some_stdcall_func) (4, 0, 0); PRINTF_STACK_POINTER // Problem! Notice that SP is now 12 ( e.g. sizeof(int)*3 ) bytes higher. // My guess: For whatever reason TCC thinks this is a cdecl function // (caller-cleanup) and has generated code to recover the stack. // Of course, since the function is actually callee-cleanup, it has already // did that. The stack has been "cleaned" twice and is now sizeof(args) too high. // Seems to happen when the calling convention attribute is inside the brackets // AND before the asterisk. }