10.3 匯編語言文件格式
10.3.1 ARM匯編語言語句格式
ARM(Thumb)匯編語法語句格式如下所示。
{symbol}{instruction|directive|pseudo-instruction}{;comment}
① symbol
程序符號(hào)。通常為地址標(biāo)號(hào)(label)。在指令和偽指令中通常為標(biāo)號(hào);在一些偽操作中符號(hào)可能是變量或常數(shù)。詳見ARM偽操作一節(jié)。
在書寫中,符號(hào)必須從一行的行頭開始,前面不能包含空格或制表符tab。
② instruction
ARM或Thumb指令。
③ directive
偽操作。詳見ARM偽操作一節(jié)。
④ pseudo-instruction
ARM偽指令。詳見ARM偽指令一節(jié)。
⑤ comment
語句注釋。注釋以分號(hào)(;)開頭,注釋的結(jié)尾即為一行的結(jié)尾。為了程序清晰易讀,注釋也可以單獨(dú)占用一行。匯編器在對程序進(jìn)行匯編時(shí)忽略注釋。
在匯編語言程序設(shè)計(jì)中,每一條指令的助記符可以全部用大寫或全部用小寫,但不允許在一條指令中大、小寫混用。
同時(shí),如果一條語句太長,可將該長語句分為若干行來書寫,在行的末尾用“”表示下一行與本行為同一條語句。
10.3.2 ARM匯編語言中的符號(hào)
在匯編語言程序設(shè)計(jì)中,經(jīng)常使用各種符號(hào)代替地址(addresses)、變量(variables)和常量(constants)等,以增加程序的靈活性和可讀性。盡管符號(hào)的命名由編程者決定,但并不是任意的,必須遵循以下的約定。
(1)符號(hào)區(qū)分大小寫,同名的大、小寫符號(hào)會(huì)被編譯器認(rèn)為是兩個(gè)不同的符號(hào)。
(2)符號(hào)在其作用范圍內(nèi)必須惟一。
(3)自定義的符號(hào)名不能與系統(tǒng)的保留字相同。其中保留字包括系統(tǒng)內(nèi)部變量
(built in variable)和系統(tǒng)預(yù)定義(predefined symbol)的符號(hào)。
(4)符號(hào)名不應(yīng)與指令或偽指令同名。如果要使用和指令或偽指令同名的符號(hào)要用雙斜杠“||”將其括起來,如“||ASSERT||”。
注意 |
雖然符號(hào)被雙斜杠括起來,但雙斜杠并非符號(hào)名的一部分。 |
(5)局部標(biāo)號(hào)以數(shù)字開頭,其他的符號(hào)都不能以數(shù)字開頭。
1.變量(variable)
程序中的變量是指其值在程序的運(yùn)行過程中可以改變的量。ARM(Thumb)匯編程序所支持的變量有三種。
· 數(shù)字變量(numeric)。
· 邏輯變量(logical)。
· 字符串變量(string)。
數(shù)字變量用于在程序的運(yùn)行中保存數(shù)字值,但注意數(shù)字值的大小不應(yīng)超出數(shù)字變量所能表示的范圍。
邏輯變量用于在程序的運(yùn)行中保存邏輯值,邏輯值只有兩種取值情況:真({TURE})和假({FALSE})。
字符串變量用于在程序的運(yùn)行中保存一個(gè)字符串,注意字符串的長度不應(yīng)超出字符串變量所能表示的范圍。
在ARM(Thumb)匯編語言程序設(shè)計(jì)中,可使用GBLA、GBLL、GBLS偽指令聲明全局變量,使用LCLA、LCLL、LCLS偽指令聲明局部變量,可使用SETA、SETL和SETS對其進(jìn)行初始化。
2.常量(constants)
程序中的常量是指其值在程序的運(yùn)行過程中不能被改變的量。ARM(Thumb)匯編程序所支持的常量有數(shù)字常量、邏輯常量和字符串常量。
數(shù)字常量一般為32位的整數(shù),當(dāng)作為無符號(hào)數(shù)時(shí),其取值范圍為0~232−1,當(dāng)作為有符號(hào)數(shù)時(shí),其取值范圍為−231~231−1。匯編器認(rèn)為−n和232−n是相等的。對于關(guān)系操作,如比較兩個(gè)數(shù)的大小,匯編器將其操作數(shù)看作無符號(hào)的數(shù),也就是說“0>−1”,對匯編器來說取值為“假({FLASE})”。
邏輯常量只有兩種取值情況,真或假。
字符串常量為一個(gè)固定的字符串,一般用于程序運(yùn)行時(shí)的信息提示。
3.程序中的變量代換
匯編語言中的變量可以作為作為一整行出現(xiàn)在匯編程序中,也可以作為行的一部分使用。
如果在數(shù)字變量前面有一個(gè)代換操作符“$”,編譯器會(huì)將該數(shù)字變量的值轉(zhuǎn)換為十六進(jìn)制的字符串,并將該十六進(jìn)制的字符串代換“$”后的數(shù)字變量。
如果在邏輯變量前面有一個(gè)代換操作符“$”,編譯器會(huì)將該邏輯變量代換為它的取值(真或假)。
如果在字符串變量前面有一個(gè)代換操作符“$”,編譯器會(huì)將該字符串變量的值代換“$”后的字符串變量。
如果程序中需要字符“$”,則可以用“$$”來表示。匯編器將不進(jìn)行變量替換,而是將“$$”作為“$”。
下面的兩個(gè)例子說明了變量替換的過程。
; 直接的變量替換
GBLS add4ff
;
add4ff SETS "ADD r4,r4,#0xFF" ;給變量add4ff賦值
$add4ff.00 ;引用變量
; codes
ADD r4,r4,#0xFF00
; 有特殊符號(hào)的變量替換
GBLS s1
GBLS s2
GBLS fixup
GBLA count
;
count SETA 14
s1 SETS "a$$b$count" ;s1 =a$b0000000E
s2 SETS "abc"
fixup SETS "|xy$s2.z|" ;fixup= |xyabcz|
|C$$code| MOV r4,#16 ;label= C$$code
4.程序標(biāo)號(hào)(label)
在ARM匯編中,標(biāo)號(hào)代表一個(gè)地址,段內(nèi)標(biāo)號(hào)的地址在匯編時(shí)確定,而段外標(biāo)號(hào)地址值在鏈接時(shí)確定。根據(jù)標(biāo)號(hào)的生成方式,程序標(biāo)號(hào)分為以下三種。
· 程序相關(guān)標(biāo)號(hào)(Program-relative labels)。
· 寄存器相關(guān)標(biāo)號(hào)(Register-relative labels)。
· 絕對地址(Absolute address)。
(1)程序相關(guān)標(biāo)號(hào)
程序相關(guān)標(biāo)號(hào)指位于目標(biāo)指令前的標(biāo)號(hào)或程序中的數(shù)據(jù)定義偽操作前的標(biāo)號(hào)。這種標(biāo)號(hào)在匯編時(shí)將被處理成PC值加上或減去一個(gè)數(shù)字常量。它常用于表示跳轉(zhuǎn)指令的目標(biāo)地址或代碼段中所嵌入的少量數(shù)據(jù)。
(2)寄存器相關(guān)地址
這種標(biāo)號(hào)在匯編時(shí)將被處理成寄存器的值加上或減去一個(gè)數(shù)字常量。它常被用于訪問數(shù)據(jù)段中的數(shù)據(jù)。這種基于寄存器的標(biāo)號(hào)通常用MAP和FIELD偽操作定義,也可以用EQU偽操作定義。
(3)絕對地址
絕對地址是一個(gè)32位的數(shù)字量,使用它可以直接尋址整個(gè)內(nèi)存空間。
5.局部標(biāo)號(hào)
局部標(biāo)號(hào)是一個(gè)0~99之間的十進(jìn)制數(shù)字,可重復(fù)定義。局部標(biāo)號(hào)后面可以緊接一個(gè)通常表示該局部變量作用范圍的符號(hào)。局部變量的作用范圍為當(dāng)前段,也可以用偽操作ROUT來定義局部標(biāo)號(hào)的作用范圍。
局部標(biāo)號(hào)在子程序或程序循環(huán)中常被用到,也可以配合宏定義偽操作(MACRO和MEND)來使程序結(jié)構(gòu)更加合理。
在同一個(gè)段中,可以使用相同的數(shù)字命名不同的局部變量。默認(rèn)情況下,匯編器會(huì)尋址最近的變量。也可以通過匯編器命令選項(xiàng)來改變搜索順序。
局部變量命名語法如下。
n{routname}
局部變量引用的語法格式如下。
%{F|B}{A|T}n{routname}
其中,routname為變量作用范圍名稱;%表示引用操作;F指示匯編器只向前搜索;B指示匯編器只向后搜索;A指示匯編器搜索所有宏的嵌套。T指示匯編器只搜索宏的當(dāng)前層。
如果在引用過程中,沒有指定F和B,則匯編器先向后搜索,再向前搜索。
如果A和T沒有指定,匯編器搜索所有從當(dāng)前層次到宏最高層次,比當(dāng)前層次低的層次不再搜索。
如果指定了routname,匯編器向前搜索最近的ROUT操作,若routname與該ROUT偽操作定義的名稱不匹配,匯編器報(bào)告錯(cuò)誤并結(jié)束匯編。
10.3.3 匯編語言程序中的表達(dá)式和運(yùn)算符
在匯編語言程序設(shè)計(jì)中經(jīng)常使用各種表達(dá)式,表達(dá)式一般由變量、常量、運(yùn)算符和括號(hào)構(gòu)成。常用的表達(dá)式有數(shù)字表達(dá)式、邏輯表達(dá)式和字符串表達(dá)式。
下面分別介紹表達(dá)式中各元素。
1.字符串表達(dá)式
字符串表達(dá)式一般由字符串常量、字符串變量、運(yùn)算符和括號(hào)構(gòu)成。字符串由包含在雙引號(hào)內(nèi)的一系列字符組成。編譯器所支持的字符串最大長度為512字節(jié)。
當(dāng)在字符串中包含“$”或引號(hào)時(shí),可以用“$$”表示“$”,用兩個(gè)雙引號(hào)表示一個(gè)雙引號(hào)。
例如:
abc SETS "one "" double quote"
def SETS "one $$ dollar symbol"
上面的例子分別將字符串a(chǎn)bc和def賦值為“one " double quote”和“one $ dollar symbol”。
字符串可以通過SETA、SETL、SETS偽操作對其賦值。
常用的與字符串表達(dá)式相關(guān)的運(yùn)算符如下。
· LEN:計(jì)算字符串長度運(yùn)算符。
· CHR:ASCII碼轉(zhuǎn)換運(yùn)算符。
· STR:字符串轉(zhuǎn)換運(yùn)算符。
· LEFT:字符串取左運(yùn)算符。
· RIGHT:字符串取右運(yùn)算符。
· CC:字符串連接運(yùn)算符。
詳見后面操作符一節(jié)。
下面的例子說明了如何使用字符串操作符給字符串變量賦值。
improb SETS "literal":CC:(strvar2:LEFT:4)
這個(gè)例子將字符串賦值為“literalatrv”。
2.整數(shù)表達(dá)式
整數(shù)表達(dá)式一般由數(shù)字常量、數(shù)字變量、數(shù)字運(yùn)算符和括號(hào)構(gòu)成。
整數(shù)表示式可以包含寄存器相關(guān)(register-relative)或程序相關(guān)(program-relative)表達(dá)式,這些表達(dá)式在編譯時(shí)被匯編器翻譯為地址無關(guān)數(shù)字常量。
整數(shù)表達(dá)式一般被計(jì)算為32位的整數(shù),當(dāng)此整數(shù)被定義為無符號(hào)數(shù)時(shí),其取值范圍為0~232-1,當(dāng)被定義為有符號(hào)數(shù)時(shí),其取值范圍為-231~231-1。匯編器認(rèn)為-n和232-n是相等的。對于關(guān)系操作,如比較兩個(gè)數(shù)的大小,匯編器將其操作數(shù)看作無符號(hào)的數(shù),也就是說“0>-1”對匯編器來說取值為“假({FLASE})”。
下面的例子說明了在程序中,如何對整數(shù)表達(dá)式進(jìn)行操作。
a SETA 256*256 ;將數(shù)字變量賦值為 256*256
MOV r1,#(a*22) ;將數(shù)字表達(dá)式(a*22) 的值放入r1
匯編語言中,整數(shù)數(shù)字量有以下幾種形式。
· 十進(jìn)制數(shù)(decimal-digis)
· “0x”+ 十六進(jìn)制數(shù)(0xhexadecimal-digits)
· “&”+ 十六進(jìn)制數(shù)(&hexadecimal-digits)
· n進(jìn)制數(shù)(n_base-n-digits)
· 字符(character)
其中,十進(jìn)制數(shù)(decimal-digis)可以是“0”到“9”數(shù)字的任意組合;十六進(jìn)制數(shù)(hexadecimal-digits)可以是“0”到“9”數(shù)字和字母“A”到“F”的任意組合;“n_”可以取2到9,“base-n-digits”是在n進(jìn)制下合法的任意數(shù)值;字符(character)可以是除單引號(hào)以外的所有字符。
下面的例子說明了整數(shù)表達(dá)式的基本用法。
a SETA 34906
addr DCD 0xA10E
LDR r4,=&1000000F
DCD 2_11001010
c3 SETA 8_74007
DCQ 0x0123456789abcdef
LDR r1,='A' ;ARM偽指令將整數(shù)65(A的ASCII碼)存入寄存器
ADD r3,r2,#''' ;將整數(shù)39(字符“/”的ASCII碼)加到r2,結(jié)果存入r3
3.浮點(diǎn)數(shù)字量表達(dá)式
浮點(diǎn)數(shù)字量有以下幾種形式。
· {-}digitsE{-}digits。
· {-}{digits}.digits{E{-}digits}。
· 0xhexdigits。
· &hexdigits。
其中,digits為十進(jìn)制數(shù),要在其后加上字母E(大寫或小寫)來表示其指數(shù);hexdigits為十六進(jìn)制數(shù)。
單精度浮點(diǎn)數(shù)的表示范圍為1.17549435e−38~3.40282347e+38;雙精度浮點(diǎn)數(shù)的表示范圍為2.22507385850720138e-308~1.79769313486231571e+308。
下面的例子說明了浮點(diǎn)數(shù)據(jù)量的基本用法。
DCFD 1E308,-4E-100
DCFS 1.0
DCFD 3.725e15
LDFS 0x7FC00000 ;
LDFD &FFF0000000000000 ;
4.邏輯表達(dá)式
邏輯表達(dá)式一般由邏輯量、邏輯運(yùn)算符和括號(hào)構(gòu)成,其表達(dá)式的運(yùn)算結(jié)果為真或假。與邏輯表達(dá)式相關(guān)的運(yùn)算符有“=”、“>”、“<”、“>=”、“<= ”、“/=”、“ <>” 運(yùn)算符和“LAND”、“LOR”、“LNOT”及“LEOR”運(yùn)算符。
5.程序或寄存器相關(guān)表達(dá)式
寄存器相關(guān)表達(dá)式的值等于指定寄存器的值加上或減去一個(gè)數(shù)字表達(dá)式。
程序相關(guān)表達(dá)式的值等于程序計(jì)數(shù)器PC的值加上或減去一個(gè)數(shù)字表達(dá)式的值。此種表達(dá)式通常由程序中的標(biāo)號(hào)與一個(gè)數(shù)字表達(dá)式組成。
下面的例子說明了程序或寄存器相關(guān)表達(dá)式的基本使用方法。
LDR r4,=data+4*n ;n 是匯編時(shí)取值變量
; code
MOV pc,lr
data DCD value0
; n-1 個(gè)DCD 偽操作
DCD valuen ;data+4*n 指向此
;更多DCD偽操作
6.匯編中的操作符
(1)操作符的優(yōu)先級
在匯編語言程序設(shè)計(jì)中,表達(dá)式包含一個(gè)擴(kuò)展的操作符集,這些操作符和高級語言中的運(yùn)算符十分接近。其運(yùn)算次序遵循如下的優(yōu)先級。
① 優(yōu)先級相同的雙目運(yùn)算符的運(yùn)算順序?yàn)閺淖蟮接摇?/p>
② 相鄰的單目運(yùn)算符的運(yùn)算順序?yàn)閺挠业阶?,單目運(yùn)算符的優(yōu)先級高于其他運(yùn)算符。
③ 括號(hào)運(yùn)算符的優(yōu)先級最高。
匯編語法的操作符優(yōu)先級和C語言中的不完全相同。例如在匯編中,下面的匯編語言
(1+2∶SHR∶3)相當(dāng)于(1+(2∶SHR∶3)),而在C語言中,運(yùn)算則變?yōu)椋ǎ?+2)>>3)=0。類似于這樣的操作,在使用時(shí)要特別注意。
注意 |
為了保證表達(dá)式運(yùn)算結(jié)果的正確,建議使用“()”來避免異義。 |
表10.4列出了匯編操作符的優(yōu)先級以及對應(yīng)的C語言運(yùn)算符。
表10.4 匯編操作符優(yōu)先級
匯編操作符 |
C語言運(yùn)算符 |
單目運(yùn)算 |
單目運(yùn)算 |
* / :MOD: |
* / % |
字符串操作 |
n/a |
:SHL::SHR::ROR::ROL: |
<< >> |
+ - :AND: :OR: :EOR: |
+ - $ | |
= > >= < <= /= <> |
== > >= < <= != |
:LAND: :LOR: :LEOR: |
&& || |
說明 |
表10.3是按操作符的優(yōu)先級從上到下排列的。 |
C語言運(yùn)算符優(yōu)先級從高到低排列如下。
· 單目運(yùn)算
· * / %
· + - (as binary operators)
· << >>
· < <= > >=
· == !=
· &
· ^
· |
· &&
· ||
(2)單目運(yùn)算
最高優(yōu)先級的單目運(yùn)算在表達(dá)式中最先被計(jì)算。單目操作符寫在操作數(shù)的前面。運(yùn)算順序?yàn)閺挠业阶蟆?/p>
表10.5列出了匯編中單目運(yùn)算操作符及其返回值。
表10.5 匯編中單目運(yùn)算操作符及其返回值。
操 作 符 |
使 用 |
描 述 |
:CHR: |
:CHR:A |
返回字母A的ASCII碼 |
:LOWERCASE |
:LOWERCASE:string |
將給定字符串中的所有大寫字母變成小寫 |
REVERSE_CC |
:REVERSE_CC:cond_code |
對條件碼取反 |
:STR: |
:STR:A |
將一個(gè)數(shù)字量或邏輯表達(dá)式轉(zhuǎn)換成串 |
:UPPERCASE: |
:UPPERCASE:string |
將給定字符串中的所有小寫字母變成大寫 |
? |
?A |
返回定義符號(hào)A的代碼行所生產(chǎn)代碼行的字節(jié)數(shù) |
續(xù)表
操 作 符 |
使 用 |
描 述 |
+和- |
+A和-A |
單目加和單目減,操作數(shù)為數(shù)學(xué)或程序相關(guān)表達(dá)式 |
:BASE: |
:BASE:A |
如果A是程序或寄存器相關(guān)表達(dá)式,:BASE:返回基址寄存器的編號(hào) |
:CC_ENCODING: |
:CC_ENCODING:cond_code |
返回條件碼中的數(shù)字值 |
:DEF: |
:DEF:A |
判斷A是否被定義,如果被定義返回{TRUE};如果沒有定義返回{FALSE} |
:INDEX: |
:INDEX:A |
如果A是寄存器相關(guān)表達(dá)式,:INDEX:返回A相對于寄存器的偏移量,常用在宏操作中 |
:LEN: |
:LEN:A |
字符串A的長 |
:LNOT: |
:LNOT:A |
邏輯表達(dá)式A的值取反 |
:NOT: |
:NOT:A ~A |
A的值按位取反 |
:RCONT: |
:RCONT:Rn |
返回寄存器編號(hào),0~15對應(yīng)寄存器r0~r15 |
(3)雙目運(yùn)算
ARM匯編中將雙目運(yùn)算符放在兩個(gè)操作數(shù)中間。一般情況下,雙目運(yùn)算的優(yōu)先級低于單目運(yùn)算。下面將以操作符的優(yōu)先級為序分別介紹各操作符。
注意 |
操作符的優(yōu)先級與C語言中操作符優(yōu)先級順序略有不同,詳見單目運(yùn)算一節(jié)。 |
表10.6列出了乘法相關(guān)操作符。
表10.6 乘法相關(guān)操作符
操 作 符 |
別 名 |
使 用 |
說 明 |
* |
A*B |
乘法操作 |
|
/ |
A/B |
除法操作 |
|
:MOD: |
% |
A:MOD:B |
以B為除數(shù)對A取模 |
乘法相關(guān)操作符包括乘、除、取模運(yùn)算,在雙目運(yùn)算中具有最高優(yōu)先級。這些運(yùn)算的操作數(shù)只能是數(shù)字表達(dá)式。
表10.7列出了字符串相關(guān)操作符。
表10.7 字符串操作符
操 作 符 |
使 用 |
說 明 |
:CC: |
A:CC:B |
連接兩個(gè)字符串 |
:LEFT: |
A:LEFT:B |
返回字符串A最左端B長度的字符,操作數(shù)A必須為字符串,B必須為整數(shù)表達(dá)式 |
:RIGHT: |
A:RIGHT:B |
返回字符串A最右端B長度的字符,操作數(shù)A必須為字符串,B必須為整數(shù)表達(dá)式 |
表10.8列出了移位操作符。移位操作中兩個(gè)操作數(shù)均為數(shù)字表達(dá)式。
表10.8 移位操作符
操 作 符 |
別 名 |
使 用 |
說 明 |
:ROL: |
A:ROL:B |
A循環(huán)左移B位 |
|
:ROR: |
A:ROR:B |
A循環(huán)右移B位 |
|
:SHL: |
<< |
A:SHL:B |
A左移B位 |
:SHR: |
>> |
A:SHR:B |
A右移B位 |
注意 |
SHR是邏輯右移,不影響符號(hào)位。 |
表10.9列出了所有加、減、邏輯操作符。
表10.9 加減運(yùn)算操作符
操 作 符 |
別 名 |
使 用 |
說 明 |
+ |
A+B |
A加上B |
|
− |
A−B |
從B中減去A |
|
:AND: |
&& |
A:AND:B |
A和B按位與 |
:EOR: |
^ |
A:EOR:B |
A和B按位異或 |
:OR: |
|| |
A:OR:B |
A和B按位或 |
加、減運(yùn)算的操作數(shù)均為數(shù)字表達(dá)式。邏輯運(yùn)算的表達(dá)式為數(shù)字表達(dá)式,此運(yùn)算按位操作產(chǎn)生結(jié)果。
表10.10列出了ARM匯編中的關(guān)系符。關(guān)系操作符用于表示兩個(gè)同類表達(dá)式之間的關(guān)系。關(guān)系符的兩個(gè)操作數(shù)必須為同種類型的操作數(shù)。操作數(shù)可以是數(shù)字變量、程序相關(guān)表達(dá)式、寄存器相關(guān)表達(dá)式或字符串。
表10.10 關(guān)系操作符
操 作 符 |
別 名 |
使 用 |
說 明 |
= |
= = |
A=B |
判斷A是否等于B |
> |
A>B |
判斷A是否大于B |
|
>= |
A>=B |
判斷A是否大于等于B |
|
< |
A<B |
判斷A是否小于B |
|
<= |
A<=B |
判斷A是否小于等于B |
|
/= |
<> != |
A/=B |
判斷A是否不等于B |
表10.11列出了匯編語言中的邏輯操作符。邏輯操作符進(jìn)行兩個(gè)邏輯表達(dá)式之間的基本邏輯操作。操作的結(jié)果為{FALSE}或{TURE}。
表10.11 邏輯操作符
操 作 符 |
使 用 |
說 明 |
:LAND: |
A:LAND:B |
A和B做邏輯與 |
續(xù)表
操 作 符 |
使 用 |
說 明 |
:LEOR: |
A:LEOR:B |
A和B做邏輯異或 |
:LOR: |
A:LOR:B |
A和B做邏輯或 |
10.3.4 匯編語言預(yù)定義寄存器和協(xié)處理器
ARM匯編器對ARM的寄存器和協(xié)處理器進(jìn)行了預(yù)定義(包括APCS對r0~r15寄存器的定義),所有的寄存器和協(xié)處理器名都是大小寫敏感的。
1.預(yù)定義寄存器名
下面列出了被ARM匯編器預(yù)定義的寄存器名。
· r0~r15和R0~R15(15個(gè)通用寄存器)。
· a1~a4(參數(shù)、結(jié)果或臨時(shí)寄存器,同r0~r3)。
· v1~v8(變量寄存器,同r4~r11)。
· sb和SB(靜態(tài)基址寄存器,同r9)。
· sl和SL(棧頂指針寄存器,同r10)。
· fp和FP(幀指針寄存器,同r11)。
· ip和IP(過程調(diào)用中間臨時(shí)寄存器,同r12)。
· sp和SP(棧指針寄存器,同r13)。
· lr和LR(連接寄存器,同r14)。
· pc和PC(程序計(jì)數(shù)器,同r15)。
2.預(yù)定義程序狀態(tài)寄存器名
下面列出了ARM匯編器預(yù)定義的程序狀態(tài)寄存器的名稱。
· cpsr和CPSR(當(dāng)前程序狀態(tài)寄存器)。
· spsr和SPSR(保留程序狀態(tài)寄存器)。
3.預(yù)定義的浮點(diǎn)寄存器名
下面列出了ARM匯編器預(yù)定義的浮點(diǎn)運(yùn)算寄存器。
· s0~s31和S0~S31(VFP單精度浮點(diǎn)運(yùn)算寄存器)。
· d0~d15和D0~D15(VFP雙精度浮點(diǎn)運(yùn)算寄存器)。
注意 |
FPA的寄存器f0~f7和F0~F7已不再使用。 |
4.預(yù)定義的協(xié)處理器名
下面列出了ARM匯編器預(yù)定義的協(xié)處理器名和協(xié)處理器寄存器名。
· p0~p15(預(yù)定義的協(xié)處理器0~15的名稱)。
· c0~c15(預(yù)定義的協(xié)處理器寄存器0~15的名稱)。
10.3.5 匯編語言內(nèi)置變量
ARM匯編器中定義了一些內(nèi)置變量,這些內(nèi)置變量不能使用偽指令設(shè)置(如,SETA、SETL、SETS等),一般用于程序的條件匯編控制。
下面的例子顯示了如何使用內(nèi)置變量控制程序的執(zhí)行流程。
If {CONFIG}=16 ;若為Thumb代碼則執(zhí)行If后的語句
;codes
else
;codes
endif
b ;程序結(jié)束
下面介紹由ARM匯編器預(yù)定義的內(nèi)置變量。
· {ARCHITECTURE}:選定的ARM體系結(jié)構(gòu)的值,如3,3M,4,4T。
· {AREANAME}:當(dāng)前段名。
· {ARMASM_VERSION}:ARM編譯器ARMASM的變量號(hào)。
· |ads$version|:ARM編譯器ARMASM的變量號(hào),同{ARMASM_VERSION}。
· {CODESIZE}:如果當(dāng)前指令為ARM指令,該內(nèi)置變量取值為32,如果當(dāng)前指令為Thumb指令,該內(nèi)置變量取值為16,同{CONFIG}。
· {COMMANDLINE}:當(dāng)前命令行內(nèi)容。
· {CONFIG}:如果當(dāng)前指令為ARM指令,該內(nèi)置變量取值為32,如果當(dāng)前指令為Thumb指令,該內(nèi)置變量取值為16,同{CODESIZE}。
· {CPU}:所使用的CPU名稱。默認(rèn)為ARM7TDMI。如果在編譯命令行中使用“-CPU”選項(xiàng)確定CPU類型,則該值為“Generic ARM”。
· {ENDIAN}:如果編譯器在大端模式下,其值為“big”;如果在小端模式下,其值為“little”。
· {FPIC}:默認(rèn)為{FALSE},如果設(shè)置了“/fpic”選項(xiàng),其值為{TRUE}。
· {FPU}:所選fpu協(xié)處理器的名字。默認(rèn)為“softVFP”。
· {INPUTFILE}:當(dāng)前源文件名。
· {INTER}:默認(rèn)為{FALSE},如果設(shè)置了“/inter”選項(xiàng),其值為{TRUE}。
· {LINENUM}:目前源文件行號(hào)。
· {NOSWST}:默認(rèn)為{FALSE},如果設(shè)置了“/noswst”選項(xiàng),其值為{TRUE}。
· {OPT}:保存當(dāng)前設(shè)置的列表選項(xiàng)。偽操作OPT用來保存當(dāng)前列表選項(xiàng),改變選項(xiàng)值,或恢復(fù)原始值。
· {PC} 或“.”:當(dāng)前程序地址值。
· {PCSTOREOFFSET}:指令STR pc,[...]和STM Rb,{..., pc}與存儲(chǔ)的PC值之間的偏移量。
· {ROPI}:默認(rèn)為{FALSE},如果設(shè)置了“/ropi”選項(xiàng),其值為{TRUE}。
· {RWPI}:默認(rèn)為{FALSE},如果設(shè)置了“/rwpi”選項(xiàng),其值為{TRUE}。
· {SWST}:默認(rèn)為{FALSE},如果設(shè)置了“/swst”選項(xiàng),其值為{TRUE}。
· {VAR}或@:存儲(chǔ)區(qū)位置寄存器的當(dāng)前值。
10.3.6 匯編語言的程序結(jié)構(gòu)
在ARM(Thumb)匯編語言程序中以程序段為單位組織代碼。段是相對獨(dú)立的指令或數(shù)據(jù)序列,具有特定的名稱。段可以分為代碼段(Code Section)和數(shù)據(jù)段(Data Section),代碼段的內(nèi)容為執(zhí)行代碼,數(shù)據(jù)段存放代碼運(yùn)行時(shí)需要用到的數(shù)據(jù)。一個(gè)匯編程序至少應(yīng)該有一個(gè)代碼段,當(dāng)程序較長時(shí),可以分割為多個(gè)代碼段和數(shù)據(jù)段,多個(gè)段在程序編譯鏈接時(shí)最終形成一個(gè)可執(zhí)行的映像文件。
可執(zhí)行映像文件通常由以下幾部分構(gòu)成。
· 一個(gè)或多個(gè)代碼段,代碼段的屬性為只讀。
· 零個(gè)或多個(gè)數(shù)據(jù)段,數(shù)據(jù)段的屬性為可讀寫。數(shù)據(jù)段可是被初始化的數(shù)據(jù)段或沒有被初始化的數(shù)據(jù)段(ZI,zero initialized)。
鏈接器根據(jù)系統(tǒng)默認(rèn)或用戶設(shè)定的規(guī)則,將各個(gè)段安排在存儲(chǔ)器中的相應(yīng)位置。因此源程序中段之間的相對位置與可執(zhí)行的映像文件中段的相對位置一般不會(huì)相同。
以下是一個(gè)匯編語言源程序的基本結(jié)構(gòu)。
AREA Init,CODE,READONLY
ENTRY
Start
LDR R0,=0x3FF5000
LDR R1,0xFF
STR R1,[R0]
LDR R0,=0x3FF5008
LDR R1,0x01
STR R1,[R0]
……
END
在匯編語言程序中,用AREA偽操作定義一個(gè)段,并說明所定義段的相關(guān)屬性,本例定義一個(gè)名為Init的代碼段,屬性為只讀。ENTRY偽操作標(biāo)識(shí)程序的入口點(diǎn),接下來為指令序列,程序的末尾為END偽指令,該偽操作告訴編譯器源文件的結(jié)束,每一個(gè)匯編程序段都必須有一條END偽操作,指示代碼段的結(jié)束。
10.3.7 匯編語言子程序調(diào)用
在ARM匯編語言程序中,子程序的調(diào)用一般是通過BL指令來實(shí)現(xiàn)的。在程序中,使用指令“BL子程序”名即可完成子程序的調(diào)用。
該指令在執(zhí)行時(shí)完成如下操作:將子程序的返回地址存放在連接寄存器LR中,同時(shí)將程序計(jì)數(shù)器PC指向子程序的入口點(diǎn)。當(dāng)子程序執(zhí)行完畢需要返回調(diào)用處時(shí),只需要將存放在LR中的返回地址重新拷貝給程序計(jì)數(shù)器PC即可。在調(diào)用子程序的同時(shí),也可以完成參數(shù)的傳遞和從子程序返回運(yùn)算的結(jié)果,通常可以使用寄存器R0~R3完成。
注意 |
不同編譯器編譯的代碼間的相互調(diào)用,要遵循AAPCS(ARM Architecture)。詳見ARM編譯工具手冊。 |
以下是使用BL指令調(diào)用子程序的匯編語言源程序的基本結(jié)構(gòu):
AREA Init,CODE,READONLY
ENTRY
Start
LDR R0,=0x3FF5000
LDR R1,0xFF
STR R1,[R0]
LDR R0,=0x3FF5008
LDR R1,0x01
STR R1,[R0]
BL PRINT_TEXT
……
PRINT_TEXT
……
MOV PC,BL
……
END