详解ARM汇编条件标志
版权归作者所有,如有转发,请注明文章出处:https://cyrus-studio.github.io/blog/
条件标志
在 ARM 指令集中,条件标志是控制指令执行的一种机制,它们用于实现条件分支、比较和其他逻辑操作。
我们平时使用 IDA 调试程序时,在 general registers 窗口中看到的条件标志
ARM 处理器通常使用四个主要的条件标志,它们的状态影响指令的执行。这些条件标志包括:
1. N (Negative): 负标志,用于指示最后一次操作的结果是否为负值。若结果为负,则 N 被置为 1;否则为 0。
2. Z (Zero): 零标志,用于指示最后一次操作的结果是否为零。如果结果为零,则 Z 被置为 1;否则为 0。
3. C (Carry): 进位标志,用于指示加法操作是否产生了进位或减法操作是否没有借位。对于加法,若产生进位,则 C 被置为 1;对于减法,若没有借位,则 C 被置为 1。
4. V (Overflow): 溢出标志,用于指示最后一次算术操作是否发生了溢出。当两个有符号数相加或相减时,如果结果的符号与操作数的符号不一致,表示发生了溢出,V 被置为 1。
在 ARM 指令中,条件执行可以通过附加条件码实现,例如:
EQ (Equal): 当 Z = 1 时执行(相等)。
NE (Not Equal): 当 Z = 0 时执行(不相等)。
GT (Greater Than): 当 Z = 0 且 N = V 时执行(大于)。
LT (Less Than): 当 N ≠ V 时执行(小于)。
GE (Greater Than or Equal): 当 N = V 时执行(大于或等于)。
LE (Less Than or Equal): 当 Z = 1 或 N ≠ V 时执行(小于或等于)。
在 armv7 文档中 A8.3 Conditional execution 可以找到所有条件码的详细说明
文档地址:https://developer.arm.com/documentation/ddi0406/latest/
这些条件标志和条件码使得 ARM 架构能够高效地进行复杂的控制流和决策逻辑,从而优化程序的执行效率。
条件标志如何影响指令的执行
下面以一段汇编代码解释条件标志的变化过程,以及如何通过条件码用于指令影响汇编指令的走向。
.data
a: .word 5 // 定义变量 a,值为 5
b: .word 10 // 定义变量 b,值为 10
max_value: .word 0 // 存储最大值的变量
.text
.global _start
_start:
// 读取 a 和 b 的值
LDR R0, =a // 将 a 的地址加载到 R0
LDR R1, [R0] // 将 a 的值加载到 R1 (R1 = 5)
LDR R0, =b // 将 b 的地址加载到 R0
LDR R2, [R0] // 将 b 的值加载到 R2 (R2 = 10)
// 比较 a 和 b
CMP R1, R2 // 比较 R1 (a) 和 R2 (b)
// 根据 R1 和 R2 的值,设置条件标志
// 如果 R1 < R2:
// N = 1, Z = 0, C = 1, V = 0
// 如果 R1 == R2:
// N = 0, Z = 1, C = 1, V = 0
// 如果 R1 > R2:
// N = 0, Z = 0, C = 0, V = 0
// 根据比较结果设置最大值
BEQ a_equals_b // 如果 Z = 1 (相等),跳转到 a_equals_b
BGT a_greater // 如果 N = 0 且 Z = 0,(a > b),跳转到 a_greater
// 如果到这里,说明 b > a
STR R2, =max_value // b 是最大值,存储 b 的值
B end // 跳转到 end
a_equals_b:
// a 和 b 相等
STR R1, =max_value // 存储任一值,a 或 b 都可以
B end // 跳转到 end
a_greater:
// a 大于 b
STR R1, =max_value // 存储 a 的值
end:
// 结束程序
MOV R7, #1 // 系统调用号,退出
SWI 0 // 触发系统调用
CMP 指令是如何影响条件标志
在 ARM 汇编中,CMP 指令用于比较两个寄存器的值。具体来说,CMP R1,R2 指令会将寄存器 R1 的值减去寄存器 R2 的值,但不会将结果存储在任何寄存器中。这一操作的主要目的是更新条件标志,以便后续的条件执行指令可以根据比较结果做出决策。
我们可以在执行比较 CMP R1, R2 时观察到条件标志的变化。
步骤 | R1 (a) | R2 (b) | N (Negative) | Z (Zero) | C (Carry) | V (Overflow) | 说明 |
---|---|---|---|---|---|---|---|
读取 a 的值 | 5 | - | - | - | - | - | 加载 a 的值到 R1 |
读取 b 的值 | 5 | 10 | - | - | - | - | 加载 b 的值到 R2 |
比较 R1 和 R2 | 5 | 10 | 1 | 0 | 1 | 0 | 执行 CMP R1, R2 ,结果 5 - 10(借位) |
BEQ 检查 | 5 | 10 | 1 | 0 | 1 | 0 | Z = 0(不相等),不跳转到 a_equals_b |
BGT 检查 | 5 | 10 | 1 | 0 | 1 | 0 | N = 1,Z = 0(a 不大于 b),不跳转到 a_greater |
存储最大值 | - | 10 | 1 | 0 | 1 | 0 | 存储 b 的值到 max_v |