您的位置:首页 >太阳能 >

技术分析:从字节码的粒度来探索ELF文件

时间:2021-05-25 20:16:17 来源:

初次见面

大家好,我是 ELF 文件,大名叫 Executable and Linkable Format。

经常在 Linux 系统中开发的小伙伴们,对于我肯定是再熟悉不过了,特别是那些需要了解编译、链接的家伙们,估计已经把我研究的透透的。

为了结识更多的小伙伴,今天呢,就是我的开放日,我会像洋葱一样,一层一层地拨开我的心,让更多的小伙伴来了解我,欢迎大家前来围观。

以前啊,我看到有些小伙伴在研究我的时候,看一下头部的汇总信息,然后再瞅几眼 Section 的布局,就当做熟悉我了。

从科学的态度上来说,这是远远不够的,未达究竟。

当你面对编译、链接的详细过程时,还是会一脸懵逼。

今天,我会从字节码的颗粒度,毫无保留、开诚布公、知无不言、言无不尽、赤胆忠心、一片丹心、鞠躬尽瘁、死而后已的把自己剖析一遍,让各位看官大开眼界、大饱眼福。

您了解这些知识之后呢,在今后继续学习编译、链接的底层过程,以及一个可执行程序在从硬盘加载到内存、一直到 main 函数的执行,心中就会非常的敞亮。

也就是说,掌握了 ELF 文件的结构和内容,是理解编译、链接和程序执行的基础。

你们不是有一句俗话嘛:磨刀不误砍柴工!

好了,下面我们就开始吧!

文件很单纯,复杂的是人

作为一种文件,那么肯定就需要遵守一定的格式,我也不例外。

从宏观上看,可以把我拆卸成四个部分:

图中的这几个概念,如果不明白的话也没关系,下面我会逐个说明的。

在 Linux 系统中,一个 ELF 文件主要用来表示 3 种类型的文件:

既然可以用来表示 3 种类型的文件,那么在文件中,肯定有一个地方用来区分这 3 种情况。

也许你已经猜到了,在我的头部内容中,就存在一个字段,用来表示:当前这个 ELF 文件,它到底是一个可执行文件?是一个目标文件?还是一个共享库文件?

另外,既然我可以用来表示 3 种类型的文件,那么就肯定是在 3 种不同的场合下被使用,或者说被不同的家伙来操作我:

可执行文件:被操作系统中的加载器从硬盘上读取,载入到内存中去执行;

目标文件:被链接器读取,用来产生一个可执行文件或者共享库文件;

共享库文件:在动态链接的时候,由 ld-linux.so 来读取;

就拿链接器和加载器来说吧,这两个家伙的性格是不一样的,它们看我的眼光也是不一样的。

链接器在看我的时候,它的眼睛里只有 3 部分内容:

也就是说,链接器只关心 ELF header, Sections 以及 Section header table 这 3 部分内容。

加载器在看我的时候,它的眼睛里是另外的 3 部分内容:

加载器只关心 ELF header, Program header table 和 Segment 这 3 部分内容。

对了,从加载器的角度看,对于中间部分的 Sections, 它改了个名字,叫做 Segments(段)。换汤不换药,本质上都是一样一样的。

可以理解为:一个 Segment 可能包含一个或者多个 Sections,就像下面这样:

这就好比超市里的货架上摆放的商品:有矿泉水、可乐、啤酒,巧克力,牛肉干,薯片。

从理货员的角度看:它们属于 6 种不同的商品;但是从超市经理的角度看,它们只属于 2 类商品:饮料和零食。

怎么样?现在对我已经有一个总体的印象了吧?

其实只要掌握到 2 点内容就可以了:

一个 ELF 文件一共由 4 个部分组成;

链接器和加载器,它们在使用我的时候,只会使用它们感兴趣的部分;

还有一点差点忘记给你提个醒了:在 Linux 系统中,会有不同的数据结构来描述上面所说的每部分内容。

我知道有些小伙伴比较性急,我先把这几个结构体告诉你。

初次见面,先认识一下即可,千万不要深究哦。

描述 ELF header 的结构体:

123下一页>


郑重声明:文章仅代表原作者观点,不代表本站立场;如有侵权、违规,可直接反馈本站,我们将会作修改或删除处理。