ARM V8R中汇编指令CMP的详细用法
好的,我们来详细解析 ARMv8-R 架构(通常运行在 AArch32 状态)中 CMP (CoMPare) 指令的用法。这是一条极其重要且频繁使用的指令,它是实现程序条件逻辑和循环控制的基石。
🧠 核心功能与概述
CMP 指令的核心功能是:比较两个数的大小,并根据比较结果设置应用程序状态寄存器 (APSR) 中的条件标志位。它本身不存储计算结果,仅用于为后续的条件分支或条件执行指令提供判断依据。
- 操作本质:
CMP Rn, Operand2在内部执行Rn - Operand2减法操作。 - 关键特性:它不将减法结果保存到任何通用寄存器,只更新 APSR 中的条件标志位(N, Z, C, V)。
- 主要用途:为
BEQ,BNE,BGT,BLT等条件分支指令,以及MOVEQ,ADDNE等条件执行指令准备判断条件。
用高级语言的思维来理解:CMP R0, R1 就像执行了 if (R0 == R1) 或 if (R0 > R1) 中的比较部分,但还没有执行跳转动作。
为了让您快速理解 CMP 指令如何影响标志位并为条件跳转做准备,下图展示了其核心工作流程:
⚙️ 语法与操作数格式
CMP 指令的语法如下:
CMP{<cond>} <Rn>, <operand2>
{<cond>}:可选的条件码后缀(如EQ,NE)。这允许条件地执行比较指令本身,但此用法较为罕见。<Rn>:第一个源操作数寄存器(被减数)。<operand2>:第二个源操作数(减数)。它可以是一个:- 寄存器:
Rm - 立即数:
#imm - 经过移位操作的寄存器:
Rm, <shift> #<amount>
- 寄存器:
🛠️ 详细用法与示例
1. 基本比较:判断相等或不等
这是最常用的场景,通常后跟 BEQ (Branch if EQual) 或 BNE (Branch if Not Equal)。
MOV R0, #10
MOV R1, #10
CMP R0, R1 @ 内部计算 R0 - R1 = 0
@ 结果为零,因此 APSR.Z (Zero) 标志被置为 1
BEQ values_equal @ 因为 Z == 1,所以跳转
B not_equal @ 这条指令会被跳过
values_equal:
@ R0 等于 R1 时执行的代码
not_equal:
@ R0 不等于 R1 时执行的代码
2. 大小比较:判断大于、小于
CMP 配合不同的条件码,可以判断有符号数和无符号数的大小关系。
有符号数比较 (Signed Comparison):
CMP R0, R1 @ 执行 R0 - R1
BGT target_gt @ Branch if Greater Than (有符号大于): (N==V) AND (Z==0)
BGE target_ge @ Branch if Greater than or Equal (有符号大于等于): N==V
BLT target_lt @ Branch if Less Than (有符号小于): N != V
BLE target_le @ Branch if Less than or Equal (有符号小于等于): (Z==1) OR (N != V)
无符号数比较 (Unsigned Comparison):
CMP R0, R1 @ 执行 R0 - R1
BHI target_hi @ Branch if Higher (无符号大于): (C==1) AND (Z==0)
BHS target_hs @ Branch if Higher or Same (无符号大于等于): C==1
BLO target_lo @ Branch if Lower (无符号小于): C==0
BLS target_ls @ Branch if Lower or Same (无符号小于等于): (C==0) OR (Z==1)
3. 与循环控制结合
CMP 常用于循环结束条件的判断。
MOV R0, #0 @ 初始化计数器
loop_start:
@ ... (循环体代码) ...
ADD R0, R0, #1 @ 计数器递增
CMP R0, #10 @ 比较计数器是否达到 10
BNE loop_start @ 如果 R0 != 10,则继续循环
@ 循环结束,继续执行后续代码
4. 检查范围
通过两次比较来检查一个值是否在某个范围内。
CMP R0, #100 @ 检查 R0 >= 100?
BLO out_of_range @ 如果无符号小于 (Lower), 则小于100,跳转
CMP R0, #200 @ 检查 R0 <= 200?
BHI out_of_range @ 如果无符号大于 (Higher), 则大于200,跳转
@ 如果执行到这里,说明 100 <= R0 <= 200
B in_range
out_of_range:
@ 处理超出范围的情况
in_range:
@ 处理在范围内的情况
⚠️ 重要注意事项与原理
-
CMP与SUBS的关系:CMP Rn, Operand2在功能上完全等同于SUBS Rzr, Rn, Operand2。- 也就是说,它执行减法并设置标志,但将结果丢弃(写入零寄存器
Rzr)。 - 因此,
CMP不会破坏任何通用寄存器的值,这是它与SUBS的最大区别。
-
条件标志的设置:
CMP执行Rn - Operand2,并根据减法结果设置标志:- Z (Zero):如果结果为 0(即两数相等),则置 1。
- C (Carry):对于减法,C=1 表示无借位(即
Rn >= Operand2,无符号数比较时)。这与加法的含义相反,需要特别注意。 - N (Negative):如果结果为负数(最高位为1),则置 1。
- V (oVerflow):如果结果发生有符号溢出,则置 1。
-
立即数范围:
与SUB指令相同,立即数#imm的取值范围受到 ARM 编码规则的限制(12位立即数,可移位)。 -
与
TST指令的区别:CMP:用于比较两个数值的大小(执行减法)。TST:用于测试一个寄存器中特定的位是否设置(执行按位与操作)。
💎 总结
CMP 指令是 ARM 汇编中条件执行的触发器和程序流程的决策者。
它的核心价值在于:
- 非破坏性:只设置标志,不改变任何通用寄存器,非常适合在判断前比较。
- 高效性:一条指令为后续多条条件指令做好准备。
- 灵活性:支持寄存器、立即数、移位操作数,能够应对各种比较场景。
主要应用场景:
- 条件分支:与
B{cond}指令配合,实现if-else逻辑。 - 循环控制:检查循环计数器,实现
for,while循环。 - 范围检查:判断值是否在合法区间内。
- 条件执行:为
MOV{cond},ADD{cond}等条件数据操作指令设置条件。
简单来说:只要你需要比较两个数的大小或判断是否相等,就应该使用 CMP 指令。 它是编写任何具有逻辑判断功能的汇编代码的必备工具。
浙公网安备 33010602011771号