-3

我写了一些代码来解决这个提示:

创建一个提示用户输入数字的 HLA 汇编语言程序。创建并调用计算斐波那契数列中的值的函数。在数学中,斐波那契数列以意大利数学家比萨的莱昂纳多命名,他生前被称为斐波那契。斐波那契数列从 1 和 1 开始。数列中的后一项是前两个值的总和。所以系列将是:1,1,2,3,5,8,13 等等。为了获得完整的信用,您必须使用递归来解决这个问题,构建一个签名为:

程序 fibRec(值:int8);@无显示;@无框; 以下是一些示例程序对话来指导您的工作:

提供一个数字:3 fib(3) = 2

提供一个字母:5 fib(5) = 5

为了帮助您专注于构建汇编程序,我想为您提供以下符合上述程序规范的 C 语句。如果您愿意,可以将它们用作构建您的汇编程序的基础。

SAMPLE C CODE:
------------------------
int main( )
{
  int value;
  printf( "Provide a value: " );
  scanf( "%d", &value );
  int f = fibRec( value );
  printf( "fib( %d ) = %d\n", value, f );
  return( 0 );
}

int fibRec( int value ) 
{
    int result = 1; 
    if (value == 1 || value == 2)   // base case
       result = 1;
    else 
       result = fibRec( value-1 ) + fibRec( value-2 );
    return( result );
}

我的方法是尝试使用C实现并将其转换为HLA。当我运行程序时,我得到一个无限循环(cmd 崩溃),这可能是因为我使用递归的方式。我不确定如何实施

否则结果 = fibRec(value-1) + fibRec(value-2);

C 实现的一部分。

这是我所拥有的:

program fib;
#include("stdlib.hhf");

static
        value : int8; 
        //returnAddress : dword;
        //temp: int16;


procedure fibRec( value : int8 ); @nodisplay; @noframe; 

begin fibRec;

        mov(CL, value);
        mov(1, DL);

        cmp(CL, 1);
        je Res1;
        cmp(CL, 2);
        je Res1;

        jmp Else1;

        //else result = fibRec( value-1 ) + fibRec( value-2 );
Else1:

        //mov(1, DL);

        dec(CL);
        call fibRec;

        sub(2, CL);
        call fibRec;

        add(CL, DL);

        jmp ProgExit;

Res1:
        mov(1, DL);
        jmp ProgExit;

ProgExit:


end fibRec;


/////////////////////////////////////////////////////////////////////////////////////////////////////

begin fib;

    stdout.put( "Provide a value: " );
    stdin.get(value); //CHANGED TO IVALUE

    mov(CL, value); //SAVES THE INPUT TO A REGISTER


    call fibRec; // MUST CALL THE PROCEDURE
    stdout.put("fib(");
    stdout.puti8(value);
    stdout.put(") = ");
    stdout.put(DL);



end fib;
4

1 回答 1

1

学习如何调试你的代码,如果你试图越过它,就会有明显的问题,比如一开始你用 in 的值覆盖用户输入CL

然后在过程中指定参数“值”,但CL改为使用覆盖内容value(不确定它在 HLA、堆栈变量或内存中是什么?)。

您将 CL/DL 8 位寄存器用于值,但 C 示例使用int(32b 有符号)。

您使用“@noframe”:

@NOFRAME 选项告诉 HLA 您不希望编译器自动生成过程的进入和退出代码。这告诉 HLA 不要自动生成 RET 指令(以及其他几条指令)。

但是你没有“ret();” 在您的程序结束时,因此将在您的程序之后继续执行一些随机代码。

最后是关于你的递归问题。

ASM 不是 C,当您调用子程序时,寄存器一直是“活的”,一直只有一组。

所以这是完全错误的:

    dec(CL);
    call fibRec;
    sub(2, CL);
    call fibRec;
    add(CL, DL);

在第一次打电话给你之后CLDL已经被覆盖了。保存寄存器值的最简单和最直接的方法是使用堆栈,即push ecx, edx在调用之前,然后pop edx, ecx从堆栈中恢复它们。

例如,fib。用 x86 32b 汇编程序编写的子例程(NASM Intel 语法!所以它是mov destination, source,与您的 HLA 不同的方式!):

fibRecursion:
    ; expects unsigned "n" (1+) in eax, returns fibonacci(n) in eax
    ; will crash on large "n" due to stack overflow
    cmp   eax,2
    ja    moreThanTwo
    mov   eax,1         ; n: 0, 1 and 2 returns "1"
    ret
moreThanTwo:
    push  edx           ; preserve edx
    dec   eax
    push  eax           ; store n-1 in stack
    call  fibRecursion  ; eax = fib(n-1)
    xchg  eax,[esp]     ; store fib(n-1) in stack, get n-1 into eax
    dec   eax
    call  fibRecursion  ; eax = fib(n-2)
    pop   edx           ; edx = fib(n-1)
    add   eax,edx       ; eax = fib(n) = eax+edx
    pop   edx           ; restore edx
    ret

是的,所以现在你只需要修复 HLA 的语法......(更像是重写它,所以你要确保你理解它是如何工作的)。

并学习如何调试您的代码,我想我忘了提及这一点。

我还提到你应该调试你的代码吗?

我确实调试了这个我的,所以我 100% 确定它按预期工作(对于小的“n”,比如几百/几千,不确定 linux elf32 二进制文件的默认堆栈有多大,我不会尝试它何时会因堆栈溢出而崩溃)。

于 2016-08-08T06:48:06.977 回答