第5部分- Linux ARM彙編 ARM 架構細節
ARM處理器有37個寄存器,包括31個通用寄存器,和6個狀態寄存器。
通用寄存器是31個從x0-x30,31個數量是比較奇怪的,其實還有一個是Zero Register是wzr。如果是使用寄存器中的32位,就是w0-w30了。類型X86中的rax和eax寄存器,一個64位一個32位。
ARM處理器共有7種不同的處理器模式,在每一種處理器模式中有一組響應的寄存器組。
在AArch64時使用X30作爲子函數調用時使用的link register
在AArch32時始終使用LR作爲link register。
ARM64通用寄存器
後續主要都是ARM64架構了,所以這裏以arm64例。
Register |
Volatile? |
Role |
x0 |
Volatile |
Parameter/scratch register 1, result register |
x1-x7 |
Volatile |
Parameter/scratch register 2-8 |
x8-x15 |
Volatile |
Scratch registers |
x16-x17 |
Volatile |
Intra-procedure-call scratch registers |
x18 |
Non-volatile |
Platform register: in kernel mode, points to KPCR for the current processor; in user mode, points to TEB |
x19-x28 |
Non-volatile |
Scratch registers |
x29/fp |
Non-volatile |
Frame pointer |
x30/lr |
Non-volatile |
Link registers |
|
|
|
可以通過w0 ~ w30來訪問這31個64位寄存器的低32位,寫入時會將高32位清零。
ARM64浮點寄存器
也是有32個浮點寄存器。
每個寄存器都可以作爲完整的128位值(通過v0-v31或q0-q31)進行訪問。 可以以64位值(通過d0-d31),32位值(通過s0-s31),16位值(通過h0-h31)或8位值進行訪問 (通過b0-b31)。 小於128位的訪問僅訪問整個128位寄存器的低位。 除非另有說明,否則它們保持其餘位不變。 (AArch64與AArch32不同,在AArch32中,較小的寄存器封裝在較大的寄存器的頂部。)
- 32個B寄存器(B0~B31),8bit
- 32個H寄存器(H0~H31),半字 16bit
- 32個S寄存器(S0~S31),單子 32bit
- 32個D寄存器(D0~D31),雙字 64bit
- 32個Q寄存器(V0~V31),四字 128bit
Register |
Volatile? |
Role |
v0 |
Volatile |
Parameter/scratch register 1, result register |
v1-v7 |
Volatile |
Parameter/scratch registers 2-8 |
v8-v15 |
Non-volatile |
Scratch registers (only the low 64 bits are non-volatile) |
v16-v31 |
Volatile |
Scratch registers |
浮點控制寄存器
浮點控制寄存器(FPCR)對其中的各個位字段有某些要求:
Bits |
Meaning |
Volatile? |
Role |
26 |
AHP |
Non-Volatile |
Alternative half-precision control. |
25 |
DN |
Non-Volatile |
Default NaN mode control. |
24 |
FZ |
Non-volatile |
Flush-to-zero mode control. |
23-22 |
RMode |
Non-volatile |
Rounding mode control. |
15,12-8 |
IDE/IXE/etc |
Non-Volatile |
Exception trap enable bits, must always be 0. |
32位浮點寄存器
浮點寄存器的單精度命名爲s0至s31,雙精度命名爲d0至d15。
這些寄存器分爲4個存儲區:s0–s7(d0–d3),s8–s15(d4–d7),s16–s23(d8–d11)和s24–s31(d12–d15)。
(存儲體0,s0–s7,d0–d3)稱爲標量存儲體,而其餘三個是矢量存儲體
VFPv2指令集
Vector Floating-point v2
可以通過軟件來實現VFPv2當然相比硬件,其性能會更差。
VFPv2提供了三個控制寄存器,其中一個稱爲fpscr, 該寄存器與cpsr相似,保留了通常的比較標誌N,Z,C和V。它還存儲了兩個非常有用的字段len和stride。 這兩個字段控制浮點指令的行爲。
大多數VFPv2指令的格式爲vname Rdest,Rsource1,Rsource2或fname Rdest,Rsource1。 它們具有三種操作模式。
- 標量。當目標寄存器位於存儲區0(s0–s7或d0–d3)中時,使用此模式。在這種情況下,該指令僅對Rsource1和Rsource2起作用。不涉及其他寄存器。
- 矢量。當目標寄存器和Rsource2(或對於只有一個源寄存器的指令爲Rsource1)不在存儲區0中時,使用此模式。在這種情況下,指令將操作儘可能多的寄存器(從指令中的給定寄存器開始並環繞fpscr字段len中定義的寄存器組(至少1)。下一個操作的寄存器由fpscr的跨度字段定義(至少1)。如果發生折回,則任何寄存器都不能操作兩次。
- 標量擴展(也稱爲混合矢量/標量)。如果Rsource2(如果指令只有一個源寄存器,則爲Rsource1)位於bank0中,而目的地則不是,則使用此模式。在這種情況下,Rsource2(或對於只有一個源的指令爲Rsource1)被固定爲源。其餘寄存器的操作與矢量情況一樣(即使用fpscr的len和stride)。
示例
|
Load和store
單精度是:vldr
/vstr
加載/存儲的地址必須已經在通用寄存器中
|
可以Load/store多個寄存器:
vldm indexing-mode precision Rbase{!}, floating-point-register-set
vstm indexing-mode precision Rbase{!}, floating-point-register-set
|
32位中還有vpush
|
寄存器間移動
指令是vmov.
在一個通用寄存器和一個單精度寄存器之間vmov,數據不會轉換。 只有位會被複制,因此不要將浮點值與整數指令混合使用,反之亦然。
|
轉化
單精度轉換爲整型的時候丟失精度是必然的的,是多少問題。
指令:
vcvt
兩個寄存器都必須是浮點寄存器。浮點寄存器將包含一個不是IEEE 754值的值。
|
修改fpscr
設置了len和stride的特殊寄存器fpscr無法直接修改。
必須使用vmrs指令將fpscr加載到通用寄存器中。 然後使用vmsr指令對寄存器進行操作,並將其移回fpscr。
len的值存儲在fpscr的第16至18位中。 len的值不直接存儲在這些位中。這是因爲len不能爲0(操作0個浮點數沒有意義)。 這樣,這些位中的值000表示len = 1,001表示len = 2,…,111表示len =8。以下是將len設置爲8的代碼。
|
stride存儲在fpscr的20至21位中。 與len相似,這些位中的值00表示1,01表示 2,10表示 3,11表示 4。
https://developer.arm.com/docs/ddi0595/d/aarch32-system-registers/fpscr
該寄存器中的命名字段映射到AArch64 FPCR和FPSR中的等效字段。
寄存器FPEXC中,EN表示NEON和VFP是否使能。清零是關閉
要使能,將EN置1。
函數調用約定和浮點寄存器
- fpscr的len和stride字段的所有位在函數輸入時均爲零,離開時這些位必須爲零。
- 可以使用寄存器s0–s15和d0–d7傳遞浮點參數。 請注意,在單精度之後傳遞雙精度可能涉及丟棄奇數單精度寄存器(例如,可以使用s0和d1,但請注意,s1將不被使用)。
- 所有其他浮點寄存器(s16-s31和d8-d15)在退出功能時必須保留其值。 可以使用vpush和vpop指令。
- 如果函數返回浮點值,則返回寄存器將爲s0或d0。
注意有關可變參數函數(例如printf):不能將單精度浮點傳遞給此類函數之一。 只能通過雙精度。 需要將單精度值轉換爲雙精度值。 還要注意,通常使用整數寄存器(r0–r3),因此您最多隻能傳遞2個雙精度值,其餘的必須在堆棧上傳遞。 特別是對於printf,因爲r0包含字符串格式的地址,所以您只能在{r2,r3}中傳遞雙精度。
編譯
要將標誌-mfpu = vfpv2傳遞給as,否則將無法識別VFPv2指令。
浮點和整數傳輸
VMRS/VMSR在ARM寄存器與NEON和VFP系統寄存器之間傳輸內容。
fmrx/fmxr在ARM寄存器和VFP系統寄存器之間傳輸內容。
Fmrs/fmsr 在ARM寄存器和浮點寄存器之間傳輸內容。
ARM64系統寄存器
與AArch32一樣,AArch64規範提供了三個系統控制的“線程ID”寄存器:
Register |
Role |
TPIDR_EL0 |
Reserved. |
TPIDRRO_EL0 |
Contains CPU number for current processor. |
TPIDR_EL1 |
Points to KPCR structure for current processor. |
程序計數器
pc,保存着當前CPU執行指令的地址。不能用作算數指令的源或目的地以及用作加載或存儲指令。
堆棧指針
sp,即x31,指向堆棧的頂部。sp不能被大多數指令引用, 但一些算術指令,例如ADD指令,可以讀寫當前的堆棧指針來調整函數中的堆棧指針。每個異常級別都有一個專用的SP寄存器。
fp,即x29,幀指針,指向當前frame的棧底,也就是高地址。
鏈接寄存器
lr,即x30,存儲着函數的返回地址。
程序狀態寄存器
在彙編中通過狀態寄存器來控制分支的執行。
cpsr:與其他寄存器不太一樣,其他寄存器用來存儲數據的,但是這個寄存器是,按位起作用的,每一位都有專門的含義。
spsr:當發生異常時,cpsr會存入spsr直到異常恢復再複製回cpsr。
特殊寄存器
運行模式
ARM處理器支持7種運行模式,分別是:
- 用戶模式(usr):ARM處理器正常的程序運行狀態。
- 快速中斷模式(flq):用於高速數據傳輸或通道處理。
- 外部中斷模式(irq):用於通用的中斷處理。
- 管理模式(svc):操作系統使用的保護模式。
- 數據訪問終止模式(abt):當數據或指令預取終止時進入該模式,可用於虛擬存儲以及存儲保護。
- 系統模式(sys):運行具有特短的操作系統任務。
- 未定義指令終止模式(und):當未定義的指令執行時進入該模式。
各種處理器模式下的,通用寄存器
還有兩個工作模式:
hyp:用於虛擬化擴展。
monitor:用於Security擴展。
工作狀態
ARM狀態:執行32位字對齊的ARM指令。
Thumb狀態:執行16位字對齊的ARM指令。
Thumb狀態下的寄存器的命名與ARM有部分差異,它們的對應關係如下所示:
Thumb狀態下的R0~R7與ARM狀態下的R0~R7相同。
Thumb狀態下的CPSR與ARM狀態下的CPSR相同。
Thumb狀態下的FP與ARM狀態下的R11相同。
Thumb狀態下的IP與ARM狀態下的R12相同。
Thumb狀態下的SP與ARM狀態下的R13相同。
Thumb狀態下的LR與ARM狀態下的R14相同。
Thumb狀態下的PC與ARM狀態下的R15相同。
程序狀態寄存器
CPSR(當前程序狀態寄存器)可以在任何處理器模式下被訪問。
非對齊的存儲訪問操作
如果寫入到寄存器PC中的值是非字對齊的,要麼指令執行的結果不可預知,要麼地址值中最低兩位被忽略。