共计 3180 个字符,预计需要花费 8 分钟才能阅读完成。
接到催更的信息,其实还是很快乐。原本忙了很长一段时间为生存奔走,想给本人一个假期。起初脑子里响起了莎士比亚的一句话“如果一年到头如假日,岂不像连日工作那样困乏?”,而后还是决定放下劳碌的生存,持续去摸索。
通过最近一段时间的繁忙,对生存也多了一些从新的意识。人活着不要自觉,不要止步不前,不要高估本人的实力,也不要低估本人的能力,多一些自我扫视,重复 review 或者在生活上、工作上走的会更远~
一顿感概之后还是要回归主题,上一篇文章说到了 go1.3 编译应用了 6g 进行编译,编译成对应.a 链接库。那么这一章接着来讲 6l,那么持续来讲一下 6l 的实现过程与原理。
1. 可执行文件介绍
在链接的过程中就是为了生成可执行文件,那么可执行文件必定须要固定的格局。在计算机科学中,不同零碎的二进制文件,可执行文件,指标代码、共享库等格局是不同的。
那么简略来介绍集中可执行文件的格局。
1.1 PE 文件格式
PE 文件格式次要利用与 Windows 系列零碎,可执行文件索引。说到 pe 格局有一个比拟出名的黑客社区(看雪),就叫 pediy。
PE(Portable Executable)格局,是微软 Win32 环境可移植可执行文件 (如 exe、dll、vxd、sys 和 vdm 等) 的规范文件格式。PE 格局衍生于晚期建设在 VAX(R)VMS(R)上的 COFF(Common Object File Format)文件格式。PE 构造如图 1 - 1 所示。
<center> 图 1 -1 PE 格局 </center>
1.2 ELF 文件格式
ELF 文件格式是 linux 系列零碎,可执行文件索引;ELF 格局如图 1 - 2 所示。
ELF 是 UNIX 零碎实验室(USL)作为应用程序二进制接口(Application Binary Interface,ABI)而开发和公布的,也是 Linux 的次要可执行文件格局。
1999 年,被 86open 我的项目选为 x86 架构上的类 Unix 操作系统的二进制文件规范格局,用来取代 COFF。因其可扩展性与灵活性,也可利用在其它处理器、计算机系统架构的操作系统上。
<center> 图 1 -2 ELF 格局 </center>
1.3 mach- o 文件格式
mach- o 是 mac 系列零碎的可执行文件格局,苹果零碎是基于 FreeBSD 的,属于 unix-like 操作系统;
Mach- O 已经为大部分基于 Mach 外围的操作系统所应用。NeXTSTEP,Darwin 和 Mac OS X 等零碎应用这种格局作为其原生可执行文件,库和指标代码的格局。而同样应用 GNU Mach 作为其微内核的 GNU Hurd 零碎则应用 ELF 而非 Mach- O 作为其规范的二进制文件格式。
1.4 大节揭示
其实文件格式在很多场景都会利用到,比如说常常听到的蠕虫病毒,还有外挂编程,还有软件查杀等等都会利用到。简略说,就拿 PE 构造来说,比方通过 PE 晓得程序入口点,其实入口点个别都是代码段。那么在入口点动静注入代码,这样注入的代码段能做到复制,这就是一个蠕虫病毒的原理。
当然除了这些以外什么对程序加壳,加密,加花都会波及到文件格式。
这边有一篇介绍文件构造比拟好的文章:
https://blog.csdn.net/abc_123…
2.Inferno 介绍
6l 除了应用 plan9 之外还应用了 Inferno 零碎库。
Inferno 是一个分布式操作系统,最后由贝尔实验室开发,但当初由 Vita Nuova 作为自由软件开发和保护。应用 Inferno 的并发编程语言 Limbo 编写的应用程序被编译为其可移植虚拟机代码 (Dis),以便在 Inferno 提供的可移植环境中的网络上的任何地位运行。不同寻常的是,该环境的外观和行为就像一个残缺的操作系统。
Inferno 以相似文件的名称层次结构示意服务和资源。程序仅应用文件操作关上、读 / 写和敞开来拜访它们。“文件”不仅仅是存储的数据,还代表设施、网络和协定接口、动静数据源和服务。该办法对立并为所有系统资源提供根本的命名、构造和访问控制机制。繁多的文件服务协定(与 Plan 9 的 9P 雷同)使所有这些资源都能够通过网络以对立的形式导入或导出,与地位无关。应用程序只是将它须要的资源附加到它本人的每个过程名称层次结构(“命名空间”)。
Inferno 能够在各种 ARM、PowerPC、SPARC 和 x86 平台上“本机”运行,也能够在现有操作系统(包含 AIX、FreeBSD、IRIX、Linux、MacOS X、Plan 9 和 Solaris)下“托管”,再次在各种平台上运行处理器类型。
这个 Bitbucket 我的项目包含根本应用程序的源代码、Inferno 自身(托管和本机)、所有支持软件,包含本机编译器套件、根本可执行文件和反对文件。
Inferno 源代码:https://bitbucket.org/inferno…
Inferno 文档:http://www.vitanuova.com/infe…
3.6l 执行过程
6l 绝对于 6g 来说会简略一些,6l 其实就是针对不同的系统生成不同的执行文件构造,并且对文件构造填充数据。
3.1 调试内容
想要理解 6l 的一些过程能够通过如下命令:
#/mnt/pkg/tool/linux_amd64/6g -o ./command-line-arguments.a -D _/mnt/src/demo -pack ./demo.go
#/mnt/pkg/tool/linux_amd64/6l -v -o demo -extld=gcc ./command-line-arguments.a
如上命令其实做了两件事件,一个是通过 6g 生成.a 库,另外一个是通过 6l 链接 6g 生成的库。
既然晓得 6l 命令用处,那么下断点的话,必定要对 6l 进行调试,命令如下:
#gdb /mnt/pkg/tool/linux_amd64/6l
进入 gdb 模式后,须要设置编译参数,参数如下:
(gdb) set args -v -o demo -extld=gcc ./command-line-arguments.a
设置完参数后, 就能够“b mian”下断点了,比较简单,就不赘述了。
3.2 过程介绍
通过对源码的浏览后, 整顿了一张流程图,如图 3 - 1 所示。
<center> 图 3 -1 6l 链接过程 </center>
依据上图能够得悉 plan9 作为一个操作系统库,能够执行不同程序的 main 函数。除此之外在链接过程中会做一些操作,比方创立输入文件。依据不同的零碎通过 headtype 函数取得不同的文件格式类型,如图 3 - 2 所示。
<center> 图 3 -2 不同零碎的文件格式 </center>
通过文件格式类型调用 archinit 生成不同的可执行构造, 不同的构造对应一套代码,对应的 dwarf 构造、elf 构造、mach- o 构造、pe 构造,如图 3 - 3 所示。
<center> 图 3 -3 不同零碎的文件格式 </center>
而后会调用各种函数对可执行构造进行数据段,代码段,零碎描述符表,链接库等做数据填充,最初刷新到输入文件。
总结
理解 6l 之后对跨平台和可移植性零碎有了一些意识,并且把握了如下常识:
- 不同零碎之间存在不同的可执行文件构造。
- 6l 除了应用 plan9 之外还应用了 Inferno 零碎库。
- plan9 作为一个操作系统库,能够执行不同程序的 main 函数。
- headtype 函数与 archinit 函数组合应用,针对不同的零碎,初始化不同的构造体。
- 链接过程其实是通过可执行文件构造体填充不同程序段的数据。
其实针对填充的数据里还有很多更细节的,比方导出表,导入表等等。如果有趣味能够自行钻研,除此之外还有可执行程序的执行原理,比方 unix/linux 的 execvp、windows 的 CreateProcessW 等内核态调用细节。