1.彙編程序的基本組成
ARM彙編語言程序中,程序是以程序段爲單位組織代碼的。段是相對獨立的指令或者代碼序列,擁有特定的名稱。段的種類有代碼段、數據段和通用段,代碼段的內容爲執行代碼,數據段存放代碼運行時需要用到的數據,通用段不包含用戶代碼和數據,所有通用段共用一個空間。段使用AREA僞操作來定義,並且說明相關屬性,如
代碼段定義
AREA Init, CODE, READONLY
…
數據段定義
AREA Stack1,DATA,READWRITE,NOINIT,ALIGN=3
……
等
一個彙編程序至少應該有一個代碼段,可以有零或者多個數據段。在格式上,一個彙編程序需要至少有一個ENTRY(關於ENTRY具體內容看僞操作符ENTRY),還需要在彙編源文件結束處,寫上END表示該源文件的結束。
如一個基本的彙編源程序
AREA Init, CODE, READONLY ;定義一個代碼段
ENTRY ;標記程序入口點
Start LDRR0,0x3FF5000 ;標號Start可以要,也可以不要
LDR R1,0Xff
STR R1,[R0]
LDR R0,=0x3FF5000
LDR R1,0x01
STR R1,[R0]
……
END ;END僞操作表示本源文件結束
當彙編程序較長時,可以分割爲多個代碼段和多個數據段,多個段在程序編譯鏈接時,最終形成一個可執行的映像文件。一個可執行映像文件通常由以下幾部分組成
一個或者多個代碼段,代碼段屬性爲只讀(只讀數據也放在代碼段?RO)
零個或者多個初始化數據的數據段,可讀寫(存放初始化了的變量數據,RW)
零個或者多個不包含初始化數據的數據段,可讀寫(所有未初始化的變量,也就是ZI)
鏈接器根據系統默認或者用戶設定的規則,將各段安排在存儲器中的相應位置,因此源程序中段之間的相對位置與可執行映像文件中的段的相對位置一般不會相同。
2.彙編語句應該注意的地方
彙編語句格式
[LABEL] OPERATION, [OPERAND], [;COMMENT]
LABEL必須在一行的開頭寫。
OPERATION包括指令、僞操作、宏指令或僞指令。每一條操作助記符必須全部大寫或者全部小寫。在寫操作助記符前,必須有空格。
OPERAND 表示操作的對象,可以使常量、變量、標號、寄存器或者表達式,不同的對象之間必須用逗號分開。
例子:
AREA EX2,CODE,READONLY ;操作助記符前面必須有空格
GBLA DATA ;操作助記符前面必須有空格
DATA SETA,0x20 ;變量名DATA前面不能留空格
ADD R0,R1,R2
ADD R0,R1,r2
add R0,R1,r2
Add R0,R1,r2 ;寄存器小寫正確,指令助記符大小寫混合錯誤
3.常用符號
彙編語言中,經常使用各種符號表示變量、常量和地址。
變量的定義:使用僞操作GBLA、GBLL、GBLS,分別是定義全局的數值變量、邏輯變量和字符變量;LCLA、LCLL、LCLS定義局部的數值變量、邏輯變量和字符變量。相應的變量使用SETA、SETL、SETS來進行賦值。注意字符串長度不應超過512個字節。
例子:
GBLA DATA
DATA SETA0x20
LCLS str1
str1 SETS “PEN”
LCLL lc
lc SETL {TRUE}
常量是在運行過程中不能改變的量。ARM支持數值常量、邏輯常量和字符串常量。彙編中使用EQU來定義一個數值常量,如
Test EQU 10; 定義標號Test的值爲20.
Addr EQU 0x55,CODE32;
關於EQU的具體使用,看僞操作EQU。
數值常量一般爲32爲的整數,可以使十進制、十六進制,也可以是n進制(n=2~9)如8_247是一個八進制數。
4.常見的僞操作符
符號定義僞操作
GBLA、GBLL、GBLS
LCLA、LCLL、LCLS
SETA、SETL、SETS
RLIST
其中RLIST用來定義通用寄存器列表名稱,使用該僞操作定義的名稱可以在ARM指令LDM/STM中使用。在LDM/STM中,訪問列表中的寄存器次序爲寄存器編號由低到高的順序。如
RegList RLIST {r0-r5,r8,r10}; 將寄存器列表名稱定義爲RegList
在程序中使用
STMFD SP!, RegList ;存儲列表到堆棧
LDMIA R5, RegList ; 加載列表
數據定義僞操作
DCB 分配一片連續的字節存儲單元並初始化
DCW(DCWU) 分配一片連續的半字存儲單元並初始化
DCD(DCDU) 分配一片連續的字存儲單元並初始化
DCDO、DCI、DCQ(DCQU)
DCFS(DCFSU) 爲單精度浮點數分配一片連續的字存儲單元並初始化
DCFD(DCFDU) 爲雙精度浮點數分配一片連續的字存儲單元並初始化
SPACE 分配一片連續的存儲單元
FIELD、MAP、LTORG
如:
Str DCB “this is a test” ;分配一片連續的字節存儲單元並初始化
Data DCW 1,2,3 ;分配一片連續的半字存儲單元並初始化
Data DCD 4,5,6 ; 分配一片連續的字存儲單元並初始化
Fdata DCFS 2e5,-5e-7 ;分配一片連續的字存儲單元並初始化爲指定的單精度數
Dspce SPACE 100 ;分配連續100字節的存儲單元並初始化爲0
控制僞操作
IF ELSE ENDIF
WHILE WEND
MACRO MEND;MEXIT
信息報告僞操作
ASSERT
INFO
OPT
其他常用僞操作
AREA ALIGN CODE16/CODE32 ENTRY END EQU EXPORT(GLOBLE) IMPORT EXTERNGET(INCLUDE) INCBIN RN ROUT
AREA
格式:AREA 段名 屬性1,屬性2,……
常用屬性有:
CODE :用於定義代碼段,默認爲READONLY
DATA: 定義數據段,默認爲READWRITE
READONLY: 指定本段爲只讀
READWRITE: 指定本段爲讀寫
ALIGN:使用方式爲ALIGN表達式。在默認時,ELF(可執行鏈接文件)的代碼段和數據段是按字對齊的。表達式的取值範圍爲0~31,相應的對齊方式爲2次冪。
COMMON: 定義一個通用的段,不包含任何用戶的代碼和數據。各源文件中同名的COMMON段共享同一段存儲單元。
ALIGN
格式:ALIGN [表達式[,偏移量]]
ALIGN僞操作可通過添加填充字節的方式,使當前位置滿足一定的對齊方式。
例:
……
DATA1 DCB “STRIN” ; 定義後不能保證地址對齊
ALIGN 4 ;確保當前地址是4字節對齊
……
例:
AREA Cache, CODE, ALIGN=3 ; 指定本代碼段的指令時23=8字節對齊的
……
MOV PC, LR ;程序跳轉後是4字節對齊,返回後需要繼續8字節對齊
ALIGN 8 ;當前位置再次滿足8字節對齊
……
注意上面,在AREA中使用和單獨使用ALIGN的區別,格式和計算方式不一樣。
ENTRY
用於指定彙編程序的入口點。一個程序可以由一個或者多個源文件組成,一個源文件由一個或者多個程序段組成。一個程序至少有一個入口點,也可有多個入口點,但是在一個源文件中,最多只能有一個ENTRY。當有多個ENTRY時,程序的真正入口點由鏈接器指定。編譯程序在編譯連接時根據程序入口點進行連接。在只有一個入口點時,編譯程序會把這個入口點的地址定義爲系統復位後的程序起始點。
END
在源文件結束處寫上,表示源程序的結尾。
EXPORT
格式:EXPORT 標號 [,WEAK]
聲明一個全局標號,該標號在其他文件中可引用。WEAK表示碰上其他同名標號時,其他標號優先。
AREA INIT, CODE, READONLY
EXPORT Stest
……
END
IMPORT
格式:IMPORT 標號 [,WEAK]
表示該引用的標號在其他源文件中,但要在當前文件中引用。WEAK表示找不到該標號時,也不報錯,一般講該標號值置爲0,如果是B或者BL使用到,則該指令置爲NOP。
與EXTERN的不同的是,無論當前文件是否引用該標號,該標號都被加入當前源文件的符號表中。
AREA INIT, CODE, READONLY
IMPORT MAIN;
……
END
EXTERN
和IMPORT一樣,不同之處在於,如果當前文件沒有引用該標號,該標號不會加入當前源文件的符號表中。
GET(或INCLUDE)
將一個源文件包含到當前的源文件中,並在當前位置進行編譯。
AREA INIT, CODE, READONLY
GET a1.s
GET C:/a2.s
……
END
INCBIN
將一個目標文件或者數據文件包含到當前,文件內容被原封不動的放在當前位置,編譯器不對文件內容進行編譯。
AREA INIT, CODE, READONLY
GET a1.s ; 包含a1.s並且對a1.s進行編譯
INCBIN C:/d.txt ; 包含d.txt,不對內容進行編譯
GET a2.s ; 包含a2.s,並對內容進行編譯
END
RN
給一個寄存器定義一個別名。
Temp RN, R0 ; 將R0定義一個別名 Temp