ELF 64 格式详解

本篇介绍

本篇详细介绍下ELF 64的文件格式。

ELF文件分类

  • 可重定位文件(.o),包含代码和数据,但是代码和数据都没有指定绝对地址,需要链接其他目标文件来生成可执行文件或共享目标文件
  • 共享目标文件(.so),包含代码和数据,以供链接器使用
  • 可执行文件, 包含代码和数据,是可以执行运行的程序,代码和数据都有固定的地址

ELF文件内容

一个ELF文件需要包含以下部分:

  • elf文件头,必须出现在elf文件的开头
  • 节头表(Section header table), 重定位的文件(可重定位文件)必须包含,可加载的文件可选(共享目标文件,可执行文件)
  • 段头表(Program header table),可加载的文件必选,重定位文件可选
  • 段和节的实际内容,包括可加载的数据,符号表等

节头表和段头表其实分别是链接和加载的视图,结构大致如下:


image.png

ELF 64的数据类型定义如下:


image.png

ELF文件头格式

文件头格式如下:


image.png

可以找一个so,用 readelf -h 看看输出,结果可以完全对上:


image.png

对于MacBook M1 的设备可能没有readelf,objdump等命令,一个简单的方法是可以直接使用ndk中的命令,llvm-readelf, llvm-objdump等

接下来分别看下各个字段的含义:

e_ident

elf文件的标识,一共16个字节,各个字段的含义如下:


image.png
  • e_ident[EI_MAG0] ~ e_ident[EI_MAG3] 是用来标识ELF文件的魔数,0x7f, 'E','L','F'
  • e_ident[EI_CLASS] 用来标识对应的ELF文件类别,可取的值如下:


    image.png
  • e_ident[EI_DATA] 用来区分字节序,可取的值如下


    image.png
  • e_ident[EI_VERSION] 目标文件格式的版本,目前就是EV_CURRENT,也就是1
  • e_ident[EI_OSABI] 该文件的目标操作系统和ABI,可取的值如下


    image.png
  • e_ident[EI_ABIVERSION] 该文件的目标ABI版本,如果兼容System V ABI 第三版,该字段应该是0
  • e_type 该文件的类型,可取的值如下


    image.png
  • e_machine 标识目标架构
  • e_version 文件格式的版本
  • e_entry 程序入口的虚拟地址
  • e_phoff 程序段头表在该文件内的偏移,单位是字节
  • e_shoff 节头表在该文件内的偏移,单位是字节
  • e_flags 包含处理器特定的标记
  • e_ehsize ELF头的大小,单位是字节
  • e_phentsize 程序段头表项的大小,单位是字节
  • e_phnum 程序段头表项的数量
  • e_shentsize 节头表项的大小,单位是字节
  • e_shnum 节头表项的数量
  • e_shstrndx 节头表中包含节名字的字符串表索引。

ELF节

节包含了ELF文件中除了文件头,程序段头表,节头表之外的所有内容。
节的索引中有几项是特殊的,比如如下几个:


image.png

可以实际看一下节的内容,通过readelf -S 命令就可以看到:


image.png

再看下节头表中项结构的定义,可以和输出的格式对上:


image.png
  • sh_name 节头名字在字符串表中的偏移,单位是字节。举一个例子,上图中第一项的名字是".note.android.ident",看看是如何计算的。
    节头表的位置是1393984, 转成16进制 0xD4EBC0, 每项64字节,加上第0个保留项,那偏移就是0xD4EC00,具体偏移是0x0b


    image.png

字符串表的索引是24,那偏移就是0xD4F1C0,内容如下:


image.png

按照上述的结构定义,可以看到sh_offset 的偏移是0xD4EADC, 再加上字符串偏移 0x0B,位置就是0xD4EAE7


image.png

这样就字符串位置计算出来了。

  • sh_type 节的类型,可选的值如下:


    image.png
  • sh_flags 当前节的属性,可选的值如下:


    image.png
  • sh_addr 该节在内存中的虚拟地址,如果不加载到内存中,地址是0

  • sh_offset 该节在文件中的偏移,单位是字节

  • sh_size 当前节在文件中占用的空间,唯一的例外是SHT_NOBITS,不占用文件空间

  • sh_link 当前节关联的节索引,用途如下所示


    image.png
  • sh_info 当前节的其他信息,用途如下


    image.png
  • sh_addralign 对齐参考,需要是2的幂

  • sh_entsize 如果节中包含表,该字段表中每项的大小,单位是字节

用于程序代码和数据的节如下:


image.png

用于文件信息的节如下:


image.png

字符串表

