一 ARM寄存器
1.通用寄存器
1).未分組寄存器:R0~R7
2).分組寄存器:R8~812
R13:SP,常用作堆棧指針,始終指向堆棧的頂部,當一個資料(32位)推入堆棧時,SP(R13的值減4)向下浮動指向下一個位址,即新的棧頂,當資料從堆棧中彈出時,SP(R13的值加4)向上浮動指向新的棧頂。
R14:連接配接寄存器(LR),當執行BL子程式調用指令時,R14中得到R15(程式計數器PC)的備份,其他情況下,R14用作通用寄存器。
R15:程式計數器(PC):用于控制程式中指令的執行順序。正常運作時,PC指向CPU運作的下一條指令。每次取值後PC的值會自動修改以指向下一條指令,進而保證了指令按一定的順序執行。當程式的執行順序發生改變(如轉移)時,需要修改PC的值。
2.狀态寄存器
CPSR(R16):目前程式狀态寄存器,用來儲存ALU中的目前操作資訊,控制允許和禁止中斷、設定處理器的工作模式等。
SPSRs:五個備份的程式狀态寄存器,用來進行異常處理。當異常發生時,SPSR用于儲存CPSR的目前值,從異常退出時可由SPSR來恢複CPSR。
img
N、Z、C、V均為條件碼标志位,他們的内容可被運算的結果所改變。
N:正負标志,N=1表示運算的結果為負,N=0表示運算的結果為正或0
Z:零标志,Z=1表示運算的結果為0,Z=0表示運算的結果為非0
C:進位标志,加法運算産生了進位時則C=1,否則C=0
借位标志,減肥運算産生了借位則C=0,否則C=1
V:溢出标志,V=1表示有溢出,V=0表示無溢出
3.位址空間
程式正常執行時,每執行一條ARM指令,目前指令計數器增加4個位元組
二 彙編語言
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寄存器從堆棧中彈出