Функция RET, возвращающая начало кода вместо точки CALL - PullRequest
0 голосов
/ 20 апреля 2020

Я новичок в сборке, но работаю над рекурсивной факториальной подсборкой.

Он должен использовать стек только для хранения значений между итерациями, а после завершения pu sh факториал в стек для POP после возврата к CALL.

Ниже приведен мой код, который работает, за исключением того, что он возвращается к «RJMP main» вместо возврата к «CALL» после окончания.

Предложения?

.def n = R16
.def result = R17
.def tmp =r20

.org 0x0000 ; next instruction will be written to address 0x0000
            ; (the location of the reset vector)
rjmp main   ; set reset vector to point to the main code entry point

main:       ; jump here on reset

; initialize the stack (RAMEND = 0x10FF by default for the ATmega128A)
ldi R16, HIGH(RAMEND)
out SPH, R16
ldi R16, low(RAMEND)
out SPL, R16
LDI n, 5; load a value into n
PUSH n ; push n on the stack
CALL factN ; calculate the factorial of n
POP result ; pop n! from the stack, save in result
here: RJMP here ; loop forever

factN: 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Recursive Subroutine to Calculate Factorial of n
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
push n  ; push n onto the stack
pop n   ; pop n off the stack
TST R0  ; test if R0 is <= 0
BRNE notZero ; if RO is >0 jump to nonZero
ldi tmp,1 ; load 1 into tmp
mul tmp,tmp ; multiply tmp by itself to populate R0 with 1
push R0 ; push R0 onto the stack
notZero:
pop R0  ; pop R0
mul R0, n ; mulitply R0 by n
dec n ; decrement n
push n ; push n onto stack
push R0 ; push r0 onto stack
CPI n, 1 ; does n == 1
BRNE factN ;loop factN until n == 1
ret ; return to CALL

1 Ответ

2 голосов
/ 24 апреля 2020

Помните, что инструкции CALL и RET используют тот же стек, что и PUSH и POP. Если RET не возвращает обратно, это означает, что стек каким-то образом был изменен.

Каждая PUSH операция должна иметь один и только один соответствующий POP в каждом возможном пути потока между обычной точкой входа и RET.

В вашем примере PUSH es и POP s не сбалансированы. Например:

push n  ; push n onto the stack
pop n   ; pop n off the stack 

Почему оно лопнуло сразу после того, как его нажали? В чем причина?

BRNE notZero ; if RO is >0 jump to nonZero
...
notZero:
pop R0  ; pop R0

, если BRNE происходит, этот pop извлекает данные, которые никогда не передавались, т.е. перемещает указатель стека за пределы адреса возврата.

push n ; push n onto stack
push R0 ; push r0 onto stack

для чего эти два push es?

et c. На самом деле есть много проблем с вашим кодом. Просто внимательно проверяйте все возможные потоки.

А также совет: никогда не используйте рекурсию для того, что можно сделать простым l oop. Такие как факторные вычисления.

...