文章目錄
- 一、ARMv8寄存器介紹
- 二、通用寄存器
- 三、 PSTAE寄存器
- 四、特殊寄存器
- 五、系統寄存器
一、ARMv8寄存器介紹
本文我來給大家介紹一下ARMv8的寄存器部分,ARMv8中有34個寄存器,包括31個通用寄存器、一個棧指針寄存器SP(X31),一個程序計數器寄存器PC,一個處理器狀態寄存器PSTATE(在ARMv7架構中使用程序狀態寄存器(Current Program Status Register,CPSR)來表示當前的處理器狀態(processor stste),而在ARMv8里使用PSTATE寄存器來表示)。
寄存器 | 位數 | 描述 |
---|---|---|
X0-X30 | 64bit | 通用寄存器,如果有需要可以當作32bit使用:W0-W30 |
FP(X29) | 64bit | 保存棧幀地址(棧底指針) |
LR(X30) | 64bit | 程序鏈接寄存器,保存子程序結束后需要執行的下一條指令 |
SP | 64bit | 保存棧指針,使用SP/WSP來進行對SP寄存器的訪問。 |
PC | 64bit | 程序計數器,俗稱PC指針,總是指向即將要執行的下一條指令,在arm64中,軟件不能修改PC寄存器 |
PSTATE | 64bit | 狀態寄存器,用于保存處理器的當前狀態信息。 |
二、通用寄存器
AArch64執行狀態支持31個64位的通用寄存器,分別是X0-X30寄存器,而AArch32狀態支持16個32位的通用寄存器。除用于數據運算和存儲之外,通用寄存器還可以在函數調用過程中起到特殊作用,ARM64體系結構的函數調用標準和規范對此有所約定,如下圖所示。
- X0 - X7: 這8個寄存器通常用作函數參數寄存器,在函數調用時用來傳遞前8個參數,函數返回值通常也存放在X0寄存器中。
- X8: 在一些情況下,X8可以用于普通的臨時寄存器,用于存儲中間計算結果。
- X9 - X15: 通常被用作臨時變量和中間計算結果的存儲。調用者有責任在函數調用前保存它們的值,以免被覆蓋。函數返回后,調用者也需要恢復這些寄存器的值。
- X16、X17: X16 (IP0, Intra-Procedure-call scratch register 0)這個寄存器通常被用作臨時寄存器,用于存儲函數內部的中間計算結果。它在函數調用過程中可能會被修改,所以調用者需要自行保存和恢復。X17與X16類似。
- X18: X18 (Platform register)這個寄存器通常被用作平臺相關的寄存器,其用途取決于具體的硬件平臺和軟件環境。在某些系統中,X18 可能被用作過程鏈接表(PLT)指針,用于動態鏈接。在其他系統中,X18 可能被用作線程局部存儲(Thread Local Storage)的指針。
- X19 - X28: 通常用于存儲函數的局部變量和中間計算結果。被調用的函數有責任在返回前保存和恢復這些寄存器的值,確保調用者可以繼續使用。
- X29: Frame Pointer (FP) 寄存器,它的主要作用是指向當前函數的棧幀(Stack Frame),方便訪問函數內部的局部變量和參數。當一個函數被調用時,x29 寄存器會被設置為指向該函數的棧幀起始地址。這樣可以通過 x29 寄存器輕松訪問函數內部的局部變量和參數,而不需要依賴 x30 寄存器(Link Register)中存儲的返回地址。
- X30: Link Register (LR),它的主要作用是在函數調用時存儲函數的返回地址,以便函數執行完畢后能夠正確地返回到調用點。當一個函數被調用時,CPU 會將當前執行點的地址保存到 x30 寄存器中。這樣在函數執行完畢后,只需要從 x30 寄存器中恢復返回地址,就可以正確地返回到調用點。注意:當一個函數被調用時,CPU 會自動將當前執行點的地址(也就是函數調用語句的下一條指令地址)保存到 x30 寄存器中。
X9 - X15和X19 - X28這兩組寄存器的區別:
x9 到 x15 則主要用作臨時變量和中間計算結果的存儲。x19 到 x28 通常用作函數的局部變量和中間計算結果的存儲。對于 x9 到 x15 這些"caller-saved"寄存器,調用者(caller)有責任在函數調用前保存它們的值,并在調用后恢復。對于 x19 到 x28 這些"callee-saved"寄存器,被調用的函數(callee)有責任在返回前保存和恢復它們的值。使用"callee-saved"寄存器通常可以減少對棧的訪問,提高性能。但同時也增加了函數調用時保存和恢復寄存器的開銷。
在簡單講一下函數的局部變量和臨時變量之間的區別:
作用域(Scope)不同: 局部變量(Local variables)是定義在函數內部的變量,它們的作用域僅限于該函數內部。臨時變量(Temporary variables)通常是用于存儲中間計算結果的變量,它們的作用域更加局限,可能只在某個代碼塊或表達式內部。
生命周期不同: 局部變量的生命周期與函數的執行周期相同,即在函數調用時創建,在函數返回時銷毀。臨時變量的生命周期則更短暫,通常僅在表達式或代碼塊的執行期間存在。
存儲位置不同: 局部變量通常存儲在函數的棧幀(Stack Frame)中,以便函數調用時能夠訪問。臨時變量通常存儲在寄存器或者棧上,以減少內存訪問開銷。
使用目的不同: 局部變量用于存儲函數內部需要持久保存的數據,如參數、返回值、中間計算結果等。臨時變量主要用于存儲一些中間計算結果,在表達式或代碼塊結束后可以丟棄。
優化方式不同: 編譯器通常會盡量將局部變量存儲在寄存器中,以提高訪問效率。對于臨時變量,編譯器則更加傾向于直接使用寄存器,避免不必要的內存訪問。
什么是棧幀:
棧幀是函數調用時在內存棧上分配的一塊區域,用于存儲函數的局部變量和參數等信息。每當一個函數被調用時,CPU 會在內存棧上為該函數創建一個新的棧幀。棧幀通常包含以下幾個部分:
返回地址: 當前函數返回時需要跳轉的地址,通常是調用函數的下一條指令。返回地址通常是由調用指令自動壓入棧的。
函數參數: 傳遞給當前函數的參數值,它們需要被保存在棧幀中。當函數返回時,這些參數值需要被恢復。
局部變量: 函數內部聲明的局部變量,它們的生命周期僅限于函數的執行期間。這些變量需要被保存在棧幀中,以免被其他函數覆蓋。
寄存器備份: 在函數調用過程中,需要保存一些重要的寄存器值,以便在返回時恢復。這些寄存器可能包括函數返回地址寄存器、幀指針寄存器等。
動態分配的內存: 函數在執行過程中動態分配的內存空間,需要在棧幀中保存相關信息。這些動態分配的內存會在函數返回時被自動釋放。
X0到X30是31個通用整形寄存器。每個寄存器可以存取一個64位大小的數。當使用X0 - X30時,它是一個64位的數。當使用W0 - W30訪問時,訪問的是這些寄存器的低32位,如下圖:
三、 PSTAE寄存器
在ARMv7架構中使用程序狀態寄存器(Current Program Status Register,CPSR)來表示當前的處理器狀態(processor stste),而在ARMv8里使用PSTATE寄存器來表示。下面我們來看一下AArch64中PSTATE各字段所代表的含義。
注意: PSTATE(process state)是一些狀態位,一些位僅在aarch32 state下使用、一些位僅在aarch64 state下使用、一些位可以同時在aarch32/aarch64 state下使用;我們在這里僅分析AArch64。
分類 | 字段 | 描述 |
---|---|---|
條件標志位 | N(Negative) | 負數標志位。在結果是有符號的二進制補碼的情況下,如果結果為負數,則N = 1;如果結果為非負數,則N = 0 |
條件標志位 | Z(Zero) | 0標志位。如果結果為0,則Z = 1;如果結果為非 0 ,則Z = 0 |
條件標志位 | C(Carry) | 進位標志位。當發生無符號數溢出時,C=1.其他情況下,C = 0 |
條件標志位 | V(Overflow) | 有符號溢出標志位。對于加/減法指令,在操作數和結果是有符號的整數時,如果發生溢出,則V=1;如果未發生溢出,則V = 0.對于其它指令,V通常不發生變化 |
運行狀態控制 | SS(Software Step) | 軟件單步。該步為1,說明在異常處理中使能了軟件單步功能,當前處于軟件單步調試模式 |
運行狀態控制 | IL(ILLegal Execution State) | 不合法的異常狀態,表示當前執行狀態是非法的,會導致異常 |
運行狀態控制 | nRW(Non-Secure Read/Write) | 在 AArch32 架構中:當 nRW = 0 時,表示當前處于"安全"狀態。當 nRW = 1 時,表示當前處于"非安全"狀態。在 AArch64 架構中:當 nRW = 0 時,表示當前處于 AArch64 執行狀態。當 nRW = 1 時,表示當前處于 AArch32 執行狀態。 |
運行狀態控制 | EL(Exception Level) | 當前異常等級。 0:表示EL0;1:表示EL1;2:表示EL2;3:表示EL3;決定了程序的特權訪問權限 |
運行狀態控制 | SP(Stack Pointer selection) | 選擇SP寄存器。當運行在EL0時,處理器選擇EL0的SP寄存器,即SP_EL0;當處理器運行在其他異常等級時,處理器可以選擇使用SP_EL0或者對應的SP_ELn寄存器 |
異常掩碼標志位 | D(Debug exception disabled) | 調試位。使能該位可以在異常處理過程中打開調試斷點和軟件單步等功能 |
異常掩碼標志位 | A(SError interrupt disabled) | 表示當前禁用了SError中斷。SError中斷是一種系統錯誤中斷 |
異常掩碼標志位 | I(IRQ interrupt disabled) | 表示當前禁用了普通IRQ中斷。 |
異常掩碼標志位 | F(FRQ interrupt disabled) | 表示當前禁用了快速FRQ中斷。 |
訪問權限 | PAN(Privileged Access Never) | ARMv8.1的擴展特性1:在EL1或者EL2訪問屬于EL0的虛擬地址時會觸發一個訪問權限錯誤。CPU會阻止特權模式下的代碼訪問用戶空間的內存;0:不支持該功能,需要軟件來模擬 |
訪問權限 | UAO(User Access Override) | 用戶特權訪問覆蓋標志位,是ARMv8.2的擴展特性。1:當運行在EL1或者EL2時,沒有特權的加載存儲指令可以和有特權的加載存儲指令一樣訪問內存,如LDTR指令。0:不支持該功能 |
在aarch64中,只可以通過MSR/MRS
指令訪問特殊寄存器(special-purpose)的方式讀寫PSTATE中的位。除了這些特殊寄存器中表示的位,PSTTAE的其它位都是不能訪問的。
這些特殊的寄存器包含: NZCV、DAIF、CurrentEL、SPSel、PAN、UAO
,可以使用MRS/MSR指令,直接讀寫這些寄存器。
例如我們可以使用MSR 指令直接寫入 DAIFSET 或 DAIFCLR 指令操作(注:DAIFSET 和 DAIFCLR 是兩個特殊的指令操作,用于設置和清除 DAIF 寄存器中的某些位。)
MSR DAIFSET, #0x2 // 設置 DAIF 寄存器的 I 位(IRQ 屏蔽位)
MSR DAIFCLR, #0x2 // 清除 DAIF 寄存器的 I 位(IRQ 屏蔽位)
上述指令實際上會修改DAIF寄存器的對應位
特殊寄存器 | PSTATE 位 |
---|---|
NZCV | N,Z,C,V |
DAIF | D,A,I,F |
CurrentEL | EL |
SPSel | SP |
PAN | PAN |
UAO | UAO |
我們可以認為這些位其實還是都在PSTATE寄存器中,然后相關的位被抽象到了NZCV,DAIF、CurrentEL、SPSel、PAN、UAO
寄存器中,方便指令訪問。
四、特殊寄存器
下面我們來看一下ARMv8中的特殊寄存器。
1. 零寄存器
ARMv8體系結構提供兩個零寄存器(zero register),這些寄存器的內容全是0,可以用作源寄存器,也可以用作目標寄存器。WZR是32位的零寄存器,XZR是64位的零寄存器。
2. PC寄存器
PC寄存器(Program Counter)通常用來指向當前運行指令的下一條指令的地址,用于控制程序中指令的運行順序,但是我們不能通過指令來直接訪問它。
PC 寄存器的主要作用包括:
- 保存當前指令的地址:PC 寄存器會始終保存當前正在執行的指令的地址。每當執行一條指令,PC 寄存器的值都會自動加 4(或加 2,取決于指令寬度)以指向下一條要執行的指令。
- 支持分支跳轉:當執行一條分支指令(如 B、BL 等)時,CPU 會將 PC 寄存器的值更新為分支目標地址,從而實現程序控制流的轉移。
- 參與異常處理:當發生異常(如中斷、系統調用等)時,硬件會自動保存當前 PC 的值到 ELR 寄存器,以便于事后恢復執行。
3. SP寄存器
ARMv8體系結構支持4個異常等級,每一個異常等級都有一個專門的SP(Stack Pointer)寄存器SP_ELn, 如處理器運行在ELI時選擇SP_EL1寄存器作為SP寄存器。
- SP_EL0: ELO下的SP寄存器。
- SP_EL1: ELI下的SP寄存器。
- SP_EL2: EL2下的SP寄存器。
- SP_EL3: EL3下的SP寄存器。
當處理器運行在比ELO高的異常等級時,處理器可以訪問如下寄存器。
- 當前異常等級對應的SP寄存器SP_ELs
- ELO對應的SP寄存器SP_ELO可以當作一個臨時寄存器,如Linux內核使用該寄存器 存放進程中task_struct數據結構的指針。
注意:當處理器運行在EL0時,它只能訪問SP_EL0,而不能訪問其他高級的SP寄存器。
SP 寄存器的主要作用包括:
- 管理程序棧:SP 寄存器存放著當前程序棧的頂部地址。當執行壓棧和出棧操作時,SP 寄存器的值會相應地增加或減少。這樣可以確保程序棧的正確使用。
- 支持函數調用:在函數調用過程中,CPU 會自動保存返回地址、函數參數、局部變量等信息到程序棧中。SP 寄存器的值會隨之動態變化,以管理這些棧幀。
- 參與中斷/異常處理:當發生中斷或異常時,CPU 會自動保存當前上下文(包括 SP 寄存器的值)到棧中,并切換到特定的異常處理模式。這樣可以確保異常返回后能夠恢復程序的執行狀態。
4. 保存處理狀態寄存器
當我們運行一個異常處理程序時,處理器的處理狀態會保存到保存處理狀態寄存器(Saved Program Status Register, SPSR)里。這個寄存器類似于ARMv7架構中的CPSR,當異常將要發生時,處理器會把PSTATE寄存器的值暫時保存到SPSR里;當異常處理完成并返回時,再把SPSR的值恢復到PSTATE寄存器。SPSR的重要字段如下圖所示。
SPSR的重要字段
字段 | 描述 |
---|---|
N(Negative) | 負數標志位 |
Z(Zero) | 零標志位 |
C(Carry) | 進位標志位 |
V(Overflow) | 有符號數溢出標志位 |
DAT(Data Independent Timing) | 與數據無關的指令時序,ARMv8.4的擴展特性 |
UAO(User Access Override) | 用戶特權訪問覆蓋標志位,ARMv8.2的擴展特性 |
PAN(Privileged Access Never) | 特權模式禁止訪問(Privileged Access Never)位,ARMv8.1的擴展特性 |
SS(Software Step) | 表示是否使能軟件單步功能。若該位為1,說明在異常處理中使能了軟件單步功能 |
IL(ILLegal Execution State) | 不合法的異常狀態 |
D(Debug exception disabled) | 調試位。使能該位可以在異常處理過程中打開調試斷點和軟件單步等功能 |
A(SError interrupt disabled) | 用來屏蔽系統錯誤 |
I(IRQ interrupt disabled) | 用來屏蔽IRQ |
F(FRQ interrupt disabled) | 用來屏蔽FIQ |
M[4] | 用來表示異常處理過程中處于哪個執行狀態,若為0,表示AArch64狀態 |
M[3:0] | 異常模式 |
5. ELR寄存器
ELR(Exception Link Register) 寄存器存放了異常返回的地址。
ELR寄存器的主要作用包括:
- 保存異常發生前的程序計數器(PC)值:當處理器進入異常模式(如中斷、系統調用等)時,ELR 寄存器會自動保存異常發生前的 PC 值。這樣在異常處理完成后,就可以從 ELR 中恢復 PC 值,繼續執行異常前的指令序列。
- 支持異常處理的返回:在異常處理程序中,可以使用 ERET 指令從異常返回。ERET 指令會從 ELR 寄存器中恢復 PC 值,從而實現對異常的正確返回。
6. CurrentEL寄存器
該寄存器表示PSTATE寄存器中的EL字段,其中保存了當前異常等級。使用MRS指令可 以讀取當前異常等級。
- 0: 表示 EL0
- 1: 表示 EL1
- 2: 表示 EL2
- 3: 表示 EL3
7. DAIF寄存器
該寄存器表示PSTATE寄存器中的{D, A, I, F}字段。
8. SPSel寄存器
該寄存器表示PSTATE寄存器中的SP字段,用于在SP_EL0和SP_ELn中選擇SP寄存器。
9. PAN寄存器
PAN寄存器表示PSTATE寄存器中的PAN (Privileged Access Never,特權禁止訪問)字段。 可以通過MSR和MRS指令來設置PAN寄存器。當內核態擁有訪問用戶態內存或者執行用戶態程序的能力時,攻擊者就可以利用漏洞輕松地執行用戶的惡意程序。為了修復這個漏洞, 在ARMV8.1中新增了 PAN特性,防止內核態惡意訪問用戶態內存。如果內核態需要訪問用 戶態內存,那么需要主動調用內核提供的接口,例如copy_from_user()
或者copy_to_user()
函數。
PAN寄存器的值如下。
- 0:表示在內核態可以訪問用戶態內存。
- 1:表示在內核態訪問用戶態內存會觸發一個訪問權限異常。
10. UAO寄存器
該寄存器表示PSTATE寄存器中的UAO (User Access Override,用戶訪問覆蓋)字段。我 們可以通過MSR和MRS指令設置UAO寄存器。
特權指令:如 LDR、STR 等,可以訪問任意內存區域,包括特權保護的區域。非特權指令:如 LDTR、STTR 等,通常只能訪問用戶空間的內存區域,受到限制。
- 當 UAO = 0 時,非特權指令(如 LDTR、STTR)的行為與特權指令(如 LDR、STR)是不同的,受到內存訪問權限的限制。
- 當 UAO = 1 時,非特權指令(如 LDTR、STTR)的行為與特權指令(如 LDR、STR)是一致的,即"用戶訪問被覆蓋"。也就是說,即使是在用戶模式(EL0)下執行非特權指令,也能夠訪問特權保護的內存區域,就像在特權模式(EL1/EL2)下執行特權指令一樣。
使用場景:
UAO = 1 的機制通常用于支持一些特殊的安全需求,例如在特權模式下執行用戶空間代碼、處理敏感的內存區域等。
11. NZCV寄存器
該寄存器表示PSTATE寄存器中的{N, Z, C, V}字段。
五、系統寄存器
除上面介紹的通用寄存器和特殊寄存器之外,ARMv8體系結構還定義了很多的系統寄存
器,通過訪問和設置這些系統寄存器來完成對處理器不同的功能配置。在ARMv7體系結構中,
我們需要通過訪問CP15協處理器來間接訪問這些系統寄存器,而在ARMv8體系結構中沒有協
處理器,可直接訪問系統寄存器。ARMv8體系結構支持如下7類系統寄存器;
- 通用系統控制寄存器
- 調試寄存器
- 性能監控寄存器
- 活動監控寄存器
- 統計擴展寄存器
- RAS寄存器
- 通用定時器寄存器
我們對這7類系統寄存器分別做一個簡單的介紹
1. 通用系統控制寄存器
通用系統控制寄存器:通用系統控制寄存器是指那些控制處理器整體狀態和行為的關鍵系統寄存器。它們對系統的運行狀態、保護機制、異常處理等進行配置和管理。
主要功能:
- 處理器狀態控制:如程序狀態寄存器(PSTATE)
- 內存管理單元(MMU)配置:如頁表基地址寄存器
- 異常和中斷處理:如中斷控制寄存器
- 電源管理:如電源控制寄存器
- 性能監控:如性能計數器
2. 調試寄存器
調試寄存器:調試寄存器是CPU中用于支持軟件調試的系統寄存器。它們提供了各種調試功能,如設置斷點、監視變量值、跟蹤指令執行等。
主要功能:
- 設置和管理軟件斷點
- 監視指定內存地址或寄存器的值
- 控制單步執行、步過、步入等調試行
- 記錄和跟蹤指令執行流程
3. 性能監控寄存器
性能監控寄存器:性能監控寄存器是 CPU 中用于監測和記錄處理器性能指標的特殊寄存器。它們提供了對處理器內部事件和狀態的可見性,用于性能分析和優化。
主要功能:
- 記錄各種微架構事件的計數:如緩存命中率、分支預測準確率等
- 監控處理器的使用狀態: 如 CPU 利用率、內存帶寬使用情況等
- 提供性能監控信息供軟件使用: 幫助進行性能調優。
4. 活動監控寄存器
活動監控寄存器:活動監控寄存器是 CPU 中用于記錄和監測處理器及系統內部活動情況的特殊寄存器。它們提供了對處理器資源使用狀態的可見性,用于系統行為分析和優化。
主要功能:
- 記錄各種處理器資源的使用情況:如指令執行、內存訪問、I/O 操作等
- 監控系統重要事件的發生情況:如中斷、異常、上下文切換等
- 提供系統活動信息供軟件使用:幫助進行系統行為分析和優化
5. 統計擴展寄存器:
統計擴展寄存器: 統計擴展寄存器是 CPU 中提供增強統計功能的系統寄存器。它們可以記錄和統計處理器內部各種事件和狀態信息,為性能分析和優化提供詳細數據支持。
主要功能:
- 提供更多的性能事件計數器,擴展基本性能監控功能
- 支持更精細的事件類型選擇和計數配置
- 記錄處理器微架構級別的統計數據,如緩存行為、分支預測等
- 支持復雜的性能事件關聯和統計分析
6. RAS寄存器
RAS寄存器:RAS (Reliability, Availability and Serviceability) 寄存器是 CPU 中提供增強統計功能的系統寄存器。它們可以記錄和統計處理器內部各種事件和狀態信息,為性能分析和優化提供詳細數據支持。
主要功能:
- 記錄各種系統錯誤事件,如內存錯誤、總線錯誤、異常等
- 提供錯誤事件的詳細信息,如錯誤類型、位置、嚴重程度等
- 支持錯誤事件的檢測、隔離和修復
- 實現系統健康狀態的監控和報告
7. 通用定時器寄存器
通用定時器寄存器:通用定時器寄存器是 CPU 中用于實現基礎定時功能的系統寄存器。它們提供了系統軟件和應用程序使用的基礎定時服務。
主要功能:
- 提供系統級的基本定時功能,如周期性中斷、延遲計數等
- 支持多個獨立的通用定時器,滿足不同應用場景的需求
- 提供定時器的配置、啟停、狀態查詢等基本控制功能
- 可以與系統中斷機制集成,支持定時事件的異步通知
注意:
系統寄存器支持不同的異常等級的訪問,通常系統寄存器會使用"Reg_EL"”的方式來表示。
- Reg_ELl:處理器處于ELI、EL2以及EL3時可以訪問該寄存器。
- Reg_EL2:處理器處于EL2和EL3時可以訪問該寄存器。
大部分系統寄存器不支持處理器處于EL0時訪問,但也有一些例外,如CTR_EL0。
程序可以通過MSR和MRS指令訪問系統寄存器。
mrs X0, TTBRO_EL1 //把 TTBRO_EL1 的值復制到 X。寄存器
msr TTBRO_EL1, X0 //把 X0 寄存器的值復制到 TTBRO_EL1
關于ARMv8寄存器的部分就寫到這里了,如有錯誤和遺漏,歡迎大家評論區來補充,我會及時更新!