天天看點

ARM僞指令詳解4.1 ARM彙編器所支援的僞指令4.2 彙編語言的語句格式4.3 彙編語言的程式結構4.4 本章小節

因為沒有找到最初始的部落格連結,隻有許多轉載卻沒有貼出初始連結的部落格,是以這裡沒有貼對外連結接。如果有知道者,可以留言指出,我會補上。

4.1 ARM彙編器所支援的僞指令

在ARM彙編語言程式裡,有一些特殊指令助記符,這些助記符與指令系統的助記符不同,沒有相對應的操作碼,通常稱這些特殊指令助記符為僞指令,他們所完成的操作稱為僞操作。僞指令在源程式中的作用是為完成彙程式設計式作各種準備工作的,這些僞指令僅在彙編過程中起作用,一旦彙編結束,僞指令的使命就完成。

在ARM的彙程式設計式中,有如下幾種僞指令:符号定義僞指令、資料定義僞指令、彙編控制僞指令、宏指令以及其他僞指令。

4.1.1 符号定義(Symbol Definition)僞指令

符号定義僞指令用于定義ARM彙程式設計式中的變量、對變量指派以及定義寄存器的别名等操作。常見的符号定義僞指令有如下幾種:

— 用于定義全局變量的GBLA、GBLL和GBLS。

— 用于定義局部變量的LCLA、LCLL和LCLS。

— 用于對變量指派的SETA、SETL、SETS。

— 為通用寄存器清單定義名稱的RLIST。

1、 GBLA、GBLL和GBLS

文法格式:

GBLA(GBLL或GBLS) 全局變量名

GBLA、GBLL和GBLS僞指令用于定義一個ARM程式中的全局變量,并将其初始化。其中:

GBLA僞指令用于定義一個全局的數字變量,并初始化為0;

GBLL僞指令用于定義一個全局的邏輯變量,并初始化為F(假);

GBLS僞指令用于定義一個全局的字元串變量,并初始化為空;

由于以上三條僞指令用于定義全局變量,是以在整個程式範圍内變量名必須唯一。

使用示例:

GBLA Test1 ;定義一個全局的數字變量,變量名為Test1

Test1 SETA 0xaa ;将該變量指派為0xaa

GBLL Test2 ;定義一個全局的邏輯變量,變量名為Test2

Test2 SETL {TRUE} ;将該變量指派為真

GBLS Test3 ;定義一個全局的字元串變量,變量名為Test3

Test3 SETS “Testing” ;将該變量指派為“Testing”

2、 LCLA、LCLL和LCLS

文法格式:

LCLA(LCLL或LCLS) 局部變量名

LCLA、LCLL和LCLS僞指令用于定義一個ARM程式中的局部變量,并将其初始化。其中:

LCLA僞指令用于定義一個局部的數字變量,并初始化為0;

LCLL僞指令用于定義一個局部的邏輯變量,并初始化為F(假);

LCLS僞指令用于定義一個局部的字元串變量,并初始化為空;

以上三條僞指令用于聲明局部變量,在其作用範圍内變量名必須唯一。

使用示例:

LCLA Test4 ;聲明一個局部的數字變量,變量名為Test4

Test3 SETA 0xaa ;将該變量指派為0xaa

LCLL Test5 ;聲明一個局部的邏輯變量,變量名為Test5

Test4 SETL {TRUE} ;将該變量指派為真

LCLS Test6 ;定義一個局部的字元串變量,變量名為Test6

Test6 SETS “Testing” ;将該變量指派為“Testing”

3、 SETA、SETL和SETS

文法格式:

變量名 SETA(SETL或SETS) 表達式

僞指令SETA、SETL、SETS用于給一個已經定義的全局變量或局部變量指派。

SETA僞指令用于給一個數學變量指派;

SETL僞指令用于給一個邏輯變量指派;

SETS僞指令用于給一個字元串變量指派;

其中,變量名為已經定義過的全局變量或局部變量,表達式為将要賦給變量的值。

使用示例:

LCLA Test3 ;聲明一個局部的數字變量,變量名為Test3

Test3 SETA 0xaa ;将該變量指派為0xaa

LCLL Test4 ;聲明一個局部的邏輯變量,變量名為Test4

Test4 SETL {TRUE} ;将該變量指派為真

4、 RLIST

文法格式:

名稱 RLIST {寄存器清單}

RLIST僞指令可用于對一個通用寄存器清單定義名稱,使用該僞指令定義的名稱可在ARM指令LDM/STM中使用。在LDM/STM指令中,清單中的寄存器通路次序為根據寄存器的編号由低到高,而與清單中的寄存器排列次序無關。

使用示例:

RegList RLIST {R0-R5,R8,R10} ;将寄存器清單名稱定義為RegList,可在ARM指令LDM/STM中通過該名稱通路寄存器清單。

4.1.2 資料定義(Data Definition)僞指令

資料定義僞指令一般用于為特定的資料配置設定存儲單元,同時可完成已配置設定存儲單元的初始化。常見的資料定義僞指令有如下幾種:

— DCB 用于配置設定一片連續的位元組存儲單元并用指定的資料初始化。

— DCW(DCWU) 用于配置設定一片連續的半字存儲單元并用指定的資料初始化。

— DCD(DCDU) 用于配置設定一片連續的字存儲單元并用指定的資料初始化。

— DCFD(DCFDU)用于為雙精度的浮點數配置設定一片連續的字存儲單元并用指定的資料初始化。

— DCFS(DCFSU) 用于為單精度的浮點數配置設定一片連續的字存儲單元并用指定的資料初始化。

— DCQ(DCQU) 用于配置設定一片以8位元組為機關的連續的存儲單元并用指定的資料初始化。

— SPACE 用于配置設定一片連續的存儲單元

— MAP 用于定義一個結構化的記憶體表首位址

— FIELD 用于定義一個結構化的記憶體表的資料域

1、 DCB

文法格式:

标号 DCB 表達式

DCB僞指令用于配置設定一片連續的位元組存儲單元并用僞指令中指定的表達式初始化。其中,表達式可以為0~255的數字或字元串。DCB也可用“=”代替。

使用示例:

Str DCB “This is a test!” ;配置設定一片連續的位元組存儲單元并初始化。

2、 DCW(或DCWU)

文法格式:

标号 DCW(或DCWU) 表達式

DCW(或DCWU)僞指令用于配置設定一片連續的半字存儲單元并用僞指令中指定的表達式初始化。其中,表達式可以為程式标号或數字表達式。。

用DCW配置設定的字存儲單元是半字對齊的,而用DCWU配置設定的字存儲單元并不嚴格半字對齊。

使用示例:

DataTest DCW 1,2,3 ;配置設定一片連續的半字存儲單元并初始化。

3、 DCD(或DCDU)

文法格式:

标号 DCD(或DCDU) 表達式

DCD(或DCDU)僞指令用于配置設定一片連續的字存儲單元并用僞指令中指定的表達式初始化。其中,表達式可以為程式标号或數字表達式。DCD也可用“&”代替。

用DCD配置設定的字存儲單元是字對齊的,而用DCDU配置設定的字存儲單元并不嚴格字對齊。

使用示例:

DataTest DCD 4,5,6 ;配置設定一片連續的字存儲單元并初始化。

4、 DCFD(或DCFDU)

文法格式:

标号 DCFD(或DCFDU) 表達式

DCFD(或DCFDU)僞指令用于為雙精度的浮點數配置設定一片連續的字存儲單元并用僞指令中指定的表達式初始化。每個雙精度的浮點數占據兩個字單元。

用DCFD配置設定的字存儲單元是字對齊的,而用DCFDU配置設定的字存儲單元并不嚴格字對齊。

使用示例:

FDataTest DCFD 2E115,-5E7 ;配置設定一片連續的字存儲單元并初始化為指定的雙精度數。

5、 DCFS(或DCFSU)

文法格式:

标号 DCFS(或DCFSU) 表達式

DCFS(或DCFSU)僞指令用于為單精度的浮點數配置設定一片連續的字存儲單元并用僞指令中指定的表達式初始化。每個單精度的浮點數占據一個字單元。

用DCFS配置設定的字存儲單元是字對齊的,而用DCFSU配置設定的字存儲單元并不嚴格字對齊。

使用示例:

FDataTest DCFS 2E5,-5E-7 ;配置設定一片連續的字存儲單元并初始化為指定的單精度數。

6、 DCQ(或DCQU)

文法格式:

标号 DCQ(或DCQU) 表達式

DCQ(或DCQU)僞指令用于配置設定一片以8個位元組為機關的連續存儲區域并用僞指令中指定的表達式初始化。

用DCQ配置設定的存儲單元是字對齊的,而用DCQU配置設定的存儲單元并不嚴格字對齊。

使用示例:

DataTest DCQ 100 ;配置設定一片連續的存儲單元并初始化為指定的值。

7、 SPACE

文法格式:

标号 SPACE 表達式

SPACE僞指令用于配置設定一片連續的存儲區域并初始化為0。其中,表達式為要配置設定的位元組數。SPACE也可用“%”代替。

使用示例:

DataSpace SPACE 100 ;配置設定連續100位元組的存儲單元并初始化為0。

8、 MAP

文法格式:

MAP 表達式{,基址寄存器}

MAP僞指令用于定義一個結構化的記憶體表的首位址。MAP也可用“^”代替。

表達式可以為程式中的标号或數學表達式,基址寄存器為可選項,當基址寄存器選項不存在時,表達式的值即為記憶體表的首位址,當該選項存在時,記憶體表的首位址為表達式的值與基址寄存器的和。

