条件码
CPU维护一组单个位的条件码寄存器
- CF:进位标志。最近的操作使最高位产生了进位。可用来检查无符号操作的溢出。
- ZF:零标志。最近的操作得出得结果为0。
- SF:符号标志。最仅的操作得到的结果为负数。
- OF:溢出标志。最近的操作导致一补码溢出——正溢出或负溢出。
leaq指令是用来进行地址计算的,不改变任何条件码。
指令 | 基于 | 描述 |
---|---|---|
CMP S1, S2 | S2 - S1 | 比较 |
cmpb | 比较字节 | |
cmpw | 比较字 | |
cmpl | 比较双字 | |
cmpq | 比较四字 | |
TEST S1, S2 | S1 & S2 | 测试 |
testb | 测试字节 | |
testw | 测试字 | |
testl | 测试双字 | |
testq | 测试四节 |
比较和测试指令。这些指令不修改任何寄存器的值,只设置条件码
访问条件码
指令 | 同义名 | 效果 | 设置条件 |
---|---|---|---|
sete D | setz | D<—ZF | 相等/零 |
setne D | setnz | D<—~ZF | 不等/非零 |
sets D | D<—SF | 负数 | |
setns D | D<—~SF | 非负数 | |
setg D | setnle | D<— ~(SF^OF)&~ZF | 大于(有符号>) |
setge D | setnl | D<— ~(SF^OF) | 大于等于(有符号>=) |
setl D | setnge | D<— SF^OF | 小于(有符号<) |
setle D | setng | D<— (SF^OF) | ZF |
seta D | setnbe | D<—~CF&~ZF | 超过(无符号>) |
setae D | setnb | D<—~CF | 超过或相等(无符号>=) |
setb D | setnae | D<—CF | 低于(无符号<) |
setbe D | setna | D<—CF|ZF | 低于或相等(无符号<=) |
SET指令。每条指令根据条件码的某种组合,将一个字节设置为0或者1。有些指令有” 同义名” ,也就是同一条机器指令有别的名字。
跳转指令
指令 | 同义名 | 跳转条件 | 描述 |
---|---|---|---|
jmp Label | 1 | 直接跳转 | |
jmp *Operand | 1 | 间接跳转 | |
je Label | jz | ZF | 相等/零 |
jne Label | jnz | ~ZF | 不相等/非零 |
js Label | SF | 负数 | |
jns Label | ~SF | 非负数 | |
jg Label | jnle | ~(SF^OF)&~ZF | 大于(有符号>) |
jge Label | jnl | ~(SF^OF) | 大于或等于(有符号>=) |
jl Label | jnge | SF^OF | 小于(有符号<) |
jle Label | jng | (SF^OF)|ZF | 小于或等于(有符号<=) |
ja Label | jnbe | ~CF&~ZF | 超过(无符号>) |
jae Label | jnb | ~CF | 超过或相等(无符号>=) |
jb Label | jnae | CF | 低于(无符号<) |
jbe Label | jna | CF | ZF |
jump指令。当跳转条件满足时,这些指令会跳转到一条带标号的目的地。有些指令有” 同义名 “,也就是同一条机器指令的别名
跳转目的地通常用一个标号(Label)指明,类似 “.L1” 。跳转有直接跳转”jmp .L1”或者间接跳转”jmp *%rax”用寄存器和内存中的值作为跳转目标。
跳转指令的编码可以用绝对地址或相对地址,相对地址利用jmp指令后面对应的值+下一条指令的起始地址=跳转目的地,这也方便程序在内存中的移动,最为常用。使用如下例:
movq %rdi, %rax
jmp .L2
.L3:
sarq %rax
.L2:
testq %rax, %rax
jg .L3
rep; ret
汇编器产生的 ” .o ” 格式的反汇编版本如下:
0:48 89 f8 mov %rdi, %rax
3:eb 03 jmp 8 <loop+0x8>
5:48 d1 f8 sar %rax
8:48 85 c0 test %rax, %rax
b:7f f8 jg 5 <loop+0x5>
d:f3 c3 repz retq
- 对于jmp 8; 用 0x03(二进制补码)+5 = 0x8 即可得到跳转到8
- 对于jg 5; 用 0xf8(二进制补码)+0xd = 0x5 即可得到跳转到5
现代使用条件传送来实现条件分支
long absdiff(long x, long y)
{
long result;
if(x < y)
result = y-x;
else
result = x-y;
return result;
}
优化的汇编
long absdiff(long x, long y)
x in %rdi, y in %rsi
absdiff:
movq %rsi, %rdx
subq %rdi, %rdx rval = y-x
movq %rdi, %rax
subq %rsi, %rax eval = x-y
cmpq %rsi, %rdi compare x:y
cmovl %rdx, %rax if x<y, eval = rval
ret return eval
以上汇编的实现原理可以使用如下的C语言来解释
long cmovdiff(long x, long y)
{
long rval = y-x;
long eval = x-y;
long ntest = x >= y;
/* Line below requires
* single instruction: */
if(ntest)
rval = eval;
return rval;
}
条件传送指令
指令 | 同义名 | 传送条件 | 描述 |
---|---|---|---|
cmove S, R | cmovz | ZF | 相等/零 |
cmovne S, R | cmovnz | ~ZF | 不相等/非零 |
cmovs S, R | SF | 负数 | |
cmovns S, R | ~SF | 非负数 | |
cmovg S, R | cmovnle | ~(SF^OF)&~ZF | 大于(有符号>) |
cmovge S, R | cmovnl | ~(SF^OF) | 大于或等于(有符号>=) |
cmovl S, R | cmovnge | SF^OF | 小于(有符号<) |
cmovle S, R | cmovng | (SF^OF)|ZF | 小于或等于(有符号<=) |
cmova S, R | cmovnbe | ~CF&~ZF | 超过(无符号>) |
cmovae S, R | cmovnb | ~CF | 超过或相等(无符号>=) |
cmovb S, R | cmovnae | CF | 低于(无符号<) |
cmovbe S, R | cmovna | CF|ZF | 低于或相等(无符号<=) |
条件传送指令。当传送条件满足时,指令把源值S复制到目的R。有些指令是” 同义名” ,即同一条机器指令的不同名字