版权归作者所有,如有转发,请注明文章出处:https://cyrus-studio.github.io/blog/

条件标志

在 ARM 指令集中,条件标志是控制指令执行的一种机制,它们用于实现条件分支、比较和其他逻辑操作。

我们平时使用 IDA 调试程序时,在 general registers 窗口中看到的条件标志 image.png

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 可以找到所有条件码的详细说明

image.png

文档地址: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 的值510----加载 b 的值到 R2
比较 R1 和 R25101010执行 CMP R1, R2 ,结果 5 - 10(借位)
BEQ 检查5101010Z = 0(不相等),不跳转到 a_equals_b
BGT 检查5101010N = 1,Z = 0(a 不大于 b),不跳转到 a_greater
存储最大值-101010存储 b 的值到 max_v