版权声明:本文为CSDN博主「ashimida@」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/lidan113lidan/article/details/119901186更多内容可关注微信公众号![]()
节区名
|
节区说明
|
备注
|
.rodata1
|
和rodata类似,只存放只读数据
| |
.comment
|
存放编译器版本信息,如字符串 "GCC:(GNU)4.2.0"
| |
.debug
|
存放调试信息
| |
.shstrtab
|
节区头部表名字的字符串表(Section Header String Table)
| |
.plt
|
过程链接表(Procedure Linkage Table),用来保存长跳转格式的函数调用
| |
.got
|
全局偏移表(Global Offset Table),在地址无关代码中才需要,所有只读段需要修复的位置都间接引用到此表, 因此只读段自身就无需修复,只需修复此got表即可.
.got表是在编译期间确定,静态链接期间生成的
而.plt表是在静态链接期间确定,静态链接期间生成的
|
可执行文件通常不论如何编译都有got表,这是因为是否加入got表是由编译(cc1)期间决定的,而可执行文件默认连接的多个目标文件默认都有got表元素.
|
.got.plt
| 实际上其本质是从.got表中拆除来的一部分,当开启延迟绑定(Lazy Binding)时,会将plt表中的长跳转(函数)的重定位信息单独放到此表中,以满足后续实际的延迟绑定. | |
.symtab
|
(静态链接)符号表的作用是保存当前
目标文件中所有对符号的定义和引用.
* 符号表中UND的符号不是当前目标文件定义的,也就是对符号的引用
* 符号表中其他非UND的符号,全部是定义在当前目标文件中的,也就是对符号的定义
|
默认所有非.L开头的符号都要输出,.L开头的不输出
|
.strtab
|
静态链接字符串表,其中记录的是静态链接符号表中使用到的字符串,这些字符串仅供静态链接符号表使用,strip的时候会将.symtab和.strtab两个段完全清除.
|
符号表的第一个元素必须是
STN_UNDEF,其代表一个未定义的符号索引,此符号表项内部所有值都为0
|
.group
|
是用来记录多个节区的相关信息的,比如说代码段引用了数据段,这种信息是为了保证二进制处理时候不会操作错误的,像是elf自动生成的,细节见链接
|
section groups
|
动态链接相关节区
| ||
.interp
|
.interp整个段的内容就是一个字符串,此字符串为系统中动态链接器的路径,如:
/lib/ld-linux-aarch64.so.1
linux的可执行文件加载时会去寻找可执行文件所需的动态链接器
|
![]() |
.dynamic
|
.interp保存的是动态链接器路径,.dynamic中保存的是动态链接器用到的基本信息,如动态链接符号表(.dynsym),字符串表(.dynstr),重定位表(.rela.dyn/rela.plt),依赖的运行时库,库查找路径等
| |
.rela.dyn
|
记录所有变量的动态链接重定位信息(.rela.plt记录的是函数),与.rela.plt一起,是系统中唯二的两张动态链接重定位表。
.rela.dyn记录除了.plt段之外所有段的动态链接重定位信息,若开启了地址无关代码,那么这些信息都应该只与.got段的地址有关.
| |
.rela.plt
|
过程连接表的动态链接重定位表,只要有过程链表,通常就会有此表,因为plt导致了绝对跳转,那么所有plt表中所有需要动态链接/重定位的绝对地址(可能在.got.plt或.got中,依赖于是否开启延迟绑定),都需要通过.rela.plt记录
此表中记录所有全局函数(长跳转函数)的动态链接重定位信息,与.rela.dyn一起,是系统中唯二的两张动态链接重定位表。
.rela.plt实际上记录的是.plt段的动态链接重定位信息,若未开启lazy binding,则这这些信息应该都只与.got段的地址有关;若开启lazy binding,则这些信息应该都只与.got.plt段的地址有关;
|
需要动态链接重定位的原因主要是模块有导入符号的存在,这些符号在运行时才能确定,
地址无关代码并不能改变未定符号的本质(即不影响模块是否需要动态链接重定位),
但地址无关代码可以让重定位变得简单(如仅重定位 .got/ .data/ .got.plt)
|
.dynsym
|
动态链接符号表,其格式和.symtab一样,readelf -s会尝试同时输出.dynsym和.symtab,如右图.
动态链接符号表是静态链接符号表的子集,其只保留了与动态链接相关的符号信息,所有模块内部符号则不保留(因此静态符号表是可以被strip的,其只对于目标文件有用).
动态链接符号表中未定义的符号(符号引用),又称为导入符号(类似导入表)
动态链接符号表中已定义的符号(符号定义),又称为导出符号(类似导出表)
|
![]()
全局符号默认是直接导出到动态链接重定位表的
|
.dynstr
|
动态链接符号表用到的字符串表,其与静态链接字符串表(.strtab)分开的原因应该是.strtab是可以完全strip的
|
链接过程图:
1.ELF文件头
由ELF文件的第一字节开始的一个ELF32_Ehdr结构体是ELF头,其中记录ELF的基本信息包括:
2.节区头部表(Section Heade Table)、节区头部表字符串表(shstrtab)和字符串表(strtab)
typedef struct elf64_shdr {
Elf64_Word sh_name; /* Section name, index in string tbl */
Elf64_Word sh_type; /* Type of section */
Elf64_Xword sh_flags; /* Miscellaneous section attributes */
Elf64_Addr sh_addr; /* Section virtual addr at execution */
Elf64_Off sh_offset; /* Section file offset */
Elf64_Xword sh_size; /* Size of section in bytes */
Elf64_Word sh_link; /* Index of another section */
Elf64_Word sh_info; /* Additional section information */
Elf64_Xword sh_addralign; /* Section alignment */
Elf64_Xword sh_entsize; /* Entry size if section holds table */
} Elf64_Shdr;
通过readelf -S可读取其内容,如:
##这里手动换行,便于观察
tangyuan@ubuntu:~/compiler_test/gcc_test/x86/test$ readelf -S x.o
There are 11 section headers, starting at offset 0x2e8:
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 000000000000002c 0000000000000000 AX 0 0 4
[ 2] .rela.text RELA 0000000000000000 00000218 0000000000000078 0000000000000018 I 8 1 8
[ 3] .data PROGBITS 0000000000000000 0000006c 0000000000000004 0000000000000000 WA 0 0 4
[ 4] .bss NOBITS 0000000000000000 00000070 0000000000000000 0000000000000000 WA 0 0 1
[ 5] .rodata PROGBITS 0000000000000000 00000070 0000000000000008 0000000000000000 A 0 0 8
[ 6] .comment PROGBITS 0000000000000000 00000078 0000000000000031 0000000000000001 MS 0 0 1
[ 7] .note.GNU-stack PROGBITS 0000000000000000 000000a9 0000000000000000 0000000000000000 0 0 1
[ 8] .symtab SYMTAB 0000000000000000 000000b0 0000000000000150 0000000000000018 9 11 8
[ 9] .strtab STRTAB 0000000000000000 00000200 0000000000000017 0000000000000000 0 0 1
[10] .shstrtab STRTAB 0000000000000000 00000290 0000000000000052 0000000000000000 0 0 1
其中每一行是节区头部表中的一个表项,也代表着此elf文件中的一个节区信息(ELF文件中定位节区的方式是: ELF头=>节区头部表=>节区首地址及其他信息)
tangyuan@ubuntu:~/compiler_test/gcc_test/x86/test$ aarch64-linux-gnu-readelf -p .shstrtab x
String dump of section '.shstrtab':
[ 1] .symtab
[ 9] .strtab
[ 11] .shstrtab
[ 1b] .interp
[ 23] .note.ABI-tag
[ 31] .note.gnu.build-id
[ 44] .gnu.hash
[ 4e] .dynsym
[ 56] .dynstr
[ 5e] .gnu.version
[ 6b] .gnu.version_r
[ 7a] .rela.dyn
[ 84] .rela.plt
[ 8e] .init
[ 94] .text
[ 9a] .fini
[ a0] .rodata
[ a8] .eh_frame
[ b2] .init_array
[ be] .fini_array
[ ca] .dynamic
[ d3] .got
[ d8] .got.plt
[ e1] .data
[ e7] .bss
[ ec] .comment
而字符串表则记录符号表中符号相关的字符串信息,如:
tangyuan@ubuntu:~/compiler_test/gcc_test/x86/test$ aarch64-linux-gnu-readelf -p .strtab x
String dump of section '.strtab':
[ 1] /usr/lib/gcc-cross/aarch64-linux-gnu/7/../../../../aarch64-linux-gnu/lib/../lib/crt1.o
[ 58] $d
[ 5b] $x
[ 5e] /usr/lib/gcc-cross/aarch64-linux-gnu/7/../../../../aarch64-linux-gnu/lib/../lib/crti.o
[ b5] call_weak_fn
[ c2] /usr/lib/gcc-cross/aarch64-linux-gnu/7/../../../../aarch64-linux-gnu/lib/../lib/crtn.o
[ 119] crtstuff.c
[ 124] deregister_tm_clones
[ 139] __do_global_dtors_aux
[ 14f] completed.8500
[ 15e] __do_global_dtors_aux_fini_array_entry
[ 185] frame_dummy
[ 191] __frame_dummy_init_array_entry
[ 1b0] x.c
[ 1b4] elf-init.oS
[ 1c0] __FRAME_END__
[ 1ce] __init_array_end
[ 1df] _DYNAMIC
[ 1e8] __init_array_start
[ 1fb] _GLOBAL_OFFSET_TABLE_
[ 211] __libc_csu_fini
[ 221] _ITM_deregisterTMCloneTable
[ 23d] __bss_start__
[ 24b] _edata
[ 252] __bss_end__
[ 25e] __libc_start_main@@GLIBC_2.17
[ 27c] __data_start
[ 289] __gmon_start__
[ 298] __dso_handle
[ 2a5] abort@@GLIBC_2.17
[ 2b7] _IO_stdin_used
[ 2c6] __libc_csu_init
[ 2d6] yyy
[ 2da] __end__
[ 2e2] __bss_start
[ 2ee] main
[ 2f3] __TMC_END__
[ 2ff] _ITM_registerTMCloneTable
[ 319] printf@@GLIBC_2.17
3.程序头部表(Program Header Table)
typedef struct elf64_phdr {
Elf64_Word p_type;
Elf64_Word p_flags;
Elf64_Off p_offset; /* Segment file offset */
Elf64_Addr p_vaddr; /* Segment virtual address */
Elf64_Addr p_paddr; /* Segment physical address */
Elf64_Xword p_filesz; /* Segment size in file */
Elf64_Xword p_memsz; /* Segment size in memory */
Elf64_Xword p_align; /* Segment alignment, file & memory */
} Elf64_Phdr;
通过readelf -l 可查看程序头部表,如下:
tangyuan@ubuntu:~/compiler_test/gcc_test/x86/test$ readelf -l x
Elf file type is EXEC (Executable file)
Entry point 0x400660
There are 8 program headers, starting at offset 64
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flags Align
PHDR 0x0000000000000040 0x0000000000400040 0x0000000000400040 0x00000000000001c0 0x00000000000001c0 R 0x8
INTERP 0x0000000000000200 0x0000000000400200 0x0000000000400200 0x000000000000001b 0x000000000000001b R 0x1 [Requesting program interpreter: /lib/ld-linux-aarch64.so.1]
LOAD 0x0000000000000000 0x0000000000400000 0x0000000000400000 0x0000000000000860 0x0000000000000860 R E 0x10000
LOAD 0x0000000000000de8 0x0000000000410de8 0x0000000000410de8 0x000000000000024c 0x0000000000000258 RW 0x10000
DYNAMIC 0x0000000000000df8 0x0000000000410df8 0x0000000000410df8 0x00000000000001e0 0x00000000000001e0 RW 0x8
NOTE 0x000000000000021c 0x000000000040021c 0x000000000040021c 0x0000000000000044 0x0000000000000044 R 0x4
GNU_STACK 0x0000000000000000 0x0000000000000000 0x0000000000000000 0x0000000000000000 0x0000000000000000 RW 0x10
GNU_RELRO 0x0000000000000de8 0x0000000000410de8 0x0000000000410de8 0x0000000000000218 0x0000000000000218 R 0x1
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 .text .fini .rodata .eh_frame
03 .init_array .fini_array .dynamic .got .got.plt .data .bss
04 .dynamic
05 .note.ABI-tag .note.gnu.build-i
06
07 .init_array .fini_array .dynamic .got
4..text/.data/.rodata/.bss节区
1 .arch armv8-a
2 .file "x.c"
3 .text
4 .global x
5 .data
6 .align 2
7 .type x, %object
8 .size x, 4
9 x:
......
tangyuan@ubuntu:~/compiler_test/gcc_test/x86/test$ ld -verbose
GNU ld (GNU Binutils for Ubuntu) 2.30
......
SECTIONS
{
PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x400000)); . = SEGMENT_START("text-segment", 0x400000) + SIZEOF_HEADERS;
.interp : { *(.interp) }
......
.dynsym : { *(.dynsym) }
.dynstr : { *(.dynstr) }
......
.rela.dyn :
{
......
*(.rela.text .rela.text.* .rela.gnu.linkonce.t.*)
*(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*)
*(.rela.data .rela.data.* .rela.gnu.linkonce.d.*)
*(.rela.got)
......
}
.rela.plt :
{
*(.rela.plt)
.......
}
......
.plt : { *(.plt) *(.iplt) }
.plt.got : { *(.plt.got) }
.plt.sec : { *(.plt.sec) }
.text :
{
*(.text.unlikely .text.*_unlikely .text.unlikely.*)
*(.text.exit .text.exit.*)
......
}
......
PROVIDE (__etext = .);
PROVIDE (_etext = .);
PROVIDE (etext = .);
.rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
.rodata1 : { *(.rodata1) }
......
.data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro .data.rel.ro.* .gnu.linkonce.d.rel.ro.*) }
.dynamic : { *(.dynamic) }
.got : { *(.got) *(.igot) }
. = DATA_SEGMENT_RELRO_END (SIZEOF (.got.plt) >= 24 ? 24 : 0, .);
.got.plt : { *(.got.plt) *(.igot.plt) }
.data :
{
*(.data .data.* .gnu.linkonce.d.*)
SORT(CONSTRUCTORS)
}
.data1 : { *(.data1) }
_edata = .; PROVIDE (edata = .);
. = .;
__bss_start = .;
.bss :
{
*(.dynbss)
*(.bss .bss.* .gnu.linkonce.b.*)
*(COMMON)
......
}
.......
}
5.符号表(symtab)节区
1 .arch armv8-a
2 .file "x.c"
3 .text
4 .global xx
5 .data
6 .align 2
7 .type xx, %object
8 .size xx, 4
9 xx:
10 .word 1
11 .section .rodata
12 .align 3
13 .LC0:
14 .string "x:%d,%d\n"
15 .text
16 .align 2
17 .global main
18 .type main, %function
19 main:
20 stp x29, x30, [sp, -16]!
21 add x29, sp, 0
22 adrp x0, :got:xx
23 ldr x0, [x0, #:got_lo12:xx]
......
tangyuan@ubuntu:~/compiler_test/gcc_test/x86/test$ readelf -s x.o
Symbol table '.symtab' contains 15 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000000000 0 FILE LOCAL DEFAULT ABS x.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 NOTYPE LOCAL DEFAULT 3 $d //数据段开始符号
6: 0000000000000000 0 SECTION LOCAL DEFAULT 5
7: 0000000000000000 0 NOTYPE LOCAL DEFAULT 5 $d
8: 0000000000000000 0 NOTYPE LOCAL DEFAULT 1 $x //代码段开始符号
9: 0000000000000000 0 SECTION LOCAL DEFAULT 7
10: 0000000000000000 0 SECTION LOCAL DEFAULT 6
11: 0000000000000000 4 OBJECT GLOBAL DEFAULT 3 xx
12: 0000000000000000 56 FUNC GLOBAL DEFAULT 1 main
13: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND yyy
14: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND printf
6.过程链接表(Procedure Linkage Table,plt表)节区,过程链接表动态重定位表(.rela.plt)节区
//x.s文件
......
19 func22:
......
27 ldr w2, [x0]
28 adrp x0, .LC0
29 add x0, x0, :lo12:.LC0
30 bl printf //1)
31 nop
32 ldp x29, x30, [sp], 16
33 ret
......
38 main:
39 stp x29, x30, [sp, -16]!
40 add x29, sp, 0
41 bl func22 //2)
42 mov w0, 0
......
//目标文件反汇编
Disassembly of section .text:
0000000000000000 <func22>:
0: a9bf7bfd stp x29, x30, [sp, #-16]!
4: 910003fd mov x29, sp
8: 90000000 adrp x0, 0 <func22>
c: f9400000 ldr x0, [x0]
10: b9400001 ldr w1, [x0]
14: 90000000 adrp x0, 0 <yyy>
18: f9400000 ldr x0, [x0]
1c: b9400002 ldr w2, [x0]
20: 90000000 adrp x0, 0 <func22>
24: 91000000 add x0, x0, #0x0
28: 94000000 bl 0 <printf> // 1)
2c: d503201f nop
30: a8c17bfd ldp x29, x30, [sp], #16
34: d65f03c0 ret
0000000000000038 <main>:
38: a9bf7bfd stp x29, x30, [sp, #-16]!
3c: 910003fd mov x29, sp
40: 94000000 bl 0 <func22> // 2)
44: 52800000 mov w0, #0x0 // #0
48: a8c17bfd ldp x29, x30, [sp], #16
4c: d65f03c0 ret
./binutil/gold/aarch64.cc
//此函数负责对局部符号的重定位,STT_GNU_IFUNC 参考https://sourceware.org/glibc/wiki/GNU_IFUNC https://www.airs.com/blog/archives/403
Target_aarch64<size, big_endian>::Scan::local(...)
{
bool is_ifunc = lsym.get_st_type() == elfcpp::STT_GNU_IFUNC;
if (is_ifunc && this->reloc_needs_plt_for_ifunc(object, r_type))
target->make_local_ifunc_plt_entry(symtab, layout, object, r_sym);
......
}
//对于全局符号重定位,只要是CALL26/JUMP26都直接做plt_entry
Target_aarch64<size, big_endian>::Scan::global(......)
{
case elfcpp::R_AARCH64_TSTBR14:
case elfcpp::R_AARCH64_CONDBR19:
case elfcpp::R_AARCH64_JUMP26:
case elfcpp::R_AARCH64_CALL26:
{
if (gsym->final_value_is_known())
break;
if (gsym->is_defined() &&
!gsym->is_from_dynobj() &&
!gsym->is_preemptible())
break;
// Make plt entry for function call.
target->make_plt_entry(symtab, layout, gsym);
break;
}
......
}
这里没有仔细分析这段源码,但根据<ELF for the ARM 64-bit Architecture (AArch64)>手册:
一个PLT入口代表到一个可执行文件外部的长跳转,通常来说,在静态链接的过程中只知道目标符号的名称,而不知道其地址,这样的位置称为一个导入位置或导入符号基于SysV的DSOs(Dynamic Shared Objects, 如 for linux)同样需要从可执行文件导出的函数拥有PLT入口. 事实上导出函数被当做导入函数对待,这样在动态链接时其定义才有可能被重写.静态链接器必须为每个存在的AARCH64 B/BL系列指令的重定位指令引用的符号产生一个PLT入口,在linux/sysV DSO中,如STB_GLOBAL 符号 + STV_DEFUALT可见性的就是个候选指令.
125 00000000000004a0 <func22@plt>: //2) 再间接跳转到真正函数函数
126 4a0: b0000090 adrp x16, 11000 <func22+0x10b30>
127 4a4: f9400211 ldr x17, [x16]
128 4a8: 91000210 add x16, x16, #0x0
129 4ac: d61f0220 br x17 //3) 绝对地址跳转
......
161 0000000000000508 <main>:
162 508: a9bf7bfd stp x29, x30, [sp, #-16]!
163 50c: 910003fd mov x29, sp
164 510: 97ffffe4 bl 4a0 <func22@plt> //1) 跳转到函数的plt表
165 514: 52800000 mov w0, #0x0
166 518: a8c17bfd ldp x29, x30, [sp], #16
167 51c: d65f03c0 ret
当链接器为函数创建对应的func@plt代码后:
7.全局偏移表(got表)节区和.got.plt节
......
18 .type func22, %function
19 func22:
20 stp x29, x30, [sp, -16]!
21 add x29, sp, 0
22 adrp x0, :got:xx
23 ldr x0, [x0, #:got_lo12:xx]
24 ldr w1, [x0]
25 adrp x0, :got:yyy //aarch64汇编中通过 :got:标注当前符号要放到.got表中
26 ldr x0, [x0, #:got_lo12:yyy]
27 ldr w2, [x0]
......
tangyuan@ubuntu:~/compiler_test/gcc_test/x86/test$ readelf -r --wide x.o
Relocation section '.rela.text' at offset 0x280 contains 8 entries:
Offset Info Type Symbol's Value Symbol's Name + Addend
0000000000000008 0000000b00000137 R_AARCH64_ADR_GOT_PAGE 0000000000000000 xx + 0
000000000000000c 0000000b00000138 R_AARCH64_LD64_GOT_LO12_NC 0000000000000000 xx + 0
0000000000000014 0000000d00000137 R_AARCH64_ADR_GOT_PAGE 0000000000000000 yyy + 0 //目标文件通过静态链接重定位类型来代表yyy是got表中的元素
0000000000000018 0000000d00000138 R_AARCH64_LD64_GOT_LO12_NC 0000000000000000 yyy + 0
0000000000000020 0000000600000113 R_AARCH64_ADR_PREL_PG_HI21 0000000000000000 .rodata + 0
0000000000000024 0000000600000115 R_AARCH64_ADD_ABS_LO12_NC 0000000000000000 .rodata + 0
0000000000000028 0000000e0000011b R_AARCH64_CALL26 0000000000000000 printf + 0
0000000000000040 0000000c0000011b R_AARCH64_CALL26 0000000000000000 func22 + 0
tangyuan@ubuntu:~/compiler_test/gcc_test/x86/test$ readelf -S x.o|grep got
tangyuan@ubuntu:~/compiler_test/gcc_test/x86/test$ readelf -S x|grep got
[20] .got PROGBITS 0000000000010f98 00000f98 //只有最终的dll/exe文件才有got表
开启Lazy Binding时的ELF文件和运行时重定位实现如下:

8.动态链接信息(.dynamic)表
typedef struct {
Elf64_Sxword d_tag; /* entry tag value */
union {
Elf64_Xword d_val;
Elf64_Addr d_ptr;
} d_un;
} Elf64_Dyn;
tangyuan@ubuntu:~/compiler_test/gcc_test/x86/test$ readelf -d main
Dynamic section at offset 0xd78 contains 28 entries:
Tag Type Name/Value
0x0000000000000001 (NEEDED) Shared library: [./y.so] //依赖库,正常只是库文件名,若编译时驶入的名为 ./y.so,则这里就为./y.so
0x0000000000000001 (NEEDED) Shared library: [libc.so.6] //依赖库,基本上所有非static的ELF文件中都要依赖于libc.so这个基础的系统库
0x000000000000000c (INIT) 0x730 //.init段的文件偏移
0x000000000000000d (FINI) 0x99c //.finit段的文件偏移
0x0000000000000019 (INIT_ARRAY) 0x10d68 //.init_array段的文件偏移
0x000000000000001b (INIT_ARRAYSZ) 8 (bytes) //.init_array段的大小
0x000000000000001a (FINI_ARRAY) 0x10d70 //.fini_array段的文件偏移
0x000000000000001c (FINI_ARRAYSZ) 8 (bytes) //.fini_array段的大小
0x000000006ffffef5 (GNU_HASH) 0x260 //.gnu.hash段的偏移
0x0000000000000005 (STRTAB) 0x488 //动态链接字符串表(.dynstr)的文件偏移
0x0000000000000006 (SYMTAB) 0x2a8 //动态链接符号表(.dynsym)的文件偏移
0x000000000000000a (STRSZ) 218 (bytes) //动态链接字符串表(.dynstr)的大小
0x000000000000000b (SYMENT) 24 (bytes) //动态链接符号表(.dynsym)中每个元素的大小
0x0000000000000015 (DEBUG) 0x0 //运行时ld.so会将r_debug的运行时地址填充到这里,此信息可用于GDB调试
0x0000000000000003 (PLTGOT) 0x10f78 //.got.plt段的内存偏移
0x0000000000000002 (PLTRELSZ) 120 (bytes) //.rela.plt段的大小
0x0000000000000014 (PLTREL) RELA //.rela.plt段重定位类型是RELA还是REL
0x0000000000000017 (JMPREL) 0x6b8 //.rela.plt段的地址
0x0000000000000007 (RELA) 0x5b0 //.rela.dyn段的地址
0x0000000000000008 (RELASZ) 264 (bytes) //.rela.dyn段的大小
0x0000000000000009 (RELAENT) 24 (bytes) //.rela.dyn段中每个元素的大小
0x000000000000001e (FLAGS) BIND_NOW //额外的flag,如 BIND_NOW, STATIC_TLS, TEXTREL等 当前代码是否为地址无关,是否延迟绑定都可以由这里确定
0x000000006ffffffb (FLAGS_1) Flags: NOW PIE //额外的flag,如是否是地址无关代码
0x000000006ffffffe (VERNEED) 0x590 //.gnu.version_r段的地址
0x000000006fffffff (VERNEEDNUM) 1 //needed versions的数量
0x000000006ffffff0 (VERSYM) 0x562 //.gnu.version段的地址
0x000000006ffffff9 (RELACOUNT) 6 //.rela.plt段中RELA类型的元素个数??
0x0000000000000000 (NULL) 0x0 //结束标记
9.动态链接符号表(.dynsym),动态链接字符串表(.dynstr)
//strip前后对比,静态链接符号表和字符串表被去除了
1 There are 27 section headers, starting at offset 0x1d30: 1 There are 25 section headers, starting at offset 0x1120:
2 2
3 Section Headers: 3 Section Headers:
4 [Nr] Name Type Address Offset 4 [Nr] Name Type Address Offset
5 Size EntSize Flags Link Info Align 5 Size EntSize Flags Link Info Align
6 [ 0] NULL 0000000000000000 00000000 6 [ 0] NULL 0000000000000000 00000000
7 0000000000000000 0000000000000000 0 0 0 7 0000000000000000 0000000000000000 0 0 0
+ 8 +-- 40 lines: [ 1] .interp PROGBITS 0000000000000200 0000 + 8 +-- 40 lines: [ 1] .interp PROGBITS 0000000000000200 00000200
48 [21] .data PROGBITS 0000000000011000 00001000 48 [21] .data PROGBITS 0000000000011000 00001000
49 0000000000000014 0000000000000000 WA 0 0 8 49 0000000000000014 0000000000000000 WA 0 0 8
50 [22] .bss NOBITS 0000000000011014 00001014 50 [22] .bss NOBITS 0000000000011014 00001014
51 0000000000000004 0000000000000000 WA 0 0 1 51 0000000000000004 0000000000000000 WA 0 0 1
52 [23] .comment PROGBITS 0000000000000000 00001014 52 [23] .comment PROGBITS 0000000000000000 00001014
53 0000000000000030 0000000000000001 MS 0 0 1 53 0000000000000030 0000000000000001 MS 0 0 1
54 [24] .symtab SYMTAB 0000000000000000 00001048 54 [24] .shstrtab STRTAB 0000000000000000 00001044
55 00000000000008a0 0000000000000018 25 64 8 55 00000000000000dc 0000000000000000 0 0 1
56 [25] .strtab STRTAB 0000000000000000 000018e8 ------------------------------------------------------------------------------------
57 0000000000000355 0000000000000000 0 0 1 ------------------------------------------------------------------------------------
58 [26] .shstrtab STRTAB 0000000000000000 00001c3d ------------------------------------------------------------------------------------
59 00000000000000ec 0000000000000000 0 0 1 ------------------------------------------------------------------------------------
60 Key to Flags: 56 Key to Flags:
61 W (write), A (alloc), X (execute), M (merge), S (strings), I (info), 57 W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
62 L (link order), O (extra OS processing required), G (group), T (TLS), 58 L (link order), O (extra OS processing required), G (group), T (TLS),
63 C (compressed), x (unknown), o (OS specific), E (exclude), 59 C (compressed), x (unknown), o (OS specific), E (exclude),
64 p (processor specific) 60 p (processor specific)
tangyuan@ubuntu:~/compiler_test/gcc_test/x86/test$ readelf -s y.so|grep -A5 Symbol
Symbol table '.dynsym' contains 19 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 00000000000005c8 0 SECTION LOCAL DEFAULT 9
2: 0000000000011018 0 SECTION LOCAL DEFAULT 20
3: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _ITM_deregisterTMCloneTab
--
Symbol table '.symtab' contains 73 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000000190 0 SECTION LOCAL DEFAULT 1
2: 00000000000001b8 0 SECTION LOCAL DEFAULT 2
3: 0000000000000208 0 SECTION LOCAL DEFAULT 3
10.动态链接重定位表(.rela.plt,.rela.dyn)
参考资料: