ARM匯編指令集
指令、偽指令
(匯編)指令: 是機器碼的助記符,經過匯編器編譯后,由CPU執行。
(匯編)偽指令:用來指導指令執行,是匯編器的產物,最終不會生成機器碼。
有兩種不同風格的ARM指令
1).ARM官方的ARM匯編風格:指令一般用大寫,Windows中的IDE開發環境。
2).GNU風格的ARM匯編:指令一般用小寫。
ARM匯編的特點
1. LDR/STR架構
1).ARM采用RISC架構,CPU本身不能直接讀取內存,而需要先將內存中內容加載入CPU中通用寄存器中才能被CPU處理。
2).ldr(load register)指令將內存內容加載入通用寄存器。
3).str(store register)指令將寄存器內容存入內存空間中。
4).ldr/str組合用來實現 ARM CPU和內存數據交換。
2. 至此8種尋址方式
1).寄存器尋址mov r1, r2。
2).立即(立即數)尋址 mov r0, #0xFF00。
3).寄存器移位尋址 mov r0, r1, lsl #3。
4).寄存器間接尋址 ldr r1, [r2] 表示內存,內存地址存在r2這個寄存器中,把內存地址里的值給r1。
5).基址變址尋址ldr r1, [r2, #4]內存地址在r2+4里面。
6).多寄存器尋址 ldmia r1!, {r2-r7, r12}一次訪問多個寄存器。
7).堆棧尋址 stmfd sp!, {r2-r7, lr}。
8).相對尋址 beq flag。
3. 指令后綴
同一指令經常附帶不同后綴,變成不同的指令。經常使用的后綴有:
B(byte)功能不變,操作長度變為8位
H(half word)功能不變,長度變為16位
S(signed)功能不變,操作數變為有符號
如 ldr ldrb ldrh ldrsb ldrsh
S(S標志)功能不變,影響CPSR標志位
如 mov和movs movs r0, #0
4. 條件執行后綴

