我在一个名为test.c的文件中有这个简单的C程序:
void fx2(){
int c = 30;
c++;
}
void fx1(){
int b = 20;
b++;
fx2();
}
int main(){
int a = 10;
a++;
fx1();
}
我在Ubuntu(22.04.3)x86_64系统中使用“gcc test.c -o test”编译了这个代码。然后我使用“objdump -d test”得到了这个:
0000000000001129 <fx2>:
1129: f3 0f 1e fa endbr64
112d: 55 push %rbp
112e: 48 89 e5 mov %rsp,%rbp
1131: c7 45 fc 1e 00 00 00 movl $0x1e,-0x4(%rbp)
1138: 83 45 fc 01 addl $0x1,-0x4(%rbp)
113c: 90 nop
113d: 5d pop %rbp
113e: c3 ret
000000000000113f <fx1>:
113f: f3 0f 1e fa endbr64
1143: 55 push %rbp
1144: 48 89 e5 mov %rsp,%rbp
1147: 48 83 ec 10 sub $0x10,%rsp
114b: c7 45 fc 14 00 00 00 movl $0x14,-0x4(%rbp)
1152: 83 45 fc 01 addl $0x1,-0x4(%rbp)
1156: b8 00 00 00 00 mov $0x0,%eax
115b: e8 c9 ff ff ff call 1129 <fx2>
1160: 90 nop
1161: c9 leave
1162: c3 ret
0000000000001163 <main>:
1163: f3 0f 1e fa endbr64
1167: 55 push %rbp
1168: 48 89 e5 mov %rsp,%rbp
116b: 48 83 ec 10 sub $0x10,%rsp
116f: c7 45 fc 0a 00 00 00 movl $0xa,-0x4(%rbp)
1176: 83 45 fc 01 addl $0x1,-0x4(%rbp)
117a: b8 00 00 00 00 mov $0x0,%eax
117f: e8 bb ff ff ff call 113f <fx1>
1184: b8 00 00 00 00 mov $0x0,%eax
1189: c9 leave
118a: c3 ret
我还在macOS(Monteray 12.6.5)x86_64系统中使用“clang test.c -o test”编译了test.c。然后我使用“otool -tV测试”,我得到了这个:
(__TEXT,__text) section
_fx2:
0000000100003f40 pushq %rbp
0000000100003f41 movq %rsp, %rbp
0000000100003f44 movl $0x1e, -0x4(%rbp)
0000000100003f4b movl -0x4(%rbp), %eax
0000000100003f4e addl $0x1, %eax
0000000100003f51 movl %eax, -0x4(%rbp)
0000000100003f54 popq %rbp
0000000100003f55 retq
0000000100003f56 nopw %cs:(%rax,%rax)
_fx1:
0000000100003f60 pushq %rbp
0000000100003f61 movq %rsp, %rbp
0000000100003f64 subq $0x10, %rsp
0000000100003f68 movl $0x14, -0x4(%rbp)
0000000100003f6f movl -0x4(%rbp), %eax
0000000100003f72 addl $0x1, %eax
0000000100003f75 movl %eax, -0x4(%rbp)
0000000100003f78 callq _fx2
0000000100003f7d addq $0x10, %rsp
0000000100003f81 popq %rbp
0000000100003f82 retq
0000000100003f83 nopw %cs:(%rax,%rax)
0000000100003f8d nopl (%rax)
_main:
0000000100003f90 pushq %rbp
0000000100003f91 movq %rsp, %rbp
0000000100003f94 subq $0x10, %rsp
0000000100003f98 movl $0xa, -0x4(%rbp)
0000000100003f9f movl -0x4(%rbp), %eax
0000000100003fa2 addl $0x1, %eax
0000000100003fa5 movl %eax, -0x4(%rbp)
0000000100003fa8 callq _fx1
0000000100003fad xorl %eax, %eax
0000000100003faf addq $0x10, %rsp
0000000100003fb3 popq %rbp
0000000100003fb4 retq
我的问题是
1.考虑到这个简单的C程序,我能100%确定otool和objdump显示了包含在可执行“测试”中的确切机器指令吗?例如,两个函数序言指令pushq %rbp
和movq %rsp,%rbp
是否真的包含在实际的可执行“测试”中,或者这些反汇编程序是否可以省略/添加/修改指令以使程序更容易阅读和遵循?
1.看起来Ubuntu和macOS中的gcc和clang分别使用帧指针。我们可以说Ubuntu和macOS系统确实使用帧指针,或者说只有Ubuntu和macOS上下文中的特定编译器gcc和clang分别使用帧指针更合适吗?
2条答案
按热度按时间3htmauhk1#
考虑到这个简单的C程序,我能100%确定otool和objdump显示了可执行测试中包含的确切机器指令吗?例如,两个函数序言指令pushq %rbp和movq %rsp,%rbp”是否真的包含在实际可执行的“测试”中,或者这些反汇编程序可以省略/添加/修改指令以使程序更容易阅读和遵循?
它们不能总是显示“精确的”机器指令,因为当可执行文件在内存中被分配地址时,可能会发生重新定位,并且当程序被加载时,指令流中的地址会被更新。
除此之外,它们应该显示可执行文件中的实际指令,除了使用不同的助记符或具有相同含义的显示变体之外,可能包括对多个指令使用助记符。
看起来Ubuntu和macOS中的gcc和clang分别使用帧指针。我们是否可以说Ubuntu和macOS系统确实使用了帧指针,或者说只有Ubuntu和macOS上下文中的特定编译器gcc和clang才使用帧指针?
Clang和GCC都有一个不使用帧指针的开关
-fomit-frame-pointer
,所以很明显它们并不总是使用帧指针。根据在高性能代码中使用它的经验,不使用帧指针的主要影响是它会中断调试,因为调试器(至少在macOS环境中)依赖于帧指针来获取有关调用树中进一步例程的一些信息。z18hc3ub2#
1.反汇编程序通常精确地发出可执行文件中的指令。他们可能会遇到一些麻烦,二进制数据与指令以一种不会混淆处理器的方式穿插在一起,但可能会使反汇编程序难以决定代码在哪里继续。例如,clang编译器似乎生成“无意义”字节作为填充,以便下一个函数在16字节边界上开始,这对缓存行为有好处。反汇编程序不知道这一点,并试图将它们解释为指令。
1.使用帧指针(以及哪些寄存器用于参数和返回值传递)是ABI或调用约定的一部分,通常用于平台(操作系统),并由该平台的编译器遵循。一些语言可能在内部使用不同的调用约定,但在与C库代码交互时使用标准平台约定。