- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
只是测试 __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 2
和push 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
...
参数通过寄存器edx
和ecx
传递,不通过栈传递。
那么,即使我指定了 __cdecl
,为什么在 x64 中参数没有通过堆栈传递,如果我想在 x64 环境中做同样的事情,我应该怎么做。
最佳答案
x64 有自己的调用约定。
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 a
和 int b
使用 ECX 和 EDX(因为它们是 32 位,而完整的 RCX 和 RDX 是 64 位)。
__stdcall
, __fastcall
和 __thiscall
也被忽略。 __vectorcall
可用(/Gv 开关使其成为默认值)并且是另一个寄存器调用约定,但与 x64 默认值相比,它可以在更多情况下使用寄存器并且有一些其他规则差异。
关于c++ - __cdecl 调用约定不适用于 msvc x64,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55612188/
我是一名优秀的程序员,十分优秀!