【问题标题】:Recursive Pascal's triangle (Combination func) Assembly递归帕斯卡三角(组合函数)汇编
【发布时间】:2014-05-29 10:30:16
【问题描述】:

我正在尝试在汇编中编写一个递归组合函数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)
    }
}

【问题讨论】:

  • 如果这是您的所有代码,那么当func 最终返回时您将遇到问题,因为func: 直接跟随call func
  • 这就是我的想法,但是当我查看此int func(int n,int k){if(k==0||k==n){return 1;}else{return func(n-1,k-1)+func(n-1,k);}} 此处assembly.ynh.io 的c->汇编转换时,他们做了非常相似的事情@Michael
  • 该 C 代码不包括对 func 的初始调用。
  • 这就是这里,唯一有趣的是它把nk分别放入ediesiint func(int n,int k){if(k==0||k==n){return 1;}else{return func(n-1,k-1)+func(n-1,k);}}int main(){int a=func(3,2);return 0;}
  • 如果您在该网站上查看程序集输出,需要注意的一些重要事项是 A) 从 mainfunc 的调用位于 之后 func 的主体,而不是像您的代码中那样在它之前,并且 B)在 func 返回到 main 之后,有一个 ret 返回到调用 main 函数的 C 运行时。

标签: assembly recursion x86-64 pascals-triangle yasm


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

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

【讨论】:

  • 太棒了。我正在查看 C 等效程序的汇编输出,并且可以看到正在使用的某些约定。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-08-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多