天天看點

c語言中 僞指令,ARM彙編僞指令介紹(1)

ARM彙編僞指令介紹

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

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

1)其他常用的僞指令

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

— 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之間。

2)ARM雜項僞指令

1.ADR僞指令:小範圍的位址讀取僞指令。

ADR指令将基于PC相對偏移的位址值讀取到寄存器中。在彙編編譯源程式時,ADR僞指令被編譯器替換成一條合适的指令。通常編譯器用一條ADD指令或SUB指令來實作該ADR僞指令的功能。

指令格式:ADR{cond} register ,expr

Register加載的寄存器

Expr程式相對偏移或寄存器相對偏移的表達式

非字對齊位址在-255~255位元組範圍内;

字對齊位址在-1020~1020位元組範圍内。

舉例:

Start MOV R1,#10

ADR R4,start ;相當于PC-10後指派給R4

2.ADRL指令:中等範圍的位址讀取僞指令。

ADRL指令将基于PC相對偏移的位址值或基于相對偏移的位址值讀取到寄存器中,比ADR僞指令可讀取更大範圍的位址。在彙編編譯源程式時,ADRL僞指令被編譯器替換成兩條合适的指令。若不能用兩條指令實作ADRL僞指令功能,則産生錯誤,編譯失敗。

指令格式與ADR相同

非字對齊位址在64K位元組範圍内;

字對齊位址在256K位元組範圍内。

舉例:

Start MOV R1,#10

ADR R4,start+6000 ;=>ADD R4,PC,#0xe800 ADD R4,R4,#0x254

3.LDR指令 大範圍的位址讀取僞指令

LDR僞指令用于加載32位的立即數或一個位址值到指定寄存器。

在彙編編譯源程式時,LDR指令被編譯器替換成一條合适的指令,若加載的常數未超出MOV或MVN的範圍,則使用MOV或MVN指令代替該LDR僞指令,否則彙編器将常量放入字池(記憶體),并使用一條程式相對偏移的LDR指令從文字池讀出常量。

指令格式:LDR {cond} register , = expr/label_expr

Expr32位立即數

Label_expr基于PC的位址表達式或外部表達式

舉例

LDR R0,=0x123987;加載32位立即數

LDR R0,=DATA_BUF+60;加載DATA_BUF位址+60

4.NOP指令

NOP指令産生所需的ARM無操作代碼。可以使用指令MOV R0,R0。NOP不能有條件使用。執行和不執行無操作指令是一樣的,因而不需要有條件執行。ALU狀态不受NOP影響。

3)符号定義( Symbol Definit年ion)僞指令

符号定義僞指令用于定義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中通過該名稱通路寄存器清單。