读书频道 > 系统 > linux > 深度探索Linux操作系统系统构建和原理解析
1. 合并目标文件
2013-09-28 13:24:27     我来说两句 
收藏    我要投稿   
全书一共8章:第1章介绍了如何准备工作环境。在第2章中构建了编译工具链,这是后面构建操作系统各个组件的基础。在这一章中,不仅详细讲解了工具链的构建过程,而且还通过对编译链接过程的探讨,深入讨论了工具链  立即去当当网订购

合并多个目标文件其实就是将多个目标文件的相同类型的段合并到一个段中,如图2-5所示。

 

我们来看一下目标文件和链接后的可执行文件的“.text”段。下面分别列出了目标文件hello.o、foo1.o、foo2.o以及可执行文件hello的段表中的“.text”段的相关信息。由于篇幅限制,我们删除了输出的后面几列。
root@baisheng:~/demo# readelf -S hello.o
There are 12 section headers, starting at offset 0x118:
Section Headers:
  [Nr] Name             Type            Addr       Off     Size
  [ 0]                  NULL            00000000  000000  000000     
  [ 1] .text            PROGBITS        00000000  000034  000026 
...
root@baisheng:~/demo# readelf -S foo1.o 
There are 12 section headers, starting at offset 0x104:
Section Headers:
  [Nr] Name             Type           Addr       Off      Size 
  [ 0]                  NULL           00000000  000000   000000
  [ 1] .text            PROGBITS       00000000  000034   000010
...
root@baisheng:~/demo# readelf -S foo2.o
There are 12 section headers, starting at offset 0x104:
Section Headers:
  [Nr] Name              Type           Addr       Off      Size  
  [ 0]                   NULL           00000000  000000   000000
  [ 1] .text             PROGBITS       00000000  000034   000010
...
root@baisheng:~/demo# readelf -S hello
There are 30 section headers, starting at offset 0x1198:

Section Headers:
  [Nr] Name             Type           Addr       Off      Size
...
  [13] .text            PROGBITS      080482f0   0002f0   0001b8
...

根据上面的输出结果可见,对于目标文件,并没有为目标文件中的机器指令及符号分配运行时地址。而对于可执行文件hello,链接器已经为其机器指令及符号分配了运行时地址,如对于可执行文件hello的“.text”段,其在进程地址空间中起始地址为“0x080482f0”,占据了0x1b8字节。

按照前面我们提到的目标文件合并理论,理论上三个目标文件hello.o、foo1.o、foo2.o的“.text”段的尺寸加起来应该与可执行文件hello的“.text”段的尺寸大小相等。但是,通过readelf的输出可见,三个目标文件的“.text”段的尺寸加起来是0x46(0x26 + 0x10 + 0x10)字节,远小于可执行文件hello的“.text”段的大小0x1b8。如果读者在编译时向gcc传递了参数-v,仔细观察gcc的输出可以发现,实际上在链接时链接器自作主张地链接了一些特别的文件,包括crt1.o、crti.o、crtn.o、crtbegin.o及crtend.o等,其实就是我们前面提到的启动文件。所以多出来的尺寸都是合并这些文件的“.text”导致的。

下面我们手动调用ld,不链接这些启动文件,再来对比一下“.text”段的尺寸。在默认情况下,链接器将使用函数“_start”作为可执行文件的入口,但是这个函数的实现在启动文件(crt1.o)中,因此,在这里我们通过给链接器ld传递参数“-e main”,明确告诉链接器不使用默认的“_start”了,否则链接器会找不到符号“_start”,而直接使用函数main作为可执行文件的入口。当然main函数中并没有实现启动代码的功能,在这里我们只是为了查看“.text”段的尺寸。具体如下:
root@baisheng:~/demo# ld -e main -o hello1 hello.o foo1.o foo2.o
root@baisheng:~/demo# readelf -S hello1
There are 8 section headers, starting at offset 0x1bc:
Section Headers:
  [Nr] Name             Type           Addr       Off     Size
  [ 0]                   NULL           00000000  000000  000000 
  [ 1] .text            PROGBITS      08048094  000094  000048 
...

我们看到,如果不链接那些特殊的文件,按照上面的链接方法,可执行文件的“.text”段的大小是0x48字节,依然不是0x46字节,为什么还是差了2字节?我们尝试更换一下链接时目标文件的次序:
root@baisheng:~/demo# ld -e main -o hello2 foo1.o foo2.o hello.o
root@baisheng:~/demo# readelf -S hello2
There are 8 section headers, starting at offset 0x1bc:
Section Headers:
  [Nr] Name             Type            Addr       Off     Size
  [ 0]                  NULL           00000000    000000  000000 
  [ 1] .text            PROGBITS       08048094    000094  000046 
...

这次我们看到,最终可执行文件“.text”段的尺寸与目标文件的“.text”段的尺寸和完全相同了。为什么呢?原因是在32位机器上,包括“.text”、“.data”等段有4字节对齐的要求。hello.o的“.text”段是0x26,如果按照4字节对齐,需要填充2字节。而foo1.o和foo2.o的“.text”段本身长度都是4字节对齐的,所以在合并时,如果hello.o在前面,那么其“.text”段需要使用0填充两字节,使其对齐到0x28。所以,最终“.text”的长度就是0x28 + 0x10 + 0x10,为0x48字节。而如果hello在最后,那么合并后的“.text”的长度就是0x10 + 0x10 + 0x26,即0x46字节。

点击复制链接 与好友分享!回本站首页
分享到: 更多
您对本文章有什么意见或着疑问吗?请到论坛讨论您的关注和建议是我们前行的参考和动力  
上一篇:2.1.4 链接
下一篇:2. 符号重定位
相关文章
图文推荐
3.3.6 GNOME的软件管
3.3.5 GNOME的文件管
3.3.4 GNOME的窗口管
3.3.3 收藏夹和快捷
排行
热门
文章
下载
读书

关于我们 | 联系我们 | 广告服务 | 投资合作 | 版权申明 | 在线帮助 | 网站地图 | 作品发布 | Vip技术培训
版权所有: 红黑联盟--致力于做最好的IT技术学习网站