为何.o文件Objdump反汇编看不到函数名,二进制反汇编能看到?

reteitre 2016-10-04 11:45:25
我的预想是:
(1) 在编译阶段,gcc -c使得函数调用被一个名称占位符写入,也就是call strlen, call write这种,而真正的strlen,write的地址要在链接的阶段,被真正的地址取代。

(2) 在链接的阶段,因为strlen和write函数的真正地址被gcc知道了,所以用真实的地址去取代call strlen当中
的strlen,变成一个数字。

首先我有两个.c文件,一个有main函数,一个定义了a函数,如下:

$ cat m.c
void a(char*);
int main(int argc,char*argv[])
{
char s[]="hello\n";
a(s);
return 0;
}

$ cat a.c
#include<unistd.h>
#include<string.h>
void a(char*s)
{
write(1,s,strlen(s));
}

复制代码
我用gcc -c 编译它们,然后用objdump -d看它们的反汇编结果:

$ objdump -d a.o
a.o: 文件格式 elf64-x86-64
Disassembly of section .text:

0000000000000000 <a>:
0: 55 push %rbp
1: 48 89 e5 mov %rsp,%rbp
4: 48 83 ec 10 sub $0x10,%rsp
8: 48 89 7d f8 mov %rdi,-0x8(%rbp)
c: 48 8b 45 f8 mov -0x8(%rbp),%rax
10: 48 89 c7 mov %rax,%rdi
13: e8 00 00 00 00 callq 18 <a+0x18>
18: 48 89 c2 mov %rax,%rdx
1b: 48 8b 45 f8 mov -0x8(%rbp),%rax
1f: 48 89 c6 mov %rax,%rsi
22: bf 01 00 00 00 mov $0x1,%edi
27: e8 00 00 00 00 callq 2c <a+0x2c>
2c: 90 nop
2d: c9 leaveq
2e: c3 retq

看起来在a.o文件里面,两个call指令并没有对应的函数名,而是变成了地址callq 18和callq 2c,然后

$ gcc m.o a.o -o m
$ objdump -d m

复制代码
可看到a函数的反汇编代码:

000000000040062c <a>:
40062c: 55 push %rbp
40062d: 48 89 e5 mov %rsp,%rbp
400630: 48 83 ec 10 sub $0x10,%rsp
400634: 48 89 7d f8 mov %rdi,-0x8(%rbp)
400638: 48 8b 45 f8 mov -0x8(%rbp),%rax
40063c: 48 89 c7 mov %rax,%rdi
40063f: e8 5c fe ff ff callq 4004a0 <strlen@plt>
400644: 48 89 c2 mov %rax,%rdx
400647: 48 8b 45 f8 mov -0x8(%rbp),%rax
40064b: 48 89 c6 mov %rax,%rsi
40064e: bf 01 00 00 00 mov $0x1,%edi
400653: e8 38 fe ff ff callq 400490 <write@plt>
400658: 90 nop
400659: c9 leaveq
40065a: c3 retq
40065b: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1)

复制代码
这个是有函数名的。

看到的结果,和我预想的相反。我的理解错在哪里,为什么编译阶段生成的.o只有地址,没有名称,链接之后反而变成了名称,而不是地址?
...全文
2254 2 打赏 收藏 转发到动态 举报
写回复
用AI写文章
2 条回复
切换为时间正序
请发表友善的回复…
发表回复
赵4老师 2016-10-05
  • 打赏
  • 举报
回复
gcc是开源的。
fefe82 2016-10-05
  • 打赏
  • 举报
回复
实际不是 callq 18 和 callq 2c ,是 callq +0 。 callq 指令里放的相对的偏移,填的都是零。在最后链接的时候才填上的具体内容。所以在 .o 里也就看不到实际被调用的函数。 .o 会有一个地方,记录着所有需要重新填写地址的函数列表,以及这些函数在程序中哪里被调用了。 链接只有 ,callq 后面被填入了真正的偏移。于是反汇编器可以根据这个偏移找到函数的真正的地址,然后根据地址在符号表或者调试信息找到这个函数的名字。函数名是不会即在指令里的。

65,213

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