当您在 x86 或 x86_64 中执行算术运算,并导致设置溢出标志或任何其他标志时,设置的位是否会影响运算结果值存储在哪个寄存器中?还是这只会发生在分支指令中?
我尝试自己测试一下,创建一个汇编文件,然后将其转换为可执行文件,并用 GDB 进行分析,但由于某种原因,它总是显示错误的架构,所以我决定直接来这里看看是否能得到直接的答案
当您在 x86 或 x86_64 中执行算术运算,并导致设置溢出标志或任何其他标志时,设置的位是否会影响运算结果值存储在哪个寄存器中?还是这只会发生在分支指令中?
我尝试自己测试一下,创建一个汇编文件,然后将其转换为可执行文件,并用 GDB 进行分析,但由于某种原因,它总是显示错误的架构,所以我决定直接来这里看看是否能得到直接的答案
没有 x86 指令,其中 EFLAGS 的位构成对目标进行编码的寄存器号的一部分。
寄存器目标严格来自机器代码,因此无序机器总是通过解码指令来知道哪些寄存器是由指令写入的。
(如果存在这样的指令,它必须序列化管道,以便寄存器重命名具有先前指令的输出。类似于切换模式(16 vs. 32 vs. 64)必须序列化,以便相同的机器代码以不同的方式解码。)
指令如
cmovcc eax, [rdi]
无条件读取[RDI]
、EAX 和 EFLAGS,以及无条件写入 EAX(使用由 ALU 生成的值,根据 FLAGS 条件从两个整数输入之一中选择)。因此,无论条件为真还是假,它都会在错误地址上出错。并且输出对所有三个输入都有数据依赖性。(adc
就跟踪依赖性而言,CPU 将其视为指令,而不是像 周围的分支一样处理mov
。)即将推出的 APX 扩展添加了故障抑制 CMOV 加载和存储形式,您可以将其视为类似于 ARM 预测加载或存储,如果条件为假,则类似于 NOP。但这仍然只是写入寄存器或不写入寄存器,不可能根据数据写入不同的寄存器。
类似地,如果掩码全为零,则AVX-512 掩码指令
vaddps xmm0{k1}, xmm1, xmm2
将保持不变,但这与 CMOV 没有什么区别。xmm0
无法根据其他寄存器中的数据索引不同的架构寄存器。这对于具有寄存器重命名功能的现代无序执行 CPU 来说非常不方便,而且没有传统的 x86 指令可以做到这一点。(模型特定寄存器 (MSR) 由 ECX 中的索引读取/写入
rdmsr
,wrmsr
但这些已经是序列化指令并触发微码来戳内部;与整数和矢量寄存器不同,MSR 不会被重命名。)一些有关现代 CPU 工作原理的 CPU 架构背景知识可能有助于理解为什么依赖于数据的寄存器索引会是一场灾难。请记住,寄存器分配表必须根据管道宽度(当前端未停滞时)每个周期更新 4 到 6 个重命名,并且拥有可用于在其中找到独立工作的未来指令是 OoO exec 找到指令级并行性 (ILP) 的关键。
分支指令仅写入 RIP,从不写入其他寄存器,因此它们不是您所谈论的示例。(间接
call reg/mem
也写入 RSP 和内存,但同样不依赖于 FLAGS。)