日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

ARM汇编指令集

發布時間:2023/12/20 编程问答 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 ARM汇编指令集 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

提示:文章寫完后,目錄可以自動生成,如何生成可參考右邊的幫助文檔

文章目錄

  • 前言
  • 1.8種尋址方式
  • 2.指令后綴
  • 3.條件執行后綴
  • 4.數據傳輸和跳轉指令詳解
  • 5.協處理器和協處理器指令詳解
  • 6.ldm/stm與棧的處理
  • 7.ARM匯編偽指令
    • GUN平臺無關
      • (1)符號定義偽指令
      • (2)數據定義偽指令
      • (3)匯編控制偽操作
    • GUN平臺相關
    • .balignl
    • 總結


前言


1.8種尋址方式

寄存器尋址 mov r1, r2(C語言中的r1=r2)
立即尋址(立即數) mov r0, #0xFF00(加#表示是一個數字)
寄存器移位尋址 mov r0, r1, lsl #3(r1左移3位生成的數賦給r0,即乘2^3=8)
寄存器間接尋址 ldr r1, [r2]([r2]代表內存,內存的地址就在r2里面存著,r2就相當于指針,將[r2]中的內容給r1)
基址變址尋址 ldr r1, [r2, #4](r2+4)
多寄存器尋址 ldmia r1!, {r2-r7, r12}(加載:從內存往寄存器加載。一次訪問7個寄存器r2到r7,r12,r1內存著內存的地址,并且r1相當于一個數組,r1是數組的數組名,也就是數組的頭地址,里面有7個元素)
堆棧尋址 stmfd sp!, {r2-r7, lr}(從棧指針里面連續訪問(壓棧,彈棧))
相對尋址 beq flag(以pc為參考作一個偏移量)
flag:(是作為標號的,上面的指令執行時將跳到這個標號所在處執行,flag可以是其他任何字母或單詞)

2.指令后綴

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

3.條件執行后綴


比較有用的指令,比如beq 條件,當條件相等,則執行跳轉。

4.數據傳輸和跳轉指令詳解

1.數據處理指令:
數據傳輸指令 mov mvn
算術指令 add sub rsb adc sbc rsc
邏輯指令 and orr eor bic(位清除指令)
Bic r0,r0,#0x1f 將r0中的bit0到bit4清零后賦值給r0
比較指令 cmp cmn tst teq
(比較指令不用加后綴就可以影響cpsr中的標志位)
乘法指令 mvl mla umull umlal smull smlal
前導零計數 clz
2. cpsr訪問指令
mrs用來讀psr,msr用來寫psr
CPSR寄存器比較特殊,需要專門的指令訪問,這就是mrs和msr。
程序舉例:@mrs r0,cpsr
@bic r0,r0,#0x1f
@orr r0,r0,#0xd3
@msr cpsr,r0
msr cpsr_c,#0xd3 (_c是cpsr的一個塊,上文有圖可看出cpsr分為f,s,x,c四塊,所以這一條語句=上面四條語句)
3.跳轉(分支)指令
b & bl & bx
b:直接跳轉(就沒打算返回,相當于C語言的goto指令)
bl:branch and link,跳轉前把返回地址放入lr中,以便返回,用于函數調用
bx:跳轉同時切換到ARM模式,一般用于異常處理的跳轉。(現在沒用了)
4.訪存指令
ldr/str & ldm/stm & swp
單個字/半字/字節訪問 ldr/str(若加上指令后綴,如h則訪問半個字的內容)
多字批量訪問 ldm/stm
swp r1, r2, [r0](此指令是一邊讀一邊寫的,將r0讀r1,將r2讀到r0)
swp r1, r1, [r0](寄存器和內存交換內容)
5.立即數
合法立即數與非法立即數。
ARM指令都是32位,除了指令標記和操作標記外,本身只能附帶很少位數的立即數。因此立即數有合法和非法之分。
合法立即數:經過任意位數的移位后非零部分可以用8位表示的即為合法立即數。合法:0xff,0xf00000f。非法:x01ff
6.軟中斷指令
swi(software interrupt)
軟中斷指令用來實現操作系統中系統調用
7.指令舉例:
1.mov(move) mov r1, r0 @兩個寄存器之間數據傳遞
mov r1, #0xff @將立即數賦值給寄存器
mvn和mov用法一樣,區別是mov是原封不動的傳遞,而mvn是按位取反后傳遞。按位取反的含義:譬如r1 = 0x000000ff,然后mov r0, r1 后,r0 = 0xff但是我mvn r0, r1后,r0=0xffffff00。
2.and 邏輯與
orr 邏輯或
eor 裸機異或
3.bic 位清除指令
bic r0,r1,#0x1f @ 將r1中的數的bit0到bit4清零后賦值給r0 0x1f = 0x0000001f=0x0000```11111
4.比較指令:
cmp cmp r0, r1 等價于 sub r2, r0, r1 (r2 = r0 - r1)
cmn cmn r0, r1 等價于 add r0, r1
tst tst r0, #0xf @測試r0的bit0~bit3是否全為0
teq
比較指令用來比較2個寄存器中的數
注意:比較指令不用后加s后綴就可以影響cpsr中的標志位。
5.合法立即數: 0x000000ff 0x00ff0000 0xf000000f
非法立即數: 0x000001ff

5.協處理器和協處理器指令詳解

1.協處理器cp15操作指令
mrc用于讀取CP15中的寄存器
mcr用于寫入CP15中的寄存器
2.什么是協處理器
SoC內部另一處理核心,協助主CPU實現某些功能被主CPU調用執行一定任務。
ARM設計上支持多達16個協處理器,但是一般SoC只實現其中的CP15.(cp:coprocessor)。
協處理器和MMU、cache、TLB等處理有關,功能上和操作系統的虛擬地址映射、cache管理等有關。
3.MRC & MCR的使用方法
mcr{} p15, <opcode_1>, , , , {<opcode_2>}
opcode_1:對于cp15永遠為0
Rd:ARM的普通寄存器,不能是r15(pc),否則結果不定,
Crn:cp15的寄存器,合法值是c0~c15(都是特殊功能寄存器,cp15的寄存器詳情查百度)
Crm:cp15的寄存器,一般均設為c0
opcode_2:一般省略或為0
舉例(來自于uboot)
mrc p15, 0, r0, c1, c0, 0
orr r0, r0, #1
mcr p15, 0, r0, c1, c0, 0

6.ldm/stm與棧的處理

1.為什么需要多寄存器訪問指令

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個寄存器的讀寫
3.8種后綴
ia(increase after)先傳輸,再地址+4
ib(increase before)先地址+4,再傳輸
da(decrease after)先傳輸,再地址-4
db(decrease before)先地址-4,再傳輸
fd(full decrease)滿遞減堆棧
ed(empty decrease)空遞減堆棧
fa(·······) 滿遞增堆棧
ea(·······)空遞增堆棧
4.四種棧
空棧:棧指針指向空位,每次存入時可以直接存入然后棧指針移動一格;而取出時需要先移動一格才能取出
滿棧:棧指針指向棧中最后一格數據,每次存入時需要先移動棧指針一格再存入;取出時可以直接取出,然后再移動棧指針
增棧:棧指針移動時向地址增加的方向移動的棧
減棧:棧指針移動時向地址減小的方向移動的棧
5.!的作用
ldmia r0, {r2 - r3}
ldmia r0!, {r2 - r3}
ia:increase after后綴,將r0對應的地址里的內容讀到r2,再地址加4,將加4后的地址里的內容讀到r3,注意是地址中的內容,不是地址值。讀好后r0中的值不變,還是初始地址值。
感嘆號的作用就是r0的值在ldm過程中發生的增加或者減少最后寫回到r0去,也就是說ldm時會改變r0的值。
6.^的作用
ldmfd sp!, {r0 - r6, pc}
ldmfd sp!, {r0 - r6, pc}^
^的作用:在目標寄存器中有pc時,會同時將spsr寫入到cpsr,一般用于從異常模式返回。

7.ARM匯編偽指令

GUN平臺無關

(1)符號定義偽指令

.global,.local,.set,.equ

.global
使得符號對連接器可見,變為對整個工程可用的全局變量,通俗講就是定義全局變量
eg:
.global symbol

.local
表示符號對外部不可見,只對本文件可見,通俗講就是定義局部變量
eg:
.local symbol

.set
給一個全局變量或局部變量賦值,和.equ的功能一樣
eg:
.set symbol expr
.set start, 0x40
.set start, 0x50
mov r1, #start ;r1里面是0x50

.equ
和.set一樣,只是格式不同
eg:
symbol .equ expr
start .equ, 0x40
start .equ, 0x50
mov r1, #start ;r1里面是0x50

(2)數據定義偽指令

.byte,.short,.long,.quad,.float,.string,.asciz,.ascii,.rept

.byte
在存儲器中分配1個字節,用指定的數據對存儲單元進行初始化
label: .byte expr ;label是程序標號,expr可以是-128~255的數字,也可是字符
eg:
a: .byte #1 ;等價于C語言中的char a=1;

.short
在存儲器中分配2個字節,用指定的數據對存儲單元進行初始化
eg:
a: .short 0x1234

.long / .word
在存儲器中分配4個字節,用指定的數據對存儲單元進行初始化
eg:
a: .word 0x12345678

.quad
在存儲器中分配8個字節,用指定的數據對存儲單元進行初始化
eg:
a: .quad 0x12345678 ;等價于C中的long a=0x1234567812345678

.float
在存儲器中分配4個字節,用指定的浮點數據對存儲單元進行初始化
eg:
a: .float 1.11

.space /.skip
用于分配一塊連續的存儲區域并初始化為指定的值,如果后面的填充值省略不寫則在后面填充為0;
label: .space size,expr ;expr可以是4字節(32bit)以內的浮點數
eg:
a: space 8, 0x1

.string
定義一個字符串,默認是string8,還有string16,string32,string64
eg:
a: .space “hello world!”

.rpet
重復執行接下來的指令,以.rept開始,以.endr結束
eg:
.rept cnt ;cnt是重復次數

.endr

(3)匯編控制偽操作

流程控制偽指令主要有.if .else .endif .macro .endm .exitm

.if, .else, .endif
.if logical-expression

.elseif logical-expression2

.else

.endif

.macro, .endm, .exitm
該偽指令可以將一段代碼定義為一個整體,稱為宏指令。然后就可以在程序中通過宏指令多次調用該段代碼;而.exitm用于退出當前宏指令,宏指令可以使用一個或多個參數,當宏操作被展開時,這些參數被相應的值替換。包含在.macro和.endm之間的指令序列稱為宏定義體。在宏定義體的第一行應該聲明宏的原型,包含宏名所需要的參數,然后就可以在匯編程序中通過宏名來調用該指令序列。在源程序被編譯時,編譯器將宏調用展開,用宏定義中的指令序列代替程序中的宏調用,并將實際參數值傳遞給宏定義中的形式參數。
eg:
.macro macroname macargs …
…code…
.endm

雜項
.align 用于使程序當前位置滿足一定的對齊方式
.section 用來定義一個段的偽指令
.data 用來定義一個數據段
.text 用來定義一個代碼段
.include 用來包含一個頭文件
.arm 定義以下代碼使用arm指令集編譯
.code 32 同.arm
.code 16 同.thumb
.thumb 定義以下代碼使用thumb指令集編譯
.extern 用于聲明一個外部符號,用于兼容性其他匯編
.weak 用于聲明一個弱符號,如果這個符號沒有定義,編譯就忽略,而不會報錯
.end 表示匯編結束

GUN平臺相關

ADR
把標簽所在的地址加載到寄存器中,這個指令將基于PC相對偏移的地址或基于寄存器相對偏移的地址值讀取到寄存器中。當地址是字節對齊時,取值范圍為-255-255B;當地址是字對齊時取值范圍是-1020-1020B。該指令相當于 add , pc, offset
eg:
ADR

ADRL
用于將中等范圍地址讀取到寄存器中
ADRL

LDR
裝在一個32位的常數和一個地址寄存器,即將一個32位常數加載到一個寄存器中
ldr reg, =expr
reg:目標寄存器
expr:32位常量
匯編器根據expr的取值情況對ldr偽指令會做一下處理:

當expr表示的指令地址值沒有超過MOV指令或MVN指令的地址取值范圍時,匯編器用一對MOV和MVN代替LDR指令
當超過了的時候,匯編器將常數放入緩存,同時用一條基于PC的LDR讀取該常數
eg:
LDR R3,=0xff0 @將常數0xff0讀到內存中相當于MOV R3, #0xff0
LDR R1, =0xfff @將常數0xfff讀到內存,相當于LDR R1,[pc, offset_to_litpool] … litpool DCD 0xfff
LDR R2, =place @將place標號的地址讀入到R1中,相當于LDR R1,[pc, offset_to_litpool] … litpool DCD place

.balignl

字節對齊,保證此內容在以8字節的整數倍的后面。 l表示long,8字節 w表示半字,也就是兩字節,所以.balignw的意思也就一目了然

2.gnu匯編中的一些符號
@ 用來做注釋。可以在行首也可以在代碼后面同一行直接跟,和C語言中//類似# 做注釋(存疑)一般放在行首,表示這一行都是注釋而不是代碼。
:以冒號結尾的是標號(標記這一行指令的地址,可以當作flag,用b來跳轉)
. 點號在gnu匯編中表示當前指令的地址
C語言中死循環:while(1);
匯編死循環:flag:
b flag
或者 b.# 立即數前面要加#或$,表示這是個立即數
3.常用gnu偽指令
.global _start @ 給_start外部鏈接屬性
.section .text @ 指定當前段為代碼段
.ascii .byte .short .long .word @定義變量類型,相當于C中的int,char之類
.quad .float .string @ 定義數據
.align 4 @ 以16字節對齊:2^4
.balignl 16 0xabcdefgh @ 16字節對齊填充
4.偶爾會用到的gnu偽指令
.end @標識文件結束
.include @ 頭文件包含
.arm / .code32 @聲明以下為arm指令
.thumb / .code16 @聲明以下為thubm指令
5.最重要的幾個偽指令
ldr 大范圍的地址加載指令
adr 小范圍的地址加載指令
adrl 中等范圍的地址加載指令
nop 空操作
ARM中有一個ldr指令,還有一個ldr偽指令
一般都使用ldr偽指令而不用ldr指令(不用考慮立即數是否合法)
Ldr#后面跟指令,ldr=后面跟偽指令。
6.adr與ldr
adr編譯時會被1條sub或add指令替代,而ldr編譯時會被一條mov指令替代或者文字池方式處理;
adr總是以PC為基準來表示地址,因此指令本身和運行地址有關,可以用來檢測程序當前的運行地址在哪里
ldr加載的地址和鏈接時給定的地址有關,由鏈接腳本決定。

總結

1、8種尋址方式
寄存器尋址
立即尋址
寄存器移位尋址
寄存器間接尋址
基址尋址
多寄存器尋址
堆棧尋址
相對尋址

2、6類指令:
數據處理指令:
數據傳輸指令, MOV MVN
算術指令, ADD SUB RSB ADC SBC RSC
邏輯指令, AND ORR EOR BIC
比較指令, CMP CMN TST TEQ
乘法指令, MUL MLA UMULL UMLAL SMULL SMLAL
前導零計數。
程序狀態寄存器訪問指令:MRS MSR
跳轉指令: B BL BX
訪存指令: LDR/STR LDM/STM SWP
異常中斷產生指令: SWI
協處理器指令: mcr mrc

3、LDR/STR架構
LDR LDRB LDRH LDRSB LDRSH
STR STRB STRH STRSB STRSH
LDM/STM
SWP SWPB

4、指令后綴:B H S
5、條件后綴:
EQ/NE:等于/不等于(equal / not equal)
HS/LO:無符號數高于或等于/無符號數小于(higher or same/lower)
HI/LS:無符號數高于/無符號數低于或等于(higher/lower or same)
GE/LT:有符號數大于或等于/有符號數小于(greater or equal/less than)
GT/LE:有符號數大于/有符號數小于或等于(greater than/less or equal)
MI/PL:負/非負
VS/VC:溢出/不溢出(overflow set / overflow clear)
CS/CC:進位/無進位(carry set / carry clear

6、ldm/stm與棧的操作
ldmfd/stmfd
ldmia/stmia

7、合法、非法立即數

偽指令(gnu匯編偽指令)

ARM匯編程序常用的編譯環境有2個:ARMASM(ARM官方匯編格式,Windows中常用,如ADS、MDK,指令一般用全大寫)和GNU ARM ASM(開源社區常用,如uboot、linux,指令一般全小寫)。

@開頭的之后部分是注釋(@不一定非在行首,類似于C中的//)
#開頭的整行注釋。一般整行注釋用#而前面是代碼后面寫注釋的用@
:結尾的是標號
標號+f,表示在引用處向前找;標號+b,表示在引用的地方向后查找; 局部標號一般用數字1、2
點號“.”在匯編中表示當前指令的地址
直接操作數前綴用#或$

.global xx(有時寫為.globl) 給符號xx外部鏈接屬性,一般為了在別的文件中引用這個符號
.section .mysection 自定義數據段,段名為“.mysection”
.align 2 4字節對齊
.balign/.balignw/.balignl 字節/2字節/4字節填充
注意.align數字是2的n次方,而.balign數字是直接數字
.ascii “string…” 定義一個ascii字符串
.byte .short .long .word .quad .float .string .ascii
.equ .set 賦值語句
.end 文件結束
.include 頭文件包含
.if .else .endif 條件編譯,類似于C語言的#if #elif #endif
.arm / .code32 以ARM指令格式編譯
.thumb / .code16 以thumb指令格式編譯

nop
ldr
adr

宏定義
.macro macroname
宏體
.endm

總結

以上是生活随笔為你收集整理的ARM汇编指令集的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。