你們好,這篇我開始學習函數了.先學 C 函數,而後再 OC 的吧.OC 應該複雜點的吧.算法
而後看看彙編狀況哦!xcode
學習函數呢,確定要弄清楚幾個事情.sass
1.跳轉地址.函數
2.返回地址學習
3.參數spa
4.函數獲取參數3d
5.返回值和如何返回指針
6.掃尾調試
咱們開始了哦!1個個的突破!唉,這個學習筆記是一邊學一邊寫,不知道到底能不能邊寫邊突破呢.小馬過河,試試吧.呵呵.code
1.跳轉地址.由於xcode默認反彙編的時候,並無顯示出機器碼,因此這裏,咱們要用一個命令去顯示:disassemble -fmb
咱們發現這樣子呢就能夠看到機器碼了.而後,bl就是call了哦.bl後面的0x18dc4就是具體的函數代碼地址了.這裏,咱們要從機器碼中學習下跳轉地址是如何計算的.咱們知道在x86中是這樣計算的:
call指令的地址 +call指令的長度- 偏移量 = 跳轉地址.課是這裏我卡住了.
0x18dfe: 0xf7ffffe1 bl 0x18dc4 ; Add at main.m:13
我剛纔忙乎了會,實在是沒想出來算法.這裏,我先作個記號.咱們先學習下面的內容.
2.返回地址
咱們從代碼中能夠看到bl(call)指令後的返回地址是 0x18e02 .咱們腦子裏首先浮現是x86平臺,返回地址是存放在ESP寄存器中的.經過 ESP 寄存器的地址取內容就是返回地址.可是咱們如今在 IOS 中.IOS 中我尚未發現 ESP 寄存器.那麼只有一個辦法.咱們把進入函數前和進入函數後的寄存器都打印出來對比下.
進入函數前 進入函數後
咱們看到進入函數後有一個寄存器叫lr或者叫r14的值與咱們的0x18e02最接近.可是爲何會多1個1呢.哈哈,目前還未知啊!不過咱們再看看函數的反彙編
在最後有bx lr ,既然這樣,這條指令又在最後面,一個函數結束了確定要返回的.因此說咱們就能夠認定lr寄存器就是放入的函數返回值.
3.參數
咱們再看看這個圖
咱們程序傳入的參數是1和2.咱們從反彙編看到,1和2 被傳入了r2和r3.只是咱們目前在調試版下進行的實驗,因此編譯器作了些無用功.
可是最後咱們發現,r2,r3是給了r0和r1.而後立刻就跳轉到函數了.那麼說明,r0,r1作爲傳遞參數的可能性最大.可是數據量大的時候怎麼辦的呢
等下回再分析了,呵呵.
4.函數獲取參數
咱們再看看這個截圖呢
暈!調試版的程序就是比較麻煩啊.咱們看到
0x18dc6: str r0, [sp, #0x8]
0x18dc8: str r1, [sp, #0x4]
0x18dca: ldr r0, [sp, #0x8]
0x18dcc: ldr r1, [sp, #0x4]
這笨蛋編譯器把r0和r1中的參數又放到了棧裏,又從棧裏取回到原處.
這裏的緣由是由於調試版,,爲何ro和r1寄存器中的值剛剛保存,立刻又將其加載回來.
可是至少咱們知道.取函數,就是直接從寄存器裏面取的了.
5.返回值和如何返回
從上面的截圖咱們知道
0x18dce: add r0, r1
返回值放入了r0中了.
而後呢
0x18dd4: add sp, #0xc
由於以前呢
0x18dc4: sub sp, #0xc
因此如今必須把12加回去.由於必須確保棧指針的正確性,否則棧指針會指向錯誤的地方了哦.!
咱們以前要減12呢.其實目前來看,就是預留了12個字節的空間.
6.掃尾了哦!
0x18dd6: bx lr
最後,執行bx指令會回到調用函數的地方.還記得lr嗎,放的是函數的返回地址哦.
至此函數就分析完了,可是我忘記了一個事情,就是沒有在函數裏放置局部變量.等下次我再加入局部變量分析了哦!學習過x86肯定對看 IOS arm也有幫助.其實關鍵是分析思路哦!要根據蛛絲馬跡重現犯罪現場哦!
固然後面會繼續分析 OC 的方法,但願不要太難了哦!