Loo*_*Per 3 x86 assembly integer-overflow bit-shift signed-overflow
您知道有什么方法可以有效地检查 x86 左移算术上是否发生溢出/下溢吗?
一个好的选择是在左移之后立即执行算术移位,看看是否得到相同的数字:
\n mov ebx, eax ; keep a copy of the original\n sal eax, cl ; TODO: also copy the shifted EAX somewhere\n sar eax, cl\n cmp ebx, eax ; (x << n) >> n == x\n jne overflow\n ; result: not stored anywhere by this snippet.\nRun Code Online (Sandbox Code Playgroud)\nBMI2 3操作数移位可以节省一些mov指令:
; input: x in EDI, shift count n in ESI\n shlx eax, edi, esi ; there is no salx, it\'s the same operation\n sarx edx, eax, esi ; (x << n) >> n\n cmp edx, eax\n jne overflow\n ; else EAX = x<<n without overflow\nRun Code Online (Sandbox Code Playgroud)\n(这部分答案是基于对规范的误读。)
\n如果您担心班次计数太大而导致换行,只需在移位之前检查班次计数即可。如果移位计数大于位数,则会发生溢出。(8 位和 16 位移位除外,如果需要,您可以移出所有位;对于 64 位以下的所有操作数大小,计数将被屏蔽为 5 位。)
\n通常您会为此检查标志。但是,您不能真正依赖它们SHL(或者SAL这是相同的指令)。查看软件开发人员手册或HTML 摘录:
\n\n受影响的标志
\nCF 标志包含从目标操作数移出的最后一位的值;对于计数大于或等于目标操作数的大小(以位为单位)的 SHL 和 SHR 指令,它是未定义的。OF 标志仅对 1 位移位产生影响(请参阅上面的 \xe2\x80\x9cDescription\xe2\x80\x9d);否则,它是未定义的。根据结果设置 SF、ZF 和 PF 标志。如果计数为 0,则标志不受影响。对于非零计数,AF 标志未定义。
\n
最好的方法是在移位之前确保字节操作的移位计数 <8,字操作的移位计数 <16,双字的移位计数 <32,四字的移位计数 <64。
\n使用 FLAGS 检测结果溢出:
\n如果移位计数不大于目标操作数,则可以检查 CF 标志以查看移出的最后一位。如果一次执行一位移位,则可以在每次移位后测试 CF,看看是否有 1 在任何点移出,这表明发生了溢出。
\n但这会检测到无符号溢出。要检测有符号-1溢出,当(0x...ff) 变为-2(0x...fe)时,这不是问题。但关键是符号位没有改变。根据实际有符号溢出对 OF 组进行 1 位移位,其中OF \xe2\x86\x90 MSB(DEST) XOR CF;
这仅适用于一次移位 1 位;x86 甚至没有为 1 以外的移位计数定义 OF 值,不幸的是没有记录在此过程中是否发生任何符号翻转。
\n