前言
本篇文章主要分析MachO文件
(也稱作二進(jìn)制可執(zhí)行文件
),相信大家在平時(shí)開發(fā)中都會(huì)碰到MachO文件
這個(gè)概念师崎,但是大部分人不清楚是個(gè)什么東西工扎,本篇文章就和大家一起來具體分析它的由來
以及它的內(nèi)部結(jié)構(gòu)
捉兴。
一、Mach-O
首先大家看看上面這張圖护昧,從左到右可以看出??
1.不論是哪種高級(jí)語言(C OC Swift
等),第一步都會(huì)生成AST語法樹
溜畅,只是編譯器前端
不同而已(有Clang捏卓、Swift或Rust
)
- 接著通過
CIL MIR 或SIL生成器
生成IR中間代碼
,這個(gè)中間代碼都屬于LLVM IR
- 最后交給
MIR
生成機(jī)器代碼
慈格,這個(gè)機(jī)器代碼就是MachO文件
整個(gè)過程其實(shí)都是LLVM
幫我們完成的怠晴,至于LLVM
是什么,大家可以參考我之前的文章 ?? LLVM編譯流程浴捆。
常見的Mach-O文件格式
- 目標(biāo)文件.o
- 庫文件
- .a
- .dylib
- .framework
- 可執(zhí)行文件
- dyld
- .dsym
驗(yàn)證
.o
蒜田、.out
、可執(zhí)行文件
案例一
新建test.c文件选泻,內(nèi)容如下??
#include <stdio.h>
int main() {
printf("test\n");
return 0;
}
驗(yàn)證.o
文件??
??注意:
不指定-c
默認(rèn)生成.out
格式冲粤,如果報(bào)找不到'stdio.h' file not found
美莫,則可以指定-isysroot
仪缸。
驗(yàn)證.out
可執(zhí)行文件??
驗(yàn)證可執(zhí)行文件??
再直接生成一個(gè)test3
可執(zhí)行文件??
那么問題來了 ?? 生成的a.out而克、test2、test3
是一樣的么蝶缀???
可以看到生成的可執(zhí)行文件md5相同
傀顾。
??注意:原則上test3的md5應(yīng)該和test2和a.out相同襟铭。源碼沒有變化,所以應(yīng)該相同的短曾。在指定
-isysroot
后生成的可能不同
寒砖,推測和CommandLineTools
有關(guān)(系統(tǒng)中有一個(gè),Xcode中也有一個(gè))嫉拐。
案例二
再創(chuàng)建一個(gè)test1.c文件哩都,內(nèi)容如下??
#include <stdio.h>
void test1Func() {
printf("test1 func \n");
}
修改test.c??
#include <stdio.h>
void test1Func();
int main() {
test1Func();
printf("test\n");
return 0;
}
這個(gè)時(shí)候相當(dāng)于多了個(gè)test1.c
文件了,編譯生成可執(zhí)行文件demo婉徘、demo1漠嵌、demo2
??
clang -o demo test1.c test.c
clang -c test1.c test.c
clang -o demo1 test.o test1.o
clang -o demo2 test1.o test.o
查看他們的MD5??
這里demo1和demo2的md5不同
,是因?yàn)閠est.o和test1.o順序不同
判哥。
objdump命令查看Mach-O
objdump --macho -d demo
上圖明顯可見方法調(diào)用的順序不同
献雅,這也就解釋了md5不同
的原因。這里很像Xcode中Build Phases -> Compile Sources
中源文件的順序
塌计。
??注意:源文件順序不同挺身,編譯出來的二進(jìn)制文件不同( 大小相同),二進(jìn)制排列順序不同锌仅。
.a
文件章钾、
直接創(chuàng)建一個(gè)library庫查看??
//find /usr -name "*.a"
file libTestLibrary.a
libTestLibrary.a: current ar archive random library
.dylib
文件
file /usr/lib/libprequelite.dylib
/usr/lib/libprequelite.dylib: Mach-O 64-bit dynamically linked shared library x86_64
??注意:
dyld
不是
可執(zhí)行文件,它是一個(gè)dynamic linker
热芹,由系統(tǒng)內(nèi)核
觸發(fā)贱傀。
dyld
文件
cd /usr/lib
file dyld
dyld: Mach-O universal binary with 2 architectures: [x86_64:Mach-O 64-bit dynamic linker x86_64] [i386:Mach-O dynamic linker i386]
dyld (for architecture x86_64): Mach-O 64-bit dynamic linker x86_64
dyld (for architecture i386): Mach-O dynamic linker i386
.dsym
文件
file TestDsym.app.dSYM
TestDsym.app.dSYM: directory
cd TestDsym.app.dSYM/Contents/Resources/DWARF
file TestDsym
TestDsym: Mach-O 64-bit dSYM companion file arm64
二、工程配置
2.1 查看Mach-O文件的類型
我們可以在工程配置中查看Mach-O文件的類型伊脓,如下圖??
也可以使用命令行查看??
file
your Mach-O文件路徑
可以看到是支持2個(gè)架構(gòu)的:arm64
和armv7
府寒。當(dāng)然也可以在Xcode中直觀的看到支持的架構(gòu)??
同時(shí)Xcode中架構(gòu)設(shè)置在Build Settings -> Architectures
中??
主要有以下配置選項(xiàng)??
-
Architectures
?? 支持的架構(gòu)。 -
Build Active Architecture Only
?? 默認(rèn)情況下debug模式下只編譯當(dāng)前設(shè)備架構(gòu)报腔,release模式下需要根據(jù)支持的設(shè)備株搔。 -
$(ARCHS_STANDARD)
?? 環(huán)境變量,代表當(dāng)前支持的架構(gòu)纯蛾。
如果我們要修改架構(gòu)直接在Architectures中配置(增加armv7s)??
2.2 通用二進(jìn)制文件(Universal binary)
- 蘋果公司提出的一種程序代碼纤房,能同時(shí)適用多種架構(gòu)的二進(jìn)制文件。
- 同一個(gè)程序包中同時(shí)為多種架構(gòu)提供最理想的性能翻诉。
- 因?yàn)樾枰獌?chǔ)存多種代碼炮姨,通用二進(jìn)制應(yīng)用程序通常比單一平臺(tái)二進(jìn)制的程序要大捌刮。
- 由于多種架構(gòu)有共同的非執(zhí)行資源(代碼以外的),所以并不會(huì)達(dá)到單一版本的多倍之多(特殊情況下舒岸,只有少量代碼文件的情況下有可能會(huì)大于多倍)绅作。
- 由于執(zhí)行中只調(diào)用一部分代碼,運(yùn)行起來不需要額外的內(nèi)存蛾派。
當(dāng)我們將通用二進(jìn)制文件拖入Hopper時(shí)棚蓄,能夠看到讓我們選擇對應(yīng)的架構(gòu)??
2.3 lipo命令
lipo
是管理Fat File
的工具,可以查看cpu架構(gòu)碍脏,提取特定架構(gòu),整合和拆分庫文件稍算。
1. 查看MachO
文件支持的架構(gòu)
lipo -info MachO文件
lipo -info EvergrandeCustomerApp_Example
Architectures in the fat file: EvergrandeCustomerApp_Example are: armv7 arm64
2. lifo –thin 拆分某種架構(gòu)
lipo MachO文件 –thin 架構(gòu) –output 輸出文件路徑
3. 使用lipo -create合并多種架構(gòu)
lipo -create MachO1 MachO2 -output 輸出文件路徑
三典尾、MachO文件結(jié)構(gòu)
macho
文件是mac os
或ios
系統(tǒng)可執(zhí)行文件
的格式,系統(tǒng)通過加載
這個(gè)格式來執(zhí)行代碼
糊探。相關(guān)結(jié)構(gòu)如下圖??
上圖中Mach-O
的組成結(jié)構(gòu)如圖所示包括??
-
Header
包含該二進(jìn)制文件的一般信息- 字節(jié)順序钾埂、架構(gòu)類型、加載指令的數(shù)量等
- 使得可以快速確認(rèn)一些信息科平,比如當(dāng)前文件用于32位還是64位褥紫,對應(yīng)的處理器是什么、文件類型是什么
-
Load commands
一張包含很多內(nèi)容的表- 內(nèi)容包括區(qū)域的位置瞪慧、符號(hào)表髓考、動(dòng)態(tài)符號(hào)表等
-
Data
通常是對象文件中最大的部分- 包含
Segement
的具體數(shù)據(jù)
- 包含
3.1 查看MachO文件的方式
有2種方式可查看MachO文件的結(jié)構(gòu)??
- 命令行
otool -f MachO文件
$ otool -f xxx.app/xxx
Fat headers
fat_magic 0xcafebabe
nfat_arch 2
architecture 0
cputype 12
cpusubtype 9
capabilities 0x0
offset 16384
size 69642576
align 2^14 (16384)
architecture 1
cputype 16777228
cpusubtype 0
capabilities 0x0
offset 69664768
size 80306624
align 2^14 (16384)
-
MachO View
可視化工具
3.2 MachO Header的結(jié)構(gòu)
Fat Header
首先我們來看看Fat Header
,什么是Fat Header
??
對于
多架構(gòu)MachO
會(huì)有一個(gè)Fat Header
弃酌,其中包含了CPU類型和架構(gòu)
氨菇。Offset
和Size
代表了每一個(gè)架構(gòu)
在二進(jìn)制文件
中的偏移
和大小
。
上圖中妓湘,armv7
的偏移量
和大小
分別是16384
和 79315040
查蓉,再看arm64的偏移量
是79347712
,可以發(fā)現(xiàn)16384 + 79315040 = 79331424 < 79347712
榜贴,但是79347712 - 16384 = 79331328
豌研,79331328/(1024 * 16) = 4842
,其中(1024 * 16)
代表16k字節(jié)
大小唬党,因?yàn)??
iOS中一頁
16K
鹃共,MachO中都是以頁
為單位對齊
的。
這也驗(yàn)證了以頁對齊
初嘹,并且這也是Load Commands
中可以插入LC_LOAD_DYLIB
的原因及汉。
Header的數(shù)據(jù)
上圖是arm64架構(gòu)下的Header,對應(yīng)dyld的定義代碼結(jié)構(gòu)如下(loader.h
)??
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 */
};
參數(shù) | 釋義 |
---|---|
magic |
魔數(shù)屯烦,快速定位屬于64位還是32位 |
cputype |
CPU類型坷随,比如ARM |
cpusubtype |
CPU具體類型房铭,arm64,armv7 |
filetype |
文件類型温眉,比如可執(zhí)行文件 |
ncmds |
Number of Load Commands 缸匪,即Load Commands總的條數(shù)
|
sizeofcmds |
Size of Load Commands ,即Load Commands總的大小
|
flags |
標(biāo)識(shí)二進(jìn)制文件支持的功能类溢,主要是和系統(tǒng)加載凌蔬、鏈接有關(guān) |
reserved |
arm64特有 ,保留字段 |
其中闯冷,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. */
3.3 Load Commands
dyld
檢索完Header
之后就開始加載和解析Load Commands
了砂心,Load Comands
的大致結(jié)構(gòu)如下??
2.3.1 load_command
結(jié)構(gòu)體
對應(yīng)的代碼??
/*
* The load commands directly follow the mach_header. The total size of all
* of the commands is given by the sizeofcmds field in the mach_header. All
* load commands must have as their first two fields cmd and cmdsize. The cmd
* field is filled in with a constant for that command type. Each command type
* has a structure specifically for it. The cmdsize field is the size in bytes
* of the particular load command structure plus anything that follows it that
* is a part of the load command (i.e. section structures, strings, etc.). To
* advance to the next load command the cmdsize can be added to the offset or
* pointer of the current load command. The cmdsize for 32-bit architectures
* MUST be a multiple of 4 bytes and for 64-bit architectures MUST be a multiple
* of 8 bytes (these are forever the maximum alignment of any load commands).
* The padded bytes must be zero. All tables in the object file must also
* follow these rules so the file can be memory mapped. Otherwise the pointers
* to these tables will not work well or at all on some machines. With all
* padding zeroed like objects will compare byte for byte.
*/
struct load_command {
uint32_t cmd; /* type of load command */
uint32_t cmdsize; /* total size of command in bytes */
};
每一個(gè)load_command
都需要包含??
-
cmd
?? 加載類型 -
cmdsize
?? 加載的大小
2.3.2 所有load_command
的具體信息
接下來我們仔細(xì)看看每個(gè)load_command
具體包含哪些信息??
__PAGEZERO
空指針陷阱
,目的是為了和32位
指令完全分開蛇耀。(32位
地址在4G以下
辩诞,64位
地址大于4G
,其中0xffffffff = 4G
)纺涤。有以下幾個(gè)重要的描述??
-
Segment Name
??__PAGEZERO
不占用數(shù)據(jù)(file size為0)译暂,唯一有的是VM Size
(arm64 4G,armv7比較辛么丁)外永。 -
VM Addr
?? 虛擬內(nèi)存地址 -
VM Size
?? 虛擬內(nèi)存大小。運(yùn)行時(shí)刻在內(nèi)存中的大小拧咳,一般情況下和File size相同伯顶,__PAGEZERO例外。 -
File offset
?? 數(shù)據(jù)在文件中偏移量呛踊。 -
File size
?? 數(shù)據(jù)在文件中的大小砾淌。
一般我們定位地址是通過
VM Addr + ASLR
。
__TEXT谭网、__DATA汪厨、__LINKEDIT
他們的結(jié)構(gòu)和__PAGEZERO
大致差不多,用途是將文件中(32位/64位)的段映射
到進(jìn)程地址空間中愉择。分為三大塊
?? 分別對應(yīng)DATA
中的Section(__TEXT + __DATA)
劫乱、__LINKEDIT
,告訴dyld
占用多大空間锥涕。
LC_DYLD_INFO_ONLY
動(dòng)態(tài)鏈接相關(guān)信息衷戈。
-
Rebase
?? 重定向(ASLR)偏移地址
和大小
。從Rebase Info Offset + ASLR
開始加載336
個(gè)字節(jié)數(shù)據(jù)层坠。 -
Binding
?? 綁定外部符號(hào)
殖妇。 -
Weak Binding
?? 弱綁定。 -
Lazy Binding
?? 懶綁定破花,用到的時(shí)候再綁定谦趣。 -
Export info
?? 對外開放的函數(shù)疲吸。
LC_SYMTAB
符號(hào)表地址。
-
Symbol Table Offset
?? 符號(hào)表地址偏移量 -
Number of Symbol
?? 符號(hào)總數(shù)量 -
String Table Offset
?? 字符串表地址偏移量 -
Symbol Table Size
?? 字符串表大小
LC_DSYMTAB
動(dòng)態(tài)符號(hào)表地址前鹅。
也是包含一些索引摘悴、數(shù)量、地址偏移量
等信息舰绘。
LC_LOAD_DYLINKER
使用誰加載蹂喻,iOS系統(tǒng)是使用dyld
加載,如下圖??
LC_UUID
文件的UUID捂寿,即MachO
文件的唯一識(shí)別標(biāo)識(shí)
口四。
LC_VERSION_MIN_IPHONES
支持最低
的操作系統(tǒng)版本。
LC_SOURCE_VERSION
源代碼的版本號(hào)秦陋。
LC_MAIN
程序主程序的入口地址和棧大小窃祝。
LC_ENCRYPTION_INFO_64
加密的信息。
LC_LOAD_DYLIB
依賴的庫的路徑踱侣,包含第三方的庫。
系統(tǒng)的庫??
第三方庫??
LC_RPATH
Frameworks庫的路徑大磺。
-
@executable_path
??
-
@loader_path
??
LC_FUNCTION_STARTS
函數(shù)起始地址表抡句。
LC_DATA_IN_CODE
定義在代碼段內(nèi)的非指令的表。
LC_DATA_SIGNATURE
代碼簽名杠愧。
3.4 Data
Data
包含Section(__TEXT + __DATA)
待榔、__LINKEDIT
。
3.4.1 __TEXT
__TEXT
即代碼段流济,就是我們寫的代碼锐锣。主要的幾個(gè)子段有??
1. __text: 代碼節(jié),存放機(jī)器編譯后的代碼
2. __stubs: 用于輔助做動(dòng)態(tài)鏈接代碼(dyld).
3. __stub_helper:用于輔助做動(dòng)態(tài)鏈接(dyld).
4. __objc_methname:objc的方法名稱
5. __cstring:代碼運(yùn)行中包含的字符串常量,比如代碼中定義`#define kGeTuiPushAESKey @"DWE2#@e2!"`,那DWE2#@e2!會(huì)存在這個(gè)區(qū)里绳瘟。
6. __objc_classname:objc類名
7. __objc_methtype:objc方法類型
8. __ustring:
9. __gcc_except_tab:
10. __const:存儲(chǔ)const修飾的常量
11. __dof_RACSignal:
12. __dof_RACCompou:
13. __unwind_info:
3.4.2 __DATA
__DATA數(shù)據(jù)段雕憔。主要的幾個(gè)子段有??
1. __got:存儲(chǔ)引用符號(hào)的實(shí)際地址,類似于動(dòng)態(tài)符號(hào)表糖声,存儲(chǔ)了`__nl_symbol_ptr`相關(guān)函數(shù)指針斤彼。
2. __la_symbol_ptr:lazy symbol pointers。懶加載的函數(shù)指針地址(C代碼實(shí)現(xiàn)的函數(shù)對應(yīng)實(shí)現(xiàn)的地址)蘸泻。和__stubs和stub_helper配合使用琉苇。具體原理暫留。
3. __mod_init_func:模塊初始化的方法悦施。
4. __const:存儲(chǔ)constant常量的數(shù)據(jù)并扇。比如使用extern導(dǎo)出的const修飾的常量。
5. __cfstring:使用Core Foundation字符串
6. __objc_classlist:objc類列表,保存類信息抡诞,映射了__objc_data的地址
7. __objc_nlclslist:Objective-C 的 +load 函數(shù)列表穷蛹,比 __mod_init_func 更早執(zhí)行土陪。
8. __objc_catlist: categories
9. __objc_nlcatlist:Objective-C 的categories的 +load函數(shù)列表。
10. __objc_protolist:objc協(xié)議列表
11. __objc_imageinfo:objc鏡像信息
12. __objc_const:objc常量俩莽。保存objc_classdata結(jié)構(gòu)體數(shù)據(jù)旺坠。用于映射類相關(guān)數(shù)據(jù)的地址,比如類名扮超,方法名等取刃。
13. __objc_selrefs:引用到的objc方法
14. __objc_protorefs:引用到的objc協(xié)議
15. __objc_classrefs:引用到的objc類
16. __objc_superrefs:objc超類引用
17. __objc_ivar:objc ivar指針,存儲(chǔ)屬性。
18. __objc_data:objc的數(shù)據(jù)出刷。用于保存類需要的數(shù)據(jù)璧疗。最主要的內(nèi)容是映射__objc_const地址,用于找到類的相關(guān)數(shù)據(jù)馁龟。
19. __data:暫時(shí)沒理解崩侠,從日志看存放了協(xié)議和一些固定了地址(已經(jīng)初始化)的靜態(tài)量。
20. __bss:存儲(chǔ)未初始化的靜態(tài)量坷檩。比如:`static NSThread *_networkRequestThread = nil;`其中這里面的size表示應(yīng)用運(yùn)行占用的內(nèi)存却音,不是實(shí)際的占用空間。所以計(jì)算大小的時(shí)候應(yīng)該去掉這部分?jǐn)?shù)據(jù)矢炼。
21. __common:存儲(chǔ)導(dǎo)出的全局的數(shù)據(jù)系瓢。類似于static,但是沒有用static修飾句灌。比如KSCrash里面`NSDictionary* g_registerOrders;`, g_registerOrders就存儲(chǔ)在__common里面
3.4.3 __LINKEDIT
__LINKEDIT
主要包含??
Dynamic Loader Info
?? 動(dòng)態(tài)加載信息Function Starts
?? 入口函數(shù)Symbol Table
?? 符號(hào)表Dynamic Symbol Table
?? 動(dòng)態(tài)庫符號(hào)表String Table
?? 字符串表Code Signature
?? 代碼簽名
驗(yàn)證
我們知道夷陋,獲取類名
可以用_objc_classname
, 獲取方法名
可以用_objc_methname
,但是這兩個(gè)數(shù)據(jù)怎么串聯(lián)匹配起來的胰锌?根據(jù)查相關(guān)資料骗绕,是通過__objc_classlist
來映射的。
驗(yàn)證該問題需借助2個(gè)工具 ?? MachOView
和Hopper
资昧。
-
MachOView
中打開Mach-O文件酬土,直接看__objc_classlist
??
我們選擇第一個(gè)地址,在Hopper
中看看102725E28
(按G
搜索)??
雙擊格带,對應(yīng)到__objc_class
??
而__objc_class
對應(yīng)的源碼??
typedef struct objc_class{
struct __objc_class* isa;
struct __objc_class* superclass;
struct __objc_cache* cache;
struct __objc_vtable* vtable;
struct __objc_ data* data;
}objc_class;
- 第1個(gè)成員是
isa
指針诺凡,指向了MetaClass
,對應(yīng)的地址是102badf90
??
- 第2個(gè)成員是指向父類的指針践惑,對應(yīng)地址為
0000000000000000
- 第5個(gè)成員指向
__objc_ data
腹泌,雙擊它,對應(yīng)的地址為102737e30
??
接著我們看看__objc_data
對應(yīng)的數(shù)據(jù)結(jié)構(gòu)源碼??
typedef struct objc_data{
uint32_t flags;
uint32_t instanceStart;
uint32_t instanceSize;
uint32_t reserved;
void* ivarlayout;
char* name;
struct __objc_method_list* baseMethod;
struct __objc_protos* baseProtocol;
struct __objc_ivars* ivars;
struct __objc_ivars weakIvarLayout;
struct __objc_ivars baseProperties;
}
主要的幾個(gè)成員??
- 第6個(gè)成員
name
保存的類名
尔觉,對應(yīng)的地址是0x102445615
該地址對應(yīng)的類名稱是_AFURLSessionTaskSwizzling
凉袱,至此,找到了類名稱
。
- 第7個(gè)成員
baseMethod
保存了類所有方法专甩,一樣钟鸵,對應(yīng)的地址是102737de0
??
接著查看__objc_method_list
的源碼??
typedef struct objc_method_list{
uint32_t flags;
uint32_t count;
}
使用到的數(shù)據(jù)主要是count
,對應(yīng)數(shù)據(jù)為3
,對應(yīng)10進(jìn)制
數(shù)也是3
涤躲,說明有3個(gè)方法
??
具體方法對應(yīng)的數(shù)據(jù)結(jié)構(gòu)為??
typedef struct objc_method{
char* name;
char* signature;
void* implementation;
}
objc_method_list
結(jié)構(gòu)體占用8(4+4)字節(jié)棺耍,而__objc_method_list
的地址是0000000102737de0
+ 8字節(jié) = 第1個(gè)方法
的地址0000000102737de8
,objc_method
結(jié)構(gòu)體占用24(8*3)字節(jié)种樱,再加24字節(jié)得到第2個(gè)方法
的地址0000000102737e00
蒙袍,同理再加24字節(jié)得到第3個(gè)方法
的地址0000000102737e18
。
接著我們在MachOView
中查看第1個(gè)方法的地址0000000102737de8
??
上圖中嫩挤,0000000102737de8
中存儲(chǔ)的第一個(gè)8字節(jié)
地址是0102331F27
害幅,再去到Hopper
中搜索該地址??
同理,第2個(gè)8字節(jié)
地址是01023326C4
??
第3個(gè)8字節(jié)
地址是010232C51D
??
至此岂昭,我們從__objc_classlist
中查找地址以现,首先通過__objc_class
的isa
指針找到類名稱
,接著找到下面的成員變量base method
的地址约啊,找到objc_method_list
方法列表邑遏,再根據(jù)objc_method
結(jié)構(gòu)體大小,計(jì)算內(nèi)存平移
后的地址恰矩,找到了所有的方法名稱
无宿。
以上就是dyld加載類名并關(guān)聯(lián)方法列表
的一個(gè)示例過程。
總結(jié)
- Mach-O屬于一種文件格式
- 包含:可執(zhí)行文件枢里、靜態(tài)庫、動(dòng)態(tài)庫蹂午、dyld等
- 可執(zhí)行文件:
- 通用二進(jìn)制文件:集合了多種架構(gòu)
- lipo命令
- -info 查看架構(gòu)
- ‐thin 拆分架構(gòu)
- ‐creat 合并架構(gòu)
- Mach-O結(jié)構(gòu)
- Header:用于快速確定文件的CPU類型栏豺、文件類型等
- Load Commands:指示加載器(例如dyld)如何設(shè)置并且加載二進(jìn)制數(shù)據(jù)
- Data:存放數(shù)據(jù)??
- 代碼
- 數(shù)據(jù)
- 字符串常量
- 類
- 方法