0

我正在尝试在汇编中编写递归组合函数( Yasm(类似于 nsam))。我不能使用循环、乘法或除法。

我确定我在正确的轨道上,但是一旦我点击第二个内部函数调用就会遇到问题。谁能帮助我并告诉我哪里出错了?

编辑:这是我更新的代码,它返回一个结果,但并不总是正确的。我想我一定有一点逻辑不正确。

    mov     rax, [n]
    push    rax
    mov     rax, [k]
    push    rax
    call    func    
    ...     ...     program continues from here

 func:                      
    push    rbp 
    mov     rbp, rsp

    push    rdi
    push    rsi

    cmp     rsi, 0
    je      stopcond
    cmp     rdi, rsi
    jne     contin

stopcond:
    mov     rax, 1
    jmp     endfunc
contin:
    ;C(n-1,k-1)
    mov     rax, [rsp]  ; This is k
    dec     rax
    mov     rdx, rax
    mov     rax, [rsp+8]  ; This is n
    dec     rax
    mov     rsi, rdx
    mov     rdi, rax
    call    func

    mov     rbx, rax
    mov     rax, [rsp+8]  ; This is n
    dec     rax
    mov     rdx, rax
    mov     rax, [rsp]  ; This is k
    mov     rsi, rax
    mov     rdi, rdx
    call    func

    add     rax, rbx

endfunc:
    add     rsp, 16
    pop     rbp
    ret

这是我一直用作参考的 javascript 实现

function(n,k) {
    if ( k==0 || k==n ) {
        return 1
    } else {
        return C(n-1,k-1) + C(n-1,k)
    }
}
4

1 回答 1

2
  1. C(n-1,k)调用不正确,因为两者和raxrbx已经递减,递归调用无论如何都会破坏它们的值。简单的解决方法是从堆栈中重新加载参数。
  2. 类似地,递归调用将rdx用于它自己的临时,从而覆盖调用者的副本。解决方案:您应该在堆栈上分配一个局部变量,并将其用作临时存储。
  3. 您没有恢复堆栈指针。在endfunc您应该插入一个mov esp, ebp.
  4. 您没有遵循通常的调用约定。如果您同意来电者的意见,这不是问题,但这样做可能仍然是一个好主意。您可以在wikipedia上获得快速概览。

PS:通常的建议适用:学习使用调试器,这样您就可以修复自己的错误。

于 2014-05-29T10:59:06.170 回答