【问题标题】:Call function in C to Assembly将 C 中的函数调用到程序集
【发布时间】:2021-07-24 14:24:28
【问题描述】:

如果我们有以下函数:

int func(int n, float f, char* s, double* d);

Assembly 中的函数调用将是这样的:

movl <n>, %ecx
movl <s>, %edx
pushl <d>
pushl <f>
call func

这是正确的吗?为什么是这个顺序?是因为每种类型的大小?

【问题讨论】:

  • 首先选择一个架构,然后用编译器试试看。
  • 那应该是 Windows 32 位 fastcall 吗?
  • 前两个符合条件的 args 依次进入 ECX 和 EDX,然后在堆栈中,最左边的 stack-arg 位于最低地址(最后推送)。假设这与编译器的功能相匹配,对我来说似乎是合理的;检查godbolt.org上的MSVC
  • Eligible:我的意思是调用约定允许在寄存器中传递的参数:整数和指针参数,但不是floatdouble。我假设 MS 文件 __fastcall 某处;去阅读他们的文档以了解有关规则的详细信息。
  • 相关:Why not store function parameters in XMM vector registers? 的相反问题是为什么不在 FP 寄存器中传递更多整数。哪些 args 可以在整数寄存器中传递的规则取决于调用约定。当然是指针和整数类型,当然不是 FP,但结构的设计选择(按值)并不明显;你必须检查文档或编译器实际做了什么。

标签: c assembly x86 calling-convention fastcall


【解决方案1】:

对于已知的论点,没有强烈的令人信服的理由来推动从右到左或相反,所以这只是一个要遵循的约定。

对于可变参数,以相反的顺序推送它们是有好处的,因为被调用者不知道传递了多少参数。但第一个参数位于已知位置,即在返回地址之后。

所以如果你考虑printf的例子:

 printf(FormatString, a1, a2, a3, a4);

所以FormatString 现在处于已知位置,可以轻松找到通过堆栈的其他参数。

如果是相反的情况,那么被调用者需要获取一些额外的信息才能找到第一个参数,无论是指针,还是计数器或其他东西,它告诉它在哪里找到格式字符串。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-21
    • 1970-01-01
    • 1970-01-01
    • 2014-09-26
    • 2019-08-12
    相关资源
    最近更新 更多