 arm程序匯編指令總結,讓(rang)你更高效的(de)學習
							時間:2018-07-16      來源(yuan):未知
							arm程序匯編指令總結,讓(rang)你更高效的(de)學習
							時間:2018-07-16      來源(yuan):未知 
							現(xian)在學嵌(qian)入式的(de)人也是(shi)越(yue)來越(yue)多(duo)了(le),那當然(ran)arm程序也是(shi)必須要學的(de),在這里有很多(duo)人對(dui)arm程序匯(hui)編指令都或多(duo)或少的(de)不了(le)解(jie),可以說不熟悉,今(jin)天(tian)就以arm程序來看,讓(rang)你對(dui)arm程序匯(hui)編指令有更深入的(de)學習(xi)。
首(shou)先(xian)我們要知道arm匯編程序的特(te)點:
l 所(suo)有(you)運算處(chu)(chu)理都(dou)是(shi)發生通用寄存(cun)器(一般是(shi)R0~R14)的之(zhi)中.所(suo)有(you)存(cun)儲(chu)器空間(如C語言變量的本質就是(shi)一個(ge)存(cun)儲(chu)器空間上的幾個(ge)BYTE).的值(zhi)(zhi)的處(chu)(chu)理,都(dou)是(shi)要傳送到通用寄存(cun)器來完成.因此代碼中大量看(kan)到LDR,STR指令來傳送值(zhi)(zhi).
l ARM匯編(bian)語句(ju)(ju)中(zhong).當前(qian)語句(ju)(ju)很多時(shi)候要隱(yin)含的(de)使用上一句(ju)(ju)的(de)執行(xing)結(jie)果(guo).而且上一句(ju)(ju)的(de)執行(xing)結(jie)果(guo),是放在CPSR寄存器里,(比如說進位,為0,為負…)
CMP R0,R1
BNE NoMatch
比如上一句,BNE隱含(han)的(de)使(shi)用(yong)的(de)上一句CMP執行結果.NE后綴表(biao)示使(shi)用(yong)Z標(biao)志位(wei).兩句合起(qi)來的(de)意思就是,如果R0,R1的(de)值(zhi)不相(xiang)等,就跳轉到NoMatch處(chu)執行.
注意,PC=R15,CPSR=R16,
  
