x86-64 下的读取条件码指令
SetX
系列指令
读取当前条件码 (或者某些条件码的组合), 并存入目的 "字节" 寄存器. 同时余下的七个字节不会被修改.
X86-64 下函数参数的传递, 前几个参数实际上是通过寄存器来传递的, 具体怎么传咱们以后会讲. 第一个参数 x 放到 %rdi 里面, 第二个放在 %rsi 里面, 然后我们再来看这两段代码 :
int gt (long x, long y)
{
return x > y;
}
long lgt (long x, long y)
{
return x > y;
}
这两个代码唯一的不同就是返回值是 32 位还是 64 位.
我们用 gcc 编译发现, 它们分别产生了同样的代码 :
xorl %eax, %eax ; eax = 0
cmpg %rsi. %rdi ; Compare x : y
setg %al ; al = x > y
这个代码, 不知道大家有没有注意到奇怪的地方.
第一句是异或, eax 自己和自己异或, 就变成 0 了. 然后函数返回值是放在 eax 寄存器 (64 位是 rax).
所以我先把 eax 清 0, 之后进行比较, 比较完了之后我们把这个条件码的组合放到 al 寄存器, 也就是 eax 的低位里面去.
这个看起来好像没问题, 但是如果我们从 64 位的角度来看, 就是返回值是 64 位的话, 是不是有点问题 ?
因为你 xorl 这条指令, 只是把 eax 清 0 了, eax 实际上是 rax 的低 32 位, 那么你高 32 位怎么办 ?
这么做的原因是, 就是在 64 位这个体系架构下面, 如果进行了一个 32 位的操作, 32 位的操作又产生了一个 32 位的结果, 那么就会自动向高 32 位填充 0. 就是说 eax 自己对自己异或, 清 0 了, 这个结果 0 会自动扩展到它这个 rax 的高 32 位.
又来一个问题, 我的指令是只操作低 32 位, 为什么你要把高 32 位清 0 呢 ? 这个实际上和处理器的流水线的相关性有关系.