рекурсивная функция на языке ассемблера рук - PullRequest
0 голосов
/ 03 ноября 2018
    .text
    .global main
main:
    sub sp,sp,#4
    str lr,[sp,#0]

    @ compiling a recursive C procdure
    @ int fact(int n){
    @   if(n < 1){
    @       return 1;
    @   }else{
    @       return (n * fact(n-1));
    @   }
    @ }

    @ put n in r0


    mov r0,#6   
fact:   
    sub sp,sp,#8
    str lr,[sp,#8]
    str r0,[sp,#0]

    cmp r0,#1
    bge L1

    mov r0,#1
    add sp,sp,#8
    mov pc,lr


L1:
    sub r0,r0,#1
    bl fact

    mov r12,r0
    ldr r0,[sp,#0]  
    ldr lr,[sp,#0]
    add sp,sp,#8

    mul r0,r12,r0
    mov pc,lr

    mov r7,r0


    ldr r0, =format
    mov r1,r7
    bl printf

    ldr lr,[sp,#0]
    add sp,sp,#4
    mov pc,lr


    .data
format: .asciz "The Answer is %d\n"

Я написал код на языке ассемблера, чтобы найти факториал целого числа. Но этот код не печатать ни один ответ. Я не мог найти, почему это так.

1 Ответ

0 голосов
/ 06 ноября 2018

Комментарии Питера Кордеса и Эллиота Алдерсона о необходимости предоставить пример MCV и о необходимости комментировать ваш код абсолютно верны. Пожалуйста, отвечайте на подобные запросы, потому что они значительно облегчают вашу помощь.

Самая очевидная ошибка - в пятой строке после метки L1: ваш адрес смещения для повторной загрузки lr неверен (вы выдвигаете значение r0 дважды).

В вашем коде есть несколько странных особенностей, с которыми вам действительно стоит разобраться. Первый из них предотвратил бы ошибку выше:

  • Используйте STMFD и LDMFD, чтобы нажать и выдвинуть. Это быстрее и менее подвержено ошибкам, чем ручное манипулирование указателем стека. Если sp содержит ваш указатель стека (как обычно), вы можете использовать синонимы PUSH и POP. Например, три строки, в которых находится ошибка, можно записать просто как

    LDMFD sp!, {r0,lr}
    

    или

    POP {r0,lr}
    

    Обратите внимание, что вы можете вернуться, вставив сохраненное значение lr непосредственно в pc, а не вставив его в lr и выполнив bx lr (это называется «неявным возвратом» и сохраняет строка кода).

  • Двоичный интерфейс ARM Application требует, чтобы функции отвечали за сохранение содержимого r4-r11, lr и sp. sp сохраняется, если использование стека сбалансировано, конечно. Вы этого не делаете. Кроме того, поскольку r0-r3 и r12 не гарантированно сохраняются при вызовах, как правило, рекомендуется избегать их использования для локального хранилища данных.
  • ABI также указывает, что стек должен быть выровнен по 8 байтов между вызовами функций в разных единицах перевода, поэтому рекомендуется всегда сохранять 8-байтовое выравнивание, всегда выдвигая и выталкивая четные числа регистров. За это не снижается производительность.
  • Было бы неплохо стилистически отделить fact от main, а не вкладывать одно в другое, как вы это сделали. (Вы будете вынуждены сделать это разделение на языке высокого уровня, в том числе на C.)
  • Использование подписанного типа для вашего аргумента - странная идея, когда вы все равно игнорируете отрицательные аргументы. bge использует сравнение со знаком «больше или равно»; bhs является беззнаковым эквивалентом. На самом деле вы можете использовать bhi («без знака выше»), потому что если аргумент равен 1, то нет смысла вычислять его факториал.

Я переписал ваш код, следуя приведенным ниже инструкциям. Я не добавил комментарии, это вам делать. Я также не изменил логику вашего алгоритма, так что там может быть место для улучшения. Я тоже не проверял!

    .text
    .global main
main:
    stmfd sp!, {r7,lr}

    @ compiling a recursive C procedure
    @ unsigned int fact(unsigned int n){
    @   if(n < 1){
    @       return 1;
    @   }else{
    @       return (n * fact(n-1));
    @   }
    @ }

    stmfd sp!, {r7,lr}

    @ put n in r0
    mov r0,#6

    bl fact

    mov r1,r0
    ldr r0, =format
    bl printf

    ldmfd sp!, {r7,pc}


fact:
    stmfd sp!, {r7,lr}

    cmp r0,#1
    bhi L1

    mov r0,#1
    ldmfd sp!, {r7,pc}
L1:
    mov r7,r0
    sub r0,r0,#1
    bl fact

    mov r7,r0
    mul r0,r0,r7

    ldmfd sp!, {r7,pc}


    .data
format: .asciz "The Answer is %d\n"
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...