GCC 不保存/恢复函数调用的保留寄存器
Posted
技术标签:
【中文标题】GCC 不保存/恢复函数调用的保留寄存器【英文标题】:GCC not saving/restoring reserved registers on function calls 【发布时间】:2011-07-28 17:20:37 【问题描述】:我在 GCC 中有一个场景导致我出现问题。我得到的行为不是我期望的行为。总结一下情况,我提出了几个在硬件模拟器中实现的 x86-64 新指令。为了测试这些指令,我使用现有的 C 源代码并使用十六进制对新指令进行手工编码。因为这些指令与现有的 x86-64 寄存器交互,所以我使用输入/输出/clobber 列表来声明 GCC 的依赖关系。
如果我调用一个函数,例如printf,依赖的寄存器不会被保存和恢复。
例如
register unsigned long r9 asm ("r9") = 101;
printf("foo %s\n", "bar");
asm volatile (".byte 0x00, 0x00, 0x00, 0x00" : /* no output */ : "q" (r9) );
101 被分配给 r9,并且内联汇编(在本例中为假)依赖于 r9。这在没有 printf 的情况下正确运行,但是当它存在时,GCC 不会保存和恢复 r9,并且在调用我的自定义指令时存在另一个值。
我认为也许 GCC 可能已经秘密地将赋值更改为 变量 r9,但是当我这样做时
asm volatile (".byte %0" : /* no output */ : "q" (r9) );
看看汇编输出,确实是在使用 %r9。
我正在使用 gcc 4.4.5。你认为可能会发生什么?我认为 GCC 将始终保存和恢复函数调用的寄存器。有什么办法可以强制执行吗?
谢谢!
编辑:顺便说一句,我正在编译这样的程序
gcc -static -m64 -mmmx -msse -msse2 -O0 test.c -o test
【问题讨论】:
【参考方案1】:ABI,第 3.2.1 节说:
寄存器 %rbp、%rbx 和 %r12 到 %r15 “属于”调用函数和 被调用的函数是 需要保持他们的价值。换句话说,被调用的函数必须保留 这些寄存器为其调用者的值。剩余的寄存器“属于”被调用 功能。如果调用函数想要在整个 函数调用,它必须将值保存在其本地堆栈帧中。
因此,您不应期望函数调用会保留除 %rbp、%rbx 和 %r12 到 %r15 之外的寄存器。
【讨论】:
感谢您的澄清,我不知道这一点。作为后续问题,是否有一种简单(一行)的方法来要求在 printf 之前保存一组自定义寄存器并在 printf 之后恢复?unsigned long tmp = r9; printf(...); r9 = tmp;
【参考方案2】:
gcc 不会像这样被调用者保存显式注册变量。基本上,您使用的这个寄存器符号使变量成为寄存器的直接别名,假设您希望能够读回被调用者留在寄存器中的值。如果您使用被调用者保存的寄存器而不是调用破坏(调用者保存)的寄存器,问题就会消失。
【讨论】:
谢谢,我什至不知道有调用者/被调用者保存的寄存器!以上是关于GCC 不保存/恢复函数调用的保留寄存器的主要内容,如果未能解决你的问题,请参考以下文章