ELF静态链接过程和动态链接过程中的GOT表的作用

..1. 目录

..2. 准备工具和基础汇编知识

  • readelf -a 查看elf信息
  • objdump -S 查看汇编指令
  • ldd 查看动态加载
  • xxd - make a hexdump or do the reverse.
  • gdb
    • gdb 通过layout regs打开寄存器显示, 通过set disassemble-next-line on打开汇编
    • gdb 通过peda插件字节显示汇编和寄存器 和上面的原生方式选择一个即可
    • gdb关闭ASLR:
      • set disable-randomization on
    • 开启ASLR:
      • set disable-randomization off
    • 查看ASLR状态:
      • show disable-randomization
    • disas反汇编命令,直接disas是反汇编当前函数
      • disas /r (显示汇编指令对应十六进制值)
      • disas /m (如果有源码,显示对应行源码)
    • intel语法
      • set disassembly-flavor intel
      • set disassembly-flavor att
  • 详细工具和汇编的基础知识见上一篇文章: 汇编语法/寻址/寄存器/代码模型(GNU assembler)

..3. 编译链接过程的基本原理和流程

C和C++均使用分离编译来支持多源文件模块化机制, 因此也带来了静态和动态的链接问题, 本文主要梳理了静态库的链接过程和动态链接过程.

..3.1. gcc中编译一个源文件可以拆分为4个部分

  1. 预处理 -E
  2. 编译器 -S
  3. 目标文件 -C
  4. 链接为共享库或者可执行程序

..3.2. 编译单元(Translation environment), 编译的转换阶段 :

[ISO/IEC 9899:1999]A C program need not all be translated at the same time.The text of the program is kept in units called source files, (or preprocessing files) in this International Standard.A source file together with all the headers and source files included via the preprocessing directive #include is known as a preprocessing translation unit. After preprocessing, a preprocessing translation unit is called a translation unit.
Previously translated translation units may be preserved individually or in libraries. The separate translation units of a program communicate by (for example) calls to functions whose identifiers have external linkage, manipulation of objects whose identifiers have external linkage, or manipulation of data files. Translation units may be separately translated and then later linked to produce an executable program.

C语言的程序不需要一同时间翻译, 在这个国际标准中, 程序的文本内容以源文件(或者预处理文件)为单位保存, 一个源文件连同所有通过预处理指令#include包含的头文件和源文件被称为预处理翻译单元, 经过预处理后的翻译单元称为翻译单元. 翻译单位可以单独保存,也可以打包在程序库里. 程序的独立翻译单元通过(例如) 调用具有外部链接标识的函数, 处理具有外部链接标识的对象完成连接过程. 翻译单元可以独立翻译然后通过链接生成可执行程序.

..3.3. PIC PIE 位置无关代码

编译出的二进制指令不使用绝对地址而使用相对地址称为PIC 技术
PIE和PIC的区别在于PIE假定了代码最终会被直接链接为可执行程序

..3.4. GOT PLT 全局偏移表 链接过程表

这两个表完成了上面编译单元中所说的处理过程

..3.5. 符号表和符号

..3.5.1. 全局符号和局部符号

符号的全局和局部是相对于编译单元而言的, 例如添加了static前缀的全局变量或者函数只在当前的编译单元可见, 因此是局部的 .
重定位不关心局部符号, 而对于在函数内声明的局部变量的名字并不会存储到符号表 完全由运行时栈来维护,(-g选项可以在.debug中找到符号).
符号表是为了编译单元之间建立联系使用的, 比如重定位.

..3.5.2. 外部符号和内部符号

外部符号是指的当前编译单元使用但是却不在当前编译单元定义的符号.

..3.5.3. 和字符串表的关系

符号表的name字段是字符串表的索引, 也就是说, 符号表本身并不存储符号的’字符串’名.
字符串表除了保存符号名外, 还保存常量字符串的值

..3.6. 静态链接过程

  1. 编译阶段
    1. 建立字符串表,符号表, 保存符号对应的声明信息.
    2. 建立重定位表, 对全局符号的访问都标记出准确的偏移地址
  2. 链接生成阶段
    1. 合并目标文件中相同的节, 确定虚拟内存地址(pic技术只确定相对地址)
    2. 重建重定位表和符号表
    3. 使用重定位表和符号表中记录的数据对代码段和数据段进行修改.
  3. 运行时
    1. 所有地址已经完成重定位 对全局符号的访问不存在中间过程
    2. 如果未非位置无关代码, 则对全局符号的访问为立即数即为分配好的实际地址
    3. 如果是位置无关代码, 则对全局符号的访问需要用rip计算相对偏移.

..3.7. 动态链接过程

动态链接和静态链接的区别在于, 动态链接把重定位的时机放在了动态库被加载到内存之后.

  1. 编译阶段
    1. 建立字符串表,符号表, 保存符号对应的声明信息.
    2. 建立重定位表, 对全局符号的访问都标记出准确的偏移地址
  2. 链接生成阶段
    1. 合并目标文件中相同的节 确定虚拟内存地址(pic技术只确定相对地址)
    2. 重建重定位表和符号表
    3. 使用重定位表和符号表中记录的数据对代码段和数据段进行修改.
    4. 保存全局符号到动态符号表(符号表中有全部符号数据 此为优化)
    5. 建立动态重定位表, 对全局变量的访问走GOT表, 动态重定位表记录了符号名和对应数据段中的编号(该数据段被标记为.got节).
    6. 建立链接过程表, 对全局函数的访问生成plt代码(.plt), 链接过程重定位表(.rela.plt)记录了每个全局函数的符号名以及在保存实际函数地址的数据段的地址. (.got.plt节), .got.plt表中存储的指针默认是
      1. .got.plt中所有函数的地址都会默认保存为第 个元素的内容, 该地址为_dl_runtime_resolve , 通过符号表找到真正的函数地址后填充.got.plt并执行函数.
    7. 对于内部符号的访问是否会进行优化 取决于代码模型, 例如对于小型代码模型中, 可执行程序中会直接访问全局变量的地址(被优化,但仍然保留GOT机制的有效性). 但是共享库中对全局变量的访问即使是当前库中的也一定会走got表.
  3. 运行时
    1. 加载共享库
      1. 完成got, got.plt的填充
      2. 如果有repolr技术则设置内存段的只读
    2. 运行过程中
      1. 对全局变量的访问需要通过got表找到真正的地址
      2. 对函数的访问每次都会走plt, 第一次访问会跳转到符号解析函数找到真正的函数地址, 后续plt则会省略解析流程, 此为惰性加载机制.

..4. 跟踪调测

编译选项为

  • 位置无关代码
  • 禁止优化
  • 禁止假设代码模型

..4.1. 测试源码

lib.cpp

1
2
3
4
5
6
int g_static_lib_bss = 0;
int g_static_lib_data = 100;
int lib_func(int a, int b)
{
return a+b + g_static_lib_bss + g_static_lib_data;
}

so.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
int lib_func(int a, int b);
extern long long g_static_lib_bss;
extern long long g_static_lib_data;
long long g_static_so_bss = 0;
long long g_static_so_data = 100000;

static long long g_local_so_data = 0xff00ff00;

int so_child_func(int a, int b)
{
return a+b + g_static_so_bss + g_static_so_data;
}

static int so_local_func()
{
return g_local_so_data;
}

int so_func(int a, int b)
{
g_static_so_bss ++;
g_static_so_data ++;
int ret = lib_func(g_static_so_bss, g_static_so_data);
ret += so_child_func(g_static_lib_data, g_static_lib_bss);
ret += so_local_func();
return ret;
}

main.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
int so_child_func(int a, int b);
int so_func(int a, int b);
extern int g_static_so_bss;
extern int g_static_so_data;

int g_main_static[128*1024] = {2,1};

int main_func(int a, int b)
{
int c = a+b;
c += g_static_so_bss;
c += g_static_so_data;
c += g_main_static[0];
c += so_func(a, b);
return c;
}

int main(int argc, char *argv[])
{
int a = 0;
g_static_so_bss = 1000000;
a += main_func(argc, 1);
return a;
}

..4.2. 位置有关的重定位分析

1
2
3
4
g++ -c so.cpp  -O0 -mcmodel=large  -fno-pic  
g++ -c lib.cpp -O0 -mcmodel=large -fno-pic
g++ -c main.cpp -O0 -mcmodel=large -fno-pic
g++ so.o lib.o main.o -O0 -mcmodel=large -no-pie
..4.2.1. 分析结论如下:
  • so.cpp中所有非static的全局变量和函数都存在符号表中

    • 符号表的起始偏移为00000200 大小为198
    • 字符串表的起始偏移为00000398 大小为a4
  • 通过xxd命令可以观察到存储所有所有符号名的位置为 0x398处开始分别是字符串:

    • null
    • so.cpp
    • _ZL15g_local_so_data
  • 字符串表中的字符串均为标准的c-style风格的null为结尾(0x00)的字符串

  • 符号表的所在位置0x00000200则为规整的数组 没有字符串信息

  • 局部变量出现在目标对象的符号表中但对其访问的代码位置未出现在重定位表中

  • 局部变量在符号中的类型是LOCAL

  • 无论外部符号还是内部符号, 对于全局符号的访问均在重定位表中指明了具体的符号和偏移数据

  • R_X86_64_64类型或者PC类型均为直接修改访问代码来完成重定位

  • 对于外部的符号 无论是函数还是数据 在符号表中 均为NOTYPE GLOBAL UND的一行占位数据

  • 对于内部定义的全局函数, 则记录了再文本节中的具体的地址偏移,大小,类型等信息.

  • 对于内部定义的全局变量, 则记录了该变量的序号, 大小, 类型信息.

  • .data字段为16字节 内容分别是 a086 0100 0000 0000, 00ff 00ff 0000 0000

    • 对应为long long g_static_so_data = 100000; 和static long long g_local_so_data = 0xff00ff00;

