ARM指令集詳解2
ARM微處理器支持加載/存儲指令用于在寄存器和存儲器之間傳送數(shù)據(jù),加載指令用于將存儲器中的數(shù)據(jù)傳送到寄存器,存儲指令則完成相反的操作。
本文引用地址:http://2s4d.com/article/201611/318756.htmLDR{條件} 目的寄存器, <存儲器地址>
指令用于將存儲器中的一個32位的字數(shù)據(jù)傳送到目的寄存器中。本指令通常用于將存儲器上的字數(shù)據(jù)傳送到通用寄存器。
LDR R0,[R1]
將存儲器地址為R1的字數(shù)據(jù)讀入寄存器R0
LDR R0,[R1,R2]
將存儲器地址為R1+R2的字數(shù)據(jù)讀入寄存器R0。
LDR R0,[R1,#8]
將存儲器地址為R1+8的字數(shù)據(jù)讀入寄存器R0
LDR R0, [R1,R2]!
將存儲器地址R1+R2的字數(shù)據(jù)讀入寄存器R0,同時將新地址R1+R2寫入R1。
LDR R0, [R1,#5]!
將存儲器地址R1+5的字數(shù)據(jù)讀入寄存器R0,同時將新地址R1+5寫入到R1。
LDR R0,[R1], R2
將存儲器地址為R1的字數(shù)據(jù)讀入寄存器R0,并將新地址R1+R2寫入R1。
LDR R0,[R1,R2,LSL #2]!
將存儲器地址為R1+R2*4的字數(shù)據(jù)讀入到寄存器R0中,并將新地址R1+R2*4寫入R1
LDR R0, [R1], R2, LSL #2
將存儲器地址為R1的字數(shù)據(jù)讀入寄存器R0,并進新地址R1+R2*4寫入R1。
LDR{條件}B 目的寄存器,<存儲器地址>
LDRB指令用于從存儲器中將一個8位的字節(jié)數(shù)據(jù)傳送到目的寄存器中,同時將寄存器的高24位清零。
LDRB R0,[R1]
LDRB R0,[R1,#8]
LDR{條件}H 目的寄存器,<存儲器地址>
LDRH指令用于從存儲器中將一個16位的半字數(shù)據(jù)傳送到目的寄存器中,同時將寄存器的高16位清零。
LDRH R0,[R1]
LDRH R0,[R1,R2]
STR{條件} 源寄存器,<存儲器地址>
STR指令用于從源寄存器中將一個32位字數(shù)據(jù)傳送到存儲器中。
STR R0,[R1], #8
STR R0,[R1,#8]
ARM微處理器所支持的批量數(shù)據(jù)加載/存儲指令可以一次在一片連續(xù)的存儲器單元和多個寄存器之間傳遞數(shù)據(jù),批量加載指令用于將一片連續(xù)的存儲單元的數(shù)據(jù)傳送到多個寄存器,批量數(shù)據(jù)存儲指令則完成相反的操作。
LDM
STM
LDM{條件}{類型}
指令用于從由基址寄存器所指示的一片連續(xù)存儲器到寄存器列表所指示的多個寄存器之間傳送數(shù)據(jù),該指令的常見用途是將多個寄存器的內(nèi)容入?;虺鰲?。其中,{類型}為以下幾種情況:
IA 每次傳送后地址加1;
IB 每次傳送前地址加1;
DA 每次傳送后地址減1;
DB 每次傳送前地址減1;
FD 滿遞減堆棧;
ED 空遞減堆棧;
FA 滿遞增堆棧;
EA 空遞增堆棧;
{!}為可選后綴,若選用該后綴,則當數(shù)據(jù)傳送完畢之后,將最后的地址寫入基址寄存器,否則基址寄存器的內(nèi)容部改變。基址寄存器不允許為R15,寄存器列表可以為R0-R15的任意組合。
{^}為可選后綴,當指令為LDM且寄存器列表中包含R15,選用該后綴時表示:除了正常的數(shù)據(jù)傳送之外,還將SPSR到CPSR。
STMFD R13!, {R0,R4-R12,LR}
將寄存器列表中的寄存器(R0,R4到R12,LR)存入堆棧。
LDMFD R13!, {R0,R4-R12,LR}
將堆棧內(nèi)容恢復到寄存器(R0,R4到R12,LR)。
數(shù)據(jù)交換指令
ARM微處理器所支持數(shù)據(jù)交換指令能在存儲器和寄存器之間交換數(shù)據(jù)。
SWP 字數(shù)據(jù)交換指令
SWPB 字節(jié)數(shù)據(jù)交換指令
SWP{條件} 目的寄存器, 源寄存器1,[源寄存器2]
SWP指令用于將源寄存器2所指向的存儲器中的字數(shù)據(jù)傳送到目的寄存器中,同時將源寄存器1中的字數(shù)據(jù)傳送到源寄存器2所指向的存儲器中,顯然,當源寄存器1和目的寄存器為同一個寄存器時,指令交換該寄存器和存儲器的內(nèi)容。
SWP R0,R1,[R2]
SWP R0,R0,[R1]
移位指令
ARM微處理器支持數(shù)據(jù)的移位操作,移位操作在ARM指令集中不作為單獨的指令使用,它只能作為指令格式中是一個字段。
LSL logical shifter left
ASL arithmetic shifter left
LSR logical shifter right
ASR arithmetic shifter right
ROR rotate right
通用寄存器,LSL操作數(shù)
LSL可完成對寄存器中的內(nèi)容進行邏輯左移操作,按操作數(shù)所指定的數(shù)量向左移位,低位用零來填充。其中,操作數(shù)可以是通用寄存器,也可以是立即數(shù)(0—31)。
MOV R0,R1,LSL#2
將R1中的內(nèi)容左移兩位后傳送到R0中。
通用寄存器,ROR 操作數(shù)
ROR可完成對通用寄存器中的內(nèi)容進行循環(huán)右移的操作,按操作數(shù)所指定的數(shù)量向右循環(huán)移位,左端用右端移出的位來填充。其中,操作數(shù)可以是通用寄存器,也可以是立即數(shù)(0-31)。顯然,當進行32位的循環(huán)右移操作時,通用寄存器中的值不改變。
MOV R0,R1,ROR#2
將R1中的內(nèi)容循環(huán)右移兩位后傳送到R0中。
異常產(chǎn)生的指令
ARM微處理器所支持的異常指令如下兩條:
SWI 軟件中斷指令
BKPT 斷點中斷指令
SWI{條件} 24位的立即數(shù)
SWI指令用于產(chǎn)生軟件中斷,以便用戶程序能調(diào)用操作系統(tǒng)的系統(tǒng)API。操作系統(tǒng)在SWI的異常處理程序中提供了相應的系統(tǒng)服務,指令中24位的立即數(shù)指定用戶程序調(diào)用的API類型。
SWI 0x02
該指令調(diào)用操作系統(tǒng)編號為02的系統(tǒng)例程。
偽指令
這些助記符與指令系統(tǒng)的助記符不同,沒有相對應的操作碼,通常稱這些特殊指令助記符為偽指令,他們所完成的操作稱為偽操作。偽指令在源程序中的作用是為完成匯編程序作各種準備工作,這些偽指令僅在匯編過程中起作用,一旦匯編結束,偽指令的使命就完成。
ARM中有如下幾種偽指令:符號定義偽指令、數(shù)據(jù)定義偽指令、匯編控制偽指令、宏指令以及其他偽指令。
符號定義偽指令用于定義ARM匯編程序中的變量、對變量賦值以及定義寄存器的別名等操作。常見的符號定義偽指令有如下幾種:
定義全局變量的GBLA、GBLL和GBLS
定義局部變量的LCLA、LCLL和LCLS
對變量賦值的SETA、SETL、SETS
為通用寄存器列表定義名稱的RLIST
GBLA:定義一個全局的數(shù)字變量,并初始化為0;
GBLL:定義一個全局的邏輯變量,并初始化為F(假);
GBLS:定義一個全局的字符串變量,并初始化為空;
以上三條偽指令用于定義全局變量,因此在整個程序范圍內(nèi)變量名必須唯一。
GBLA Test1
定義一個全局的數(shù)字變量,變量名為Test1
Test1 SETA 0xaa
進該變量賦值為0xaa
GBLL Test2
定義一個全局的邏輯變量,變量名為Test2
Test2 SETL {TRUE}
將該變量賦值為真
GBLS Test3
定義一個全局的字符串變量,變量名為Test3
Test3 SETS “testing”
將該變量賦值為“testing”
名稱 RLIST {寄存器列表}
RLIST 偽指令用于對一個通用寄存器列表定義名稱,使用該偽指令定義的列表名稱可在ARM指令LDM/STM中使用。在LDM/STM指令中,列表中的寄存器訪問次序為根據(jù)寄存器的編號由低到高,而與列表中的寄存器排序無關。
Reglist RLIST {R0-R5,R8,R10}
數(shù)據(jù)定義偽指令一般用于為特定的數(shù)據(jù)分配存儲單元,同時可完成已分配存儲單元的初始化。
DCB DCW DCD DCFD DCFS DCQ SPACE MAP FIELD
標號 DCB 表達式
DCB偽指令用于分配一片連續(xù)的字節(jié)存儲單元并用偽指令中指定的表達式初始化。其中,表達式可以為0-255的數(shù)字或字符串。DCB也可用“=”代替。
Str DCB “This is a test!”
標號 SPACE 表達式
SPACE偽指令用于分配一片連續(xù)的存儲區(qū)域并初始化為0.其中,表達式為要分配的字節(jié)數(shù)。SPACE也可用“%”代替。
DateSpace SPACE 100
MAP 表達式 {基址寄存器}
MAP偽指令用于定義一個結構化的內(nèi)存表的首地址。MAP也可用“^”代替。表達式可以為程序中的標號或數(shù)學表達式,基址寄存器為可選項,當基址寄存器選項不存在時,表達式的值即為內(nèi)存表的首地址,當該選項存在時,內(nèi)存表的首地址為表達式的值與基址寄存器的和。MAP偽指令通常與FIELD偽指令配合使用來定義結構化的內(nèi)存表。
MAP 0x100,R0
定義結構化內(nèi)存表首地址的值為0x100+R0。
標號 FIELD 表達式
FIELD偽指令用于定義一個結構化內(nèi)存表中的數(shù)據(jù)域。FILED也可用“#”代替。表達式的值為當前數(shù)據(jù)域在內(nèi)存表中所占的字節(jié)數(shù)。FIELD偽指令常與MAP偽指令配合使用來定義結構化的內(nèi)存表。MAP偽指令定義內(nèi)存表的首地址,F(xiàn)IELD偽指令定義內(nèi)存表中的各個數(shù)據(jù)域,并可以為每個數(shù)據(jù)域指定一個標號供其他的指令引用。
MAP 0x100
A
B
S
匯編控制偽指令:
IF ELSE ENDIF
WHILE WEND
MACRO MEND
MEXIT
WHILE 邏輯表達式
指令序列
WEND
其他偽指令:
AREA 段名 屬性1,屬性2,......
AREA偽指令用于定義一個代碼段或數(shù)據(jù)段。其中,段名若以數(shù)字開頭,則該段名需用“|”括起來,如|1_test|。屬性字段表示該代碼段的相關屬性,多個屬性用逗號分隔。常用屬性如下:
CODE:用于定義代碼段,默認為READONLY。
DATA:用于定義數(shù)據(jù)段,默認為READWRITE。
READONLY:定義本段為只讀,代碼段默認為READONLY。
READWRITE;指定本段為可讀可寫,數(shù)據(jù)段的默認屬性READWRITE。
ALIGN屬性,使用方式為:
ALIGN 表達式
在默認時,ELF的代碼段和數(shù)據(jù)段是按字對齊的。
一個匯編語言程序至少要包含一個段,當程序太長時,也可以將程序分為多個代碼段和數(shù)據(jù)段。
AREA Init,CODE,READONLY
該偽指令定義了一個代碼段,段名為Init,屬性為只讀。
ALIGN {表達式{偏移量}}
ALIGN偽指令可通過添加填充字節(jié)的方式,使當前位置滿足一定的對齊方式。其中,表達式的值用于指定對齊方式,可能的取值為2的冪,如1,2,4,8,16等。若未指定表達式,則將當前位置對齊到下一個字的位置。偏移量也為一個數(shù)字表達式,若使用該字段,則當前位置的對齊方式為:2的表達式次冪+偏移量。
AREA Init,CODE,READONLY,ALIGN=3
指定后面的指令為8字節(jié)對齊。
CODE16(或CODE32)
CODE16偽指令通知編譯器,其后的指令序列為16位的Thumb指令。CODE32偽指令通知編譯器,其后的指令序列為32位的ARM指令。因此,在使用ARM指令和Thumb指令混合編程的代碼里,可用這兩條偽指令進行切換,但注意他們只通知編譯器其后指令的類型,并不能對處理器進行狀態(tài)的切換。
ENTRY
ENTRY偽指令用于指定匯編程序的入口點,在一個完整的匯編程序中至少要有一個ENTRY(也可有多個,當有多個ENTRY時,程序的真正入口點由鏈接器指定),但在一個源文件里最多只能有一個ENTRY。
名稱 EQU 表達式{類型}
EQU偽指令用于為程序中的常量、標號等定義一個等效的字符名稱,類似于C語言中的#define。其中EQU可用“*”代替。
Test EQU 50
Addr EQU 0x55,CODE32
EXPORT 標號
EXPORT偽指令用于在程序中聲明一個全局的標號,該標號可在其他的文件中引用。EXPORT可用GLOBAL代替。標號在程序中區(qū)分大小寫。
AREA Init,CODE,READONLY
EXPORT Stest
聲明一個可全局引用的標號Stest
IMPORT 標號
IMPORT偽指令用于通知編譯器要使用的標號在其他的源文件中定義,但要在當前源文件中引用。標號在程序中區(qū)分大小寫。
AREA Init,CODE,READONLY
IMPORT Main
通知編譯器當前文件要引用標號Main,但Main在其他源文件中定義
END
END偽指令用于通知編譯器已經(jīng)到了源程序的結尾。
評論