当前位置: 首页 > 知识库问答 >
问题:

为什么在x64中忽略__stdcall调用约定?

申屠项明
2023-03-14
int __stdcall stdcallFunc(int a, int b, int c, int d, int e, int f, int g)
{
    return a + b + c + d + e + f + g;
}

int __cdecl cdeclFunc(int a, int b, int c, int d, int e, int f, int g)
{
    return a + b + c + d + e + f + g;
}

int main()
{
    stdcallFunc(1, 2, 3, 4, 5, 6, 7);
    cdeclFunc(1, 2, 3, 4, 5, 6, 7);

    return 0;
}
main    PROC
$LN3:
        sub     rsp, 72                             ; 00000048H
        mov     DWORD PTR [rsp+48], 7
        mov     DWORD PTR [rsp+40], 6
        mov     DWORD PTR [rsp+32], 5
        mov     r9d, 4
        mov     r8d, 3
        mov     edx, 2
        mov     ecx, 1
        call    ?stdcallFunc@@YAHHHHHHHH@Z          ; stdcallFunc
        mov     DWORD PTR [rsp+48], 7
        mov     DWORD PTR [rsp+40], 6
        mov     DWORD PTR [rsp+32], 5
        mov     r9d, 4
        mov     r8d, 3
        mov     edx, 2
        mov     ecx, 1
        call    ?cdeclFunc@@YAHHHHHHHH@Z                ; cdeclFunc
        xor     eax, eax
        add     rsp, 72                             ; 00000048H
        ret     0
main    ENDP

x86

_main   PROC
        push    ebp
        mov     ebp, esp
        push    7
        push    6
        push    5
        push    4
        push    3
        push    2
        push    1
        call    ?stdcallFunc@@YGHHHHHHHH@Z          ; stdcallFunc
        push    7
        push    6
        push    5
        push    4
        push    3
        push    2
        push    1
        call    ?cdeclFunc@@YAHHHHHHHH@Z                ; cdeclFunc
        add     esp, 28                             ; 0000001cH
        xor     eax, eax
        pop     ebp
        ret     0
_main   ENDP
  1. 正如所料,前4个参数通过x64中的寄存器传递。
  2. 其余参数按与x86中相同的顺序放在堆栈中。
  3. 与x86相反,在x64中我们不使用push指令。相反,我们在main的开头保留足够的堆栈空间,并使用mov指令将参数添加到堆栈中。
  4. 在x64中,在调用之后,不会进行堆栈清理,而是在main的末尾。

这就引出了我的问题:

共有1个答案

岑俊明
2023-03-14
  1. 为什么x64使用mov而不是push?我想它只是效率更高,在x86中没有。

这不是原因。这两条指令在x86汇编语言中也存在。

编译器没有为x64代码发出push指令的原因可能是因为它无论如何都必须直接调整堆栈指针,以便为被调用的函数创建32字节的“阴影空间”。请参见此链接(由@nateeldredge提供)以获得关于“阴影空间”的更多信息。

添加rsp,72

做。

但是,由于某些原因(可能是提高了性能),x64编译器只在调用函数的末尾执行清理,而不是在每次函数调用之后。这意味着在x64编译器中,所有函数调用都为其参数共享相同的堆栈空间,而在x86编译器中,堆栈空间在每次函数调用时都被分配和清理。

 类似资料:
  • 我对iOS布局约束的机制有误解。请参阅下面列出的我放在viewDidLoad中的代码。 在我看来,我的意图是明确的。我想在设备屏幕的中央看到一个按钮。但我只能看到下面的图片。 我在项目控制台中有一个输出,非常可怕,我无法从中理解任何东西。 无法同时满足约束。可能以下列表中至少有一个约束是您不想要的。尝试以下方法:(1)查看每个约束,并尝试找出您不期望的约束;(2) 查找添加了一个或多个不需要的约束

  • 我已经用FilesystemMetadataProvider基于此实现了:https://github.com/vdenotaris/spring-boot-security-saml-sample 为了使 SSL 握手适用于工件绑定,我必须将 IDP 的 CA 证书放在 keyManager 使用的 java 密钥库中。 我宁愿使用jre上的cacerts,以防IDP更改CA,但是我还没有找到任

  • 问题内容: 与这两个帖子@iMohammad有关, 在单击JButtonJava时使用JButton增加/减少textArea内的字体大小并在单击JButton Java时更改字体样式 …,我面临着一个非常有趣的问题,该问题来自于on 作为参数传递屏幕 请如何动态调整大小取决于,与我在sscce中尝试过的另一个JComponent正常工作一样 问题答案: 我调试了您的SSCCE,并且传递给的值为空

  • 问题内容: // Ignore z-index if position is set to a value where z-index is ignored by the browser // This makes behavior of this function consistent across browsers // WebKit always returns auto if the el

  • 我在JMeter中创建了一个脚本,它从CSV获取登录凭据。 用户名:pshah 密码:欢迎 当我执行脚本时,我可以在POST中看到值: 用户名:pshah 但密码:欢迎 我想知道原因”

  • 注:据我所知,该问题不是以下问题的重复问题: HTML5:为什么我的“oninvalid”属性让模式失败 HTML5表单必需属性。设置自定义验证消息 如何更改或删除HTML5表单验证默认错误消息 给定一个字段: 为验证设置了属性,例如对于4个字符的十六进制字符串输入设置了 下面是一个示例,说明了这一点: 验证工作几乎与预期一样,除非用户输入无效条目,然后继续尝试并编辑它,其以下输入状态仍然无效: