x86 左移算术溢出控制
您知道有什么方法可以有效地检查 x86 左移算术上是否发生溢出/下溢吗?
Do you know any way to efficient check if overflow/underflow occurs on x86 left shift arithmetically?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
一个好的选择是在左移后右执行算术移位,看看是否得到相同的数字:
BMI2 3操作数移位可以节省一些
mov
指令:(这部分答案是基于误读的规格。)
如果您担心班次计数太大而导致换行,只需在移位之前检查班次计数即可。如果移位计数大于位数,则会发生溢出。 (8 位和 16 位移位除外,如果需要,您可以移出所有位;对于低于 64 位的所有操作数大小,计数被屏蔽为 5 位。)
通常您会检查标志。但是,您不能真正依赖它们来执行
SHL
(或SAL
,这是相同的指令)。查看软件开发人员手册,或HTML 摘录:最好的方法是在移位之前确保字节操作的移位计数 <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:
BMI2 3-operand shifts can save some
mov
instructions:(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
(orSAL
which is the same instruction). Look at the Software Developer's Manual, or an HTML extract: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, withOF ← 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.