理解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.1 =>  (0x00007ffdb075f000)
    libselinux.so.1 => /lib/x86_64-linux-gnu/libselinux.so.1 (0x00007fb9e3650000)
    libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fb9e3286000)
    libpcre.so.3 => /lib/x86_64-linux-gnu/libpcre.so.3 (0x00007fb9e3016000)
    libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007fb9e2e11000)
    /lib64/ld-linux-x86-64.so.2 (0x00005607fd069000)
    libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (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 9 program headers, starting at offset 64

Program Headers:
  Type           Offset             VirtAddr           PhysAddr
                 FileSiz            MemSiz              Flags  Align
  PHDR           0x0000000000000040 0x0000000000400040 0x0000000000400040
                 0x00000000000001f8 0x00000000000001f8  R E    8
  INTERP         0x0000000000000238 0x0000000000400238 0x0000000000400238
                 0x000000000000001c 0x000000000000001c  R      1
      [Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
  LOAD           0x0000000000000000 0x0000000000400000 0x0000000000400000
                 0x000000000001da64 0x000000000001da64  R E    200000
  LOAD           0x000000000001de00 0x000000000061de00 0x000000000061de00
                 0x0000000000000800 0x0000000000001568  RW     200000
  DYNAMIC        0x000000000001de18 0x000000000061de18 0x000000000061de18
                 0x00000000000001e0 0x00000000000001e0  RW     8
  NOTE           0x0000000000000254 0x0000000000400254 0x0000000000400254
                 0x0000000000000044 0x0000000000000044  R      4
  GNU_EH_FRAME   0x000000000001a5f4 0x000000000041a5f4 0x000000000041a5f4
                 0x0000000000000804 0x0000000000000804  R      4
  GNU_STACK      0x0000000000000000 0x0000000000000000 0x0000000000000000
                 0x0000000000000000 0x0000000000000000  RW     10
  GNU_RELRO      0x000000000001de00 0x000000000061de00 0x000000000061de00
                 0x0000000000000200 0x0000000000000200  R      1

 Section to Segment mapping:
  Segment Sections...
   00     
   01     .interp 
   02     .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 
   03     .init_array .fini_array .jcr .dynamic .got .got.plt .data .bss 
   04     .dynamic 
   05     .note.ABI-tag .note.gnu.build-id 
   06     .eh_frame_hdr 
   07     
   08     .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.2 \
    -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符号,因此可以直接运行。

 

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
你好!关于报错 "error while loading shared libraries libjvm.so" ,这通常是由于缺少 Java 虚拟机(JVM)库文件 libjvm.so 导致的。您可以尝试以下解决方案来解决这个问题: 1. 检查 Java 安装:确保已正确安装 Java 并设置了正确的环境变量。您可以在终端中运行 "java -version" 命令来检查 Java 版本和配置是否正确。 2. 检查库文件路径:确认 libjvm.so 库文件的路径是否正确。您可以通过设置 LD_LIBRARY_PATH 环境变量来指定库文件的路径。例如,如果库文件位于 /usr/lib/jvm/java-8-openjdk-amd64/jre/lib/amd64/server/ 目录下,可以运行以下命令: ``` export LD_LIBRARY_PATH=/usr/lib/jvm/java-8-openjdk-amd64/jre/lib/amd64/server/ ``` 运行上述命令后,再次尝试运行您的程序,看是否解决了问题。 3. 检查依赖关系:使用 ldd 命令检查可执行文件或共享库文件的依赖关系,确认是否有其他缺失的库文件。例如,运行以下命令: ``` ldd /path/to/your/executable ``` 上述命令将显示与可执行文件相关的库文件及其路径。确保所有依赖的库文件都存在并且路径正确。 4.重新安装 Java:如果上述步骤都没有解决问题,您可以尝试重新安装 Java,确保安装过程中没有发生错误。 如果问题仍然存在,请提供更多详细信息,例如您的操作系统、Java 版本以及相关命令的完整输出。这将有助于更好地理解和解决您遇到的问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值