翻译自: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符号,因此可以直接运行。

理解ld-linux.so.2的更多相关文章

  1. 彻底理解Cisco/Linux/Windows的IP路由

    -1.只要理解实质,名称并不重要! 很多使用Linux的网络高手在面对Cisco管理员的诸如管理距离,路由度量等词汇时,还没有PK就自觉败下阵来了.我觉得这实在太可惜了,大家本是一家,为何这么为难对方 ...

  2. 我理解的Linux内存管理

    众所周知,内存管理是Linux内核中最基础,也是相当重要的部分.理解相关原理,不管是对内存的理解,还是对大家写用户态代码都很有帮助.很多书上.很多文章都写了相关内容,但个人总觉得内容太复杂,不是太容易 ...

  3. Linux系统理解以及Linux系统学习心得

    原创作品转载请注明出处  <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 作者:严哲璟 说一下我对Lin ...

  4. 操作系统-多用户如何理解(Linux)

    单用户.多用户.单任务.多任务,这么多种操作系统容易让人迷糊.其实这种初看你会觉得理解了一点,但其实你仔细研究会发现,多用户到底讲的是什么鬼? 多任务比较简单,就是应用程序都要放置到内存上去给CPU调 ...

  5. [翻译]理解分析Linux里的101个ELF文件

    原文:https://linux-audit.com/elf-binaries-on-linux-understanding-and-analysis/

  6. 深入理解LINUX下动态库链接器/加载器ld-linux.so.2

    [ld-linux-x86-64.so.2] 最近在Linux 环境下开发,搞了好几天 Compiler 和 linker,觉得有必要来写一篇关于Linux环境下 ld.so的文章了,google上搜 ...

  7. 理解linux and inode

    inode是一个重要概念,是理解Unix/Linux文件系统和硬盘储存的基础. 我觉得,理解inode,不仅有助于提高系统操作水平,还有助于体会Unix设计哲学,即如何把底层的复杂性抽象成一个简单概念 ...

  8. 理解Linux文件系统之inode

    很少转发别人的文章,但是这篇写的太好了. 理解inode   作者: 阮一峰 inode是一个重要概念,是理解Unix/Linux文件系统和硬盘储存的基础. 我觉得,理解inode,不仅有助于提高系统 ...

  9. 深入理解linux关闭文件和删除文件

    背景介绍 最近看了linux系统编程(linux system programming)一书,结合深入理解linux内核(understanding the linux kernel)一书,深入理解了 ...

  10. [转]理解Linux文件系统之inode

    很少转发别人的文章,但是这篇写的太好了. 理解inode   作者: 阮一峰 inode是一个重要概念,是理解Unix/Linux文件系统和硬盘储存的基础. 我觉得,理解inode,不仅有助于提高系统 ...

随机推荐

  1. SAS如何看待大数据

    SAS如何看待大数据 "大数据"现在是一个炙手可热的词语,数据分析师这个词虽然比较新,但收集与存储大量信息的历史却不短了. 早在本世纪初,行业分析师Doug Laney就提出了&q ...

  2. Top 10 Machine Learning Algorithms For Beginners

    Linear Regression Logistic regression KNN Classification Support Vector Machine (SVM) Decision Trees ...

  3. web端自动化——selenium3+Python3+pycharm自动化

    1.前言: 对于初学者来说,python自带的IDLE,精简又方便,不过一个好的编辑器能让python编码变得更方便,更加优美些. 不过呢,也可以自己去下载其他更好用的代码编辑器,在这推荐: PyCh ...

  4. intel 蓝牙驱动安装时报错

    BT_20.120.2_64_Win7.exe 安装时报错. 把系统补丁打全,就可以安装 了.

  5. SQL在线自助查询

    数据的日常查询统计分析是高频的需求,然而生产数据库由于安全.管理等方面的要求,仅仅对部分人员开发,例如DBA,总监等, 其他人员都要通过DBA才能查询数据,十分不便. 为了让DBA免于日常繁琐的工作, ...

  6. python signal模块

    signal包负责在Python程序内部处理信号,典型的操作包括预设信号处理函数,暂 停并等待信号,以及定时发出SIGALRM等.要注意,signal包主要是针对UNIX平台(比如Linux, MAC ...

  7. c++ 在Ubuntu系统中使用access函数

    include<iostream> #include<stdlib.h> #include<stdio.h> #include<unistd.h> us ...

  8. Hive 企业调优

    9.企业级调优 9.1 Fetch 抓取 Fetch 抓取:Hive 中对某些情况的查询可以不必使用 MapReduce 计算: hive.fetch.task.conversion:more 9.2 ...

  9. Echarts dataZoom 区域缩放

    dataZoom=[ //区域缩放 { id: 'dataZoomX', show:true, //是否显示 组件.如果设置为 false,不会显示,但是数据过滤的功能还存在. backgroundC ...

  10. [转帖]年经贴: ARM将为苹果开发高性能CPU核心 取代笔记本x86处理器?

    ARM将为苹果开发高性能CPU核心 取代笔记本x86处理器? https://www.cnbeta.com/articles/tech/899421.htm . 之前苹果的哥们说过 谁特别在意自己的软 ...