免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 4894 | 回复: 7
打印 上一主题 下一主题

[C] 为何.o文件Objdump反汇编看不到函数名,二进制反汇编能看到? [复制链接]

论坛徽章:
1
2015年迎新春徽章
日期:2015-03-04 09:58:11
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2016-10-04 23:34 |只看该作者 |倒序浏览
我的预想是:
(1) 在编译阶段,gcc -c使得函数调用被一个名称占位符写入,也就是call strlen, call write这种,而真正的strlen,write的地址要在链接的阶段,被真正的地址取代。
(2) 在链接的阶段,因为strlen和write函数的真正地址被gcc知道了,所以用真实的地址去取代call strlen当中的strlen,变成一个数字。
首先我有两个.c文件,一个有main函数,一个定义了a函数,如下:
  1. $ cat m.c
  2. void a(char*);
  3. int main(int argc,char*argv[])
  4. {
  5.   char s[]="hello\n";
  6.   a(s);
  7.   return 0;
  8. }

  9. $ cat a.c
  10. #include<unistd.h>
  11. #include<string.h>
  12. void a(char*s)
  13. {
  14.   write(1,s,strlen(s));
  15. }
复制代码
我用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,然后
  1. $ gcc m.o a.o -o m
  2. $ objdump -d m
复制代码
可看到a函数的反汇编代码:
  1. 000000000040062c <a>:
  2.   40062c:        55                           push   %rbp
  3.   40062d:        48 89 e5                     mov    %rsp,%rbp
  4.   400630:        48 83 ec 10                  sub    $0x10,%rsp
  5.   400634:        48 89 7d f8                  mov    %rdi,-0x8(%rbp)
  6.   400638:        48 8b 45 f8                  mov    -0x8(%rbp),%rax
  7.   40063c:        48 89 c7                     mov    %rax,%rdi
  8.   40063f:        e8 5c fe ff ff               callq  4004a0 <strlen@plt>
  9.   400644:        48 89 c2                     mov    %rax,%rdx
  10.   400647:        48 8b 45 f8                  mov    -0x8(%rbp),%rax
  11.   40064b:        48 89 c6                     mov    %rax,%rsi
  12.   40064e:        bf 01 00 00 00               mov    $0x1,%edi
  13.   400653:        e8 38 fe ff ff               callq  400490 <write@plt>
  14.   400658:        90                           nop
  15.   400659:        c9                           leaveq
  16.   40065a:        c3                           retq   
  17.   40065b:        0f 1f 44 00 00               nopl   0x0(%rax,%rax,1)
复制代码
这个是有函数名的。

看到的结果,和我预想的相反。我的理解错在哪里,为什么编译阶段生成的.o只有地址,没有名称,链接之后反而变成了名称,而不是地址?

论坛徽章:
95
程序设计版块每日发帖之星
日期:2015-09-05 06:20:00程序设计版块每日发帖之星
日期:2015-09-17 06:20:00程序设计版块每日发帖之星
日期:2015-09-18 06:20:002015亚冠之阿尔艾因
日期:2015-09-18 10:35:08月度论坛发贴之星
日期:2015-09-30 22:25:002015亚冠之阿尔沙巴布
日期:2015-10-03 08:57:39程序设计版块每日发帖之星
日期:2015-10-05 06:20:00每日论坛发贴之星
日期:2015-10-05 06:20:002015年亚冠纪念徽章
日期:2015-10-06 10:06:482015亚冠之塔什干棉农
日期:2015-10-19 19:43:35程序设计版块每日发帖之星
日期:2015-10-21 06:20:00每日论坛发贴之星
日期:2015-09-14 06:20:00
2 [报告]
发表于 2016-10-05 00:02 |只看该作者
回复 1# asker160

你要是看看 gcc -S 生成的汇编的话,就会发现你的猜测是正确的:
$ cat func.c

  1. #include<unistd.h>
  2. #include<string.h>
  3. void a(char*s)
  4. {
  5.         write(1,s,strlen(s));
  6. }

复制代码


$ cat func.s

  1.         .file        "func.c"
  2.         .text
  3.         .globl        a
  4.         .type        a, @function
  5. a:
  6. .LFB0:
  7.         .cfi_startproc
  8.         pushq        %rbp
  9.         .cfi_def_cfa_offset 16
  10.         .cfi_offset 6, -16
  11.         movq        %rsp, %rbp
  12.         .cfi_def_cfa_register 6
  13.         subq        $16, %rsp
  14.         movq        %rdi, -8(%rbp)
  15.         movq        -8(%rbp), %rax
  16.         movq        %rax, %rdi
  17.         call        strlen
  18.         movq        %rax, %rdx
  19.         movq        -8(%rbp), %rax
  20.         movq        %rax, %rsi
  21.         movl        $1, %edi
  22.         call        write
  23.         leave
  24.         .cfi_def_cfa 7, 8
  25.         ret
  26.         .cfi_endproc
  27. .LFE0:
  28.         .size        a, .-a
  29.         .ident        "GCC: (Debian 4.9.2-10) 4.9.2"
  30.         .section        .note.GNU-stack,"",@progbits

复制代码


至于 objdump -d 给出的地址:

$ objdump -d func.o

  1. func.o:     file format elf64-x86-64


  2. Disassembly of section .text:

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

复制代码


你仔细看看实际的机器码,就会发现跳转地址都是 0。在这里 objdump -d 给出了错误的结果。

论坛徽章:
0
3 [报告]
发表于 2016-10-05 09:28 |只看该作者
如果对这个问题感兴趣,建议看看《linking and loader》,或者《程序员自我修养:链接,装载与库》

简单来说,objdump的结果是对的,指令中确实是填0,然后在elf文件中有另外的symbol table section来记录指令中哪些地方需要将地址填成哪个函数的地址,
可以使用readelf来看这些信息,

论坛徽章:
95
程序设计版块每日发帖之星
日期:2015-09-05 06:20:00程序设计版块每日发帖之星
日期:2015-09-17 06:20:00程序设计版块每日发帖之星
日期:2015-09-18 06:20:002015亚冠之阿尔艾因
日期:2015-09-18 10:35:08月度论坛发贴之星
日期:2015-09-30 22:25:002015亚冠之阿尔沙巴布
日期:2015-10-03 08:57:39程序设计版块每日发帖之星
日期:2015-10-05 06:20:00每日论坛发贴之星
日期:2015-10-05 06:20:002015年亚冠纪念徽章
日期:2015-10-06 10:06:482015亚冠之塔什干棉农
日期:2015-10-19 19:43:35程序设计版块每日发帖之星
日期:2015-10-21 06:20:00每日论坛发贴之星
日期:2015-09-14 06:20:00
4 [报告]
发表于 2016-10-05 10:51 |只看该作者
回复 3# drangon

然后在elf文件中有另外的symbol table section来记录指令中哪些地方需要将地址填成哪个函数的地址,


这些信息是在 relocation 段中记录的,不是 symbol table:

$ objdump -r func.o

  1. func.o:     file format elf64-x86-64

  2. RELOCATION RECORDS FOR [.text]:
  3. OFFSET           TYPE              VALUE
  4. 0000000000000014 R_X86_64_PC32     strlen-0x0000000000000004
  5. 0000000000000028 R_X86_64_PC32     write-0x0000000000000004


  6. RELOCATION RECORDS FOR [.eh_frame]:
  7. OFFSET           TYPE              VALUE
  8. 0000000000000020 R_X86_64_PC32     .text

复制代码


评分

参与人数 1信誉积分 +50 收起 理由
asker160 + 50 很给力!

查看全部评分

论坛徽章:
6
2015年辞旧岁徽章
日期:2015-03-05 16:13:092015年迎新春徽章
日期:2015-03-05 16:13:092015小元宵徽章
日期:2015-03-06 15:58:1815-16赛季CBA联赛之浙江
日期:2016-11-05 14:38:4115-16赛季CBA联赛之新疆
日期:2016-11-11 18:38:06
5 [报告]
发表于 2016-10-05 11:53 |只看该作者
其实gcc包括链接器都不知道最终地址,因为你用的是动态链接方式,所以要到实际运行装载时才能确定最终地址。
与此相关的记录保存在重定位表与符号表中(实际上还有字符串表,符号表中有指向字符串表的索引,重定位表中则有指向符号表的索引)
楼上推荐的《linking and loader》或者《程序员自我修养:链接,装载与库》中有详细描述

评分

参与人数 1信誉积分 +10 收起 理由
asker160 + 10 很给力!

查看全部评分

论坛徽章:
6
2015年辞旧岁徽章
日期:2015-03-05 16:13:092015年迎新春徽章
日期:2015-03-05 16:13:092015小元宵徽章
日期:2015-03-06 15:58:1815-16赛季CBA联赛之浙江
日期:2016-11-05 14:38:4115-16赛季CBA联赛之新疆
日期:2016-11-11 18:38:06
6 [报告]
发表于 2016-10-05 12:16 |只看该作者
明白了重定位机制后就可明白,.o文件其实也应该能看到函数名的(名称信息都已经保存在相应的表里了),你为什么看不到实际上是反汇编器的具体实现问题。所以这也说明了自主编译工具还是很有必要的

论坛徽章:
1
操作系统版块每日发帖之星
日期:2016-06-12 06:20:00
7 [报告]
发表于 2016-10-14 11:21 |只看该作者
同一个编译器,同样的源码,在不同平台上生成 obj文件是一样的吗?

论坛徽章:
95
程序设计版块每日发帖之星
日期:2015-09-05 06:20:00程序设计版块每日发帖之星
日期:2015-09-17 06:20:00程序设计版块每日发帖之星
日期:2015-09-18 06:20:002015亚冠之阿尔艾因
日期:2015-09-18 10:35:08月度论坛发贴之星
日期:2015-09-30 22:25:002015亚冠之阿尔沙巴布
日期:2015-10-03 08:57:39程序设计版块每日发帖之星
日期:2015-10-05 06:20:00每日论坛发贴之星
日期:2015-10-05 06:20:002015年亚冠纪念徽章
日期:2015-10-06 10:06:482015亚冠之塔什干棉农
日期:2015-10-19 19:43:35程序设计版块每日发帖之星
日期:2015-10-21 06:20:00每日论坛发贴之星
日期:2015-09-14 06:20:00
8 [报告]
发表于 2016-10-14 19:03 |只看该作者
yakczh_cu 发表于 2016-10-14 11:21
同一个编译器,同样的源码,在不同平台上生成 obj文件是一样的吗?

不一样。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP