本文出處: www.jollen.org
已取得原作者授權使用
#1: 前言與簡介
接續前些時日的「Program Loading」專欄,本系列日 記將會介紹「dynamic linking」的核心觀念。首先,我們由 dynamic segment,即 .dynamic section 切入;如果您還不清楚為何以此做切入,建議先行閱讀 'Program Loading' 專欄,以建立基礎概念。
Dynamic section 是整個 dynamic linking 體 系的觀念核心,絕對不能放過;在 System V ABI 規格中,有詳細的 dynamic section 介紹。Dynamic section 裡頭包含多個 'entry',每一個 entry 紀載不同的資訊。首先,我們先找出 dynamic section 的資料結構定義如下:
/* Dynamic section entry. */typedef struct{Elf32_Sword d_tag; /* Dynamic entry type */union{
Elf32_Word d_val; /* Integer value */
Elf32_Addr d_ptr; /* Address value */
} d_un;
} Elf32_Dyn;
'd_tag' 用來標記該 entry 的用途,'d_val' 或 'd_ptr' 則是該 entry 的內容。完整的 dynamic section 有哪些 entry?以及每一個 entry 的用途說明為何?此部 份請參閱 System V ABI 文件的說明,該文件有一份列表整理出所有的 dynamic section entry 及其說明,在此不再重覆刊載。不過,我們可由 elf.h 來快速了解 dynamic section 裡的主要(generic, processor-independent) entry:
/* Legal values for d_tag (dynamic entry type). */#define DT_NULL 0 /* Marks end of dynamic section */#define DT_NEEDED 1 /* Name of needed library */#define DT_PLTRELSZ 2 /* Size in bytes of PLT relocs */#define DT_PLTGOT 3 /* Processor defined value */#define DT_HASH 4 /* Address of symbol hash table */
#define DT_STRTAB 5 /* Address of string table */
#define DT_SYMTAB 6 /* Address of symbol table */
#define DT_RELA 7 /* Address of Rela relocs */
#define DT_RELASZ 8 /* Total size of Rela relocs */
#define DT_RELAENT 9 /* Size of one Rela reloc */
#define DT_STRSZ 10 /* Size of string table */
#define DT_SYMENT 11 /* Size of one symbol table entry */
#define DT_INIT 12 /* Address of init function */
#define DT_FINI 13 /* Address of termination function */
#define DT_SONAME 14 /* Name of shared object */
#define DT_RPATH 15 /* Library search path (deprecated) */
#define DT_SYMBOLIC 16 /* Start symbol search here */
#define DT_REL 17 /* Address of Rel relocs */
#define DT_RELSZ 18 /* Total size of Rel relocs */
#define DT_RELENT 19 /* Size of one Rel reloc */
#define DT_PLTREL 20 /* Type of reloc in PLT */
#define DT_DEBUG 21 /* For debugging; unspecified */
#define DT_TEXTREL 22 /* Reloc might modify .text */
#define DT_JMPREL 23 /* Address of PLT relocs */
#define DT_BIND_NOW 24 /* Process relocations of object */
#define DT_INIT_ARRAY 25 /* Array with addresses of init fct */
#define DT_FINI_ARRAY 26 /* Array with addresses of fini fct */
#define DT_INIT_ARRAYSZ 27 /* Size in bytes of DT_INIT_ARRAY */
#define DT_FINI_ARRAYSZ 28 /* Size in bytes of DT_FINI_ARRAY */
#define DT_RUNPATH 29 /* Library search path */
#define DT_FLAGS 30 /* Flags for the object being loaded */
#define DT_ENCODING 32 /* Start of encoded range */
#define DT_PREINIT_ARRAY 32 /* Array with addresses of preinit fct*/
#define DT_PREINIT_ARRAYSZ 33 /* size in bytes of DT_PREINIT_ARRAY */
#define DT_NUM 34 /* Number used */
本系列專欄將針對以 下幾個重要的 entry type 做觀念上的分享:
- DT_NEEDED 1 /* Name of needed library */
- DT_HASH 4 /* Address of symbol hash table */
- DT_STRTAB 5 /* Address of string table */
- DT_SYMTAB 6 /* Address of symbol table */
我們可使用 Linux 常見的 ELF 工具 - 'readelf' 來觀 察 ELF executables 的 dynamic segment 資訊:
# readelf -d testDynamic segment at offset 0x404 contains 20 entries: Tag Type Name/Value 0x00000001 (NEEDED) Shared library: [libc.so.6]0x0000000c (INIT) 0x80482300x0000000d (FINI) 0x80483d0
0x00000004 (HASH) 0x8048128
0x00000005 (STRTAB) 0x80481a0
0x00000006 (SYMTAB) 0x8048150
0x0000000a (STRSZ) 75 (bytes)
0x0000000b (SYMENT) 16 (bytes)
0x00000015 (DEBUG) 0x0
0x00000003 (PLTGOT) 0x80494e0
0x00000002 (PLTRELSZ) 16 (bytes)
0x00000014 (PLTREL) REL
0x00000017 (JMPREL) 0x8048220
0x00000011 (REL) 0x8048218
0x00000012 (RELSZ) 8 (bytes)
0x00000013 (RELENT) 8 (bytes)
0x6ffffffe (VERNEED) 0x80481f8
0x6fffffff (VERNEEDNUM) 1
0x6ffffff0 (VERSYM) 0x80481ec
0x00000000 (NULL) 0x0
對於 dynamic linking 的說明,後續會先行整理這 4 個 entry 的主要觀念,然後再針對「如何找到程式所需(depends)的程式庫」做分析,並談論有關符號(symbol)的連結(relocation)處 理機制。
#2: DT_NEEDED 基本概念
所謂「如何找到程式所需(depends)的程式庫」並非一件很技術面的事情,程式經常會呼叫程式庫裡的函數,並且由於 Linux 是 shared library 系統,因此 程式執行時,如何找到程式需要的程式庫,其實是一件很自然的事情。
程式所需的程式庫,稱為相依性程式庫,即 library dependencies;並且,程式庫也會再相依其他的程式庫,因此,找出 library dependencies 是一種拓樸邏輯關係。
由 dynamic linker 的實作角度來說,程式的 library dependencies 紀錄在 dynamic segment 的 DT_NEEDED entry 裡,dynamic linker 便是由 DT_NEEDED 為起點,建立 library dependencies 關係圖,此圖又稱做 NEEDED list。
例如,若程式相依 libm 與 libc,那麼,DT_NEEDED entry 的內容就會是:
# readelf -d testDynamic segment at offset 0x494 contains 21 entries: Tag Type Name/Value 0x00000001 (NEEDED) Shared library: [libm.so.6]
0x00000001 (NEEDED) Shared library: [libc.so.6]
0x0000000c (INIT) 0x80482a4
0x0000000d (FINI) 0x8048460
...
使用 ldd 也能觀察到 library dependencies:
# ldd test libm.so.6 => /lib/tls/libm.so.6 (0x40026000)
libc.so.6 => /lib/tls/libc.so.6 (0x42000000)
/lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)
熟悉 embedded Linux 系統建置的朋友想必對這個部份不感到陌生,現在我們終於知道 library dependencies 是紀錄在 dynamic segment 的 DT_NEEDED 裡,對於 dynamic linking 的研究又跨出了一大步。
來源: Jollen's Blog
--jollen
0 comments:
Post a Comment