GCC不在函数调用中保存/恢复保留寄存器

时间:2011-07-28 17:20:38

标签: c gcc assembly gas register-allocation

我在GCC有一个场景让我有问题。我得到的行为不是我期望的行为。总结一下这种情况,我提出了一些x86-64的新指令,它们是在硬件模拟器中实现的。为了测试这些指令,我正在使用现有的C源代码并使用十六进制对新指令进行手动编码。因为这些指令与现有的x86-64寄存器交互,所以我使用input / output / 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

2 个答案:

答案 0 :(得分:7)

ABI,第3.2.1节说:

  

注册%rbp,%rbx和%r12到%r15“属于”调用函数和   叫做函数是   需要保持他们的价值观。换句话说,被调用的函数必须保留   这些寄存器的值为其调用者。剩余的寄存器“属于”被叫   功能。如果调用函数想要在a中保留这样的寄存器值   函数调用时,必须将值保存在本地堆栈框架中。

所以你不应该期望函数调用保留除%rbp,%rbx和%r12到%r15之外的寄存器。

答案 1 :(得分:2)

gcc不会像这个callee-saved那样生成显式寄存器变量。基本上,您使用的寄存器表示法使变量成为寄存器的直接别名,假设您希望能够读回被调用者在寄存器中留下的值。如果你使用被调用者保存的寄存器而不是call-clobbered(调用者保存的)寄存器,问题就会消失。