2016-03-31 83 views
0

正如你可能已经猜到的问题是gcc自动保存被调用保存寄存器还是应该自己做?我认为gcc会为我做的,但是当我gcc a.c && objdump -d a.out后写了这个代码确实gcc保存被调用者保存寄存器

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

void main(void) { 
    foo(); 
} 

我看到这个

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 

据ABI x86-64的是%rbx被叫保存登记,但在这代码gcc在修改之前未将其保存在foo中。仅仅是因为我在调用foo()之后没有在主要功能中使用%rbx,或者因为gcc不提供这样的服务,我必须在修改之前自己将其保存在foo之前?

+2

GCC不关注你的内联asm,它只是逐字地发布它。这取决于你做正确的事情。 –

+1

这将是非常糟糕的代码,通过死记硬背保存和恢复每个寄存器。 –

+0

@WeatherVane所以这意味着'gcc'不会预先保存这个寄存器,我应该自己保存它们吗? – PepeHands

回答

3

海湾合作委员会将自动保存和恢复所有被调用者保存寄存器它的知识使用。它知道它自己使用的寄存器,但只知道内联汇编中使用的寄存器(如果你告诉它)。这就是“则会覆盖”名单是什么:

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

现在编译器知道你正在使用/修改RBX,因此,如果需要将其保存。

请注意,您确实想要这样做,而不是试图自己保存它,因为如果gcc也想在此函数中使用寄存器,它将只会被保存一次。

+0

'asm'关键字优先于'__asm__',除非您'重新编写需要工作的库代码,即使用户做了类似'#define asm 1'的工作,哦,但是OP使用了'__asm__',所以你只需要遵循该代码 –

+0

感谢您的解释良好! – PepeHands

1

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

汇编程序可以让你得到引擎盖,但它不会替代你的火花塞。