接續前些時日的「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 做觀念上的分享:
我們可使用 Linux 常見的 ELF 工具 - 'readelf' 來觀 察 ELF executables 的 dynamic segment 資訊:
# readelf -d test Dynamic segment at offset 0x404 contains 20 entries: Tag Type Name/Value 0x00000001 (NEEDED) Shared library: [libc.so.6] 0x0000000c (INIT) 0x8048230 0x0000000d (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)處 理機制。
來源: Jollen's Blog
Jollen's Blog 使用 Github issues 與讀者交流討論。請點擊上方的文章專屬 issue,或 open a new issue
您可透過電子郵件 jollen@jollen.org,或是 Linkedin 與我連絡。更歡迎使用微信,請搜尋 WeChat ID:jollentw