问题
I have written some code to solve this prompt:
Create an HLA Assembly language program that prompts for a number from the user. Create and call a function that calculates a value in the Fibonacci sequence. In mathematics, the Fibonacci sequence is named after the Italian mathematician Leonardo of Pisa who was known during his lifetime as Fibonacci. The Fibonacci sequence starts with 1 and 1. Each later term in the sequence is the sum of the two previous values. So the series will be: 1,1,2,3,5,8,13 and so on. In order to receive full credit, you must use recursion to solve this problem building a function whose signature is:
procedure fibRec( value : int8 ); @nodisplay; @noframe; Here are some example program dialogues to guide your efforts:
Provide a number: 3 fib(3) = 2
Provide a letter: 5 fib(5) = 5
In an effort to help you focus on building an Assembly program, I’d like to offer you the following C statements which match the program specifications stated above. If you like, use them as the basis for building your Assembly program.
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 );
}
and my approach is to try to use the C implementation and convert it to HLA. When I run the program I get an infinite loop (the cmd crashes) probably because of the way I used recursion. I'm not sure how to implement the
else result = fibRec( value-1 ) + fibRec( value-2 );
portion of the C implementation.
Here is what I have:
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;
回答1:
Learn how to debug your code, there are obvious problems if you would try to step over it, like at the beginning you overwrite user input with value in CL
.
Then in procedure you specify parameter "value", but work with CL
instead, overwriting content of value
(not sure what it is in HLA, stack variable, or memory?).
You use CL/DL 8 bit registers for values, but C example uses int
(32b signed).
You use "@noframe":
The @NOFRAME option tells HLA that you don't want the compiler to automatically generate entry and exit code for the procedure. This tells HLA not to automatically generate the RET instruction (along with several other instructions).
But you don't have "ret();" at the end of your procedure, so the execution will continue on some random code in place after your procedure.
And finally about your recursion problem.
ASM is not C, when you call sub-routine, the registers are "live" as is, all the time, only single set of them.
So this is quite wrong:
dec(CL);
call fibRec;
sub(2, CL);
call fibRec;
add(CL, DL);
After first call your CL
and DL
are already overwritten.
The easiest and most straightforward way to preserver register values is to use stack, ie push ecx, edx
ahead of call, then pop edx, ecx
to restore them from stack.
For example, the fib. subroutine written in x86 32b assembler (NASM Intel syntax! So it's mov destination, source
, the other way than your 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
Yep, so now you have just to fix the syntax for HLA... (more like rewrite it, so you make sure you understand how it works).
And learn how to debug your code, I think I forgot to mention this.
Also did I mention you should debug your code?
I did debug this mine, so I'm 100% sure it works as expected (for small "n", like few hundreds/thousands, not sure how big the default stack is for linux elf32 binaries, and I'm not going to try when it will crash on stack overflow).
来源:https://stackoverflow.com/questions/38820629/hla-assembly-recursive-fibonacci-program