在研究这个问题的时候, 参考了很多的资料, 其中对我影响最大的一片文章是来自360涅槃团队的Proteas写的文章《Xcode 7 Bitcode的工作流程及安全性评估》, 在这篇文章信息量很大,让我消化了很久才摸到门道。在此感谢Proteas。

简介

Bitcode是llvm编译器的中间语言, 可以认为是llvm将C/C++/OC直接翻译成了llvm ir, llvm ir的二进制表现形式被称作bitcode。

在苹果官方的文档中, 是这样描述bitcode这个特性的:
bitcode feature

可见,苹果之所以要启用bitcode这个特性,主要是为“云编译”做准备。

启用bitcode后的macho有哪些改变?

下图是增加bitcode特性之后的macho文件格式,
image

可以看到启用bitcode特性之后, macho文件中多了一个名为LLVM,bundle的section, 通过查看,发现这个段中包含了一个xar的压缩文件(关于xar文件, 可以查看这里)。

解压这个文件就可以得到对应的bitcode。

bitcode是什么时候嵌入的?

目前苹果已经开源了clang7.0和对应的ld64两部分的代码。

通过查看代码, 我们发现, clang7.0首先将对应的文件编译成xx.o这样的中间文件, 并且在.o文件中插入了”__LLVM,__bitcode”和”__LLVM,__cmdline”, 在前者保留了对应的bitcode, 后者则保留了对应的编译参数。

我们知道, 每个项目都有不只一个.o这样的中间文件, 因此clang最后会调用连接器ld64, 将所有的.o的文件连接成一个有可执行权限的macho文件。

在链接的过程中, ld64会将每个.o文件中的bitcode解压出来, 并压缩成一个xar压缩包。并将这个包含有bitcode的xar压缩包, 再写回macho的”__LLVM,__bundle”这个section中, 从而完成bitcode的嵌入。

除了流程其他需要知道的

  1. 在苹果的流程中, 被打包进macho的bitcode字节流是没有经过任何的中间优化的, 也就是没有经过llvm pass的处理, 完全是对源代码的翻译。

  2. 如何dump macho中的对应的bundle段, 我已经写好了代码,传送门

Happy HACKING,
Axis