【问题标题】:What is the purpose of ADD BX,2 in this code?这段代码中 ADD BX,2 的目的是什么?
【发布时间】:2019-03-26 09:26:37
【问题描述】:

我试图理解这个递归代码,但我对add bx, 2 的用途感到困惑。我已经在相关行上做了标记。据我了解,我们必须用值递增指向数组的指针,但为什么我们要添加 2 而不是 1?

    .model small
    .stack 100
    .data
     arr dw 38, 39, 90, 94, 13, 24, 53, 59, 63
     size dw 9
     result dw ?
    .code
    func proc
     push bp
     mov bp, sp
     push ax
     push bx
     push cx
     push dx
     mov cx, [bp+4]
     mov bx, [bp+6]
     mov ax, [bx]
     cmp cx, 1
     ja more
     mov [bp+6], ax
     jmp done
    more:

     **add bx, 2**

     push bx
     dec cx
     push cx
     call func
     pop dx
     cmp dx, ax
     jg greater
     mov [bp+6], ax
     jmp done
    greater:
     mov [bp+6], dx
    done:
     pop dx
     pop cx
     pop bx
     pop ax
     pop bp
     ret 2
    func endp

【问题讨论】:

    标签: arrays recursion assembly x86-16


    【解决方案1】:

    据我了解,我们必须用值递增指向数组的指针,但为什么我们要添加 2 而不是 1?

    如果我理解正确,BX 指向包含 16 位值的数组中的元素地址。

    指令mov ax, [bx] 显示元素是 16 位值,而不是 8 位或 32 位值。一个 16 位的值是 2 个字节长。

    在大多数 CPU(TMS 320 或 TMS 9900 等例外)上,如果元素为 n 字节长,则数组中两个元素的地址之间的差异为 n

    因此,如果x 是包含 16 位值的数组中元素的地址,y 是下一个元素的地址,则 y-x=2

    因此必须在BX 中添加两个才能获得下一个元素的地址。

    【讨论】:

    • 谢谢!现在我明白了,因为数组的每个元素都是单词而不是字节!
    【解决方案2】:

    注意后面的push bx / ... / call func:这是一个递归函数,它会将bx+2 传递给下一次调用。

    我认为 BX 被用作指针,并且有一个 arr 是一个“单词”数组(2 个字节),所以这几乎可以肯定是一个指针增量。

    这看起来非常效率低下;它只是单递归的,所以它可以很容易地写成一个循环。例如C 中的do { something with *p++; } while(--cx);,即底部带有dec cx / jnz 的循环。

    分支也很愚蠢:它可以在保存尽可能多的寄存器之前更早地检查递归终止条件。它可以通过使用jna donejmp 带出函数的正常路径。也许它需要在函数末尾跳转到一个特殊块,在特殊路径上放置 2 次跳转,但这仍然比在主路径上进行 2 次跳转要好。

    将内容存储/重新加载到[bp+6] 也很奇怪。此函数是否通过修改堆栈中的一个参数返回?在通话之后,它看起来就是基于pop dx。我希望这是故意混淆的,或者写为优化的起点,因为这看起来过于复杂。

    根据分支目标名称,我假设它只是在给定指针和长度的情况下在数组中找到最大有符号字。这很简单,但使用循环会大大提高效率。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-07-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-10-24
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多