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

我们知道,与静态库不同,动态库不会在可执行文件中有任何副本,那么为什么编译链接时依然需要指定动态库呢?原因包括下面几点:

1)动态加载器需要知道可执行程序依赖的动态库,这样在加载可执行程序时才能加载其依赖的动态库。所以,在链接时,链接器将根据可执行程序引用的动态库中的符号的情况在dynamic段中记录可执行程序依赖的动态库。我们使用如下命令将foo1.c和foo2.c编译为动态库,并将hello链接到动态库libfoo.so。
root@baisheng:~/demo# gcc -shared -fPIC foo1.c foo2.c -o libfoo.so
root@baisheng:~/demo# gcc hello.c -o hello -L./ -lfoo

我们来查看hello中的dynamic段:
root@baisheng:~/demo# readelf -d hello | grep Shared
 0x00000001 (NEEDED)                     Shared library: [libfoo.so]
 0x00000001 (NEEDED)                     Shared library: [libc.so.6]

显然,在dynamic段中,记录了hello依赖的动态链接库libfoo.so。

2)链接器需要在重定位表中创建重定位记录(Relocation Record),这样当动态链接器加载hello时,将依据重定位记录重定位hello引用的这些外部符号。重定位记录存储在ELF文件的重定位段(Relocation)中,ELF文件中可能有多个段包含需要重定位的符号,所以可能会包含多个重定位段。以hello的重定位段为例:
root@baisheng:~/demo# readelf -r hello
Relocation section '.rel.dyn' at offset 0x3d4 contains 2 entries:
 Offset     Info    Type             Sym.Value  Sym. Name
08049ffc  00000206 R_386_GLOB_DAT    00000000   __gmon_start__
0804a020  00000905 R_386_COPY        0804a020   foo2
Relocation section '.rel.plt' at offset 0x3e4 contains 3 entries:
 Offset     Info    Type             Sym.Value  Sym. Name
0804a00c  00000207 R_386_JUMP_SLOT   00000000   __gmon_start__
0804a010  00000307 R_386_JUMP_SLOT   00000000   __libc_start_main
0804a014  00000507 R_386_JUMP_SLOT   00000000   foo2_func

根据输出可见,可执行文件hello包含两个重定位段,“.rel.dyn”段中记录的是加载时需要重定位的变量,“.rel.plt”段中记录的是需要重定位的函数。

因此,虽然编译时不需要链接共享库,但是可执行文件中需要记录其依赖的共享库以及加载/运行时需要重定位的条目,在加载程序时,动态加载器需要这些信息来完成加载时重定位。

最后我们再来关注一下在hello中的全局符号foo2和foo2_func。
root@baisheng:~/demo# nm hello | grep foo
0804a020 B foo2
         U foo2_func

在符号表中,我们看到,foo2_func是Undefined的,这没错,因为其确实不在hello中定义。但是注意变量foo2,理论上它也应该是Undefined的,但是我们看到其在hello中是有定义的,而且其还在BSS段中。换句话说,虽然我们在hello中没有定义一个未初始化的全局变量,但是链接器却偷偷在hello中定义了一个未初始化的变量foo2。那么,这个foo2与libfoo.so中的全局变量foo2是什么关系呢?为什么编译器要这样做?这也是和重定位有关的,事实上,这种重定位方式称为“Copy relocation”,后面我们在讨论用户进程的加载时将会进一步介绍。

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

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