读书笔记-程序员的自我修养(三)

目标文件(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_EhdrElf64_Ehdr

        • 段表(Section Table):描述包含的所有段信息,比如每个段名、段的长度、在文件中的偏移、读写权限及段的其他属性。每个段的结构是由 Elf32_Shdr 的结构体组成,对于编译器和链接器来说,主要决定段的属性是类型(sh_type)(12种)和标志位(sh_flags)(读写可分配),如果段的类型是与连接相关的,那么段的链接信息就是控制如此的(sh_linksh_info

          • 重定位表sh_type = SHT_RELA[.rel]:重定位代码段和数据段中那些对绝对地址的引用的位置

          • 字符串表sh_type = SHT_STRTAB[.symtab]:ELF文件中用到的很多字符串,比如段名和变量名等,比较聪明的做法是,具体字符串存放在字符串表中,段中直接引用 偏移量 即可

如需转载,请注明出处