【arm】arm的匯編指令及特點


###Date: 2018-7-15

轉載自:https://www.cnblogs.com/ziv3/p/6476114.html?utm_source=itdadao&utm_medium=referral

--------------------------------------------------------------------------------------------------------------------------------

指令和偽指令:前者編譯后會生成一串1和0組成的機器碼,后者幫助前者進行編譯過程,不會生成機器碼。

ARM匯編特點1:LDR/STR架構
ARM采用RISC架構,CPU本身不能直接讀取內存,而需要先將內存中內容加載入CPU中通用寄存器中才能被CPU處理。
ldr(load register)指令將內存內容加載入通用寄存器。
str(store register)指令將寄存器內容存入內存空間中。
ldr/str組合用來實現 ARM CPU和內存數據交換  

(這兩個指令只能在寄存器和內存之間進行)

 

ARM匯編特點2:8種尋址方式

寄存器尋址                mov r1, r2
立即尋址        mov r0, #0xFF00

寄存器移位尋址      mov r0, r1, lsl #3(r1先左移3位再賦給r0)
寄存器間接尋址      ldr r1, [r2]  (r2加一個[]后表示一個內存地址)
基址變址尋址         ldr r1, [r2, #4](r2加4的內存地址)
多寄存器尋址         ldmia r1!, {r2-r7, r12}(r1有初始值,將r2到r7,r12的值傳入相應的地址,每次傳輸之后遞增r1指向的存儲地址,因為是32位,每次遞增的地址應該是4bytes)
堆棧尋址               stmfd sp!, {r2-r7, lr}

相對尋址               beq flag
    flag:      (這是個標號)

ARM匯編特點3:指令后綴

同一指令經常附帶不同后綴,變成不同的指令。經常使用的后綴有:
B(byte)功能不變,操作長度變為8位
H(half word)功能不變,長度變為16位
S(signed)功能不變,操作數變為有符號
如 ldr ldrb ldrh ldrsb ldrsh
S(S標志)功能不變,影響CPSR標志位
如 mov和movs movs r0, #0    (mov不會改變cpsr中的標志位,要讓標志位變化需使用movs)

ARM匯編特點4:條件執行后綴

如果后綴條件滿足才執行。
例如: 
mov r0, r1     //r0 = r1 
moveq r0,r1  // if(eq) r0 =r1(上一條指令如果使cpsr中的標志位置或則進行這條語句)
條件后綴執行注意:條件后綴是否成立,不是取決於本句代碼,而是取決於這句代碼之前的代碼運行后的結果。

ARM匯編特點5:多級指令流水線

 

n級就會有PC-2^n

 

數據處理指令

數據傳輸指令

mov (move)

mov r1, r0     @兩個寄存器之間數據傳遞 r1 = r0
mov r1, #0xFF   @將立即數賦值給寄存器 r1 = 0xFF
mvn 用法和mov一樣,區別是mvn是按位取反后傳遞

例如:r1 = 0xF0,執行mov r0, r1 后 r0 = 0xF0
         執行mvn r0, r1 后 r0 = 0x0F
算術指令

add 加法指令add r2, r0, r1     @(r2 = r0+r1) 
sub 減法指令sub r2, r0, r1     @(r2 = r0 - r1) 
rsb 逆向減法指令 rsb r2,r0,r1     @(r1 = r1 - r0)
adc 帶進位加法指令

sbc 帶借位減法指令 
rsc 帶借位的逆向減法指令

邏輯指令

and 邏輯與 
orr 邏輯或         ORR   R0,R0,#3             @r0先與3相或,在把值賦給r0
eor 邏輯異或 
bic 位清除指令 (bic r0, r1, #0x1F @將r1中的數的bit0到bit4清零后賦值給r0 )

比較指令

cmp   cmp r0, r1   @(r0 - r1 = 0?) 
cmn   cmn r0, r1   @(r0 + r1 = 0?) 
tst     tst r0, 0x0f   @測試r0的bit0-bit3是否全為0 
teq      teq r0,r1     @P = r0 EOR r1 
比較指令不用后加S 就能影響CPSR中的標志位。

乘法指令

mvl mla umull umlal smull smlal 都不常用,這里只作為知識點羅列。

前導零計數

clz 計算返回操作數二進制編碼中第一個1前0的個數

CPSR訪問指令(不可用mov訪問)

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] 互換(將r0所指向內存中的數據寫入第一個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    (查閱cp15協處理器的作用位,存入PC中的都是指令,不可以是內容)

例2:

此例子用於打開mmu(on,所有地址為虛擬地址;off,所有地址為實地址)
mrc p15, 0, r0, c1, c0, 0
orr r0, r0, #1
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內容存入內存。
棧類型

空棧:棧指針指向空位,每次存入時可以直接存入然后棧指針移動一格;而取出時需要先移動一格才能取出(用完之后都得移動)
滿棧:棧指針指向棧中最后一格數據,每次存入時需要先移動棧指針一格再存入;取出時可以直接取出,然后再移動棧指針(用完之后都得移動)
增棧:棧指針移動時向地址增加的方向移動的棧
減棧:棧指針移動時向地址減小的方向移動的棧

因此有四種棧類型:空增棧,空減棧,滿增棧,滿減棧。

八種后綴

后綴 意義
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中的值變化(為r3內容的地址)。

感嘆號的作用就是r0的值在ldm過程中發生的增加或者減小最后寫會到r0中。

^的作用

ldmfd sp!, {r0-r6, pc}  (操作了八個寄存器)
ldmfd sp!, {r0-r6, pc}^ (此項操作實際操作了9個寄存器,spsr->cpsr)
^:在目標寄存器中有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指令

eg.

.word 0xAABBFF 類似於C語言的 int AAAA = 0xAABBFF;

.align 4 @ 16字節對齊
.align 2 @ 4字節對齊

.balignl 16, 0xABCDEF 對齊+填充,b表示位填充,最后的l表示long,16表示16字節對齊,0xABCDEF表示填充的原料。 
0x00000008 : .balignl 16, 0xABCDEF,
0x0000000C: 0xABCDEF
0x00000010: 下一條指令

 

ldr 大范圍的地址加載指令
adr 小范圍的地址加載指令
adrl 中等范圍的地址加載指令
nop 空操作

ARM中有一個ldr指令,還有一個ldr偽指令。兩者的區別: 
ldr r0, #0xFF @ldr指令 
ldr r0, =0xFF @ldr偽指令 涉及到合法/非法立即數,還涉及到ARM文字池
adr 和 ldr的差別: 
- adr編譯時會被1條sub或add指令替代,而ldr編譯時會被一條mov指令替代或者文字池方式處理; 
- adr總是以PC為基准來表示地址,因此指令本身和運行地址有關,可以用來檢測程序當前的運行地址在哪里 
-ldr加載的地址和鏈接時給定的地址有關,由鏈接腳本決定。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM