///

不需要牛刀,不需要阅读源码,如果只是为解决109的含义。楼主执行的查询命令readelf -S  test2.o

[ 8] .symtab           SYMTAB          00000000 0002a8 0000c0 10         9   7  4

.symtab起始于2a8,保存了符号信息,根据楼主提供的test2.o,从2a8开始,读到367:

00002a8:             0000 0000 0000 0000

00002b0: 0000 0000 0000 0000 0100 0000 0000 0000  ................

00002c0: 0000 0000 0400 f1ff 0000 0000 0000 0000  ................

00002d0: 0000 0000 0300 0100 0000 0000 0000 0000  ................

00002e0: 0000 0000 0300 0300 0000 0000 0000 0000  ................

00002f0: 0000 0000 0300 0400 0000 0000 0000 0000  ................

0000300: 0000 0000 0300 0500 0000 0000 0000 0000  ................

0000310: 0000 0000 0300 0600 0900 0000 0000 0000  ................

0000320: 0400 0000 1100 0300 0b00 0000 0400 0000  ................

0000330: 0400 0000 1100 0300 0d00 0000 0800 0000  ................

0000340: 0400 0000 1100 0300 0f00 0000 0000 0000  ................

0000350: 0e00 0000 1200 0100 1300 0000 0e00 0000  ................

0000360: 5200 0000 1200 0100

我们按照8字节为一个整体,数7个(前6个是symtab头不信息?),到了318:

0900 0000 0000 0000 0400 0000 1100 0300

其中0900就是符号的具体位置偏移,我们再从368开始看.strtab:

0074 6573 7432 2e63 0061 0062 0063 0066 756e 006d 6169 6e00

自己数数09位置是什么?没错就是61,它是“a”的asic的16进制值。

以此类推,0b是“b”,0d是“c”。

讲到这里,0109、0108、0107的秘密应该大白天下了吧?二楼已经讲了01是object,你在1100中的第二个`1`指的就是这个。而09、08、07,指的就是.symtab按八字节为一整块算时的块号罢了!每个块代表一个符号,并给出了strtab中相应字符串的位置偏移和属性解释!

以上结论纯属观察,本人完全不懂编译原理,哈哈^_^

//

不是搞编译的,只是记得以前看过一些介绍的文章,尝试解答一下。

.text+2a:

2a:   ff 35 00 00 00 00       pushl  0x0

很明显,这是在push一个参数,只是在编译的时候,由于不知道最后的地址,操作数暂时为0。

经过了链接阶段,所有变量的地址都确定了,就可以替换这些临时的操作数了。

如楼主所言,这些信息是保留在elf文件的relcoation section里的。

代码中一共有8处引用全局变量

#fun(a, b, c)

[2a]:   ff 35 00 00 00 00       pushl  0x0

[30]:   ff 35 00 00 00 00       pushl  0x0

[36]:   ff 35 00 00 00 00       pushl  0x0

[3c]:   e8 fc ff ff ff          call   3d

#func(c, b, a)

[44]:   ff 35 00 00 00 00       pushl  0x0

[4a]:   ff 35 00 00 00 00       pushl  0x0

[50]:   ff 35 00 00 00 00       pushl  0x0

[56]:   e8 fc ff ff ff          call   57

.rel.text:

0000380: [2c00] 0000 <0109> 0000 [3200] 0000 <0108> 0000  ,.......2.......

0000390: [3800] 0000 <0107> 0000 [3d00] 0000 <020a> 0000  8.......=.......

00003a0: [4600] 0000 <0108> 0000 [4c00] 0000 <0107> 0000  F.......L.......

00003b0: [5200] 0000 <0109> 0000 [5700] 0000 <020a> 0000  R.......W.......

00003c0: 0a

显然,.rel.text需要描述这8个对全局变量的引用,并观察到[]里的地址的相似性,

因此可以推测,每个引用占8个字节。

并且,<>里面的部分可以分为两类:6个传参的属于一类01**,函数调用属于一类02**。

猜测**是变量/函数名在符号表中的id。

观察其中一组01类型的:

.text:

[2a]:   ff 35 [00 00 00 00]       pushl  0x0

.rel.text:

0000380: [2c00] 0000 <0109> 0000

2c正好是2a(push指令的地址)+2(push操作码ff35的长度),这就告诉ld,

在连接的时候,需要把2c的内容(就是push指令的参数)替换掉(当前为0)。

替换成什么内容,由<0109>决定。01是一种类型,09应该是变量在symbol表中的id。

