简体   繁体   中英

__cdecl calling convention not work on msvc x64

Just a test for __cdecl calling convention.

It's a cmake project and only have 1 source file:

#include <stdio.h>

#define CALL_CONVENTION __cdecl

void CALL_CONVENTION f(int a, int b)
{
    printf("%d, %d", a, b);
}

int main()
{
    f(1, 2);

    return 0;
}

I'm using set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /FA") to output the assembly code.

and when I build with cmake -G "Visual Studio 15" , It's build a 32bit application, and every thing is in anticipation:

...
; Line 12
    push    ebp
    mov ebp, esp
; Line 13
    push    2        ; <------- argument 2
    push    1        ; <------- argument 1
    call    _f       ; <------- call function
    add esp, 8
; Line 15
    xor eax, eax
; Line 16
    cmp ebp, esp
    call    __RTC_CheckEsp
    pop ebp
    ret 0
_main   ENDP
...

You can see the arguments is passed by push 2 and push 1 instructions, it's __cdecl call convention.

But if I'm using cmake -G "Visual Studio 15 Win64" to build a 64bit application, the __cdecl annotation seems not work (arguments not passed by stack):

...
; Line 12
$LN3:
    push    rdi
    sub rsp, 32                 ; 00000020H
    mov rdi, rsp
    mov ecx, 8
    mov eax, -858993460             ; ccccccccH
    rep stosd
; Line 13
    mov edx, 2        ; <------ argument 2
    mov ecx, 1        ; <------ argument 1
    call    f         ; <------ call function
; Line 15
    xor eax, eax
; Line 16
    add rsp, 32                 ; 00000020H
    pop rdi
    ret 0
main    ENDP
...

the arguments is passed by register edx and ecx , not passed by stack.

So why arguments not passed by stack in x64 even if I specify __cdecl and what should I do if I want do same things in x64 environments.

x64 has it's own calling conventions.

Microsoft docs __cdecl

On ARM and x64 processors, __cdecl is accepted but typically ignored by the compiler. By convention on ARM and x64, arguments are passed in registers when possible, and subsequent arguments are passed on the stack. In x64 code, use __cdecl to override the /Gv compiler option and use the default x64 calling convention.

Microsoft docs x64 calling convention

The x64 Application Binary Interface (ABI) uses a four-register fast-call calling convention by default. Space is allocated on the call stack as a shadow store for callees to save those registers. There's a strict one-to-one correspondence between the arguments to a function call and the registers used for those arguments. Any argument that doesn't fit in 8 bytes, or isn't 1, 2, 4, or 8 bytes, must be passed by reference.

...

Integer arguments are passed in registers RCX, RDX, R8, and R9

You can see it using ECX and EDX for the int a and int b (as they are 32bits, while the full RCX and RDX is 64bits).

__stdcall , __fastcall and __thiscall are also ignored. __vectorcall is available (the /Gv switch makes it default) and is another register calling convention, but compared to the x64 default it can use registers in more cases and has some other rule differences.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM