###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加載的地址和鏈接時給定的地址有關,由鏈接腳本決定。