1 什么是MachO文件
Mach-O其实就是Mach Object文件格式的缩写,是Mac以及iOS上可执行文件的格式,类似于Windows上的PE格式(Portable Exectable)、linux上的elf格式(executable and Linking Format)。
MachO是一种可执行文件、目标代码以及动态库等类型文件的格式。作为a.out格式的替代,Mach-O提供了更强的扩展性。
属于MachO格式的常见文件:
- 目标文件.o
- 库文件[.a(静态库) .dylib(动态库) framework]
- 可执行文件
- dyld
- .dsym
可以通过File指令来查看文件的类型
file指令使用格式:file 文件路径
2 查看各种MachO文件的信息
2.1查看一个.c文件生成的可执行文件的信息
打开XCode使用快捷键command+N创建一个名为test的c文件,文件内容如下所示:
#include <stdio.h>
int main() {
printf("test\n");
return 0;
}
打开终端将这个.c文件使用clang命令编译为.o文件
再通过file指令查看编译之后生成的.o文件的信息
可以看到这个test.o文件是一个MachO格式,架构是x86_64的64位的object文件,架构是x86_64表示只有英特尔芯片的Mac电脑能读取这个文件。
再使用clang命令将这个.o文件链接成为可执行文件
使用file命令查看a.out文件的信息
可以看到这个a.out文件是一个MachO格式,架构是x86_64的64位的可执行文件,架构是x86_64表示只有英特尔芯片的Mac电脑能读取这个文件。
也可以直接将.c文件通过使用clang命令直接编译链接成为可执行文件,如下图所示:
还可以直接将.o文件通过使用clang命令直接链接成为可执行文件,如下图所示:
现在所生成的a.out、test以及test2文件是不是一样的呢?我们通过md5命令来查看这三个文件的hash值是否一致。
通过hash值对比我们可以得知这三个文件是一样的。因为这三个文件的源码文件test.c是一样的,clang编译时的编译方式是一样的,所有生成的可执行文件是一样的。
2.2 查看两个.c文件生成的可执行文件的信息
创建一个test.c文件,文件内容为:
#include <stdio.h>
void test2();
int main() {
printf("test\n");
return 0;
}
创建一个test2.c文件,文件内容为:
#include <stdio.h>
void test2() {
printf("test2\n");
}
使用clang命令将两个.c文件(test.c在前)进行编译以及链接生成一个test可执行文件,文件信息如下:
使用clang命令将两个.c文件(test2.c在前)进行编译以及链接生成一个test可执行文件,文件信息如下:
再来看看生成的两个执行文件是否一样。
我们可以看到这两个可执行文件的hash值是不一样的,但使用的确是两个相同的.c文件编译链接而成的,这是为什么呢?
因为可执行文件实际上是多个.o文件的集合,链接时候的这些.o文件的顺序不一样,所生成的可执行文件的内容就不一样。
我们可以使用objdump命令来查看以下这两个执行文件的内容:
就如同你在项目中改变.m文件的编译顺序,所生成的可执行文件的内容也是不一样的,如下图所示:
2.3 查看.a文件的信息
使用find命令在/usr目录下查找.a文件
find命令使用格式:find 文件路径 -name 文件名
查看.a文件的信息
2.4 查看.dylib文件的信息
2.5 查看dyld文件的信息
由上图我们得知dyld实际上是一个动态链接器(dynamic linker),它不是一个可执行文件,是一个通用二进制文件,当启动系统的时候,系统内核会触发这个文件。
2.6 查看dSYM文件的信息
将项目工程的iOS版本改到13.1以下,并且当前环境设置为release模式,编译之后
可以看到这个是一个Macho-O类型的arm64架构下64位的dSYM手册文件。
3 通用二进制(Universal binary)
- 苹果公司提出的一种程序代码,能同时适用多种架构的二进制文件。
- 同一个程序包中同时为多种架构提供最理想的性能。
- 因为需要存储多种代码,通用二进制应用程序通常比单一平台二进制的程序要大
- 由于执行中只调用一部分代码,运行起来也不需要额外的内存。
iOS11以上的系统只支持64位以上的架构
3.1iOS11版本以上可执行文件的架构
3.2 iOS11版本以下可执行文件的架构
3.2 添加armv7s架构并查看iOS11版本以下可执行文件的架构
XCode中设置可执行文件的架构模式
armv7s是生成iPhone5、iPhone 5c都能用的架构
编译之后查看可执行文件支持的架构
4 使用lipo命令对MachO文件包含的架构进行合并以及拆分
4.1 使用lipo命令查看MachO文件的架构信息
命令格式:lipo -info MachO文件路径
4.2 使用lipo命令拆分MachO文件的某种架构
命令格式:lipo MachO文件 -thin 架构 -output 输出文件路径
4.3 使用lipo命令合并MachO文件的多种架构
命令格式:lipo -create MachO1 MachO2 -output 输出文件路径
5 MachO文件结构
5.1 MachO文件基本结构
如上图所示:Mach-O的组成结构包括了
- Header包含了该二进制文件的一般信息(字节顺序、结构类型、加载指令的数量等,使得可以快速确认一些信息,比如当前文件用于32位还是64位,对应的处理器是什么,文件类型是什么)
- Load commands是一张包含了很多内容的表(内容包括区域的位置、符号表、动态符号表等)
- Data是对象文件中最大的部分(包含Segement的具体数据)
5.1 使用otool命令查看MachO文件结构
5.1.1 使用otool命令查看MachO文件的header信息
命令格式:otool -f MachO文件路径
使用MachOView查看MachO文件信息
对比上下两张图我们可以发现:
cpuType 是12代码arm架构
cpuType 是16777228代表arm64架构
cpusubType为9对应的是arm_v7架构
cpusubType为11对应的是arm_v7s架构
cpusubType为0对应的是arm64架构
Offset代表的是这个类型架构的machO文件在整个MachO中首地址的偏移量,Size代表的是这个类型架构的machO文件大小
各个架构的MachO文件之间的空隙是因为分页原因造成的,mac中是2的12次方(4k)也就是4096,iOS中分页大小是2的14次方(16k)。
5.1.2 使用MachOView查看具体架构类型的MachO文件的header信息
/*
* The 64-bit mach header appears at the very beginning of object files for
* 64-bit architectures.
*/
struct mach_header_64 {
uint32_t magic; /* mach magic number identifier */
cpu_type_t cputype; /* cpu specifier */
cpu_subtype_t cpusubtype; /* machine specifier */
uint32_t filetype; /* type of file */
uint32_t ncmds; /* number of load commands */
uint32_t sizeofcmds; /* the size of all the load commands */
uint32_t flags; /* flags */
uint32_t reserved; /* reserved */
};
fileType类型
#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 /* a file composed of other Mach-Os to
be run in the same userspace sharing
a single linkedit. */
注意:第二行是外部符号绑定、