为何.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只有地址,没有名称,链接之后反而变成了名称,而不是地址?
...全文
2131 2 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
2 条回复
切换为时间正序
请发表友善的回复…
发表回复
赵4老师 2016-10-05
  • 打赏
  • 举报
回复
gcc是开源的。
fefe82 2016-10-05
  • 打赏
  • 举报
回复
实际不是 callq 18 和 callq 2c ,是 callq +0 。 callq 指令里放的相对的偏移,填的都是零。在最后链接的时候才填上的具体内容。所以在 .o 里也就看不到实际被调用的函数。 .o 会有一个地方,记录着所有需要重新填写地址的函数列表,以及这些函数在程序中哪里被调用了。 链接只有 ,callq 后面被填入了真正的偏移。于是反汇编器可以根据这个偏移找到函数的真正的地址,然后根据地址在符号表或者调试信息找到这个函数的名字。函数名是不会即在指令里的。
反汇编带符号表的32位/64位ELF目标文件,CPU类型:ARM PowerPC MIPS X86 操作菜单选择:文件解析 Alx+P ELF文件解析 Alt+E 另有文本比较等杂项功能。V1.26.00相对上一版本,增强EXE反汇编,增加dbx老邮件解析、二维码功能,;V1.25.07相对上一版本,增加二进制反汇编、IQ数据解析功能,完善MIPS反汇编,修复小BUG;V1.25.05相对上一版本,增加内存数据按数据类型解析功能;V1.25.04相对上一版本,完善X86反汇编,修复小BUG;V1.25.02相对上一版本,COREDUMP统计、匹配目标文件等相关功能优化,修复小BUG;V1.25.00相对上一版本,相关功能支持动态库文件,查询代码支持无符号目标文件+有符号目标文件,COREDUMP统计、与问题单关联、目标文件/CORE文件/问题单同步;V1.24.02相对上一版本,针对进程主动捕捉异常的信息定制处理进一步完善COREDUMP文件解析与应用,增强软件管理;V1.24.01相对上一版本,进一步完善COREDUMP文件解析与应用,提供部分ARM Thumb指令反汇编;V1.24.00相对上一版本,进一步完善COREDUMP文件解析与应用,提供堆栈调用关系分析;V1.23.03相对上一版本,提供32位X86反汇编;V1.23.02相对上一版本,提供源代码行查询指令地址,OBJ/COREDUMP文件解析,sprintf函数参数特定检查,完善文件拖放操作,修复小BUG;V1.23.01相对上一版本,提供ELF文件指令修改,修复ARM MLS指令反汇编错误等BUG;V1.23.00相对上一版本,提供程序地址对应源代码行查询,修复MIPS调试信息错误;V1.22相对上一版本,修复MIPS小端字节序反汇编错误,网上最新版本提示;V1.21相对上一版本,菜单调整,完善64位ELF文件解析,解析调试信息;另部分增强功能的菜单操作设有密码,如有兴趣欢迎咨询。欢迎大家反馈相关软件使用过程中的问题!

65,185

社区成员

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

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