gpt4 book ai didi

c++ - __cdecl 调用约定不适用于 msvc x64

转载 作者:行者123 更新时间:2023-11-27 23:40:20 24 4
gpt4 key购买 nike

只是测试 __cdecl 调用约定。

这是一个 cmake 项目,只有 1 个源文件:

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

我正在使用 set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS}/FA") 输出汇编代码。

当我使用 cmake -G "Visual Studio 15" 构建时,它构建了一个 32 位应用程序,一切都在预期之中:

...
; 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
...

可以看到参数是通过push 2push 1指令传递的,是__cdecl调用约定。

但是如果我使用 cmake -G "Visual Studio 15 Win64" 构建 64 位应用程序,__cdecl 注释似乎不起作用(参数未通过堆栈传递):

...
; 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
...

参数通过寄存器edxecx传递,不通过栈传递。

那么,即使我指定了 __cdecl,为什么在 x64 中参数没有通过堆栈传递,如果我想在 x64 环境中做同样的事情,我应该怎么做。

最佳答案

x64 有自己的调用约定。

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

您可以看到它对 int aint b 使用 ECX 和 EDX(因为它们是 32 位,而完整的 RCX 和 RDX 是 64 位)。

__stdcall , __fastcall__thiscall也被忽略。 __vectorcall可用(/Gv 开关使其成为默认值)并且是另一个寄存器调用约定,但与 x64 默认值相比,它可以在更多情况下使用寄存器并且有一些其他规则差异。

关于c++ - __cdecl 调用约定不适用于 msvc x64,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55612188/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com