• 理解ld-linux.so.2


    翻译自: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.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)
    View Code

    当应用程序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 
    View Code

    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
    View Code

    通过-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,-)'
    View Code

    因此,作为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符号,因此可以直接运行。

  • 相关阅读:
    Java实现 蓝桥杯 历届试题 斐波那契
    Java实现 蓝桥杯 历届试题 斐波那契
    Java实现 蓝桥杯 历届试题 斐波那契
    Java实现 LeetCode 552 学生出勤记录 II(数学转换?还是动态规划?)
    linux下查看动态链接库so文件的依赖的相关组建
    linux 查看 *.a *.so 符号表(zt)
    linux下查看动态链接库依赖关系的命令 x86: ldd *.so arm: arm-linux-readelf -d *.so 实际例子: 以项目中用到的库librtsp.so分析: lijun@ubuntu:~/workspace$ arm-hisiv100nptl-linux-ld -d librtsp.so arm-hisiv100nptl-linux-ld:
    ldd 查看程序/动态库 的依赖
    修改SVN中文件的可执行属性
    widow下svn上传项目时的文件可执行权限问题
  • 原文地址:https://www.cnblogs.com/kelamoyujuzhen/p/9823272.html
Copyright © 2020-2023  润新知