MAP僞指令通常與FIELD僞指令配合使用來定義結構化的記憶體表。

使用示例:

MAP 0x100,R0 ;定義結構化記憶體表首位址的值為0x100+R0。

9、 FILED

文法格式:

标号 FIELD 表達式

FIELD僞指令用于定義一個結構化記憶體表中的資料域。FILED也可用“#”代替。

表達式的值為目前資料域在記憶體表中所占的位元組數。

FIELD僞指令常與MAP僞指令配合使用來定義結構化的記憶體表。MAP僞指令定義記憶體表的首位址,FIELD僞指令定義記憶體表中的各個資料域,并可以為每個資料域指定一個标号供其他的指令引用。

注意MAP和FIELD僞指令僅用于定義資料結構,并不實際配置設定存儲單元。

使用示例:

MAP 0x100 ;定義結構化記憶體表首位址的值為0x100。

A FIELD 16 ;定義A的長度為16位元組,位置為0x100

B FIELD 32 ;定義B的長度為32位元組,位置為0x110

S FIELD 256 ;定義S的長度為256位元組,位置為0x130

4.1.3 彙編控制(Assembly Control)僞指令

彙編控制僞指令用于控制彙程式設計式的執行流程,常用的彙編控制僞指令包括以下幾條:

— IF、ELSE、ENDIF

— WHILE、WEND

— MACRO、MEND

— MEXIT

1、 IF、ELSE、ENDIF

文法格式:

IF 邏輯表達式

指令序列1

ELSE

指令序列2

ENDIF

IF、ELSE、ENDIF僞指令能根據條件的成立與否決定是否執行某個指令序列。當IF後面的邏輯表達式為真,則執行指令序列1,否則執行指令序列2。其中,ELSE及指令序列2可以沒有,此時,當IF後面的邏輯表達式為真,則執行指令序列1,否則繼續執行後面的指令。

IF、ELSE、ENDIF僞指令可以嵌套使用。

使用示例:

GBLL Test ;聲明一個全局的邏輯變量,變量名為Test

……

IF Test = TRUE

指令序列1

ELSE

指令序列2

ENDIF

2、 WHILE、WEND

文法格式:

WHILE 邏輯表達式

指令序列

WEND

WHILE、WEND僞指令能根據條件的成立與否決定是否循環執行某個指令序列。當WHILE後面的邏輯表達式為真,則執行指令序列,該指令序列執行完畢後,再判斷邏輯表達式的值,若為真則繼續執行,一直到邏輯表達式的值為假。

WHILE、WEND僞指令可以嵌套使用。

使用示例:

GBLA Counter ;聲明一個全局的數學變量,變量名為Counter

Counter SETA 3 ;由變量Counter控制循環次數

……

WHILE Counter < 10

指令序列

WEND

3、 MACRO、MEND

文法格式:

标号宏名 參數1,$參數2,……

指令序列

MEND

MACRO、MEND僞指令可以将一段代碼定義為一個整體,稱為宏指令,然後就可以在程式中通過宏指令多次調用該段代碼。其中,$标号在宏指令被展開時,标号會被替換為使用者定義的符号,

宏指令可以使用一個或多個參數,當宏指令被展開時,這些參數被相應的值替換。

宏指令的使用方式和功能與子程式有些相似,子程式可以提供子產品化的程式設計、節省存儲空間并提高運作速度。但在使用子程式結構時需要保護現場,進而增加了系統的開銷,是以,在代碼較短且需要傳遞的參數較多時,可以使用宏指令代替子程式。

包含在MACRO和MEND之間的指令序列稱為宏定義體,在宏定義體的第一行應聲明宏的原型(包含宏名、所需的參數),然後就可以在彙程式設計式中通過宏名來調用該指令序列。在源程式被編譯時,彙編器将宏調用展開,用宏定義中的指令序列代替程式中的宏調用,并将實際參數的值傳遞給宏定義中的形式參數。

MACRO、MEND僞指令可以嵌套使用。

4、 MEXIT

文法格式:

MEXIT

MEXIT用于從宏定義中跳轉出去。

4.1.4 其他常用的僞指令

還有一些其他的僞指令,在彙程式設計式中經常會被使用,包括以下幾條:

— AREA

— ALIGN

— CODE16、CODE32

— ENTRY

— END

— EQU

— EXPORT(或GLOBAL)

— IMPORT

— EXTERN

— GET(或INCLUDE)

— INCBIN

— RN

— ROUT

1、 AREA

文法格式:

AREA 段名 屬性1,屬性2,……

AREA僞指令用于定義一個代碼段或資料段。其中,段名若以數字開頭,則該段名需用“|”括起來,如|1_test|。

屬性字段表示該代碼段(或資料段)的相關屬性,多個屬性用逗号分隔。常用的屬性如下:

— CODE屬性:用于定義代碼段,預設為READONLY。

