CPU还维护一组单个位的条件码寄存器,用来描述最近的算术和逻辑操作的属性。常用
CF:无符号溢出
OF:有符号溢出
ZF:零标志
SF:符号标志
注意:
用法:两个操作数是一样的,例如testq %rax,%rax用来检测%rax是负数、零、正数
假设temp=test %rax,%rax
SET指令的目的操作数是低位单字节寄存器,或是一个字节的内存位置(指令将这个字节设置为0或1,为得到32或64位结果,将高位清零)
机器代码对于有符号和无符号两种情况都使用一样的指令,许多算术运算对于无符号和补码算术有一样的位级操作。对于右移、除法、乘法和不同的条件码组合需使用的不同的版本。
两种指令
将目标指令的地址与紧跟在跳转指令后面那条指令的地址之间的差作为编码。
还有一种编码方式是给出绝对地址,用4字节直接指定目标,汇编器和链接器会选择适当编码。
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
第二行的跳转目标是0x8,指令中的字节编码为0x03,它与第三行地址0x5相加为0x8,,第5行跳转目标是0x5,指令中的字节编码为0xf8(十进制-8)
注意:程序计数器的值是跳转指令后面的那条指令,而不是跳转指令本身地址。
使用PC-relative寻址好处
C语言的if-else语句
if(test-expr)
then-statement
else
else-statement
汇编形式
t-test-expr;
if(!t)
goto false;
then-statement
goto done;
false:
else-statement
done:
控制的条件转移,当条件满足时,程序沿着一条路径,不满足时,条件沿着另一条路径,在现代处理器上很低效。
处理器通过流水线(pipelining)获得高性能,流水线中一条指令的处理经过一系列阶段,每个阶段执行所需操作的一部分(例如,从内存取指令,确定指令类型,从内存读数据,执行算术运算,向内存写数据,更新程序计数器),通过重叠连续指令的步骤获得高性能。这要保证能过事先确定要执行的指令序列,保证流水线里充满了待执行的指令。而条件跳转,需要分支条件求值后才能决定路径。处理器会采用分支预测逻辑猜测指令路径。错误的预测跳转,要求处理器丢掉之前的指令,再用正确的位置填充流水线,大约15~30个时钟周期。
处理器无需预测测试结果就可以执行条件传送,处理器读源值,检查条件码,看是否需要更新目的寄存器。
C语言形式
v=test-expr?then-expr:else-expr;
条件传送形式
v=then-expr;
ve=else-expr;
t=test-expr;
if(!t) v=ve;
do-while循环
do
body-statement
while(test-expr);
汇编形式
loop:
body-statement
t=test-expr;
if(t)
goto loop;
while循环
while(test-expr)
body-statement
汇编形式
goto test;
loop:
body-statement
test:
t=test-expr;
if(t)
gpto loop;
考官语句通过整数索引值进行多重分支,使用跳转表(地址数组),表项i是一个代码段的地址,这个代码段的实现相当于开关索引值等于i时程序的路径。这里直接给出书上的例子。