ARM常用指令,偽(wei)指令
對于arm指令(ling)你要知(zhi)道一個問題就是arm偽(wei)指令(ling)
ARM偽指令(ling)不是必須的(de),但(dan)是一(yi)個(ge)完整(zheng)沒有偽指令(ling)幾乎很難寫出(chu)來.
n 比(bi)如一個程序(xu)至少包含READONLY AREA和(he)ENTRY,否則CPU都無法知道從(cong)哪里開始(shi)運行
l ARM的屬于(yu)RISC,指令并不(bu)(bu)多,但是可以帶后綴表示擴展出不(bu)(bu)同用法(fa),這(zhe)里與(yu)X86匯編完(wan)全不(bu)(bu)同風格(ge)
n 如BNE實際上是B指(zhi)令的(de)變(bian)種(zhong),本質(zhi)還同一類(lei)指(zhi)令.只是多一個(ge)對CPSR的(de)Z標志位(wei)的(de)判斷。
首先我們要(yao)從ARM程序(xu)常(chang)用指(zhi)令來(lai)了解(jie),這(zhe)些都(dou)是(shi)你(ni)要(yao)學習的哦(e),雖然不是(shi)很詳(xiang)細但是(shi)對于學習ARM程序(xu)來(lai)說這(zhe)些就夠了。
l B,BL
l MOV,MVN
l LDR,STR
l ADD,SUB,ADC,SBC,MUL
l AND,ORR,XOR,TST,BIC
l CMP
l LDM/STM
l nop
1. 傳輸數據指令MOV,MVN
n MOV(MOVE)指令可完成從(cong)另一個寄存器(qi)(qi)、被移(yi)位的寄存器(qi)(qi)或將一個立即數加載到目的寄存器(qi)(qi)
MOV R0,R1 ; 把(ba)R1的值傳到(dao)R0
MOV R3,#3 ;把常數3傳給R3,MOV中用(yong)#表(biao)示常數,這個值不能超過
n MVN( MOVE Negative)取反后(hou)再(zai)傳值,比MOV多了(le)一步(bu)取反
MVN R0, #0 ;把(ba)0取反(fan)(即-1)傳給R0
MVN R1,R2 ;把R2的值取反(fan)傳給(gei)R1
2. 跳轉語(yu)句 B,BL
程序流程的跳轉,在 ARM 程序中有(you)兩種方(fang)法可以實現(xian)程序流程的跳轉指令用于實現(xian)
l 使(shi)用專門的跳轉(zhuan)指令 B
l 直接(jie)向程序計(ji)數器(qi)PC 寫(xie)入跳轉地址值(zhi)
n 這是幾乎是任何(he)一種CPU必(bi)備的機(ji)器(qi),PC表示(shi)CPU當前執行語句位置,改變PC的值(zhi),相當于實(shi)現程(cheng)序跳轉
n 如實現(xian)類似C語言的Return 語句,就是用MOV PC,LR
n 這里可以在任意(yi)4G的空間進行(xing)跳轉(zhuan)
B指令(ling)(Branch)表示無(wu)條件跳轉.
B main ;跳轉到標號為main地代碼處
BL指令(Branch with Link)表示帶返回值的跳轉.
BL比B多做一步(bu),在(zai)跳(tiao)轉(zhuan)前(qian),BL會把當前(qian)位(wei)置保存在(zai)R14(即(ji)LR寄(ji)存器(qi)),當跳(tiao)轉(zhuan)代(dai)碼結束后,用MOV PC,LR指令(ling)跳(tiao)回(hui)來,這實際上就是C語(yu)言執行函(han)數的用法,
匯編里調子(zi)程序(xu)都用BL,執行(xing)完子(zi)函數后(hou),可以(yi)用MOV PC,LR跳回來.
BL delay ;執行(xing)子函(han)數(shu)或代碼(ma)段(duan)delay ,delay可(ke)以為C函(han)數(shu).
與MOV PC,XXX能在4G空間(jian)跳(tiao)轉不(bu)同,B語句只(zhi)能32M空間(jian)跳(tiao)轉,(因為偏移量是一個(ge)有符號(hao)26bit的數值=32M)
3. 算(suan)術(shu)運算(suan)指令,ADD/ADC,SUB/SBC ,MUL
n ADD加(jia)法指令
ADD R0,R1,R2; R0=R1+R2
ADD R0,R1,#3 ;R0=R1+3
n ADC帶進位加法指令,即除了加兩個數以(yi)外,還要把CPSR的(de)C值也要帶進來
u 通常(chang)用于大(da)數(超過32Bit整數)相加(jia),這(zhe)時(shi)單用ADD不(bu)能處理,必(bi)須折成兩步(bu),其中一(yi)步(bu)用ADC.
u 以下是做64Bit的加(jia)法(fa)
ADDS R0,R1,R2; R0=R1+R2,ADDS中(zhong)S表示把(ba)進位結果寫入CPSR
ADC R5,R3,R4 ;R5=R3+R4+C
n SUB減法(fa)指令(ling)
SUB R0,R1,R2; R0=R1-R2
SUB R0,R1,#3 ;R0=R1-3
n SBC帶(dai)進(jin)(jin)位減法指令,即除了(le)加兩個數(shu)以外,還(huan)要(yao)把CPSR的(de)C值也(ye)要(yao)帶(dai)進(jin)(jin)來,類(lei)似ADC
u 以(yi)下是做64Bit的減法
SUBS R0,R1,R2; R0=R1-R2,SUBS中S表示把進位結果寫入CPSR
SBC R5,R3,R4 ;R5=R3-R4-C
n MUL 乘法(fa)指令
MUL R0,R1,R2; R0=R1*R2
MUL R0,R1,#3 ;R0=R1*3
4. 加載/存儲指(zhi)令,LDR,STR
n LDR,STR是用于寄(ji)存器和外(wai)部存儲器交換數(shu)據指令,注意與MOV的區別,后面(mian)只(zhi)在寄(ji)存器或常數(shu)交換.
u LDR/STR可以采用多(duo)種(zhong)尋(xun)址(zhi)方式,以下只舉出使用頻率最高幾種(zhong)用法
n LDR(load)用于把(ba)一個32Bit的WORD數據從(cong)外部存儲空間(jian)裝入到寄存器中
LDR R0,[R1]; R1的(de)值(zhi)當成地(di)址,再從(cong)這(zhe)個地(di)址裝入數據到R0 (R0=*R1)
LDR R1,=0x30008000 ; 把地址0x30008000的值裝入到R1中,LDR中用常數要用=打(da)頭.(注意(yi)跟MOV的區別,MOV是#)
ldr r0, =(0<<13)|(0<<12)|(0<<10)|(0<<9)|(0<<8)|(1<<6)|(1<<5)|(1<<4)|(1<<1)|(1<<0)
用位(wei)與的方(fang)法賦值
n STR(Store) 用(yong)于把一個寄存(cun)器的值存(cun)入(ru)外部存(cun)儲空間,是(shi)LDR的逆操作.
STR R0,[R1] ; 把R0的(de)值,存入到(dao)R1對應地(di)址空間上(*R1 = R0)
STR R0,=0x30008000 ;把R0中值存入到地址0x30008000
S2C2440的(de)中CPU內核以外(wai)(wai)的(de)模(mo)塊(kuai)的(de)控制(zhi)寄存器空(kong)間也是屬于外(wai)(wai)部空(kong)間,所以也得用如(ru)下指令LDR R0,=GPFDAT
5. 比較指令(ling) CMP
n CMP比較兩個操(cao)作數(shu),并(bing)把結果存入CPSR供(gong)下一句語句使用
CMP R0,R1; 比較R0,R1
6. 位(wei)操作指令 AND,ORR, TST,BIC
n AND位與(yu)指令
AND R0,R1,R2; R0=R1 & R2
AND R0,R1,#0xFF ;R0=R1 & 0xFF
n ORR位(wei)或指(zhi)令
ORR R0,R1,R2; R0=R1 | R2
ORR R0,R1,#0xFF ;R0=R1 | 0xFF
n TST測試某一(yi)(yi)位是(shi)否為1,并把結果寫入CPSR,供下一(yi)(yi)句(ju)使用
TST R1,#0xffe; 等同于if(R1 & 0xffe)
TST R1,#%1;測試(shi)最低位是否為(wei)1,%表示二(er)進制
n BIC清位操(cao)作
BIC R0,R0,#0xF ; 等(deng)同(tong)于 R0 &=~(0xF)
BIC R0,R0,#%1011 ; 該指令清除 R0 中的位(wei) 0 1 3,其余的位(wei)保持; %表示是(shi)二(er)進(jin)制(zhi),0x表示十六進(jin)制(zhi)
7. 多寄存器語句傳輸(shu)指令,LDM,STM
類(lei)似于一(yi)次傳一(yi)個BUFFER到寄存器當中,或反過(guo)來(lai).后面一(yi)般(ban)要接一(yi)個地址改變(bian)方法
n LDM 從BUFFER傳數據(ju)多(duo)個寄存器傳輸(shu)數據(ju)到
LDMIA R0! ,{R3-R9} ;加(jia)R0指向(xiang)的(de)地址上連(lian)續空間的(de)數據,保存到R3-R9當中,!表示R0值(zhi)更新,IA后綴表示按WORD遞增
LDMFD SP!,{R0-R7,PC}^;恢復現場(chang),異(yi)常處理返回(hui),^表示不允許在用(yong)(yong)戶模式下使用(yong)(yong)。
n STM 從寄存器列(lie)表向存儲(chu)空(kong)間傳值。
STMIA R1!,{R3-R9} ;將(jiang)R3-R9的數據存儲到R1指向的地址上,R1值更新。
STMFD SP!,{R0-R7,LR}; 現場保存,將R0~R7,LR入棧
stmfd sp!,{r8-r9} ,把SP寄存器(qi)對(dui)慶的地址的值存到(dao)R8,R9當中(zhong)(zhong).!表(biao)示最后的值寫入SP中(zhong)(zhong)。Fd表(biao)示
8. ARM指令的(de)變形
  大部分指令后位可以接 
S,表示當前指令執行后把結果(guo)改寫CPSR
subs,Adds
  
BEQ 實(shi)際上B+ EQ的條件執(zhi)行.
addne 表示ADD +NE 才(cai)開始加.
9. ADS ARM的偽指令(ling)
類似于C語言的宏,由匯編(bian)程序預處理.
l 符號(hao)定義指令(ling)
全局(ju)變量定義 GBLA ,GBLL,GBLS
局域變量定(ding)義(yi) LCLA,LCLL,LCLS
變量賦值SETA,SETL,SETS
其中(zhong)上述偽指令(ling)中(zhong),最后面的A表(biao)示(shi)給一個算術變量(liang)(liang)賦(fu)值,L表(biao)示(shi)用于給一個邏(luo)輯變量(liang)(liang)賦(fu)值,s表(biao)示(shi)給一個字符串賦(fu)值
GBLL codedbg; 聲明一個(ge)全局的邏輯變量
Codebg SETL {TRUE} ; 設置變量為{TRUE}
LCLA bitno; 聲明一個(ge)算術變量
Bitno SETA 8 ;設變(bian)量(liang)值為8
l 數據定義偽(wei)指(zhi)令
n SPACE 定義(yi)一個內存空間,并用0初(chu)始(shi)化
{label } SPACE expr
DataBuf SPACE 100 ;定義(yi)100字節(jie)長(chang)空間, unsigned char DataBuf[100];
n DCB 定(ding)義(yi)一個(ge)連續字(zi)節內(nei)存空間,用偽指令的(de)表(biao)達式expr來初始化.一般(ban)可以用定(ding)義(yi)數據表(biao)格,或文字(zi)字(zi)符串.(這時等同于SETS),用于初始二進制BUFFER
{label} DCB expr{,expr …}
Dest DCB -120,20,36,55 ;等同(tong)于(yu) unsigned char Dest[]={-120,20,36,55};
n DCU定(ding)義(yi)的一段字的內存空間(jian)(DCB是字節),并用后面表(biao)達(da)式初(chu)始化
_RESET DCU Reset ; 等同于(yu) DWORD _RESET[]={Reset};
n MAP定一(yi)個結(jie)(jie)構(gou)化(hua)內存,相當(dang)于定義一(yi)個C結(jie)(jie)構(gou)
n FILED 定義一個結構化內存的成員(yuan)
MAP 0x00,R9 ; 定義內存表,地址為(wei)R9
Timer FIELD 4 ; 定義數(shu)據域(yu)Timer,長為4字(zi)
Attrib FIELD 4 ; 定義數據域Attrib,長為(wei)4字
String FILED 100 ; 定義數據域(yu)String ,長為(wei)100字
相當(dang)于(yu)C語言(yan)的定義:
struct {
DWORD Timer ;
DWORD Attrib ;
Char String[100];
} R9;
10. ARM指令(ling)的尋址方(fang)式(shi)
尋址(zhi)方式是根(gen)據指令中給出(chu)的地址(zhi)碼來定位真實的地址(zhi),ARM中有9種尋址(zhi)方法
l 寄存(cun)器尋址
直接(jie)用寄存器編號來尋址,最為常(chang)用
MOV R1,R2 ;R2->R1
l 立即數尋址(zhi)
即(ji)指(zhi)令中的地址碼(ma)是操作(zuo)數(shu)本身,可以立(li)即(ji)取出使用,立(li)即(ji)數(shu)前帶(dai)一(yi)個#表示,否則(ze)表示一(yi)個地址
SUBS R0,R0,#1 ;R0 -1 ->R0
注意與SUBS R0,R0,1區別(bie)
l 寄存器偏移尋址(zhi)
這是(shi)ARM特有的尋址模式,當第2操(cao)作數是(shi)寄存器,在執(zhi)行操(cao)作之(zhi)前,可以做一(yi)次移(yi)位操(cao)作
MOV R0,R2,LSL #3 ;R2的邏(luo)輯左(zuo)移3位(wei),結果放(fang)入R0,即(ji)R0=R2*8
ANDS R1,R1,R2,LSL R3;RS的值左移R3位,然后和(he)R1相與操作(zuo),結果放入R1
移(yi)位操作有LSL (邏輯左移(yi)),LSR(邏輯右(you)(you)移(yi)) ,ASR(算術右(you)(you)移(yi)),ROR(循環(huan)右(you)(you)移(yi))RRX帶擴展(zhan)的循環(huan)右(you)(you)移(yi)
l 寄存(cun)器間接尋(xun)址
即寄存器中(zhong)(zhong)值(zhi)是一個地(di)址(zhi),用[]來(lai)取出定位到地(di)址(zhi)當中(zhong)(zhong)
LDR R2,[R0] ;把R0的值(zhi)當成地址,取出相應(ying)值(zhi),賦給R2
l 基(ji)址尋址
把寄存器的地址值(zhi)加上一(yi)個偏(pian)移量
LDR R2,[R3,#0x0F]; R3中的值加(jia)上0x0F,從這個地(di)址取出(chu)值賦(fu)給R@
l 相對尋址
基址(zhi)尋址(zhi)的變形,由(you)PC寄存器提供基準(zhun)地(di)(di)址(zhi),指令中(zhong)地(di)(di)址(zhi)段(duan)作為偏移量(liang).兩者相加即是(shi)有效地(di)(di)址(zhi),以下(xia)是(shi)BL采(cai)用相對(dui)尋址(zhi)
BL NEXT
…
NEXT
…
MOV PC,LR ;從子程序返回
11. 雜(za)項的偽指(zhi)令
n 字節對(dui)齊 ALIGN
ALIGN; 聲明4字節(jie)對齊
n 定義(yi)一個(ge)數字常(chang)量定義(yi) EQU
NAME EQU expr {type}
PLLCON EQU 0xE01FC080;定(ding)義PLLCON,類似于C的宏或C++的常(chang)量
n 包含(han)文件 GET和INCLUDE
INCLUDE lpc2106.inc
n NOP 空指令(ling)
在匯編時會被ARM的空操(cao)作代替,比(bi)如MOV R0,R0,一般用于延(yan)時與占位。
n 聲明(ming)一個外(wai)部(bu)符符號 IMPORT,EXTERN
IMPORT,EXTERN 向外部導(dao)入一(yi)個符號,一(yi)般是外部程序全局變量
n 條(tiao)件編譯:[]。類(lei)似(si)于C的#ifdef 之類(lei)定義。
格式 :[ 條件表達式
滿(man)足條(tiao)件分支
|
不滿足條件分支
]
示例1:
[ ENTRY_BUS_WIDTH=32 ;類似#if ENTRY_BUS_WIDTH=32
b ChangeBigEndian ;DCD 0xea000007
] ; 類似#endif
示例2: [ CLKDIV_VAL>1 ; 類似#if CLKDIV_VAL>1
bl MMU_SetAsyncBusMode
|;類似(si)#else
bl MMU_SetFastBusMode ; default value.
]; 類(lei)似#endif
示(shi)例(li)3 [ THUMBCODE 類似#ifdef THUMBCODE
bx lr
| ;類似#else
mov pc,lr
] ;類(lei)似#endif
n 段定(ding)義 AREA
n 指(zhi)令集(ji)定義 CODE16和(he)CODE32
指(zhi)示(shi)是Thumb 指(zhi)令(ling)集(ji)(壓(ya)縮指(zhi)令(ling)集(ji),每個(ge)指(zhi)令(ling)16位(wei))。還是普通(tong)32位(wei)指(zhi)令(ling)集(ji)
n 匯編結束:END
n 程序(xu)入口ENTRY
一直都在(zai)(zai)(zai)說arm程(cheng)序(xu),那這(zhe)個arm程(cheng)序(xu),你(ni)又了解多少呢,在(zai)(zai)(zai)這(zhe)里在(zai)(zai)(zai)附(fu)加arm程(cheng)序(xu)的結構,讓(rang)你(ni)一次(ci)性吃個飽,一個簡單的arm程(cheng)序(xu)結構一般包括(kuo):ARM匯編程(cheng)序(xu)結構,ARM 匯編語句(ju)格式(shi), 匯編程(cheng)序(xu)的段定義,對于(yu)這(zhe)些知識點,相信下面這(zhe)些就夠你(ni)學會了。
ARM匯編程序(xu)結構(gou)
源代(dai)碼由文(wen)本文(wen)件(jian)組(zu)成.按照(zhao)匯編(bian)的編(bian)譯器不(bu)同(tong),分為兩(liang)大量,一(yi)類(lei)是ADS的匯編(bian)程(cheng)序,一(yi)類(lei)是GNU匯編(bian)格(ge)式,兩(liang)者在指令(ling)集是完(wan)成一(yi)樣,但是在偽指令(ling).程(cheng)序結(jie)構等方法(fa)各(ge)不(bu)同(tong)相同(tong).本節主要是講解ADS匯編(bian)格(ge)式.
ADS匯(hui)編程(cheng)序(xu),主要(yao)包含如下幾類程(cheng)序(xu)
n 匯編源(yuan)程序,后綴名是.S
n 匯編包含文件(jian),后(hou)綴名(ming)是(shi).inc
n 如果是與C混(hun)和編程..C,.h也能識(shi)別(bie)
匯編程(cheng)序的段定義
任何一個(ge)程(cheng)序(xu)(xu)都要分(fen)段,C語言一般由編(bian)譯器(qi)自(zi)動(dong)分(fen)段,(分(fen)成.Text,.Data段之類),但在匯編(bian)程(cheng)序(xu)(xu)這樣的(de)底層程(cheng)序(xu)(xu)中,由開發者自(zi)行分(fen)段. 它包含(han)如下段
l 至少(shao)一個(ge)代(dai)碼段,并且代(dai)碼段是只讀的,對(dui)應(.Text)
l 數(shu)據段可以沒有,也可以有多個(ge).
l 每一(yi)個段用END結束(shu)
AREA 定義一(yi)個(ge)段
AREA 段(duan)名 屬性(xing)1, 屬性(xing)2,
例子:AREA Init,CODE,READONLY
l ENTRY 指明一個段的(de)入口
l END結(jie)束一個段
ABC EQU 0x12
AREA Example,CODE,READONLY
ENTRY
START MOV R7,#10
MOV R6,#5
ADD R6,R6,R7
B
END
ADS ARM匯編程序格式(shi)要(yao)求
1. 所(suo)有標號要頂格寫.
2. 所有指令不能頂格寫,一般插入Tab鍵在行(xing)首
3. ADS ARM中,是大小寫敏感的(de).建議標號,指(zhi)令,偽指(zhi)令,寄(ji)存器(qi)名(ming)全部(bu)為(wei)大寫
4. 注釋采用;打頭
5. 每個(ge)程序至少(shao)有一個(ge)AREA在代(dai)碼里(READONLY)
6. 每個段都(dou)要用(yong)END結束(不能頂格)
ARM 匯編語句格(ge)式(shi)
[標(biao)號(hao)] <指令(ling)|條件(jian)|S> <操作數> [;注釋]
l 所有標號頂格(ge)寫,而指令和偽指令不(bu)能頂格(ge)寫
l 標識符(標號,指令(ling))大小(xiao)寫(xie)敏感,所以要在標號和(he)指令(ling)時書寫(xie)一致,一般偽(wei)指令(ling),指令(ling),寄存器名可以全部為大寫(xie)
l 注釋以(yi);開頭,可以(yi)頂格(ge)寫
l 可以使(shi)用\來(lai)分行(xing)寫太長語句
l 變(bian)量(liang),常量(liang)的(de)定義(yi)必須在一(yi)行頂格寫
常量的書寫
l 數字常量(liang)
在程序中(zhong)直接(jie)寫數字 ,十進(jin)制(zhi) 12,256,十六進(jin)制(zhi) 0x1228,
l 字符常量
類似于(yu)C的定義,用(yong)SETS來(lai)定義字符常量
HELLO SETS “hello,the world!”
l 邏輯常量
邏(luo)輯真為(wei){TRUE},邏(luo)輯假為(wei){FLASE}
Testno SETS {TURE}
最(zui)常見幾(ji)個偽指令 AREA,EQU,DCB,END ,ENTRY,EXPORT,GOBEL,IMPORT。
就先說到這(zhe)里了,對(dui)于這(zhe)些arm程(cheng)序匯編指令(ling),你(ni)是否都(dou)(dou)掌握好了呢,學(xue)習arm程(cheng)序這(zhe)些是離不開的,需要有邊(bian)(bian)學(xue)邊(bian)(bian)記,邊(bian)(bian)學(xue)邊(bian)(bian)實踐,這(zhe)樣才會對(dui)arm程(cheng)序匯編指令(ling)都(dou)(dou)了如指掌。

