CPU包括控制器癞尚、運算器、寄存器乱陡。其中寄存器的作用就是進(jìn)行數(shù)據(jù)的臨時存儲浇揩。
CPU的運算速度是非常快的憨颠,為了性能CPU在內(nèi)部開辟一小塊臨時存儲區(qū)域胳徽,并在進(jìn)行運算時先將數(shù)據(jù)從內(nèi)存復(fù)制到這一小塊臨時存儲區(qū)域中,運算時就在這一小快臨時存儲區(qū)域內(nèi)進(jìn)行爽彤。我們稱這一小塊臨時存儲區(qū)域為寄存器膜廊。
對于arm64系的CPU來說, 如果寄存器以x開頭則表明的是一個64位的寄存器淫茵,如果以w開頭則表明是一個32位的寄存器爪瓜,在系統(tǒng)中沒有提供16位和8位的寄存器供訪問和使用。其中32位的寄存器是64位寄存器的低32位部分并不是獨立存在的匙瘪。
高速緩存
iPhoneX上搭載的ARM處理器A11它的1級緩存的容量是64KB铆铆,2級緩存的容量8M.
CPU每執(zhí)行一條指令前都需要從內(nèi)存中將指令讀取到CPU內(nèi)并執(zhí)行。而寄存器的運行速度相比內(nèi)存讀寫要快很多,為了性能,CPU還集成了一個高速緩存存儲區(qū)域.當(dāng)程序在運行時丹喻,先將要執(zhí)行的指令代碼以及數(shù)據(jù)復(fù)制到高速緩存中去(由操作系統(tǒng)完成).CPU直接從高速緩存依次讀取指令來執(zhí)行.
寄存器
內(nèi)部部件之間由總線連接
- 對程序員來說薄货,CPU中最主要部件是寄存器,可以通過改變寄存器的內(nèi)容來實現(xiàn)對CPU的控制
- 不同的CPU碍论,寄存器的個數(shù)谅猾、結(jié)構(gòu)是不相同的
通用寄存器
-
ARM64擁有有31個64位的通用寄存器 x0 到 x30,這些寄存器通常用來存放一般性的數(shù)據(jù),稱為通用寄存器(有時也有特定用途)
- 那么w0 到 w28 這些是32位的. 因為64位CPU可以兼容32位.所以可以只使用64位寄存器的低32位.
- 比如 w0 就是 x0的低32位!
image.png
- 通常鳍悠,CPU會先將內(nèi)存中的數(shù)據(jù)存儲到通用寄存器中税娜,然后再對通用寄存器中的數(shù)據(jù)進(jìn)行運算
-
假設(shè)內(nèi)存中有塊紅色內(nèi)存空間的值是3,現(xiàn)在想把它的值加1藏研,并將結(jié)果存儲到藍(lán)色內(nèi)存空間
image.png
- CPU首先會將紅色內(nèi)存空間的值放到X0寄存器中:mov X0,紅色內(nèi)存空間
- 然后讓X0寄存器與1相加:add X0,1
- 最后將值賦值給內(nèi)存空間:mov 藍(lán)色內(nèi)存空間,X0
pc寄存器(program counter)
-
為指令指針寄存器敬矩,它指示了CPU當(dāng)前要讀取指令的地址
image.png
image.png
- 在內(nèi)存或者磁盤上,指令和數(shù)據(jù)沒有任何區(qū)別蠢挡,都是二進(jìn)制信息
- CPU在工作的時候把有的信息看做指令弧岳,有的信息看做數(shù)據(jù)凳忙,為同樣的信息賦予了不同的意義
- 比如 1110 0000 0000 0011 0000 1000 1010 1010
- 可以當(dāng)做數(shù)據(jù) 0xE003008AA
- 也可以當(dāng)做指令 mov x0, x8
- CPU根據(jù)什么將內(nèi)存中的信息看做指令?
- CPU將pc指向的內(nèi)存單元的內(nèi)容看做指令
- 如果內(nèi)存中的某段內(nèi)容曾被CPU執(zhí)行過禽炬,那么它所在的內(nèi)存單元必然被pc指向過
棧
-
棧:是一種具有特殊的訪問方式的存儲空間(后進(jìn)先出涧卵, Last In Out Firt,LIFO)
image.png
image.png
SP和FP寄存器
- sp寄存器在任意時刻會保存我們棧頂?shù)牡刂?
- fp寄存器也稱為x29寄存器屬于通用寄存器,但是在某些時刻我們利用它保存棧底的地址!()
注意:ARM64開始,取消32位的 LDM,STM,PUSH,POP指令! 取而代之的是ldr\ldp str\stp
ARM64里面 對棧的操作是16字節(jié)對齊的!!
狀態(tài)寄存器
???CPU內(nèi)部的寄存器中,有一種特殊的寄存器(對于不同的處理器,個數(shù)和結(jié)構(gòu)都可能不同).這種寄存器在ARM中,被稱為狀態(tài)寄存器就是CPSR(current program status register)寄存器
CPSR和其他寄存器不一樣,其他寄存器是用來存放數(shù)據(jù)的,都是整個寄存器具有一個含義.而CPSR寄存器是按位起作用的,也就是說,它的每一位都有專門的含義,記錄特定的信息.
注:CPSR寄存器是32位的
- CPSR的低8位(包括I腹尖、F艺演、T和M[4:0])稱為控制位,程序無法修改,除非CPU運行于特權(quán)模式下,程序才能修改控制位!
- N桐臊、Z、C晓殊、V均為條件碼標(biāo)志位断凶。它們的內(nèi)容可被算術(shù)或邏輯運算的結(jié)果所改變,并且可以決定某條指令是否被執(zhí)行!意義重大!
N(Negative)標(biāo)志
CPSR的第31位是 N巫俺,符號標(biāo)志位认烁。它記錄相關(guān)指令執(zhí)行后,其結(jié)果是否為負(fù).如果為負(fù) N = 1,如果是非負(fù)數(shù) N = 0.
???注意,在ARM64的指令集中,有的指令的執(zhí)行時影響狀態(tài)寄存器的,比如add\sub\or等,他們大都是運算指令(進(jìn)行邏輯或算數(shù)運算);
Z(Zero)標(biāo)志
CPSR的第30位是Z介汹,0標(biāo)志位却嗡。它記錄相關(guān)指令執(zhí)行后,其結(jié)果是否為0.如果結(jié)果為0.那么Z = 1.如果結(jié)果不為0,那么Z = 0.
???對于Z的值,我們可以這樣來看,Z標(biāo)記相關(guān)指令的計算結(jié)果是否為0,如果為0,則N要記錄下"是0"這樣的肯定信息.在計算機中1表示邏輯真,表示肯定.所以當(dāng)結(jié)果為0的時候Z = 1,表示"結(jié)果是0".如果結(jié)果不為0,則Z要記錄下"不是0"這樣的否定信息.在計算機中0表示邏輯假,表示否定,所以當(dāng)結(jié)果不為0的時候Z = 0,表示"結(jié)果不為0"。
C(Carry)標(biāo)志
CPSR的第29位是C嘹承,進(jìn)位標(biāo)志位窗价。一般情況下,進(jìn)行無符號數(shù)的運算。
加法運算:當(dāng)運算結(jié)果產(chǎn)生了進(jìn)位時(無符號數(shù)溢出)叹卷,C=1撼港,否則C=0。
減法運算(包括CMP):當(dāng)運算時產(chǎn)生了借位時(無符號數(shù)溢出)骤竹,C=0帝牡,否則C=1。
???對于位數(shù)為N的無符號數(shù)來說蒙揣,其對應(yīng)的二進(jìn)制信息的最高位靶溜,即第N - 1位,就是它的最高有效位懒震,而假想存在的第N位罩息,就是相對于最高有效位的更高位。如下圖所示:
進(jìn)位
???我們知道个扰,當(dāng)兩個數(shù)據(jù)相加的時候扣汪,有可能產(chǎn)生從最高有效位向更高位的進(jìn)位。比如兩個32位數(shù)據(jù):0xaaaaaaaa + 0xaaaaaaaa,將產(chǎn)生進(jìn)位锨匆。由于這個進(jìn)位值在32位中無法保存崭别,我們就只是簡單的說這個進(jìn)位值丟失了冬筒。其實CPU在運算的時候,并不丟棄這個進(jìn)位制茅主,而是記錄在一個特殊的寄存器的某一位上舞痰。ARM下就用C位來記錄這個進(jìn)位值。比如诀姚,下面的指令
mov w0,#0xaaaaaaaa响牛;0xa 的二進(jìn)制是 1010
adds w0,w0,w0; 執(zhí)行后 相當(dāng)于 1010 << 1 進(jìn)位1(無符號溢出) 所以C標(biāo)記 為 1
adds w0,w0,w0赫段; 執(zhí)行后 相當(dāng)于 0101 << 1 進(jìn)位0(無符號沒溢出) 所以C標(biāo)記 為 0
adds w0,w0,w0呀打; 重復(fù)上面操作
adds w0,w0,w0
借位
???當(dāng)兩個數(shù)據(jù)做減法的時候,有可能向更高位借位糯笙。再比如贬丛,兩個32位數(shù)據(jù):0x00000000 - 0x000000ff,將產(chǎn)生借位,借位后给涕,相當(dāng)于計算0x100000000 - 0x000000ff豺憔。得到0xffffff01 這個值。由于借了一位够庙,所以C位 用來標(biāo)記借位恭应。C = 0.比如下面指令:
"mov w0,#0x7fffffff\n" //寄存器 cpsr = 0x60000000 0110
"adds w0,w0,#0x2\n" //寄存器 cpsr = 0x90000000 1001
"mov w0,#0x80000000\n" //寄存器 cpsr =0x90000000 1001
"subs w0,w0,#0x2\n" //寄存器 cpsr = 0x30000000 0011
V(Overflow)溢出標(biāo)志
CPSR的第28位是V,溢出標(biāo)志位耘眨。在進(jìn)行有符號數(shù)運算的時候昼榛,如果超過了機器所能標(biāo)識的范圍,稱為溢出剔难。
- 正數(shù) + 正數(shù) 為負(fù)數(shù) 溢出
- 負(fù)數(shù) + 負(fù)數(shù) 為正數(shù) 溢出
- 正數(shù) + 負(fù)數(shù) 不可能溢出
關(guān)于內(nèi)存讀寫指令
注意:讀/寫 數(shù)據(jù)是都是往高地址讀/寫
str(store register)指令
將數(shù)據(jù)從寄存器中讀出來,存到內(nèi)存中.
ldr(load register)指令
將數(shù)據(jù)從內(nèi)存中讀出來,存到寄存器中
此ldr 和 str 的變種ldp 和 stp 還可以操作2個寄存器.
堆棧操作練習(xí)
使用32個字節(jié)空間作為這段程序的棸伲空間,然后利用棧將x0和x1的值進(jìn)行交換.
sub sp, sp, #0x20 ;拉伸棧空間32個字節(jié)
stp x0, x1, [sp, #0x10] ;sp往上加16個字節(jié),存放x0 和 x1
ldp x1, x0, [sp, #0x10] ;將sp偏移16個字節(jié)的值取出來,放入x1 和 x0
bl和ret指令
bl標(biāo)號
- 將下一條指令的地址放入lr(x30)寄存器
-
轉(zhuǎn)到標(biāo)號處執(zhí)行指令
image.png
ret
- 默認(rèn)使用lr(x30)寄存器的值,通過底層指令提示CPU此處作為下條指令地址!
ARM64平臺的特色指令,它面向硬件做了優(yōu)化處理的
x30寄存器
x30寄存器存放的是函數(shù)的返回地址.當(dāng)ret指令執(zhí)行時刻,會尋找x30寄存器保存的地址值!
注意:在函數(shù)嵌套調(diào)用的時候.需要講x30入棧!
adrp
是計算指定的數(shù)據(jù)地址到當(dāng)前PC值的相對偏移钥飞。
/*1.先將1的值左移12位二進(jìn)制位則為 1 0000 0000 0000 ==> 0x1000
*2.將 PC 寄存器的低12位清零莺掠,也就是0x100c1e6c4 ==> 0x100c1f000
*/
0x100c1e6c4 <+36>: adrp x0, 1
//0x100c1f000 + 0x65c ==> 0x100c1f65c也就是說這個常量所對應(yīng)的值得地址是0x100c1f65c
0x100c1e6c8 <+40>: add x0, x0, #0x65c ; =0x65c
memory read X //簡寫memory read 簡寫x
0x100400e48: d9 55 2b a5 01 00 00 00 c1 eb 3f 00 01 00 00 00
0x100400e58: ac c7 a0 8c 01 00 00 00 f8 0e 40 00 01 00 00 00
//iOS是從右邊向左讀10位 0x 01 a5 2b 55 d9
p (char *)0x01a52b55d9 //實際是什么類型,就強轉(zhuǎn)成什么類型
bl指令
CPU從何處執(zhí)行指令是由pc中的內(nèi)容決定的读宙,我們可以通過改變pc的內(nèi)容來控制CPU執(zhí)行目標(biāo)指令
-
ARM64提供了一個mov指令(傳送指令)彻秆,可以用來修改大部分寄存器的值,比如
- mov x0,#10结闸、mov x1,#20
但是唇兑,mov指令不能用于設(shè)置pc的值,ARM64沒有提供這樣的功能
ARM64提供了另外的指令來修改PC的值桦锄,這些指令統(tǒng)稱為轉(zhuǎn)移指令扎附,最簡單的是bl指令
bl指令 -- 練習(xí)
現(xiàn)在有兩段代碼!假設(shè)程序先執(zhí)行A,請寫出指令執(zhí)行順序.最終寄存器x0的值是多少?
_A:
mov x0,#0xa0
mov x1,#0x00
add x1, x0, #0x14
mov x0,x1
bl _B
mov x0,#0x0
ret
_B:
add x0, x0, #0x10
ret