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



我在GCC中有一个导致我出现问题的场景。我得到的行为不是我期望的行为。为了总结这种情况,我为x86-64提出了几个在硬件模拟器中实现的新指令。为了测试这些指令,我采取现有的C源代码和手工编码的新指令使用十六进制。因为这些指令与现有的x86-64寄存器交互,所以我使用input/output/clober列表来声明GCC的依赖项。

发生的事情是,如果我调用一个函数,例如printf,相关寄存器不会被保存和恢复。

例如

register unsigned long r9  asm ("r9")  = 101;
printf("foo %sn", "bar");
asm volatile (".byte 0x00, 0x00, 0x00, 0x00" : /* no output */ : "q" (r9) );

101被赋值给r9,内联汇编(在本例中为fake)依赖于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

ABI,第3.2.1节说:

寄存器%rbp、%rbx和%r12到%r15"属于"主叫函数和被调用函数是需要保存它们的价值。换句话说,被调用的函数必须保留这些寄存器为调用者的值。剩余的寄存器"属于"被调用者函数。如果一个调用函数想要在a中保留这样一个寄存器值函数调用时,它必须将值保存在其本地堆栈帧中。

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

gcc将不会使这样的显式注册变量被调用保存。基本上,你使用的这个寄存器符号使变量成为寄存器的直接别名,假设你希望能够读回被调用者在寄存器中留下的值。如果使用被调用者保存的寄存器而不是调用者保存的寄存器,问题就会解决。

最新更新