由于楼主没有贴出test.o经过linker链接后的结果,手头也没有32bit的机器,所以就不太好猜了……

最简单的可能性是,linker直接替换为变量的绝对地址。

至于02类型的:

3c:   e8 fc ff ff ff          call   3d

0000398: [3d00] 0000 <020a> 0000

分析同上,3d=3c(call指定的地址)+1(call操作码的长度),就是call的参数的地址。

我手头有64bit的机器,传参和函数调用都被编译为02类型的,通过readelf可以看到,02属于R_X86_64_PC32类型。

实际上,这个call是个相对jmp,参数是相对于当前ip/pc的偏移,在.o文件里,目的地址是-4(0xfffffffc),就是这条指令本身。

可以想象,在ld阶段,-4会被替换为func函数跟call指令之间的地址差值。

(实际上,由于func是编译单元内部的函数调用,这个差值在编译阶段也可以确定的。)

由于<02>是相对偏移,因此[3c]和[56]虽然都是call $func,它们的偏移值是不一样的,所以两条指令并不相同。

作为对比,30和4a都是push $b,如果<01>类型是绝对地址的话,那么两条指令就完全一样。

以上,啰啰嗦嗦的,不知道有没有说清楚。

1,调用fun前,将a,b,c作为参数压栈,我们只看到连续push三个0,因为编译阶段,a,b,c的地址都不确定,暂时用0代替。

2,到了链接阶段,linker会搜集所有.o文件中的符号,并放到一张全局符号表里。像a,b,c,它们就有名字“a","b","c",并算出了对应的地址,就这样存到全局符号表里。

3,之前说到的,那三条push 0的指令,它们对应的机器码,是存储在test2.o的.text段的,这时候当然要把那三个零换成a,b,c的地址。

4,linker是根据test.o的.rel.text段来完成这个重定位的。.rel.text段是一个表,每个entry(表项)8个字节,数据结构是这样:

struct{

unsigned      r_offset;

usnigned      r_info;

}

linker根据r_offset知道,要修正的位置相对于.text段的偏移。就这样定位到那三个0的位置。

根据r_info知道要修正的是哪个符号。再说细点:linker根据r_info的高24位在全局符号表里索引到这个符号,这样,符号的地址就

顺藤摸瓜的出来了。把它写入r_offset处。

这样重定位就完成了。

----------------以上是就32位elf来说的,某些叙述有简化。你可以去看《程序员的自我修养》

最新文章

  1. 【WPF】一个简单的ColorPicker控件
  2. 烟雾检测电路c语言程序,烟雾报警器电路图大全(六款模拟电路设计原理图详解)...
  3. python 不得不知的第三方库以及常用安装包
  4. 前端学习(1598):ref转发
  5. 360浏览器打不开qq空间_刘连康:解决电脑网络正常,浏览器打不开的问题
  6. HiveQL:文件格式和压缩方法
  7. 刚入行的测试工程师如何自学软件测试【下篇】-- 软实力
  8. vue中使用element-ui的表单验证功能prop属性
  9. linux中断处理体系结构
  10. Java jar 包免费下载(全)
  11. android 支付接口
  12. Win10环境下ubuntu安装教程
  13. 微软招 HR 了!看来是招聘需求太旺盛,忙不过来了
  14. 传奇服务器常见的网络攻击方式有哪些?-版本被攻击
  15. 如何消除win10文件右上角的蓝色箭头
  16. Swing交通罚单管理系统java车辆违章缴费金额查询交警信息jsp源代码Maven数据库mysql
  17. PTA团体程序设计天梯赛-练习集
  18. 除了菊纹识别,AI还有哪些奇奇怪怪的识别能力?
  19. 上海python周末培训班_上海python周末班
  20. 【持续更新】计算机类PDF整理

热门文章

  1. react 组件怎么公用_React、Redux与复杂业务组件的复用
  2. android 点击外部接收事件,Android Dialog外部点击事件
  3. 计算器中 MS、MR、M+、M- 和 MC 的功能介绍
  4. xiaocms php,XiaoCms PHP企业网站模板, ,后台可备份 WEB(ASP,PHP,...) 238万源代码下载- www.pudn.com...
  5. python中name没有定义_Python;NameError:未定义名称“handsum”
  6. 超低延迟直播架构解析
  7. centos sudo不能运行_Linux操作系统中sudo的使用和sudoers配置
  8. python正则表达式指南_Python正则表达式指南(转)
  9. 爬取虎扑NBA首页主干道推荐贴的一只小爬虫,日常爬不冷笑话解闷
  10. 学习练习 java 二分查找法