ARM匯編程序設(shè)計(jì)之:ARM匯編器所支持的偽操作
ARM源程序文件(即源文件)有特定的文件格式和語法規(guī)則,可以使用任意文本編輯器編寫程序代碼。一般地,ARM源程序文件名的后綴如表10.1所示。
表10.1 ARM源程序文件名后綴
程序
文件名
匯編
*.S
引入文件
*.INC
C程序
*.C
頭文件
*.H
在一個(gè)項(xiàng)目中,至少要有一個(gè)匯編源文件,可以有多個(gè)匯編源文件或多個(gè)C程序,或者C程序文件和匯編文件兩者的組合。
ARM匯編語言語句格式如下所示。
{label}{instruction/directive/pseudo-instruction}{;comment}
注意
所有指令均不能頂格寫,要用空格(space)或TAB開頭。
其中instruction即ARM指令集中的匯編指令。Directive為ARM匯編器所支持的偽操作。pseudo-instruction為ARM匯編器所支持的偽操作。下面章節(jié)分別介紹偽操作和偽指令。
10.1ARM匯編器所支持的偽操作在ARM匯編語言程序里,有一些特殊指令助記符,這些助記符與指令系統(tǒng)的助記符不同,沒有相對應(yīng)的操作碼,通常稱這些特殊指令助記符為偽操作標(biāo)識符(directive),它們所完成的操作稱為偽操作。偽操作在源程序中的作用是為完成匯編程序作各種準(zhǔn)備工作的,這些偽操作僅在匯編過程中起作用,一旦匯編結(jié)束,偽操作的使命就完成。
在ARM的匯編程序中,偽操作主要有符號定義偽操作、數(shù)據(jù)定義偽操作、匯編控制偽操作、宏指令等。
10.1.1符號定義(SymbolDefinition)偽操作符號定義偽操作用于定義ARM匯編程序中的變量、對變量賦值以及定義寄存器的別名等操作。常見的符號定義偽操作有如下幾種。
·用于定義全局變量的GBLA、GBLL和GBLS。
·用于定義局部變量的LCLA、LCLL和LCLS。
·用于對變量賦值的SETA、SETL、SETS。
·為通用寄存器列表定義名稱的RLIST。
·為協(xié)處理器寄存器定義別名的CN。
·為協(xié)處理器定義別名的CP。
·為VFP寄存器定義名稱的DN和SN。
·為FPA浮點(diǎn)指針寄存器定義名稱的FPA。
1.全局變量定義偽操作GBLA、GBLL和GBLS(1)語法格式
GBLA、GBLL和GBLS偽操作用于定義一個(gè)ARM程序中的全局變量并將其初始化。其中:
GBLA偽操作用于定義一個(gè)全局的數(shù)字變量并初始化為0。
GBLL偽操作用于定義一個(gè)全局的邏輯變量并初始化為F(假)。
GBLS偽操作用于定義一個(gè)全局的字符串變量并初始化為空。
由于以上3條偽指令用于定義全局變量,因此在整個(gè)程序范圍內(nèi)變量名必須惟一。
語法格式如下。
<gblx><variable>
①<gblx>
取值為GBLA、GBLL、GBLS之一。
②<variable>
定義的全局變量名,在其作用范圍內(nèi)必須惟一。全局變量的作用范圍為包含該變量的源程序。
(2)使用說明
如果用這些偽操作重新聲明已經(jīng)聲明過的變量,變量的值將被初始化成后一次聲明語句中的值。
(3)示例
①使用偽操作聲明全局變量。
GBLATest1 ;定義一個(gè)全局的數(shù)字變量,變量名為Test1
Test1SETA0xaa ;將該變量賦值為0xaa
GBLLTest2 ;定義一個(gè)全局的邏輯變量,變量名為Test2
Test2SETL{TRUE} ;將該變量賦值為真
GBLSTest3 ;定義一個(gè)全局的字符串變量,變量名為Test3
Test3SETS"Testing" ;將該變量賦值為“Testing”
②聲明變量objectsize并設(shè)置其值為0xff,為“SPACE”操作做準(zhǔn)備。
GBLAobjectsize
ObjectsizeSETAoxff
SPACEobjectsize
③下面的例子顯示如何使用匯編命令設(shè)置變量的值。具體做法是使用“-pd”選項(xiàng)。
Armasm-pd"objectsizeSETAoxff"-oobjectfilesourcefile
2.局部變量定義偽操作LCLA、LCLL和LCLS(1)語法格式
LCLA、LCLL和LCLS偽指令用于定義一個(gè)ARM程序中的局部變量并將其初始化。其中:
LCLA偽操作用于定義一個(gè)局部的數(shù)字變量并初始化為0。
LCLL偽操作用于定義一個(gè)局部的邏輯變量并初始化為F(假)。
LCLS偽操作用于定義一個(gè)局部的字符串變量并初始化為空。
以上三條偽操作用于聲明局部變量,在其作用范圍內(nèi)變量名必須惟一。
語法格式如下。
<lclx><variable>
①<gblx>
取值為LCLA、LCLL、LCLS之一。
②<variable>
所定義的局部變量名,在其作用范圍內(nèi)必須惟一。局部變量作用范圍為包含該局部變量的宏。
(2)使用說明
如果用這些偽操作重新聲明已經(jīng)聲明過的變量,則變量的值將被初始化成后一次聲明語句中的值。
(3)示例
①使用偽操作聲明局部變量。
LCLATest4 ;聲明一個(gè)局部的數(shù)字變量,變量名為Test4
Test3SETA0xaa ;將該變量賦值為0xaa
LCLLTest5 ;聲明一個(gè)局部的邏輯變量,變量名為Test5
Test4SETL{TRUE} ;將該變量賦值為真
LCLSTest6 ;定義一個(gè)局部的字符串變量,變量名為Test6
Test6SETS"Testing" ;將該變量賦值為“Testing”
②下面的例子定義一個(gè)宏,顯示了局部變量的作用范圍。
MACRO ;聲明一個(gè)宏
$labelmessage$a ;宏原型
LCLSerr ;聲明局部字符串變量
$label
INFO0,"err":CC::STR:$a
MEND ;宏結(jié)束,局部變量不再起作用
3.變量賦值偽操作SETA、SETL和SETS(1)語法格式
偽指令SETA、SETL和SETS用于給一個(gè)已經(jīng)定義的全局變量或局部變量賦值。
SETA偽操作用于給一個(gè)數(shù)學(xué)變量賦值;
SETL偽操作用于給一個(gè)邏輯變量賦值;
SETS偽操作用于給一個(gè)字符串變量賦值;
語法格式如下。
Variable<setx>expr
①Variable
變量名為已經(jīng)定義過的全局變量或局部變量,表達(dá)式為將要賦給變量的值。
②<setx>
取值為SETA、SETL、SETS之一。
③expr
數(shù)學(xué)、邏輯或字符串表達(dá)式,也就是將要賦予變量的值。
(2)使用說明
在向變量賦值前必須先聲明變量。
也可以在匯編指令中預(yù)定義變量,如:
"Armasm--pd"objectsizeSETAoxff"--oobjectfilesourcefile"
(3)示例
①為預(yù)先定義的變量賦值。
LCLATest3 ;聲明一個(gè)局部的數(shù)字變量,變量名為Test3
Test3SETA0xaa ;將該變量賦值為0xaa
LCLLTest4 ;聲明一個(gè)局部的邏輯變量,變量名為Test4
Test4SETL{TRUE} ;將該變量賦值為真
LCLSTest6 ;定義一個(gè)局部的字符串變量,變量名為Test6
Test6SETS"Testing" ;將該變量賦值為“Testing”
②使用變量賦值偽操作,定義一些程序相關(guān)內(nèi)容。
GBLAversionNumber
VersionNumber SETA21
GBLLDebug
Debug SETL{TRUE}
GBLS versionString
VersionString SETS"version1.0"
4.通用寄存器列表定義偽操作RLIST(1)語法格式
RLIST偽操作可用于對一個(gè)通用寄存器列表定義名稱,使用該偽操作定義的名稱可在ARM指令LDM/STM中使用。在LDM/STM指令中,列表中的寄存器訪問次序根據(jù)寄存器的編號由低到高,與列表中的寄存器排列次序無關(guān)。
語法格式如下。
NameRLIST{list-of-registers}
①Name
寄存器列表的名稱。
注意
該名稱不能和已經(jīng)定義寄存器或協(xié)處理器名稱相同。
②list-of-registers
通用寄存器列表。列表中的寄存器用“,”隔開,如果是編號連續(xù)的通用寄存器可以用“-”指定寄存器范圍。具體用法參見程序示例。
(2)使用說明
在使用ARM匯編編譯器編譯源文件時(shí),可以使用“-checkreg”選項(xiàng)來指定匯編器進(jìn)行寄存器檢查。如果匯編器檢測到寄存器列表中的寄存器編號非升序排列,將給出編譯警告。
(3)示例
①將寄存器列表名稱定義為RegList,可在ARM指令LDM/STM中通過該名稱訪問寄存器列表。
RegListRLIST{R0-R5,R8,R10};
②使用“-”在寄存器列表中,指定寄存器范圍。
ContextRLIST{r0-r6,r8,r10-r12,r15} ;
5.協(xié)處理器寄存器名稱定義偽操作CN(1)語法格式
CN偽操作為協(xié)處理器寄存器定義名稱。
語法格式如下。
NameCNexpr
①Name
定義的協(xié)處理器寄存器的名稱。
注意
該名稱不能和已經(jīng)定義寄存器或協(xié)處理器名稱相同。
②expr
協(xié)處理器寄存器編號。
(2)使用說明
協(xié)處理器寄存器編號的數(shù)值范圍為0~15。避免使用不同的名稱定義同一物理寄存器。
注意
協(xié)處理器寄存器的名稱不能被定義為c0~c15,這些名稱已經(jīng)被匯編器預(yù)定義。
(3)示例
將協(xié)處理器寄存器6命名為Power。
PowerCN6
6.協(xié)處理器名稱定義偽操作CP(1)語法格式
CP偽操作為指定的協(xié)處理器定義名稱。
語法格式如下。
NameCPexpr
①Name
定義的協(xié)處理器名稱。
注意
該名稱不能和已經(jīng)定義寄存器或其他協(xié)處理器名稱相同。
②expr
協(xié)處理器編號。
(2)使用說明
協(xié)處理器編號范圍為0~15。
使用CP偽操作為協(xié)處理器定義一個(gè)方便記憶的名稱,可以使程序員更高效地編寫代碼。
注意
協(xié)處理器寄存器的稱不能被定義為p0~p15,這些名稱已經(jīng)被匯編器預(yù)定義。
(3)示例
將協(xié)處理器6命名為Dmu。
DmuCP6
7.VFP寄存器名稱定義偽操作DN/SN(1)語法格式
DN偽操作為雙精度(double-precision)VFP寄存器定義名稱。D0~D15是匯編器預(yù)先定義的,用戶不能使用。
SN偽操作為單精度(single-precision)VFP寄存器定義名稱。S0~S31是匯編器預(yù)先定義的,用戶不能使用。
語法格式如下。
NameDNexpr
NameSNexpr
①Name
指定的VFP寄存器的名稱。
注意
該名稱不能和已經(jīng)定義寄存器或其他協(xié)處理器名稱相同。
②expr
指定VFP寄存器編號。對于雙精度寄存器編號范圍為0~15;對于單精度寄存器編號范圍為0~31。
(2)示例
①將VFP雙精度寄存器6定義為energy。
energyDN6
②將VFP單精度寄存器16定義為mass。
massSN16
8.浮點(diǎn)寄存器名稱定義偽操作FN(1)語法格式
FN為一個(gè)FPA浮點(diǎn)寄存器定義名稱。F0~F7是匯編器預(yù)先定義的,用戶不能使用。
注意
FPA的使用在ARM公司新發(fā)布的編譯器RVCT中已不再支持。
語法格式如下。
NameFNexpr
①Name
指定的浮點(diǎn)寄存器的名稱。
注意
該名稱不能和已經(jīng)定義寄存器或其他協(xié)處理器名稱相同。
②expr
指定浮點(diǎn)寄存器編號。編號范圍為0~7。
(2)示例
為浮點(diǎn)寄存器6指定名稱為Energy。
EnergyFN6