x64 参数传递

时间:2024-03-06 09:26:55

近日某青年似乎研究到x64(AMD64 in history)的参数传递调用约定,这玩意确实和x86上面不一样,于是我决定写点字介绍一下。

x64首先把x86原有的寄存器扩展到了64位,然后更增加了8个通用寄存器:R8~~R15,嗯,确实有点RISC的味道。

  • x64上面默认的函数调用约定是fast call,也就是ABI是fast call。
  • 前四个参数传递顺序是RCX,RDX,R8,R9,其余的参数通过压栈传递。注意这里有一个细节:前四个参数也是占用栈空间的,或者说,栈需要为前四个参数保留32个字节。
  • 小于64位的参数传递时高位并不填充零,大于64位需要按照地址传递。
  • 返回值在RAX
  • 被调用函数不负责清栈
  • RAX,RCX,RDX,R8,R9,R10,R11是“易挥发”的,其余寄存器需要保护。
  • 栈需要16字节对齐。

OK,以上是理论上的东西,实际上编译器会把一切都搞糟,具体可以看一下两篇文章:

The history of calling conventions, part 5: amd64

Although the x64 calling convention reserves spill space for parameters, you don\'t have to use them as such

这一切看起来非常的令人迷惑,个人推荐的解决办法有三种:

  • 使用ICC或者GCC,这样可以用内联汇编,于是绝大多数问题都解决了。
  • 使用编译器 intrinsics 指令,这玩意好像应该翻译成内省指令,还是内醒,总之不管了,知道是这玩意就行。
  • 手工代码发射,不过这个最好还是用在API hook的时候,写算法真还不如用MASM,不过MASM免不了还得和参数调用约定捉迷藏。