abi总结

总结x86-64架构中的abi接口

前置基础

叶子函数:如果一个函数不再调用其他函数,这样的函数被称为叶子函数。 在许多应用程序中,大约一半的函数调用是对叶子函数的调用。 叶子函数在所有平台上都可以得到非常高效的编译,因为他们不需要进行参数的保存和恢复。

叶子函数函数内部不分配栈空间,也不调用其它函数,也不存储非易失性寄存器,也不处理异常

非叶子函数:函数中调用了其他函数的函数。

red zone区域,这个区域是 System V ABI 的优化,允许函数临时使用其堆栈帧(rsp指针)下方的 128 个字节(红色区域始终是 RSP 下方的 128 字节。随着 RSP 的变化(通过 PUSH/POP/MOV 等),红区的位置也会发生变化。),而无需调整堆栈指针。但是ABI明确指出 rsp 之外的区域被认为是不稳定且使用不安全的。操作系统、调试器或中断处理程序可能会覆盖该区域。

一个关于red zone的示例:

1
2
3
4
5
6
7
8
9
long utilfunc(long a, long b, long c)
{
long xx = a + 2;
long yy = b + 3;
long zz = c + 4;
long sum = xx + yy + zz;

return xx * yy * zz + sum;
}

下面是使用gcc编译它的结构,由于该函数是一个叶子函数,所以gcc不会使区去调动sp指针,而是将函数的变量都存储在red zone中。这就相当于进行了指令优化。

但是这种优化可能会带来巨大的隐患。CPU和异常处理程序覆盖red zone中的数据。但被中断的函数仍然需要这些数据。因此,当我们从异常处理程序返回时,该函数将不再正常工作。这可能会导致奇怪的错误,需要数周的时间才能调试。

所以我们一般都会禁用该优化方法。-mno-red-zone为什么内核代码不可使用red zone

这里不得不提到的是Windows abi和AMD abi的不同了,实际上在Windows中根本就没有red zone这个优化。还有以下不同:
- 只是用了四个寄存器进行整数类型的对象的传递( rcx, rdx, r8, r9 )。

数据表示

由上表可知:

  • 所有类型的对齐值和其大小是一致的。
  • LP64表示64位系统,ILP32表示32位系统

寄存器

  • AMD64提供了16个通用寄存器,每个64位
  • 8个浮点数寄存器,每个80位
  • 16个SSE寄存器,每个128位

数据分类

这里还要区分一下 “Caller Save” 和 ”Callee Save” 寄存器,即寄存器的值是由”调用者保存“ 还是由 ”被调用者保存“。当产生函数调用时,子函数内通常也会使用到通用寄存器,那么这些寄存器中之前保存的调用者(父函数)的值就会被覆盖。为了避免数据覆盖而导致从子函数返回时寄存器中的数据不可恢复,CPU 体系结构中就规定了通用寄存器的保存方式。

上图中最右侧显示了是否被 被调用者保存 :

rbx rsp rbp r12-r15 fs x87 CW

参数传递

整数参数传递

只有前6个参数可以被存入寄存器,后面的整数参数都按照参数传递的反序入栈。
六个寄存器分别为:
rdi rsi rdx rcx r8 r9

参数传递

函数的调用


除此之外,我们还发现func()没有下移rsp开辟栈空间的操作,导致rbp和rsp的值是相同的,其实这是一项编译优化:根据AMD64 ABI文档的描述,rsp以下128字节的区域被称为red zone,这是一块被保留的内存,不会被信号或者中断所修改。于是,func()作为叶子函数就可以在不调整栈指针的情况下,使用这块内存保存临时数据。

在更极端的优化下,rbp作为栈基址其实也是可以省略的,编译器完全可以使用rsp来代替,从而减少指令数量。GCC编译时添加参数“-fomit-frame-pointer”即可。

资料参考

http://6.s081.scripts.mit.edu/sp18/x86-64-architecture-guide.html

https://learn.microsoft.com/zh-cn/cpp/build/prolog-and-epilog?view=msvc-170

abi.pdf

https://learn.microsoft.com/zh-cn/cpp/build/prolog-and-epilog?view=msvc-170

https://zhuanlan.zhihu.com/p/27339191

寄存器总结

https://os.phil-opp.com/red-zone/

https://eli.thegreenplace.net/2011/09/06/stack-frame-layout-on-x86-64#the-red-zone

https://devblogs.microsoft.com/oldnewthing/20190111-00/?p=100685


abi总结
https://ysc2.github.io/ysc2.github.io/2023/12/12/abi总结/
作者
Ysc
发布于
2023年12月12日
许可协议