一、目标文件的格式
目标文件是源代码编译后但为进行链接的那些中间文件(Window 的 .obj 和 Linux 下的 .o)
动态链接库(DLL, Dynamic Linking Library), Window 是 .dll, Linux 是 .so
静态链接库(Static Linking Library), Window 是 .lib 和 Linux 是 .a
可执行文件格式是 ELF
二、目标文件的文件类型
命令 file 查看文件的类型格式
例如
1 | > file libdycloudmedia.so |
三、目标文件的内容
3.1 可执行文件的内容
程序源代码编译后的机器指令经常被放在代码段(Code Section), 代码段常见的字有 “.code” 或 ”.text”
全局变量和局部变量数据经常放在数据段(Data Section)
总体来说,源程序代码被编译以后主要分成两种段,程序指令和程序数据。代码段属于程序指令,而数据段和.bss 属于程序数据
将数据和指令分段的好处:
- 程序被装载后,数据和指令分别被映射到两个虚拟区域。数据区对于进程是可读写,指令区对于进程是只读,这两个两个区域的权限分别设置为可读写和只读。这样防止程序指令被破坏
- 充分利用 CPU 的缓存,提供命中率
- 当系统中存在该程序的副本时,可以共享指令,节约内存。
查看 ELF 各段的基本信息
objdump -h SimpleSection.o
-h 将 ELF 文件的各个段的基本信息打印出来
查看ELF文件的代码段、数据段、和 BSS 段的长度
size SimpleSection.o
3.2 文件头 HEADER
ELF 目标文件最前面的是 ELF 文件头,它包含描述整个文件的基本属性,例如 ELF 文件版本、目标机器型号、程序入口等
查看
$readelf -h SimpleSection.o // linex 用
$otool -h SimpleSection.o // mac 使用
3.3 代码段 .text
使用命令下面命令查看
objdump -s -d SimpleSection.o
-s 参数表示将所有段的内容以十六进制的方式打印出来
-d 参数将所有包含指令的段反汇编
3.3 数据段和只读数据段 .data
.data 段保存已经初始化了的全局静态变量和局部静态变量
.rodata 段存放只读数据,(mac 里面是 cstring )
1 | Contents of section __data: |
3.4 BSS 段
.bss 段存放未初始化的全局变量和局部静态变量
1 | Contents of section __bss: |
四、ELF 文件结构描述
链接过程的本质就是要把多个不同的目标文件之间相互”粘“到一起,或者说像玩具积木一样,可以拼成一个整体
符号是链接过程的粘合剂
4.1 重新定位表 .rel.text
链接器在处理目标文件时,必须要对目标文件中某些部位进行重定位
4.2 符号
链接过程的本质就是把不同的目标文件相互“粘”到一起,拼成一个整体。符号就是链接中的粘合剂,整个链接过程正是基于符号才能正确完成的。
查看符号表
$ nm SimpleSection.o
ELF 符号表结构
1 | typedef struct { |
五、其他
示例代码
1 |
|
Mac 使用 readelf
Mac 上没有 ‘readelf 命令’ 可以使用 ’greadelf‘ 和 ’gobjdump‘
安装步骤:
- 使用命令
brew update && brew install binutils
2.路径添加到 ’~/.bash_profile‘ 文件中
1 | # binutils |
Mac otool替代readelf命令
$otool -h
1 | rg] [--version] <object file> ... |