— DATA屬性:用于定義資料段,預設為READWRITE。

— READONLY屬性:指定本段為隻讀,代碼段預設為READONLY。

— READWRITE屬性:指定本段為可讀可寫,資料段的預設屬性為READWRITE。

— ALIGN屬性:使用方式為ALIGN 表達式。在預設時,ELF(可執行連接配接檔案)的代碼段和資料段是按字對齊的,表達式的取值範圍為0~31,相應的對齊方式為2表達式次方。

— COMMON屬性:該屬性定義一個通用的段,不包含任何的使用者代碼和資料。各源檔案中同名的COMMON段共享同一段存儲單元。

一個彙編語言程式至少要包含一個段,當程式太長時,也可以将程式分為多個代碼段和資料段。

使用示例:

AREA Init,CODE,READONLY

指令序列

;該僞指令定義了一個代碼段,段名為Init,屬性為隻讀

2、 ALIGN

文法格式:

ALIGN {表達式{,偏移量}}

ALIGN僞指令可通過添加填充位元組的方式,使目前位置滿足一定的對其方式|。其中,表達式的值用于指定對齊方式,可能的取值為2的幂,如1、2、4、8、16等。若未指定表達式,則将目前位置對齊到下一個字的位置。偏移量也為一個數字表達式,若使用該字段,則目前位置的對齊方式為:2的表達式次幂+偏移量。

使用示例:

AREA Init,CODE,READONLY,ALIEN=3 ;指定後面的指令為8位元組對齊。

指令序列

END

3、 CODE16、CODE32

文法格式:

CODE16(或CODE32)

CODE16僞指令通知編譯器,其後的指令序列為16位的Thumb指令。

CODE32僞指令通知編譯器,其後的指令序列為32位的ARM指令。

若在彙編源程式中同時包含ARM指令和Thumb指令時,可用CODE16僞指令通知編譯器其後的指令序列為16位的Thumb指令,CODE32僞指令通知編譯器其後的指令序列為32位的ARM指令。是以,在使用ARM指令和Thumb指令混合程式設計的代碼裡,可用這兩條僞指令進行切換,但注意他們隻通知編譯器其後指令的類型,并不能對處理器進行狀态的切換。

使用示例:

AREA Init,CODE,READONLY

……

CODE32 ;通知編譯器其後的指令為32位的ARM指令

LDR R0,=NEXT+1 ;将跳轉位址放入寄存器R0

BX R0 ;程式跳轉到新的位置執行,并将處理器切換到Thumb工作狀态

……

CODE16 ;通知編譯器其後的指令為16位的Thumb指令

NEXT LDR R3,=0x3FF

……

END ;程式結束

4、 ENTRY

文法格式:

ENTRY

ENTRY僞指令用于指定彙程式設計式的入口點。在一個完整的彙程式設計式中至少要有一個ENTRY(也可以有多個,當有多個ENTRY時,程式的真正入口點由連結器指定),但在一個源檔案裡最多隻能有一個ENTRY(可以沒有)。

使用示例:

AREA Init,CODE,READONLY

ENTRY ;指定應用程式的入口點

……

5、 END

文法格式:

END

END僞指令用于通知編譯器已經到了源程式的結尾。

使用示例:

AREA Init,CODE,READONLY

……

END ;指定應用程式的結尾

6、 EQU

文法格式:

名稱 EQU 表達式{,類型}

EQU僞指令用于為程式中的常量、标号等定義一個等效的字元名稱,類似于C語言中的#define。其中EQU可用“*”代替。

名稱為EQU僞指令定義的字元名稱,當表達式為32位的常量時,可以指定表達式的資料類型,可以有以下三種類型:

CODE16、CODE32和DATA

使用示例:

Test EQU 50 ;定義标号Test的值為50

Addr EQU 0x55,CODE32 ;定義Addr的值為0x55,且該處為32位的ARM指令。

7、 EXPORT(或GLOBAL)

文法格式:

EXPORT 标号{[WEAK]}

EXPORT僞指令用于在程式中聲明一個全局的标号,該标号可在其他的檔案中引用。EXPORT可用GLOBAL代替。标号在程式中區分大小寫,[WEAK]選項聲明其他的同名标号優先于該标号被引用。

使用示例:

AREA Init,CODE,READONLY

EXPORT Stest ;聲明一個可全局引用的标号Stest

……

END

8、 IMPORT

文法格式:

IMPORT 标号{[WEAK]}

IMPORT僞指令用于通知編譯器要使用的标号在其他的源檔案中定義,但要在目前源檔案中引用,而且無論目前源檔案是否引用該标号,該标号均會被加入到目前源檔案的符号表中。

标号在程式中區分大小寫,[WEAK]選項表示當所有的源檔案都沒有定義這樣一個标号時,編譯器也不給出錯誤資訊,在多數情況下将該标号置為0,若該标号為B或BL指令引用,則将B或BL指令置為NOP操作。

