函數(shù)的本質(zhì)
關(guān)于CPU的補(bǔ)充
寄存器
CPU由: 控制器, 計算器和寄存器組成. 其中寄存器的作用就是將數(shù)據(jù)進(jìn)行臨時存儲
CPU的運(yùn)行速度非乘钔担快,為了性能CPU會在內(nèi)部開辟一小塊臨時存儲區(qū)域, 并在運(yùn)算時先將數(shù)據(jù)從內(nèi)存復(fù)制到這小塊臨時存儲區(qū)域中, 在這小塊區(qū)域進(jìn)行運(yùn)算,這小塊臨時區(qū)域就稱作寄存器.
-
對于ARM64架構(gòu)的CPU, 以 X 開頭的就是64位的寄存器, 以 W 開頭的就是32位的寄存器, 其中32位寄存器就是64位寄存器的低32位部分
Snip20180422_33.png
Snip20180422_34.png
系統(tǒng)中沒有提供16位 和 8位的寄存器供以訪問(注意: 查看時要使用真機(jī)調(diào)試, 模擬器使用的X86的架構(gòu))
高速緩存
iPhoneX搭載的ARM64處理器A11, 它的一級緩存容量是64KB, 二級緩存容量是8M (現(xiàn)在普遍也只有二級緩存)
CPU每執(zhí)行一條指令都需要從內(nèi)存中將指令讀取到CPU中執(zhí)行, 而寄存器運(yùn)行速度要比內(nèi)存的讀寫速度快很多, CPU還集成了一個高速緩存存儲區(qū)域來提高性能. 當(dāng)程序運(yùn)行時, 先將要執(zhí)行的指令代碼存儲到高速緩存存儲區(qū)域中(由操作系統(tǒng)完成), CPU直接從高速緩存中依次讀取指令來執(zhí)行.
寄存器的補(bǔ)充
數(shù)據(jù)地址存儲器
數(shù)據(jù)地址存儲器通常作為數(shù)據(jù)計算的臨時存儲, 做累加, 計數(shù)地址保存等功能. 這些寄存器的作用主要用于在CPU指令中保存操作數(shù), 在CPU中當(dāng)做常規(guī)變量使用.
ARM64中
- 64位: X0 - X30 , XZR(零寄存器)
- 32位: W0 - W30 , WZR(零寄存器)
注意: 8086匯編中有一種寄存器, 段寄存器: CS, ES, DS, SS四個寄存器用來保存段的基地址, 這屬于Intel CPU中, 在ARM中沒有.
浮點(diǎn)和向量寄存器
現(xiàn)在CPU支持向量運(yùn)算(向量運(yùn)算在圖形處理中使用比較廣泛), 為支持向量運(yùn)算, 故提供了更多向量寄存器.
- 向量寄存器: 128位 v0 - v128
因為浮點(diǎn)數(shù)以及其運(yùn)算的特殊性, CPU專門提供浮點(diǎn)寄存器來計算浮點(diǎn)數(shù)
- 浮點(diǎn)寄存器: 64位s0 - s31 和 32位d0 - d31
棧
-
棧: 是一種具有特殊方式的訪問存儲空間(先進(jìn)后出)
15193998892055.jpg
sp, fp寄存器
- sp寄存器會在任意時刻保存棧頂?shù)牡刂?/li>
- fp寄存器也成為x29寄存器屬于通用寄存器, 但是在某些時刻我們會用它保存棧底的地址
注意: ARM64開始取消32位的LDM, STM, PUSH, POP指令. 與之替代的是 ldr/ ldp, str/ stp
ARM64里面 對棧的操作都是16進(jìn)制對齊的!!!
關(guān)于內(nèi)存的讀寫指令
注意: 讀/寫 數(shù)據(jù)都是往高地址讀/寫
str(store register)寫入指令
將數(shù)據(jù)從寄存器中讀出來, 寫入到內(nèi)存中
ldr(load register)讀取指令
將數(shù)據(jù)從內(nèi)存中讀取出來, 存到寄存器中
ldp/stp 是 ldr/str 的衍生, 可以同時讀/寫兩個寄存器, ldr/str只能讀寫一個
匯編代碼--堆棧操作練習(xí)
使用32字節(jié)空間作為這段程序的棧空間, 然后利用棧將x0, x1的值進(jìn)行交換
sub sp, sp, #0x20 ; 拉伸椏敢兀空間32(20 = 2*16)個字節(jié)
stp x0 , x1, [sp, #0x10] ; sp往上加16(10 = 1 * 16)個字節(jié),存放x0 和 x1
ldp x1 , x0, [sp, #0x10] ; 將sp偏移16個字節(jié)的值取出來,放入x1 和 x0
注意: 拉伸椂峥耍空間是往低地址拉伸, 拉伸的字節(jié)數(shù)只能是16的倍數(shù), 否則會崩潰(對照上面 16進(jìn)制對齊理解 )
第一句代碼: sp = sp - #0x20, 將sp的地址往低地址偏移32個字節(jié)
有sub就會有add, 這就是棧平衡, 如果只有sub沒有add, 會導(dǎo)致內(nèi)存不夠用, 堆棧溢出
第二,三句代碼: sp指向的地址不會變, 只是將x0, x1的值從相應(yīng)地址存入或讀取.
bl 和 ret 指令
bl: 跳轉(zhuǎn)指令
1. 將下一條指令的地址存放到 lr(x30) 寄存器中
2. 跳轉(zhuǎn)到對應(yīng)函數(shù)中執(zhí)行指令
ret: 返回指令
默認(rèn)使用 lr(x30) 寄存器的值, 通過底層指令提示CPU這是下一條指令的地址.
ARM64架構(gòu)中的特色指令, 面向硬件做了優(yōu)化處理
lr (x30) 寄存器
- x30寄存器存放的是函數(shù)返回的地址, 當(dāng)ret執(zhí)行指令時, 會尋找這個寄存器中保存的地址
注意: 在函數(shù)嵌套調(diào)用中, 需要將x30入棧, 否則可能會造成死循環(huán).
函數(shù)的參數(shù)和返回值
ARM64下, 參數(shù)都是保存在x0-x7 (w0-w7) 這8個寄存器中, 如果超過這8個參數(shù)就會入棧, 函數(shù)的返回值是放在 x0寄存器中的.
函數(shù)的局部變量
函數(shù)的局部變量都是保存在棧里面.
好了, 第三篇對于初識匯編的復(fù)習(xí)和梳理就到這了