una serie recursividad recibe que programacion números número los imprime función funcion consideremos con ats assembly fibonacci

assembly - recursividad - serie fibonacci funcion



Fibonacci recursivo en Asamblea (3)

Cuando realiza una call , la dirección de la siguiente operación se envía a la pila como un valor de retorno. Al crear una función, a menudo es costumbre crear un "marco de pila". Este marco se puede utilizar para imprimir la pila de llamadas, así como un desplazamiento para variables locales y argumentos. El marco se crea mediante dos operaciones al comienzo de la función:

push ebp mov ebp, esp

Al final de la función, la pila de llamadas se elimina usando leave , que es equivalente al reverso de esas 2 operaciones. Cuando se utiliza un marco de pila, el valor de esp se almacena en ebp , lo que hace que apunte a una ubicación en la pila llamada base del marco. Dado que, encima de esta dirección, está el antiguo valor de ebp y la dirección de retorno, normalmente obtendría el primer argumento usando [ebp+8] . Sin embargo, no configuró un marco de pila. Esto significa que el valor anterior de ebp no se ebp a la pila, y el valor actual de ebp no se puede usar para obtener argumentos porque no se sabe dónde está. Por lo tanto, deberías obtener tu argumento usando [esp+4] .

Además, es habitual que los valores devueltos se coloquen en eax y se preserve ebx para la persona que llama. Su código no sigue ninguna de estas convenciones. Además, técnicamente no se requieren funciones para ecx o edx preservados, por lo que normalmente deberías empujarlos a la pila antes de llamar a otra función si quieres que se conserven. Con este código, edx y ebx se sobrescribirán si se llama con un valor mayor que 2, lo que causa un resultado no válido.

Aquí hay una lista completa que incluye todas las correcciones que he mencionado. No creé un marco de pila ya que no es necesario y tu código no.

.386 .model Flat public Fibonacci include iosmacros.inc ;includes macros for outputting to the screen .code Fibonacci proc MOV EAX, [ESP+4] CMP EAX, 1 JA Recurse MOV EAX, 1 ; return value in eax JMP exit Recurse: PUSH EBX ; preserve value of ebx DEC EAX PUSH EAX CALL Fibonacci MOV EBX, EAX ; ebx is preserved by callee, so it is safe to use DEC [ESP] ; decrement the value already on the stack CALL Fibonacci ADD EAX, EBX ; return value in eax ADD ESP, 4 ; remove value from stack POP EBX ; restore old value of ebx exit: ret Fibonacci endp

Estoy intentando implementar un programa recursivo de Fibonacci en la Asamblea. Sin embargo, mi programa falla, con una excepción no controlada, y parece que no puedo distinguir el problema. No dudo que se trate de mi uso incorrecto de la pila, pero no puedo señalar dónde ...

.386 .model Flat public Fibonacci include iosmacros.inc ;includes macros for outputting to the screen .code Fibonacci proc MOV EAX, [EBP+8] CMP EAX, 1 JA Recurse MOV ECX, 1 JMP exit Recurse: DEC EAX MOV EDX, EAX PUSH EAX CALL Fibonacci ADD ESP, 4 MOV EBX, ECX DEC EDX PUSH EDX CALL Fibonacci ADD ECX, EBX exit: ret Fibonacci endp .data end

Además, presioné el número que estoy usando para obtener el valor de Fibonacci en la pila en un procedimiento externo. ¿Alguna idea de dónde podría estar el problema?


Primero, estás usando un desplazamiento de pila de 8 de EBP, ¿por qué? ¿No te refieres a ESP? Y una llamada normal solo usa una celda de 32 bits, por lo que su argumento debería estar en el desplazamiento 4. Estoy bastante seguro de que existen otros problemas, pero puede comenzar con eso.

Probablemente deberías escribir algunos pseudocódigos para que tú y nosotros podamos ver lo que estás tratando de lograr. Si quiere hacer trampa, buscar en Google "nasa recursive fibonacci" lo lleva a un programa de trabajo. Pero serás un mejor programador si lo resuelves tú mismo.

Varios problemas:

  • si va a pasar parámetros en la pila, no tiene la entrada de la función correcta (estándar), por lo que EBP apunta al lugar equivocado
  • no está guardando correctamente el valor del argumento en edx

Esto es lo que creo que usted quería, suponiendo que está pasando parámetros en la pila (lo mejor es agregar un comentario a cada instrucción dejando en claro lo que cree que es):

Fibonacci proc PUSH EBP ; save previous frame pointer MOV EBP, ESP ; set current frame pointer MOV EAX, [EBP+8] ; get argument N CMP EAX, 1 ; N<=1? JA Recurse ; no, compute it recursively MOV ECX, 1 ; yes, Fib(1)--> 1 JMP exit Recurse: DEC EAX ; = N-1 MOV EDX, EAX ; = N-1 PUSH EDX ; save N-1 PUSH EAX ; set argument = N-1 CALL Fibonacci ; compute Fib(N-1) to ECX POP EAX ; pop N-1 DEC EAX ; = N-2 PUSH ECX ; save Fib(N-1) PUSH EAX ; set argument = N-2 CALL Fibonacci ; compute Fib(N-2) to ECX POP EAX ; = Fib(N-1) ADD ECX, EAX ; = Fib(N-1)+FIB(N-2) exit: MOV ESP,EBP ; reset stack to value at function entry POP EBP ; restore caller''s frame pointer RET ; and return

Pero no tienes que pasar los parámetros en la pila. Es más eficiente usar los registros:

Fibonacci proc ; computes Fib(EAX) --> EAX; do not call with EAX==0 CMP EAX, 1 ; N<=1? JBE exit ; yes, we have the answer DEC EAX ; = N-1 PUSH EAX ; save N-1 CALL Fibonacci ; computing FIB(n-1)to EAX XCHG EAX,0[ESP] ; swap FIB(n-1) for saved N-1 (You''ll love this instruction, look it up in the Intel manual) DEC EAX ; = N-2 CALL Fibonacci ; computing FIB(N-2) to EAX POP ECX ; = FIB(N-1) ADD EAX,ECX ; = FIB(N-1)+FIB(N-2) exit: RET