1.Supervisor模式與SVC模式
- Supervisor模式是ARM處理器的一個特權工作模式,允許執行特權指令和訪問特權資源。
- SVC模式(Supervisor Call)是與Supervisor模式相關的一個功能或指令,用于從用戶模式切換到Supervisor模式,并觸發系統服務例程的執行。
- SVC不是一種獨立的工作模式,而是與Supervisor模式協同工作,用于系統調用和異常處理。
????????所以,Supervisor模式和SVC模式在ARM處理器中是不同的概念,但它們之間有密切的關聯。SVC模式使用Supervisor模式的功能來提供系統服務。
2.指令+s的作用,影響N,Z,C,V位
????????ARM指令中的“S”后綴用于指示該指令執行后是否更新程序狀態寄存器(CPSR)的條件標志位。這些標志位可以用于后續的條件判斷或分支操作,從而影響指令的執行順序。
以下是具體功能和詳細解釋:
-
條件標志位更新:當ARM指令后帶有“S”后綴時,該指令執行后,程序狀態寄存器的條件標志位(如N、Z、C、V等,分別代表負數、零、進位和溢出)將被刷新或更新。這些標志位經常用于對條件進行測試,例如是否溢出、是否進位等。
-
影響指令執行順序:根據這些條件標志位的變化,程序可以執行不同的分支或循環,從而影響指令的執行順序。例如,可以使用這些標志位來判斷一個加法操作是否導致溢出,然后根據結果選擇不同的后續指令。
-
指令格式:在ARM指令中,后綴“S”是可選的。當不使用“S”后綴時,指令執行后程序狀態寄存器的條件標志位將不會發生變化。指令的一般格式可以表示為
<opcode>{ <cond> } {S}<Rd>,<Rn>{, <operand2> }
,其中<opcode>
是操作碼,<cond>
是可選的條件碼,<Rd>
是目標寄存器,<Rn>
是存放第一操作數的寄存器,<operand2>
是第二操作數。 -
具體示例:以加法指令為例,
ADD R3, R5, R8
(沒有使用“S”后綴)執行后,條件標志位將不會發生變化;而ADDS R3, R5, R8
(使用了“S”后綴)執行后,條件標志位將根據結果刷新。
3.CPSR(程序狀態寄存器)/SPSR(程序狀態保存寄存器)
在ARM架構中,CPSR(Current Program Status Register,當前程序狀態寄存器)和SPSR(Saved Program Status Register,程序狀態保存寄存器)是兩個重要的狀態寄存器,它們在處理器中扮演著關鍵的角色。以下是關于這兩個寄存器的詳細解釋:
????????3.1. CPSR(當前程序狀態寄存器)
????????N和C標志位被“置位”,指的是這些標志位被設置為特定的值以表示某種狀態或條件。
功能與作用:
- CPSR在用戶級編程時用于存儲條件碼。
- 它包含條件碼標志、中斷禁止位、當前處理器模式以及其他狀態和控制信息。
內容詳解:
- 條件標志位:包括N、Z、C、V等,用于表示指令執行后的狀態,如運算結果的符號、零、進位和溢出等。
- 中斷禁止位:包括I(IRQ中斷禁止位)和F(FIQ中斷禁止位),用于控制是否允許相應的中斷發生。
- 處理器模式標志位:指示處理器當前處于哪種模式,如用戶模式、系統模式、中斷模式等。
訪問方式:
- CPSR在任何處理器工作模式下都可以被訪問。
????????3.2. SPSR(程序狀態保存寄存器)
功能與作用:
- SPSR用于保存CPSR的狀態,以便在異常返回后恢復異常發生時的工作狀態。
內容詳解:
- 當特定的異常中斷發生時,SPSR會存放當前CPSR的內容。
- 在異常中斷退出時,可以使用SPSR來恢復CPSR的狀態。
注意:
- 由于用戶模式和系統模式不是異常中斷模式,所以它們沒有對應的SPSR。
- 如果在用戶模式或系統模式下嘗試訪問SPSR,將會產生不可預知的后果。
總結:
- CPSR是ARM處理器中的核心寄存器之一,用于存儲處理器的狀態信息,并在各種模式下提供對中斷和其他功能的控制。
- SPSR作為CPSR的備份,用于在異常處理過程中保存和恢復處理器的狀態。這兩個寄存器共同確保了ARM處理器在各種復雜操作中的穩定性和可靠性。
4.跳轉指令和加載指令
???4.1跳轉指令(b/bl/bx)
????????b:無條件跳轉指令;
? ? ? ? bl:用于函數調用,并保存返回地址。
????????bl和b之間的區別就在于bl會在lr寄存器中保存回來的地址。
? ? ? ? bx:回到調用處;
? ? ? ? bxgt:滿足gt條件時,回到調用處。
??bx
?基于寄存器的內容進行跳轉,并支持 ARM/Thumb 切換。
4.2 加載指令(LDR)
- LDR指令:
- 功能:用于從內存中讀取一個32位的字數據到目的寄存器中。
- 格式:
LDR{條件} 目的寄存器, <存儲器地址>
- 示例:
LDR R0, [R1]
:將存儲器地址為R1的字數據讀入寄存器R0。LDR R0, [R1, #8]
:將存儲器地址為R1+8的字數據讀入寄存器R0。
- 特點:
- 尋址方式靈活多樣,支持直接地址、基址加偏移量等。
- 當程序計數器PC作為目的寄存器時,指令從存儲器中讀取的字數據被當作目的地址,從而可以實現程序流程的跳轉。
- bic指定位清零指令:
- BIC{S}<c> <Rd>, <Rn>, #<const>;將rn中的字數據const為1的比特清零,把結果放入rd
- orr指定位置位指令:
- ORR{S}<c> <Rd>, <Rn>, #<const>
5.ARM中常見的數據處理指令
-
ADD:
- 含義:加法指令。
- 使用:將兩個寄存器或立即數與一個寄存器相加,并將結果存儲在一個寄存器中。
- 示例:
ADD R1, R2, R3
?將?R2
?和?R3
?的值相加,并將結果存儲在?R1
?中。
-
SUB:
- 含義:減法指令。
- 使用:從一個寄存器中減去另一個寄存器或立即數,并將結果存儲在一個寄存器中。
- 示例:
SUB R1, R2, R3
?從?R2
?中減去?R3
?的值,并將結果存儲在?R1
?中。
ARM指令集中的數據處理指令是用于在寄存器中執行數學運算、邏輯運算以及數據傳送的指令。這些指令在ARM架構中扮演著核心角色,允許CPU高效地執行各種計算任務。以下是一些ARM中常見的數據處理指令,按照其功能分類進行歸納:
- 數據傳送指令:
- MOV指令:用于將一個寄存器或立即數的值傳送到另一個寄存器。例如,MOV R1, R0 將寄存器R0的值傳送到寄存器R1。
- MVN指令:是數據取反傳送指令,將一個寄存器或立即數的反碼傳送到目標寄存器。例如,MVN R0, #0 將立即數0取反后傳送到寄存器R0。
- 算術運算指令:
- ADD指令:用于將兩個寄存器或立即數相加,并將結果存放到目的寄存器中。例如,ADD R0, R1, R2 將R1和R2的值相加后存放到R0。
- ADC指令:帶進位的加法指令,用于將兩個寄存器或立即數相加,并加上CPSR中的C條件標志位的值,然后將結果存放到目的寄存器中。
- 邏輯運算指令(雖然參考文章中沒有直接提及邏輯運算指令,但它們是數據處理指令的重要部分):
- AND指令:用于將兩個寄存器或立即數進行邏輯與運算。
- ORR指令:用于將兩個寄存器或立即數進行邏輯或運算。
- EOR指令:用于將兩個寄存器或立即數進行邏輯異或運算。
- 比較指令:
- CMP指令:用于比較兩個寄存器或立即數的值,并更新CPSR中的條件標志位,但不保存運算結果。
- CMN指令:將一個寄存器或立即數的取反值與另一個寄存器或立即數進行比較,并更新CPSR中的條件標志位。
- 移位指令(雖然參考文章中沒有直接提及移位指令,但它們也是數據處理指令的一部分):
- LSL指令:邏輯左移指令,將寄存器的內容向左移動指定的位數。
- LSR指令:邏輯右移指令,將寄存器的內容向右移動指定的位數。
- ASR指令:算術右移指令,在移位時保留符號位。
- 特殊數據處理指令:
- MOVS指令:與MOV指令類似,但會更新CPSR中的條件標志位。
- BIC指令:位清零指令,用于將某個寄存器中的特定位清零。
這些指令共同構成了ARM指令集中的數據處理部分,允許開發者在ARM架構的CPU上執行各種復雜的計算任務。需要注意的是,ARM指令集在不同的版本(如ARMv7、ARMv8等)中可能會有所不同,上述指令是ARM指令集中常見的和通用的部分。
6.棧的實現類型:
2440實現保護和恢復現場使用的棧是數組棧,即用一段連續的內存空間為棧提供空間。從數組棧的具體實現來看入棧的方式有四種做法:
- 空增:先寫入數據,再讓棧指針自增;(棧指針平時指向空)
- 空減:先寫入數據,再讓棧指針自減;(棧指針一開始指向棧頂)
- 滿增:先讓棧指針自增,再寫入數據;(棧指針平時指向最高層數據)
- 滿減:先讓棧指針自減,再寫入數據。(棧指針指向棧頂的上一個空位置)
????????arm體系采用的方案是滿減,但是在進行操作之前,我們必須告訴2440棧底的位置,這里我們把棧底設置為0x40001000,從地址0x40000000開始的0x1000這段內存空間對應的是2440內部的一段ram,總共4k。實際能夠使用的內存空間為[0x40000000~0x40000FFF],設置棧底指針寄存器: ldr sp =0x40001000
? ? ? ? 6.1入棧保護指令stmfd(STMDB)
STMFD<c> <Rn>{!}, <registers>
其中Rn表示棧底指針寄存器,<?registers?>表示需要入棧保護的寄存器,!表示入棧之后sp自動自減。如:
stmfd sp!, {r0, r1, r2, r3-r12, lr}???????????????;保護現場
6.2出棧恢復指令ldmfd(LDM/LDMIA/)
LDMFD<c> <Rn>{!}, <registers>
中Rn表示棧底指針寄存器,<?registers?>表示需要入棧保護的寄存器,!表示出棧之后sp自動自增。如:
ldmfd sp!, {r0, r1, r2, r3-r12, lr}?? ;恢復現場
7.匯編與C語言代碼互相調用規則
7.1在匯編中調用c語言編寫的函數
????????設有c語言定義的函數void func_c(void);在匯編代碼中調用該函數,只需用import(導入)聲明函數名即可,之后就可以使用bl指令調用該函數,注意,既然是調函數,就一定要保護現場。
????????7.2 向c函數傳參
向c函數傳參的方法很簡單,如果參數個數小于等于4個,就直接用r0~r3傳參,c函數返回值通過r0寄存器返回:
設有c函數:
????????int add_c(int a, int b, int c, int d)
????????{
????????return a + b + c + d;
??}
如果參數個數大于4個,從第五個參數開始就需要通過棧來傳參(前4個參數傳參,通過r0-r3傳參,返回值用r0傳參)
在c語言中調用匯編編寫的函數類似,不過在匯編中用export聲明函數,同時需要在c語言中用extern聲明函數,按照標準,調用者負責保護現場和恢復現場
傳參方法于此類似
8.切換ARM內核的工作模式
? ? ? ? mrs:讀取CPSR的狀態;
? ? ? ? msr:寫入CPSR寄存器。
????????切換工作方式的思路很簡單,由于內核的工作模式是由cpsr寄存器的低5位來設置的,那么就可以先把cpsr讀出來,更改低5位之后再設置進去。這里讀取cpsr使用mrs指令,寫cpsr寄存器用msr指令,需要注意的是在keil環境下寫cpsr需要寫成: ??msr cpsr_c r0;將r0的值寫入到cpsr寄存器