指令与条件码
条件码寄存器
条件码寄存器是由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会置1SF
: Sign Flaag,符号标志,最近操作结果小于0时,SF置1OF
: Overflow Flag,溢出标志,针对有符号数,最近的操作导致正溢出或负溢出,OF会置1
条件码寄存器的值是由ALU在执行算术和运算指令时写入的
不同的指令有相应的规则来设置条件码寄存器,例如,逻辑操作指令xor
,进位标志CF
和溢出标志OF
会置0;加一和减一指令会设置溢出标志OF
和零标志ZF
,但不会改变进位标志CF
除此之外,cmp
和test
指令也可以改变条件码寄存器
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
然后mov
对al
进行零扩展,最后返回判断结果
判断小于
int comp(long a, long b) {
return a < b;
}
汇编代码也发生了变化
cmpq %rsi, %rdi
setl %al
movzbl %al, %eax
ret
指令setl
的含义是如果a < b
,al
置为1,其中l是less
小于需要用SF
和OF
的异或结果来判定
- 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
,可以以此作为判断依据