考虑以下内容:
ammarfaizi2@integral:/tmp$ vi test.c
ammarfaizi2@integral:/tmp$ cat test.c
extern void use_buffer(void *buf);
void a_func(void)
{
char buffer[4096];
use_buffer(buffer);
}
__asm__("emit_mov_rbp_to_rsp:\n\tmovq %rbp, %rsp");
ammarfaizi2@integral:/tmp$ clang -Wall -Wextra -c -O3 -fno-omit-frame-pointer test.c -o test.o
ammarfaizi2@integral:/tmp$ objdump -d test.o
test.o: file format elf64-x86-64
Disassembly of section .text:
0000000000000000 <emit_mov_rbp_to_rsp>:
0: 48 89 ec mov %rbp,%rsp
3: 66 2e 0f 1f 84 00 00 cs nopw 0x0(%rax,%rax,1)
a: 00 00 00
d: 0f 1f 00 nopl (%rax)
0000000000000010 <a_func>:
10: 55 push %rbp
11: 48 89 e5 mov %rsp,%rbp
14: 48 81 ec 00 10 00 00 sub $0x1000,%rsp
1b: 48 8d bd 00 f0 ff ff lea -0x1000(%rbp),%rdi
22: e8 00 00 00 00 call 27 <a_func+0x17>
27: 48 81 c4 00 10 00 00 add $0x1000,%rsp
2e: 5d pop %rbp
2f: c3 ret
ammarfaizi2@integral:/tmp$
在
a_func()
结束前,在返回之前,函数的结尾部分是恢复 %rsp
。它使用语句 add $0x1000, %rsp
,其结果为 48 81 c4 00 10 00 00
。它难道不能只使用语句
mov %rbp, %rsp
,其结果只有 3 个字节 48 89 ec
吗?为什么 clang 不使用更短的方式(
mov %rbp, %rsp
)呢?在代码大小方面的权衡中,使用
add $0x1000, %rsp
而不是 mov %rbp, %rsp
的优点是什么?更新(额外内容)
即使使用了
-Os
,仍会生成相同的代码。因此,我认为有一个合理的理由避免使用 mov %rbp, %rsp
。ammarfaizi2@integral:/tmp$ clang -Wall -Wextra -c -Os -fno-omit-frame-pointer test.c -o test.o
ammarfaizi2@integral:/tmp$ objdump -d test.o
test.o: file format elf64-x86-64
Disassembly of section .text:
0000000000000000 <emit_mov_rbp_to_rsp>:
0: 48 89 ec mov %rbp,%rsp
0000000000000003 <a_func>:
3: 55 push %rbp
4: 48 89 e5 mov %rsp,%rbp
7: 48 81 ec 00 10 00 00 sub $0x1000,%rsp
e: 48 8d bd 00 f0 ff ff lea -0x1000(%rbp),%rdi
15: e8 00 00 00 00 call 1a <a_func+0x17>
1a: 48 81 c4 00 10 00 00 add $0x1000,%rsp
21: 5d pop %rbp
22: c3 ret
ammarfaizi2@integral:/tmp$
clang -Os -fno-omit-frame-pointer
编译的。有时候人们会想要它(如果我没记错的话,这是-Os
GCC的默认设置),所以如果你已经强制编译器把RBP浪费在作为一个框架指针上,你要充分利用它的最大好处。但是,既然你提到了它,调整措辞以提醒读者大多数软件是没有使用-fno-omit-frame-pointer
构建的。 - Peter Cordes