使用示例:

AREA Init,CODE,READONLY

IMPORT Main ;通知編譯器目前檔案要引用标号Main,但Main在其他源檔案中定義

……

END

9、 EXTERN

文法格式:

EXTERN 标号{[WEAK]}

EXTERN僞指令用于通知編譯器要使用的标号在其他的源檔案中定義,但要在目前源檔案中引用,如果目前源檔案實際并未引用該标号,該标号就不會被加入到目前源檔案的符号表中。

标号在程式中區分大小寫,[WEAK]選項表示當所有的源檔案都沒有定義這樣一個标号時,編譯器也不給出錯誤資訊,在多數情況下将該标号置為0,若該标号為B或BL指令引用,則将B或BL指令置為NOP操作。

使用示例:

AREA Init,CODE,READONLY

EXTERN Main ;通知編譯器目前檔案要引用标号Main,但Main在其他源檔案中定義

……

END

10、 GET(或INCLUDE)

文法格式:

GET 檔案名

GET僞指令用于将一個源檔案包含到目前的源檔案中,并将被包含的源檔案在目前位置進行彙編處理。可以使用INCLUDE代替GET。

彙程式設計式中常用的方法是在某源檔案中定義一些宏指令,用EQU定義常量的符号名稱,用MAP和FIELD定義結構化的資料類型,然後用GET僞指令将這個源檔案包含到其他的源檔案中。使用方法與C語言中的“include”相似。

GET僞指令隻能用于包含源檔案,包含目标檔案需要使用INCBIN僞指令

使用示例:

AREA Init,CODE,READONLY

GET a1.s ;通知編譯器目前源檔案包含源檔案a1.s

GE T C:\a2.s ;通知編譯器目前源檔案包含源檔案C:\ a2.s

……

END

11、 INCBIN

文法格式:

INCBIN 檔案名

INCBIN僞指令用于将一個目标檔案或資料檔案包含到目前的源檔案中,被包含的檔案不作任何變動的存放在目前檔案中,編譯器從其後開始繼續處理。

使用示例:

AREA Init,CODE,READONLY

INCBIN a1.dat ;通知編譯器目前源檔案包含檔案a1.dat

INCBIN C:\a2.txt ;通知編譯器目前源檔案包含檔案C:\a2.txt

……

END

12、 RN

文法格式:

名稱 RN 表達式

RN僞指令用于給一個寄存器定義一個别名。采用這種方式可以友善程式員記憶該寄存器的功能。其中,名稱為給寄存器定義的别名,表達式為寄存器的編碼。

使用示例:

Temp RN R0 ;将R0定義一個别名Temp

13、 ROUT

文法格式:

{名稱} ROUT

ROUT僞指令用于給一個局部變量定義作用範圍。在程式中未使用該僞指令時,局部變量的作用範圍為所在的AREA,而使用ROUT後,局部變量的作為範圍為目前ROUT和下一個ROUT之間。

4.2 彙編語言的語句格式

ARM(Thumb)彙編語言的語句格式為:

{标号} {指令或僞指令} {;注釋}

在彙編語言程式設計中,每一條指令的助記符可以全部用大寫、或全部用小寫,但不用許在一條指令中大、小寫混用。

同時,如果一條語句太長,可将該長語句分為若幹行來書寫,在行的末尾用“\”表示下一行與本行為同一條語句。

4.2.1 在彙編語言程式中常用的符号

在彙編語言程式設計中,經常使用各種符号代替位址、變量和常量等,以增加程式的可讀性。盡管符号的命名由程式設計者決定,但并不是任意的,必須遵循以下的約定:

— 符号區分大小寫,同名的大、小寫符号會被編譯器認為是兩個不同的符号。

— 符号在其作用範圍内必須唯一。

— 自定義的符号名不能與系統的保留字相同。

— 符号名不應與指令或僞指令同名。

1、 程式中的變量

程式中的變量是指其值在程式的運作過程中可以改變的量。ARM(Thumb)彙程式設計式所支援的變量有數字變量、邏輯變量和字元串變量。

數字變量用于在程式的運作中儲存數字值,但注意數字值的大小不應超出數字變量所能表示的範圍。

邏輯變量用于在程式的運作中儲存邏輯值,邏輯值隻有兩種取值情況:真或假。

字元串變量用于在程式的運作中儲存一個字元串,但注意字元串的長度不應超出字元串變量所能表示的範圍。

在ARM(Thumb)彙編語言程式設計中,可使用GBLA、GBLL、GBLS僞指令聲明全局變量,使用LCLA、LCLL、LCLS僞指令聲明局部變量,并可使用SETA、SETL和SETS對其進行初始化。

2、 程式中的常量

程式中的常量是指其值在程式的運作過程中不能被改變的量。ARM(Thumb)彙程式設計式所支援的常量有數字常量、邏輯常量和字元串常量。

