什么是 Mach-O
Mach-O 是 Mach object 的缩写,是 iOS/Mac 上用于存储程序、库的标准格式。
可执行文件是 Mach-O 文件的一种类型,不能说 Mach-O 文件等价于可执行文件。
在 xnu 源码中,可以查看 Mach-O 格式的详细定义。在源码的 EXTERNAL_HEADERS/mach-o/loader.h
文件中,我们可以看到 Mach-O 格式的所有文件类型:
#define MH_OBJECT 0x1 /* relocatable object file */
#define MH_EXECUTE 0x2 /* demand paged executable file */
#define MH_FVMLIB 0x3 /* fixed VM shared library file */
#define MH_CORE 0x4 /* core file */
#define MH_PRELOAD 0x5 /* preloaded executable file */
#define MH_DYLIB 0x6 /* dynamically bound shared library */
#define MH_DYLINKER 0x7 /* dynamic link editor */
#define MH_BUNDLE 0x8 /* dynamically bound bundle file */
#define MH_DYLIB_STUB 0x9 /* shared library stub for static */
/* linking only, no section contents */
#define MH_DSYM 0xa /* companion file with only debug */
/* sections */
#define MH_KEXT_BUNDLE 0xb /* x86_64 kexts */
#define MH_FILESET 0xc /* set of mach-o's */
xnu是苹果iOS/MacOS等操作系统的内核,下源码地址:https://opensource.apple.com/tarballs/xnu/
常见的 Mach-O 文件类型:
类型 | 描述 |
---|---|
MH_OBJECT | 源文件编译后的目标文件(.o),静态库文件(.a),静态库文件其实就是多个 .o 文件合并在一起 |
MH_EXECUTE | 可执行文件,iOS里在 xx.app/xx ,Mac则在 xx.app/Contents/MacOS/xx |
MH_DYLIB | 动态库文件,.dylib 、xx.framework/xx |
MH_DYLINKER | 动态链接编辑器,也就是 /usr/lib/dylb 工具 |
MH_DSYM | 存储着二进制文件符号信息的文件,xx.dSYM/Contents/Resources/DWARF/xx ,常用于分析APP的崩溃信息 |
Mach-O文件的基本结构
Mach-O由3个部分组成
名称 | 描述 |
---|---|
Header | 包含文件类型,目标架构类型等 |
Load commands | 描述文件在虚拟内存中的逻辑结构和布局,相当于一份目录索引 |
Raw segment data | 存放了所有的原始数据,而Load commands相当于Raw segment data的索引目录 |
窥探Mach-O的结构
命令行工具
file
命令查看 Mach-O 文件的基本信息:
file Dagou
Dagou: Mach-O 64-bit executable arm64
otool
命令查看 Mach-O 特定部分和段的内容:
otool -h 文件路径 # 查看Mach-O文件的header信息
otool -l 文件路径 # 查看Mach-O文件的load commands信息
lipo
命令用来处理多架构 Mach-O 文件:
lipo -info 文件路径 # 查看架构信息
lipo 文件路径 -thin 架构类型 -output 输出文件路径 # 导出某种类型的架构
lipo -create 文件路径1 文件路径2 -output 输出文件路径 # 合并多种架构类型
GUI工具
使用 MachOView
可视化查看 Mach-O 文件的结构,下载地址:https://github.com/mythkiven/MachOView 。
Universal Binary(通用二进制文件)
同时适用于多种架构的二进制文件,它包含了多种不同架构的独立的二进制文件,它有以下特点:
1.因为需要存储多种架构的二进制,所以通用二进制文件要比单架构二进制文件更大。
2.因为两种架构之间可以共用一些资源,所以两种架构的通用二进制文件大小不会达到单一架构版本的2倍。
3.运行过程中只会调用其中的部分代码,所以运行起来不会占用额外的内存。
4.通用二进制文件通常也被称为“胖二进制文件(Fat binary)”。
iOS开发中的编译链接
在iOS开发中,有很多功能都是现成可用的,比如 UIKit 框架、GUI 框架、I/O、网络框架等等,这些库都是通过链接器链接到 Mach-O 文件中的。
静态库:静态库是编译时链接的库,需要链接进 Mach-O 文件中,如果需要更新就必须重新编译一次,无法做到动态加载和更新。
动态库:动态库是运行时链接的库,Mach-O 是文件编译之后的产物,动态库并没有参与 Mach-O 文件的编译和链接。所以 Mach-O 文件中没有包含动态库的符号定义,也就是说这些符号会直接显示未定义,但是他们的名字和对应库的路径会被记录下来。在运行时通过 dlopen
和 dlsym
导入动态库时,会根据记录的路径找到对应的库,再通过记录的名字符号找到绑定的地址。
编译:将 OC 代码编译成汇编代码,汇编代码编译成机器代码。
反编译:在同一种架构平台下,每一条汇编指令都有与之对应的唯一的机器指令,所以可以把机器代码反编译成汇编代码,但汇编代码没办法反编译成 OC 代码。
勾选
Xcode - Debug - Debug Workflow - Always Show Disassembly
,断点则可看到汇编代码。
动态库共享缓存:iOS 系统的动态库的 Mach-O 文件存放在动态库共享缓存(dyld shared cache
)里,比如 UIKit、MapKit 等等库。从 iOS3.1 开始,为了提高性能,绝大部分系统动态库文件都打包存放到了一个缓存文件中。缓存文件路径:/System/Library/Caches/com.apple.dyld/dyld_shared_cache_arm
XXX ,XXX 代表 ARM 处理器指令集架构。
指令集(CPU指令架构的集合):
指令集 | 机型 |
---|---|
armv6 | iPhone、iPhone3G、iPod Touch、iPod Touch2 |
armv7 | iPhone3GS、iPhone4、iPhone4S、iPad、iPad2、iPad3(The New iPad)、iPad mini、iPod Touch3G、iPod Touch4、iPod Touch5 |
armv7s | iPhone5、iPhone5C、iPad4 |
arm64 | iPhone5S、iPhone6、iPhone6 Plus、iPhone6S、iPhone6S Plus、iPhoneSE、iPhone7、iPhone7 Plus、iPhone8、iPhone8 Plus、iPhoneX、iPad5、iPad Air、iPad Air2、iPad Pro、iPad Pro2、iPad mini with Retina display、iPad mini3、iPad mini4、iPod Touch6 等等 |
arm64e | iPhoneXS、iPhoneXR、iPhoneXS Max 等等 |
动态库共享缓存一个非常明显的好处是节省内存,现在
ida
、Hopper
反编译工具都可以识别动态库共享缓存。
所有指令集原则上都是向下兼容的,也就是arm64
指令集架构原则上支持以上所有设备。
dyld
dyld
叫动态加载器(又叫动态链接编辑器),是 iOS 中用来加载可执行文件、动态库的工具,其实它本身也是一个 Mach-O 文件。它可以加载 MH_EXECUTE
、MH_DYLIB
、MH_BUNDLE
三种类型的 Mach-O 文件。
dyld 位置 /usr/lib/dyld
,源码地址:https://opensource.apple.com/tarballs/dyld/
从编码到APP安装到手机
想要了解 Mach-O 文件,首先要了解从编写代码,开发 APP 到 APP 打包并安装到手机上的整个过程:
1.首先我们编写完成代码之后,会通过 LLVM 编译器 预处理 我们的代码,比如将宏替换到指定位置。
2.预处理结束后,LLVM 会对代码进行 词法分析 和 语法分析,生成 AST(AST是抽象语法树,主要用来进行快速遍历,实现静态代码检查的功能)。
3.AST 会生成 IR,IR 是一种更接近机器码的语言,通过 IR 可以生成不同平台的机器码。对于 iOS 平台,IR 生成可执行的 Mach-O 文件。
4.最后通过签名等操作生成 .app 文件,然后对 .app 文件进行压缩就得到我们可以安装的 ipa 安装包。
5.ipa 安装包可以通过开发者账号上传到 App Store,然后让用户下载安装。或者通过Xcode、iFunBox、爱思助手等工具来安装。