gcc保留被调用者保存寄存器

时间:2016-03-31 20:22:22

标签: c gcc x86-64 abi

您可能已经猜到了问题是gcc是否会自动保存被调用者保存寄存器,还是我自己应该这样做?我认为gcc会为我做,但是当我写这段代码时

void foo(void) {
    __asm__ volatile ("mov $123, %rbx");
}

void main(void) {
    foo();
}

gcc a.c && objdump -d a.out之后我看到了这个

00000000004004f6 <foo>:
  4004f6:   55                      push   %rbp
  4004f7:   48 89 e5                mov    %rsp,%rbp
  4004fa:   48 c7 c3 7b 00 00 00    mov    $0x7b,%rbx
  400501:   90                      nop
  400502:   5d                      pop    %rbp
  400503:   c3                      retq   

0000000000400504 <main>:
  400504:   55                      push   %rbp
  400505:   48 89 e5                mov    %rsp,%rbp
  400508:   e8 e9 ff ff ff          callq  4004f6 <foo>
  40050d:   90                      nop
  40050e:   5d                      pop    %rbp
  40050f:   c3                      retq

根据x86-64 ABI %rbx是一个被调用者保存寄存器,但在此代码中gcc在修改之前没有将其保存在foo中。是因为我在调用%rbx之后没有在主要功能中使用foo(),或者它是因为gcc没有提供此类保证,我必须保存它在修改之前我自己在foo

2 个答案:

答案 0 :(得分:3)

Gcc将自动保存并恢复所有被调用者保存寄存器已知的。它知道它自己使用的寄存器,但是如果你告诉它,它只会知道内联汇编中使用的寄存器。这就是'clobbers'列表的用途:

void foo(void) {
    __asm__ volatile ("mov $123, %%rbx" : : : "rbx");
}

现在编译器知道你正在使用/修改rbx,所以它会在需要的时候保存它。

请注意,你真的想这样做,而不是试图自己保存它,因为这样只有gcc也想在这个函数中使用寄存器来保存一次。

答案 1 :(得分:1)

这将是一个非常恶劣的代码,通过死记硬背保存和恢复每个寄存器。编译器将寄存器保存在它编译的C代码中,但是你自己在这里,gcc不知道你的意图是什么。

汇编程序允许您进入引擎盖,但它不会替换火花塞。