數字常量一般為32位的整數,當作為無符号數時,其取值範圍為0~232-1,當作為有符号數時,其取值範圍為-231~231-1。

邏輯常量隻有兩種取值情況:真或假。

字元串常量為一個固定的字元串,一般用于程式運作時的資訊提示。

3、 程式中的變量代換

程式中的變量可通過代換操作取得一個常量。代換操作符為“$”。

如果在數字變量前面有一個代換操作符“ ”,編譯器會将該數字變量的值轉換為十六進制的字元串,并将該十六進制的字元串代換“ ”後的數字變量。

如果在邏輯變量前面有一個代換操作符“$”,編譯器會将該邏輯變量代換為它的取值(真或假)。

如果在字元串變量前面有一個代換操作符“ ”,編譯器會将該字元串變量的值代換“ ”後的字元串變量。

使用示例:

LCLS S1 ;定義局部字元串變量S1和S2

LCLS S2

S1 SETS “Test!”

S2 SETS “This is a $S1” ;字元串變量S2的值為“This is a Test!”

4.2.2 彙編語言程式中的表達式和運算符

在彙編語言程式設計中,也經常使用各種表達式,表達式一般由變量、常量、運算符和括号構成。常用的表達式有數字表達式、邏輯表達式和字元串表達式,其運算次序遵循如下的優先級:

— 優先級相同的雙目運算符的運算順序為從左到右。

— 相鄰的單目運算符的運算順序為從右到左,且單目運算符的優先級高于其他運算符。

— 括号運算符的優先級最高。

1、 數字表達式及運算符

數字表達式一般由數字常量、數字變量、數字運算符和括号構成。與數字表達式相關的運算符如下:

— “+”、“-”、“×”、“/” 及“MOD”算術運算符

以上的算術運算符分别代表加、減、乘、除和取餘數運算。例如,以X和Y表示兩個數字表達式,則:

X+Y 表示X與Y的和。

X-Y 表示X與Y的差。

X×Y 表示X與Y的乘積。

X/Y 表示X除以Y的商。

X:MOD:Y 表示X除以Y的餘數。

— “ROL”、“ROR”、“SHL”及“SHR”移位運算符

以X和Y表示兩個數字表達式,以上的移位運算符代表的運算如下:

X:ROL:Y 表示将X循環左移Y位。

X:ROR:Y 表示将X循環右移Y位。

X:SHL:Y 表示将X左移Y位。

X:SHR:Y 表示将X右移Y位。

— “AND”、“OR”、“NOT”及“EOR”按位邏輯運算符

以X和Y表示兩個數字表達式,以上的按位邏輯運算符代表的運算如下:

X:AND:Y 表示将X和Y按位作邏輯與的操作。

X:OR:Y 表示将X和Y按位作邏輯或的操作。

:NOT:Y 表示将Y按位作邏輯非的操作。

X:EOR:Y 表示将X和Y按位作邏輯異或的操作。

2、 邏輯表達式及運算符

邏輯表達式一般由邏輯量、邏輯運算符和括号構成,其表達式的運算結果為真或假。與邏輯表達式相關的運算符如下:

— “=”、“>”、“<”、“>=”、“<= ”、“/=”、“ <>” 運算符

以X和Y表示兩個邏輯表達式,以上的運算符代表的運算如下:

X = Y 表示X等于Y。

X > Y 表示X大于Y。

X < Y 表示X小于Y。

X >= Y 表示X大于等于Y。

X <= Y 表示X小于等于Y。

X /= Y 表示X不等于Y。

X <> Y 表示X不等于Y。

— “LAND”、“LOR”、“LNOT”及“LEOR”運算符

以X和Y表示兩個邏輯表達式,以上的邏輯運算符代表的運算如下:

X:LAND:Y 表示将X和Y 作邏輯與的操作。

X:LOR:Y 表示将X和Y作邏輯或的操作。

:LNOT:Y 表示将Y作邏輯非的操作。

X:LEOR:Y 表示将X和Y作邏輯異或的操作。

3、 字元串表達式及運算符

字元串表達式一般由字元串常量、字元串變量、運算符和括号構成。編譯器所支援的字元串最大長度為512位元組。常用的與字元串表達式相關的運算符如下:

— LEN運算符

LEN運算符傳回字元串的長度(字元數),以X表示字元串表達式,其文法格式如下:

:LEN:X

— CHR運算符

CHR運算符将0~255之間的整數轉換為一個字元,以M表示某一個整數,其文法格式如下:

:CHR:M

— STR運算符

STR運算符将将一個數字表達式或邏輯表達式轉換為一個字元串。對于數字表達式,STR運算符将其轉換為一個以十六進制組成的字元串;對于邏輯表達式,STR運算符将其轉換為字元串T或F,其文法格式如下:

:STR:X

其中,X為一個數字表達式或邏輯表達式。

