在此代码中添加BX,2的目的是什么?

时间:2019-03-26 09:26:37

标签: arrays recursion assembly x86-16

我试图理解此递归代码,但对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

2 个答案:

答案 0 :(得分:4)

  

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

如果我理解正确,gap' :: Eq a => a -> a -> [a] -> Maybe Int gap' x y ls | null ls' = Nothing | head ls' == y = Nothing | otherwise = elemIndex y ls' where ls' = dropWhile (\t -> t /= x && t /= y) ls 指向包含16位值的数组中元素的地址。

指令BX向您显示元素是16位值,而不是8位或32位值。 16位值是2个字节长。

在大多数CPU(有TMS 320或TMS 9900之类的例外)上,如果元素的长度为mov ax, [bx]个字节,则数组中两个元素的地址之差为n

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

因此必须将两个添加到y-x=2中以获取下一个元素的地址。

答案 1 :(得分:1)

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

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

这看上去非常效率低下;它只是单个递归,因此很容易将其编写为循环。 C中的do { something with *p++; } while(--cx);,即底部为dec cx / jnz的循环。

此外,分支非常愚蠢:它可以在保存尽可能多的寄存器之前更早地检查递归终止条件。使用jmp可以使jna done脱离函数的正常路径。也许需要在函数末尾跳转到一个特殊的块,在特殊情况下将2个跳转放在特殊情况下,但这仍然比在主路径上进行2个跳转要好。

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

基于分支目标名称,我假设它只是在给定指针和长度的情况下在数组中找到最大带符号的单词。这样做很简单,而且循环效率更高。