猿问
下载APP

通过linux x86-64函数调用保留了哪些寄存器

通过linux x86-64函数调用保留了哪些寄存器

我相信我理解linux x86-64 ABI如何使用寄存器和堆栈将参数传递给函数。我感到困惑的是,在函数调用中是否预期保留了哪些寄存器。也就是说,哪些寄存器被保证不被破坏?



12345678_0001
浏览 62回答 3
3回答

哆啦的时光机

以下是文档[ PDF链接 ]中完整的寄存器表及其用法:r12,r13,r14,r15,rbx,rsp,rbp是被调用方保存的寄存器-他们在“腌制在函数调用”一栏有一个“是”。

123456qqq

ABI指定允许符合标准的软件。它主要是为编译器,链接器和其他语言处理软件的作者编写的。这些作者希望他们的编译器能够生成能够与由相同(或不同)编译器编译的代码一起正常工作的代码。它们都必须同意一组规则:函数的形式参数如何从调用者传递给被调用者,函数返回值如何从被调用者传递回调用者,哪些寄存器在调用边界上保留/暂存/未定义,等等上。例如,一条规则声明生成的函数汇编代码必须在更改值之前保存保留寄存器的值,并且代码必须在返回其调用者之前恢复保存的值。对于临时寄存器,生成的代码不需要保存和恢复寄存器值; 如果需要,它可以这样做,但不允许符合标准的软件依赖于这种行为(如果它不是符合标准的软件)。如果您正在编写汇编代码,那么您有责任按照这些相同的规则进行播放(您正在扮演编译器的角色)。也就是说,如果您的代码更改了被调用者保留的寄存器,则您负责插入保存和恢复原始寄存器值的指令。如果汇编代码调用外部函数,则代码必须以符合标准的方式传递参数,并且它可以取决于当被调用者返回时保留的寄存器值实际上被保留的事实。规则定义了符合标准的软件如何相处。然而,这是完全合法的编写(或生成)的代码,而不是通过这些规则玩!编译器一直这样做,因为他们知道在某些情况下不需要遵循规则。例如,考虑一个名为foo的C函数,该函数声明如下,并且从不采用其地址:static foo(int x);在编译时,编译器100%确定此函数只能由当前正在编译的文件中的其他代码调用。foo考虑到静态意义的定义,函数不能被任何其他东西调用。因为编译器在编译时知道所有调用者foo,所以编译器可以自由地使用它想要的任何调用序列(直到并且包括根本不进行调用,即将代码内联foo到调用者中foo。作为汇编代码的作者,您也可以这样做。也就是说,只要该协议不会干扰或违反符合标准的软件的期望,您就可以在两个或更多例程之间实现“私有协议”。

qq_花开花谢_0

实验方法:反汇编GCC代码主要是为了好玩,但也作为一个快速验证,你明白ABI是正确的。让我们尝试使用内联汇编来破坏所有寄存器以强制GCC保存和恢复它们:main.c中#include <inttypes.h>uint64_t inc(uint64_t i) {&nbsp; &nbsp; __asm__ __volatile__(&nbsp; &nbsp; &nbsp; &nbsp; ""&nbsp; &nbsp; &nbsp; &nbsp; : "+m" (i)&nbsp; &nbsp; &nbsp; &nbsp; :&nbsp; &nbsp; &nbsp; &nbsp; : "rax",&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "rbx",&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "rcx",&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "rdx",&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "rsi",&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "rdi",&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "rbp",&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "rsp",&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "r8",&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "r9",&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "r10",&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "r11",&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "r12",&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "r13",&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "r14",&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "r15",&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "ymm0",&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "ymm1",&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "ymm2",&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "ymm3",&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "ymm4",&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "ymm5",&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "ymm6",&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "ymm7",&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "ymm8",&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "ymm9",&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "ymm10",&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "ymm11",&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "ymm12",&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "ymm13",&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "ymm14",&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "ymm15"&nbsp; &nbsp; );&nbsp; &nbsp; return i + 1;}int main(int argc, char **argv) {&nbsp; &nbsp; (void)argv;&nbsp; &nbsp; return inc(argc);}GitHub上游。编译和反汇编:&nbsp;gcc -std=gnu99 -O3 -ggdb3 -Wall -Wextra -pedantic -o main.out main.c&nbsp;objdump -d main.out反汇编包含:00000000000011a0 <inc>:&nbsp; &nbsp; 11a0:&nbsp; &nbsp; &nbsp; &nbsp;55&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; push&nbsp; &nbsp;%rbp&nbsp; &nbsp; 11a1:&nbsp; &nbsp; &nbsp; &nbsp;48 89 e5&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; mov&nbsp; &nbsp; %rsp,%rbp&nbsp; &nbsp; 11a4:&nbsp; &nbsp; &nbsp; &nbsp;41 57&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;push&nbsp; &nbsp;%r15&nbsp; &nbsp; 11a6:&nbsp; &nbsp; &nbsp; &nbsp;41 56&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;push&nbsp; &nbsp;%r14&nbsp; &nbsp; 11a8:&nbsp; &nbsp; &nbsp; &nbsp;41 55&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;push&nbsp; &nbsp;%r13&nbsp; &nbsp; 11aa:&nbsp; &nbsp; &nbsp; &nbsp;41 54&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;push&nbsp; &nbsp;%r12&nbsp; &nbsp; 11ac:&nbsp; &nbsp; &nbsp; &nbsp;53&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; push&nbsp; &nbsp;%rbx&nbsp; &nbsp; 11ad:&nbsp; &nbsp; &nbsp; &nbsp;48 83 ec 08&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;sub&nbsp; &nbsp; $0x8,%rsp&nbsp; &nbsp; 11b1:&nbsp; &nbsp; &nbsp; &nbsp;48 89 7d d0&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;mov&nbsp; &nbsp; %rdi,-0x30(%rbp)&nbsp; &nbsp; 11b5:&nbsp; &nbsp; &nbsp; &nbsp;48 8b 45 d0&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;mov&nbsp; &nbsp; -0x30(%rbp),%rax&nbsp; &nbsp; 11b9:&nbsp; &nbsp; &nbsp; &nbsp;48 8d 65 d8&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;lea&nbsp; &nbsp; -0x28(%rbp),%rsp&nbsp; &nbsp; 11bd:&nbsp; &nbsp; &nbsp; &nbsp;5b&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; pop&nbsp; &nbsp; %rbx&nbsp; &nbsp; 11be:&nbsp; &nbsp; &nbsp; &nbsp;41 5c&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;pop&nbsp; &nbsp; %r12&nbsp; &nbsp; 11c0:&nbsp; &nbsp; &nbsp; &nbsp;48 83 c0 01&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;add&nbsp; &nbsp; $0x1,%rax&nbsp; &nbsp; 11c4:&nbsp; &nbsp; &nbsp; &nbsp;41 5d&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;pop&nbsp; &nbsp; %r13&nbsp; &nbsp; 11c6:&nbsp; &nbsp; &nbsp; &nbsp;41 5e&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;pop&nbsp; &nbsp; %r14&nbsp; &nbsp; 11c8:&nbsp; &nbsp; &nbsp; &nbsp;41 5f&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;pop&nbsp; &nbsp; %r15&nbsp; &nbsp; 11ca:&nbsp; &nbsp; &nbsp; &nbsp;5d&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; pop&nbsp; &nbsp; %rbp&nbsp; &nbsp; 11cb:&nbsp; &nbsp; &nbsp; &nbsp;c3&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; retq&nbsp; &nbsp;&nbsp; &nbsp; 11cc:&nbsp; &nbsp; &nbsp; &nbsp;0f 1f 40 00&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;nopl&nbsp; &nbsp;0x0(%rax)所以我们清楚地看到以下内容被推送和弹出:rbxr12r13r14r15rbp规范中唯一缺少的是rsp,但我们希望堆栈当然可以恢复。仔细阅读程序集确认在这种情况下维护它:sub $0x8, %rsp:分配堆栈8个字节以保存%rdi在%rdi, -0x30(%rbp),其被用于内联组件进行+m约束lea -0x28(%rbp), %rsp恢复%rsp到之前sub,即之后的5个流行音乐mov %rsp, %rbp有6个推送和6个相应的流行音乐没有其他指示触摸 %rsp在Ubuntu 18.10,GCC 8.2.0中测试。
打开App,查看更多内容
随时随地看视频慕课网APP
我要回答