ARM 汇编语言语法小解

ARM 汇编语言语法小解

📚 系列文章提示

本文来自《ARM汇编指令深入解析》系列教程。如果你想要:

  • 查找其他ARM汇编指令的讲解
  • 了解本系列的整体结构
  • 按顺序系统学习ARM汇编

请访问:系列导读与目录总览


文章目录

ARM汇编语言是一种低级编程语言,用于直接控制ARM处理器的操作。以下是ARM汇编语言的详细语法介绍:

一、基本架构特点

  1. RISC架构:精简指令集,大多数指令在一个时钟周期内执行
  2. 加载/存储架构:只有加载/存储指令可以访问内存,运算指令只操作寄存器
  3. 统一字长:大多数指令为32位(ARM模式)或16位(Thumb模式)
  4. 条件执行:几乎所有指令都可以条件执行

二、基本语法结构

1. 指令格式

复制代码
[label:] mnemonic [operands] [; comment]

示例

assembly 复制代码
start:          ; 标签
    MOV R0, #10 ; 将立即数10加载到R0
    ADD R1, R0, #5 ; R1 = R0 + 5

2. 程序组成

  • 指令:处理器执行的操作
  • 伪指令:汇编器指令,不生成机器码
  • 汇编器指示符:控制汇编过程的指令

三、寄存器

1. 通用寄存器(32位)

  • R0-R12:通用目的寄存器
  • R13 (SP):堆栈指针
  • R14 (LR):链接寄存器(保存返回地址)
  • R15 (PC):程序计数器

2. 特殊寄存器

  • CPSR :当前程序状态寄存器
    • N(负标志)、Z(零标志)、C(进位标志)、V(溢出标志)
    • 模式位、中断禁止位等

四、指令分类与语法

1. 数据处理指令

复制代码
OPcode{S}{cond} Rd, Rn, Operand2
  • S:可选,更新条件标志
  • cond:条件码(可选)
  • Rd:目标寄存器
  • Rn:第一操作数寄存器
  • Operand2:第二操作数(寄存器/立即数/移位寄存器)

常见指令

assembly 复制代码
MOV R0, #0x3F      ; 传送立即数
ADD R1, R2, R3     ; 加法:R1 = R2 + R3
SUB R4, R5, #10    ; 减法:R4 = R5 - 10
AND R0, R1, R2     ; 按位与
ORR R3, R4, #0xFF  ; 按位或
EOR R5, R6, R7     ; 按位异或
CMP R0, R1         ; 比较,设置标志位

2. 加载/存储指令

