理解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符號,因此可以直接運行。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM