【问题标题】:Assembly partial registers汇编部分寄存器
【发布时间】:2016-03-08 16:49:19
【问题描述】:

我已阅读有关部分寄存器的说明 并想了解为什么这段代码:

XOR EAX,EAX
MOV AX, BX

仅当 eax 持有无符号正数时才有效 但是如果eax中有一个带符号的负数 您需要确保您添加的新位是 111 ..,我知道它与二进制补码有关 但是还是没看懂。

编辑:

我知道上面的代码可以使用任何一种方式 我想了解您为什么需要填充那些额外的 1(当我不将 eax 归零时)

【问题讨论】:

  • EAX 中的内容无关紧要,因为它会归零。重要的是BX 中的内容。大概您所说的是将BX 扩展为EAX 的符号,但是此代码执行零扩展。对于非负数当然等同于符号扩展,因为符号位是0
  • 您实际上应该在这里做的是movzx eax, bxmovsx eax, bx,用于零或符号扩展。或者,这是您推理哪些序列与哪些指令等效的参考点。
  • 其实我想了解 movzx 的用法,我的意思是为什么你甚至需要填充那些额外的 1s
  • 如果您不将eax 归零,那么上半部分的任何内容都会保留在那里。它甚至可能不全是零或一,所以不知道生成的 32 位数字是什么。一个 16 位数字符号扩展到 32 位将在上半部分有一个符号位的副本,对于负数全为 1,否则全为零。
  • 如果要将窄整数用作数组索引或其他内容,则需要进行零扩展或符号扩展。例如int foo(short a) { return LUT[a]; } 需要将 a 符号扩展为 32 位寄存器,以便您可以在 32 位或 64 位有效地址中使用它,例如 [LUT + eax*4]。如果a 未签名,则您将进行零扩展。

标签: assembly x86 cpu-registers


【解决方案1】:

通常情况下,您在手写汇编时使用无符号数字。当然,情况并非总是如此,C 的int 促销应该以某种方式实现,对吧?

让我们从解释位级别的二进制补码开始。首先,最高位在设置时表示负数,在清除时表示非负 nne。如果很清楚,这些东西会按照您的预期运行。即0写成0x000000002147483647写成0x7FFFFFFF。然而,对于任何负数N,为了得到它的绝对值,你必须做~N-1,以及所有各自的环绕。这导致-1 被写成0xFF,而-2147483648 被写成0x80。这有一些很好的副作用,例如-0 == 0 和加法/减法对于所有数字都是相同的操作。

现在,你的代码......

XOR EAX,EAX

作为一个数学规则,对某事物进行异或运算总是会产生零作为结果。所以,你可以把它想象成一个优化的“MOV EAX, 0”。顺便说一句,您可能想阅读why XOR is better for this。那么……

MOV AX, BX

MOV 是一条指令,字面意思是“按原样复制位”。即,源中所有清零的位分别在目的中清零,源中所有置位的位分别在目的中置位。在这种情况下,AX 现在将包含BX 内容的精确副本。在x86架构中,EAXEBXECXEDX都是这样划分的……

 ________________ ________ ____ ____
|      ERX       |   RX   | RH | RL |
|________________|________|____|____|
 \_________________________________/
          |       \________________/
      32 bits              |    \__/
                       16 bits   ||
                               8 bits

这意味着对于每个寄存器RERX 表示其所有 32 位,RX 表示其低 16 位,RH 表示其低 16 位的高字节,RL 表示其低 16 位的低字节。因此,返回您的代码,并假设 BX 包含 0xFFFF-1 在二进制补码中),这就是发生的事情......

 ______________ __________________________________ __________________________________
| Instruction  | EAX                              | EBX                              |
|______________|__________________________________|__________________________________|
| XOR EAX, EAX | 00000000000000000000000000000000 | 00000000000000001111111111111111 |
|______________|__________________________________|__________________________________|
| MOV AX, BX   | 00000000000000001111111111111111 | 00000000000000001111111111111111 |
|______________|__________________________________|__________________________________|

那么,如果我们将AX解释为二进制补码,我们就会得到正确的答案,即-1。但是,如果我们将EAX 解释为二进制补码,我们会得到一个错误答案,65535。为了正确地做到这一点,我们必须做一个符号扩展移动。这意味着该指令将考虑该值是二进制补码形式的事实,因此将正确操作它。例如,请参阅...

 _______________ __________________________________ __________________________________
| Instruction   | EAX                              | EBX                              |
|_______________|__________________________________|__________________________________|
| MOVSX EAX, BX | 11111111111111111111111111111111 | 00000000000000001111111111111111 |
|_______________|__________________________________|__________________________________|

现在,将 EAX 解释为 32 位二进制补码将产生正确答案 -1。这是(还)二进制补码的另一个优点。您可以根据需要多次复制最高位来进行符号扩展。

【讨论】:

  • This explains why xor-zeroing is better than mov reg, 0。您可能希望将该链接合并到您的答案中。此外,x86 标记 wiki 有一些指向寄存器图的链接,例如您为单个寄存器创建的 ASCII 图表。
  • @PeterCordes:已编辑。谢谢!
  • 为什么在版主删除I hope this has led a light on you! 后,您还要继续添加它?这甚至不是一个有意义的英语句子。您可以说“我希望这对您的问题有所启发”,即阐明/澄清了以前不清楚/难以看到的内容。但这听起来不是很酷。我想不出一个好的方法来表达我认为你想说的话。我认为无论如何都是多余的。每个发布答案的人都这样做是为了帮助人们。无论是提出问题的人,还是更经常地帮助将来阅读它的其他人。
  • @PeterCordes:我不打算扭转它。这……有点乱。撤消该操作。
猜你喜欢
  • 2021-03-25
  • 2016-11-11
  • 1970-01-01
  • 1970-01-01
  • 2012-01-02
  • 2012-01-11
  • 2014-04-25
  • 2011-01-22
  • 2014-04-04
相关资源
最近更新 更多