目錄
1.全局標號
1.1.使用方法
1.1.1.聲明全局標號
1.1.2.定義全局標號
1.1.3.引用全局標號
1.2.全局標號與局部標號的區別
1.3.注意事項
2.局部標號
2.1.使用方法
2.1.1.定義局部標號
2.1.2.跳轉引用
2.2.局部標號與全局標號的對比
2.3.注意事項
3.符號定義偽指令
3.1.變量與數據定義
3.1.1.定義字節 - DCB
3.1.2.定義字 - DCW
3.1.3.定義雙字 - DCD
3.2.內存分配與對齊
3.2.1.預留內存空間 - SPACE
3.2.2.內存對齊 - ALIGN
3.2.3.設置起始地址 - ORG
3.3.符號重定義與別名
3.3.1.定義常量 - EQU
3.3.2.定義變量 - SET
3.3.3.宏定義 - MACRO、MEND
3.4.代碼段與數據段控制
3.4.1.定義段 - AREA
3.5.外部符號引用
3.5.1.聲明外部符號 - IMPORT
3.5.2.導出符號 -?EXPORT
3.6. 注意事項
4.程序控制偽指令
4.1.程序入口 - ENTRY
4.2.程序結束 - END
5.條件編譯偽指令
1.全局標號
ARM 匯編中,全局標號是可在整個程序范圍內被引用的標識符,代表了內存中的一個特定地址,能夠指向代碼中的某條指令,也可以指向數據段里的某個數據項,全局標號通過 .global 或 .globl 偽指令來聲明,其作用如下:
-
跨文件引用:大型項目中,程序往往會被分割成多個源文件,全局標號能讓不同源文件之間相互引用特定的代碼或數據,從而實現模塊化編程。
-
鏈接器識別:鏈接器在將多個目標文件鏈接成一個可執行文件時,會利用全局標號來確定不同模塊之間的跳轉地址和數據引用,保證程序的正確執行。
1.1.使用方法
1.1.1.聲明全局標號
使用 .global 或 .globl 偽指令將一個標號 <label> 聲明為全局標號,語法如下:
@ 方式一:
.global <label>@ 方式二:
.globl <label>
1.1.2.定義全局標號
全局標號聲明后,就可以在代碼中定義它,例如,以下代碼定義了一個名為 _start 的全局標號,它通常作為程序的入口點:
@ 聲明全局標號 _start全局標號
.global _start@ _start 定義
_start:MOV R0, #1MOV R7, #1SWI 0
1.1.3.引用全局標號
在其他文件或代碼段中,可直接引用已經聲明的全局標號,例如,在另一個文件中調用上述代碼中的 _start 標號:
.extern _start @ 引用全局標號 _startB _start @ 跳轉至該全局標號處執行
其中 .extern 偽指令用于聲明外部全局標號,表示該標號在其他文件中定義
1.2.全局標號與局部標號的區別
-
作用域:
-
全局標號:作用域是整個程序,可以在任何文件或者代碼段中被引用。
-
局部標號:作用域僅限于當前文件或代碼段,不能在其他文件中被引用。
-
-
聲明方式:
-
全局標號:需要使用 .global 或 .globl 偽指令進行聲明。
-
局部標號:直接在代碼中定義,無需額外的聲明指令。
-
1.3.注意事項
-
命名沖突:使用全局標號時,要確保標號名稱在整個程序中是唯一的,避免出現命名沖突,否則,鏈接器在鏈接過程中會報錯。
-
標號類型:全局標號既可以指向代碼,也可以指向數據,在引用標號時,要明確其類型,確保正確使用。
-
鏈接順序:在鏈接多個目標文件時,鏈接器會按照指定的順序處理這些文件,要保證引用全局標號的文件在鏈接時能夠找到定義該標號的文件。
2.局部標號
ARM 匯編中,局部標號是一種僅在特定范圍內有效的標號,與全局標號相對。局部標號僅能在當前文件或代碼段內被引用,它代表內存中的一個特定地址,可指向代碼中的某條指令,也可指向數據段里的某個數據項,局部標號有如下特點:
-
作用域局限:局部標號的作用范圍僅限于定義它的文件或代碼段,在其他文件中無法引用,這使得局部標號具有較好的封裝性,能避免不同文件之間的標號命名沖突。
-
使用靈活:局部標號通常用于標記代碼中的臨時位置,比如循環的起始和結束位置、條件分支的跳轉點等,方便代碼的編寫和維護。
-
無需額外聲明:和全局標號不同,局部標號不需要使用 .global 或 .globl 偽指令聲明,直接在代碼中定義即可。
2.1.使用方法
2.1.1.定義局部標號
局部標號由標號名和一個 : 組成,以下代碼定義了一個名為 fun_1 的局部標號:
fun_1:MOV R0, #10CMP R0, #20BLE fun_1b ; 跳轉到標號 1 處(向后跳轉)
在這個例子中,fun_1 就是一個局部標號,fun_1b 表示向后跳轉到標號 fun_1 處。
2.1.2.跳轉引用
局部標號主要用于跳轉指令,通過指定標號和跳轉方向(向前或向后)實現代碼的跳轉
跳轉方向通過 f(forward,向前)或 b(backward,向后)指定,例如:
MOV R1, #0
fun_2:ADD R1, R1, #1CMP R1, #8BLT fun_2b ; 若 R1 < 8,向后跳轉到標號 fun_2 處繼續執行
上面的代碼中,當 R1 中的值小于 8 時,向后跳轉至標號 fun_2 處繼續執行
MOV R0, #15CMP R0, #8BGT fun_1f ; 如果 R0 大于 8,向前跳轉到標號 fun_3 處繼續執行MOV R1, #20
fun_3:ADD R2, R0, R1MOV R7, #1SWI 0 ; 退出程序
上面的代碼中,當 R0 中的值大于 8 時,向前跳轉至標號 fun_3 處繼續執行
2.2.局部標號與全局標號的對比
-
作用域:
-
全局標號:作用域是整個程序,可以在任何文件或代碼段中被引用。
-
局部標號:作用域僅限于當前文件或者代碼段,不能在其他文件中被引用。
-
-
聲明方式:
-
全局標號:需要使用 .global 或 .globl 偽指令進行聲明。
-
局部標號:直接在代碼中定義,無需額外的聲明指令。
-
-
使用場景:
-
全局標號:常用于定義程序的入口點、公共函數、全局變量等,方便不同文件之間的調用和引用。
-
局部標號:主要用于標記代碼中的臨時位置,如循環、分支等,方便代碼的控制和跳轉。
-
2.3.注意事項
-
標號重復使用:由于局部標號的作用域僅限于當前文件或代碼段,同一個局部標號可以在不同的代碼段中重復使用,但在同一個代碼段中不能重復定義。
-
跳轉方向:在使用局部標號進行跳轉時,要明確指定跳轉方向(f 或 b),否則可能會導致跳轉錯誤。
3.符號定義偽指令
在匯編中,如果要定義變量,則需要用到特定的符號定義偽指令,同時,匯編中也提供了一些偽指令用于修改變量的值或者實現類似 C 語言中宏定義 #define 的功能
3.1.變量與數據定義
3.1.1.定義字節 - DCB
-
作用:在內存中定義一個或多個字節(8 位)數據,可用于存儲字符、數值或二進制數據:
label: DCB value1, value2, ...
-
示例:
; 定義字符串(ASCII 碼)
message: DCB 'H', 'e', 'l', 'l', 'o', 0; 定義數值數組
data_array: DCB 10, 20, 30, 40, 50; 定義二進制數據
flags: DCB 0x01, 0x02, 0x04, 0x08
3.1.2.定義字 - DCW
-
作用:定義 16 位數據(半字),常用于存儲短整數或 16 位常量:
label: DCW value1, value2, ...
-
示例:
; 定義 16 位整數數組
short_nums: DCW 1000, 2000, 3000; 定義 16 位常量
max_value: DCW 0xFFFF
3.1.3.定義雙字 - DCD
-
作用:定義 32 位數據(雙字),常用于存儲整數、地址或指針:
label: DCD value1, value2, ...
-
示例:
; 定義 32 位整數數組
int_array: DCD 1, 2, 3, 4, 5; 定義地址常量
device_addr: DCD 0x40000000; 定義函數指針
func_ptr: DCD my_function ; 指向 my_function 函數的地址
3.2.內存分配與對齊
3.2.1.預留內存空間 - SPACE
-
作用:在內存中預留指定字節數的未初始化空間,常用于創建緩沖區:
label: SPACE size_in_bytes
-
示例:
; 預留 100 字節的緩沖區
buffer: SPACE 100; 預留 4 字節空間(初始值未定義)
temp_var: SPACE 4
3.2.2.內存對齊 - ALIGN
-
作用:強制后續代碼或數據按指定字節對齊(如 2、4、8 字節),優化內存訪問效率:
.ALIGN alignment ; alignment 為 2 的冪(如 2、4、8)
-
示例:
; 按 4 字節對齊(地址為 4 的倍數)
.ALIGN 4
my_table: DCD 1, 2, 3, 4 ; 確保起始地址是 4 的倍數
3.2.3.設置起始地址 - ORG
-
作用:指定后續代碼或數據在內存中的起始地址,用于定位特定區域:
ORG 0x10000 ; 從地址 0x10000 開始放置數據
config_data:DCB 0x01, 0x02 ; 配置數據將位于 0x10000
3.3.符號重定義與別名
3.3.1.定義常量 - EQU
-
作用:為常量或表達式定義符號名,類似 C 語言的 #define:
symbol EQU expression
-
示例:
; 定義數值常量
MAX_SIZE EQU 100
TIMEOUT EQU 5000; 定義寄存器別名
GPIO_BASE EQU 0x40020000
LED_PIN EQU 5; 使用表達式
DELAY_VAL EQU MAX_SIZE * 2
3.3.2.定義變量 - SET
-
作用:定義可修改的符號值,類似變量,但在匯編時確定具體值:
symbol SET expression
-
示例:
count SET 0 ; 初始值為 0
count SET count+1 ; 遞增(匯編時計算)
3.3.3.宏定義 - MACRO、MEND
-
作用:定義可復用的代碼片段,類似函數但在匯編時展開:
MACRO
$label macro_name $param1, $param2... ; 宏體(使用 $param1 等參數)
MEND
-
示例:
MACRO
$label DELAY $countMOV r0, #$count
delay_loop:SUBS r0, r0, #1BNE delay_loop
MEND; 使用宏
DELAY 100 ; 插入 100 次循環的延遲代碼
3.4.代碼段與數據段控制
3.4.1.定義段 - AREA
-
作用:將代碼或數據分組到不同的內存區域(如 .text、.data、.bss):
AREA name, attributes
-
示例:
; 代碼段(只讀、可執行)
AREA my_code, CODE, READONLY
ENTRY ; 程序入口點
MOV r0, #1 ; 代碼指令; 數據段(已初始化數據)
AREA my_data, DATA, READWRITE
my_variable DCD 100 ; 初始值為 100; BSS 段(未初始化數據,僅占位)
AREA my_bss, NOINIT, READWRITE
buffer SPACE 1024 ; 預留 1024 字節未初始化空間
3.5.外部符號引用
3.5.1.聲明外部符號 - IMPORT
-
作用:聲明當前文件中使用的、但定義在其他文件中的符號(如函數、變量):
IMPORT printf ; 聲明 printf 函數在其他文件中定義...LDR r0, =messageBL printf ; 調用外部函數
3.5.2.導出符號 -?EXPORT
-
作用:聲明當前文件中定義的符號可被其他文件引用(類似 C 語言的 extern):
EXPORT my_function ; 導出函數供其他文件使用
my_function:...
3.6. 注意事項
-
符號作用域:在 AREA 內定義的符號僅在該區域可見,跨區域需使用全局聲明(如 .global)。
-
對齊要求:某些架構(如 ARM)要求特定類型的訪問(如 32 位數據)必須按 4 字節對齊,否則會觸發異常。
-
匯編時計算:EQU 和 SET 的值在匯編時確定,無法在運行時修改。
4.程序控制偽指令
4.1.程序入口 - ENTRY
偽指令 ENTRY 標記程序的起始執行地址,通常位于 .text 段:
AREA MyCode, CODE, READONLY
ENTRY ; 程序從此處開始執行B main ; 跳轉到主函數
4.2.程序結束 - END
程序結束偽指令 END 標記匯編程序結束,告訴匯編器停止處理后續代碼:
END
5.條件編譯偽指令
IF、ELSE、ENDIF 使程序可以根據條件選擇性地包含或排除代碼段,類似 C 語言的 #ifdef:
IF :DEF: DEBUG ; 如果定義了 DEBUG 符號MOV r0, #1 ; 執行這段代碼
ELSEMOV r0, #0 ; 若程序中未定義 DEBUG 符號則執行這段代碼
ENDIF