Программа рекурсивной Фибоначчи HLA-сборки
Я написал код для решения этой подсказки:
Создайте программу на языке ассемблера HLA, которая запрашивает у пользователя номер. Создайте и вызовите функцию, которая вычисляет значение в последовательности Фибоначчи. В математике последовательность Фибоначчи названа в честь итальянского математика Пизанского Леонардо, который при жизни был известен как Фибоначчи. Последовательность Фибоначчи начинается с 1 и 1. Каждый более поздний член в последовательности является суммой двух предыдущих значений. Так что серия будет: 1,1,2,3,5,8,13 и так далее. Чтобы получить полный кредит, вы должны использовать рекурсию для решения этой проблемы, создав функцию, подпись которой:
процедура fibRec(значение: int8); @нет дисплея; @noframe; Вот несколько примеров диалогов программы, которые помогут вам:
Укажите число: 3 fib(3) = 2
Укажите букву: 5 фиб (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(значение-1) + fibRec(значение-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;
1 ответ
Узнайте, как отлаживать ваш код, есть очевидные проблемы, если вы попытаетесь перешагнуть через него, как в начале вы перезаписываете пользовательский ввод значением в CL
,
Затем в процедуре вы указываете параметр "значение", но работаете с CL
вместо этого, перезаписывая содержимое value
(не уверен, что это в HLA, переменной стека или памяти?).
Для значений используются 8-битные регистры CL/DL, но в примере 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
восстановить их из стека.
Например, фиб. подпрограмма написана на 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, и я не собираюсь попробуйте, когда он потерпит крах при переполнении стека).