玩命加载中 . . .

3.5-指令与条件码


指令与条件码

条件码寄存器

条件码寄存器是由CPU来维护的,长度是1Bit,它描述了最近执行的操作的属性,例如ALU执行两条连续的算术指令

t1: addq %rax, %rbx
t2: subq %rcx, %rdx

t1时刻执行指令1,t2时刻执行指令2,t1时刻条件码寄存器保存的是指令1的执行结果的属性,t2时刻,条件码寄存器中的内容将会被下一条指令所覆盖

常用条件码

  • CF: Carry Flag,进位标志,当执行的指令最高位产生进位时,CF会被置1,用来检查无符号数操作的溢出
  • ZF: Zero Flag,零标志,最近操作结果等于0时,ZF会置1
  • SF: Sign Flaag,符号标志,最近操作结果小于0时,SF置1
  • OF: Overflow Flag,溢出标志,针对有符号数,最近的操作导致正溢出或负溢出,OF会置1

条件码寄存器的值是由ALU在执行算术和运算指令时写入的

不同的指令有相应的规则来设置条件码寄存器,例如,逻辑操作指令xor,进位标志CF和溢出标志OF会置0;加一和减一指令会设置溢出标志OF和零标志ZF,但不会改变进位标志CF

除此之外,cmptest指令也可以改变条件码寄存器

cmp指令是根据两个操作数的差来设置,与sub指令不同的是,cmp只是作差,然后设置寄存器,不会更新目的操作数的值

test指令和and类似,同样只是设置条件码寄存器

例子

判断等于

int comp(long a, long b) {
    return a == b;
}

对应的汇编代码,参数a放在寄存器rdi中,参数b放在rsi

cmpq    %rsi, %rdi
sete    %al
movzbl  %al, %eax
ret

指令cmpq根据a-b的结果设置条件码寄存器,当a==b时,会将ZF设置为1

通常情况下,不会直接去读条件码寄存器的值,其中一种方式是根据条件码的某种组合,通过set类指令,将一个字节设置为0或者1

sete根据ZF的值,对寄存器al进行赋值,后缀e是equal

  • 如果ZF=1,将al置为1
  • 如果ZF=0,将al置为0

然后moval进行零扩展,最后返回判断结果

判断小于

int comp(long a, long b) {
    return a < b;
}

汇编代码也发生了变化
cmpq    %rsi, %rdi
setl    %al
movzbl  %al, %eax
ret

指令setl的含义是如果a < bal置为1,其中l是less

小于需要用SFOF的异或结果来判定

  • a < b, t < 0, SF = 1, SF ^ OF = 1
  • a > b, t > 0, SF = 0, SF ^ OF = 0
  • a < b, t > 0, 正溢出,SF = 0, OF = 1, SF ^ OF = 1
  • a > b, t < 0, 负溢出,SF = 1, OF = 1, SF ^ OF = 0

所以,a<b的异或结果SF ^ OF = 1,可以以此作为判断依据


文章作者: kunpeng
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 kunpeng !
  目录