Программа рекурсивной Фибоначчи 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, и я не собираюсь попробуйте, когда он потерпит крах при переполнении стека).

Другие вопросы по тегам