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

我在GCC有一个场景给我带来了问题。 我得到的行为不是我期望的行为。 总结一下这种情况,我提出了一些x86-64的新指令,这些指令是在硬件模拟器中实现的。 为了测试这些指令,我使用现有的C源代码并使用hex对新指令进行手动编码。 因为这些指令与现有的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 

ABI ,第3.2.1节说:

寄存器%rbp,%rbx和%r12到%r15“属于”调用函数,并且需要被调用函数来保存它们的值。 换句话说,被调用函数必须为其调用者保留这些寄存器的值。 剩余寄存器“属于”被调用函数。 如果调用函数想要在函数调用中保留这样的寄存器值,则必须将该值保存在其本地堆栈帧中。

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

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