assembly 复制代码
LDR Rd, [Rn]           ; 从内存加载到寄存器
STR Rd, [Rn]           ; 从寄存器存储到内存
LDR Rd, [Rn, #offset]  ; 带偏移量的加载
LDMIA Rn!, {reglist}   ; 多寄存器加载
STMIA Rn!, {reglist}   ; 多寄存器存储

3. 分支指令

assembly 复制代码
B label        ; 无条件跳转
BL label       ; 带链接的跳转(用于函数调用)
BX Rn          ; 跳转到寄存器指定的地址
BEQ label      ; 相等时跳转(Z=1)
BNE label      ; 不相等时跳转(Z=0)

4. 移位操作

assembly 复制代码
LSL R0, R1, #2     ; 逻辑左移2位
LSR R2, R3, #4     ; 逻辑右移4位
ASR R4, R5, #1     ; 算术右移1位
ROR R6, R7, #8     ; 循环右移8位

五、寻址方式

1. 立即数寻址

assembly 复制代码
MOV R0, #0xFF      ; 立即数0xFF
ADD R1, R2, #100   ; 立即数100

2. 寄存器寻址

assembly 复制代码
ADD R0, R1, R2     ; R0 = R1 + R2
MOV R3, R4         ; R3 = R4

3. 寄存器间接寻址

assembly 复制代码
LDR R0, [R1]       ; R0 = memory[R1]
STR R2, [R3]       ; memory[R3] = R2

4. 基址加偏移寻址

assembly 复制代码
LDR R0, [R1, #4]     ; R0 = memory[R1 + 4]
LDR R0, [R1, R2]     ; R0 = memory[R1 + R2]
LDR R0, [R1, R2, LSL #2] ; R0 = memory[R1 + (R2 << 2)]

5. 前变址/后变址寻址

assembly 复制代码
LDR R0, [R1, #4]!    ; 前变址:R1 = R1 + 4, 然后加载
LDR R0, [R1], #4     ; 后变址:先加载,然后R1 = R1 + 4

六、条件执行

1. 条件码后缀

后缀 含义 条件标志
EQ 相等 Z=1
NE 不相等 Z=0
CS/HS 进位/无符号>= C=1
CC/LO 无进位/无符号< C=0
MI N=1
PL 正/零 N=0
VS 溢出 V=1
VC 无溢出 V=0
HI 无符号> C=1且Z=0
LS 无符号<= C=0或Z=1
GE 有符号>= N=V
LT 有符号< N!=V
GT 有符号> Z=0且N=V
LE 有符号<= Z=1或N!=V
AL 总是执行 任何

2. 条件执行示例

assembly 复制代码
CMP R0, R1      ; 比较R0和R1
ADDGT R2, R3, #1  ; 如果R0>R1,则执行
MOVLE R2, #0     ; 如果R0<=R1,则执行

七、伪指令和汇编器指示符

1. 常用伪指令

assembly 复制代码
ADR R0, label      ; 加载标签地址(小范围)
LDR R0, =label     ; 加载标签地址(大范围)
LDR R0, =0x12345678 ; 加载32位立即数
NOP                ; 空操作

2. 汇编器指示符

assembly 复制代码
.global _start     ; 声明全局符号
.section .text     ; 代码段开始
.align 2           ; 按4字节对齐
.arm               ; 使用ARM指令集
.thumb             ; 使用Thumb指令集
.word 0x12345678   ; 定义32位数据
.byte 0x12, 0x34   ; 定义字节数据
.ascii "Hello"     ; 定义ASCII字符串
.asciz "World"     ; 定义以null结尾的字符串
.equ MAX, 100      ; 定义常量

八、完整示例程序

assembly 复制代码
/* ARM汇编示例:计算1+2+...+10 */

.global _start      /* 全局入口点 */
.section .text      /* 代码段 */

_start:
    MOV R0, #0      /* 总和清零 */
    MOV R1, #1      /* 计数器从1开始 */
    MOV R2, #10     /* 最大值 */
    
loop:
    CMP R1, R2      /* 比较计数器和最大值 */
    BGT end         /* 如果R1>R2,跳转到结束 */
    ADD R0, R0, R1  /* 累加:R0 = R0 + R1 */
    ADD R1, R1, #1  /* 计数器加1 */
    B loop          /* 继续循环 */
    
end:
    /* 此时R0中存储着结果55 */
    
    /* 退出程序(Linux系统调用) */
    MOV R7, #1      /* 退出系统调用号 */
    MOV R0, #0      /* 返回码0 */
    SWI 0           /* 软中断 */
    
.section .data      /* 数据段 */
result: .word 0     /* 存储结果 */

九、ARM与Thumb模式

  1. ARM模式

    • 32位指令
    • 完整的指令集
    • 所有指令都可以条件执行
  2. Thumb模式

    • 16位指令(也有32位Thumb-2指令)
    • 代码密度更高
    • 有限的指令集
    • 只有分支指令可以条件执行
  3. 模式切换

assembly 复制代码
ADR R0, thumb_code+1
BX R0               ; 切换到Thumb模式
.thumb
thumb_code:
    MOV R0, #10     ; Thumb指令

十、注意事项

  1. 立即数限制:ARM立即数必须是8位位图循环移位得到的
  2. 对齐要求:ARM指令需要4字节对齐,数据访问也有对齐要求
  3. PC的特殊性:读取PC时返回当前指令地址+8(ARM模式)
  4. 寄存器使用约定:函数调用时通常使用R0-R3传递参数,R0保存返回值

十一、常用编程模式

  1. 函数调用
assembly 复制代码
/* 调用函数 */
BL function_name
/* ... */

/* 函数定义 */
function_name:
    PUSH {R4-R11, LR}  /* 保存寄存器和返回地址 */
    /* 函数体 */
    POP {R4-R11, PC}   /* 恢复寄存器并返回 */
  1. 堆栈操作
assembly 复制代码
PUSH {R0-R3, LR}   /* 压栈多个寄存器 */
POP {R0-R3, PC}    /* 出栈并返回 */

ARM汇编语言通过其丰富的指令集和灵活的条件执行机制,为底层系统编程提供了强大的控制能力。随着ARM架构的发展(如ARMv8-A的AArch64),语法有所变化,但基本概念保持了一致性。

相关推荐
森焱森6 小时前
嵌入式硬件工程师应知 白银快速分析报告
linux·c语言·arm开发·嵌入式硬件·去中心化
森G19 小时前
七、04ledc-sdk--------makefile有变化
linux·c语言·arm开发·c++·ubuntu
VekiSon1 天前
Linux内核驱动——杂项设备驱动与内核模块编译
linux·c语言·arm开发·嵌入式硬件
AI+程序员在路上1 天前
Nand Flash与EMMC区别及ARM开发板中的应用对比
arm开发
17(无规则自律)1 天前
深入浅出 Linux 内核模块,写一个内核版的 Hello World
linux·arm开发·嵌入式硬件
梁洪飞2 天前
内核的schedule和SMP多核处理器启动协议
linux·arm开发·嵌入式硬件·arm
代码游侠2 天前
学习笔记——Linux字符设备驱动
linux·运维·arm开发·嵌入式硬件·学习·架构
syseptember3 天前
Linux网络基础
linux·网络·arm开发
代码游侠3 天前
学习笔记——Linux字符设备驱动开发
linux·arm开发·驱动开发·单片机·嵌入式硬件·学习·算法
程序猿阿伟3 天前
《Apple Silicon与Windows on ARM:引擎原生构建与模拟层底层运作深度解析》
arm开发·windows