Linux/Unix平台X64函数调用约定

目录

1. System V AMD64 ABI约定

2. System V AMD64 ABI的栈帧结构


X64调用约定利用寄存器来传递部分函数参数,不规范的函数调用规则逐渐减少。现主要有两种比较通用的函数调用规则。一种是Microsoft X64函数调用约定,参见以下链接:MSVC平台下X64处理器函数调用规则——底层机制_ComputerInBook的博客-优快云博客目录1. 默认的调用规则2. 内存边界对齐问题3. 解开性(Unwindability)4. 参数传递5. 可变数量参数的传递6. 非原型函数7. 函数返回值8. 调用函数或被调函数存储寄存器9. 函数指针10. 对较旧代码的浮点支持11. 浮点状态和控制寄存器(Float Point Status and Control Register,简记为FPSCR)12. 多媒体扩展控制和状态寄存器(Multimedia Extensions Control andhttps://blog.youkuaiyun.com/ComputerInBook/article/details/124342574

另一种是System V AMD64 函数调用约定(即Application Binary Interface,简记为ABI)。这里主要讲System V AMD64约定的规则。

遵循System V AMD64 ABI约定的操作系统平台主要有:Solaris, Linux, FreeBSD, macOS,等等。是很多Unix和类Unix操作系统事实上的ABI标准。OpenVMS的X64 ABI调用约定基于System V ABI调用标准,并做了一些后向兼容的扩展。

1. System V AMD64 ABI约定

    前6个整数参数(整型参数或指针参数)使用RDI, RSI, RDX, RCX, R8, R9这6个寄存器传递(在嵌套函数的情况下,R10 用作静态链指针);XMM0, XMM1, XMM2, XMM3, XMM4, XMM5, XMM6 和 XMM7用于传递前8个浮点参数。超出规定寄存器个数的参数采用内存栈传递。整数返回值最多64位,存储在RAX中以返回;如果返回值达到128位,存储在RAX和RDX中以返回。类似地,64位浮点值放在寄存器XMM0以返回,128位浮点值放在寄存器XMM0和XMM1以返回。如果存在更宽位的值,使用YMM寄存器和ZMM寄存器传递参数及返回值。用于传递参数的寄存器如下图:

参数类型

寄存器

整数参数 1-6

RDI, RSI, RDX, RCX, R8, R9

浮点参数 1-8

XMM0 - XMM7

超出部分的参数

内存栈

静态链指针

R10

如果被调函数期望使用寄存器RBX, RSP, RBP, and R12–R15(称为易失性寄存器),则在返回被调函数之前,必须恢复它们在使用之前的值;如果调用函数期望恢复所有其它寄存器调用前的值,则在使用之前必须先保存这些寄存器的值。

   对于叶函数(leaf-node function,即,没有进一步函数其它调用的函数),在栈指针之下保留了128字节的空间这段空间称为红色区域(red zone)。这块区域不能被任何信号或中断处理器占用。因此,编译器可以使用这块区域来保存局部变量。编译器通过使用这块区域来忽略函数开头的一些指令(调整寄存器RSP,RBP)。然而,其它函数可以占用这块区域,因此,这块区域应当仅用于叶函数。gcc和clang使用-mno-red-zone标识来禁止对红色区域的优化。

    对于被调函数是可变参数函数(variadic function)的情况,以向量寄存器传递浮点参数的数量必须由调用函数在寄存 器AL寄存器中指定。

    与Microsoft调用不同的是,系统并没有提供影子内存(shadow space),而是,在函数入口点,返回地址在栈上紧邻第7个整型函数参数。

    栈空间采用16字节边界对齐方式。在栈之下保留有128字节的红色区域。内核接口使用RDI, RSI, RDX, R10, R8 和R9寄存器。在C++类函数中,this是第一个参数。

2. System V AMD64 ABI的栈帧结构

    除了寄存器之外,每个函数在运时栈上都拥有一个函数栈帧。这个栈帧的方向为从高地址向低地址向下递减。下图为栈帧结构:

位置

内容

栈帧

8n+16(%rbp)

内存参数8字节n

      ...

内存参数8字节0

高地址

8(%rbp)

0(%rbp)

-8(%rbp)

0(%rbp)

-128(%rbp)

返回地址

当前地址

前一个%rbp值

未指定

...

变量大小

红色区域

 在输入参数和末尾,将按16字节边界对齐(如果使用在栈上传递__m256大小的整数,则采用32字节的边界对齐方式)。换句话说,当控制权交给函数入口头的时候,(%rsp+8)的值总是16(32)的倍数。栈指针%rsp总是指向最新分配的栈的底端。%rsp指向的位置以外的 128 字节区域被认为是保留的,不应被信号或中断处理程序修改。因此,函数可以使用此区域存储局部变量。特别是,叶函数使用这个区域作为其整个栈帧,而不是作为序言和结语的代码去调整栈桢。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值