程序集x86:我必须编写Ackermann函数

Exn*_*Exn 2 x86 assembly

我需要编写Ackermann函数.这是我到目前为止:

    .model small
;
    extrn   putstrng:far
    extrn   newline:far
    extrn   getdec$:far
    extrn   putdec$:far
; 
;
    .stack 1024                  
;
    .const


    .data

    .code
    assume ds:dgroup
;
debut:  mov     ax, seg dgroup     
    mov     ds, ax
    mov     es, ax
;

    mov     ax,2   ; value of N
    mov     bx,ax
    mov     ax,2 ; Value of M
    mov     dx,ax
    mov     cx,0

    push    dx
    push    bx

    call ackermann

    pop     bx
    pop     dx

    MOV ax, 0
    MOV ax, cx
call    putdec$
call    newline


    mov     ax, 4c00h          
    int     21h

ackermann   proc far C uses cx

    mov dx, [bp+6] 
    mov bx, [bp+4]
    cmp bx, 0
    JE firstCase
    cmp dx, 0
    JE secondCase
    dec dx
    push dx
    push bx
    CALL ackermann
    pop bx
    pop dx
    dec bx
    push dx
    push bx
    CALL ackermann
    pop bx
    pop dx
    ret


firstCase:
    MOV cx, dx
    inc cx
    ret


secondCase:
    DEC bx
    push dx
    push bx
    call ackermann
    pop bx
    pop dx
    ret

ackermann endp

    end     debut
Run Code Online (Sandbox Code Playgroud)

无论我为N或M的价值做什么,我总能得到答案0.我想我知道为什么.这部分 :

MOV ax, 0
MOV ax, cx
call    putdec$
call    newline
Run Code Online (Sandbox Code Playgroud)

可能是错的,但我不知道该怎么做.

任何帮助将不胜感激.

谢谢.

pax*_*blo 5

假设您的Ackermann函数实际工作并将其结果留在cx寄存器中,并在寄存器中putdec$打印该值ax,那么您所显示的代码段绝对没有问题.

ax首先将零加载到第一个,然后用它替换它cx.

因此,您的问题在于:

  • putdec$不打印ax.
  • 您的Ackermann功能无法正常工作.
  • 你的Ackermann函数没有返回它的值cx.

第一步是启动调试器并在mov ax, 0指令处设置断点- 这将告诉您cx(和其他寄存器)中的值是什么来检查Ackermann功能是否正常工作.

然后,您可能需要返回并单步执行该功能,将其与您期望在每个阶段使用纸张和铅笔进行比较.


通过一些静态代码分析,以及对Ackermann函数实际意图做什么的快速调查:-),我可以看出以下内容:

有一两件事我不知道你有正确的(如果你使用的阿克曼函数的定义,维基百科这里)是第二种情况.它指出:

         /  n + 1             if m = 0
A(m,n) = |  A(m-1,1)          if m > 0 and n = 0
         \  A(m-1,A(m,n-1))   if m > 0 and n > 0
Run Code Online (Sandbox Code Playgroud)

您的第二个案例代码bx/m按预期递减,但dx/n单独留下,而不是将其设置为1.

在你的第三种情况下(虽然我没有仔细查看)你确实调用了两次函数,但是现在我可以看到cx第一次内部A()调用的结果转移到外部堆栈的任何一个寄存器中呼叫.这将是计算嵌套函数的关键步骤A(x,A(y,z)).

相反,您的外部呼叫似乎使用原始值的某些变体.

这两个有用的指针应该是一个良好的开端,磨练你的调试技巧,成为一个更好的开发人员:-)