1.OC反匯編
objc_msgSend中存在兩個(gè)參數(shù)(id,SEL),id類型實(shí)質(zhì)上是一個(gè)結(jié)構(gòu)體指針類型委煤,SEL是一個(gè)選擇器
x8寄存器中存放的是一個(gè)地址0x1021295b0茫虽,將x8寄存器中存放的地址值讀取8個(gè)字節(jié)內(nèi)容存放到x0寄存器中
再將x8寄存器中存放的一個(gè)地址0x1021295a0觉增,讀取8個(gè)字節(jié)內(nèi)容存放到x1寄存器中
將x0,x1的值傳入objc_msgSend方法中
(lldb) x 0x1021295b0
0x1021295b0: 98 96 12 02 01 00 00 00 d0 95 12 02 01 00 00 00 ................
0x1021295c0: 08 00 00 00 10 00 00 00 08 00 00 00 00 00 00 00 ................
(lldb) po 0x0102129698
Person
(lldb) x 0x1021295a0
0x1021295a0: 05 3d 2a 8b 01 00 00 00 00 00 00 00 00 00 00 00 .=*.............
0x1021295b0: 98 96 12 02 01 00 00 00 d0 95 12 02 01 00 00 00 ................
(lldb) po (SEL)0x018b2a3d05
"person"
(lldb) register read x0
x0 = 0x0000000102129698 (void *)0x000001a102129671
(lldb) register read x1
x1 = 0x000000018b2a3d05 "person"
(lldb)
通過objc_msgSend方法分析就能還原方法的調(diào)用
進(jìn)入[Person person]方法后發(fā)現(xiàn)赶撰,系統(tǒng)的alloc和init在iOS11以后沒有走objc_msgSend方法了,
根據(jù)系統(tǒng)的版本不同,而會(huì)有不同的優(yōu)化,iOS11.0的系統(tǒng)中alloc不會(huì)調(diào)用objc_msgSend方法了,而init還會(huì)調(diào)用objc_msgSend方法莹捡,如下是iOS11.0系統(tǒng)真機(jī)
objc_msgSend方法中沒有看到x0賦值,可以推測(cè)objc_alloc的返回值又賦值給了x0傳入到了objc_msgSend方法,讀取x0為init方法扣甲,讀取x1為Person實(shí)例對(duì)象<Person: 0x1c402e8e0>篮赢,為objc_msgSend的兩個(gè)參數(shù)id self和SEL _cmd
最初的版本[[self alloc] init]會(huì)有兩次消息發(fā)送齿椅,如iOS9.0
到了iOS11.0只有init會(huì)走消息發(fā)送
到了iOS13.0都不會(huì)走消息發(fā)送了
執(zhí)行完[Person person]方法后,返回值存放在x0启泣,是一個(gè)Person實(shí)例對(duì)象
會(huì)進(jìn)入objc_storeStrong函數(shù)涣脚,OC中用strong修飾的對(duì)象都會(huì)調(diào)用這個(gè)函數(shù),main中有個(gè)局部變量寥茫,相當(dāng)于有個(gè)強(qiáng)引用在引用它Person *person = [Person person],這一句代碼相當(dāng)于讓p銷毀了遣蚀,函數(shù)調(diào)用棧要平衡了
將x0存到x8指向的地址空間,x0為objc_msgSend的返回值&p
x8的值賦值給x0
0賦值給x1
(lldb) register read x0
x0 = 0x00000001c4039d60
(lldb) po 0x00000001c4039d60
<Person: 0x1c4039d60>
傳入objc_storeStrong方法纱耻,x0 = *location = &p;
obj = nil,
即p = nil,
id = prev = *location = person對(duì)象
*location = person對(duì)象 = obj = nil
objc_release(prev) = objc_release(person對(duì)象)回收堆空間
release p
棧平衡時(shí)回收棸盘荩空間釋放p指針變量的地址
2.通過工具分析OC反匯編
將Product下生成的MachO文件直接拖入Hopper Disassembler v4中
雙擊OBJC_CLASS$_Person得到Person類的地址在1000096c8
雙擊Selector,person
MachO中分析匯編代碼的時(shí)候根據(jù)地址能找到字符串,找到字符串后根據(jù)類型知道是什么弄喘,有類玖喘,類的引用,方法的名稱限次,放在不同的位置代表不同的意義,hopper和MachOView都是根據(jù)特定的格式讀取MachO文件
3.Block的反匯編
I.不引用外部變量的block
讀取寄存器x0發(fā)現(xiàn)此block是一個(gè)全局block,全局靜態(tài)block不引用外部變量,在編譯器確定內(nèi)存分配柴灯,存在于MachO文件中的可執(zhí)行文件常量區(qū)
Block本質(zhì)是結(jié)構(gòu)體卖漫,isa指針8字節(jié),為全局block赠群、棧區(qū)block羊始、堆區(qū)block,flags占用4個(gè)字節(jié),reserved占用4字節(jié)查描,invoke中的內(nèi)容是16個(gè)字節(jié)之后的內(nèi)容突委,descriptor是底層問題描述
通過反匯編工具Hopper查看invoke中的內(nèi)容,雙擊全局block,查看block結(jié)構(gòu)
雙擊invoke,invoke中的內(nèi)容都顯示出來
descriptor在block的上方
II.引用外部變量的block
isa指針指向棧block
讀取invoke冬三,通過dis -s invoke內(nèi)存地址讀取到
hopper工具分析:雙擊invoke,雙擊descriptor查看
hopper查看流程圖
流程圖如下匀油,if判斷可以通過過匯編代碼分析,但沒有圖分析顯示分期的
查看偽代碼:還原main函數(shù)