【问题标题】:Arithmetic operations not yielding expected result [duplicate]算术运算未产生预期结果[重复]
【发布时间】:2021-06-11 11:59:25
【问题描述】:

以下代码打印值:-83396
我在这里做的计算是Z2 = (var3 – var2 - 1000) + (var1 – 500)
所以 Z2 = (FFFF0000h - 4000h- 1000) + (24 - 500)
我不确定结果如何是-83396?我只是存储值
在寄存器中为 var2、var3 计算

.386
.model flat,stdcall
.stack 4096
ExitProcess proto,dwExitCode:dword

INCLUDE Irvine32.inc

.data
var1    byte    24
var2    word    4000h
var3    dword   0FFFF0000h
Z1    dword    ?
Z2    dword    ?
Z3    dword    ?
Z4    dword    ?

.code
main proc
xor eax,eax
xor ebx,ebx

mov eax, var3
movzx ebx, var2
sub eax, ebx
xor ebx,ebx
sub eax, 1000

xor ebx, ebx
movzx ebx, var1
sub ebx, 500
add eax, ebx
mov Z2, eax
call writeint




clc
invoke ExitProcess,0
main endp
end main

【问题讨论】:

  • 根据我的计算器,这是正确的答案(使用(0xFFFF0000 - 0x4000- 1000) + (24 - 500) - 2**32 将其包装到有符号整数范围内);你期望它是什么? FFFF0000h-65536 的 2 的补码位模式;也许你不知道? IDK 还有什么其他原因会让您对答案感到惊讶,因此作为问答的副本结束。
  • 另外,您没有存储var2var3,而是将它们作为输入加载到寄存器中。

标签: assembly masm twos-complement


【解决方案1】:

这是因为您的结果值被视为二进制补码。

作为二进制补码的值ffff0000<sub>16</sub>-65,536。减去4000<sub>16</sub> (16,384),然后再减去1,000。然后加上24 并减去500。这会给你-83,396正是你所看到的。

但是,即使它们一路上都是未签名的,将 result 视为已签名(1) 会给您同样的问题(这些都是十六进制数字除了括号中的):

  ffff0000
-     4000  (16,384)
==========
  fffec000
-      3e8  (1,000)
==========
  fffebc18
+       18  (24)
==========
  fffebc30
-      1f4  (500)
==========
  fffeba3c

在 32 位 2 的补码中,最终值将是(全部为十六进制):

  - (100000000 - fffeba3c)
= - 145c4

145c4<sub>16</sub>83,396


(1) 二进制补码的一大特点是用于加法或减法的位操作方式与相同大小的无符号值的操作方式完全相同。

【讨论】:

  • WriteInt 将结果视为有符号的 int32_t,而不是无符号数;为此使用 Irvine32 WriteDecWriteHex。 (csc.csudh.edu/mmccullough/asm/help/…)
  • 请注意,唯一的“视为 2 的补码”发生在打印期间。其他一切都是零扩展至 32 位,或者已经是 32 位。 addsub 不会以任何会产生影响的方式“视为 2 的补码”:您同样可以将问题的结果描述为仅进行无符号数学运算(包括一个接近 UINT_MAX 的大输入),包装到uint32_t 寄存器宽度,然后将该结果作为int32_t 传递给WriteInt。除了 FLAGS 设置之外,在打印步骤之前不会发生“解释”或“处理”。
  • 所以是writeint 赋予了 2 的补码的含义,所以我的理解是,没有任何指令假设与 2 的补码等有任何关系。它们只是添加或减去。我还认为减法就像 ALU 中的加法一样完成。但似乎 sub 指令在内部执行实际减法似乎是错误的,并且具有借用 n 的逻辑。因此,当执行sub 时,该数字不会转换为 2 的补码形式,它只会执行二进制减法。对吗?
  • @ravan:你无法真正说出 ALU 在内部是如何工作的。 FLAGS(OF 和 CF)根据实际减法设置,CF 是最高有效位的借位输出。但是通过添加-x(如果需要,可以计算为~x + 1)的内部实现将在输出寄存器中产生相同的32位二进制结果;请记住,输出总是被截断以适应操作数大小。 位如何到达那里(添加负数与减去)并不重要,重要的是您如何解释它们。(因为您没有查看 FLAGS 位)。
  • @PeterCordes:“它在哪里将其视为已签名?”问题。已相应地更新了答案,希望能更清楚。
猜你喜欢
  • 2020-08-10
  • 1970-01-01
  • 1970-01-01
  • 2019-03-07
  • 1970-01-01
  • 2012-01-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多