轉載:
https://blog.csdn.net/weifengzhimo/article/details/70477899
本來想自己整理的,但是懶癌發作。找到一篇寫的很清楚的。就貼上來了。
1.彙編指令格式
<opcode>{<cond>}{S}<Rd>,<Rn>{,<OP2>}
格式中<>的內容必不可少,{}中的內容可省略
<opcode>:表示操作碼,如ADD表示算術加法
{<cond>}:表示指令執行的條件域,如EQ、NE等。
{S}:決定指令的執行結果是否影響CPSR的值,使用該後綴則指令執行的結果影響CPSR的值,否則不影響
<Rd>:表示目的寄存器
<Rn>:表示第一個操作數,爲寄存器
<op2>:表示第二個操作數,可以是立即數、寄存器或寄存器移位操作數
例子:ADDEQS R0,R1,#8;其中操作碼爲ADD,條件域cond爲EQ,S表示該指令的執行影響CPSR寄存器的值,目的寄存器Rd爲R0,第一個操作數寄存器Rd爲R1,第二個操作數OP2爲立即數#8
2.指令的可選後綴
S:指令執行後程序狀態寄存器的條件標誌位將被刷新
ADDS R1,R0,#2
!:指令中的地址表達式中含有!後綴時,指令執行後,基址寄存器中的地址值將發生變化,變化的結果是:基址寄存器中的值(指令執行後)=指令執行前的值 + 地址偏移量
LDR R3,[R0,#2]! 指令執行後,R0 = R0 + 2
3.指令的條件執行
指令的條件後綴只是影響指令是否執行,不影響指令的內容
條件碼 |
助記符後綴 |
標誌 |
含義 |
0000 |
EQ |
Z置位 |
相等 |
0001 |
NE |
Z清零 |
不相等 |
0010 |
CS |
C指令 |
無符號數大於或等於 |
0011 |
CC |
C清零 |
無符號數小於 |
0100 |
MI |
N置位 |
負數 |
0101 |
PL |
N清零 |
正數或零 |
0110 |
VS |
V置位 |
溢出 |
0111 |
VC |
V清零 |
未溢出 |
1000 |
HI |
C置位Z清零 |
無符號數大於 |
1001 |
LS |
C清零Z置位 |
無符號數小於或等於 |
1010 |
GE |
N等於V |
帶符號數大於或等於 |
1011 |
LT |
N不等於V |
帶符號數小於 |
1100 |
GT |
Z清零且(N等於V) |
帶符號數大於 |
1101 |
LE |
Z置位或(N不等於V) |
帶符號數小於或等於 |
1110 |
AL |
忽略 |
無條件執行 |
例子:ADDEQ R4,R3,#1 相等則相加,即CPSR中Z置位時該指令執行,否則不執行。
4.ARM指令分類
助記符 |
指令功能描述 |
助記符 |
指令功能描述 |
ADC |
帶進位加法指令 |
MRC |
從協處理器寄存器到ARM寄存器的數據傳輸指令 |
ADD |
加法指令 |
MRS |
傳送CPSR或SPSR的內容到通用寄存器指令 |
AND |
邏輯與指令 |
MSR |
傳送通用寄存器到CPSR或SPSR的指令 |
B |
分支指令 |
MUL |
32位乘法指令 |
BIC |
位清零指令 |
MLA |
32位乘加指令 |
BL |
帶返回的分支指令 |
MVN |
數據取反傳送指令 |
BLX |
帶返回和狀態切換的分支指令 |
ORR |
邏輯或指令 |
BX |
帶狀態切換的分支指令 |
RSB |
逆向減法指令 |
CDP |
協處理器數據操作指令 |
RSC |
帶錯位的逆向減法指令 |
CMN |
比較反值指令 |
SBC |
帶錯位減法指令 |
CMP |
比較指令 |
STC |
協處理器寄存器寫入存儲器指令 |
EOR |
異或指令 |
STM |
批量內存字寫入指令 |
LDC |
存儲器到協處理器的數據傳輸指令 |
STR |
寄存器到存儲器的數據存儲指令 |
LDM |
加載多個寄存器指令 |
SUB |
減法指令 |
LDR |
存儲器到寄存器的數據加載指令 |
SWI |
軟件中斷指令 |
MCR |
從ARM寄存器到協處理器寄存器的數據傳輸指令 |
TEQ |
相等測試指令 |
MOV |
數據傳送指令 |
TST |
位測試指令 |
5.ARM尋址方式
尋址方式就是根據指令中操作數的信息來尋找操作數實際物理地址的方式
1)立即數尋址
MOV R0,#15 #15就是立即數
2)寄存器尋址
ADD R0, R1, R2 將R1和R2的內容相加,其結果存放在寄存器R0中
3)寄存器間接尋址
LDR R0, [R4] 以寄存器R4的值作爲操作數的地址,在存儲器中取得一個操作數存入寄存器R0中
4)寄存器移位尋址
ADD R0,R1,R2,LSL #1 將R2的值左移一位,所得值與R1相加,存放到R0中
MOV R0,R1,LSL R3 將R1的值左移R3位,然後將結果存放到R0中
5)基址變址尋址
LDR R0,[R1,#4] 將R1的值加4作爲操作數的地址,在存儲器中取得操作數放入R0中
LDR R0,[R1,#4]! 將R1的值加4作爲操作數的地址,在存儲器中取得操作數放入R0中,然後R1 = R1+4
LDR R0,[R1],#4 R0 = [R1],R1 = R1 +4
LDR R0,[R1,R2] R0 = [R1+R2]
6).多寄存器尋址
一條指令可以完成多個寄存器值的傳送(最多可傳送16個通用寄存器),連續的寄存器用“-”,否則用“,”
LDMIA R0!,{R1 - R4} R1 = [R0],R2=[R0+4],R3=[R0+8],R4=[R0+12]
後綴IA表示在每次執行玩加載/存儲操作後,R0按自長度增加。
7).相對尋址
以程序計數器PC的當前值爲基地址,指令中的地址標號作爲偏移量,將兩者相加之後得到操作數的有效地址,如下圖的BL分支跳轉
BL proc 跳轉到子程序proc處執行
...
proc MOV R0,#1
...
8).堆棧尋址
按先進先出的方式工作,堆棧指針用R13表示,總是指向棧頂,LDMFD和STMFD分別表示POP出棧和PUSH進棧
STMFD R13!,{R0 - R4};
LDMFD R13!,{R0 - R4};
6.數據處理指令
1). MOV指令
MOV {<cond>}{S} Rd,op2 將op2傳給Rd
MOV R1, R0 將寄存器R0的值傳到寄存器R1
MOV PC,R14 將寄存器R14的值傳到PC,常用於子程序返回
MOV R1,R0,LSL #3 將寄存器R0的值左移3位後傳給R1
MOV R0,#5 將立即數5傳給R0
2). MVN指令
MVN {<cond>}{S}Rd, op2 將op2取反傳給Rd
MVN R0,#0 將0取反後傳給R0,R0 = -1
MVN R1,R2 將R2取反,結果保存到R1
3). 移位指令
LSL 邏輯左移
LSR 邏輯右移
ASR 算術右移
ROR 循環右移
RRX 帶擴展的循環右移
4). ADD加法指令
ADD{<cond>}{S}Rd, Rn, op2
ADD R0,R1,R2 R0 = R1 + R2
ADD R0,R1,#5 R0 = R1 + 5
ADD R0,R1,R2,LSL #2 R0 = R1 + (R2左移2位)
5). ADC帶進位加法指令
ADC{<cond>}{S} Rd,Rn,op2 將Rn的值和操作數op2相加,再加上CPSR中C條件標誌位的值,並將結果保存到Rd中
例:用ADC完成64位加法,設第一個64位操作數保存在R2,R3中,第二個64位操作數放在R4,R5中,結果保存在R0,R1中
ADDS R0,R2,R4 低32位相加,產生進位
ADC R1,R3,R5 高32位相加,加上進位
6). SUB減法指令
SUB{<cond>}{S} Rd,Rn,op2 Rd = Rn - op2
SUB R0,R1,R2 R0 = R1 - R2
SUB R0,R1,#6 R0 = R1 -6
SUB R0,R2,R3,LSL #1 R0 = R2 - (R3左移1位)
7). SBC帶借位減法指令
SBC{<cond>}{S} Rd,Rn,op2 把Rn的值減去操作數op2,再減去CPSR中的C標誌位的反碼,並將結果保存到Rd中,Rd = Rn - op2 - !C
例:用SBC完成64位減法,設第一個64位操作數保存在R2,R3中,第二個64位操作數放在R4,R5中,結果保存在R0,R1中
SUBS R0,R2,R4 低32位相減,S影響CPSR
SBC R1,R3,R5 高32位相減,去除C的反碼
8). RSC帶借位的逆向減法指令
RSC{<cond>}{S} Rd,Rn,op2 把操作數op2減去Rn,再減去CPSR中的C標誌位的反碼,並將結果保存到Rd中,Rd = op2 - Rn - !C
9). 邏輯運算指令
AND{<cond>}{S} Rd,Rn,op2 按位與,Rd = Rn AND op2
ORR{<cond>}{S} Rd,Rn,op2 按位或,Rd = Rn OR op2
EOR{<cond>}{S} Rd,Rn,op2 按位異或,Rd = Rn EOR op2
10). CMP比較指令
CMP{<cond>}{S} Rd,Rn,op2 將Rn的值和op2進行比較,同時更新CPSR中條件標誌位的值(實際上是執行一次減法,但不存儲結果),當操作數Rn大於op2時,則此後帶有GT後綴的指令將可以執行(根據相應的指令判斷是否執行,如GT,LT等)。
CMP R1,#10 比較R1和10,並設置CPSR的標誌位
ADDGT R0,R0,#5 如果R1>10,則執行ADDGT指令,將R0加5
11). CMN反值比較指令
CMN{<cond>}{S} Rd,Rn,op2 將Rn的值和op2取反後進行比較,同時更新CPSR中條件標誌位的值(實際上將Rn和op2相加),後面的指令就可以根據條件標誌位決定是否執行。
CMN R0,R1 將R0和R1相加,並設置CPSR的值
12). MUL/MLA/SMULL/SMLAL/UMULL/UMLAL乘法指令
MUL 32位乘法指令
MLA 32位乘加指令
SMULL 64位有符號數乘法指令
SMLAL 64位有符號數乘加指令
UMULL 64位無符號數乘法指令
UMLAL 64位無符號數乘加指令
MUL{<cond>}{S} Rd,Rm,Rs Rd = Rm * Rs
MULS R0,R1,R2
MLA{<cond>}{S} Rd,Rm,Rs,Rn Rd = (Rm * Rs) + Rn
MLAS R0,R1,R2,R3
7.數據加載與存儲指令
助記符 |
說明 |
操作 |
LDR{}Rd,addr |
加載字數據 |
Rd = [addr] |
LDRB{}Rd,addr |
加載無符號字節數據 |
Rd = [addr] |
LDRT{}Rd,addr |
以用戶模式加載字數據 |
Rd = [addr] |
LDRBT{}Rd,addr |
以用戶模式加載無符號字節數據 |
Rd = [addr] |
LDRH{}Rd,addr |
加載無符號半字數據 |
Rd = [addr] |
LDRSB{}Rd,addr |
加載有符號字節數據 |
Rd = [addr] |
LDRSH{}Rd,addr |
加載有符號半字數據 |
Rd = [addr] |
STR{}Rd,addr |
存儲字數據 |
[addr] = Rd |
STRB{}Rd,addr |
存儲字節數據 |
[addr] = Rd |
STRT{}Rd,addr |
以用戶模式存儲字數據 |
[addr] = Rd |
STRBT{}Rd,addr |
以用戶模式存儲字節數據 |
[addr] = Rd |
STRH{}Rd,addr |
存儲半字數據 |
[addr] = Rd |
LDM{}{type}Rn{!},regs |
多寄存器加載 |
reglist = [Rn...] |
STM{}{type}Rn{!},regs |
多寄存器存儲 |
[Rn...] = reglist |
SWP{}Rd,Rm,[Rn] |
寄存器和存儲器字數據交換 |
Rd=[Rn],[Rn]=Rm(Rn!=Rd或Rm) |
SWP{}B Rd,Rm,[Rn] |
寄存器和存儲器字節數據交換 |
Rd = [Rn],[Rn] = Rm(Rn!=Rd或Rm) |
1). LDR/STR字數據加載/存儲指令
LDR/STR{<cond>}{T}Rd,addr LDR指令用於從存儲器中將一個32位的字數據加載到目的寄存器Rd中,當程序計數器PC作爲目的寄存器時,指令從存儲器中讀取的字數據被當做目的地址,從而可以實現程序流程的跳轉。
STR指令用於從源寄存器中將一個32位的字數據存儲到存儲器中,和LDR相反。後綴T可選。
LDR R4,START 將存儲地址爲START的字數據讀入R4
STR R5,DATA1 將R5存入存儲地址爲DATA1中
LDR R0,[R1] 將存儲器地址爲R1的字數據讀入存儲器R0
LDR R0,[R1,R2] 將存儲器地址爲R1+R2的字數據讀入存儲器R0
LDR R0,[R1,#8] 將存儲器地址爲R1+8的字數據讀入存儲器R0
LDR R0,[R1,R2,LSL #2] 將存儲器地址爲R1+R2*4的字數據讀入存儲區R0
STR R0,[R1,R2]! 將R0字數據存入存儲器地址R1+R2的存儲單元中,並將新地址R2+R2寫入R2
STR R0,[R1,#8]! 將R0字數據存入存儲器地址R1+8的存儲單元中,並將新地址R2+8寫入R2
STR R0,[R1,R2,LSL #2] 將R0字數據存入存儲器地址R1+R2*4的存儲單元中,並將新地址R2+R2*4寫入R1
LDR R0,[R1],#8 將存儲器地址爲R1的字數據讀入寄存器R0,並將新地址R1+8寫入R1
LDR R0,[R1],R2 將存儲器地址爲R1的字數據讀入寄存器R0,並將新地址R1+R2寫入R1
LDR R0,[R1],R2,LSL #2 將存儲器地址爲R1的字數據讀入寄存器R0,並將新地址R1+R2*4寫入R1
2). LDRB/STRB字節數據加載/存儲指令
LDRB/STRB{<cond>}{T}Rd,addr LDRB指令用於從存儲器中將一個8位的字節數據加載到目的寄存器中,同時將寄存器的高24位清零,當程序計數器PC作爲目的寄存器時,指令從存儲器中讀取的字數據被當做目的地址,從而可以實現程序流程的跳轉。
STRB指令用於從源寄存器中將一個8位的字節數據存儲到存儲器中,和LDRB相反。後綴T可選。
3). LDRH/STRH半字數據加載/存儲指令
LDRH/STRH{<cond>}{T}Rd,addr LDRH指令用於從存儲器中將一個16位的半字數據加載到目的寄存器中,同時將寄存器的高16位清零,當程序計數器PC作爲目的寄存器時,指令從存儲器中讀取的字數據被當做目的地址,從而可以實現程序流程的跳轉。
STRH指令用於從源寄存器中將一個16位的半字數據存儲到存儲器中,和LDRH相反。後綴T可選。
4). LDM/STM批量數據加載/存儲指令
LDM/STM{<cond>}{<type>}Rn{!},<regs>{^} LDM用於從基址寄存器所指示的一片連續存儲器中讀取數據到寄存器列表所指向的多個寄存器中,內存單元的起始地址爲基址寄存器Rn的值,各個寄存器由寄存器列表regs表示,該指令一般用於多個寄存器數據的出棧操作
STM用於將寄存器列表所指向的多個寄存器中的值存入由基址寄存器所指向的一片連續存儲器中,內存單元的起始地址爲基址寄存器Rn的值,各個寄存器又寄存器列表regs表示。該指令一般用於多個寄存器數據的進棧操作。
type表示類型,用於數據的存儲與讀取有以下幾種情況:
IA:每次傳送後地址值加。
IB:每次傳送前地址值加。
DA:每次傳送後地址值減。
DB:每次傳送前地址值減。
用於堆棧操作時有如下幾種情況:
FD:滿遞減堆棧
ED:空遞減堆棧
FA:滿遞增堆棧
EA:空遞增堆棧
5). SWP字數據交換指令
SWP{<cond>}<Rd>,<Rm>,[<Rn>] Rd = [Rn],[Rn] = Rm,當寄存器Rm和目的寄存器Rd爲同一個寄存器時,指令交換該急促親和存儲器的內容
SWP R0,R1,[R2] R0 = [R2],[R2] = R1
SWP R0,R0,[R1] R0 = [R1],[R1] = R0
SWPB指令用於將寄存器Rn指向的存儲器中的字節數據加載到目的寄存器Rd中,目的寄存器的高24位清零,同時將Rm中的字數據存儲到Rn指向的存儲器中。
8.分支語句
助記符 說明 操作
B{cond}label 分支指令 PC<-label
BL{cond}label 帶返回的分支指令 PC<-label,LR=BL後面的第一條指令地址
BX{cond}Rm 帶狀態切換的分支指令 PC = Rm & 0xffffffe,T=Rm[0] & 1
BLX{cond}label Rm 帶返回和狀態切換的分支指令 | PC=label,T=1 PC; PC = Rm &0xffffffe,T=Rm[0] & 1;LR = BLX後面的第一條指令地址
1). 分支指令B
B{<cond>}label 跳轉到label處執行,PC=label
例子:
backword SUB R1,R1,#1
CMP R1,#0 比較R1和0
BEQ forward 如果R1=0,跳轉到forware處執行
SUB R1,R2,#3
SUB R1,R1,#1
forward ADD R1,R2,#4
ADD R2,R3,#2
B backword 無條件跳轉到backword處執行
2). 帶返回的分支指令BL
BL{<cond>}label 在跳轉之前,將PC的當前內容保存在R14(LR)中保存,因此,可以通過將R14的內容重新加載到PC中,返回到跳轉指令之後的指令處執行。該指令用於實現子程序的調用,程序的返回可通過把LR寄存器的值複製到PC寄存器中來實現。
例子:
BL func 跳轉到子程序
ADD R1,R2,#2 子程序調用完返回後執行的語句,返回地址
....
func 子程序
...
MOV R15,R14 複製返回地址到PC,實現子程序的返回
3). 帶狀態切換的分支指令BX
BX{<cond>} Rm 當執行BX指令時,如果條件cond滿足,則處理器會判斷Rm的位[0]是否爲1,如果爲1則跳轉時自動將CPSR寄存器的標誌T置位,並將目標地址的代碼解釋爲Thumb代碼來執行,則處理器會切換到Thumb狀態,反之,若Rm的位[0]爲0,則跳轉時自動將CPSR寄存器的標誌T復位,並將目標地址處的代碼解釋爲ARM代碼來執行,即處理器會切換到ARM狀態。
注意:bx lr的作用等同於mov pc,lr。即跳轉到lr中存放的地址處。 非零值存儲在R0中返回。
那麼lr存放的是什麼地址呢?lr就是連接寄存器(Link Register, LR),在ARM體系結構中LR的特殊用途有兩種:一是用來保存子程序返回地址;二是當異常發生時,LR中保存的值等於異常發生時PC的值減4(或者減2),因此在各種異常模式下可以根據LR的值返回到異常發生前的相應位置繼續執行。
當通過BL或BLX指令調用子程序時,硬件自動將子程序返回地址保存在R14寄存器中。在子程序返回時,把LR的值複製到程序計數器PC即可實現子程序返回。
9.堆棧
1). 進棧出棧
出棧使用LDM指令,進棧使用STM指令。LDM和STM指令往往結合下面一些參數實現堆棧的操作。
FD:滿遞減堆棧。
ED:空遞減堆棧。
FA:滿遞增堆棧。
EA:空遞增堆棧。
滿堆棧是指SP(R13)指向堆棧的最後一個已使用地址或滿位置(也就是SP指向堆棧的最後一個數據項的位置);相反,空堆棧是指SP指向堆棧的第一個沒有使用的地址或空位置。
LDMFD和STMFD分別指POP出棧和PUSH入棧
2). PUSH指令
PUSH{cond} reglist PUSH將寄存器推入滿遞減堆棧
PUSH {r0,r4-r7} 將R0,R4-R7寄存器內容壓入堆棧
2.9.3. POP指令
POP{cond} reglist POP從滿遞減堆棧中彈出數據到寄存器
POP {r0,r4-r7} 將R0,R4-R7寄存器從堆棧中彈出