CPU通过条件码的检测来执行条件分支指令,最常用的条件码有
CF:进位。最近的操作使最高位产生了进位
ZF:零标志。最近的操作得出结果为0
SF:最近操作得出结果为负数
OF:溢出,最近操作导致补码溢出-正溢出或负溢出
除leaq指令,一般都会设置条件码
值得注意的时CMP和TEST两类指令,它们只设置条件码不改变其他寄存器。CMP指令和SUB指令一样。TEST指令行为和AND指令行为一样。
条件码第一种使用方式是根据条件码某个组合,将一个字节设置为0或1,一般将这一整类指令称为SET指令。
一般会利用cmpXXX + setXXX的形式设置。
如cmp:
cmpq %rsi, %rdi #比较
setl %al #小于时设置%eax的低阶为1
movzbl %al,%eax
ret
条件码第二种使用方式是条件跳转,分有条件跳转和无条件跳转,具体jmp跳转指令可查阅https://blog.youkuaiyun.com/wjy397/article/details/52355341
无条件直接跳转
movq $0,%rax
jmp .L1
movq (%rax),%rdx#这行直接跳掉不执行
.L1:
popq %rdx
无条件间接跳转
例子
jmp *%rax用寄存器%rax的值作为跳转目标
jmp *(%rax)以%rax的值作为读地址,从内存中读出跳转目标
有条件跳转
为了便于理解汇编的有条件跳转,我们通常可以将对应的C语言的if语句改写成goto版本
这里用一个绝对值的例子解释一下
原始版本:
long lt_cnt=0;
long ge_cnt=0;
long absdiff_se(long x, long y)
{
long result;
if (x<y){
lt_cnt++;
result=y-x;
}
else{
ge_cnt++;
result =x-y;
}
return result;
}
对应的goto 版本
long absdiff_se(long x, long y)
{
long result;
if (x>=y)
goto x_ge_y;
lt_cnt++;
result =y-x;
return result;
x_ge_y:
ge_cnt++;
result=x-y;
return result
}
其对应的汇编版本
absdiff_se:
cmpq %rsi, %rdi
jge .L2
addq $1, lt_cnt(%rip)
movq %rsi,%rax
subq %rdi,%rax
ret
.L2:
addq $1, ge_cnt(%rip)
movq %rdi, %rax
subq %rsi, %rax
ret