彙編指令和僞彙編指令
彙編指令:CPU指令的助記符
僞彙編指令:本質上不是指令,是編譯器環境提供的,目的是用來指導編譯過程,經過編譯後僞指令最終不會生成機器碼
ARM彙編的特點
ARM彙編的特點1:LDR/STR架構
ARM採用RISC架構,CPU本身不能直接讀取內存(CISC結構的可以直接讀取內存),而需要先將內存中內容載入CPU中通用寄存器才能被CPU執行。
ldr (load register) 將內存內容加載進入通用寄存器
str (store register) 將寄存器內容存入內存空間
ARM彙編的特點2:8種尋址方式
類別 | 示例 |
---|---|
寄存器尋址 | mov r1, r2 |
立即尋址 | mov r0, #0xFF00} |
寄存器移位尋址 | mov r0, r1, lsl #3 @(r0=r1<<3) |
寄存器間接尋址 | ldr r1, [r2] |
基址變址尋址 | ldr r1,[r2,#4] @r1 = r2+4 |
多寄存器尋址 | ldmia r1!,{r2-r7,r12} |
堆棧尋址 | stmfd sp!, {r1-r7,lr} |
相對尋址 | beq flag |
ARM彙編的特點3:指令後綴
同一指令經常附帶不同後綴,變成不同的指令。經常使用的後綴有:
後綴 | 功能 |
---|---|
B (byte) | 功能不變,操作長度變爲8位 |
H (half word) | 功能不變,長度變爲16位 |
S (signed) | 功能不變,操作數變爲有符號 如 ldr ldrb ldrh ldrsb ldrsh |
S (S標誌) | 功能不變,影響CPSR標誌位 如 mov和movs |
ARM彙編的特點3:條件執行後綴
如果後綴條件滿足才執行。
例如:
mov r0, r1 @r0 = r1
moveq r0,r1 @ if(eq) r0 =r1
條件後綴執行注意:條件後綴是否成立,不是取決於本句代碼,而是取決於這句代碼之前的代碼運行後的結果。
ARM彙編的特點4:多級指令流水線
S5PV210使用13級流水線。PC指向正被取值的指令,而非正在執行的指令。
數據處理指令
數據傳輸指令
mov (move)
mov r1, r0 @兩個寄存器之間數據傳遞 r1 = r0
mov r1, #0xFF @將立即數賦值給寄存器 r1 = 0xFF
mvn 用法和mov一樣,區別是mvn是按位取反後傳遞
r1 = 0xFF,執行mov r0, r1 後 r0 = 0xFF
執行mvn r0, r1 後 r0 = 0xffffff00
算術指令
add 加法指令add r2, r0, r1 @(r2 = r0+r1)
sub 減法指令sub r2, r0, r1 @(r2 = r0 - r1)
rsb 逆向減法指令
adc 帶進位加法指令
sbc 帶借位減法指令
rsc 帶借位的逆向減法指令
邏輯指令
and 邏輯與
orr 邏輯或
eor 邏輯異或
bic 位清除指令 (bic r0, r1, #0x1F @將r1中的數的bit0到bit4清零後賦值給r0 0x1F = 0001 1111)
比較指令
cmp cmp r0, r1 @(r0 - r1 = 0?)
cmn cmn r0, r1 @(r0 + r1 = 0?)
tst tst r0, 0xf @測試r0的bit0-bit3是否全爲0
teq teq r0,r1, @P = r0 EOR r1
比較指令不用後加S 就能影響CPSR中的標誌位。
乘法指令
mvl mla umull umlal smull smlal 都不常用,這裏只作爲知識點羅列。
前導零計數
clz 返回操作數二進制編碼中第一個1前0的個數
CPSR訪問指令
mrs & msr
mrs 用來讀psr (cpsr&spsr)
msr 用來寫psr
mrs r0, cpsr 將cpsr的值讀入到r0中
……………… 處理r0的值
msr cpsr, r0 將r0的值寫入到cpsr中
cpsr : 程序狀態寄存器,CPU中只有一個,記錄程序運行狀態
spsr:CPU中有五個,分別在五種異常模式下,作用是從普通模式進入異常模式時,用來保存之前普通模式下的cpsr的,在返回普通模式時恢復原來的cpsr。
跳轉指令
b & bl &bx
b 直接跳轉
bl (branch and link) 跳轉前把返回地址存在lr寄存器中,以便返回。
bx 跳轉同時切換到ARM模式,一般用於異常處理的跳轉。
訪存指令
ldr/srt & ldm/stm & swp
單個字/半字/字節訪問 ldr/str
多字批量訪問 ldm/stm
swp r1, r2, [r0] 內存和寄存器交換指令,將r0所指向內存中的數據寫入r1,並將r2中的數據寫入到r0所指向的內存。
swp r1, r1, [r0] 互換
軟中斷指令
swi (software interrupt) 用來實現操作系統中的系統調用。
彙編中的立即數
ARM指令都是32位,除了指令標記和操作標記外,本身只能附帶很少位數的立即數,因此立即數有合法和非法之分。
合法立即數:經過任意位數的移位後非零部分可以用8位標識的即爲合法立即數(非零部分少於等於8位,0x000000ff 是合法立即數,0x00ff0000是合法立即數,0xf000000f循環移位之後仍然是合法立即數,0x000001ff是非法立即數)
協處理器以及協處理器指令
什麼是協處理器
Soc內部另一處理核心,協助CPU實現某些功能,被主CPU調用執行一定的任務。CP15 (cooperation processor)
協處理器和MMU、cache、TLB等處理有關,功能上和操作系統的虛擬地址映射、cache等的管理有關。
協處理器訪問指令
mcr & mrc
mrc 用於讀取CP15中的寄存器
mcr 用於寫CP15中的寄存器
Rd:ARM的普通寄存器,不能是r15/pc
Crn:cp15的寄存器,合法值爲c0 - c15
Crm:cp15的寄存器,一般均爲c0
mrc p15, 0, r0, c1, c0, 0
mcr p15, 0, r0, c1, c0, 0
ldm/stm與棧的處理
ldr/str每週期只能訪問4個字節內存,如果需要批量讀取,寫入內存時太慢,這個時候就要用ldm/stm (load register mutiplt / store register mutiplt)
多寄存器訪問舉例
stmia sp, {r0-r12}
將r0存入sp指向的內存處,然後地址+4,將r1存入內存,然後地址再+4……直到將r12內容存入內存。
棧類型
空棧:棧指針指向空位,每次存入數據後,sp+4
滿棧:棧指針指向滿位,每次存入數據時,先sp+4然後再存入數據
增棧:棧指針移動時向地址增加的方向移動
減棧:棧指針移動時向地址減小的方向移動
因此有四種棧類型:空增棧,空減棧,滿增棧,滿減棧。
八種後綴
後綴 | 意義 |
---|---|
ia (increase after) | 先傳輸,再地址+4 |
ib (increase before) | 先地址+4,再傳輸 |
da (decrease after) | 先傳輸,再地址-4 |
db (decreade before) | 先地址-4,再傳輸 |
fd (full decrease) | 滿遞減棧 |
ed (empty decrease) | 空遞減棧 |
fa | 滿遞增棧 |
ea | 空遞增棧 |
操作棧的時候使用相同的後綴,就會避免出錯。
!的作用
ldmia r0, {r2-r3} @把r0指向的內存中的數據讀入到r2中,然後內存地址+4再將+4後地址中的數據讀入到r3中。指令執行完畢後r0中的值不變。
ldmia r0!, {r2-r3} @把r0指向的內存中的數據讀入到r2中,然後內存地址+4再將+4後地址中的數據讀入到r3中。指令執行完畢後r0中的值變化。
感嘆號的作用就是r0的值在ldm過程中發生的增加或者減小最後寫會到r0中。
^的作用
ldmfd sp!, {r0-r6, pc}
ldmfd sp!, {r0-r6, pc}^
^:在目標寄存器中有pc時,會同時將spsr寫入到cpsr,一般用在異常返回的時候。
GNU彙編僞指令
僞指令和具體的編譯器相關,我們使用GNU工具鏈,因此學習GNU環境下達彙編僞指令。
GNU彙編中的一些符號
@ 行註釋,可以在指令後邊也可以在行首
: 以冒號結束的是標號
. 點號表示當前指令的地址
立即數前面加#或者$,表示這是個立即數
常見的gnu彙編僞指令
僞指令 | 意義 |
---|---|
.globl _start | 給_start外部鏈接屬性 |
.section .text | 指定當前爲代碼段 |
.ascii .byte .short .long .word .quad .float .string | 定義數據 |
.align 4 | 以16(2^4)字節內存地址對齊 |
.balignl 16,0xABCDEF | 16字節對齊填充 |
.equ | 類似於C中的宏定義 |
.end | 彙編文件的結束,不加無所謂 |
.include | 頭文件包含 |
.arm或者.code32 | 聲明以下的代碼爲arm指令不是thumb指令 |
.thumb或者.code16 | 聲明以下的代碼爲thumb指令 |
ldr | 大範圍的地址加載指令 |
adr | 小範圍的地址加載指令 |
adrl | 中等範圍的地址加載指令 |
nop | 空操作 |
- AAAA:.word 0xAABBFF 類似於C語言的 int AAAA = 0xAABBFF;
- .balignl 16, 0xABCDEF 對齊+填充,b表示位填充,最後的l表示long,16表示16字節對齊,0xABCDEF表示填充的原料。
- 0x00000008 : .balignl 16, 0xABCDEF,
- 0x0000000C: 0xABCDEF
- 0x00000010: 下一條指令
- ARM中有一個ldr指令,還有一個ldr僞指令。兩者的區別:
ldr r0, #0xFF @ldr指令
ldr r0, =0xFF @ldr僞指令 涉及到合法/非法立即數,還涉及到ARM文字池
adr 和 ldr的差別:
- adr編譯時會被1條sub或add指令替代,而ldr編譯時會被一條mov指令替代或者文字池方式處理;
- adr總是以PC爲基準來表示地址,因此指令本身和運行地址有關,可以用來檢測程序當前的運行地址在哪裏
-ldr加載的地址和鏈接時給定的地址有關,由鏈接腳本決定。