【问题标题】:Incorrect calculation of mathematical equation in Assembly Language (Intel)汇编语言(英特尔)中数学方程的计算不正确
【发布时间】:2023-03-17 07:30:01
【问题描述】:

我有一个想用汇编语言建模的方程。我编写了以下代码,它在语法上是正确的,但在寄存器中产生了错误的结果。最终结果将存储在 DX 寄存器中。我正在建模的方程是:

DX = (AX2 + (AX-1) + 2 * (AX +2)) / 2

以下是英特尔微处理器的汇编语言代码:

[org 0x0100]
            jmp start

number:         db  02
multiplicand:   db  0
multiplier:     db  0
multiResult:    dw  0
squareResult:   dd  0


square:     mov   [multiplicand], AX
            mov   [multiplier], AX
            call  multi
            mov   AX, [multiResult]
            mov   [squareResult], AX
            ret


multi:          mov CL, 8
                mov BX, [multiplicand]
                mov DX, [multiplier]

carryCheck:     shr BX, 1
                jnc skip

                 add    [multiResult], BX


skip:           shl BX, 1
                dec CL
                jnz carryCheck
                ret


start:          mov AX, [number]
                call    square
                mov DX, [squareResult]
                sub byte[number], 1
                add DX, AX
                add byte[number], 2
                mov AX, [number]
                mov [multiplicand],AX
                mov byte[multiplier], 2
                call    multi
                add DX, [multiResult]
                shr DX, 1                   ; division by 2

            mov AX, 0x4c00              ;ending program
            int 0x21

【问题讨论】:

  • 当你使用调试器单步执行代码时,你能确定它失败的地方吗?
  • 你只有db字节存储但是读写AX和其他16位寄存器:冲突。 db ==> dw.
  • 为什么不在汇编代码中使用注释?
  • @WeatherVane 我应该使用所有的 dw 吗?
  • DX square 计算的 m.s 字怎么了?毕竟,你已经分配了 4 个字节的存储空间。

标签: assembly nasm dos microprocessors x86-16


【解决方案1】:

你把这种方式弄得太复杂了。首先,将表达式简化为更容易计算的表达式

(AX*AX + (AX-1) + 2 * (AX+2)) / 2;
(AX*AX + AX + 2*AX - 1 + 2) / 2
(AX*AX + 3*AX + 1) / 2
(AX*(AX+3) + 1) / 2

这很容易实现:

mov   dx, ax
add   dx, 3      ; dx = ax+3

mul   dx         ; dx:ax = ax * (ax+3)

inc   ax         ; ignore the high-half of the mul result in DX.
shr   ax, 1

mov   dx, ax     ; apparently you want the result in DX?

或者您应该保留 32 位临时文件?如果是这样,使用 ADD/ADC 将 1 添加到 DX:AX。如果您使用的是emu8086或其他东西,那么您不能使用SHRD将一点从DX转移到AX。因此,您可以使用 SHR 将位移出 DX,并使用 RCR 将该位移入 AX。

如果你这样做,你还需要保存 AX+3 的结转。


顺便说一句,您可以轻松地向编译器询问想法。不过,gcc 并没有真正做到纯 16 位,并且在 32 位模式下编译 32 位 unsigned 时,它以 16 位寻址模式不支持的方式使用 LEA。但这里是what I tried on Godbolt


如果您想修复原始代码,请使用调试器。 IDK 为什么你要在任何事情上进行分支,或者将内存用于任何事情,并且没有 cmets。

【讨论】:

    【解决方案2】:

    carryCheck: 标签处,指令shr BX, 1 应为shr DX, 1

    【讨论】:

    • 正如 Weather Vane 在 cmets 中所指出的,当单词值被写入带有字节间隔标签的地址时,也存在变量修饰的可能性。代码(如所写)将正确的值写入地址,但如果 square: 标签处的两条 mov 指令的顺序颠倒,结果将不正确。
    猜你喜欢
    • 2018-10-10
    • 2012-10-22
    • 1970-01-01
    • 2020-07-31
    • 2021-02-06
    • 1970-01-01
    • 1970-01-01
    • 2011-02-14
    • 1970-01-01
    相关资源
    最近更新 更多