您可能已经猜到了问题是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
?
答案 0 :(得分:3)
Gcc将自动保存并恢复所有被调用者保存寄存器已知的。它知道它自己使用的寄存器,但是如果你告诉它,它只会知道内联汇编中使用的寄存器。这就是'clobbers'列表的用途:
void foo(void) {
__asm__ volatile ("mov $123, %%rbx" : : : "rbx");
}
现在编译器知道你正在使用/修改rbx,所以它会在需要的时候保存它。
请注意,你真的想这样做,而不是试图自己保存它,因为这样只有gcc也想在这个函数中使用寄存器来保存一次。
答案 1 :(得分:1)
这将是一个非常恶劣的代码,通过死记硬背保存和恢复每个寄存器。编译器将寄存器保存在它编译的C代码中,但是你自己在这里,gcc不知道你的意图是什么。
汇编程序允许您进入引擎盖,但它不会替换火花塞。