ARM匯編常見偽指令及其用法示例

偽指令不是指令,偽指令和指令的根本區別是經過編譯后會不會生成機器碼。 偽指令的意義在于指導編譯過程。 偽指令是和具體的編譯器相關的,我們使用gnu工具鏈,因此學習gnu環境下的匯編偽指令。

在 ARM 匯編中,偽指令(Pseudoinstruction)由匯編器解析,用于輔助程序編寫(如定義數據、劃分段、設置對齊等),不直接生成機器碼。以下是常用偽指令及其用法示例:

一、數據定義偽指令

用于在內存中定義數據(如整數、字符串、數組等)。

1.?.byte

定義8 位整數(1 字節),可跟多個值,用逗號分隔。

.data
byte1: .byte 0x10          ; 定義1字節數據0x10
byte2: .byte 0x20, 0x30    ; 連續定義兩個字節:0x20、0x30

2.?.half?/?.short

定義16 位整數(2 字節),兩者功能相同。

.data
half1: .half 0x1234        ; 定義2字節數據0x1234
half2: .short 0x5678       ; 等價于.half,定義0x5678

3.?.word?/?.int

定義32 位整數(4 字節),ARM 架構中最常用的數據定義偽指令。

.data
word1: .word 0x12345678    ; 定義4字節數據0x12345678
array: .word 1, 2, 3       ; 定義32位整數數組:1、2、3(占12字節)

4.?.quad?/?.long

定義64 位整數(8 字節),適用于支持 64 位的 ARM 架構(如 ARMv8)。

.data
quad1: .quad 0x1122334455667788  ; 定義8字節數據

5.?.asciz?/?.ascii

  • .asciz:定義以 null 結尾的字符串(C 風格字符串,自動添加\0)。
  • .ascii:定義字符串,不自動添加 null 結尾
.data
str1: .asciz "Hello"       ; 存儲 'H','e','l','l','o','\0'(6字節)
str2: .ascii "ARM"         ; 存儲 'A','R','M'(3字節,無結束符)

6.?.space?/?.fill

  • .space n:分配n 字節的未初始化空間
  • .fill n, size, val:重復填充 n 次,每次填充 size 字節,值為 val(size 通常為 1、2、4)。
.data
buf: .space 100            ; 分配100字節緩沖區
arr: .fill 5, 4, 0x1234    ; 填充5個4字節數據,每個值為0x1234(共20字節)

更多待補充

數據只能在.data段下定義嗎??

在 ARM 匯編中,數據并非只能在.data段中定義,不同類型的數據適合放在不同的段中,常見的段包括.data.bss.rodata等,各自有不同的用途和特性。

1.?.data段:初始化的讀寫數據

  • 用途:存放已初始化且需要修改的數據(如變量、數組等)。
  • 特點:數據會被存儲在可執行文件中,加載到內存后可讀寫。
  • 示例
    .data
    count: .word 100         ; 初始化的整數(可修改)
    buffer: .byte 0x01, 0x02 ; 初始化的字節數組(可修改)
    

2.?.bss段:未初始化或零初始化數據

  • 用途:存放未初始化初始值為 0的數據(如緩沖區、大數組等)。
  • 特點
    • 不占用可執行文件的空間(僅記錄需要分配的大小)。
    • 程序加載時由系統自動初始化為 0。
    • 適合存儲大容量數據(節省文件大小)。
  • 示例
    .bss
    big_buffer: .space 1024  ; 1024字節未初始化緩沖區(自動初始化為0)
    temp_var: .word 0        ; 初始值為0的變量(等效于未初始化)
    

3.?.rodata段:只讀數據

  • 用途:存放初始化后不需要修改的數據(如常量、字符串字面量等)。
  • 特點
    • 數據會被存儲在可執行文件中。
    • 加載到內存后處于只讀區域(修改會觸發錯誤)。
    • 提高安全性,適合保護常量數據。
  • 示例
    .rodata
    PI: .word 0x4048F5C3     ; 浮點數π的32位表示(只讀)
    msg: .asciz "Hello"      ; 只讀字符串(不可修改)
    

4. 自定義段(.section)

通過.section偽指令可創建自定義段,用于特殊用途(如硬件相關數據、特定內存區域的數據等)。