— LEFT運算符

LEFT運算符傳回某個字元串左端的一個子串,其文法格式如下:

X:LEFT:Y

其中:X為源字元串,Y為一個整數,表示要傳回的字元個數。

— RIGHT運算符

與LEFT運算符相對應,RIGHT運算符傳回某個字元串右端的一個子串,其文法格式如下:

X:RIGHT:Y

其中:X為源字元串,Y為一個整數,表示要傳回的字元個數。

— CC運算符

CC運算符用于将兩個字元串連接配接成一個字元串,其文法格式如下:

X:CC:Y

其中:X為源字元串1,Y為源字元串2,CC運算符将Y連接配接到X的後面。

4、 與寄存器和程式計數器(PC)相關的表達式及運算符

常用的與寄存器和程式計數器(PC)相關的表達式及運算符如下:

— BASE運算符

BASE運算符傳回基于寄存器的表達式中寄存器的編号,其文法格式如下:

:BASE:X

其中,X為與寄存器相關的表達式。

— INDEX運算符

INDEX運算符傳回基于寄存器的表達式中相對于其基址寄存器的偏移量,其文法格式如下:

:INDEX:X

其中,X為與寄存器相關的表達式。

5、 其他常用運算符

— ?運算符

?運算符傳回某代碼行所生成的可執行代碼的長度,例如:

?X

傳回定義符号X的代碼行所生成的可執行代碼的位元組數。

— DEF運算符

DEF運算符判斷是否定義某個符号,例如:

:DEF:X

如果符号X已經定義,則結果為真,否則為假。

4.3 彙編語言的程式結構

4.3.1 彙編語言的程式結構

在ARM(Thumb)彙編語言程式中,以程式段為機關組織代碼。段是相對獨立的指令或資料序列,具有特定的名稱。段可以分為代碼段和資料段,代碼段的内容為執行代碼,資料段存放代碼運作時需要用到的資料。一個彙程式設計式至少應該有一個代碼段,當程式較長時,可以分割為多個代碼段和資料段,多個段在程式編譯連結時最終形成一個可執行的映象檔案。

可執行映象檔案通常由以下幾部分構成:

— 一個或多個代碼段,代碼段的屬性為隻讀。

— 零個或多個包含初始化資料的資料段,資料段的屬性為可讀寫。

— 零個或多個不包含初始化資料的資料段,資料段的屬性為可讀寫。

連結器根據系統預設或使用者設定的規則,将各個段安排在存儲器中的相應位置。是以源程式中段之間的相對位置與可執行的映象檔案中段的相對位置一般不會相同。

以下是一個彙編語言源程式的基本結構:

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僞指令定義一個段,并說明所定義段的相關屬性,本例定義一個名為Init的代碼段,屬性為隻讀。ENTRY僞指令辨別程式的入口點,接下來為指令序列,程式的末尾為END僞指令,該僞指令告訴編譯器源檔案的結束,每一個彙程式設計式段都必須有一條END僞指令,訓示代碼段的結束。

4.3.2 彙編語言的子程式調用

在ARM彙編語言程式中,子程式的調用一般是通過BL指令來實作的。在程式中,使用指令:BL 子程式名

即可完成子程式的調用。

該指令在執行時完成如下操作:将子程式的傳回位址存放在連接配接寄存器LR中,同時将程式計數器PC指向子程式的入口點,當子程式執行完畢需要傳回調用處時,隻需要将存放在LR中的傳回位址重新拷貝給程式計數器PC即可。在調用子程式的同時,也可以完成參數的傳遞和從子程式傳回運算的結果,通常可以使用寄存器R0~R3完成。

以下是使用BL指令調用子程式的彙編語言源程式的基本結構:

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

4.3.3 彙編語言程式示例

以下是一個基于S3C4510B的串行通訊程式,關于S3C4510B的串行通訊的工作原理,可以參考第六章的相關内容,在此僅向讀者說明一個完整彙編語言程式的基本結構:

Institute of Automation,Chinese Academy of Sciences

Description: This example shows the UART communication!

Author: JuGuang,Lee

Date:

UARTLCON0 EQU 0x3FFD000

UARTCONT0 EQU 0x3FFD004

UARTSTAT0 EQU 0x3FFD008

UTXBUF0 EQU 0x3FFD00C

UARTBRD0 EQU 0x3FFD014

AREA Init,CODE,READONLY

ENTRY

LED Display

LDR R1,=0x3FF5000

LDR R0,=&ff

STR R0,[R1]

LDR R1,=0x3FF5008

LDR R0,=&ff

STR R0,[R1]

UART0 line control register

LDR R1,=UARTLCON0

LDR R0,=0x03

STR R0,[R1]

UART0 control regiser

LDR R1,=UARTCONT0

LDR R0,=0x9

STR R0,[R1]

UART0 baud rate divisor regiser

