x86 左移算术溢出控制

发布于 2024-12-04 06:56:53 字数 43 浏览 1 评论 0原文

您知道有什么方法可以有效地检查 x86 左移算术上是否发生溢出/下溢吗?

Do you know any way to efficient check if overflow/underflow occurs on x86 left shift arithmetically?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

回首观望 2024-12-11 06:56:53

一个好的选择是在左移后执行算术移位,看看是否得到相同的数字

    mov ebx, eax      ; keep a copy of the original
    sal eax, cl         ;  TODO: also copy the shifted EAX somewhere
    sar eax, cl
    cmp ebx, eax      ;  (x << n) >> n == x
    jne overflow
 ; result: not stored anywhere by this snippet.

BMI2 3操作数移位可以节省一些mov指令:(

; input: x in EDI, shift count n in ESI
    shlx  eax, edi, esi       ; there is no salx, it's the same operation
    sarx  edx, eax, esi       ; (x << n) >> n
    cmp   edx, eax
    jne   overflow
   ; else EAX = x<<n  without overflow

这部分答案是基于误读的规格。)

如果您担心班次计数太大而导致换行,只需在移位之前检查班次计数即可。如果移位计数大于位数,则会发生溢出。 (8 位和 16 位移位除外,如果需要,您可以移出所有位;对于低于 64 位的所有操作数大小,计数被屏蔽为 5 位。)

通常您会检查标志。但是,您不能真正依赖它们来执行 SHL(或 SAL,这是相同的指令)。查看软件开发人员手册,或HTML 摘录

受影响的标志

CF 标志包含从目标操作数移出的最后一位的值;对于计数大于或等于目标操作数的大小(以位为单位)的 SHL 和 SHR 指令,它是未定义的。 OF 标志仅对 1 位移位产生影响(参见上面的“说明”);否则,它是未定义的。根据结果​​设置 SF、ZF 和 PF 标志。如果计数为 0,则标志不受影响。对于非零计数,AF 标志未定义。

最好的方法是在移位之前确保字节操作的移位计数 <8、字的移位计数 <16、双字的移位计数 <32、四字的移位计数 <64。


使用 FLAGS 检测结果溢出:

如果移位计数不大于目标操作数,则可以检查 CF 标志以查看移出的最后一位。如果一次执行一位移位,则可以在每次移位后测试 CF,看看是否有 1 在任何点移出,这表明发生了溢出。

但这会检测到无符号溢出。要检测有符号溢出,当 -1 (0x...ff) 变为 -2 (0x...fe) 时就不是问题。但关键是符号位没有改变。改变。根据实际有符号溢出对 OF 进行 1 位移位,OF ← MSB(DEST) XOR CF;

这只适用于一次移位 1 位; x86 甚至没有为 1 以外的移位计数定义 OF 值,不幸的是没有记录在此过程中是否发生任何符号翻转。

A good option is to perform an arithmetic shift right after the shift left and see if you got the same number:

    mov ebx, eax      ; keep a copy of the original
    sal eax, cl         ;  TODO: also copy the shifted EAX somewhere
    sar eax, cl
    cmp ebx, eax      ;  (x << n) >> n == x
    jne overflow
 ; result: not stored anywhere by this snippet.

BMI2 3-operand shifts can save some mov instructions:

; input: x in EDI, shift count n in ESI
    shlx  eax, edi, esi       ; there is no salx, it's the same operation
    sarx  edx, eax, esi       ; (x << n) >> n
    cmp   edx, eax
    jne   overflow
   ; else EAX = x<<n  without overflow

(This part of the answer is based on a misreading of the spec.)

If you're worried about the shift-count being so large it wraps, just check the shift count before shifting. If the shift count is greater than the number of bits, you'll get an overflow. (Except with 8 and 16-bit shifts, where you can shift out all the bits if you want; the count is masked to 5 bits for all operand-sizes below 64-bit.)

Usually you'd check the flags for this. However, you can't really rely on them for SHL (or SAL which is the same instruction). Look at the Software Developer's Manual, or an HTML extract:

Flags Affected

The CF flag contains the value of the last bit shifted out of the destination operand; it is undefined for SHL and SHR instructions where the count is greater than or equal to the size (in bits) of the destination operand. The OF flag is affected only for 1-bit shifts (see “Description” above); otherwise, it is undefined. The SF, ZF, and PF flags are set according to the result. If the count is 0, the flags are not affected. For a nonzero count, the AF flag is undefined.

The best way is to ensure that the shift count is <8 for byte operations, <16 for words, <32 for doublewords and <64 for quadwords, before shifting.


For detecting overflow of the result using FLAGS:

If the shift count is not greater than the destination operand, you can check the CF flag to see the last bit shifted out. If you perform the shift one bit at a time, you can test the CF after each shift to see if there was a 1 shifted out at any point, which would indicate an overflow.

But that would detect unsigned overflow. To detect signed overflow, it's not a problem when -1 (0x...ff) becomes -2 (0x...fe). But the key is that the sign bit didn't change. 1-bit shifts set OF according to actual signed overflow, with OF ← MSB(DEST) XOR CF;

This only works for shifting 1 bit at a time; x86 doesn't even define the value of OF for shift counts other than 1, unfortunately not recording whether any sign-flips happened along the way.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文