Objective-C 是以 C 語言為基礎的,
PC 上,在 C 語言中對null 指標進行操作,
程式會由于越界訪問而出現保護錯進而崩潰。
原因需要從原始碼中尋找,
下面是 objc_msgSend 的 arm 版彙編程式碼片段:
在 arm 的函數調用過程中,
一般用 r0-r4 傳遞參數,
用 r0 傳遞傳回值。
對應 objc_msgSend,第一個參數為 self,傳回值也是 self,都放在 r0(a1)中。
/******************************************************************** * idobjc_msgSend(id self, SEL op, ...) * On entry: a1 is the message receiver, * a2 is the selector ********************************************************************/ENTRY objc_msgSend# check whether receiver is nilteq a1, #0 //語句一:判斷self是不是空moveq a2, #0 //如果語句一判斷self是空,那麼也要把SEL置空,否則不執行這句bxeq lr //如果語句一判斷self是空就返回到調用 objc_msgSend 的地方繼續執行
teq 指令說明:
TEQ Rn, Operand2
The TEQ instruction performs a bitwise(逐位,按位) Exclusive OR operation on the value in Rn and the value of Operand2.
逐位和0異或,判斷是不是0
測試 self 是否為空白。
moveq 指令說明:
如果self為空白,則將 selector 也設定為空白。
bx 指令說明:
在 arm 中 bx lr 用來返回到調用子程式的地方(即:返回到調用者),此處是:如果 self 為空白,就返回到調用 objc_msgSend 的地方繼續執行。
總之:
如果傳遞給 objc_msgSend 的 self 參數是 nil,該函數不會執行有意義的操作,直接返回。
ARM彙編指令
1.條件執行尾碼:
在ARM彙編指令後面加條件執行尾碼,用來決定這條語句是否會被執行
mov r0, r1: 相當於C語言中的r0 = r1;
moveq r0, r1:
如果eq尾碼成立,則直接執行mov r0, r1;
如果eq不成立則本句代碼直接作廢,相當於沒有。
類似於C語言中 if (eq) {r0 = r1;}
條件尾碼執行注意點:
1)、條件尾碼是否成立,不是取決於本句代碼,而是取決於這句代碼之前的代碼運行後的結果。
2)、條件尾碼決定了本句代碼是否被執行,而不會影響上一句和下一句代碼是否被執行。
2.比較指令 CMP
• CMP指令:比較兩個運算元,並把結果存入CPSR供下一句語句使用
CMP R0,R1; 比較R0,R1;等價於 sub r2, r0, r1 (r2 = r0 - r1)
CMN R0,R1; 等價於 add r0, r1
tst r0, #0xf; 測試r0的bit0~bit3是否全為0
teq: TEQ是對2個數,進行EOR(異或)
注意:比較指令用來比較2個寄存器中的數,比較指令不用後加s尾碼就可以影響cpsr中的標誌位。
3.跳躍陳述式 B/BL/BX
在 ARM 程式中有兩種方法可以實現程式流程的跳轉:
• 使用專門的跳轉指令 B
• 直接向程式計數器PC寫入跳轉地址值,這幾乎是任何一種CPU必備的,PC表示CPU當 前執行語句位置,改變PC的值,相當於實現程式跳轉,類似C語言的Return 語句。用 MOV PC,LR,這裡可以在任意4G的空間進行跳轉。
• 與MOV PC,XXX能在4G空間跳轉不同,B語句只能32M空間跳轉(因為位移量是一個 有符號26bit的數值=32M)
B指令(Branch)表示無條件跳轉。例:B main ; 跳轉到標號為main的代碼處
BL指令(Branch with Link)表示帶傳回值的跳轉,跳轉前把返回地址放入lr中,以便返回。例:BL delay ; 執行子函數或程式碼片段 delay,delay可以為C函數。
BL比B多做一步,在跳轉前,BL會把當前位置儲存在R14(即LR寄存器),當跳轉代碼結束後,用MOV PC,LR指令跳回來,這實際上就是C語言執行函數的用法。彙編裡調子程式都用BL執行完子函數後,用MOV PC,LR跳回來。