示例:定義一個用于硬件寄存器映射的數據段

.section .hw_regs, "aw"  ; "a"=可分配, "w"=可寫
uart_base: .word 0x12340000  ; UART寄存器基地址(自定義段數據)

總結:如何選擇段?

數據類型推薦段原因
已初始化且需要修改.data可讀寫,數據存儲在文件中
未初始化或初始值為 0.bss不占文件空間,自動初始化為 0
初始化后不需要修改.rodata只讀保護,防止意外修改
特殊用途(如硬件相關)自定義段靈活控制段屬性和內存布局

合理劃分數據段可以優化程序的內存使用效率,并提高代碼的安全性和可維護性。

如何訪問數據

用偽指令定義數據后,怎么訪問這個數據?

在 ARM 匯編中,訪問用偽指令定義的數據通常需要通過標號(Label)?獲取數據地址,再結合加載 / 存儲指令(如LDRSTR)訪問數據。具體方法取決于數據的類型和位置,以下是常見場景及示例:

一、訪問數據段中的初始化數據

假設已用偽指令在.data段定義數據,通過標號獲取地址后,用LDR(加載)指令讀取數據到寄存器。

示例 1:訪問 32 位整數(.word 定義)

.data
; 用偽指令定義數據并標記標號
num: .word 0x12345678    ; 32位數據,地址由標號num標識.text
.global main
main:; 步驟1:將數據地址加載到寄存器(用LDR =標號)LDR R0, =num         ; R0 = num的地址(0x...); 步驟2:從地址加載數據到寄存器(用LDR 寄存器, [地址寄存器])LDR R1, [R0]         ; R1 = 內存[R0] = 0x12345678; 后續操作(例如修改數據后存回)ADD R1, R1, #1       ; R1 = 0x12345679STR R1, [R0]         ; 內存[R0] = R1(更新數據); 程序結束MOV PC, LR

示例 2:訪問字符串(.asciz 定義)

字符串本質是字節數組,可通過地址逐個訪問字符:

