1 什么是MachO文件
??Mach-O其實(shí)就是Mach Object文件格式的縮寫,是Mac以及iOS上可執(zhí)行文件的格式棚点,類似于Windows上的PE格式(Portable Exectable)、linux上的elf格式(executable and Linking Format)坪创。
??MachO是一種可執(zhí)行文件、目標(biāo)代碼以及動(dòng)態(tài)庫等類型文件的格式勒庄。作為a.out格式的替代挣轨,Mach-O提供了更強(qiáng)的擴(kuò)展性军熏。
??屬于MachO格式的常見文件:
- 目標(biāo)文件.o
- 庫文件[.a(靜態(tài)庫) .dylib(動(dòng)態(tài)庫) framework]
- 可執(zhí)行文件
- dyld
- .dsym
可以通過File指令來查看文件的類型
file指令使用格式:file 文件路徑
2 查看各種MachO文件的信息
2.1查看一個(gè).c文件生成的可執(zhí)行文件的信息
??打開XCode使用快捷鍵command+N創(chuàng)建一個(gè)名為test的c文件,文件內(nèi)容如下所示:
#include <stdio.h>
int main() {
printf("test\n");
return 0;
}
打開終端將這個(gè).c文件使用clang命令編譯為.o文件
再通過file指令查看編譯之后生成的.o文件的信息
可以看到這個(gè)test.o文件是一個(gè)MachO格式卷扮,架構(gòu)是x86_64的64位的object文件荡澎,架構(gòu)是x86_64表示只有英特爾芯片的Mac電腦能讀取這個(gè)文件。
再使用clang命令將這個(gè).o文件鏈接成為可執(zhí)行文件
使用file命令查看a.out文件的信息
可以看到這個(gè)a.out文件是一個(gè)MachO格式晤锹,架構(gòu)是x86_64的64位的可執(zhí)行文件摩幔,架構(gòu)是x86_64表示只有英特爾芯片的Mac電腦能讀取這個(gè)文件。
也可以直接將.c文件通過使用clang命令直接編譯鏈接成為可執(zhí)行文件鞭铆,如下圖所示:
還可以直接將.o文件通過使用clang命令直接鏈接成為可執(zhí)行文件或衡,如下圖所示:
現(xiàn)在所生成的a.out、test以及test2文件是不是一樣的呢车遂?我們通過md5命令來查看這三個(gè)文件的hash值是否一致封断。
通過hash值對(duì)比我們可以得知這三個(gè)文件是一樣的。因?yàn)檫@三個(gè)文件的源碼文件test.c是一樣的舶担,clang編譯時(shí)的編譯方式是一樣的坡疼,所有生成的可執(zhí)行文件是一樣的。
2.2 查看兩個(gè).c文件生成的可執(zhí)行文件的信息
創(chuàng)建一個(gè)test.c文件衣陶,文件內(nèi)容為:
#include <stdio.h>
void test2();
int main() {
printf("test\n");
return 0;
}
創(chuàng)建一個(gè)test2.c文件回梧,文件內(nèi)容為:
#include <stdio.h>
void test2() {
printf("test2\n");
}
使用clang命令將兩個(gè).c文件(test.c在前)進(jìn)行編譯以及鏈接生成一個(gè)test可執(zhí)行文件,文件信息如下:
使用clang命令將兩個(gè).c文件(test2.c在前)進(jìn)行編譯以及鏈接生成一個(gè)test可執(zhí)行文件祖搓,文件信息如下:
再來看看生成的兩個(gè)執(zhí)行文件是否一樣狱意。
我們可以看到這兩個(gè)可執(zhí)行文件的hash值是不一樣的,但使用的確是兩個(gè)相同的.c文件編譯鏈接而成的拯欧,這是為什么呢详囤?
因?yàn)榭蓤?zhí)行文件實(shí)際上是多個(gè).o文件的集合,鏈接時(shí)候的這些.o文件的順序不一樣镐作,所生成的可執(zhí)行文件的內(nèi)容就不一樣藏姐。
我們可以使用objdump命令來查看以下這兩個(gè)執(zhí)行文件的內(nèi)容:
就如同你在項(xiàng)目中改變.m文件的編譯順序,所生成的可執(zhí)行文件的內(nèi)容也是不一樣的该贾,如下圖所示:
2.3 查看.a文件的信息
使用find命令在/usr目錄下查找.a文件
find命令使用格式:find 文件路徑 -name 文件名
查看.a文件的信息
2.4 查看.dylib文件的信息
2.5 查看dyld文件的信息
由上圖我們得知dyld實(shí)際上是一個(gè)動(dòng)態(tài)鏈接器(dynamic linker)羔杨,它不是一個(gè)可執(zhí)行文件,是一個(gè)通用二進(jìn)制文件杨蛋,當(dāng)啟動(dòng)系統(tǒng)的時(shí)候兜材,系統(tǒng)內(nèi)核會(huì)觸發(fā)這個(gè)文件理澎。
2.6 查看dSYM文件的信息
將項(xiàng)目工程的iOS版本改到13.1以下,并且當(dāng)前環(huán)境設(shè)置為release模式曙寡,編譯之后
可以看到這個(gè)是一個(gè)Macho-O類型的arm64架構(gòu)下64位的dSYM手冊(cè)文件糠爬。
3 通用二進(jìn)制(Universal binary)
- 蘋果公司提出的一種程序代碼,能同時(shí)適用多種架構(gòu)的二進(jìn)制文件举庶。
- 同一個(gè)程序包中同時(shí)為多種架構(gòu)提供最理想的性能执隧。
- 因?yàn)樾枰鎯?chǔ)多種代碼,通用二進(jìn)制應(yīng)用程序通常比單一平臺(tái)二進(jìn)制的程序要大
- 由于執(zhí)行中只調(diào)用一部分代碼户侥,運(yùn)行起來也不需要額外的內(nèi)存镀琉。
iOS11以上的系統(tǒng)只支持64位以上的架構(gòu)
3.1iOS11版本以上可執(zhí)行文件的架構(gòu)
3.2 iOS11版本以下可執(zhí)行文件的架構(gòu)
3.2 添加armv7s架構(gòu)并查看iOS11版本以下可執(zhí)行文件的架構(gòu)
XCode中設(shè)置可執(zhí)行文件的架構(gòu)模式
armv7s是生成iPhone5、iPhone 5c都能用的架構(gòu)
編譯之后查看可執(zhí)行文件支持的架構(gòu)
4 使用lipo命令對(duì)MachO文件包含的架構(gòu)進(jìn)行合并以及拆分
4.1 使用lipo命令查看MachO文件的架構(gòu)信息
命令格式:lipo -info MachO文件路徑
4.2 使用lipo命令拆分MachO文件的某種架構(gòu)
命令格式:lipo MachO文件 -thin 架構(gòu) -output 輸出文件路徑
4.3 使用lipo命令合并MachO文件的多種架構(gòu)
命令格式:lipo -create MachO1 MachO2 -output 輸出文件路徑
5 MachO文件結(jié)構(gòu)
5.1 MachO文件基本結(jié)構(gòu)
如上圖所示:Mach-O的組成結(jié)構(gòu)包括了
- Header包含了該二進(jìn)制文件的一般信息(字節(jié)順序蕊唐、結(jié)構(gòu)類型滚粟、加載指令的數(shù)量等,使得可以快速確認(rèn)一些信息刃泌,比如當(dāng)前文件用于32位還是64位凡壤,對(duì)應(yīng)的處理器是什么,文件類型是什么)
- Load commands是一張包含了很多內(nèi)容的表(內(nèi)容包括區(qū)域的位置耙替、符號(hào)表亚侠、動(dòng)態(tài)符號(hào)表等)
- Data是對(duì)象文件中最大的部分(包含Segement的具體數(shù)據(jù))
5.1 使用otool命令查看MachO文件結(jié)構(gòu)
5.1.1 使用otool命令查看MachO文件的header信息
命令格式:otool -f MachO文件路徑
使用MachOView查看MachO文件信息
對(duì)比上下兩張圖我們可以發(fā)現(xiàn):
cpuType 是12代碼arm架構(gòu)
cpuType 是16777228代表arm64架構(gòu)
cpusubType為9對(duì)應(yīng)的是arm_v7架構(gòu)
cpusubType為11對(duì)應(yīng)的是arm_v7s架構(gòu)
cpusubType為0對(duì)應(yīng)的是arm64架構(gòu)
Offset代表的是這個(gè)類型架構(gòu)的machO文件在整個(gè)MachO中首地址的偏移量,Size代表的是這個(gè)類型架構(gòu)的machO文件大小
各個(gè)架構(gòu)的MachO文件之間的空隙是因?yàn)榉猪撛蛟斐傻乃咨龋琺ac中是2的12次方(4k)也就是4096硝烂,iOS中分頁大小是2的14次方(16k)。
5.1.2 使用MachOView查看具體架構(gòu)類型的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. */
注意:第二行是外部符號(hào)綁定铜幽、