实例分析ELF文件静态链接参考文献:
《ELF V1.2》
《程序员的自我修养---链接、装载与库》第4章 静态链接
开发平台:
[thm@tanghuimin static_link]$ uname -a linux tanghuimin 2.6.32-358.el6.x86_64 #1 SMP Fri Feb 22 00:31:26 UTC 2013 x86_64 x86_64 x86_64 GNU/Linux
1.ELF文件格式概貌
readelf -h 查看elf文件头部信息可以看到Type值有三种:REL,EXEC,DYN。
REL文件是只被编译没有被链接过的文件,其格式属于左边一种,elf header+section1,2,3...+section header table,每个section对应一个section header table entry,section header table为各个section提供索引。没有被链接过的文件没有PRogram header,不能被加载到内存中运行,readelf -l会提示”There are no program headers in this file”。
EXEC和DYN文件属于被链接过的文件,其格式属于右边一种,elf header+program header table+segment1,2,3...+section header table。每个segment对应一个program header table entry,program header table为各个segment提供索引。EXEC和DYN文件有program headers,可以被加载到内存中运行,readelf -l可以看到一个segment是由一个或多个section构成,Type为LOAD的segment可以被加载到内存中运行,其他类型的segment提供辅助信息。
2.实例分析
(1)创建文件
创建文件common.c
int val = 1; int func(void) { return (val+10); }
创建文件test.c
extern int val; extern int func(void); int main() { val = 10; func(); return 0; }
(2)编译
编译两个.c文件
gcc -c test.c
gcc -c common.c
生成的test.o和common.o属于REL类型
来分析一下编译后生成的REL文件
(2.1)先看看test.o:
readelf -s test.o查看test.o的符号表
[thm@tanghuimin static_link]$ readelf -s test.o Symbol table '.symtab' contains 11 entries: Num: Value Size Type Bind Vis Ndx Name 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND 1: 0000000000000000 0 FILE LOCAL DEFAULT ABS test.c 2: 0000000000000000 0 SECTION LOCAL DEFAULT 1 3: 0000000000000000 0 SECTION LOCAL DEFAULT 3 4: 0000000000000000 0 SECTION LOCAL DEFAULT 4 5: 0000000000000000 0 SECTION LOCAL DEFAULT 6 6: 0000000000000000 0 SECTION LOCAL DEFAULT 7 7: 0000000000000000 0 SECTION LOCAL DEFAULT 5 8: 0000000000000000 26 FUNC GLOBAL DEFAULT 1 main 9: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND val 10: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND func
因为val和func不是在test.c中定义的,所以这两个符号的Ndx(符号所在section的index)为UND。为了能让程序顺利执行,我们希望在未来链接的过程中可以从其他文件中找到val和func这两个符号,并确定这两个符号的地址,确定未定义符号的地址的过程即是“重定位”(relocation)。
readelf -S test.o可以看到test.o的section header table
[thm@tanghuimin static_link]$ readelf test.o -S There are 12 section headers, starting at offset 0x128: Section Headers: [Nr] Name Type Address Offset Size EntSize Flags Link Info Align [ 0] NULL 0000000000000000 00000000 0000000000000000 0000000000000000 0 0 0 [ 1] .text PROGBITS 0000000000000000 00000040 000000000000001a 0000000000000000 AX 0 0 4 [ 2] .rela.text RELA 0000000000000000 00000548 0000000000000030 0000000000000018 10 1 8 [ 3] .data PROGBITS 0000000000000000 0000005c 0000000000000000 0000000000000000 WA 0 0 4 [ 4] .bss NOBITS 0000000000000000 0000005c 0000000000000000 0000000000000000 WA 0 0 4 [ 5] .comment PROGBITS 0000000000000000 0000005c 000000000000002d 0000000000000001 MS 0 0 1 [ 6] .note.GNU-stack PROGBITS 0000000000000000 00000089 0000000000000000 0000000000000000 0 0 1 [ 7] .eh_frame PROGBITS 0000000000000000 00000090 0000000000000038 0000000000000000 A 0 0 8 [ 8] .rela.eh_frame RELA 0000000000000000 00000578 0000000000000018 0000000000000018 10 7 8 [ 9] .shstrtab STRTAB 0000000000000000 000000c8 0000000000000059 0000000000000000 0 0 1 [10] .symtab SYMTAB 0000000000000000 00000428 0000000000000108 0000000000000018 11 8 8 [11] .strtab STRTAB 0000000000000000 00000530 0000000000000016 0000000000000000 0 0 1 Key to Flags: W (write), A (alloc), X (execute), M (merge), S (strings) I (info), L (link order), G (group), x (unknown) O (extra OS processing required) o (OS specific), p (processor specific)
我们重点关注rela section。
可以看到rela.text entry的描述中,link=10,info=1,link表示被重定位的符号所在的符号表的section index,info表示需要被重定位的section的index,通俗点讲就是,将来有朝一日我知道了该符号的地址,我该把这个地址写到哪个section里面去,这里是.text。
readelf -r test.o可以看到rel section里的详细信息。
[thm@tanghuimin static_link]$ readelf test.o -r Relocation section '.rela.text' at offset 0x548 contains 2 entries: Offset Info Type Sym. Value Sym. Name + Addend 000000000006 000900000002 R_X86_64_PC32 0000000000000000 val - 8 00000000000f 000a00000002 R_X86_64_PC32 0000000000000000 func - 4 Relocation section '.rela.eh_frame' at offset 0x578 contains 1 entries: Offset Info Type Sym. Value Sym. Name + Addend 000000000020 000200000002 R_X86_64_PC32 0000000000000000 .text + 0
offset表示该符号在被重定位的section中的偏移,info的高4个字节表示该符号在.symtab中的index,低4字节表示重定位的类型,不同的类型计算目标地址的方法不一样。
综上所述,我们可以得出符号val和func的种种信息:
val的重定位地址是在.text的偏移为6处,将来的链接过程中,连接器要将val的地址写到这个位置上来,val在.symtab中的index为9。
func的重定位地址是在.text的偏移为f处,将来的链接过程中,连接器要将func的地址写到这个位置上来,func在.symtab中的为a。
关于重定位的类型,《ELF V1.2》的第57和93页有详细说明。
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