一、指令
1、b(Branch)
原型:B<c> <label>
作用:實現無條件跳轉,常用于不返回的跳轉場景
特點:僅跳轉到目標地址,不保存返回地址
示例:b reset ????????;跳轉到reset標號處執行
2、bl(Branch with Link)
原型:?BL<label>
作用:硬件自動將返回地址(
PC+4
?或?PC+2
)存入 LR (帶鏈接的跳轉,用于子程序調用,跳轉前將返回地址(PC+4
)保存到鏈接寄存器?LR
(R14))特點:子程序執行完畢后可通過?
mov pc, lr
?或?bx lr
?返回調用點示例:
注意事項:一個嵌套可用,大于兩個嵌套以上,需要搭配棧來使用(用法如下)
3、bx lr
原型:BX{<cond>} <Rm>
作用:將程序計數器(PC)設置為鏈接寄存器(LR/R14)中保存的地址,實現函數返回
特點:
BX LR
?將 LR 的值加載到 PC,恢復原程序流示例:
4、stmdb 壓棧
原型:STMDB<c><Rn>{!},<registers>
作用:保護現場/恢復現場(壓棧/彈棧)
? ? ? ? ?壓棧操作,ARM通常默認采用滿遞減棧,棧指針先減后存或先讀后增
參數:
<Rn>
?是棧頂指針寄存器,通常為棧指針?SP
(R13),指向當前棧頂位置!
?后綴的作用:
- 不加!:僅按指令操作存儲數據,不更新基址寄存器(
SP
?的值不變)- 加!?:存儲完成后,自動更新基址寄存器(
SP = SP - 4*N
,N
?為寄存器數量)
- 壓棧保存寄存器,同時更新棧指針
<registers>
?的存儲規則(入棧出棧的寄存器列表):
存儲順序:寄存器按編號從大到小依次存儲(如?
R3
→R2
→R1
→R0
)內存地址:基址先遞減,再存儲
使用要點: 棧頂指針寄存器初始化
mov sp, #0x40001000 ?: 報錯非立即數 ? ?
ldr sp,?? ?=0x40001000
魔術棒 -> Target->IRAM1:#0x40000000? ? ?size:0x1000示例:
5、ldmfd 彈棧
原型:LDMFD{<cond>} SP!, {<registers>}
作用:恢復現場
????????從棧中按低地址到高地址依次加載恢復數據到寄存器,并遞增棧指針(彈棧方向與壓棧相反)
用法:類似stmdb
示例:同上
6、ldr 普通加載數據
原型:LDR<c> <Rt>, <label>
作用:加載非立即數寄存器中(初始化寄存器 、加載常量數據)
特點:
- 用于加載?32 位立即數(ARM 指令不能直接加載 32 位立即數,
ldr =
?是一種偽指令)示例:
????????ldr r0, =0x40001000 ; 將地址 0x40001000 存入 r0
7、ldr 類(*p)操作
原型:
作用:從?內存地址?加載數據到寄存器(類指針操作)
特點:對應的是C語言中的?
*p
(指針解引用)示例:
? ?---? ? ? ldr r0, [r1]? ? ? ? ? ? ? ? ? ? ? ? ?; 將 r1 指向的內存數據加載到 r0
? ?---? ? ? ldr r0, [r1, #4]? ? ? ? ? ? ? ? ?? ; r0 = *(r1 + 4)
? ? ? ? ? ? ldr r0, [r1, r2]? ? ? ? ? ? ? ? ? ? ; r0 = *(r1 + r2)
? ? ? ? ? ? ldr r0, [r1, r2, LSL #2]???????; r0 = *(r1 + (r2 << 2))
? ? ? ? ? ? ldr r0, [r1], #4? ? ? ? ? ? ? ? ? ? ; r0 = *r1; r1 += 4 (后索引)
? ? ? ? ? ? ldr r0, [r1, #4]!? ? ? ? ? ? ? ? ? ?; r0 = *(r1 + 4); r1 += 4 (前索引并更新基址)
二、匯編調用C語言
1、流程
(1) 創建main.c
(2) 在main中聲明將要在filename.s文件中將要使用的文件 extern void c_add(void);
(3) 導入 import +文件名; (keil當中要求)導出文件文件用export +文件名
(4) 保護現場 bl函數調用 恢復現場
(5) 解決編譯報錯:
????????asm.axf: Error: L6238E: start.o(reset) contains invalid call from '~PRES8 (The user did not require code to preserve 8-byte aligment of 8-byte data objects)' function to 'REQ8 (Code was permitted to depend on the 8-byte aligment of 8-byte data items)' function c_add. asm.axf: Finished: 0 information, 0 warning and 1 error messages.
解決辦法:在.s文件開頭 寫上
???????????????????棧對齊偽指令:preserve8 用于確保函數調用時棧指針保持 8 字節對齊
(6) 創建工程自動添加了啟動代碼報錯
(7)重設軟件配置? ---(魔術棒)
- 魔術棒 -> Debug -> Use Simulator->Run to main(取消)
- 魔術棒 -> Linker -> Use Memory Layout from Taget Dialog(勾選)
- 魔術棒 -> Taget -> ROM1 -> Start: 0x0 Size:0x2000
(8)函數傳參:基本參數只能傳遞四個超出部分需采用壓棧傳遞
例:
main.c
start.s
2、?ARM的7種異常類型
異常類型 | 觸發條件 | 進入模式 | 優先級 |
---|---|---|---|
復位(Reset) | 上電或硬件復位 | 管理模式(SVC) | 1(最高) |
數據中止(Data Abort) | 非法內存訪問(如缺頁) | 中止模式(ABT) | 2 |
快速中斷(FIQ) | 高優先級外設中斷(如DMA) | FIQ模式 | 3 |
普通中斷(IRQ) | 常規外設中斷(如定時器) | IRQ模式 | 4 |
預取中止(Prefetch Abort) | 指令預取失敗 | 中止模式(ABT) | 5 |
軟件中斷(SWI/SVC) | SVC ?指令觸發(系統調用) | 管理模式(SVC) | 6 |
未定義指令 | 執行未知指令 | 未定義模式(UND) | 7(最低) |
3、ARM匯編調用C函數
(1)前4個參數:依次通過寄存器 R0
、R1
、R2
、R3
傳遞。
(2)超過4個參數:剩余參數按從右向左的順序壓棧(棧內存傳遞)。
(3)返回值:
????????32位整數:通過 R0
返回。
????????64位整數:通過 R0
(低32位)和 R1
(高32位)返回。
????????浮點數:通過 S0
(單精度)或 D0
(雙精度)返回
三、ARM 裸機開發環境搭建
? ? ? ? ;標準偽指令
????????preserve8? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ;
????????area reset, code, readonly
????????code32
????????entry
????????
? ? ? ? ;<1>
????????ldr pc, =start_hander ????????????????; 復位異常(Reset)
????????ldr pc, =undefine_hander? ? ? ? ? ?; 未定義指令異常
????????ldr pc, =software_hander? ? ? ? ? ?; 軟件中斷(SWI/SVC)
????????ldr pc, =prefetch_hander? ? ? ? ? ? ; 預取中止異常
????????ldr pc, =data_hander? ? ? ? ? ? ? ? ? ; 數據中止異常
????????nop? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ; 保留位(ARMv5+)
????????ldr pc, =irq_hander? ? ? ? ? ? ? ? ? ? ? ; 普通中斷(IRQ)
????????ldr pc, =fiq_hander? ? ? ? ? ? ? ? ? ? ? ; 快速中斷(FIQ)
undefine_hander
????????b undefine_hander
import software_vectorsoftware_hander
????????stmfd sp!, {r0-r12, lr}? ? ? ? ? ? ? ? ? ? ?; 保存寄存器現場
????????bl software_vector???????????????????????? ; 調用C函數處理SWI
????????ldmfd sp!, {r0-r12, pc}^????????????????? ; 恢復現場并返回(^表示恢復CPSR)
;注意:此處使用^修飾符,表示同時將SPSR恢復到CPSR(用于模式切換)
;默認異常處理均為死循環,實際項目中需替換為具體邏輯
prefetch_hander
????????b prefetch_hander ????????????????????????; 預取中止死循環
data_hander
????????b data_hander ????????????????????????????? ; 數據中止死循環
irq_hander
????????b irq_hander ????????????????????????????????; IRQ死循環
fiq_hander
????????b fiq_hander???????????????????????????????? ; FIQ死循環
? ?
;SWI觸發函數
? ? ? ?export ?asm_swi_fun
asm_swi_fun
swi #7? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ;觸發軟件中斷(編號7)? ? ? ?bx lr? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ;返回調用者
start_hander ;(主開始位置)
????????ldr sp, =0x40001000???????????????? ; 設置棧指針初始位置<2>
????????import main???????????????????????????????; 聲明外部C入口函數
;切換處理器模式到用戶模式(CPSR.M[4:0] = 0x10),并啟用中斷(清除I-bit)<3>
????????mrs r0, cpsr ??????????????????????????????; 讀取CPSR
????????bic r0, r0, #(0x1F << 0)? ? ? ? ? ?? ; 清除模式位
????????bic r0, r0, #(1 << 7)? ? ? ? ? ? ? ? ?? ; 清除中斷禁止位(I-bit)
????????orr r0, r0, #(0x10 << 0)? ? ? ? ? ? ? ; 設置為用戶模式(0x10)
????????msr cpsr_c, r0? ? ? ? ? ? ? ? ? ? ? ? ? ? ; 寫回CPSR
;重新設置用戶模式
????????ldr sp, =0x40001000 ????????????? ? ? ; 重新設置棧指針
????????sub sp, sp, #1024???????? ? ? ? ? ? ? ? ; 預留棧空間(1KB)
????????b main ???????????????????????????????????????; 跳轉到C的main函數
end
知識點:
1、中斷向量表
位置:必須位于0x00000000地址(或可通過VBAR重定位)
組成:8個32位條目,按固定順序對應不同異常類型
跳轉方式:
?????ldr pc, =handler
:支持全地址范圍跳轉
? ? ??b handler
:僅支持±32MB范圍跳轉
2、棧設置:
在進入用戶模式前,先設置一次棧(ldr sp, =0x40001000),這是為了在切換模式前確保棧有效(因為不同模式有各自的SP寄存器)
切換到用戶模式后,再次設置棧指針并預留空間(sub sp, sp, #1024),避免用戶程序棧溢出破壞其他數據
3、ARM處理器中 CPSR(當前程序狀態寄存器)的模式位
模式值(十六進制) | 模式名稱 | 英文全稱 | 用途說明 |
---|---|---|---|
0x10 | 用戶模式 | User Mode | 運行普通應用程序的非特權模式,無法直接訪問硬件資源或執行特權指令。 |
0x11 | FIQ模式 | Fast Interrupt Mode | 處理高速中斷(FIQ),有專用的寄存器(R8-R14_fiq),用于低延遲中斷響應。 |
0x12 | IRQ模式 | Interrupt Mode | 處理普通中斷(IRQ),比 FIQ 優先級低,用于一般外設中斷。 |
0x13 | SVC模式 | Supervisor Mode | 操作系統內核模式(如 Linux 的 Kernel Mode),用于處理軟件中斷(SWI/SVC)。 |
0x17 | Abort模式 | Abort Mode | 當發生內存訪問異常(如缺頁或權限錯誤)時進入此模式。 |
0x1B | Undef模式 | Undefined Mode | 當執行未定義指令時觸發,用于模擬浮點指令或擴展指令集。 |
特權級別:
特權模式(0x11-0x1B):可以訪問所有系統資源和 CPSR 寄存器
非特權模式(0x10):限制訪問硬件和關鍵寄存器
典型應用場景:
用戶程序運行在 User Mode(0x10)
操作系統通過 SVC 指令觸發 SVC Mode(0x13)執行系統調用
硬件中斷自動切換至 IRQ/FIQ Mode(0x12/0x11)
模式切換權限:
????????只有特權模式(如 SVC)才能修改 CPSR 的模式位,用戶模式嘗試修改會觸發異常。
模式自動切換:
????????中斷/異常發生時,處理器會自動切換到對應模式(如 IRQ → 0x12)。
寄存器組差異:
????????某些模式(如 FIQ)有專用寄存器(R8-R14_fiq),可加速中斷處理