條件后綴是否成立取決於當前代碼的前面的代碼。
條件后綴只影響當前代碼的執行。
5. 多級指令流水線
為增加處理器指令流的速度,ARM使用多級流水線.,下圖為3級流水線工作原理示意圖。(S5PV210使用13級流水線,ARM11為8級)
允許多個操作同時處理,而非順序執行。
1).PC指向正被取指的指令,而非正在執行的指令
數據傳輸與跳轉指令詳解
1. 數據處理指令
數據傳輸指令 mov mvn
算術指令 add sub rsb adc sbc rsc
邏輯指令 and orr eor bic
比較指令 cmp cmn tst teq
乘法指令 mvl mla umull umlal smull smlal
前導零計數 clz
2. cpsr訪問指令
mrs & msr
mrs用來讀psr,msr用來寫psr
CPSR寄存器比較特殊,需要專門的指令訪問,這就是mrs和msr。
3. 跳轉(分支)指令
b & bl & bx
b 直接跳轉(就沒打開算返回)
bl branch and link,跳轉前把返回地址放入lr中,以便返回,以便用於函數調用
bx跳轉同時切換到ARM模式,一般用於異常處理的跳轉。
4. 訪存指令
ldr/str & ldm/stm & swp
單個字/半字/字節訪問 ldr/str
多字批量訪問 ldm/stm
swp r1, r2, [r0]
swp r1, r1, [r0]
5. 軟中斷指令
swi(software interrupt)
軟中斷指令用來實現OS中系統調用
ARM匯編中的立即數
合法立即數與非法立即數
ARM指令都是32位,除了指令標記和操作標記外,本身只能附帶很少位數的立即數。因此立即數有合法和非法之分。
合法立即數:經過任意位數的移位后非零部分可以用8位表示的即為合法立即數。
協處理器與協處理器指令集
6.協處理器cp15操作指令
mcr & mrc
mrc用於讀取CP15中的寄存器
mcr用於寫入CP15中的寄存器
7.arm尋址方式
協處理器解析:
SoC內部另一處理核心,協助主CPU實現某些功能,被主CPU調用執行一定任務。
ARM設計上支持多達16個協處理器,但是一般SoC只實現其中的CP15.(cp:coprocessor)
協處理器和MMU、cache、TLB等處理有關,功能上和操作系統的虛擬地址映射、cache管理等有關。
MRC & MCR的使用方法
mcr{<cond>} p15, <opcode_1>, <Rd>, <Crn>, <Crm>, {<opcode_2>}
opcode_1:對於cp15永遠為0
Rd:ARM的普通寄存器
Crn:cp15的寄存器,合法值是c0~c15
Crm:cp15的寄存器,一般均設為c0
opcode_2:一般省略或為。
ldm/stm與棧的處理
為什么需要多寄存器訪問指令
ldr/str每周期只能訪問4字節內存,如果需要批量讀取、寫入內存時太慢,解決方案是stm/ldm
ldm(load register mutiple)
stm(store register mutiple)
舉例(uboot start.S 537行)
stmia sp, {r0 - r12}
將r0存入sp指向的內存處(假設為0x30001000);然后地址+4(即指向0x30001004),將r1存入該地址;然后地址再+4(指向0x30001008),將r2存入該地址······直到r12內容放入(0x3001030),指令完成。
一個訪存周期同時完成13個寄存器的讀寫
后綴的種類:
ia(increase after)先傳輸,再地址+4
ib(increase before)先地址+4,再傳輸
da(decrease after)先傳輸,再地址-4
db(decrease before)先地址-4,再傳輸
fd(full decrease)滿遞減堆棧
ed(empty decrease)空遞減堆棧
fa(·······) 滿遞增堆棧
ea(·······)空遞增堆棧
四種棧解析:
空棧:棧指針指向空位,每次存入時可以直接存入然后棧指針移動一格;而取出時需要先移動一格才能取出。
滿棧:棧指針指向棧中最后一格數據,每次存入時需要先移動棧指針一格再存入;取出時可以直接取出,然后再移動棧指針。
增棧:棧指針移動時向地址增加的方向移動的棧。
減棧:棧指針移動時向地址減小的方向移動的棧。
!的作用:
ldmia r0, {r2 - r3}
ldmia r0!, {r2 - r3}
感嘆號的作用就是r0的值在ldm過程中發生的增加或者減少最后寫回到r0去,也就是說ldm時會改變r0的值。
^的作用:
ldmfd sp!, {r0 - r6, pc}
ldmfd sp!, {r0 - r6, pc}^
^的作用:在目標寄存器中有pc時,會同時將spsr寫入到cpsr,一般用於從異常模式返回。
總結:批量讀取或寫入內存時要用ldm/stm指令。
各種后綴以理解為主,不需記憶,最常見的是stmia和stmfd。
謹記:操作棧時使用相同的后綴就不會出錯,不管是滿棧還是空棧、增棧還是減棧。
常用gun偽指令:
global _start @ 給_start外部鏈接屬性
.section .text @ 指定當前段為代碼段
.ascii .byte .short .long .word
.quad .float .string @ 定義數據
.align 4 @ 以4字節對齊
.balignl 16 0xabcdefgh @ 16字節對齊填充
.equ @ 類似於C中宏定義
偶爾會用到的gun偽指令
.end @標識文件結束
.include @ 頭文件包含
.arm / .code32 @聲明以下為arm指令
.thumb / .code16 @聲明以下為thubm指令
重要的幾個偽指令
ldr 大范圍的地址加載指令
adr 小范圍的地址加載指令
adrl 中等范圍的地址加載指令
nop 空操作
ARM中有一個ldr指令,還有一個ldr偽指令
一般都使用ldr偽指令而不用ldr指令
adr與ldr
adr編譯時會被1條sub或add指令替代,而ldr編譯時會被一條mov指令替代或者文字池方式處理;
adr總是以PC為基准來表示地址,因此指令本身和運行地址有關,可以用來檢測程序當前的運行地址在哪里
ldr加載的地址和鏈接時給定的地址有關,由鏈接腳本決定。
@筆記記得有點不清晰,希望在學習ARM在座的各位指出哪有錯,大家一起進步,共同學習。@
