gpt4 book ai didi

assembly - 为什么编译器在除以 2 时会产生 31 位的右移?

转载 作者:行者123 更新时间:2023-12-03 15:59:20 25 4
gpt4 key购买 nike

我反汇编了编译器生成的代码,我看到它生成了以下指令序列:

mov     eax, edx
shr eax, 1Fh
add eax, edx
sar eax, 1

这段代码的目的是什么?

我知道
sar     eax, 1

除以 2,但什么是
shr     eax, 1Fh

做?这是否意味着 EAX如果左位是 0 或 1,它将是 0 或 1?

这对我来说看起来很奇怪!有人可以解释一下吗?

最佳答案

快速回答您的问题—什么是 shr eax, 1Fh ——是为了隔离eax的最高位.如果您转换十六进制 1Fh 可能更容易理解到十进制 31 .现在,您看到您正在移动 eax 31 岁。自 eax是一个 32 位值,将其位右移 31 将隔离最高位,例如 eax将包含 0 或 1,具体取决于第 31 位的原始值(假设我们从 0 开始编号)。

这是隔离符号位的常用技巧。当一个值在二进制补码机上被解释为有符号整数时,最高位是符号位。如果值为负,则设置 (== 1),否则清除 (== 0)。当然,如果将该值解释为无符号整数,则最高位只是用于存储其值的另一位,因此最高位具有任意值。

逐行进行反汇编,这是代码的作用:

mov     eax, edx


显然,输入在 EDX .此指令复制来自 EDX 的值进入 EAX .这允许后续代码操作 EAX 中的值。不会丢失原件(在 EDX 中)。

shr     eax, 1Fh


换类 EAX右移 31 位,从而隔离最高位。假设输入值是一个有符号整数,这将是符号位。 EAX如果原始值为负,则现在将包含 1,否则为 0。

add     eax, edx


将原始值 ( EDX ) 添加到我们在 EAX 中的临时值中.如果原始值为负,则将其加 1。否则,它将添加 0。

sar     eax, 1


换类 EAX就在 1 个地方。这里的区别在于这是算术右移,而 SHR是逻辑右移。逻辑移位用 0 填充新暴露的位。算术移位将最高位(符号位)复制到新暴露的位。

综合起来, 这是将有符号整数值除以 2 的标准习惯用法,以确保正确舍入负值 .

当您将一个无符号值除以 2 时,只需要一个简单的位移位即可。因此:
unsigned Foo(unsigned value)
{
return (value / 2);
}

相当于:
shr  eax, 1

但是在对有符号值进行除法时,必须处理符号位。您可以使用 sar eax, 1实现有符号整数除以 2,但这将导致结果值向负无穷大舍入。请注意,这与 DIV 的行为不同。/ IDIV指令,它总是向零舍入。如果你想模拟向零舍入的行为,你需要一些特殊的处理,这正是你所拥有的代码所做的。事实上,当您编译以下函数时,GCC、Clang、MSVC 以及可能所有其他编译器都会准确地生成此代码:
int Foo(int value)
{
return (value / 2);
}

这是一个非常古老的技巧。 Michael Abrash 在大约 1990 年出版的《汇编语言禅》中讨论了这个问题。( Here is the relevant section 在他的书的在线副本中。)在此之前,这肯定是汇编语言大师的常识。

关于assembly - 为什么编译器在除以 2 时会产生 31 位的右移?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40638335/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com