ARM 汇编学习

发布于:2025-09-11 ⋅ 阅读:(17) ⋅ 点赞:(0)

一、立即数

1. 立即数的三个判断条件(以 12 为例)

ARM 的立即数并非任意数,而是通过 8 位数 + 偶数位旋转组合得到。

判断规则:

  1. 如果数值范围在 0 ~ 0xFF 之间,一定是立即数;

  2. 把数写成二进制,从 最高位 1 到最低位 1 的位数不能超过 8 位;

  3. 凑够 8 位之后,其右边必须是 偶数个连续 0

例如:

#255 是立即数

#0x80000000  也是立即数

#0x12345678 不是立即数

二、跳转与函数调用

1. B 指令

功能:无条件跳转,相当于 C 的 goto

本质:把目标地址装入 PC。

B loop
; 等价于
LDR PC, =loop

补充:B 指令也可用于函数调用。

2. BL 指令

功能:跳转并保存返回地址(下一条指令)到 LR。

区别:与 B 的区别就是 BL 会在 LR 中保存返回地址。

作用:函数调用。

3. BX 指令

功能:跳转到寄存器地址。

常用BX LR 实现函数返回。

补充:可实现 ARM ↔ Thumb 状态切换(取决于地址最低位)。

三、栈(Stack)

1. 引入

函数调用会修改 R0、R1 以及 LR;嵌套调用时,LR 会丢失,无法回到正确位置。必须使用栈来保护现场、恢复现场。

2. 栈的四种方式

ARM 的栈操作方式:

空增:先写入数据,再 SP++

空减:先写入数据,再 SP--

满增:先 SP++,再写入数据

满减:先 SP--,再写入数据

ARM 体系采用 满减栈

3. 栈初始化示例(S3C2440)

内部 RAM 大小 4KB,地址范围 [0x40000000~0x40000FFF]

LDR SP, =0x40001000   ; 设置栈底

4. 栈操作指令

入栈保护现场

STMFD SP!, {R0, R1, R2, R3-R12, LR}

出栈恢复现场

LDMFD SP!, {R0, R1, R2, R3-R12, LR}

四、数据传送指令

1. LDR(加载寄存器)

  1. 指令

    LDR R0, =0x2FAB4
    

    多用于加载常数。

  2. 基本寻址

    LDR R0, [R1, #4]   ; R0 ← *(R1+4)
    

    #imm12 可省略。

  3. 后变址寻址

    LDR R0, [R1], #8   ; R0 ← *(R1), R1 ← R1+8
    
  4. 前变址并写回

    LDR R0, [R1, #8]!  ; R0 ← *(R1+8), R1 ← R1+8
    

 

2. STR(存储寄存器)

基本功能:把寄存器内容存入内存。

1.基本寻址

STR R1, [R0, #4]   ; *(R0+4) = R1

2. 后变址(post-indexed)

STR R1, [R0], #4   ; *R0 = R1, 然后 R0 ← R0+4
; 对应 C 写法:*R0 = R1; R0++

3. 前变址(pre-indexed)

STR R1, [R0, #4]!  ; R0 ← R0+4, *(R0) = R1
; 对应 C 写法:*++R0 = R1

4. 举例

MOV R0, #0x40000000
MOV R1, #0x55

STR R1, [R0], #4    ; 存到 0x40000000,R0=0x40000004
STR R1, [R0, #4]!   ; R0=0x40000008,存到 0x40000008

 

五、逻辑运算指令

1. BIC(按位清零)

MOV R0, 0xFFFFFFFF
BIC R0, R0, #3           ; 清除低 2 位 → 0xFFFFFFFC
BIC R0, R0, #(0x1F << 8) ; 清除连续 5 位

2. ORR(按位置 1)

MOV R0, #0
ORR R0, R0, #5         ; 低位 0b0101 置 1
ORR R0, R0, #(1 << 9)  ; 第 9 位设 1

六、标志位与条件执行

1. {S} 后缀(更新 CPSR 标志位)

N:结果为负 → N=1

Z:结果为 0 → Z=1

C:无符号加法进位 / 减法借位

V:有符号加减法溢出

示例:

MOV  R0, #0xFFFFFFFF ; 按有符号为 -1
ADDS R2, R0, #0      ; N=1
ADDS R1, R0, #1      ; Z=1, C=1
MOV  R0, #0x7FFFFFFF
ADDS R1, R0, #1      ; N=1, C=1, V=1

2. 条件执行 <c>

例如:

MOVCS R0, #100   ; 仅在 C=1 时执行

七、比较指令

1. CMP 指令

功能:比较两个寄存器或寄存器与立即数,本质是 Rn - Operand2,只更新 N、Z、C、V。

CMP R0, R1
BLT less

2. 最大值练习

(1) 两数取大:

CMP R0, R1
MOVGE R2, R0
MOVLT R2, R1

(2) 三数取大:

CMP R0, R1
MOVGE R3, R0
MOVLT R3, R1

CMP R3, R2
MOVLT R3, R2

八、循环与练习

1. B 指令实现循环

B loop   ; 相当于 LDR PC, =loop

2. while 循环:0+1+…+100

MOV R0, #0   ; sum
MOV R1, #0   ; i
MOV R2, #100

loop:
CMP R1, R2
BGT end
ADD R0, R0, R1
ADD R1, R1, #1
B   loop

end:
; R0 = 5050

3. do-while 循环:0+1+…+100

MOV R0, #0
MOV R1, #0
MOV R2, #100

loop:
ADD R0, R0, R1
ADD R1, R1, #1
CMP R1, R2
BLE loop

九、汇编与 C 的互调

1. 汇编调用 C 函数

  1. IMPORT 声明函数

  2. BL 调用函数

  3. 调用者负责保护现场、恢复现场

  4. 参数传递:

    • R0–R3 → 前 4 个参数

    • 超过 4 个 → 栈传递

  5. 返回值:R0

示例:

IMPORT c_add   ; 声明 C 函数
BL c_add       ; 调用

2. C 调用汇编函数

  1. C 文件中 extern 声明

  2. 汇编文件中 EXPORT 导出

  3. 参数、返回值与上面一致

  4. 调用者负责保护现场

十、模式切换

1. CPS 指令

直接修改模式:

CPS #<mode>

(Keil 不支持)

2. 使用 MRS / MSR 指令

MRS R0, CPSR
BIC R0, R0, #(0x1F)   ; 清除低 5 位
ORR R0, R0, #0x10     ; 设置 User 模式 (10000b)
MSR CPSR_c, R0
LDR SP, =0x40001000   ; 设置栈指针

网站公告

今日签到

点亮在社区的每一天
去签到