朱老師ARM裸機(jī)學(xué)習(xí)筆記(六):ARM匯編
匯編指令和偽匯編指令
匯編指令:CPU指令的助記符
偽匯編指令:本質(zhì)上不是指令,是編譯器環(huán)境提供的,目的是用來指導(dǎo)編譯過程,經(jīng)過編譯后偽指令最終不會(huì)生成機(jī)器碼
ARM采用RISC架構(gòu),CPU本身不能直接讀取內(nèi)存(CISC結(jié)構(gòu)的可以直接讀取內(nèi)存),而需要先將內(nèi)存中內(nèi)容載入CPU中通用寄存器才能被CPU執(zhí)行。
ldr (load register) 將內(nèi)存內(nèi)容加載進(jìn)入通用寄存器
str (store register) 將寄存器內(nèi)容存入內(nèi)存空間
同一指令經(jīng)常附帶不同后綴,變成不同的指令。經(jīng)常使用的后綴有:
如果后綴條件滿足才執(zhí)行。
例如:
mov r0, r1 @r0 = r1
moveq r0,r1 @ if(eq) r0 =r1
條件后綴執(zhí)行注意:條件后綴是否成立,不是取決于本句代碼,而是取決于這句代碼之前的代碼運(yùn)行后的結(jié)果。
ARM匯編的特點(diǎn)4:多級(jí)指令流水線S5PV210使用13級(jí)流水線。PC指向正被取值的指令,而非正在執(zhí)行的指令。
數(shù)據(jù)處理指令數(shù)據(jù)傳輸指令mov (move)
movr1,r0@兩個(gè)寄存器之間數(shù)據(jù)傳遞r1=r0movr1,#0xFF@將立即數(shù)賦值給寄存器r1=0xFF
mvn 用法和mov一樣,區(qū)別是mvn是按位取反后傳遞
r1=0xFF,執(zhí)行movr0,r1后r0=0xFF執(zhí)行mvnr0,r1后r0=0xffffff00算術(shù)指令
add 加法指令add r2, r0, r1 @(r2 = r0+r1)
sub 減法指令sub r2, r0, r1 @(r2 = r0 - r1)
rsb 逆向減法指令
adc 帶進(jìn)位加法指令
sbc 帶借位減法指令
rsc 帶借位的逆向減法指令
and 邏輯與
orr 邏輯或
eor 邏輯異或
bic 位清除指令 (bic r0, r1, #0x1F @將r1中的數(shù)的bit0到bit4清零后賦值給r0 0x1F = 0001 1111)
cmp cmp r0, r1 @(r0 - r1 = 0?)
cmn cmn r0, r1 @(r0 + r1 = 0?)
tst tst r0, 0xf @測(cè)試r0的bit0-bit3是否全為0
teq teq r0,r1, @P = r0 EOR r1
比較指令不用后加S 就能影響CPSR中的標(biāo)志位。
mvl mla umull umlal smull smlal 都不常用,這里只作為知識(shí)點(diǎn)羅列。
前導(dǎo)零計(jì)數(shù)clz 返回操作數(shù)二進(jìn)制編碼中第一個(gè)1前0的個(gè)數(shù)
CPSR訪問指令mrs & msr
mrs 用來讀psr (cpsr&spsr)
msr 用來寫psr
mrs r0, cpsr 將cpsr的值讀入到r0中
……………… 處理r0的值
msr cpsr, r0 將r0的值寫入到cpsr中
cpsr : 程序狀態(tài)寄存器,CPU中只有一個(gè),記錄程序運(yùn)行狀態(tài)
spsr:CPU中有五個(gè),分別在五種異常模式下,作用是從普通模式進(jìn)入異常模式時(shí),用來保存之前普通模式下的cpsr的,在返回普通模式時(shí)恢復(fù)原來的cpsr。
b & bl &bx
b 直接跳轉(zhuǎn)
bl (branch and link) 跳轉(zhuǎn)前把返回地址存在lr寄存器中,以便返回。
bx 跳轉(zhuǎn)同時(shí)切換到ARM模式,一般用于異常處理的跳轉(zhuǎn)。
ldr/srt & ldm/stm & swp
單個(gè)字/半字/字節(jié)訪問 ldr/str
多字批量訪問 ldm/stm
swp r1, r2, [r0] 內(nèi)存和寄存器交換指令,將r0所指向內(nèi)存中的數(shù)據(jù)寫入r1,并將r2中的數(shù)據(jù)寫入到r0所指向的內(nèi)存。
swp r1, r1, [r0] 互換
swi (software interrupt) 用來實(shí)現(xiàn)操作系統(tǒng)中的系統(tǒng)調(diào)用。
匯編中的立即數(shù)ARM指令都是32位,除了指令標(biāo)記和操作標(biāo)記外,本身只能附帶很少位數(shù)的立即數(shù),因此立即數(shù)有合法和非法之分。
合法立即數(shù):經(jīng)過任意位數(shù)的移位后非零部分可以用8位標(biāo)識(shí)的即為合法立即數(shù)(非零部分少于等于8位,0x000000ff 是合法立即數(shù),0x00ff0000是合法立即數(shù),0xf000000f循環(huán)移位之后仍然是合法立即數(shù),0x000001ff是非法立即數(shù))
協(xié)處理器以及協(xié)處理器指令什么是協(xié)處理器Soc內(nèi)部另一處理核心,協(xié)助CPU實(shí)現(xiàn)某些功能,被主CPU調(diào)用執(zhí)行一定的任務(wù)。CP15 (cooperation processor)
協(xié)處理器和MMU、cache、TLB等處理有關(guān),功能上和操作系統(tǒng)的虛擬地址映射、cache等的管理有關(guān)。
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
ldr/str每周期只能訪問4個(gè)字節(jié)內(nèi)存,如果需要批量讀取,寫入內(nèi)存時(shí)太慢,這個(gè)時(shí)候就要用ldm/stm (load register mutiplt / store register mutiplt)
多寄存器訪問舉例
stmia sp, {r0-r12}
將r0存入sp指向的內(nèi)存處,然后地址+4,將r1存入內(nèi)存,然后地址再+4……直到將r12內(nèi)容存入內(nèi)存。棧類型
空棧:棧指針指向空位,每次存入數(shù)據(jù)后,sp+4
滿棧:棧指針指向滿位,每次存入數(shù)據(jù)時(shí),先sp+4然后再存入數(shù)據(jù)
增棧:棧指針移動(dòng)時(shí)向地址增加的方向移動(dòng)
減棧:棧指針移動(dòng)時(shí)向地址減小的方向移動(dòng)
因此有四種棧類型:空增棧,空減棧,滿增棧,滿減棧。
操作棧的時(shí)候使用相同的后綴,就會(huì)避免出錯(cuò)。
!的作用ldmia r0, {r2-r3} @把r0指向的內(nèi)存中的數(shù)據(jù)讀入到r2中,然后內(nèi)存地址+4再將+4后地址中的數(shù)據(jù)讀入到r3中。指令執(zhí)行完畢后r0中的值不變。
ldmia r0!, {r2-r3} @把r0指向的內(nèi)存中的數(shù)據(jù)讀入到r2中,然后內(nèi)存地址+4再將+4后地址中的數(shù)據(jù)讀入到r3中。指令執(zhí)行完畢后r0中的值變化。
感嘆號(hào)的作用就是r0的值在ldm過程中發(fā)生的增加或者減小最后寫會(huì)到r0中。
^的作用ldmfd sp!, {r0-r6, pc}
ldmfd sp!, {r0-r6, pc}^
^:在目標(biāo)寄存器中有pc時(shí),會(huì)同時(shí)將spsr寫入到cpsr,一般用在異常返回的時(shí)候。
偽指令和具體的編譯器相關(guān),我們使用GNU工具鏈,因此學(xué)習(xí)GNU環(huán)境下達(dá)匯編偽指令。
GNU匯編中的一些符號(hào)@ 行注釋,可以在指令后邊也可以在行首
: 以冒號(hào)結(jié)束的是標(biāo)號(hào)
. 點(diǎn)號(hào)表示當(dāng)前指令的地址
立即數(shù)前面加?;蛘?,表示這是個(gè)立即數(shù)
.end匯編文件的結(jié)束,不加無所謂.include頭文件包含.arm或者.code32聲明以下的代碼為arm指令不是thumb指令.thumb或者.code16聲明以下的代碼為thumb指令
ldr大范圍的地址加載指令adr小范圍的地址加載指令adrl中等范圍的地址加載指令nop空操作
AAAA:.word 0xAABBFF 類似于C語(yǔ)言的 int AAAA = 0xAABBFF;
.balignl 16, 0xABCDEF 對(duì)齊+填充,b表示位填充,最后的l表示long,16表示16字節(jié)對(duì)齊,0xABCDEF表示填充的原料。
0x00000008 : .balignl 16, 0xABCDEF,
0x0000000C: 0xABCDEF
0x00000010: 下一條指令
ARM中有一個(gè)ldr指令,還有一個(gè)ldr偽指令。兩者的區(qū)別:
ldr r0, #0xFF @ldr指令
ldr r0, =0xFF @ldr偽指令 涉及到合法/非法立即數(shù),還涉及到ARM文字池
adr 和 ldr的差別:
- adr編譯時(shí)會(huì)被1條sub或add指令替代,而ldr編譯時(shí)會(huì)被一條mov指令替代或者文字池方式處理;
- adr總是以PC為基準(zhǔn)來表示地址,因此指令本身和運(yùn)行地址有關(guān),可以用來檢測(cè)程序當(dāng)前的運(yùn)行地址在哪里
-ldr加載的地址和鏈接時(shí)給定的地址有關(guān),由鏈接腳本決定。