Baudrate=19200,對應于50MHz的系統工作頻率

LDR R1,=UARTBRD0

LDR R0,=0x500

STR R0,[R1]

Print the messages!

LOOP

LDR R0,=Line1

BL PrintLine

LDR R0,=Line2

BL PrintLine

LDR R0,=Line3

BL PrintLine

LDR R0,=Line4

BL PrintLine

LDR R1,=0x7FFFFF

LOOP1

SUBS R1,R1,#1

BNE LOOP1

B LOOP

Print line

PrintLine

MOV R4,LR

MOV R5,R0

Line

LDRB R1,[R5],#1

AND R0,R1,#&FF

TST R0,#&FF

MOVEQ PC,R4

BL PutByte

B Line

PutByte

LDR R3,=UARTSTAT0

LDR R2,[R3]

TST R2,#&40

BEQ PutByte

LDR R3,=UTXBUF0

STR R0,[R3]

MOV PC,LR

Line1 DCB &A,&D,”********************************************************”,0

Line2 DCB &A,&D,”Chinese Academy of Sciences,Institute of Automation,Complex System Lab.”,0

Line3 DCB &A,&D,” ARM Development Board Based on Samsung ARM S3C4510B.”,0

Line4 DCB &A,&D,&A,&D,&A,&D,&A,&D,&A,&D,&A,&D,&A,&D,&A,&D,&A,&D,&A,&D,&A,&D,&A,&D,&A,&D,&A,&D,&A,&D,0

END

4.3.4 彙編語言與C/C++的混合程式設計

在應用系統的程式設計中,若所有的程式設計任務均用彙編語言來完成,其工作量是可想而知的,同時,不利于系統更新或應用軟體移植,事實上,ARM體系結構支援C/C+以及與彙編語言的混合程式設計,在一個完整的程式設計的中,除了初始化部分用彙編語言完成以外,其主要的程式設計任務一般都用C/C++ 完成。

彙編語言與C/C++的混合程式設計通常有以下幾種方式:

- 在C/C++代碼中嵌入彙編指令。

- 在彙程式設計式和C/C++的程式之間進行變量的互訪。

- 彙程式設計式、C/C++程式間的互相調用。

在以上的幾種混合程式設計技術中,必須遵守一定的調用規則,如實體寄存器的使用、參數的傳遞等,這對于初學者來說,無疑顯得過于煩瑣。在實際的程式設計應用中,使用較多的方式是:程式的初始化部分用彙編語言完成,然後用C/C++完成主要的程式設計任務,程式在執行時首先完成初始化過程,然後跳轉到C/C++程式代碼中,彙程式設計式和C/C++程式之間一般沒有參數的傳遞,也沒有頻繁的互相調用,是以,整個程式的結構顯得相對簡單,容易了解。以下是一個這種結構程式的基本示例,該程式基于第五、六章所描述的硬體平台:

Institute of Automation, Chinese Academy of Sciences

File Name: Init.s

Description:

Author: JuGuang,Lee

Date:

IMPORT Main ;通知編譯器該标号為一個外部标号

AREA Init,CODE,READONLY ;定義一個代碼段

ENTRY ;定義程式的入口點

LDR R0,=0x3FF0000 ;初始化系統配置寄存器,具體内容可參考第五、六章

LDR R1,=0xE7FFFF80

STR R1,[R0]

LDR SP,=0x3FE1000 ;初始化使用者堆棧,具體内容可參考第五、六章

BL Main ;跳轉到Main()函數處的C/C++代碼執行

END ;辨別彙程式設計式的結束

以上的程式段完成一些簡單的初始化,然後跳轉到Main()函數所辨別的C/C++代碼處執行主要的任務,此處的Main僅為一個标号,也可使用其他名稱,與C語言程式中的main()函數沒有關系。

/*********************************************************************

  • Institute of Automation, Chinese Academy of Sciences
  • File Name: main.c
  • Description: P0,P1 LED flash.
  • Author: JuGuang,Lee
  • Date:

********************************************************************/

void Main(void)

{

int i;

((volatile unsigned long ) 0x3ff5000) = 0x0000000f;

while(1)

{

((volatile unsigned long ) 0x3ff5008) = 0x00000001;

for(i=0; i<0x7fFFF; i++);

((volatile unsigned long ) 0x3ff5008) = 0x00000002;

for(i=0; i<0x7FFFF; i++);

}

}

4.4 本章小節

本章介紹了ARM程式設計的一些基本概念,以及在彙編語言程式設計中常見的僞指令、彙編語言的基本語句格式等,彙編語言程式的基本結構等,同時簡單介紹了C/C++和彙編語言的混合程式設計等問題,這些問題均為程式設計中的基本問題,希望讀者掌握,注意本章最後的兩個示例均與後面章節介紹的基于S3C4510B的硬體平台有關系,讀者可以參考第五、六章的相關内容。