Mostrar por pantalla
la tabla de multiplicar de un número dado y su longitud.
Start:
Imprimimos por pantalla el enunciado del problema con la
instrucción,
Invoke puts, “Enunciado”
Pedir:
Pedimos por
pantalla un número con el cual mostraremos su tabla de multiplicar, Leemos el
valor introducido y lo almacenamos en la dirección de memoria de N, realizamos
la misma operación con el siguiente invoke, pero esta vez pedimos la longitud
de la tabla y la almacenamos en LONGI.
Invoke puts, “número”
Invoke
scanf,
"%d", Addr N
Invoke puts, “Enunciado”
Invoke
scanf,
"%d", Addr LONGI
Movemos el valor de [LONGI] al registro Eax, para acceder
al contenido de una dirección de memoria, tanto para lectura como para
escritura, lo indicaremos encerrando la dirección entre corchetes, sumamos 1 al
registro Eax para que no haya desplazamiento y así me imprima la longitud de la
cadena introducida, movemos el valor del registro Eax a [LONGI] en este caso 1,
y movemos el valor 0 al registro Ebx.
Mov Eax, [LONGI]
add Eax, 1
Mov [LONGI], Eax
Mov Ebx, 0
BUCLE:
En la primera línea del
subprograma “BUCLE”, utilizaremos
la instrucción CMP junto con el registro EFLAGS, para llevar a cabo las
comparaciones realiza la operación operando1 - operando2 y coloca las banderas
en función del resultado, Jz salta si ZF = 1, Su valor es 1 si el resultado de
la comparación es 0 y 0 en caso contrario.
En este caso como el resultado
de la comparación es 1 no realiza el salto, y pasamos a la siguiente
instrucción, movemos el contenido del registro [N] a Eax, PushAD introduce en
la pila los ocho registros de propósito general, con la instrucción Push,
decrementamos el valor del puntero de pila (en ESP) e introduce el operando
fuente en la cima de la pila, con estos comandos anteriormente usados estamos
usando la pila como un almacén de parámetros para los subprogramas, la
instrucción Call consiste en meter en la pila la dirección de retorno y saltar
a la primera dirección del subprograma.
El programa llamador(“BUCLE”)
es el encargado de eliminar los parámetros que ha introducido en la pila puesto
que las funciones de C admiten que el número de parámetros sea indefinido (por
ejemplo, printf puede tener tantos parámetros como sea necesario). Para esto,
en lugar de pop, utilizaremos la instrucción add, sumando a ESP 4 por cada
parámetro introducido.
Es recomendable guardar los
valores de aquellos registros que pueden ser modificados en la pila antes de
introducir los parámetros del subprograma. En este punto, utilizamos la
instrucción PopAD, que introduce y extrae, respectivamente, los ocho registros
de propósito general.
Una vez hecho esto, procedemos
a introducir los valores calculados en el subprograma fTabla, imprimiendo los
resultados por pantalla, incrementamos Ebx en 1, de manera que cuando Ebx tenga
el mismo valor que la longitud de nuestra tabla, de esta forma en la
comparación inicial nos devolverá un ZF=1, así pues nuestra instrucción Jz realizara un salto hacia el subprograma
HECHO.
Cmp Ebx, [LONGI]
Jz > HECHO
Mov Eax, [N]
PushAD
Push Ebx
Call fTabla
Add Esp, 4
PopAD
Invoke printf, "%d
x %d = %d", [N],
Ebx, [RESULT]
Invoke
puts,
""
Inc Ebx
Jmp BUCLE
fTabla:
Como bien
he comentado anteriormente la instrucción Call consiste en meter en la pila la
dirección de retorno y saltar a la primera dirección del subprograma anterior
una vez ejecutado el bucle fTabla, el cual, al principio del subprograma
se debe guardar el contenido de EBP en la pila y copiar el contenido de ESP en
EBP. Esto se conoce como “prólogo del subprograma”, para acceder a los
parámetros que han sido pasados al subprograma no los sacamos de la pila, sino
que utilizaremos EBP, que tras el prólogo del subprograma apunta a la posición
de la pila donde está guardado el valor anterior de EBP. Dado que en [EBP] se
encuentra el contenido anterior del registro EBP y en [EBP+4] la dirección de
retorno, tendremos en [EBP+8] el primer parámetro, en [EBP+12] el segundo, en
[EBP+16] el tercero, etc, la siguiente instrucción MUL realiza una
multiplicación con el primer dato de nuestra pila, a continuación movemos el
registro Eax a [RESULT], al final del subprograma se debe sacar de la pila el valor
anterior de EBP con la instrucción Pop (dejando en la cima la dirección de
retorno) y almacenarlo de nuevo en EBP. A continuación se invocaría a la
instrucción RET. Esto se conoce como
“epílogo del subprograma”, mediante la instrucción Ret volvemos a nuestro programa
llamador,”BUCLE”.
Push Ebp
Mov Ebp, Esp
Mov Ebx, [Esp + 8]
Mul Ebx
Mov [RESULT], Eax
Pop Ebp
Ret
HECHO:
En este
subprograma creamos como un pequeño menú en el cual mediante una serie de
invokes preguntamos al usuario cual es la siguiente opción que desea realizar,
mediante un scanf tomamos el valor introducido el cual nos dirá la opción que
desea realizar, movemos el dato introducido del registro OP a Eax, hacemos una
comparación lo que quiere decir que restamos el dato introducido a 0, si nos
devuelve 1 hacemos un jump al subprograma pedir, el cual volveremos a pedir un
nuevo valor con el que trabajar, en caso contrario se finalizara el programa.
Invoke puts,
"¿Que desea hacer?"
Invoke puts,
"1.Volver a empezar"
Invoke puts,
"0.Salir"
Invoke scanf, "%d", Addr OP
Mov Eax, [OP]
Cmp Eax, 0
Jz > salir
Jmp pedir
Isaac Acejo Peña.
Isaac Acejo Peña.
No hay comentarios:
Publicar un comentario