ARM V8R中汇编指令B/BL/BX/BLX的详细用法
好的,我们来详细解析 ARMv8-R 架构(通常运行在 AArch32 状态)中 B、BL、BX、BLX 这一组分支指令的用法。它们是控制程序执行流程最核心的指令,理解了它们就理解了 ARM 程序如何跳转和调用函数。
🧠 核心概念与概述
这四条指令都用于改变程序计数器(PC)的值,从而实现跳转或调用。它们的主要区别在于:
- 是否保存返回地址(到
LR寄存器) - 是否切换指令集状态(ARM / Thumb)
为了让您快速建立整体概念,我们先通过一个对比表格来总结它们的核心区别与用途:
| 指令 | 全称 | 主要功能 | 是否保存返回地址 (LR) |
是否切换状态 | 典型用途 |
|---|---|---|---|---|---|
B |
Branch | 直接跳转 | 否 | 否 | 循环、条件判断、无限跳转 |
BL |
Branch with Link | 函数调用 | 是 | 否 | 调用函数 |
BX |
Branch and eXchange | 跳转并切换状态 | 否 | 是 | 从函数返回、跳转到Thumb/ARM代码 |
BLX |
Branch with Link and eXchange | 调用并切换状态 | 是 | 是 | 调用另一种状态下的函数 |
⚙️ 语法与操作数格式
1. B (Branch) - 最简单的跳转
语法: B{<cond>} <label>
- 功能: 无条件或条件跳转。将 PC 设置为标签地址。
- 行为: 不保存返回地址。不切换指令集状态。
- 应用场景: 循环、条件分支、无限循环。
loop:
@ ... 一些代码 ...
B loop @ 无限循环跳转到自身
CMP R0, #10
BGT greater_than_10 @ 条件跳转:如果 R0 > 10,则跳转
2. BL (Branch with Link) - 函数调用
语法: BL{<cond>} <label>
- 功能: 用于函数调用。跳转前,将下一条指令的地址(返回地址)保存到链接寄存器 (
LR或R14) 中。 - 行为: 保存返回地址 (
MOV LR, PC的效果)。不切换指令集状态。 - 应用场景: 这是调用函数的最常用指令。
main:
MOV R0, #5
MOV R1, #3
BL my_add_function @ 调用函数!LR = main 中下一条指令的地址
@ ... @ 函数返回后,继续从这里执行
my_add_function:
ADD R0, R0, R1
BX LR @ 返回调用者!通过 LR 中的返回地址跳转回 main
3. BX (Branch and eXchange) - 跳转并切换状态
语法: BX{<cond>} <Rm>
- 功能: 跳转到寄存器指定的地址,并根据该地址的最低位(bit[0])决定切换到的指令集状态。
- 行为:
- 如果目标地址的 bit[0] = 0,则处理器进入 ARM 状态。
- 如果目标地址的 bit[0] = 1,则处理器进入 Thumb 状态。
- 不保存返回地址。
- 应用场景:
- 从函数返回(如上例中的
BX LR)。BL指令将返回地址保存到LR时,已经自动设置了最低位以指示当前的指令集状态,所以BX LR总能正确返回。 - 在 ARM 和 Thumb 代码之间跳转。
- 从函数返回(如上例中的
@ 从 ARM 状态切换到 Thumb 状态的代码
LDR R0, =thumb_code + 1 @ 将目标地址的 bit[0] 设为 1,表明是 Thumb 代码
BX R0 @ 跳转并切换到 Thumb 状态
.thumb @ 告诉汇编器之后是 Thumb 代码
thumb_code:
@ ... (这里是 Thumb 指令) ...
4. BLX (Branch with Link and eXchange) - 调用并切换状态
语法:
1. BLX <label> (由标签指定目标,汇编器自动处理状态)
2. BLX <Rm> (由寄存器指定目标,行为与 BX 一致,但会保存 LR)
- 功能:
BL和BX的结合体。它保存返回地址到 LR,然后跳转到目标地址,并根据目标地址的最低位切换指令集状态。 - 行为: 同时具备
BL(保存返回地址)和BX(切换状态)的功能。 - 应用场景: 从一种指令集状态中调用另一种指令集状态的函数。这在很多库函数中非常常见。
@ 在 ARM 代码中调用一个 Thumb 函数
.arm
BLX thumb_function @ 调用Thumb函数,LR被设置,并切换到Thumb状态
@ 函数返回后,会自动切换回 ARM 状态
...
.thumb
thumb_function:
@ ... (Thumb 指令) ...
BX LR @ 返回到 ARM 状态的调用者
🛠️ 关键区别与总结
| 特性 | B |
BL |
BX |
BLX |
|---|---|---|---|---|
| 跳转目标 | 标签 | 标签 | 寄存器 | 标签或寄存器 |
| 保存返回地址 (LR) | 否 | 是 | 否 | 是 |
| 切换指令集状态 | 否 | 否 | 是 | 是 |
| 主要用途 | 循环、分支 | 函数调用 | 函数返回、状态跳转 | 跨状态函数调用 |
💡 核心记忆点
- 想调用函数?用
BL。这是你每天都会用的指令。 - 函数执行完了想返回?用
BX LR。这是函数返回的标准方式。 - 看到
BX或BLX的操作数是寄存器时,要特别注意最低位,它决定了处理器下一步是执行 ARM 还是 Thumb 代码。 BLX <label>形式让程序员无需手动计算状态位,汇编器会帮你处理。
⚠️ 重要注意事项
- 跳转范围:
B和BL指令的跳转目标受到偏移量范围的限制(大约 ±32MB)。如果标签太远,汇编器会报错。 - 寄存器状态:使用
BX和BLX时,必须确保目标寄存器的最低位的正确性,否则会导致不可预知的行为。 - 流水线效应:所有分支指令都会清空处理器的流水线,可能带来性能 penalty,这在时间敏感的代码中需要考虑。
理解这四条指令的差异,是编写和理解任何非平凡 ARM 汇编代码(如函数调用、中断处理、混合模式编程)的基础。
浙公网安备 33010602011771号