字符串节表包含用于节名字和符号名字的字符串,内部的字符串表是包含C格式的字符串,对外的索引就是对应字符串的起始位置偏移,单位是字节。

符号表

符号表结构如下:


image.png
  • st_name 符号名字在符号字符串表中的偏移
  • st_info 符号的绑定属性和类型,高4比特是绑定属性,低4比特是符号类型,
    绑定属性定义如下:


    image.png

符号类型定义如下:


image.png
image.png
  • st_other 保留字段,保持是0就行
  • st_shndx 定义当前符号的节索引,如果是未定义的,字段值是SHN_UNDEF,对于绝对符号的,值是SHN_ABS,common符号的,值是SHN_COMMON
  • st_value 符号的地址,可能是绝对或相对的地址,对于可重定位的文件,值是定义该符号的节的相对偏移,对于可执行或可供行的文件,值是定义该符号的虚拟地址
  • st_size 该符号对应的值的存储空间大小,如果未知,字段值是0

可重定位表

ELF 文件有2种重定位格式,"Rel"和"Rela", 前者较短,记录相对于符号原始值的偏移,后者是记录相对于特定字段的偏移。结构定义如下:


image.png
  • r_offset 标识需要重定位的位置,对于可重定位文件,是从节开头到需要被重定位的存储位置的偏移量,对于可执行或共享库,是需要被重定位的存储位置的虚拟地址,单位都是字节
  • r_info 包含符号表索引和重定向类型,符号表索引用于标识当前项在对应符号表中的符号,重定向类型是处理机指定的。
#define ELF64_R_SYM(i)((i) >> 32)
#define ELF64_R_TYPE(i)((i) & 0xf f f f f f f f L)
#define ELF64_R_INFO(s, t)(((s) << 32) + ((t) & 0xf f f f f f f f L))
  • r_addend 计算重定向位置时候需要额外加的常数项

程序段头表

对于可执行和共享库,为了加载方便,用的视图是段,也就是内容一样,只是分类方式变化了。
可以先实际看下共享库的段表信息,readelf -l libtxffmpeg.so

image.png

可以看到,段是由节组成的,这是对于加载器,权限一样的,就可以合并到一块,方便内存的管理。
再看下段结构,可以和上图对得上:
image.png

  • p_type 段的类型,参考如下:


    image.png
image.png
  • p_flags 段属性,高8比特是处理器专用,接下来8比特是环境变量专用


    image.png
  • p_offset 当前段相对于文件的偏移,单位是字节

  • p_vaddr 当前段在内存中的虚拟地址

  • p_paddr 保留项,用于物理寻址的系统

  • p_filesz 当前段在文件中的大小,单位是字节

  • p_memsz 当前段在内存中的大小,单位是字节

  • p_align 段的对齐约束,需要是2的幂

Note 节

SHT_NOTE的节或PT_NOTE的段,被编译器或其他用于用于存放一些特殊的信息,而这些信息可以被特定的工具所用,格式如下:


image.png
  • namesz and name 记录用于该项所有者的名字长度和名字,name 包含一个C格式的字符串,并且按8字节对齐
  • descsz and desc 该项的描述符长度和描述符信息,描述符信息需要 8字节对齐
  • type 和该项所有者,信息解析者相关的一个值

动态段表

动态段表的实际内容如下:


image.png

结构定义如下:


image.png
  • d_tag 该项的类型,也会决定d_un的解析,具体取值如下:


    image.png
image.png
image.png
  • d_val 按整数值解析
  • d_ptr 按虚拟地址解析

哈希表

使用哈希表可以加快动态符号表的查找速度。哈希表就是DT_HASH的节,看下实际例子的输出,命令是readelf --gnu-hash-table

image.png

内容比较多,忽略了一部分,接下来看下结构:


image.png

对应的哈希函数如下:


image.png

一个哈希表需要解决如何快速查找,如何解决冲突的问题。
看看hash 表如何快速查找,这儿用到了一个Bloom Filter, 本质上就是在查找前先用Bloom Filter判断下,如果结果是不在,那么就没必要查找了,如果是在,实际上也不一定在,就需要实际去查一下。
解决冲突时利用了chain数组,在查找符号时,如果Bloom Filter判断出在,然后就在bueket中对应索引位置看看,如果等于期望的字符串,那么直接返回,然后在chain数组同样索引位置拿到下一个需要查找的位置,然后递归查找下去,直到 chain中的值是STN_UNDEF。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,366评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,521评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,689评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,925评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,942评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,727评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,447评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,349评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,820评论 1 317
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,990评论 3 337
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,127评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,812评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,471评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,017评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,142评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,388评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,066评论 2 355

推荐阅读更多精彩内容