.data
str: .asciz "Hello"      ; 字符串:'H','e','l','l','o','\0'.text
main:LDR R0, =str         ; R0 = 字符串首地址; 訪問第一個字符(H的ASCII碼為0x48)LDRB R1, [R0]        ; R1 = 0x48(LDRB:加載字節,自動零擴展); 訪問第二個字符(e的ASCII碼為0x65)LDRB R2, [R0, #1]    ; R2 = 0x65(地址偏移+1字節)MOV PC, LR

二、訪問數組數據(多個連續元素)

對于.word.byte等定義的數組,通過地址 + 偏移量訪問元素:

.data
arr: .word 10, 20, 30, 40  ; 32位整數數組(每個元素4字節).text
main:LDR R0, =arr           ; R0 = 數組首地址; 訪問第1個元素(索引0):10LDR R1, [R0]           ; R1 = 10; 訪問第2個元素(索引1):20(偏移4字節)LDR R2, [R0, #4]       ; R2 = 20; 訪問第3個元素(索引2):30(用寄存器偏移)MOV R3, #8LDR R4, [R0, R3]       ; R4 = 30MOV PC, LR

三、訪問.bss 段的未初始化數據

.bss段數據僅分配空間(初始值為 0),訪問方式與.data段相同:

.bss
buf: .space 16            ; 16字節未初始化緩沖區.text
main:LDR R0, =buf          ; R0 = 緩沖區首地址; 向緩沖區第1個字節寫入0x55MOV R1, #0x55STRB R1, [R0]         ; STRB:存儲字節; 向緩沖區第5個字節(偏移4)寫入0xAAMOV R2, #0xAASTRB R2, [R0, #4]MOV PC, LR

四、關鍵指令總結

指令用途示例
LDR Rn, =label將標號地址加載到寄存器LDR R0, =num
LDR Rd, [Rn]從 Rn 指向的地址加載 32 位數據LDR R1, [R0]
LDRB Rd, [Rn]從 Rn 指向的地址加載 8 位數據LDRB R1, [R0]
LDRH Rd, [Rn]從 Rn 指向的地址加載 16 位數據LDRH R1, [R0]
STR Rd, [Rn]將 32 位數據存儲到 Rn 指向的地址STR R1, [R0]
STRB Rd, [Rn]將 8 位數據存儲到 Rn 指向的地址STRB R1, [R0]
STRH Rd, [Rn]將 16 位數據存儲到 Rn 指向的地址STRH R1, [R0]

核心邏輯

  1. 獲取地址:用?LDR Rn, =label?將數據標號的地址加載到寄存器(Rn)。
  2. 訪問數據:根據數據寬度(8/16/32 位),用?LDR/STR?及其變體(LDRB/STRB等),通過地址寄存器(Rn)讀寫內存。

這種方式依賴匯編器對地址的解析和鏈接器的地址分配,最終實現對偽指令定義數據的訪問。

二、段定義偽指令

用于劃分程序的不同段(代碼段、數據段等),便于內存管理。

1.?.text

定義代碼段(存放可執行指令),是程序的默認段。

.text               ; 進入代碼段
start:MOV R0, #0      ; 指令存放于此段

2.?.data

定義數據段(存放初始化的數據)。

.data               ; 進入數據段
var: .word 0x1234   ; 初始化數據存放于此段

3.?.bss

定義未初始化數據段(僅分配空間,初始值為 0),節省可執行文件大小。

.bss                ; 進入未初始化數據段
buf: .space 200     ; 200字節緩沖區(初始為0)

4.?.section

自定義段(靈活劃分特殊用途的段,如中斷向量表)。

.section .vector, "a"  ; 定義名為.vector的段,"a"表示可分配
reset:B start            ; 中斷向量表中的復位向量

更多待補充

三、符號與地址偽指令

用于聲明符號可見性、加載地址等。

1.?.global?/?.extern

  • .global sym:聲明 sym 為全局符號(可被其他文件引用)。
  • .extern sym:聲明 sym 為外部符號(在其他文件中定義)。
.global main         ; 聲明main為全局符號(供鏈接器識別)
.extern printf       ; 聲明printf為外部符號(來自C庫)

2.?.equ

定義符號常量(類似 C 中的#define),便于代碼維護。

.equ MAX_LEN, 100    ; 定義常量MAX_LEN=100
.equ PI, 3.14        ; 也可定義浮點數(匯編器支持時).text
start:MOV R1, #MAX_LEN ; 使用常量

3.?=label(地址加載偽指令)

配合LDR指令,將標號的絕對地址加載到寄存器(實際會被匯編器轉換為合適的指令)。

.data
msg: .asciz "Hello".text
main:LDR R0, =msg     ; 將msg的地址加載到R0(等價于加載絕對地址)LDR R1, =0x12345678  ; 加載32位立即數(超出MOV指令范圍時用)

更多待補充

四、對齊與定位偽指令?

用于控制數據或指令在內存中的對齊方式(提高訪問效率)。

1.?.align n

使當前地址對齊到2^n字節邊界(n 通常為 0~3,對應 1、2、4、8 字節對齊)。

.data
.align 2            ; 對齊到4字節邊界(2^2=4)
val: .word 0x1234   ; val的地址必為4的倍數

2.?.org addr

強制將當前地址設置為addr(常用于固定地址初始化,如硬件寄存器)。

.org 0x40000000     ; 強制當前地址為0x40000000(假設為UART寄存器地址)
uart_tx: .word 0    ; uart_tx的地址固定為0x40000000

更多待補充

五、其他常用偽指令

1.?.end

標記程序結束,匯編器遇到此指令后停止處理。

.text
start:MOV PC, LR
.end                ; 程序結束

2.?.include

包含其他匯編文件(類似 C 的#include),便于代碼復用。

.include "common.s"  ; 包含common.s文件中的代碼

3.?.thumb?/?.arm

切換指令集:.thumb進入 Thumb 模式(16/32 位指令),.arm進入 ARM 模式(32 位指令)。

.arm                ; 使用ARM指令集
MOV R0, #1.thumb              ; 切換到Thumb指令集
MOV R1, #2

更多待補充?

總結?

偽指令是 ARM 匯編的 “輔助工具”,核心作用是:

  • 定義數據(.word.asciz等);
  • 劃分內存段(.text.data等);
  • 控制符號與地址(.global=label等);
  • 優化內存對齊(.align)。

靈活使用偽指令可使匯編代碼更清晰、易維護,同時適配不同的硬件和內存布局需求。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/90235.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/90235.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/90235.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

算法調試技巧

引言算法調試常比編寫更耗時,尤其是動態規劃、遞歸等邏輯復雜的代碼。本文分享一套系統化的調試方法,幫助快速定位問題。一、調試前的準備代碼格式化使用統一縮進(4 空格)和命名規范,避免因格式混亂導致的邏輯誤讀。邊…

每日功能分享|讓觀看者體驗“無縫鏈接”觀看的功能——視頻自動續播功能

你是否遇到過這樣的困擾——看到一半的視頻,關閉后卻忘記進度,再打開時需要手動拖拽尋找上次的觀看位置?如今,“視頻自動續播功能”完美解決了這一痛點!無論是在線教育課程、影視劇集還是企業內部員工培訓,…

AWS: 云上偵探手冊,七步排查ALB與EC2連接疑云

今天,咱們來聊一個對于許多剛接觸AWS的運維同學來說,既常見又有點頭疼的話題:如何優雅地排查和解決AWS上ALB(Application Load Balancer)暴露EC2服務時遇到的種種疑難雜癥。 最近,我剛幫一個朋友解決了類似…

EIDE 創建基于STM32-HD的項目快速創建流程

EIDE 創建基于STM32-HD的項目流程芯片系列定義宏Flash 大小RAM 大小STM32F10x_HD#define STM32F10X_HD256KB~512KB48KB~64KBSTM32F10x_MD#define STM32F10X_MD64KB~128KB20KBSTM32F10x_LD#define STM32F10X_LD16KB~32KB4KB~10KB 新建項目遠程倉庫獲取裸機開發程序STM(意法半導體…

使用 QLExpress 構建靈活可擴展的業務規則引擎

目錄 一、什么是 QLExpress? 二、推薦系統中的規則腳本應用 1 場景描述 2 推薦規則腳本(QLExpress) 3 系統實現 4 執行結果 5 推薦系統應用建議 三、風控系統中的規則判定 1 場景描述 2 風控規則腳本(QLExpress&#xff…

【硬件-筆試面試題】硬件/電子工程師,筆試面試題-13,(知識點:DC-DC電源,相位裕度,增益裕度)

目錄 1、題目 2、解答 相位裕度 增益裕度 3、相關知識點 一、波特圖 二、相位裕度 三、增益裕度 四、在 DC - DC 電源中的應用 【硬件-筆試面試題】硬件/電子工程師,筆試面試題匯總版,持續更新學習,加油!!&a…

學生信息管理系統 - HTML實現增刪改查

學生信息管理系統 - HTML實現增刪改查 效果圖 代碼 <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><titl…

Agile簡介

Agile&#xff08;敏捷&#xff09;是一種軟件開發方法論&#xff0c;核心是通過快速迭代、靈活響應變化&#xff0c;解決傳統軟件開發中周期長、需求變更困難等問題&#xff0c;最終高效交付符合用戶實際需求的產品。 一、Agile 的起源&#xff1a;為什么需要敏捷&#xff1f;…

關于 URL 中 “+“ 號變成空格的問題

當你在 URL 中傳遞參數時&#xff0c;加號 () 會被自動轉換為空格&#xff0c;這是 URL 編碼的標準行為。問題原因在 URL 中&#xff1a;空格會被編碼為 號當 URL 被解碼時&#xff0c; 號又會被轉換回空格這會導致原始數據中的 號丟失解決方案你需要對參數值進行正確的 URL …

綜合實驗(2)

文章目錄 目錄 文章目錄 前言 OSPF運行在GRE隧道概述 典型應用場景 OSPF over GRE 配置 總結 前言 OSPF運行在GRE隧道概述 GRE&#xff08;Generic Routing Encapsulation&#xff09;隧道是一種通過封裝原始數據包在IP網絡中創建虛擬點對點連接的隧道技術。OSPF&#xff08;…

【應急響應工具教程】司稽(Whoamifuck):純Shell打造的Linux應急響應利器

1、工具簡介司稽&#xff08;Whoamifuck或Chief-Inspector,簡稱"who"&#xff09;&#xff0c;永恒之鋒發布的第一款開源工具&#xff0c;這是一款由shell編寫的Linux應急響應腳本&#xff0c;能對基本的檢查項進行輸出和分析&#xff0c;并支持一些擴展的特色功能。…

新手操作steam搬磚項目,應該如何快速起步

大家好哦&#xff0c;我是阿陽&#xff0c;今天繼續給大家分享一些steam搬磚的知識。在我們操作過程中&#xff0c;問題問得最多的就是&#xff0c;新手應該怎么做&#xff1f;首先&#xff0c;那我們得先來了解-下,什么是steam搬磚,它的項目原理是什么&#xff0c;其次針對于這…

rt-thread加一個庫

背景 官方軟件包里沒有的 可以以庫或組件形式加入 本次僅為了驗證&#xff0c;加到庫 過程 下載源碼 假設為 lib_demo 自己的板子目錄為bsp/stm32 代碼目錄結構 bsp/stm32librarieslib_demo //新建文件夾src //把lib_demo里源碼文件放進來inc //把lib_demo里頭文件放進來SConsc…

c++深拷貝和淺拷貝

一、淺拷貝本質&#xff1a;簡單地復制對象的成員值。如果成員里有指針&#xff0c;新對象和原對象的指針會指向同一塊內存。比如你有對象 A&#xff0c;里面指針 p 指向堆內存 0x123&#xff1b;用 A 拷貝出對象 B&#xff0c;B 的指針 p 也指向 0x123。問題&#xff1a;若其中…

NineData新增SQL Server到MySQL復制鏈路,高效助力異構數據庫遷移

在實際的數據庫遷移工作中&#xff0c;異構庫之間的遷移常常被視為一項“高風險、高工作量、高復雜度”的挑戰任務。這不僅是一次數據庫切換&#xff0c;更是對系統穩定性、數據一致性、業務連續性和技術團隊耐力的全方位考驗。為解決企業在異構數據庫遷移中的痛點&#xff0c;…

字符串和對象的深拷貝和淺拷貝

字符串和對象的深拷貝和淺拷貝【一】基本介紹【1】淺拷貝【2】深拷貝【二】字符串的拷貝【1】字符串的 “淺拷貝”【2】字符串的 “深拷貝”【三】對象的拷貝【1】淺拷貝&#xff08;Shallow Copy&#xff09;【2】深拷貝&#xff08;Deep Copy&#xff09;【四】字符串和對象拷…

4.5 優化器中常見的梯度下降算法

梯度下降算法&#xff08;Gradient Descent&#xff09;的數學公式可以通過以下步驟嚴格表達&#xff1a;1. 基本梯度下降&#xff08;Batch Gradient Descent&#xff09; 目標&#xff1a;最小化損失函數L(θ)\mathcal{L}(\theta)L(θ)&#xff0c;其中 θ\thetaθ是模型參數…

AM1.5G AAA穩態太陽光模擬器特點

光譜匹配度AM1.5G AAA穩態太陽光模擬器的光譜分布嚴格匹配國際標準IEC 60904-9中的AM1.5G光譜&#xff08;波長范圍300-4000nm&#xff09;&#xff0c;確保與自然太陽光的偏差在25%以內&#xff08;AAA級標準&#xff09;。光譜匹配度通過精密濾光片和氙燈或LED組合光源實現&a…

OSPF開放式最短路徑優先

1OSPF簡介&#xff08;1&#xff09;OSPF英文全稱Open Shortest Path First (開放式最短路徑優先)&#xff08;2&#xff09;OSPF是IETF 開發的一種鏈路狀態路由協議&#xff0c;使用基于帶寬的度量值。&#xff08;3&#xff09;OSPF采用SPF算法計算路由&#xff0c;從算法上保…

Lua(模塊與包)

Lua 模塊的基本概念Lua 中的模塊是一個由函數、變量組成的代碼庫&#xff0c;通常保存在獨立的 .lua 文件中。模塊通過 return 語句導出其內容&#xff0c;供其他腳本調用。模塊化設計可以提高代碼復用性&#xff0c;便于管理。創建模塊模塊通常以 .lua 文件形式存在&#xff0…