在 x86 intel 引用手册中,它说:
"The overflow flag is set only if the single-shift forms of the instruction are used. [...]"
但是当我遇到以下情况时:
xor eax, eax
mov al, 0b11000000
shl al, 2
;content of al: 00000000
这里答案的高位与进位结果不一样,即cf = 1
,并且没有设置溢出标志。
我不明白为什么这是正确的行为。为什么只有在使用单类时才设置溢出标志?
最佳答案
OF=undefined for shift counts other than 1 ;实际结果取决于您的 CPU。请参阅下文,了解我在 Intel CPU 上如何设置它的理论。
这个设计决策有一定道理,让硬件稍微简单一些。
正确检测 2 的补码溢出需要检查所有移出的位是否与新的 MSB 匹配。这与像现在使用 CF 那样仅检查移出的最后一位不同,因此一次一个移位器需要一些内部状态,例如使用的原始 8086。
这也许就是斯蒂芬·莫尔斯所说的
(8086 ISA 的架构师)在为 8086 做出设计选择时正在思考。他的书《8086 Primer》是 available for free on his web site ,并确认(第 96 页)8086 的可变计数操作码未定义 OF。 (对于 8086,显然包括 CL=1 的 shl al, cl
,与 Intel 目前的文档不同。)有关移位指令及其用途的部分(第 64-66 页)没有提到 OF,只提到 CF。
必须检查所有移出的位也可能会使桶形移位器更加昂贵,但莫尔斯不太可能考虑到这一点。
不知道为什么 Morse 没有将 OF 定义为始终以某种特定方式设置,也许根据 CF 与当前 MSB 不匹配,这可能没有用,但对于 1 的计数仍然有意义。 ALU 已经需要为 CF 移出最后一位。也许这是因为 8086 没有在可变计数操作码中为 OF 定义任何内容,即使计数恰好为 1。
请注意,在实践中,某些 CPU 在计数大于 1 的某些情况下会产生 OF=1。例如,我的 i7-6700k Skylake 会使用 0x7f << 2
。
documentation说
OF flag is affected only for 1-bit shifts (see “Description” above); otherwise, it is undefined.
未定义并不是受影响的反义词;那将“不受影响”。它总是设置为某个值,他们只是没有记录 CPU 如何选择 0 与 1。
实际上,未经修改将强制读取除 0
之外的立即移位计数并与旧的 FLAGS 值合并。在现代 CPU 上,就像变量计数一样,如果它是 0,所以最好不以这种方式指定。 (shl reg, cl
在 Sandybridge 系列上是 3 uops,因为在 CL&31 == 0 的情况下需要保持 FLAGS 不变)。因此,这将是一个不需要的数据依赖性,与现在的情况不同,除非计数为 0,否则移位会写入所有标志。
我用这个 NASM 程序测试了我的 CPU
_start:
mov cl, 7
mov dl, 0x7f ; GDB set $dl = 0xc0 or whatever after this
.loop:
mov eax, edx
shl al, cl
dec cl ; set a breakpoint here to look at EFLAGS after every continue
jnz .loop
;; fall off the end; I'm only single-stepping this in GDB anyway
使用 nasm+ld 汇编+链接到静态可执行文件,使用 GDB 运行并使用 layout reg
/layout next
。使用starti
和si
.
我的 Skylake CPU 确实为 shl al,cl
设置了 OF=1 AL=0x7f CL=2(或 1 或任何非零计数)。或者 AL=0x80。但切勿将其设置为任何计数的 AL=0x3 或 AL=0xc0 (0b1100_0000)
我目前对解释该行为的猜测是 OF 被设置为移位 1,
即如果 OF = (input[MSB] != input[MSB-1])
输入位。
这是有道理的;在纸张规范需要特定结果的情况下,它给出了正确的结果,并且实现起来很便宜。 (OF 输出仍然必须来自不同的位,具体取决于操作数大小。)
当然,其他供应商的其他微架构可能有所不同。纯软件 x86 模拟器也同样符合纸上规范。
关于assembly - 为什么仅在使用单类时才设置溢出标志?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71771188/