我已经写了一些代码来解决这个提示:
创建一个HLA汇编语言程序,提示用户输入一个号码。创建并调用一个计算Fibonacci序列中的值的函数。在数学方面,斐波那契序列以意大利数学家比萨莱昂纳多命名,他在生命中被称为斐波那契。 Fibonacci序列以1和1开始。序列中的每个后续项都是前两个值的总和。所以系列将是:1,1,2,3,5,8,13等。为了获得完全信用,您必须使用递归来解决此问题,构建一个签名为:
的函数procedure fibRec(value:int8); @nodisplay; @noframe; 以下是一些示例程序对话来指导您的工作:
提供一个数字: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崩溃)可能是因为我使用递归的方式。我不确定如何实现
否则 result = 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;
答案 0 :(得分:1)
了解如何调试代码,如果您尝试跳过代码,则会出现明显的问题,例如在开始时使用CL
中的值覆盖用户输入。
然后在过程中指定参数“value”,但是改为使用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);
首次通话后,您的CL
和DL
已被覆盖。
保存寄存器值的最简单,最直接的方法是在调用之前使用堆栈,即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二进制文件有多大,而且我是不会尝试它会在堆栈溢出时崩溃。)