ARM 匯編程序由機器指令,偽指令和宏指令組成。偽指令不像機器指令那樣在處理器運行期間由機器執(zhí)行,而是匯編程序?qū)υ闯绦騾R編期間由匯編程序處理。在前面的指令集章節(jié)中,我們已經(jīng)接觸了幾條常用到的偽指令,如ADR 、ADRL、LDR、NOP 等,把它們和指令集一起介紹是因為它們在匯編時會被合適的機器指令代替,實現(xiàn)真正機器指令操作。宏是一段獨立的程序代碼,它是通過偽指令定義的,在程序中使用宏指令即可調(diào)用宏。 當程序被匯編時,匯編程序?qū)γ總€調(diào)用進行展開,用宏定義取代源程序中的宏指令。
本文引用地址:http://butianyuan.cn/article/201611/319695.htm 符號定義偽指令
符號定義偽指令用于定義ARM 匯編程序的變量,對變量進行賦值以及定義寄存器名稱,該類偽指令如下:
全局變量聲明:GBLA、GBLL 和GBLS。
局部變量聲明:LCLA、LCLL 和LCLS。
變量賦值: SETA、SETL 和SETS。
為一個通用寄存器列表定義名稱:RLIST。
為一個協(xié)處理器的寄存器定義名稱:CN。
為一個協(xié)處理定義名稱: CP。
為一個VFP 寄存器定義名稱:DN 和SN。
為一個FPA 浮點寄存器定義名稱:FN。
GBLA、GBLL、GBLS
全局變量聲明偽指令。
GBLA 偽指令用于聲明一個全局的算術(shù)變量,并將其初始化為0。
GBLL 偽指令用于聲明一個全局的邏輯變量,并將其初始化為{FALSE}。
GBLS 偽指令用于聲明一個全局的字符串變量,并將其初始化為空字符串“”。
偽指令格式:
GBLA variable
GBLL variable
GBLS variable
其中:variable 定義的全局變量名,在其作用范圍內(nèi)必須惟一。全局變量的作用范圍為包含該變量的源程序。
偽指令應(yīng)用舉例如下:
GBLL codedbg ;聲明一個全局邏輯變量
codebg SETL {TRUE} ;設(shè)置變量為{TRUE}
…
LCLA、LCLL、LCLS
局部變量聲明偽指令,用于宏定義的體中。
LCLA 偽指令用于聲明一個局部的算術(shù)變量,并將其初始化為0。
LCLL 偽指令用于聲明一個局部的邏輯變量,并將其初始化為{FALSE}。
LCLS 偽指令用于聲明一個局部的字符串變量,并將其初始化為空字符串“”。
偽指令格式:
LCLA variable
LCLL variable
LCLS variable
其中:variable 定義的局部變量名。在其作用范圍內(nèi)必須惟一。局部變量的作用范圍為包含該局部變量只能在宏中進行聲明及使用。
偽指令應(yīng)用舉例如下:
MACRO ;聲明一個宏
SENDDAT $dat ;宏的原型
LCLA bitno ;聲明一個局部算術(shù)變量
…
bitno SETA 8 ;設(shè)置變量值為8
…
MEND
SETA、SETL、SETS
變量賦值偽指令。用于對已定義的全局變量,局部變量賦值。
SETA 偽指令用于給一個全局/局部的算術(shù)變量賦值。
SETL 偽指令用于給一個全局/局部的邏輯變量賦值。
SETS 偽指令用于給一個全局/局部的字符串變量賦值。
偽指令格式:
variable_a SETA expr_a
variable_l SETL expr_l
variable_s SETS expr_s
其中:variable_a 算術(shù)變量。用GBLA、LCLA 偽指令定義的變量。
expr_a 賦值的常數(shù)。
variable_l 邏輯變量。用GBLL、LCLL 偽指令定義的變量。
expr_l 邏輯值,即{TRUE}或{FALSE}。
variable_s 字符串變量。用GBLS、LCLS 偽指令定義的變量。
expr_s 賦值的字符串。
偽指令應(yīng)用舉例如下:
GBLS ErrStr
…
ErrStr SETS “No,semaphone”
…
RLIST
RLIST 為一個通用寄存器列表定義名稱。偽指令格式如下:
name RLIST {reglist}
其中:name 要定義的寄存器列表的名稱。
reglist 通用寄存器列表。
偽指令應(yīng)用舉例如下:
LoReg RLIST {R0-R7} ;定義寄存器列表LoReg
…
STMFD SP!,LoReg ;保存寄存器列表LoReg
…
CN
CN 為一個協(xié)處理器的寄存器定義名稱。
偽指令格式:
name CN expr
其中:name 要定義的協(xié)處理器的寄存器名稱。
expr 協(xié)處理器的寄存器編號,數(shù)值范圍為0~15。
偽指令應(yīng)用舉例如下:
MemSet CN l ;將協(xié)處理的寄存器l 名稱定義為MemSet
CP
CP 為一個協(xié)處理器定義的名稱。
偽指令格式:
name CP expr
其中:name 要定義的協(xié)處理器名稱。
expr 協(xié)處理器的編號,數(shù)值范圍為0~15。
偽指令應(yīng)用舉例如下:
DivRun CN 5 ;將協(xié)處理器5 名稱定義為DivRun
DN、SN
DN 和SN 為VFP 的寄存器的名稱定義的偽指令。
DN 為一個雙精度原VFP 寄存器定義名稱。
SN 為一個單精度的VFP 寄存器定義名稱。
偽指令格式:
name DN expr
name SN expr
其中:name 要定義的VFP 寄存器名稱。
expr 雙精度的VFP 寄存器編號為0~15,單精度的VFP 寄存器編號為0~31。
偽指令應(yīng)用舉例如下:
cdn DN 1 ;將VFP 雙精度寄存器1 名稱定義為cdn
rex SN 3 ;將VFP 單精度寄存器3 名稱定義為rex
FN
FN 為一個FPA 浮點寄存器定義名稱
偽指令格式:
name FN expr
其中:name 要定義的浮點寄存器名稱。
expr 浮點寄存器的編號,值為0~7。
偽指令應(yīng)用舉例如下:
ibq FN l ;將浮點寄存器l 名稱定義為ibq
A.4.2 數(shù)據(jù)定義偽指令
數(shù)據(jù)定義偽指令用于數(shù)據(jù)表定義,文字池定義,數(shù)據(jù)空間分配等。該類偽指令如下:
聲明一個文字池:LTORG。
定義一個結(jié)構(gòu)化的內(nèi)存表的首地址:MAP。
定義結(jié)構(gòu)化內(nèi)存表中的一個數(shù)據(jù)域:FIELD。
分配一塊內(nèi)存空間,并用0 初始化:SPACE。
分配一段字節(jié)的內(nèi)存單元,并用指定的數(shù)據(jù)初始化:DCB。
分配一段字的內(nèi)存單元,并用指令的數(shù)據(jù)初始化:DCD 和DCDU。
分配一段字的內(nèi)存單元,將每個單元的內(nèi)容初始化為該單元相對于靜態(tài)基址寄存器的偏移量:DCDO。
分配一段雙字的內(nèi)存單元,并用雙精度的浮點數(shù)據(jù)初始化:DCFD 和DCFDU。
分配一段字的內(nèi)存單元,并用單精度的浮點數(shù)據(jù)初始化:DCFS 和DCFSU。
分配一段字的內(nèi)存單元,并用單精度的浮點數(shù)據(jù)初始化,指定內(nèi)存單元存放的是代碼,而不是數(shù)據(jù):DCI。
分配一段雙字的內(nèi)存單元,并用64 位整數(shù)數(shù)據(jù)初始化:DCQ 和DCQU。
分配一段半字的內(nèi)存單元,并用指定的數(shù)據(jù)初始化:DCW 和DCWU。
LTORG
LTORG 用于聲明一個文字池,在使用LDR 偽指令時,要在適當?shù)牡刂芳尤隠TORG 聲明文字池,這樣就會把要加載的數(shù)據(jù)保存在文字池內(nèi),再用ARM 的加載指令讀出數(shù)據(jù)。(若沒有使用LTORG 聲明文字池,則匯編器會在程序末尾自動聲明。)
偽指令格式:
LTORG
偽指令應(yīng)用舉例如下:
…
LDR R0,=0x12345678
ADD R1,R1,R0
MOV PC,LR
LTORG ;聲明文字池,此地址存儲0x12345678
… ;其它代碼
LTORG 偽指令常放在無條件跳轉(zhuǎn)指令之后,或者子程序返回指令之后,這樣處理器就不會錯誤地將文字池中的數(shù)據(jù)當作指令來執(zhí)行。
MAP
MAP 用于定義一個結(jié)構(gòu)化的內(nèi)存表的首地址。此時,內(nèi)存表的位置計數(shù)器{VAR}設(shè)置為該地址值{VAR}為匯編器的內(nèi)置變量。^與MAP 同義。
偽指令格式:
MAP expr,{base_register}
其中:expr 數(shù)字表達式或程序中的標號。當指令中沒有
base_register 時,expr 即為結(jié)構(gòu)化內(nèi)存表的首地址。
base_register 一個寄存器。當指令中包含這一項時,結(jié)構(gòu)化內(nèi)存表的首地址為expr 與base_register 寄存器值的和。
偽指令應(yīng)用舉例如下:
MAP 0x00,R9 ;定義內(nèi)存表的首地址為R9
Timer FIELD 4 ;定義數(shù)據(jù)域Timer,長度為4 字節(jié)
Attrib FIELD 4 ;定義數(shù)據(jù)域Attrib,長度為4 字節(jié)
String FIELD 100 ;定義數(shù)據(jù)域String,長度為100 字節(jié)
…
ADR R9,DataStart ;設(shè)置R9 的值,即設(shè)置結(jié)構(gòu)化的內(nèi)存表地址
LDR R0,Atrrib ;相當于LDR,R0,[R9,#4]
…
MAP 偽指令和FIELD 偽指令配合使用,用于定義結(jié)構(gòu)化的內(nèi)存表結(jié)構(gòu)。MAP 偽指令中的base-register 寄存器的值對于其后所有的FIELD 偽指令定義的數(shù)據(jù)域是默認使用的,直到遇到新的包含base-register 項的MAP 偽指令。
FIELD
FIELD 用于定義一個結(jié)構(gòu)化內(nèi)存表中的數(shù)據(jù)域。#與FIELD 同義。
偽指令格式:
{tabel} FIELD expr
其中:label 當指令中包含這一項時,label 的值為當前內(nèi)存表的位置計數(shù)器{VAR}的值,匯編編譯器處理了這條FIELD 偽指令后,內(nèi)存表計數(shù)器的值將加上expr。
expr 表示本數(shù)據(jù)域在內(nèi)存表中所占用的字節(jié)數(shù)。
偽指令應(yīng)用舉例如下:
MAP 0x40003000 ;內(nèi)存表的首地址為0x40003000
count1 FIELD 4 ;定義數(shù)據(jù)域count1,長度為4 字節(jié)
count2 FIELD 4 ;定義數(shù)據(jù)域count2,長度為4 字節(jié)
count3 FIELD 4 ;定義數(shù)據(jù)域count3,長度為4 字節(jié)
LDR R1,count1 ;R1=[0x40003000+0x00]
STR R1,count2 ;[0x40003000+0x00]=R1
MAP、FIELD 偽指令僅僅是定義數(shù)據(jù)結(jié)構(gòu),它們并不實際分配內(nèi)存單元。
SPACE
SPACE 用于分配一塊內(nèi)存單元,并用0 初始化。%與SPACE 同義。
偽指令格式:
{label} SPACE expr
其中:label 內(nèi)存塊起始地址標號。
expr 所要分配的內(nèi)存字節(jié)數(shù)。
偽指令應(yīng)用舉例如下:
AREA DataRA,DATA,READWROTE ;聲明一數(shù)據(jù)段,名為DataRAM
DataBuf SPACE 1000 ;分配1000 字節(jié)空間
DCB
DCB 用于分配一段字節(jié)內(nèi)存單元,并用偽指令中的expr 初始化。一般可用來定義數(shù)據(jù)表格,或文字符串。=與DCB 同義。
偽指令格式:
{label} DCB expr{,expr}{,expr}…
其中:label 內(nèi)存塊起始地址標號。
expr 可以為-128~255 的數(shù)值或字符串。內(nèi)存分配的字節(jié)數(shù)由expr 個數(shù)決定。
偽指令應(yīng)用舉例如下
DISPTAB DCB 0x33,0x43,0x76,0x12
DCB -120,20,36,55
ERRSTR DCB “Send,data is error!”,0
DCD 和DCDU
DCD 用于分配一段字內(nèi)存單元,并用偽指令中的expr 初始化。DCD 偽指令分配的內(nèi)存需要字對齊,一般可用來定義數(shù)據(jù)表格或其它常數(shù)。&與DCD 同義。
DCDU 用于分配一段字內(nèi)存單元,并用偽指令中的expr 初始化。DCD 偽指令分配的內(nèi)存不需要字對齊,一般可用來定義數(shù)據(jù)表格或其它常數(shù)。
偽指令格式:
{label} DCD expr{,expr}{,expr}…
{label} DCDU expr{,expr}{,expr}…
其中:label 內(nèi)存塊起始地址標號。
expr 常數(shù)表達式或程序中的標號。內(nèi)存分配字節(jié)數(shù)由expr 個數(shù)決定。
偽指令應(yīng)用舉例如下:
Vectors
LDR PC,ReserAddr
LDR PC,UndefinedAddr
…
ResetAddr DCD Reset
UndefinedAddr DCD Undefined
…
Reset
…
Undefined
…
DCDO
DCDO 用于分配一段字內(nèi)存單元。并將每個單元的內(nèi)容初始化為該單元相對于靜態(tài)基址寄存器的偏移量。DCDO 偽指令作為基于靜態(tài)基址寄存器R9 的偏移量分配內(nèi)存單元。DCDO 偽指令分配的內(nèi)存需要字對齊。
偽指令格式:
{label} DCDO expr{,expr}{,expr}…
其中:label 內(nèi)存塊起始地址標號。
expr 地址偏移表達式或程序中的標號。內(nèi)存分配的字數(shù)由expr 個數(shù)決定。
偽指令應(yīng)用舉例如下:
IMPORT externsym
DCDO externsym ;分配32 位的字單元,其值為標號externsym 基于R9 的偏移
DCFD 和DCFDU
DCFD 用于分配一段雙字的內(nèi)存單元,并用雙精度的浮點數(shù)據(jù)fpliteral 初始化。每個雙精度的浮點數(shù)占據(jù)兩個字單元。DCFD 偽指令分配的內(nèi)存需要字對齊。
DCFDU 具有DCFD 同樣的功能,但分配的內(nèi)存不需要字對齊。
偽指令格式:
{label} DCFD fpliteral{,fpliteral}{,fpliteral}…
{label} DCFDU fpliteral{,fpliteral}{,fpliteral}…
其中:label 內(nèi)存塊起始地址標號。
fpliteral 雙精度的浮點數(shù)。
偽指令應(yīng)用舉例如下:
DCFD 2E30,-3E-20
DCFDU -.1,1000,2.1E18
DCFS 和DCFSU
DCFS 用于分配一段字的內(nèi)存單元,并用單精度的浮點數(shù)據(jù)fpliteral 初始化。每個單精度的浮點數(shù)占據(jù)一個字單元。DCFD 偽指令分配的內(nèi)存需要字對齊。
DCFSU 具有DCFS 同樣的功能,但分配的內(nèi)存不需要字對齊。
偽指令格式:
{label} DCFS fpliteral{,fpliteral}{,fpliteral}…
{label} DCFSU fpliteral{,fpliteral}{,fpliteral}…
其中:label 內(nèi)存塊起始地址標號
fpliteral 單精度的浮點數(shù)。
偽指令應(yīng)用舉例如下:
DCFS 1.1E2,-1.3E10,0.0999
DCI
在ARM 代碼中,DCI 用于分配一段字節(jié)的內(nèi)存單元,用指定的數(shù)據(jù)expr 初始化。指定內(nèi)存單元存放的是代碼,而不是數(shù)據(jù)。
在Thumb 代碼中,DCI 用于分配一段半字節(jié)的內(nèi)存單元,用指定的數(shù)據(jù)expr 初始化。指定內(nèi)存單元存放的是代碼,而不是數(shù)據(jù)。
偽指令格式:
{label} DCI expr
其中:label 內(nèi)存塊起始地址標號。
expr 可為數(shù)字表達式。
DCI 偽指令和DCD 偽指令非常類似,不同之處在于DCI 分配的內(nèi)存中的數(shù)據(jù)被標識為指令??捎糜谕ㄟ^宏指令業(yè)定義處理器不支持的指令。
偽指令應(yīng)用舉例如下:
MACRO ;宏定義(定義NEWCMN Rd,Rn 指令)
NEWCMN $Rd,$Rm ;宏名為NEWCMN,參數(shù)為Rd 和Rm
DCI 0xe16a0e20:OR:($Rd:SHL:12):OR:$Rm
MEND
DCQ 和DCQU
DCQ 用于分配一段雙字的內(nèi)存單元,并用64 位的整數(shù)數(shù)據(jù)literal 初始化。DCQ 偽指令分配的內(nèi)存需要字對齊。
DCQU 具有DCQ 同樣的功能,但分配的內(nèi)存不需要字對齊。
偽指令格式:
{label} DCQ {-}literal{,{-}{literal}}…
{label} DCQU {-}literal{,{-}{literal}}…
其中:label 內(nèi)存塊起始地址標號。
literal 64 位的數(shù)字表達式。取值范圍為0~264-1 當literal前有“.”號時,取值范圍為-263~-1 之間。
偽指令應(yīng)用舉例如下:
DCQU 1234,-76568798776
DCW 和DCWU
DCW 用于分配一段字的內(nèi)存單元,并用指定的數(shù)據(jù)expr 初始化。DCW 偽指令分配的內(nèi)存需要字對齊。
DCWU 具有DCW 同樣的功能,但分配的內(nèi)存不需要字對齊。
偽指令格式:
{label} DCW expr{,expr}{,expr}…
{label} DCWU expr{,expr}{,expr}…
其中:label 內(nèi)存塊起始地址標號。
expr 數(shù)字表達式,取值范圍為-32768~65535。
偽指令應(yīng)用舉例如下:
DCW -592,123,6756
報告?zhèn)沃噶?br /> 報告?zhèn)沃噶钣糜趨R編報告指示。該類偽指令如下:
斷言錯誤:ASSERT。
匯編診斷信息顯示:INFO。
設(shè)置列表選項:OPT。
插入標題:TTL 和SUBT。
ASSERT
ASSERT 為斷言錯誤偽指令。在匯編編譯器對匯編程序的第二遍掃描中,如果其中
ASSERT 條件不成立,ASSERT 偽指令將報告該錯誤信息。
偽指令格式:
ASSERT Logical_expr
其中:Logical_expr 用于斷言的邏輯表達式
偽指令應(yīng)用舉例如下:
ASSERT Top<>Temp ;斷言Top 不等于Temp
INFO
匯編診斷信息顯示偽指令,在匯編器處理過程中的第一遍掃描或第一遍掃描時報告診斷信息。
偽指令格式:
INFO numeric_expr,string_expr
其中:numeric_expr 數(shù)據(jù)表達式。若值為0,則在第一遍掃描時報告診斷信息。否則在第一遍掃描時報告診斷信息。
strint_expr 要顯示的字串
偽指令應(yīng)用舉例如下:
INFO 0,”Version 0。1” ;在第二遍掃描時,報告版本信息
if cont1 > cont2 ;如果cont1 > cont2
INFO 1,”cont1 > cont2” ;則在第一遍掃描時報告”cont1 > cont2”
OPT
設(shè)置列表選項偽指令。通過OPT 偽指令可以在源程序中設(shè)置列表選項。
偽指令格式:
OPI n
其中n 所設(shè)置的選項的編碼如下:
1 設(shè)置常規(guī)列表選項
2 關(guān)閉常規(guī)列表選項
4 設(shè)置分頁符,在新的一頁開始顯示
8 將行號重新設(shè)置為0
16 設(shè)置選項,顯示SET、GBL、LCL 偽指令
32 設(shè)置選項,不顯示SET、GBL、LCL 偽指令
64 設(shè)置選項,顯示宏展開
128 設(shè)置選項,不顯示宏展開
256 設(shè)置選頂,顯示宏調(diào)用
512 設(shè)置先項,不顯示宏調(diào)用
1024 設(shè)置選頂,顯示第一遍掃描列表
2048 設(shè)置選項,不顯示第一遍掃描列表
4096 設(shè)置選項目,顯示條件匯編偽指令
8192 設(shè)置選項,不顯示條件匯編偽指令
16384 設(shè)置選項,顯示MEND 偽指令
32768 設(shè)置選項,不顯示MEND 偽
默認情況下,-list 選項生成常規(guī)的列表文件,包括變量聲明,宏展開,條件匯編偽指令及MEND 偽指令,而且列表文件只是在第二遍掃描時給出,通過OPT 偽指令,可以在源程序中改變默認的選項。
偽指令應(yīng)用舉例如下:
… ;代碼
OPT 512 ;不顯示宏調(diào)用
… ;代碼
TTL 和SUBT
TTL 和SUBT 為插入標題偽指令。
TTL 偽指令在列表文件的每一頁的開頭插入一個標題。該TTL 偽指令的作用在其后的每一頁,直到遇到新的TTL 偽指令。
SUBT 偽指令在列表文件的每頁的開頭第一個子標題。該SUBT 偽指令的作用在其后的每一頁,直到遇到新的SUBT 偽指令。
偽指令格式:
TTL title
SUBT subtitle
其中:title 標題名。
subtitle 子標題名。
偽指令應(yīng)用舉例如下:
…
TTL mainc
…
SUBT subc con
…
A.4.3 匯編控制偽指令
匯編控制偽指令用于條件匯編、宏定義、重復(fù)匯編控制等。該類偽指令如下:
條件匯編控制: IF、ELSE 和ENDIF
宏定義: MACRO 和MEND
重復(fù)匯編: WHILE 及WEND
IF、ELSE 和ENDIF
IF 、ELSE 和ENDIF 偽指令能夠根據(jù)條件把一段代碼包括在匯編程序內(nèi)或?qū)⑵渑懦诔绦蛑狻?br /> [與IF 同義,|與ELSE 同義,]與ENDIF 同義。
偽指令格式:
IF logical_expr
;指令或偽指令代碼段1
ELSE
;指令或偽指令代碼段2
ENDIF
其中:logical_expr 用于控制的邏輯表達式。若條件成立,則代碼段落在匯編源程序中有效。若條件不成立,代碼段1 無效,同時若使用ELSE 偽指令,代碼段有效。
偽指令應(yīng)用舉例如下:
…
IF {CONFIG}=16
BNE __rt_udiv_1
LDR R0,=__rt_div0
BX R0
ELSE
BEQ __rt_div0
ENDIF
IF、ELSE 和ENDIF 偽指令是可以嵌套使用的。
MACRO 和MEND
MACRO 和MEND 偽指令用于宏定義。MACRO 標識宏定義的開始,MEND 標識宏定義久的結(jié)束。用MACRO 及MEND 定義的一段代碼,稱為宏定義體。這樣在程序中就可以通過宏指令多次調(diào)用該代碼段。
偽指令格式:
MACRO
{$label} macroname {$parameter} {$parameter}…
;宏定義體。
MEND
其中:$label 宏指令被展開時,label 可被替換成相應(yīng)的符號,通常為一個標號在一個符號前使用$表示被匯編時將使用相應(yīng)的值替代$后的符號。
macroname 所定義的宏的名稱。
$parameter 宏指令的參數(shù)。當宏指令被展開時將被替換成相應(yīng)的值,類似于函數(shù)中的形式參數(shù)。
對于子程序代碼比較短,而需要傳遞的參數(shù)比較多的情況下可以使用匯編技術(shù)。首先要用MACR 和MEND 偽指令定義宏,包括宏定義體代碼。在MACRO 偽指令之后的第一行聲明宏的原型,其中包含該宏定義的名稱,及需要的參數(shù)。在匯編程序中可以通過該宏定義的名稱來調(diào)用它。當源程序被匯編時,匯編編譯器將展開每個宏調(diào)用,用宏定義體代替源程序中的宏定義的名稱,并用實際的參數(shù)值代替宏定義時的形式參數(shù)。
偽指令應(yīng)用舉例如下:
MACRO
CSI_SETB ;宏名為CSI_SETB,無參數(shù)
LDR R0,=rPDATG ;讀取GPG0 口的值
LDR R1,[R0]
ORR R1,R1#0x01 ;CSI 置位操作
STR R1,[R0] ;輸出控制
MEND
帶參數(shù)的宏定義如程序清單:
MACRO
$IRQ_Label HANDLER $IRQ_Exception
EXPORT $IRQ_Label
IMPORT $IRQ_Exception
$IRQ_Label
SUB LR,LR,#4
STMFD SP!,{R0-R3,R12,LR}
MRS R3,STSR
STMFD SP!,{R3}
…
MEND
WHIL 和WEND
WHILE 和WEND 偽指令用于根據(jù)條件重復(fù)匯編相同的或幾乎相同的一段源程序。
偽指令格式:
WHILE logical_expr
;指令或偽指令代碼段
WEND
其中:logical_expr 用于控制的邏輯表達式。若條件成立,則代碼段在匯編源程序中有效,并不斷重復(fù)這段代碼直到條件不成立。
偽指令應(yīng)用舉例如下:
WHILE no<5
no SETA no+1
…
WEND
WHILE 和WEND 偽指令是可以嵌套使用的。
A.4.5 雜項偽指令
雜項偽指令在匯編編程設(shè)計較為常用,如段定義偽指令,入口點設(shè)置偽指令,包含文件偽指令,標號導(dǎo)出或引入聲明等,該類偽指令如下:
邊界對齊: ALIGN。
段定義: AREA。
指令集定義: CODE16 和CODE32。
匯編結(jié)束: END。
程序入口: ENTRY。
常量定義: EQU。
聲明一個符號可以被其它文件引用:EXPORT 和GLORBAL。
聲明一個外部符號:IMPORT 和EXTERN。
包含文件:GET 和INCLUDE。
包含不被匯編的文件:INCBIN。
保留符號表中的局部符號:KEEP。
禁止浮點指令:NOFP。
指示兩段之間的依賴關(guān)系:REQUIRE。
堆棧8 字節(jié)對準:PEQUIRE8 和PRESERVE8。
給特定的寄存器命名:RN。
標記局部標號使用范圍的界限:ROUT。
ALIGN
ALIGN 偽指令通過添加補丁字節(jié)使當前位置滿足一定的對齊方式。
偽指令格式:
ALIGN {expr{,offset}}
其中:expr 數(shù)字表達式,用于指定對齊的方式。取值為2 的n 次冪,如1、2、4、8等,不能為0 其沒有expr,則默認為字對齊方式。
offset 數(shù)字表達式,當前位置對齊到下面形式的地址處:offset+n*expr
在下面的情況中,需要特定的地址對齊方式:
(A)Thumb 偽指令A(yù)DR 要求地址是字對齊的。而Thumb 代碼中地址標號可能不是字對齊的。這時就要使用偽指令A(yù)LIGN4 使Thumb 代碼中地址標號為字對齊。
(B)由于有些ARM 處理器的Cache 采用了其他對齊方式。如16 字節(jié)對齊方式,這時使用ALIGN 偽指令指定合適的對齊方式可以充分發(fā)揮Cache 的性能優(yōu)勢。
(C)LDRD 和STRD 指令要求存儲單元為8 字節(jié)對齊。這樣在為LDRD/STRD 指令分配的存儲單元前要使用偽指令A(yù)LIGN8 實現(xiàn)8 字節(jié)對齊方式。
(D)地址標號通常自身沒有對齊要求,而在ARM 代碼中要求地起標號對齊是字對齊的,Thumb 代碼中要求半字對齊。這樣可以使用ALIGN4 和ALIGN2 偽指令來調(diào)整對齊方式。
偽指令應(yīng)用舉例如下。
通過ALIGN 偽指令使程序中的地址標號字對齊:
AREA Example,CODE,READONLY ;聲明代碼段Example
START LDR R0,=Sdfjk
…
MOV PC,LR
Sdfjk DCB 0x58 ;定義一字節(jié)存儲空間,字對齊方式被破壞
ALIGN ;聲明字對齊
SUBI MOV R1,R3 ;其它代碼
…
MOV PC,LR
在段定義AREA 中,也可使用ALIGN 偽指令對齊,但表達式的數(shù)字含義是同的
AREA MyStack,DATA,NOINIT,ALIGN=2 ;聲明數(shù)據(jù)段
;MyStack,并重新字對齊
IrqStackSpace SPACE IRQ_STACK_LEGTH*4 ;中斷模式堆棧空間
FiqStackSpace SPACE FIQ_STACK_LEGTH*4 ;快速中斷模式堆??臻g
AbtStackSpace SPACE ABT_STACK_LEGTH*4 ;中止義模式堆棧空間
UndtStackSpace SPACE UND_STACK_LEGTH*4 ;未定義模式堆棧
…
將兩個字節(jié)的數(shù)據(jù)放在同一個字的第一個字節(jié)和第四個字節(jié)中,帶offset 的ALIGN對齊:
AREA offsetFxample, CODE
DCB 0x31 ;第一個字節(jié)保存0x31
ALIGN 4,3 ;字對齊
DCB 0x32 ;第四個字節(jié)保存0x32
…
AREA
AREA 偽指令用于定義一個代碼段或數(shù)據(jù)段。ARM 匯編程序設(shè)計采用分段式設(shè)計,一個ARM 源程序至少需要一個代碼段,大的程序可以包含多少個代碼段及數(shù)據(jù)段。
偽指令格式:
AREA sectionname{,attr}{,attr}…
其中:sectionname 所定義的代碼段或數(shù)據(jù)段的名稱。如果該名稱是以數(shù)據(jù)開頭的,則該名稱必須用“|”括起來,如|1_datasec|。還有一些代碼段具有的約定的名稱。如|text|表示C 語言編譯器產(chǎn)生的代碼段或者與C 語言庫相關(guān)的代碼段。
attr 該代碼段或數(shù)據(jù)段的屬性。
在AREA 偽指令中,各屬性之間用逗號隔開。以下為段屬性及相關(guān)說明:
ALIGN = expr。默認的情況下,ELF 的代碼段和數(shù)據(jù)段是4 字節(jié)對齊的,expr 可以取0~31 的數(shù)值,相應(yīng)的對齊方為2expr 字節(jié)對齊。如expr=3 時為字節(jié)對齊。對于代碼段,expr 不能為0 或1。
ASSOC = section。指定與本段相關(guān)的ELF 段。任何時候連接section 段也必須包括sectionname 段。
DODE 為定義代碼段。默認屬性為READONLY。
COMDEF 定義一個通用的段。該段可以包含代碼或者數(shù)據(jù)。在其它源文件中,同名的COMDEF 段必須相同。
COMMON 定義一個通用的段。該段不包含任何用戶代碼和數(shù)據(jù),連接器將其初始化為此。各源文件中同名的COMMON 段共用同樣的內(nèi)存單元,連接器為其分配合適的尺寸。
DATA 為定義段。默認屬性為READWRITE。
NOINIT 指定本數(shù)據(jù)段僅僅保留了內(nèi)存單元,而沒有將各初始寫入內(nèi)存單元,或者將內(nèi)存單元值初始化為0。
READONLY 指定本段為只讀,代碼段的默認屬性為READONLY。
READWRITE 指定本段為可讀可寫。數(shù)據(jù)段的默認屬性為READWRITE。
使用AREA 偽指令將程序分為多個ELF 格式的段,段名稱可以相同, 這時同名的段被放在同一個ELF 段中。
偽指令應(yīng)用舉例如下:
AREA Example ,CODE,READNOLY ;聲明一個代碼,名為Example
CODE16 和CODE32
CODE16 偽指令指示匯編編譯器后面的指令為16 位的Thumb 指令。
CODE32 偽指令指示匯編編譯器后面的指令為32 位的ARM 指令。
偽指令格式:
CODE16
CODE32
CODE16 和CODE32 偽指令只是指示匯編編譯器后面的指令的類型,偽指令本身并不進行程序狀態(tài)的切換。要進行狀態(tài)切換,可以使用BX 指令操作。
偽指令應(yīng)用舉例如下:
AREA Example CODE,READONLY
CODE32
…
使用CODE16 和CODE32 定義Thumb 指令及ARM 指令并用BX 指令進行切換。
CODE16 和CODE32 的使用:
AREA ArmThumC,CODE,READONLY
CODE32
ADR R0,ThumbStart+1
BX R0
CODE16
ThumbStart
MOV R0,#10
…
END
END
END 偽指令用于指示匯編編譯器源文件已結(jié)束。每一個匯編源文件均要使用一個END 偽指令,指示本源程序結(jié)束。
偽指令格式:
END
ENTRY
ENTRY 偽指令用于指定程序的入口點。
偽指令格式:
ENTRY
一個程序(可以包含多個源文件)中至少要有一個ENTRY,可以有多個ENTRY。但一個源文件中最多只有一個ENTRY。
偽指令應(yīng)用舉例如下。
AREA, Example, CODE,READNOLY
ENTRY
CODE32
START MOV R1,#0x5F
…
EQU
EQU 偽指令為數(shù)字常量,基于寄存器的值和程序中的標號定義一個名稱。*與EQU同義。
指令格式:
name EQU expr{,type}
其中:name 要定義的常量的名稱。
expr 基于寄存器的地址值,程序中的標號,32 位地址常量或32 位常量。
type 當expr 為32 位常量時,可用type 指示expr 表示的數(shù)據(jù)類型。如下示例:
CODE16
CODE32
DATA
EQU 偽指令的作用類似于C 語言中的#define。用于為一個常量定義名稱。
偽指令應(yīng)用舉例如下:
T_bit EQU 0x20 ;定義常量T_bit,其值為0x20
PLLCON EQU 0xE01FC080 ;定義寄存器PLLCON,地址為0Xe01F080
ABCD EQU label+8 ;定義ABCD 為label+8
EXPORT 和GLOBAL
EXPORT 聲明一個符號可以被其它文件引用。相當于聲明了一個全局變量。
GLOBAL 與EXPORT 相同
指令格式:
EXPORT symbol{[WEAK]}
GLOBAL symbol{[WEAK]}
其中:symbol 要聲明的符號名稱
[WEAK] 聲明其它的同名符優(yōu)先于本符號被引用。
偽指令應(yīng)用舉例如下:
EXPORT InitStack
GLOBAL Vectors
IMPORT 和EXTERN
IMJPORT 偽指令指示編譯器當前的符號不是在本源文件中定義的,而是在其他源文件中定義的,在本源文件中可能引用該符號。
EXTERN 與IMPORT 相同
指令格式:
IMPORT symbol{[WEAK]}
EXTERN symbol{[WEAK]}
其中:symbol 要聲明的符號名稱。
[WEAK] 指定該選項后,如果symbol 在所有的源程序中都沒有被定義,編譯器也不會生任何錯誤信息,同時編譯器也不會到當前沒有被INCLUDE 進來庫中去查找該標號。
使用IMPORT 或EXTERN 聲明外部標號時,若連接器在連接處理時不能解釋該符號,而偽指令中沒有[WEAK]選項,則連接器會報告錯誤,若偽指令中有[WEAK]選項,則連接器不會報告錯誤,而是進行下面的操作:
(A)如果該符號被B 或者BL 指令引用,則該符號被設(shè)置成下一條指令的地址,該B 或者BL 指令相當于一條NOP 指令。
(B)其它情況下該符號被設(shè)置0。
偽指令應(yīng)用舉例如下:
IMPORT InitStack
EXTERN Vectors
GET 和INCLUDE
GET 偽指令將一個源文件包含到當前源文件中,并將被包含的文件在當前位置進行匯編處理。INCLUDE 與GFT 同義。
指令格式:
GET filename
INCLUDE filename
其中:filename 要包含的源文件名,可以使用路徑信息。
GET 偽指令通常用于包含一些宏定義或常量定義的源文件。如用EQU 定義的常量,用MAP 和FIELD 定義的結(jié)構(gòu)化的數(shù)據(jù)類型,這樣的源文件類似于C 語言中的頭文件,GET、INCLUDE 偽指令不能用來包含目標文件,而INCBIN 偽指令可以包含目標文件。
偽指令應(yīng)用舉例如下:
INCLUDE LPC2106.inc
INCBIN
INCBIN 偽指令將一個文件包含到當前源文件中,而被包含的文件不進行匯編處理。
指令格式:
INCBIN filename
其中:filename 要包含的源文件名,可以使用路徑信息。
通??梢允褂肐NCBIN 將一個執(zhí)行文件或者任意數(shù)據(jù)包含到當前文件中,被包含的執(zhí)行文件或數(shù)據(jù)將被原封不動地放下當前文件中,編譯器從INCBIN 偽指令后面開始繼續(xù)處理。
偽指令應(yīng)用舉例如下:
NCBIN charlib。bin
KEEP
KEEP 偽指令指示編譯器保留符號表中的局部符號。
偽指令格式:
KEEP {symbol}
其中:symbol 要保留的局部標號。若沒有此項,則除了基于寄存器處的所有符號將包含在目標文件的符號表中。
NOFP
NOFP 偽指令用于禁止源程序中包含浮點運算指令。
偽指令格式:
NOFP
REQUIRE
REQUIRE 偽指令指定段之間的依賴關(guān)系。
偽指令格式:
REQUIRE label
其中:label 所需要的標號的名稱。
當進行鏈接處理時,包含了REQUIRE label 偽指令的源文件,則定義label 的源文件也被包含。
PEQUIRE8 和PRESERVE8
PEQUIRE8 偽指令指示當前文件請求堆棧為8 字節(jié)對齊。
PRESERVE8 偽指令指示當前文件保持堆棧為8 字節(jié)對齊。
偽指令格式:
PEQUIRE8
PRESERVE8
鏈接器保證要求8 字節(jié)對齊的堆棧只能被堆棧為8 字的對齊的代碼調(diào)用
評論