访问全局数据

1
2
3
int so_func(int a, int b)
{
g_static_so_bss ++;

这里的g_static_so_bss 对应的汇编为:

1
2
3
4
55:   48 b8 00 00 00 00 00    movabs $0x0,%rax
5c: 00 00 00
5f: 48 8b 00 mov (%rax),%rax
62: 48 8d 50 01 lea 0x1(%rax),%rdx

其意思是

  • 用64位立即数0来设置rax寄存器
  • 解引用rax 并把内容保存到rax寄存器
  • rax的内容+1 (这里利用了lea寻址完成++)并保存到rdx寄存器
    这里问题就来了, 用C语言来描述就是 我们对地址 为0的的指针当做真实的全局变量的地址进行了解引用.

那么我们看下经过链接后的该汇编代码:

1
2
3
4
4005d3:       48 b8 60 10 68 00 00    movabs $0x681060,%rax
4005da: 00 00 00
4005dd: 48 8b 00 mov (%rax),%rax
4005e0: 48 8d 50 01 lea 0x1(%rax),%rdx

在这里, 这个立即数已经变成了合并完.data后, g_static_so_bss的真实地址.
这个立即数指令所在的地址偏移为0x57 然后我们查看重定位表即可发现完成该过程所需要的重定位信息:

1
000000000057  000a00000001 R_X86_64_64       0000000000000000 g_static_so_bss + 0

备注:
这里我们看到最终链接出的地址4005da: 说明该程序并非pic代码, 对全局变量的访问没有任何相对计算以及读表过程.

..4.2.2. 系统源码参考:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/* $begin elfsymbol */
typedef struct {
int name; /* String table offset */
char type:4, /* Function or data (4 bits) */
binding:4; /* Local or global (4 bits) */
char reserved; /* Unused */
short section; /* Section header index */
long value; /* Section offset or absolute address */
long size; /* Object size in bytes */
} Elf64_Symbol;
/* $end elfsymbol */

/* $begin elfrelo */
typedef struct {
long offset; /* Offset of the reference to relocate */
long type:32, /* Relocation type */
symbol:32; /* Symbol table index */
long addend; /* Constant part of relocation expression */
} Elf64_Rela;
/* $end elfrelo */
..4.2.3. 字符串数据
1
2
3
4
5
6
7
8
9
10
11
00000390: 0000 0000 0000 0000 0073 6f2e 6370 7000  .........so.cpp.
000003a0: 5f5a 4c31 3567 5f6c 6f63 616c 5f73 6f5f _ZL15g_local_so_
000003b0: 6461 7461 005f 5a4c 3133 736f 5f6c 6f63 data._ZL13so_loc
000003c0: 616c 5f66 756e 6376 0067 5f73 7461 7469 al_funcv.g_stati
000003d0: 635f 736f 5f62 7373 0067 5f73 7461 7469 c_so_bss.g_stati
000003e0: 635f 736f 5f64 6174 6100 5f5a 3133 736f c_so_data._Z13so
000003f0: 5f63 6869 6c64 5f66 756e 6369 6900 5f5a _child_funcii._Z
00000400: 3773 6f5f 6675 6e63 6969 005f 5a38 6c69 7so_funcii._Z8li
00000410: 625f 6675 6e63 6969 0067 5f73 7461 7469 b_funcii.g_stati
00000420: 635f 6c69 625f 6273 7300 675f 7374 6174 c_lib_bss.g_stat
00000430: 6963 5f6c 6962 5f64 6174 6100 0000 0000 ic_lib_data.....
..4.2.4. 节信息
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
ELF 头:
Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
类别: ELF64
数据: 2 补码,小端序 (little endian)
版本: 1 (current)
OS/ABI: UNIX - System V
ABI 版本: 0
类型: REL (可重定位文件)
系统架构: Advanced Micro Devices X86-64
版本: 0x1
入口点地址: 0x0
程序头起点: 0 (bytes into file)
Start of section headers: 1592 (bytes into file)
标志: 0x0
本头的大小: 64 (字节)
程序头大小: 0 (字节)
Number of program headers: 0
节头大小: 64 (字节)
节头数量: 12
字符串表索引节头: 11

节头:
[号] 名称 类型 地址 偏移量
大小 全体大小 旗标 链接 信息 对齐
[ 0] NULL 0000000000000000 00000000
0000000000000000 0000000000000000 0 0 0
[ 1] .text PROGBITS 0000000000000000 00000040
0000000000000103 0000000000000000 AX 0 0 1
[ 2] .rela.text RELA 0000000000000000 00000440
0000000000000150 0000000000000018 I 9 1 8
[ 3] .data PROGBITS 0000000000000000 00000148
0000000000000010 0000000000000000 WA 0 0 8
[ 4] .bss NOBITS 0000000000000000 00000158
0000000000000008 0000000000000000 WA 0 0 8
[ 5] .comment PROGBITS 0000000000000000 00000158
000000000000002e 0000000000000001 MS 0 0 1
[ 6] .note.GNU-stack PROGBITS 0000000000000000 00000186
0000000000000000 0000000000000000 0 0 1
[ 7] .eh_frame PROGBITS 0000000000000000 00000188
0000000000000078 0000000000000000 A 0 0 8
[ 8] .rela.eh_frame RELA 0000000000000000 00000590
0000000000000048 0000000000000018 I 9 7 8
[ 9] .symtab SYMTAB 0000000000000000 00000200
0000000000000198 0000000000000018 10 10 8
[10] .strtab STRTAB 0000000000000000 00000398
00000000000000a4 0000000000000000 0 0 1
[11] .shstrtab STRTAB 0000000000000000 000005d8
0000000000000059 0000000000000000 0 0 1
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
L (link order), O (extra OS processing required), G (group), T (TLS),
C (compressed), x (unknown), o (OS specific), E (exclude),
l (large), p (processor specific)

There are no section groups in this file.

本文件中没有程序头。

重定位节 '.rela.text' 位于偏移量 0x440 含有 14 个条目:
偏移量 信息 类型 符号值 符号名称 + 加数
000000000016 000a00000001 R_X86_64_64 0000000000000000 g_static_so_bss + 0
000000000025 000b00000001 R_X86_64_64 0000000000000000 g_static_so_data + 0
00000000003a 000300000001 R_X86_64_64 0000000000000000 .data + 8
000000000057 000a00000001 R_X86_64_64 0000000000000000 g_static_so_bss + 0
000000000068 000a00000001 R_X86_64_64 0000000000000000 g_static_so_bss + 0
000000000075 000b00000001 R_X86_64_64 0000000000000000 g_static_so_data + 0
000000000086 000b00000001 R_X86_64_64 0000000000000000 g_static_so_data + 0
000000000093 000b00000001 R_X86_64_64 0000000000000000 g_static_so_data + 0
0000000000a2 000a00000001 R_X86_64_64 0000000000000000 g_static_so_bss + 0
0000000000b3 000e00000001 R_X86_64_64 0000000000000000 _Z8lib_funcii + 0
0000000000c2 000f00000001 R_X86_64_64 0000000000000000 g_static_lib_bss + 0
0000000000d1 001000000001 R_X86_64_64 0000000000000000 g_static_lib_data + 0
0000000000e2 000c00000001 R_X86_64_64 0000000000000000 _Z13so_child_funcii + 0
0000000000f1 000200000001 R_X86_64_64 0000000000000000 .text + 34

重定位节 '.rela.eh_frame' 位于偏移量 0x590 含有 3 个条目:
偏移量 信息 类型 符号值 符号名称 + 加数
000000000020 000200000002 R_X86_64_PC32 0000000000000000 .text + 0
000000000040 000200000002 R_X86_64_PC32 0000000000000000 .text + 34
000000000060 000200000002 R_X86_64_PC32 0000000000000000 .text + 47

The decoding of unwind sections for machine type Advanced Micro Devices X86-64 is not currently supported.

Symbol table '.symtab' contains 17 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000000000 0 FILE LOCAL DEFAULT ABS so.cpp
2: 0000000000000000 0 SECTION LOCAL DEFAULT 1
3: 0000000000000000 0 SECTION LOCAL DEFAULT 3
4: 0000000000000000 0 SECTION LOCAL DEFAULT 4
5: 0000000000000008 8 OBJECT LOCAL DEFAULT 3 _ZL15g_local_so_data
6: 0000000000000034 19 FUNC LOCAL DEFAULT 1 _ZL13so_local_funcv
7: 0000000000000000 0 SECTION LOCAL DEFAULT 6
8: 0000000000000000 0 SECTION LOCAL DEFAULT 7
9: 0000000000000000 0 SECTION LOCAL DEFAULT 5
10: 0000000000000000 8 OBJECT GLOBAL DEFAULT 4 g_static_so_bss
11: 0000000000000000 8 OBJECT GLOBAL DEFAULT 3 g_static_so_data
12: 0000000000000000 52 FUNC GLOBAL DEFAULT 1 _Z13so_child_funcii
13: 0000000000000047 188 FUNC GLOBAL DEFAULT 1 _Z7so_funcii
14: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND _Z8lib_funcii
15: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND g_static_lib_bss
16: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND g_static_lib_data

No version information found in this file.
..4.2.5. text数据
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
so.o:     文件格式 elf64-x86-64   


Disassembly of section .text:

0000000000000000 <_Z13so_child_funcii>:
0: 55 push %rbp
1: 48 89 e5 mov %rsp,%rbp
4: 89 7d fc mov %edi,-0x4(%rbp)
7: 89 75 f8 mov %esi,-0x8(%rbp)
a: 8b 55 fc mov -0x4(%rbp),%edx
d: 8b 45 f8 mov -0x8(%rbp),%eax
10: 01 d0 add %edx,%eax
12: 89 c2 mov %eax,%edx
14: 48 b8 00 00 00 00 00 movabs $0x0,%rax
1b: 00 00 00
1e: 48 8b 00 mov (%rax),%rax
21: 01 c2 add %eax,%edx
23: 48 b8 00 00 00 00 00 movabs $0x0,%rax
2a: 00 00 00
2d: 48 8b 00 mov (%rax),%rax
30: 01 d0 add %edx,%eax
32: 5d pop %rbp
33: c3 retq

0000000000000034 <_ZL13so_local_funcv>:
34: 55 push %rbp
35: 48 89 e5 mov %rsp,%rbp
38: 48 b8 00 00 00 00 00 movabs $0x0,%rax
3f: 00 00 00
42: 48 8b 00 mov (%rax),%rax
45: 5d pop %rbp
46: c3 retq

0000000000000047 <_Z7so_funcii>:
47: 55 push %rbp
48: 48 89 e5 mov %rsp,%rbp
4b: 48 83 ec 20 sub $0x20,%rsp
4f: 89 7d ec mov %edi,-0x14(%rbp)
52: 89 75 e8 mov %esi,-0x18(%rbp)
55: 48 b8 00 00 00 00 00 movabs $0x0,%rax
5c: 00 00 00
5f: 48 8b 00 mov (%rax),%rax
62: 48 8d 50 01 lea 0x1(%rax),%rdx
66: 48 b8 00 00 00 00 00 movabs $0x0,%rax
6d: 00 00 00
70: 48 89 10 mov %rdx,(%rax)
73: 48 b8 00 00 00 00 00 movabs $0x0,%rax
7a: 00 00 00
7d: 48 8b 00 mov (%rax),%rax
80: 48 8d 50 01 lea 0x1(%rax),%rdx
84: 48 b8 00 00 00 00 00 movabs $0x0,%rax
8b: 00 00 00
8e: 48 89 10 mov %rdx,(%rax)
91: 48 b8 00 00 00 00 00 movabs $0x0,%rax
98: 00 00 00
9b: 48 8b 00 mov (%rax),%rax
9e: 89 c2 mov %eax,%edx
a0: 48 b8 00 00 00 00 00 movabs $0x0,%rax
a7: 00 00 00
aa: 48 8b 00 mov (%rax),%rax
ad: 89 d6 mov %edx,%esi
af: 89 c7 mov %eax,%edi
b1: 48 b8 00 00 00 00 00 movabs $0x0,%rax
b8: 00 00 00
bb: ff d0 callq *%rax
bd: 89 45 fc mov %eax,-0x4(%rbp)
c0: 48 b8 00 00 00 00 00 movabs $0x0,%rax
c7: 00 00 00
ca: 48 8b 00 mov (%rax),%rax
cd: 89 c2 mov %eax,%edx
cf: 48 b8 00 00 00 00 00 movabs $0x0,%rax
d6: 00 00 00
d9: 48 8b 00 mov (%rax),%rax
dc: 89 d6 mov %edx,%esi
de: 89 c7 mov %eax,%edi
e0: 48 b8 00 00 00 00 00 movabs $0x0,%rax
e7: 00 00 00
ea: ff d0 callq *%rax
ec: 01 45 fc add %eax,-0x4(%rbp)
ef: 48 b8 00 00 00 00 00 movabs $0x0,%rax
f6: 00 00 00
f9: ff d0 callq *%rax
fb: 01 45 fc add %eax,-0x4(%rbp)
fe: 8b 45 fc mov -0x4(%rbp),%eax
101: c9 leaveq
102: c3 retq

..4.3. 位置无关的重定位分析

1
2
3
4
5
6
g++ -c so.cpp  -O0 -mcmodel=large  -fPIC  
g++ -c lib.cpp -O0 -mcmodel=large -fPIC
g++ -c main.cpp -O0 -mcmodel=large -fPIC
g++ -shared so.o -O0 -mcmodel=large -fPIC
g++ so.so lib.o main.o -O0 -mcmodel=large -pie -fPIE
export LD_LIBRARY_PATH=LD_LIBRARY_PATH:./
1
2
3
4
5
6
g++-6 -c so.cpp  -O0 -mcmodel=large  -fPIC  
g++-6 -c lib.cpp -O0 -mcmodel=large -fPIC
g++-6 -c main.cpp -O0 -mcmodel=large -fPIC
g++-6 -shared so.o -oso.so -O0 -mcmodel=large -fPIC
g++-6 so.so lib.o main.o -O0 -mcmodel=large -pie -fPIE
export LD_LIBRARY_PATH=LD_LIBRARY_PATH:./
..4.3.1. 分析说明

PIC的代码在编译为目标对象时, 所用的重定位方法和非PIC在方法上并没有差别

指明代码段中访问全局符号的操作数位置
在编译阶段用正确的地址替换掉占位用的空地址
与非PIC的差别我们会看到访问所有数据最终最终都会通过GOT表, 所以这部分的立即数会首先被替换成GOT表的地址
本段分析中主要分析动态链接的关键部分GOT/PLT/LOAD/FIXSYMBO部分分析, 对上述部分不再贴细节分析代码.

  • so中的重定位表分别是.rela.dyn .rela.plt, 和目标文件中的记录格式类似但有明显不同
    • 无论是对全局数据的访问还是对全局函数的访问, 其重定位的地址都不在是代码段中的位置, 而是位于数据段
      • 对全局变量的访问, 重定位地址在.got段 数据段
      • 对全局函数的访问, 重定位地址在.got.plt段 数据段
  • 重定位不在涉及修改.txt段中的内容, 所以共享库的文本段是可以跨进程安全共享的
..4.3.2. 全局数据访问代码分析

访问全局数据

1
2
3
int so_func(int a, int b)
{
g_static_so_bss ++;

这里的g_static_so_bss++ 对应的汇编为:

1
2
3
4
5
6
7
8
9
10
11
8a3:   48 8d 1d f9 ff ff ff    lea    -0x7(%rip),%rbx        # 8a3 <_Z7so_funcii+0xb>
8aa: 49 bb 5d 07 20 00 00 movabs $0x20075d,%r11
8b1: 00 00 00
8b4: 4c 01 db add %r11,%rbx
8b7: 89 7d dc mov %edi,-0x24(%rbp)
8ba: 89 75 d8 mov %esi,-0x28(%rbp)
8bd: 48 b8 e0 ff ff ff ff movabs $0xffffffffffffffe0,%rax
8c4: ff ff ff
8c7: 48 8b 04 03 mov (%rbx,%rax,1),%rax
8cb: 48 8b 00 mov (%rax),%rax
8ce: 48 8d 50 01 lea 0x1(%rax),%rdx

其意思是

  • 8a3这行指令+0x20075d偏移保存到%rbx
  • 计算出最终地址(%rbx + xffffffffffffffe0 (-20) * 1)并取值到rax
    • rbx的值为0x201000该地址对应的是节.got.plt 也是.got + sizeof(.got)的位置
    • -20位则表示在.got中 最终的地址为0x200fe0
    • 查找.dyn表可以知道该位置为000000200fe0 g_static_so_bss + 0
    • 查看该位置的内存为0
    • 那么如果在运行时没有进行动态填充, 则这里会出现对地址0进行解引用的操作.
    • rbx寄存器会复用 专门用来保存got表的入口偏移, 也就是浪费了一个通用寄存器来实现地址无关代码
  • 我们进入gdb调试
1
2
3
4
5
6
7
8
9
0x7ffff7bd68a3    lea    -0x7(%rip),%rbx        # 0x7ffff7bd68a3 <_Z7so_funcii+11>   
0x7ffff7bd68aa movabs $0x20075d,%r11
0x7ffff7bd68b4 add %r11,%rbx
0x7ffff7bd68b7 mov %edi,-0x24(%rbp)
0x7ffff7bd68ba mov %esi,-0x28(%rbp)
0x7ffff7bd68bd movabs $0xffffffffffffffe0,%rax
0x7ffff7bd68c7 mov (%rbx,%rax,1),%rax
0x7ffff7bd68cb mov (%rax),%rax
0x7ffff7bd68ce lea 0x1(%rax),%rdx

带入计算:

+ 0x20075d + -20*1
1
该位置位于加载so.so的内存中, 对应为只读的got表

00007ffff7bd6000 4K r-x– so.so
00007ffff7bd7000 2044K —– so.so
00007ffff7dd6000 4K r—- so.so
00007ffff7dd7000 4K rw— so.so

1
2
推算got表在内存中的实际位置为 0x7FFFF7DD6FE0 - 28 =  0x7FFFF7DD6FB8  
那么查看该got实际的内存如下:

(gdb) x /9ag 0x7FFFF7DD6FB8
0x7ffff7dd6fb8: 0x7ffff6f27c30 <__cxa_finalize>
0x7ffff7dd6fc0: 0x555555755030
0x7ffff7dd6fc8: 0x5555557d5044
0x7ffff7dd6fd0: 0x0
0x7ffff7dd6fd8: 0x7ffff7dd7030
0x7ffff7dd6fe0: 0x7ffff7dd7048
0x7ffff7dd6fe8: 0x0
0x7ffff7dd6ff0: 0x0
0x7ffff7dd6ff8: 0x0

1
2
3

对应0x7FFFF7DD6FE0的位置已经保存了正确的g_static_so_bss的地址.
再进一步读取变量的值:

0x7ffff7dd7048 : 0xf4240 (1000000)
0x7ffff7dd7030 : 0x186a0 (100000)

1
2
3
4
5
6
7
值也正确.   
全局变量实际保存的位置对应so.so的可读写数据段




##### ..4.3.3. 全局函数访问代码分析

int so_func(int a, int b)
{
g_static_so_bss ++;
g_static_so_data ++;
int ret = lib_func(g_static_so_bss, g_static_so_data);
ret += so_child_func(g_static_lib_data, g_static_lib_bss);
ret += so_local_func();
return ret;
}

1
2
3
对应的汇编码如下:  
%esi保存了g_static_lib_data %edi 保存了g_static_lib_bss
%rbx保存了base 偏移 8a3 + 0x20075d

934: 48 b8 00 f7 df ff ff movabs $0xffffffffffdff700,%rax
93b: ff ff ff
93e: 48 01 d8 add %rbx,%rax
941: ff d0 callq *%rax

1
2
3
这里callq的实际地址为 8a3 + 0x20075d -0x900 = 0x200700   
该地址位于.plt中 其偏移相对于.plt为: 0x200700-0x00000000000206e0 = 0x20 偏移地址为700
我们找到代码位置

00000000000006e0 <.plt>:
6e0: ff 35 22 09 20 00 pushq 0x200922(%rip) # 201008 <GOT_+0x8> link_map
6e6: ff 25 24 09 20 00 jmpq *0x200924(%rip) # 201010 <GOT+0x10> _dl_runtime_resolve_xsavec
6ec: 0f 1f 40 00 nopl 0x0(%rax)

00000000000006f0 <_Z13so_child_funcii@plt>:
6f0: ff 25 22 09 20 00 jmpq *0x200922(%rip) # 201018 <_Z13so_child_funcii@@Base+0x2007f8>
6f6: 68 00 00 00 00 pushq $0x0
6fb: e9 e0 ff ff ff jmpq 6e0 <.plt>

0000000000000700 <_Z8lib_funcii@plt>:
700: ff 25 1a 09 20 00 jmpq *0x20091a(%rip) # 201020 <_Z8lib_funcii>
706: 68 01 00 00 00 pushq $0x1
70b: e9 d0 ff ff ff jmpq 6e0 <.plt>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

700跳转到 (706+0x20091a) 这个地址保存的内存
这个地址为 0x201020 即.got.plt的第5项
在elf文件中.got.plt是有5个值的, 第五项保存的值为706 也就是jmpq的下一行代码
```pushq $0x1``` 意思是把当前的plt序号(.rela.plt的项)保存到栈上(传参)
在装载后, 相对偏移706会被替换成实际分配好的地址
因此第一次jmpq会跳转到偏移6e0处
再把got+8的位置压栈, (这个指针是link_map 后文会继续讲)
然后跳转到函数 ```_dl_runtime_resolve_xsavec```

got+8 和got+10 将会完成符号的解析工作并找到真正的目标函数地址, 然后回写plt 执行目标函数.
这两项程序装载时会完成填充, 而后续的plt的其他函数会基于该机制以惰性加载机制调用时解析.



GDB调试内容如下:

0x7ffff7bd6700 <_Z8lib_funcii@plt> jmpq *0x20091a(%rip) # 0x7ffff7dd7020
0x7ffff7bd6706 <_Z8lib_funcii@plt+6> pushq $0x1
0x7ffff7bd670b <_Z8lib_funcii@plt+11> jmpq 0x7ffff7bd66e0
0x7ffff7bd6710 jmpq *0x2008a2(%rip) # 0x7ffff7dd6fb8

(gdb) x /1ag 0x7ffff7dd7020
0x7ffff7dd7020: 0x7ffff7bd6706 <_Z8lib_funcii@plt+6>

(gdb) x /5ag 0x7ffff7dd7000
0x7ffff7dd7000: 0x200dc8
0x7ffff7dd7008: 0x7ffff7ff6000
0x7ffff7dd7010: 0x7ffff7ded310 <_dl_runtime_resolve_xsavec>
0x7ffff7dd7018: 0x7ffff7bd66f6 <_Z13so_child_funcii@plt+6>
0x7ffff7dd7020: 0x7ffff7bd6706 <_Z8lib_funcii@plt+6>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45

```_dl_runtime_resolve_xsavec```
rbx+8为符号表链表指针
rbx+16为压到栈上的目标函数编号 存储在plt的下标从第四项开始, 前三项分别是offset, link_map, 解析函数
```_dl_fixup``` 返回了查找到的真实地址 ```bnd jmpq *%r11``` 跳转到实际地址

```
0x7ffff7ded310 push %rbx
0x7ffff7ded311 mov %rsp,%rbx
0x7ffff7ded314 and $0xffffffffffffffc0,%rsp
0x7ffff7ded318 sub 0x20f4e9(%rip),%rsp # 0x7ffff7ffc808 <_rtld_global_ro+168>
0x7ffff7ded31f mov %rax,(%rsp)
0x7ffff7ded323 mov %rcx,0x8(%rsp)
0x7ffff7ded328 mov %rdx,0x10(%rsp)
0x7ffff7ded32d mov %rsi,0x18(%rsp)
0x7ffff7ded332 mov %rdi,0x20(%rsp)
0x7ffff7ded337 mov %r8,0x28(%rsp)
0x7ffff7ded33c mov %r9,0x30(%rsp)
0x7ffff7ded341 mov $0xee,%eax
0x7ffff7ded346 xor %edx,%edx
0x7ffff7ded348 mov %rdx,0x250(%rsp)
0x7ffff7ded350 mov %rdx,0x258(%rsp)
0x7ffff7ded358 mov %rdx,0x260(%rsp)
0x7ffff7ded360 mov %rdx,0x268(%rsp)
0x7ffff7ded368 mov %rdx,0x270(%rsp)
0x7ffff7ded370 mov %rdx,0x278(%rsp)
0x7ffff7ded378 xsavec 0x40(%rsp)
0x7ffff7ded37d mov 0x10(%rbx),%rsi
0x7ffff7ded381 mov 0x8(%rbx),%rdi
0x7ffff7ded385 callq 0x7ffff7de6630 <_dl_fixup>
0x7ffff7ded38a mov %rax,%r11
0x7ffff7ded38d mov $0xee,%eax
0x7ffff7ded392 xor %edx,%edx
0x7ffff7ded394 xrstor 0x40(%rsp)
0x7ffff7ded399 mov 0x30(%rsp),%r9
0x7ffff7ded39e mov 0x28(%rsp),%r8
0x7ffff7ded3a3 mov 0x20(%rsp),%rdi
0x7ffff7ded3a8 mov 0x18(%rsp),%rsi
0x7ffff7ded3ad mov 0x10(%rsp),%rdx
0x7ffff7ded3b2 mov 0x8(%rsp),%rcx
0x7ffff7ded3b7 mov (%rsp),%rax
0x7ffff7ded3bb mov %rbx,%rsp
0x7ffff7ded3be mov (%rsp),%rbx
0x7ffff7ded3c2 add $0x18,%rsp
0x7ffff7ded3c6 bnd jmpq *%r11
1
2
3
4
5
6
7
8
9
10
11
12
```C++
// Elf64_Rela
typedef uint64_t Elf64_Addr;
typedef uint64_t Elf64_Xword;
typedef int64_t Elf64_Sxword;

typedef struct
{
Elf64_Addr r_offset; /* Address */
Elf64_Xword r_info; /* Relocation type and symbol index */
Elf64_Sxword r_addend; /* Addend */
} Elf64_Rela;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/Elf64_Sym
typedef uint32_t Elf64_Word;
typedef uint16_t Elf64_Section;
typedef uint64_t Elf64_Addr;
typedef uint64_t Elf64_Xword;

typedef struct
{
Elf64_Word st_name; /* Symbol name (string tbl index), 4 bytes */
unsigned char st_info; /* Symbol type and binding, 1 byte */
unsigned char st_other; /* Symbol visibility, 1 byte */
Elf64_Section st_shndx; /* Section index, 2 bytes */
Elf64_Addr st_value; /* Symbol value, 8 bytes */
Elf64_Xword st_size; /* Symbol size, 8 bytes */
} Elf64_Sym;

libc/elf/dl-runtime.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
__attribute ((noinline)) ARCH_FIXUP_ATTRIBUTE _dl_fixup (
/* GKM FIXME: Fix trampoline to pass bounds so we can do
without the `__unbounded' qualifier. */
struct link_map *__unbounded l, ElfW(Word) reloc_offset)
{
const ElfW(Sym) *const symtab
= (const void *) D_PTR (l, l_info[DT_SYMTAB]);
const char *strtab = (const void *) D_PTR (l, l_info[DT_STRTAB]);

const PLTREL *const reloc
= (const void *) (D_PTR (l, l_info[DT_JMPREL]) + reloc_offset);
const ElfW(Sym) *sym = &symtab[ELFW(R_SYM) (reloc->r_info)];
void *const rel_addr = (void *)(l->l_addr + reloc->r_offset);
lookup_t result;
DL_FIXUP_VALUE_TYPE value;

/* Sanity check that we're really looking at a PLT relocation. */
assert (ELFW(R_TYPE)(reloc->r_info) == ELF_MACHINE_JMP_SLOT);

/* Look up the target symbol. If the normal lookup rules are not
used don't look in the global scope. */
if (__builtin_expect (ELFW(ST_VISIBILITY) (sym->st_other), 0) == 0)
{
const struct r_found_version *version = NULL;

if (l->l_info[VERSYMIDX (DT_VERSYM)] != NULL)
{
const ElfW(Half) *vernum =
(const void *) D_PTR (l, l_info[VERSYMIDX (DT_VERSYM)]);
ElfW(Half) ndx = vernum[ELFW(R_SYM) (reloc->r_info)] & 0x7fff;
version = &l->l_versions[ndx];
if (version->hash == 0)
version = NULL;
}

/* We need to keep the scope around so do some locking. This is
not necessary for objects which cannot be unloaded or when
we are not using any threads (yet). */
int flags = DL_LOOKUP_ADD_DEPENDENCY;
if (!RTLD_SINGLE_THREAD_P)
{
THREAD_GSCOPE_SET_FLAG ();
flags |= DL_LOOKUP_GSCOPE_LOCK;
}

result = _dl_lookup_symbol_x (strtab + sym->st_name, l, &sym, l->l_scope,
version, ELF_RTYPE_CLASS_PLT, flags, NULL);

/* We are done with the global scope. */
if (!RTLD_SINGLE_THREAD_P)
THREAD_GSCOPE_RESET_FLAG ();

/* Currently result contains the base load address (or link map)
of the object that defines sym. Now add in the symbol
offset. */
value = DL_FIXUP_MAKE_VALUE (result,
sym ? (LOOKUP_VALUE_ADDRESS (result)
+ sym->st_value) : 0);
}
else
{
/* We already found the symbol. The module (and therefore its load
address) is also known. */
value = DL_FIXUP_MAKE_VALUE (l, l->l_addr + sym->st_value);
result = l;
}

/* And now perhaps the relocation addend. */
value = elf_machine_plt_value (l, reloc, value);

/* Finally, fix up the plt itself. */
if (__builtin_expect (GLRO(dl_bind_not), 0))
return value;

return elf_machine_fixup_plt (l, result, reloc, rel_addr, value);
}

elf/dl-lookup.c

1
2
3
4
5
6
7
8
9
10
11
/* Search loaded objects' symbol tables for a definition of the symbol
UNDEF_NAME, perhaps with a requested version for the symbol.
We must never have calls to the audit functions inside this function
or in any function which gets called. If this would happen the audit
code might create a thread which can throw off all the scope locking. */
lookup_t
_dl_lookup_symbol_x (const char *undef_name, struct link_map *undef_map,
const ElfW(Sym) **ref,
struct r_scope_elem *symbol_scope[],
const struct r_found_version *version,
int type_class, int flags, struct link_map *skip_map);
字符串表strtab
1
2
3
4
5
6
7
8
9
10
11
12

reloc_offset即是传入的参数reloc_arg 其代表在.rela.plt表中的第几项 保存在reloc中
reloc的r_offset表示需要修改的函数地址在GOT表中的地址 加上装载地址l_addr得到的rel_addr就是最终要修改的.got.plt保存该函数地址的项的绝对地址

st_other描述符号的可见性 如果包含STV_PROTECTED、STV_HIDDEN和STV_INTERNAL的其中任何一种 则直接将装载地址加上st_value即得到函数的最终地址value 将其写入rel_addr (相当于作用域不超过当前符号表的范围)

其他情况 会进入if语句
首先获得符号的version信息 然后调用 ```_dl_lookup_symbol_x``` 函数从已装载的共享库中查找最终的符号地址 查找到符号sym后 对其进行重定位 即加上装载地址 保存在value中
最后调用```elf_machine_fixup_plt```函数进行修正


fixup plt 回写.got.plt的项

static inline Elf64_Addr
elf_machine_fixup_plt (struct link_map *map, lookup_t t,
const Elf64_Rela *reloc,
Elf64_Addr *reloc_addr, Elf64_Addr value)
{
return *reloc_addr = value;
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

```_dl_lookup_symbol_x```
...



got表和plt表在代码中是直接根据代码行的偏移获取的, 因此这里并无随机化过程






##### .got节内容
未填充任何数据

zsummer@debian:~/symbo$ xxd -s+0x00000fb8 -l0x0000000000000048 so.so
00000fb8: 0000 0000 0000 0000 0000 0000 0000 0000 …………….
00000fc8: 0000 0000 0000 0000 0000 0000 0000 0000 …………….
00000fd8: 0000 0000 0000 0000 0000 0000 0000 0000 …………….
00000fe8: 0000 0000 0000 0000 0000 0000 0000 0000 …………….
00000ff8: 0000 0000 0000 0000 ……..

1
2
3
4
5
6
7
8


##### .got.plt节
0x200dc8
0x0
0x0
0x6f6
0x706

zsummer@debian:~/symbo$ xxd -s+0x00001000 -l0x0000000000000028 so.so
00001000: c80d 2000 0000 0000 0000 0000 0000 0000 .. ………….
00001010: 0000 0000 0000 0000 f606 0000 0000 0000 …………….
00001020: 0607 0000 0000 0000 ……..

1
2
3
4
5

##### .data节
2101288
100000
0xff00ff00

zsummer@debian:~/symbo$ xxd -s+0x00001028 -l0x0000000000000018 so.so
00001028: 2810 2000 0000 0000 a086 0100 0000 0000 (. ………….
00001038: 00ff 00ff 0000 0000 ……..

1
2

##### pmap信息

zsummer@debian:~/symbo$ pmap 9208
9208: /home/zsummer/symbo/a.out
0000555555554000 4K r-x– a.out
0000555555754000 4K r—- a.out
0000555555755000 516K rw— a.out
00005555557d6000 132K rw— [ anon ]
00007ffff6ef0000 1732K r-x– libc-2.27.so
00007ffff70a1000 2044K —– libc-2.27.so
00007ffff72a0000 16K r—- libc-2.27.so
00007ffff72a4000 8K rw— libc-2.27.so
00007ffff72a6000 16K rw— [ anon ]
00007ffff72aa000 92K r-x– libgcc_s.so.1
00007ffff72c1000 2044K —– libgcc_s.so.1
00007ffff74c0000 4K r—- libgcc_s.so.1
00007ffff74c1000 4K rw— libgcc_s.so.1
00007ffff74c2000 1608K r-x– libm-2.27.so
00007ffff7654000 2044K —– libm-2.27.so
00007ffff7853000 4K r—- libm-2.27.so
00007ffff7854000 4K rw— libm-2.27.so
00007ffff7855000 1480K r-x– libstdc++.so.6.0.25
00007ffff79c7000 2048K —– libstdc++.so.6.0.25
00007ffff7bc7000 40K r—- libstdc++.so.6.0.25
00007ffff7bd1000 8K rw— libstdc++.so.6.0.25
00007ffff7bd3000 12K rw— [ anon ]
00007ffff7bd6000 4K r-x– so.so
00007ffff7bd7000 2044K —– so.so
00007ffff7dd6000 4K r—- so.so
00007ffff7dd7000 4K rw— so.so
00007ffff7dd8000 148K r-x– ld-2.27.so
00007ffff7fd6000 20K rw— [ anon ]
00007ffff7ff6000 8K rw— [ anon ]
00007ffff7ff8000 8K r—- [ anon ]
00007ffff7ffa000 8K r-x– [ anon ]
00007ffff7ffc000 4K r—- ld-2.27.so
00007ffff7ffd000 4K rw— ld-2.27.so
00007ffff7ffe000 4K rw— [ anon ]
00007ffffffde000 132K rw— [ stack ]
ffffffffff600000 4K r-x– [ anon ]
total 16260K

1
2
3


##### 节信息

ELF 头:
Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
类别: ELF64
数据: 2 补码,小端序 (little endian)
版本: 1 (current)
OS/ABI: UNIX - System V
ABI 版本: 0
类型: DYN (共享目标文件)
系统架构: Advanced Micro Devices X86-64
版本: 0x1
入口点地址: 0x720
程序头起点: 64 (bytes into file)
Start of section headers: 6544 (bytes into file)
标志: 0x0
本头的大小: 64 (字节)
程序头大小: 56 (字节)
Number of program headers: 7
节头大小: 64 (字节)
节头数量: 28
字符串表索引节头: 27

节头:
[号] 名称 类型 地址 偏移量
大小 全体大小 旗标 链接 信息 对齐
[ 0] NULL 0000000000000000 00000000
0000000000000000 0000000000000000 0 0 0
[ 1] .note.gnu.build-i NOTE 00000000000001c8 000001c8
0000000000000024 0000000000000000 A 0 0 4
[ 2] .gnu.hash GNU_HASH 00000000000001f0 000001f0
0000000000000048 0000000000000000 A 3 0 8
[ 3] .dynsym DYNSYM 0000000000000238 00000238
00000000000001b0 0000000000000018 A 4 1 8
[ 4] .dynstr STRTAB 00000000000003e8 000003e8
000000000000013d 0000000000000000 A 0 0 1
[ 5] .gnu.version VERSYM 0000000000000526 00000526
0000000000000024 0000000000000002 A 3 0 2
[ 6] .gnu.version_r VERNEED 0000000000000550 00000550
0000000000000020 0000000000000000 A 4 1 8
[ 7] .rela.dyn RELA 0000000000000570 00000570
0000000000000120 0000000000000018 A 3 0 8
[ 8] .rela.plt RELA 0000000000000690 00000690
0000000000000030 0000000000000018 AI 3 21 8
[ 9] .init PROGBITS 00000000000006c0 000006c0
0000000000000017 0000000000000000 AX 0 0 4
[10] .plt PROGBITS 00000000000006e0 000006e0
0000000000000030 0000000000000010 AX 0 0 16
[11] .plt.got PROGBITS 0000000000000710 00000710
0000000000000008 0000000000000000 AX 0 0 8
[12] .text PROGBITS 0000000000000720 00000720
0000000000000282 0000000000000000 AX 0 0 16
[13] .fini PROGBITS 00000000000009a4 000009a4
0000000000000009 0000000000000000 AX 0 0 4
[14] .eh_frame_hdr PROGBITS 00000000000009b0 000009b0
0000000000000034 0000000000000000 A 0 0 4
[15] .eh_frame PROGBITS 00000000000009e8 000009e8
00000000000000c4 0000000000000000 A 0 0 8
[16] .init_array INIT_ARRAY 0000000000200db0 00000db0
0000000000000008 0000000000000008 WA 0 0 8
[17] .fini_array FINI_ARRAY 0000000000200db8 00000db8
0000000000000008 0000000000000008 WA 0 0 8
[18] .jcr PROGBITS 0000000000200dc0 00000dc0
0000000000000008 0000000000000000 WA 0 0 8
[19] .dynamic DYNAMIC 0000000000200dc8 00000dc8
00000000000001f0 0000000000000010 WA 4 0 8
[20] .got PROGBITS 0000000000200fb8 00000fb8
0000000000000048 0000000000000008 WA 0 0 8
[21] .got.plt PROGBITS 0000000000201000 00001000
0000000000000028 0000000000000008 WA 0 0 8
[22] .data PROGBITS 0000000000201028 00001028
0000000000000018 0000000000000000 WA 0 0 8
[23] .bss NOBITS 0000000000201040 00001040
0000000000000010 0000000000000000 WA 0 0 8
[24] .comment PROGBITS 0000000000000000 00001040
000000000000002d 0000000000000001 MS 0 0 1
[25] .symtab SYMTAB 0000000000000000 00001070
00000000000005e8 0000000000000018 26 46 8
[26] .strtab STRTAB 0000000000000000 00001658
0000000000000246 0000000000000000 0 0 1
[27] .shstrtab STRTAB 0000000000000000 0000189e
00000000000000ee 0000000000000000 0 0 1
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
L (link order), O (extra OS processing required), G (group), T (TLS),
C (compressed), x (unknown), o (OS specific), E (exclude),
l (large), p (processor specific)

There are no section groups in this file.

程序头:
Type Offset VirtAddr PhysAddr
FileSiz MemSiz Flags Align
LOAD 0x0000000000000000 0x0000000000000000 0x0000000000000000
0x0000000000000aac 0x0000000000000aac R E 0x200000
LOAD 0x0000000000000db0 0x0000000000200db0 0x0000000000200db0
0x0000000000000290 0x00000000000002a0 RW 0x200000
DYNAMIC 0x0000000000000dc8 0x0000000000200dc8 0x0000000000200dc8
0x00000000000001f0 0x00000000000001f0 RW 0x8
NOTE 0x00000000000001c8 0x00000000000001c8 0x00000000000001c8
0x0000000000000024 0x0000000000000024 R 0x4
GNU_EH_FRAME 0x00000000000009b0 0x00000000000009b0 0x00000000000009b0
0x0000000000000034 0x0000000000000034 R 0x4
GNU_STACK 0x0000000000000000 0x0000000000000000 0x0000000000000000
0x0000000000000000 0x0000000000000000 RW 0x10
GNU_RELRO 0x0000000000000db0 0x0000000000200db0 0x0000000000200db0
0x0000000000000250 0x0000000000000250 R 0x1

Section to Segment mapping:
段节…
00 .note.gnu.build-id .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rela.dyn .rela.plt .init .plt .plt.got .text .fini .eh_frame_hdr .eh_frame
01 .init_array .fini_array .jcr .dynamic .got .got.plt .data .bss
02 .dynamic
03 .note.gnu.build-id
04 .eh_frame_hdr
05
06 .init_array .fini_array .jcr .dynamic .got

Dynamic section at offset 0xdc8 contains 27 entries:
标记 类型 名称/值
0x0000000000000001 (NEEDED) 共享库:[libstdc++.so.6]
0x0000000000000001 (NEEDED) 共享库:[libm.so.6]
0x0000000000000001 (NEEDED) 共享库:[libgcc_s.so.1]
0x0000000000000001 (NEEDED) 共享库:[libc.so.6]
0x000000000000000c (INIT) 0x6c0
0x000000000000000d (FINI) 0x9a4
0x0000000000000019 (INIT_ARRAY) 0x200db0
0x000000000000001b (INIT_ARRAYSZ) 8 (bytes)
0x000000000000001a (FINI_ARRAY) 0x200db8
0x000000000000001c (FINI_ARRAYSZ) 8 (bytes)
0x000000006ffffef5 (GNU_HASH) 0x1f0
0x0000000000000005 (STRTAB) 0x3e8
0x0000000000000006 (SYMTAB) 0x238
0x000000000000000a (STRSZ) 317 (bytes)
0x000000000000000b (SYMENT) 24 (bytes)
0x0000000000000003 (PLTGOT) 0x201000
0x0000000000000002 (PLTRELSZ) 48 (bytes)
0x0000000000000014 (PLTREL) RELA
0x0000000000000017 (JMPREL) 0x690
0x0000000000000007 (RELA) 0x570
0x0000000000000008 (RELASZ) 288 (bytes)
0x0000000000000009 (RELAENT) 24 (bytes)
0x000000006ffffffe (VERNEED) 0x550
0x000000006fffffff (VERNEEDNUM) 1
0x000000006ffffff0 (VERSYM) 0x526
0x000000006ffffff9 (RELACOUNT) 3
0x0000000000000000 (NULL) 0x0

重定位节 ‘.rela.dyn’ 位于偏移量 0x570 含有 12 个条目:
偏移量 信息 类型 符号值 符号名称 + 加数
000000200db0 000000000008 R_X86_64_RELATIVE 7f0
000000200db8 000000000008 R_X86_64_RELATIVE 7b0
000000201028 000000000008 R_X86_64_RELATIVE 201028
000000200fb8 000100000006 R_X86_64_GLOB_DAT 0000000000000000 cxa_finalize@GLIBC_2.2.5 + 0
000000200fc0 000200000006 R_X86_64_GLOB_DAT 0000000000000000 g_static_lib_data + 0
000000200fc8 000300000006 R_X86_64_GLOB_DAT 0000000000000000 g_static_lib_bss + 0
000000200fd0 000400000006 R_X86_64_GLOB_DAT 0000000000000000 _Jv_RegisterClasses + 0
000000200fd8 001100000006 R_X86_64_GLOB_DAT 0000000000201030 g_static_so_data + 0
000000200fe0 000d00000006 R_X86_64_GLOB_DAT 0000000000201048 g_static_so_bss + 0
000000200fe8 000500000006 R_X86_64_GLOB_DAT 0000000000000000 _ITM_deregisterTMClone + 0
000000200ff0 000700000006 R_X86_64_GLOB_DAT 0000000000000000 __gmon_start
+ 0
000000200ff8 000800000006 R_X86_64_GLOB_DAT 0000000000000000 _ITM_registerTMCloneTa + 0

重定位节 ‘.rela.plt’ 位于偏移量 0x690 含有 2 个条目:
偏移量 信息 类型 符号值 符号名称 + 加数
000000201018 001000000007 R_X86_64_JUMP_SLO 0000000000000820 _Z13so_child_funcii + 0
000000201020 000600000007 R_X86_64_JUMP_SLO 0000000000000000 _Z8lib_funcii + 0

The decoding of unwind sections for machine type Advanced Micro Devices X86-64 is not currently supported.

Symbol table ‘.dynsym’ contains 18 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000000000 0 FUNC WEAK DEFAULT UND cxa_finalize@GLIBC_2.2.5 (2)
2: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND g_static_lib_data
3: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND g_static_lib_bss
4: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _Jv_RegisterClasses
5: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _ITM_deregisterTMCloneTab
6: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND _Z8lib_funcii
7: 0000000000000000 0 NOTYPE WEAK DEFAULT UND __gmon_start

8: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _ITM_registerTMCloneTable
9: 0000000000201040 0 NOTYPE GLOBAL DEFAULT 22 _edata
10: 0000000000201050 0 NOTYPE GLOBAL DEFAULT 23 _end
11: 00000000000006c0 0 FUNC GLOBAL DEFAULT 9 _init
12: 0000000000201040 0 NOTYPE GLOBAL DEFAULT 23 __bss_start
13: 0000000000201048 8 OBJECT GLOBAL DEFAULT 23 g_static_so_bss
14: 0000000000000898 266 FUNC GLOBAL DEFAULT 12 _Z7so_funcii
15: 00000000000009a4 0 FUNC GLOBAL DEFAULT 13 _fini
16: 0000000000000820 80 FUNC GLOBAL DEFAULT 12 _Z13so_child_funcii
17: 0000000000201030 8 OBJECT GLOBAL DEFAULT 22 g_static_so_data

Symbol table ‘.symtab’ contains 63 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 00000000000001c8 0 SECTION LOCAL DEFAULT 1
2: 00000000000001f0 0 SECTION LOCAL DEFAULT 2
3: 0000000000000238 0 SECTION LOCAL DEFAULT 3
4: 00000000000003e8 0 SECTION LOCAL DEFAULT 4
5: 0000000000000526 0 SECTION LOCAL DEFAULT 5
6: 0000000000000550 0 SECTION LOCAL DEFAULT 6
7: 0000000000000570 0 SECTION LOCAL DEFAULT 7
8: 0000000000000690 0 SECTION LOCAL DEFAULT 8
9: 00000000000006c0 0 SECTION LOCAL DEFAULT 9
10: 00000000000006e0 0 SECTION LOCAL DEFAULT 10
11: 0000000000000710 0 SECTION LOCAL DEFAULT 11
12: 0000000000000720 0 SECTION LOCAL DEFAULT 12
13: 00000000000009a4 0 SECTION LOCAL DEFAULT 13
14: 00000000000009b0 0 SECTION LOCAL DEFAULT 14
15: 00000000000009e8 0 SECTION LOCAL DEFAULT 15
16: 0000000000200db0 0 SECTION LOCAL DEFAULT 16
17: 0000000000200db8 0 SECTION LOCAL DEFAULT 17
18: 0000000000200dc0 0 SECTION LOCAL DEFAULT 18
19: 0000000000200dc8 0 SECTION LOCAL DEFAULT 19
20: 0000000000200fb8 0 SECTION LOCAL DEFAULT 20
21: 0000000000201000 0 SECTION LOCAL DEFAULT 21
22: 0000000000201028 0 SECTION LOCAL DEFAULT 22
23: 0000000000201040 0 SECTION LOCAL DEFAULT 23
24: 0000000000000000 0 SECTION LOCAL DEFAULT 24
25: 0000000000000000 0 FILE LOCAL DEFAULT ABS crtstuff.c
26: 0000000000200dc0 0 OBJECT LOCAL DEFAULT 18 JCR_LIST
27: 0000000000000720 0 FUNC LOCAL DEFAULT 12 deregister_tm_clones
28: 0000000000000760 0 FUNC LOCAL DEFAULT 12 register_tm_clones
29: 00000000000007b0 0 FUNC LOCAL DEFAULT 12 do_global_dtors_aux
30: 0000000000201040 1 OBJECT LOCAL DEFAULT 23 completed.6972
31: 0000000000200db8 0 OBJECT LOCAL DEFAULT 17 _do_global_dtors_aux_fin
32: 00000000000007f0 0 FUNC LOCAL DEFAULT 12 frame_dummy
33: 0000000000200db0 0 OBJECT LOCAL DEFAULT 16 __frame_dummy_init_array

34: 0000000000000000 0 FILE LOCAL DEFAULT ABS so.cpp
35: 0000000000201038 8 OBJECT LOCAL DEFAULT 22 _ZL15g_local_so_data
36: 0000000000000870 40 FUNC LOCAL DEFAULT 12 _ZL13so_local_funcv
37: 0000000000000000 0 FILE LOCAL DEFAULT ABS crtstuff.c
38: 0000000000000aa8 0 OBJECT LOCAL DEFAULT 15 __FRAME_END

39: 0000000000200dc0 0 OBJECT LOCAL DEFAULT 18 JCR_END
40: 0000000000000000 0 FILE LOCAL DEFAULT ABS
41: 00000000000009b0 0 NOTYPE LOCAL DEFAULT 14 GNU_EH_FRAME_HDR
42: 0000000000201028 0 OBJECT LOCAL DEFAULT 22 __dso_handle
43: 0000000000200dc8 0 OBJECT LOCAL DEFAULT 19 _DYNAMIC
44: 0000000000201040 0 OBJECT LOCAL DEFAULT 22 __TMC_END

45: 0000000000201000 0 OBJECT LOCAL DEFAULT 21 GLOBAL_OFFSET_TABLE
46: 0000000000201040 0 NOTYPE GLOBAL DEFAULT 22 edata
47: 0000000000000000 0 FUNC WEAK DEFAULT UND _cxa_finalize@@GLIBC_2.2
48: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND g_static_lib_data
49: 00000000000009a4 0 FUNC GLOBAL DEFAULT 13 _fini
50: 0000000000000820 80 FUNC GLOBAL DEFAULT 12 _Z13so_child_funcii
51: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND g_static_lib_bss
52: 00000000000006c0 0 FUNC GLOBAL DEFAULT 9 _init
53: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _Jv_RegisterClasses
54: 0000000000201030 8 OBJECT GLOBAL DEFAULT 22 g_static_so_data
55: 0000000000201050 0 NOTYPE GLOBAL DEFAULT 23 _end
56: 0000000000201040 0 NOTYPE GLOBAL DEFAULT 23 __bss_start
57: 0000000000201048 8 OBJECT GLOBAL DEFAULT 23 g_static_so_bss
58: 0000000000000898 266 FUNC GLOBAL DEFAULT 12 _Z7so_funcii
59: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _ITM_deregisterTMCloneTab
60: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND _Z8lib_funcii
61: 0000000000000000 0 NOTYPE WEAK DEFAULT UND __gmon_start

62: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _ITM_registerTMCloneTable

Histogram for `.gnu.hash’ bucket list length (total of 3 buckets):
Length Number % of total Coverage
0 0 ( 0.0%)
1 0 ( 0.0%) 0.0%
2 1 ( 33.3%) 22.2%
3 1 ( 33.3%) 55.6%
4 1 ( 33.3%) 100.0%

Version symbols section ‘.gnu.version’ contains 18 entries:
地址:0000000000000526 Offset: 0x000526 Link: 3 (.dynsym)
000: 0 (本地) 2 (GLIBC_2.2.5) 0 (本地) 0 (本地)
004: 0 (本地) 0 (本地) 0 (本地) 0 (本地)
008: 0 (本地) 1 (全局) 1 (全局) 1 (全局)
00c: 1 (全局) 1 (全局) 1 (全局) 1 (全局)
010: 1 (全局) 1 (全局)

Version needs section ‘.gnu.version_r’ contains 1 entries:
地址:0x0000000000000550 Offset: 0x000550 Link: 4 (.dynstr)
000000: 版本: 1 文件:libc.so.6 计数:1
0x0010:名称:GLIBC_2.2.5 标志:无 版本:2

Displaying notes found in: .note.gnu.build-id
所有者 Data size Description
GNU 0x00000014 NT_GNU_BUILD_ID (unique build ID bitstring)
Build ID: 09ce242e3867431b496a7f5928e9817fa91d242a

1
2
3


##### 代码节

so.so: 文件格式 elf64-x86-64

Disassembly of section .init:

00000000000006c0 <init>:
6c0: 48 83 ec 08 sub $0x8,%rsp
6c4: 48 8b 05 25 09 20 00 mov 0x200925(%rip),%rax # 200ff0 <_gmon_start
>
6cb: 48 85 c0 test %rax,%rax
6ce: 74 02 je 6d2 <_init+0x12>
6d0: ff d0 callq *%rax
6d2: 48 83 c4 08 add $0x8,%rsp
6d6: c3 retq

Disassembly of section .plt:

00000000000006e0 <.plt>:
6e0: ff 35 22 09 20 00 pushq 0x200922(%rip) # 201008 <GLOBAL_OFFSET_TABLE+0x8>
6e6: ff 25 24 09 20 00 jmpq *0x200924(%rip) # 201010 <GLOBAL_OFFSET_TABLE+0x10>
6ec: 0f 1f 40 00 nopl 0x0(%rax)

00000000000006f0 <_Z13so_child_funcii@plt>:
6f0: ff 25 22 09 20 00 jmpq *0x200922(%rip) # 201018 <_Z13so_child_funcii@@Base+0x2007f8>
6f6: 68 00 00 00 00 pushq $0x0
6fb: e9 e0 ff ff ff jmpq 6e0 <.plt>

0000000000000700 <_Z8lib_funcii@plt>:
700: ff 25 1a 09 20 00 jmpq *0x20091a(%rip) # 201020 <_Z8lib_funcii>
706: 68 01 00 00 00 pushq $0x1
70b: e9 d0 ff ff ff jmpq 6e0 <.plt>

Disassembly of section .plt.got:

0000000000000710 <.plt.got>:
710: ff 25 a2 08 20 00 jmpq *0x2008a2(%rip) # 200fb8 <__cxa_finalize@GLIBC_2.2.5>
716: 66 90 xchg %ax,%ax

Disassembly of section .text:

0000000000000720 :
720: 48 8d 3d 19 09 20 00 lea 0x200919(%rip),%rdi # 201040 <_edata>
727: 48 8d 05 19 09 20 00 lea 0x200919(%rip),%rax # 201047 <_edata+0x7>
72e: 55 push %rbp
72f: 48 29 f8 sub %rdi,%rax
732: 48 89 e5 mov %rsp,%rbp
735: 48 83 f8 0e cmp $0xe,%rax
739: 76 15 jbe 750 <deregister_tm_clones+0x30>
73b: 48 8b 05 a6 08 20 00 mov 0x2008a6(%rip),%rax # 200fe8 <_ITM_deregisterTMCloneTable>
742: 48 85 c0 test %rax,%rax
745: 74 09 je 750 <deregister_tm_clones+0x30>
747: 5d pop %rbp
748: ff e0 jmpq *%rax
74a: 66 0f 1f 44 00 00 nopw 0x0(%rax,%rax,1)
750: 5d pop %rbp
751: c3 retq
752: 0f 1f 40 00 nopl 0x0(%rax)
756: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1)
75d: 00 00 00

0000000000000760 :
760: 48 8d 3d d9 08 20 00 lea 0x2008d9(%rip),%rdi # 201040 <_edata>
767: 48 8d 35 d2 08 20 00 lea 0x2008d2(%rip),%rsi # 201040 <_edata>
76e: 55 push %rbp
76f: 48 29 fe sub %rdi,%rsi
772: 48 89 e5 mov %rsp,%rbp
775: 48 c1 fe 03 sar $0x3,%rsi
779: 48 89 f0 mov %rsi,%rax
77c: 48 c1 e8 3f shr $0x3f,%rax
780: 48 01 c6 add %rax,%rsi
783: 48 d1 fe sar %rsi
786: 74 18 je 7a0 <register_tm_clones+0x40>
788: 48 8b 05 69 08 20 00 mov 0x200869(%rip),%rax # 200ff8 <_ITM_registerTMCloneTable>
78f: 48 85 c0 test %rax,%rax
792: 74 0c je 7a0 <register_tm_clones+0x40>
794: 5d pop %rbp
795: ff e0 jmpq *%rax
797: 66 0f 1f 84 00 00 00 nopw 0x0(%rax,%rax,1)
79e: 00 00
7a0: 5d pop %rbp
7a1: c3 retq
7a2: 0f 1f 40 00 nopl 0x0(%rax)
7a6: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1)
7ad: 00 00 00

00000000000007b0 <do_global_dtors_aux>:
7b0: 80 3d 89 08 20 00 00 cmpb $0x0,0x200889(%rip) # 201040 <_edata>
7b7: 75 27 jne 7e0 <
do_global_dtors_aux+0x30>
7b9: 48 83 3d f7 07 20 00 cmpq $0x0,0x2007f7(%rip) # 200fb8 <cxa_finalize@GLIBC_2.2.5>
7c0: 00
7c1: 55 push %rbp
7c2: 48 89 e5 mov %rsp,%rbp
7c5: 74 0c je 7d3 <
do_global_dtors_aux+0x23>
7c7: 48 8b 3d 5a 08 20 00 mov 0x20085a(%rip),%rdi # 201028 <__dso_handle>
7ce: e8 3d ff ff ff callq 710 <.plt.got>
7d3: e8 48 ff ff ff callq 720
7d8: 5d pop %rbp
7d9: c6 05 60 08 20 00 01 movb $0x1,0x200860(%rip) # 201040 <_edata>
7e0: f3 c3 repz retq
7e2: 0f 1f 40 00 nopl 0x0(%rax)
7e6: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1)
7ed: 00 00 00

00000000000007f0 :
7f0: 48 8d 3d c9 05 20 00 lea 0x2005c9(%rip),%rdi # 200dc0 <JCR_END>
7f7: 48 83 3f 00 cmpq $0x0,(%rdi)
7fb: 75 0b jne 808 <frame_dummy+0x18>
7fd: e9 5e ff ff ff jmpq 760
802: 66 0f 1f 44 00 00 nopw 0x0(%rax,%rax,1)
808: 48 8b 05 c1 07 20 00 mov 0x2007c1(%rip),%rax # 200fd0 <_Jv_RegisterClasses>
80f: 48 85 c0 test %rax,%rax
812: 74 e9 je 7fd <frame_dummy+0xd>
814: 55 push %rbp
815: 48 89 e5 mov %rsp,%rbp
818: ff d0 callq *%rax
81a: 5d pop %rbp
81b: e9 40 ff ff ff jmpq 760

0000000000000820 <_Z13so_child_funcii>:
820: 55 push %rbp
821: 48 89 e5 mov %rsp,%rbp
824: 48 8d 05 f9 ff ff ff lea -0x7(%rip),%rax # 824 <_Z13so_child_funcii+0x4>
82b: 49 bb dc 07 20 00 00 movabs $0x2007dc,%r11
832: 00 00 00
835: 4c 01 d8 add %r11,%rax
838: 89 7d fc mov %edi,-0x4(%rbp)
83b: 89 75 f8 mov %esi,-0x8(%rbp)
83e: 8b 4d fc mov -0x4(%rbp),%ecx
841: 8b 55 f8 mov -0x8(%rbp),%edx
844: 01 ca add %ecx,%edx
846: 89 d1 mov %edx,%ecx
848: 48 ba e0 ff ff ff ff movabs $0xffffffffffffffe0,%rdx
84f: ff ff ff
852: 48 8b 14 10 mov (%rax,%rdx,1),%rdx
856: 48 8b 12 mov (%rdx),%rdx
859: 01 d1 add %edx,%ecx
85b: 48 ba d8 ff ff ff ff movabs $0xffffffffffffffd8,%rdx
862: ff ff ff
865: 48 8b 04 10 mov (%rax,%rdx,1),%rax
869: 48 8b 00 mov (%rax),%rax
86c: 01 c8 add %ecx,%eax
86e: 5d pop %rbp
86f: c3 retq

0000000000000870 <_ZL13so_local_funcv>:
870: 55 push %rbp
871: 48 89 e5 mov %rsp,%rbp
874: 48 8d 05 f9 ff ff ff lea -0x7(%rip),%rax # 874 <_ZL13so_local_funcv+0x4>
87b: 49 bb 8c 07 20 00 00 movabs $0x20078c,%r11
882: 00 00 00
885: 4c 01 d8 add %r11,%rax
888: 48 ba 38 00 00 00 00 movabs $0x38,%rdx
88f: 00 00 00
892: 48 8b 04 10 mov (%rax,%rdx,1),%rax
896: 5d pop %rbp
897: c3 retq

0000000000000898 <_Z7so_funcii>:
898: 55 push %rbp
899: 48 89 e5 mov %rsp,%rbp
89c: 41 57 push %r15
89e: 53 push %rbx
89f: 48 83 ec 20 sub $0x20,%rsp
8a3: 48 8d 1d f9 ff ff ff lea -0x7(%rip),%rbx # 8a3 <_Z7so_funcii+0xb>
8aa: 49 bb 5d 07 20 00 00 movabs $0x20075d,%r11
8b1: 00 00 00
8b4: 4c 01 db add %r11,%rbx
8b7: 89 7d dc mov %edi,-0x24(%rbp)
8ba: 89 75 d8 mov %esi,-0x28(%rbp)
8bd: 48 b8 e0 ff ff ff ff movabs $0xffffffffffffffe0,%rax
8c4: ff ff ff
8c7: 48 8b 04 03 mov (%rbx,%rax,1),%rax
8cb: 48 8b 00 mov (%rax),%rax
8ce: 48 8d 50 01 lea 0x1(%rax),%rdx
8d2: 48 b8 e0 ff ff ff ff movabs $0xffffffffffffffe0,%rax
8d9: ff ff ff
8dc: 48 8b 04 03 mov (%rbx,%rax,1),%rax
8e0: 48 89 10 mov %rdx,(%rax)
8e3: 48 b8 d8 ff ff ff ff movabs $0xffffffffffffffd8,%rax
8ea: ff ff ff
8ed: 48 8b 04 03 mov (%rbx,%rax,1),%rax
8f1: 48 8b 00 mov (%rax),%rax
8f4: 48 8d 50 01 lea 0x1(%rax),%rdx
8f8: 48 b8 d8 ff ff ff ff movabs $0xffffffffffffffd8,%rax
8ff: ff ff ff
902: 48 8b 04 03 mov (%rbx,%rax,1),%rax
906: 48 89 10 mov %rdx,(%rax)
909: 48 b8 d8 ff ff ff ff movabs $0xffffffffffffffd8,%rax
910: ff ff ff
913: 48 8b 04 03 mov (%rbx,%rax,1),%rax
917: 48 8b 00 mov (%rax),%rax
91a: 89 c2 mov %eax,%edx
91c: 48 b8 e0 ff ff ff ff movabs $0xffffffffffffffe0,%rax
923: ff ff ff
926: 48 8b 04 03 mov (%rbx,%rax,1),%rax
92a: 48 8b 00 mov (%rax),%rax
92d: 89 d6 mov %edx,%esi
92f: 89 c7 mov %eax,%edi
931: 49 89 df mov %rbx,%r15
934: 48 b8 00 f7 df ff ff movabs $0xffffffffffdff700,%rax
93b: ff ff ff
93e: 48 01 d8 add %rbx,%rax
941: ff d0 callq *%rax
943: 89 45 ec mov %eax,-0x14(%rbp)
946: 48 b8 c8 ff ff ff ff movabs $0xffffffffffffffc8,%rax
94d: ff ff ff
950: 48 8b 04 03 mov (%rbx,%rax,1),%rax
954: 48 8b 00 mov (%rax),%rax
957: 89 c2 mov %eax,%edx
959: 48 b8 c0 ff ff ff ff movabs $0xffffffffffffffc0,%rax
960: ff ff ff
963: 48 8b 04 03 mov (%rbx,%rax,1),%rax
967: 48 8b 00 mov (%rax),%rax
96a: 89 d6 mov %edx,%esi
96c: 89 c7 mov %eax,%edi
96e: 49 89 df mov %rbx,%r15
971: 48 b8 f0 f6 df ff ff movabs $0xffffffffffdff6f0,%rax
978: ff ff ff
97b: 48 01 d8 add %rbx,%rax
97e: ff d0 callq *%rax
980: 01 45 ec add %eax,-0x14(%rbp)
983: 48 b8 70 f8 df ff ff movabs $0xffffffffffdff870,%rax
98a: ff ff ff
98d: 48 8d 04 03 lea (%rbx,%rax,1),%rax
991: ff d0 callq *%rax
993: 01 45 ec add %eax,-0x14(%rbp)
996: 8b 45 ec mov -0x14(%rbp),%eax
999: 48 83 c4 20 add $0x20,%rsp
99d: 5b pop %rbx
99e: 41 5f pop %r15
9a0: 5d pop %rbp
9a1: c3 retq

Disassembly of section .fini:

00000000000009a4 <_fini>:
9a4: 48 83 ec 08 sub $0x8,%rsp
9a8: 48 83 c4 08 add $0x8,%rsp
9ac: c3 retq


### 动态库装载过程  
[linux kernel 源码](https://elixir.bootlin.com/linux/latest/source)  

#### ELF的辅助向量 AUXV   
main函数的第三个参数  char* envp[]    

LD_SHOW_AUXV=1 whoami 

#### load_elf_binary函数  
* 填充并且检查目标程序ELF头部
* load_elf_phdrs加载目标程序的程序头表
* 如果需要动态链接, 则寻找和处理解释器段
* 检查并读取解释器的程序表头
* 装入目标程序的段segment
* create_elf_tables填写目标文件的参数环境变量等必要信息
* start_kernel宏准备进入新的程序入口









</font>