翻译自:Understanding ld-linux.so.2

前言

ld-linux.so.2是linux的动态加载器(dynamic loader)。本文试图就ld-linux.so.2如何与Linux交互,如何与正在调用的应用程序进行交互 给出一个概述。

什么是ld-linux.so

现在,大多数程序都是动态链接的。 当操作系统加载一个动态链接的应用程序时,它必须找到并加载它执行该应用程序所依赖的动态库。 在linux系统上,这份工作由ld-linux.so.2处理。 你可以对一个应用程序 或 动态库使用ldd命令查看他依赖哪些库。

root@ubuntu:/lib# ldd `which ls`
linux-vdso.so. => (0x00007ffdb075f000)
libselinux.so. => /lib/x86_64-linux-gnu/libselinux.so. (0x00007fb9e3650000)
libc.so. => /lib/x86_64-linux-gnu/libc.so. (0x00007fb9e3286000)
libpcre.so. => /lib/x86_64-linux-gnu/libpcre.so. (0x00007fb9e3016000)
libdl.so. => /lib/x86_64-linux-gnu/libdl.so. (0x00007fb9e2e11000)
/lib64/ld-linux-x86-.so. (0x00005607fd069000)
libpthread.so. => /lib/x86_64-linux-gnu/libpthread.so. (0x00007fb9e2bf4000)

当应用程序ls被加载到内存时,OS将控制权传递给ld-linux.so.2,而不是应用程序ls的正常入口点。 ld-linux.so.2搜索并加载未解析的库,然后将控制权传递给应用程序的起始点。

ld-linux.so.2的man手册页给了动态链接器(dynamic linker)一个高层次的概述。 ld-linux.so.2是链接器(linker)(ld)的运行时组件,它定位应用程序使用的动态库并将其加载到内存中。 通常,在链接期间隐式指定动态链接器。 ELF规范说GCC包含一个名为INTERP的特殊ELF程序头,它的p_type为PT_INTERP。 此程序头指定解释器(interpreter)的路径。 您可以使用readelf命令检查给定程序的程序头:

root@ubuntu:/lib# readelf -l `which ls`

Elf file type is EXEC (Executable file)
Entry point 0x4049a0
There are program headers, starting at offset Program Headers:
Type Offset VirtAddr PhysAddr
FileSiz MemSiz Flags Align
PHDR 0x0000000000000040 0x0000000000400040 0x0000000000400040
0x00000000000001f8 0x00000000000001f8 R E
INTERP 0x0000000000000238 0x0000000000400238 0x0000000000400238
0x000000000000001c 0x000000000000001c R
[Requesting program interpreter: /lib64/ld-linux-x86-.so.]
LOAD 0x0000000000000000 0x0000000000400000 0x0000000000400000
0x000000000001da64 0x000000000001da64 R E
LOAD 0x000000000001de00 0x000000000061de00 0x000000000061de00
0x0000000000000800 0x0000000000001568 RW
DYNAMIC 0x000000000001de18 0x000000000061de18 0x000000000061de18
0x00000000000001e0 0x00000000000001e0 RW
NOTE 0x0000000000000254 0x0000000000400254 0x0000000000400254
0x0000000000000044 0x0000000000000044 R
GNU_EH_FRAME 0x000000000001a5f4 0x000000000041a5f4 0x000000000041a5f4
0x0000000000000804 0x0000000000000804 R
GNU_STACK 0x0000000000000000 0x0000000000000000 0x0000000000000000
0x0000000000000000 0x0000000000000000 RW
GNU_RELRO 0x000000000001de00 0x000000000061de00 0x000000000061de00
0x0000000000000200 0x0000000000000200 R Section to Segment mapping:
Segment Sections... .interp
.interp .note.ABI-tag .note.gnu.build-id .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rela.dyn .rela.plt .init .plt .plt.got .text .fini .rodata .eh_frame_hdr .eh_frame
.init_array .fini_array .jcr .dynamic .got .got.plt .data .bss
.dynamic
.note.ABI-tag .note.gnu.build-id
.eh_frame_hdr .init_array .fini_array .jcr .dynamic .got

