目录
基本编译链接流程
- 编译并输出汇编代码
- g++ -S lib.cpp -o lib.s
- 打包成ELF可重定位文件 ELF TYPE= ET_REL 即.o文件
- g++ -c lib.s -o lib.o
- 链接到动态库或者可执行文件
- g++ lib.o -o a.out
- g++ -shared lib.o -o a.out
静态链接过程概述
静态链接过程流程追踪和代码验证
测试源代码
1 | int g_static_bss = 0; |
生成汇编代码 (从这里开始会有两个分支代码 NON-PIC 和 PIC对照)
在这段代码中
g_static_bss
- 为全局的符号(给链接器看到)
- 被放在.bss字段(未初始化数据段, Block Started by Symbol)中
- 占用4个字节 类型是object 初始化为0
- 4字节对齐
g_static_data
- 为全局的符号(给链接器看到)
- 被放在.data字段(数据段)中
- 占用4个字节 类型是object 初始化为182
- 4字节对齐
_ZL13g_static_text
- 为全局的符号(给链接器看到)
- 被放在.rodata字段(只读数据段)中
- 占用4个字节 类型是object 初始化为1987
- 4字节对齐
_Z9main_funcii
- 为全局的符号(给链接器看到)
- 被放在.text字段(代码段)中
- 占用4个字节 类型是function
main
- 为全局的符号(给链接器看到)
- 被放在.text字段(代码段)中
- 占用4个字节 类型是function
GOTPCREL
- PC-REL是指的位置相对代码
- 这里是指的走GOT表的位置相对代码
在下面的对照中 对于全局符号的访问有如下区别
- 访问全局对象时 PIC 版本会先从相对当前代码位置的GOT表中读取全局对象的地址到RAX 然后再读取其内容
- 非PIC版本则直接用记录好的地址读取其内容
汇编代码 (相对位置版本)
1 | .file "test.cpp" |
汇编代码 (位置无关版本)
1 | .file "test.cpp" |
生成ELF的可重定位文件
- .rela.text 重定位section
- 包含了所有需要进行重定位的信息, 偏移量是相对于.text 类型则是注明了重定位的方式
.rela.eh_frame 重定位section
.symtab 符号表section
- Value 标记了符号所在的偏移地址
- SIZE 标记了代码或者变量占的大小
- Ndx 如果不在本编译单元 类型为NOTYPE Ndx为UND
- Bind 全局还是局部符号(是否链接器可见)
- rodata的符号为local是因为直接被编译到了代码中
- 例如g_static_text 1987 =>
add $0x7c3,%eax
- 例如g_static_text 1987 =>
- rodata的符号为local是因为直接被编译到了代码中
.rela.eh_frame Call Frame Information
- 提供了异常的Stack Unwind 支持
- 这张表提供了’给定一个PC值, 可以查到上一个stack frame位置’
- Stack Unwind 指从最內层函数呼叫堆栈开始,找到最外层
1
2
3
4* _Unwind_Backtrace()
* uw_frame_state_for()
* uw_update_context()
* uw_update_context_1()
- PC32 的PC是指的 program counter 在本文的汇编中对应寄存器的RIP
- PC32 在重定位类型中代表相对指令位置的重定位
- PLT 则代表使用 过程链接表 进行重定位 (动态定位)
- GOT 是全局偏移表
- PGOT 是私有全局偏移表
在这个过程中
无论是PIC的PLT调用还是PC调用, 对于call 指令 他的操作数都是0
无论是GOTPCREL还是PC 对全局对象符号的访问中 操作数也都是0
在重定位节中标记了这些需要在链接过程中重建的具体位置和内容
可重定向文件和汇编指令 (相对位置版本)
1 | 重定位节 '.rela.text' 位于偏移量 0x2c8 含有 4 个条目: |
可重定向文件和汇编指令 (位置无关版本)
1 | 重定位节 '.rela.text' 位于偏移量 0x300 含有 4 个条目: |
链接为可执行文件(或者共享库)
在链接为目标文件时, 会合并处理每个目标文件, 生成plt代码 确定GOT(PGOT)的相对位置等
在相对位置的两个版本中均可以看到对全局符号的访问均正确填充了相对位移
PIE版本的区别主要是PIE使用了相对位置 连ELF类型都变成了DYN
非PIE版本则使用了绝对位置
测试代码没有调用外部函数符号 所以在PIC版本的汇编指令中并没有看到PLT指令
可执行文件 (相对位置的非PIE(EXEC)版本)
1 | 重定位节 '.rela.dyn' 位于偏移量 0x388 含有 2 个条目: |
可执行文件 (相对位置的PIE(DYN)版本)
1 |
|
可执行文件 (位置无关的非PIE(EXEC)版本)
1 | Dynamic section at offset 0xe30 contains 23 entries: |
可执行文件 (位置无关的PIE(DYN)版本)
1 | 重定位节 '.rela.dyn' 位于偏移量 0x448 含有 9 个条目: |