预处理 编译器 汇编器 链接 符号解析 重定位 下条指令地址 转移目标地址 可执行文件加载
程序的执行:周而复始地执行一条条指令
指令周期:CPU取出并执行一条指令的时间
jmp *0x8049590 0x8049590中的地址 08048352
延迟绑定 延迟重定位
延迟绑定 lazy binding 减少指令条数
procedure linkage table 过程链接表
如果静态链接,1条mov即可
寄存器溢出
全局偏移表 GOT global offset table
动态链接器接口 dlopen dlsymh dlclose
.interp段
myproc 磁盘
区别.a .so
静态链接器 ld
动态链接器 ld-linux.so
1)共享代码的位置可以是不确定的
2)即使共享代码的长度发生变化,也不会影响调用它的程序
位置无关代码 position independent code PIC
gcc -c a.c b.c
gcc -shared -fPIC -o mylib.o a.o b.o
load-time linking
run-time linking
静态库 动态库
动态链接库 dynamic link libraries .dll
静态共享对象 dynamic shared objects .so
在磁盘和内存中都只有一个备份
entry point address 入口地址,不是0x8048000是ELF起始位置
fork
在当前进程上下文中加载并运行一个新程序
可执行文件加载:通过调用execve系统调用函数来调用加载器
栈地址 高位向低位增城
堆 低 高
00 00 00 00 重定位 合并后,地址
bufp0 重定位前 0 0 0 0
后 20 96 04 08 (8049620)
28 29 3a 3b
4KB 0x08048000 0x08049000
R_386_32 绝对地址类型
绝对地址重定位
R_386_PC32 PC相对地址方式
重定位计算公式 ADDR(r_sym)-((ADDR(.text)+r_offset)-init)
转移目标地址=当前PC+偏移地址
0x12B
6: e8 fc ff ff ff
6 7 8 9 a
main 字节数 0x12B
小端 01 00 00 00 00 02 00 00 00
int buf[2]={1,2};
.rel.text 重定位条目
r_offset=0x7 第7字节开始
r_sym=10 绑定的符号是第10个符号
r_type=R_386_PC32 类型为
PC相对地址重定位
and $0xffffff0,%esp 使栈顶地址为16的倍数
显示重定位条目
readelf -r a.o
符号解析后,进行重定位
1、合并相同的节
2、对集合D中的定义符号进行重定位
3、对引用符号进行重定位
互相调用
链接器对外部引用的解析算法
gcc -L libtest.o -lmine
命令行顺序
链接顺序:应该按照调用顺序来指定
链接器符号解析过程
静态库 .a archive files 存档文件
创建
归档程序ar
ar rcs libc.a a.o b.o
允许增量更新 ar rs libc.a z.o
ar -t libc.a | sort 查看
gcc -c a.c b.c
ar rcs libc.a a.o b.o
尽量使用本地变量static
全局变量要赋初值,使其成为强符号,易查出可能的链接错误
两个重复定义的变量具有不同类型是,出现的问题
浮点计算
3FF0 0000
3FFF FFFF =2^30-1
000F FFFF = 2^20-1
多重定义符号的解析举例
链接器对符号的解析规则
gcc -fno-common
全局符号的强弱属性
强符号 弱符号
符号解析:symbol resolution 符号绑定
函数名: 其代码所在区
变量名:其所占的静态数据区
符号解析:将每个模块中引用符号与某个目标模块中的定义符号建立关联。
int but[1]={1,2}; size 4*2B=size 8
st_size 符号对应目标的字节数,比如:int 4B,short 2B,函数所占字节数
字符串存放在.strtab节
符号对应字符串,在.strtab节中的偏移量:4字节
global symbols 全局符号
external symbols 外部符号
local symbols 局部符号
链接符号的类型
符号定义
符号引用
symbol resolution 符号解析
定义的符号 引用的符号
将符号的引用存放在重定位节 .rel.text .rel.data
align 0x1000 2^12=4kB 按4kB对齐装入
虚拟空间中的地址
2's complement 2的补码
_init 函数 初始化工作
可执行目标文件
e_entry 程序执行时第一条指令地址
在可重定位文件中为0
segment header table 程序头表 段头表
section header table 节头表
440=
16^2+16*11+8
=1b8
ELF 52字节头信息
readelf -l a.o 程序头表信息
readelf -h a.o 头信息
readelf -S a.o 节头表信息
REL relocatable 可重定位
45 E 4c L 46 F
ELF Header:
Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
Class: ELF64
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: DYN (Position-Independent Executable file)
Machine: Advanced Micro Devices X86-64
Version: 0x1
Entry point address: 0x1060
Start of program headers: 64 (bytes into file)
Start of section headers: 14752 (bytes into file)
Flags: 0x0
Size of this header: 64 (bytes)
Size of program headers: 56 (bytes)
Number of program headers: 13
Size of section headers: 64 (bytes)
Number of section headers: 37
Section header string table index: 36
52B ELF
2B Elf32_half
4B Elf32_Word Elf32_Addr Elf32_Off
16B EI_NIDENT
ELF头 节头表 section header table
.symtab 存放函数名和全局变量(符号表)信息
bss节不占磁盘空间 block started by symbol
.rodata 只读数据,如 printf格式串、switch、调转表
ELF-执行视图:可重定位目标文件
ELF-链接视图:可重定位目标文件
.data 已初始化的全局变量和局部静态变量
.bss 未初始化的全局变量和局部静态变量
ELF excutable aand linkable format 可执行可链接
PE portable excutable 可移植可执行
目标文件 object code
目标文件 object file
共享目标文件:特殊的可重定位目标文件,能在装入或运行时被装入到内存并被链接
可执行目标文件:包含的代码和数据可以直接被复制到内存并执行
可执行文件存储映像
gcc -O2 -g -o a main.c
O2 2级优化
-g 生成调试信息
只读代码段
读写代码段
合并到虚拟空间
0x08048000
rodata read only
链接本质:合并相同节 section
局部变量分配在栈中,不会在过程(函数)外被引用,因此不是符号定义。
1符号解析: 确定符号引用关系
2合并.o文件
3确定每个符号的地址
4在指令中填入新地址
---》代码+数据
链接器由来
子程序其实地址、变量起始地址:符号的定义
调用子程序和使用变量:符号的引用
链接时在符号引用处填入定义的地址
链接:早于高级语言
纸袋 卡片
链接: 多个可重定位文件
静态、动态链接
编译器 汇编器
可重定位文件
预处理程序 cpp
编译器 cc1
汇编程序 as
执行:
Hello, OS World
ld: m1.o: in function `_start':
(.text+0x3): undefined reference to `SYS_write'
ld: (.text+0x21): undefined reference to `SYS_exit'
-bash: ./m1.out: No such file or directory