目标文件(ELF) 详解
目标文件 里有什么?
目标文件的格式,从 结构 上讲,它是已经 编译后的可执行文件,只是还 没有经过链接 的过程,其中可能有些符号或有些地址还没有被 调整,本身就是按照可执行文件格式存储的
普及 : 可执行文件格式(Executable) 主要是 Windows 下的 PE(Portable Executable) 和 Linux 下的 ELF(Executable Linkable Format),都隶属于 COFF(Common file format) 的变种
普及 : 动态链接库(DLL,Dynamic Linking Library) 即(Windows 上的 .dll 和 Linux 上 .so),静态链接库(Static Linking Library) 即(Windows 上的 .lib 和 Linux 上的 .a)
普及 : ELF 格式的文件归为四类:可重定位文件(Relocatable File)、可执行文件(Executable File)、共享目标文件(Shared Object File) 、核心转储文件(Coredump File),可以用
file
命令查看概述 ELF 剖析 目标文件是什么样的 ?
包含的内容: 机器指令代码、数据、符号表、调试信息、字符串等
按照信息的不同属性,存储的单位:节(Section) 和 段(Segment)
结构详解:使用 binutils 的工具 objdump 可以查看 .o 文件内部的结构
工具命令
查看主要段的基本信息:objdump -h SimpleSection.o
查看各个段的信息:readelf -S SimpleSection.o
查看ELF文件的长度:size SimpleSection.o
查看段的内容:objdump -s -d SimpleSection.o
查看ELF文件头:readelf -h SimpleSection.o
逻辑划分
代码段[ .text ]:机器指令代码(一般是执行语句)
数据段和只读数据段[ .data 和 .rodata ]:已初始化 的全局变量和局部静态变量
BSS段 [ .bss ]: 未初始化 的全局变量和局部静态变量,只是预留位置而已,值得注意的是:即便初始化为 0,也会放到 bss 中,因为未初始化的都是 0
其他段:列举几个:.comment 存放编译器版本信息,.debug 存放调试信息,.dynamic 存放动态链接信息,.hash 存放哈希表,.symtab 存放符号表,.plt/.got 动态连接的跳转表和全局入口表 等等
自定义段:GCC提供了一个扩展机制,是的程序员可以制定变量所处的段:attribute((section(“name”))) int global = 42 ,global变量即会存放于 name 作为段名的段中
物理划分
文件头(File Header):描述文件 属性,其中定义了 ELF魔数(e_ident)、文件机器字节长度、数据存储方式、版本、运行平台(e_machine)、ABI版本、ELF重定位类型(e_type)、硬件平台、硬件平台版本、入口地址、程序头入口地址、段表的位置和长度(e_shoff)、段的数量 等,常定义于:/usr/include/elf.h 中,根据版本分为:Elf32_Ehdr 和 Elf64_Ehdr
段表(Section Table):描述包含的所有段信息,比如每个段名、段的长度、在文件中的偏移、读写权限及段的其他属性。每个段的结构是由 Elf32_Shdr 的结构体组成,对于编译器和链接器来说,主要决定段的属性是类型(sh_type)(12种)和标志位(sh_flags)(读写可分配),如果段的类型是与连接相关的,那么段的链接信息就是控制如此的(sh_link、sh_info)
重定位表(sh_type = SHT_RELA)[.rel]:重定位代码段和数据段中那些对绝对地址的引用的位置
字符串表(sh_type = SHT_STRTAB)[.symtab]:ELF文件中用到的很多字符串,比如段名和变量名等,比较聪明的做法是,具体字符串存放在字符串表中,段中直接引用 偏移量 即可