ELF规范要求如果存在PT_INTERP部分,则操作系统必须创建解释器文件段(interpreter's file segments)的进程映像,而不是应用程序的过程映像。 然后控制权转到解释器,解释器负责加载动态库。 ELF规范在如何给出控制方面提供了一定程度的灵活性。 对于x86 / Linux,传递给动态加载程序的参数是指向mmap'd节的指针。

编译细节

Glibc负责创建ld-linux.so.2。在glibc 2.3.2版中,使用以下命令创建文件:

gcc -nostdlib -nostartfiles -shared \
-o /home/dww4s/packages/glibc-build/elf/ld.so \
-Wl,-z,combreloc -Wl,-z,defs \
/home/dww4s/packages/glibc-build/elf/librtld.os \
-Wl,--version-script=/home/dww4s/packages/glibc-build/ld.map \
-Wl,-soname=ld-linux.so. \
-T /home/dww4s/packages/glibc-build/elf/ld.so.lds

通过-shared标志,将构建一个名为ld.so的共享库。ld.so的符号链接是ld-linux.so.2。唯一的输入是librtld.os,它在make过程的早期通过命令创建了几行:

gcc -nostdlib -nostartfiles -r \
-o /home/dww4s/packages/glibc-build/elf/librtld.os \
'-Wl,-(' \
/home/dww4s/packages/glibc-build/elf/dl-allobjs.os \
/home/dww4s/packages/glibc-build/elf/rtld-libc.a \
-lgcc \
'-Wl,-)'

因此,作为librtld.os包含的文件dl-allobjs.os,rtld-libc.a以及libgcc.so。 请注意使用-Wl前缀发送到链接器的参数 - (和 - )。 这些参数告诉链接器迭代存档直到达到稳定状态。 dl-allobjs.os和rtld-libc.a包含共享库的目标文件以及入口点_start。 _start在rtld.c中定义,来自头文件dl-machine.h中包含的宏(RTLD_START)。 宏扩展为内联程序集,用于定义_start符号,并调用函数_dl_start。 由于ld-linux.so.2有一个_start符号,因此可以直接运行。

最新文章

  1. Python之路 day2 字符串/元组/列表/字典互转
  2. PHP实现文件上传下载——心在忙而已
  3. Android课程---环境配置很重要
  4. 12-8下午 php语法
  5. AngularJs 返回上一页
  6. 黑马程序员_Java基础:十进制转换其他进制
  7. 20145208 实验五 Java网络编程
  8. JDK的版本历史
  9. CSU 1808 地铁
  10. js导出execl兼容ie Chrome Firefox各种主流浏览器(js export execl)
  11. C#代码生成工具:文本模板初体验 使用T4批量修改实体框架(Entity Framework)的类名
  12. python学习:递归列出目录里的文件
  13. typename的用法
  14. Effective Java -- 使可变性最小化
  15. Day8 Python基础之遗漏知识点(六)
  16. np.tile语法
  17. ubuntu 16042 安装过程
  18. C#学习笔记(12)——三种方法操作XML
  19. Microsoft Word 2010/2013 无法创建工作文件 请检查临时环境变量
  20. tomcat 的线程池配置,字符编码设置

热门文章

  1. 【线段树】HDU 1166 敌兵布阵
  2. 【Leetcode_easy】965. Univalued Binary Tree
  3. react 生命周期图解
  4. MockMvc 进行 controller层单元测试 事务自动回滚 完整实例
  5. 14点睛Spring4.1-脚本编程
  6. cmake vs qmake
  7. nlp算法
  8. tp5 关键字模糊查询 日期查询 小于大于某范围等查询的优点
  9. QT release版QAudioDeviceInfo获取不到音频设备,而debug版可以获取到
  10. Linux基础-10-网络原理和基础设置