Tutorial de Assembler en emu8086
Tutorial de Assembler en emu8086
Tutorial de
introducción al
lenguaje de bajo nivel
mediante el uso del
software emu8086
1
U.T.N. Facultad Regional Venado Tuerto
Catedra: Arquitectura de Computadoras
Tutorial Assembler
Revisar los conceptos de arquitectura X86 antes de comenzar este tutorial, la siguiente imagen es un
resumen de los registros y flags de al ALu que se utilizan en dicha arquitectura.
Acceso a Memoria
2
U.T.N. Facultad Regional Venado Tuerto
Catedra: Arquitectura de Computadoras
d8 – Se utiliza para el desplazamiento inmediato con signo de 8 bits (por ejemplo: 22, 55h, -1, etc...)
d16 – Se utiliza para desplazamiento inmediato con signo de 16 bits (por ejemplo: 300, 5517h, -259, etc...)
El desplazamiento puede ser un valor inmediato o un desplazamiento de una variable, o incluso ambos. si
hay varios valores, el ensamblador evalúa todos los valores y calcula un único valor inmediato.
El desplazamiento puede ser dentro o fuera de los símbolos [], el ensamblador genera el mismo código de
máquina para ambas formas.
El desplazamiento es un valor con signo, por lo que puede ser tanto positivo como negativo.
Generalmente, el compilador se preocupa por la diferencia entre d8 y d16 y genera el código de máquina
requerido.
Por ejemplo, supongamos que DS = 100, BX = 30, SI = 70.
El siguiente modo de direccionamiento: [BX + SI] + 25
lo calcula el procesador a esta dirección física: 100 * 16 + 30 + 70 + 25 = 1725.
De forma predeterminada, el registro de segmento DS se utiliza para todos los modos excepto aquellos con
registro BP, para estos se utiliza el registro de segmento SS.
Hay una manera fácil de recordar todas esas combinaciones posibles usando este cuadro:
puedes formar todas las combinaciones válidas tomando solo un elemento de cada columna o saltándote la
columna sin tomar nada de ella. Como puede ver, BX y BP nunca van juntos. SI y DI tampoco van juntos. Aquí
hay ejemplos de modos de direccionamiento válidos: [BX+5], [BX+SI], [DI+BX-4]
7h = 7
70h = 112
3
U.T.N. Facultad Regional Venado Tuerto
Catedra: Arquitectura de Computadoras
Tipos de datos
para decirle al compilador sobre el tipo de datos,se deben utilizar estos prefijos:
byte ptr - para byte.
word ptr - para palabra (dos bytes).
Por ejemplo:
byte ptr [BX]; acceso a bytes.
o
palabra ptr [BX]; acceso a palabras.
El ensamblador también admite prefijos más cortos:
A veces, el compilador puede calcular el tipo de datos automáticamente, pero no puede ni debe confiar en
eso cuando uno de los operandos es un valor inmediato.
Instrucción MOV
4
U.T.N. Facultad Regional Venado Tuerto
Catedra: Arquitectura de Computadoras
REG: AX, BX, CX, DX, AH, AL, BL, BH, CH, CL, DH, DL, DI, SI, BP, SP.
La instrucción MOV no se puede utilizar para establecer el valor de los registros CS e IP.
Este es un pequeño programa de còmo usar MOV, (copia el código y probalo en eEMu)
ORG 100h ; Esta directiva es necesaria para generar un segmento de memoria en programa tipo COM
MOV AX, 0B800h ;setea AX con el valor hexadecimal B800h.
MOV DS, AX ; copia el valor de AX a DS.
MOV CL, 'A' ;setea CL con el código ASCII de 'A',es 41h.
MOV CH, 1101_1111b ; setea CH con un valor binario.
MOV BX, 15Eh ; setea BX con 15Eh.
MOV [BX], CX ; copia el contenido de CX en la dirección de memoria lógica B800:015E
RET ; retorna al Sistema operativo
De hecho, el programa anterior escribe directamente en la memoria de video, por lo que puede ver que
MOV es una instrucción muy poderosa.
5
U.T.N. Facultad Regional Venado Tuerto
Catedra: Arquitectura de Computadoras
VARIABLES
La variable es una ubicación de memoria. Para un programador es mucho más fácil mantener algún valor en
una variable llamada "var1" que en la dirección 5A73:235B, especialmente cuando tiene 10 o más variables.
Nuestro compilador admite dos tipos de variables: BYTE y WORD.
nombre valor DB
nombre valor DW
nombre: puede ser cualquier combinación de letras o dígitos, aunque debe comenzar con una letra. Es
posible declarar variables sin nombre sin especificar el nombre (esta variable tendrá una dirección pero
no un nombre).
valor: puede ser cualquier valor numérico en cualquier sistema de numeración admitido (hexadecimal,
binario o decimal) o "?" Símbolo para variables que no están inicializadas.
VAR1 DB 7
var2 DW 1234h
6
U.T.N. Facultad Regional Venado Tuerto
Catedra: Arquitectura de Computadoras
Como puede ver, esto se parece mucho a nuestro ejemplo, excepto que las variables se reemplazan con
ubicaciones de memoria reales. Cuando el compilador crea código de máquina, reemplaza automáticamente
todos los nombres de variables con sus offsets. De forma predeterminada, el segmento se carga en el
registro DS (cuando se cargan archivos COM, el valor del registro DS se establece en el mismo valor que el
registro CS: segmento de código).
En la lista de memoria, la primera fila es un desplazamiento, la segunda fila es un valor hexadecimal, la
tercera fila es un valor decimal y la última fila es un valor de carácter ASCII.
El compilador no distingue entre mayúsculas y minúsculas, por lo que "VAR1" y "var1" se refieren a la misma
variable.
El desplazamiento de var2 es 0109h y la dirección completa es 0700:0109, esta variable es una PALABRA por
lo que ocupa 2 BYTES. Se supone que el byte bajo se almacena en la dirección inferior, por lo que 34 h se
ubica antes de las 12 h.
Puede ver que hay algunas otras instrucciones después de la instrucción RET, esto sucede porque el
desensamblador no tiene idea de dónde comienzan los datos, simplemente procesa los valores en la
memoria y los entiende como instrucciones 8086 válidas (las aprenderemos más adelante).
7
U.T.N. Facultad Regional Venado Tuerto
Catedra: Arquitectura de Computadoras
ORG 100h
DB 0A0h
DB 08h
DB 01h
DB 8Bh
DB 1Eh
DB 09h
DB 01h
DB 0C3h
DB 7
DB 34h
DB 12h
MATRICES(ARRAYS)
Las matrices pueden verse como cadenas de variables. Una cadena de texto es un ejemplo de una matriz de
bytes, cada carácter se presenta como un valor de código ASCII (0..255).
8
U.T.N. Facultad Regional Venado Tuerto
Catedra: Arquitectura de Computadoras
b) es una copia exacta de la matriz a), cuando el compilador ve una cadena entre comillas, la convierte
automáticamente en un conjunto de bytes. Este gráfico muestra una parte de la memoria donde se declaran
estos arreglos:
Puede acceder al valor de cualquier elemento de la matriz utilizando corchetes, por ejemplo:
MOV AL, a[3]
También puedes utilizar cualquiera de los registros índice de memoria BX, SI, DI, BP, por ejemplo:
MOV SI, 3
MOV AL, a[SI]
un ejemplo más:
dDB 5 DUP(1, 2)
es una forma alternativa de declarar:
dDB 1, 2, 1, 2, 1, 2, 1, 2, 1, 2
Por supuesto, puede usar DW en lugar de DB si es necesario mantener valores mayores que 255 o menores
que -128. DW no se puede utilizar para declarar cadenas.
9
U.T.N. Facultad Regional Venado Tuerto
Catedra: Arquitectura de Computadoras
Hay una instrucción LEA (Load Effective Address) y un operador OFFSET alternativo. Tanto OFFSET como LEA
se pueden utilizar para obtener la dirección de desplazamiento de la variable.
LEA es más poderosa porque también le permite obtener la dirección de variables indexadas. Obtener la
dirección de la variable puede resultar muy útil en algunas situaciones.
Recordatorio:
Para informarle al compilador sobre el tipo de datos,
se deben utilizar estos prefijos:
BYTE PTR - para byte.
WORD PTR: para palabra (dos bytes).
Por ejemplo:
BYTE PTR [BX] ; acceso a bytes.
o
PALABRA PTR [BX] ; acceso a palabras.
El ensamblador también admite prefijos más cortos:
A veces, el compilador puede calcular el tipo de datos automáticamente, pero no puede ni debe confiar
en eso cuando uno de los operandos es un valor inmediato.
ORG 100h
MOV AL, VAR1 ; chequeamos el valor de VAR1 copiandolo a AL.
LEA BX, VAR1 ; obtenemos la direccion de VAR1 en BX.
MOV BYTE PTR [BX], 44h ; modificamos el valor VAR1.
MOV AL, VAR1 ; chequeamos el valor de VAR1 copiandolo a AL.
RET
VAR1 DB 22h
END
Ahora usamos OFFSET en vez de LEA:
ORG 100h
RET
10
U.T.N. Facultad Regional Venado Tuerto
Catedra: Arquitectura de Computadoras
VAR1 DB 22h
END
Tenga en cuenta que sólo estos registros se pueden utilizar entre corchetes (como punteros de memoria):
BX, SI, DI, BP.
(ver parte anterior del tutorial).
Constantes
Las constantes son como las variables, pero existen sólo hasta que se compila (ensambla) el programa.
Después de la definición de una constante, su valor no se puede cambiar. Para definir constantes se utiliza la
directiva EQU:
MOV AX, k
Es lo mismo que
MOV AX, 5
Puede ver las variables mientras se ejecuta su programa seleccionando "Variables" en el menú "Ver" del
emulador.
11
U.T.N. Facultad Regional Venado Tuerto
Catedra: Arquitectura de Computadoras
Para ver matrices, debe hacer clic en una variable y establecer la propiedad Elementos en el tamaño de la
matriz. En lenguaje ensamblador no existen tipos de datos estrictos, por lo que cualquier variable se puede
presentar como una matriz.
Puede editar el valor de una variable cuando su programa se está ejecutando, simplemente haga doble clic
en él o selecciónelo y haga clic en el botón Editar.
Es posible ingresar números en cualquier sistema, los números hexadecimales deben tener el sufijo "h", el
sufijo binario "b", el sufijo octal "o", los números decimales no requieren sufijo. La cadena se puede ingresar
de esta manera:
'hola mundo', 0
(Esta cadena termina en cero).
12
U.T.N. Facultad Regional Venado Tuerto
Catedra: Arquitectura de Computadoras
(la matriz puede ser una matriz de bytes o palabras, depende de si se selecciona BYTE o WORD para la
variable editada).
Interrupciones
Las interrupciones pueden verse como una serie de funciones. Estas funciones hacen que la programación
sea mucho más fácil, en lugar de escribir un código para imprimir un carácter, simplemente puedes llamar a
la interrupción y ella hará todo por ti. También hay funciones de interrupción que funcionan con unidades
de disco y otro hardware. A estas funciones las llamamos interrupciones de software.
Las interrupciones también son provocadas por diferentes hardware, lo que se denomina interrupciones de
hardware. Actualmente sólo nos interesan las interrupciones de software.
Para realizar una interrupción de software existe una instrucción INT, tiene una sintaxis muy simple:
INT valor
Donde el valor puede ser un número entre 0 y 255 (o 0 a 0FFh),
generalmente usaremos números hexadecimales.
Quizás pienses que sólo hay 256 funciones, pero eso no es correcto. Cada interrupción puede tener
subfunciones.
Para especificar una subfunción, se debe configurar el registro AH antes de llamar a la interrupción.
Cada interrupción puede tener hasta 256 subfunciones (por lo que obtenemos 256 * 256 = 65536
funciones). En general, se utiliza el registro AH, pero a veces es posible que se utilicen otros registros.
Generalmente se utilizan otros registros para pasar parámetros y datos a la subfunción.
El siguiente ejemplo utiliza la subfunción INT 10h 0Eh para escribir "¡Hola!" mensaje. Esta función muestra
un personaje en la pantalla, avanza el cursor y desplaza la pantalla según sea necesario.
ORG 100h ; Indica al compilador que cree un archivo .com simple de un solo segmento.
13
U.T.N. Facultad Regional Venado Tuerto
Catedra: Arquitectura de Computadoras
Copie y pegue el programa anterior en el editor de código fuente y presione el botón [Compilar y emular].
¡Ejecutarlo!
Para facilitar la programación, existen algunas funciones comunes que se pueden incluir en su programa.
Para que su programa use funciones definidas en otro archivo, debe usar la directiva INCLUDE seguida de un
nombre de archivo. El compilador busca automáticamente el archivo en la misma carpeta donde se
encuentra el archivo fuente y, si no puede encontrar el archivo allí, busca en la carpeta Inc.
Actualmente es posible que no puedas entender completamente el contenido de [Link] (ubicado en
la carpeta Inc), pero está bien, ya que sólo necesitas entender lo que puede hacer.
Para utilizar cualquiera de las funciones en [Link], debe tener la siguiente línea al principio de su
archivo fuente:
include '[Link]'
14
U.T.N. Facultad Regional Venado Tuerto
Catedra: Arquitectura de Computadoras
GOTOXY col, fila - macro con 2 parámetros, establece la posición del cursor.
PRINTN cadena: macro con 1 parámetro, imprime una cadena. Lo mismo que PRINT pero agrega
automáticamente "retorno de carro" al final de la cadena.
Para utilizar cualquiera de las macros anteriores, simplemente escriba su nombre en algún lugar de su
código y, si es necesario, los parámetros, por ejemplo:
include [Link]
ORG 100h
GOTOXY 10, 5
Cuando el compilador procesa su código fuente, busca en el archivo [Link] declaraciones de macros y
reemplaza los nombres de las macros con código real. Generalmente, las macros son partes de código
relativamente pequeñas; el uso frecuente de una macro puede hacer que el ejecutable sea demasiado
grande (los procedimientos son mejores para optimizar el tamaño).
15
U.T.N. Facultad Regional Venado Tuerto
Catedra: Arquitectura de Computadoras
PRINT_STRING: procedimiento para imprimir una cadena terminada en nulo en la posición actual del cursor,
recibe la dirección de la cadena en el registro DS:SI. Para usarlo, declare: DEFINE_PRINT_STRING antes de la
directiva END.
PTHIS: procedimiento para imprimir una cadena terminada en nulo en la posición actual del cursor (al igual
que PRINT_STRING), pero recibe la dirección de la cadena de la pila. La cadena TERMINADA EN CERO debe
definirse justo después de la instrucción CALL. Por ejemplo:
CALL PTHIS
db '¡Hola mundo!', 0
GET_STRING: procedimiento para obtener una cadena terminada en nulo de un usuario, la cadena recibida
se escribe en el búfer en DS:DI, el tamaño del búfer debe estar en DX. El procedimiento detiene la entrada
cuando se presiona 'Entrar'. Para usarlo, declare: DEFINE_GET_STRING antes de la directiva END.
CLEAR_SCREEN: procedimiento para borrar la pantalla (que se realiza desplazándose por toda la ventana de
la pantalla) y establecer la posición del cursor en la parte superior de ella. Para usarlo, declare:
DEFINE_CLEAR_SCREEN antes de la directiva END.
SCAN_NUM: procedimiento que obtiene el número FIRMADO de varios dígitos del teclado y almacena el
resultado en el registro CX. Para usarlo, declare: DEFINE_SCAN_NUM antes de la directiva END.
PRINT_NUM: procedimiento que imprime un número firmado en el registro AX. Para usarlo, declare:
DEFINE_PRINT_NUM y DEFINE_PRINT_NUM_UNS antes de la directiva END.
PRINT_NUM_UNS: procedimiento que imprime un número sin firmar en el registro AX. Para usarlo, declare:
DEFINE_PRINT_NUM_UNS antes de la directiva END.
16
U.T.N. Facultad Regional Venado Tuerto
Catedra: Arquitectura de Computadoras
Para utilizar cualquiera de los procedimientos anteriores, primero debe declarar la función al final de su
archivo (pero antes de la directiva END) y luego usar la instrucción CALL seguida de un nombre de
procedimiento. Por ejemplo:
include '[Link]'
ORG 100h
DEFINE_SCAN_NUM
DEFINE_PRINT_STRING
DEFINE_PRINT_NUM
DEFINE_PRINT_NUM_UNS ; requerido para print_num.
DEFINE_PTHIS
Primero el compilador procesa las declaraciones (estas son simplemente las macros normales que se
expanden a procedimientos). Cuando el compilador llega a la instrucción CALL, reemplaza el nombre del
procedimiento con la dirección del código donde se declara el procedimiento. Cuando se ejecuta la
instrucción CALL, el control se transfiere al procedimiento. Esto es bastante útil, ya que incluso si llamas al
mismo procedimiento 100 veces en tu código, seguirás teniendo un tamaño ejecutable relativamente
pequeño. Parece complicado, ¿no? Está bien, con el tiempo aprenderás más; actualmente es necesario que
comprendas el principio básico.
17
U.T.N. Facultad Regional Venado Tuerto
Catedra: Arquitectura de Computadoras
La mayoría de las instrucciones aritméticas y lógicas afectan el registro de estado del procesador (o
banderas).
Como puede ver, hay 16 bits en este registro, cada bit se llama bandera y puede tomar un valor de 1 o 0.
Bandera de acarreo (CF): esta bandera se establece en 1 cuando hay un desbordamiento sin firmar. Por
ejemplo, cuando agrega bytes 255 + 1 (el resultado no está en el rango 0...255). Cuando no hay
desbordamiento, este indicador se establece en 0.
Bandera cero (ZF): se establece en 1 cuando el resultado es cero. Para ningún resultado cero, este indicador
se establece en 0.
Bandera de signo (SF): se establece en 1 cuando el resultado es negativo. Cuando el resultado es positivo, se
establece en 0. En realidad, este indicador toma el valor del bit más significativo.
Bandera de desbordamiento (OF): se establece en 1 cuando hay un desbordamiento firmado. Por ejemplo,
cuando agrega los bytes 100 + 50 (el resultado no está en el rango -128...127).
Bandera de paridad (PF): esta bandera se establece en 1 cuando hay un número par de bits uno en el
resultado y en 0 cuando hay un número impar de bits uno. Incluso si el resultado es una palabra, ¡sólo se
analizan 8 bits bajos!
18
U.T.N. Facultad Regional Venado Tuerto
Catedra: Arquitectura de Computadoras
Bandera auxiliar (AF): se establece en 1 cuando hay un desbordamiento sin firmar para cuarteto bajo (4
bits).
Indicador de habilitación de interrupción (IF): cuando este indicador se establece en 1, la CPU reacciona a
las interrupciones de dispositivos externos.
Bandera de dirección (DF): algunas instrucciones utilizan esta bandera para procesar cadenas de datos;
cuando esta bandera se establece en 0, el procesamiento se realiza hacia adelante; cuando esta bandera se
establece en 1, el procesamiento se realiza hacia atrás.
REG, memory
memory, REG
REG, REG
memory, immediate
REG, immediate
REG: AX, BX, CX, DX, AH, AL, BL, BH, CH, CL, DH, DL, DI, SI, BP, SP.
Después de la operación entre operandos, el resultado siempre se almacena en el primer operando. Las
instrucciones CMP y TEST afectan únicamente a los indicadores y no almacenan un resultado (estas
instrucciones se utilizan para tomar decisiones durante la ejecución del programa).
19
U.T.N. Facultad Regional Venado Tuerto
Catedra: Arquitectura de Computadoras
AND: AND lógico entre todos los bits de dos operandos. Se aplican estas reglas:
1 AND 1 = 1
1 AND 0 = 0
0 AND 1 = 0
0 AND 0 = 0
OR: OR lógico entre todos los bits de dos operandos. Se aplican estas reglas:
1 OR 1 = 1
1 OR 0 = 1
0 OR 1 = 1
0 OR 0 = 0
XOR: XOR lógico (OR exclusivo) entre todos los bits de dos operandos. Se aplican estas reglas:
1 XOR 1 = 0
1 XOR 0 = 1
0 XOR 1 = 1
0 XOR 0 = 0
20
U.T.N. Facultad Regional Venado Tuerto
Catedra: Arquitectura de Computadoras
21
U.T.N. Facultad Regional Venado Tuerto
Catedra: Arquitectura de Computadoras
NEG: convierte el operando en negativo (complemento a dos). En realidad, invierte cada bit de operando y
luego le suma 1. Por ejemplo, 5 se convertirá en -5 y -2 se convertirá en 2.
Controlar el flujo del programa es algo muy importante, aquí es donde su programa puede tomar decisiones
de acuerdo con ciertas condiciones.
saltos incondicionales
La instrucción básica que transfiere el control a otro punto del programa es JMP.
22
U.T.N. Facultad Regional Venado Tuerto
Catedra: Arquitectura de Computadoras
calc:
add ax, bx ; sumo bx to ax.
jmp back ; salto a 'back'.
stop:
Por supuesto, existe una forma más sencilla de calcular algunos de dos números, pero sigue siendo un buen
ejemplo de instrucción JMP.
Como puede ver en este ejemplo, JMP puede transferir el control tanto hacia adelante como hacia atrás.
Puede saltar a cualquier parte del segmento de código actual (65.535 bytes).
23
U.T.N. Facultad Regional Venado Tuerto
Catedra: Arquitectura de Computadoras
A diferencia de la instrucción JMP que realiza un salto incondicional, hay instrucciones que realizan saltos
condicionales (saltan solo cuando algunas condiciones están vigentes). Estas instrucciones se dividen en tres
grupos: el primer grupo simplemente prueba una sola bandera, el segundo compara los números con signo y
el tercero compara los números sin signo.
Como ya habrás notado, hay algunas instrucciones que hacen lo mismo, eso es correcto, incluso están
ensambladas en el mismo código de máquina, por lo que es bueno recordar que cuando compilas la
instrucción JE, la desensamblas como: JZ, JC. se ensambla igual que JB etc...
Se utilizan diferentes nombres para hacer que los programas sean más fáciles de entender, codificar y, lo
más importante, recordar.
Si emulas el código siguiente, verá que todas las instrucciones están ensambladas en JNB, el código
operativo (código de operación) para esta instrucción es 73h, esta instrucción tiene una longitud fija de dos
bytes, el segundo byte es el número de bytes para agregar al registro IP si la condición es verdadera. debido
24
U.T.N. Facultad Regional Venado Tuerto
Catedra: Arquitectura de Computadoras
a que la instrucción tiene solo 1 byte para mantener el desplazamiento, está limitada a pasar el control a -
128 bytes hacia atrás o 127 bytes hacia adelante, este valor siempre está con signo.
jnc a
jnb a
jae a
mov ax, 4
a: mov ax, 5
ret
ZF = 0
Salta si es mayor (>).
JG , JNLE y JNG, JLE
Salta si no es menor o igual (not <=).
SF = OF
ZF = 1
Salta si es menor o igual(<=).
JLE , JNG or JNLE, JG
Salta si no es mayor(not >).
SF <> OF
25
U.T.N. Facultad Regional Venado Tuerto
Catedra: Arquitectura de Computadoras
CF = 0
Jump if Above (>).
JA , JNBE and JNA, JBE
Jump if Not Below or Equal (not <=).
ZF = 0
CF = 1
Jump if Below or Equal (<=).
JBE , JNA or JNBE, JA
Jump if Not Above (not >).
ZF = 1
Generalmente, cuando se requiere comparar valores numéricos se usa la instrucción CMP (hace lo mismo
que la instrucción SUB (resta), pero no guarda el resultado, solo afecta las banderas).
La lógica es muy simple, por ejemplo:
es necesario comparar 5 y 2,
5-2=3
el resultado no es cero (el indicador cero se establece en 0).
Otro ejemplo:
es necesario comparar 7 y 7,
7-7=0
¡el resultado es cero! (Zero Flag se establece en 1 y JZ o JE harán el salto).
26
U.T.N. Facultad Regional Venado Tuerto
Catedra: Arquitectura de Computadoras
include "[Link]"
org 100h
stop:
Pruebe el ejemplo anterior con números diferentes para AL y BL, abra las banderas haciendo clic en el botón
de banderas, use un solo paso y vea qué sucede. puede usar la tecla de acceso rápido F5 para recompilar y
recargar el programa en el emulador.
Loops
LOOPE disminuir cx, saltar a la etiqueta si cx no es cero e igual (zf = 1). LOOPNE
LOOPNE disminuir cx, saltar a la etiqueta si cx no es cero y no es igual (zf = 0). LOOPE
27
U.T.N. Facultad Regional Venado Tuerto
Catedra: Arquitectura de Computadoras
Los bucles son básicamente los mismos saltos, es posible codificar bucles sin usar la instrucción de bucle,
simplemente usando saltos condicionales y comparar, y esto es exactamente lo que hace el bucle. todas las
instrucciones de bucle usan el registro CX para contar pasos, como sabes el registro CX tiene 16 bits y el
valor máximo que puede contener es 65535 o FFFF, sin embargo con cierta agilidad es posible meter un
bucle en otro, y otro en otros dos, y tres y etc... y recibir un buen valor de 65535 * 65535 * 65535....hasta el
infinito.... o el final de la memoria ram o pila. Es posible almacenar el valor original del registro cx usando la
instrucción push cx y devolverlo al original cuando el bucle interno finalice con pop cx, por ejemplo:
org 100h
Ret
28
U.T.N. Facultad Regional Venado Tuerto
Catedra: Arquitectura de Computadoras
bx cuenta el número total de pasos, de forma predeterminada el emulador muestra los valores en
hexadecimal, puede hacer doble clic en el registro para ver el valor en todas las bases disponibles.
Al igual que todos los demás bucles de saltos condicionales, tienen un compañero opuesto que puede
ayudar a crear soluciones alternativas, cuando la dirección de la ubicación deseada está demasiado lejos,
assembelr ensambla automáticamente instrucciones de salto inverso y largo, lo que hace un total de 5 bytes
en lugar de solo 2, como se puede ver también en el desensamblador.
para obtener una descripción más detallada y ejemplos, consulte el conjunto completo de instrucciones
8086
Todos los saltos condicionales tienen una gran limitación: a diferencia de las instrucciones JMP, solo pueden
saltar 127 bytes hacia adelante y 128 bytes hacia atrás (tenga en cuenta que la mayoría de las instrucciones
se ensamblan en 3 o más bytes). Mediante técnicas de programación se puede evitar este inconveniente, no
son parte del curso por ahora .
PROCEDIMIENTOS
El procedimiento es una parte del código que se puede llamar desde su programa para realizar alguna tarea
específica. Los procedimientos hacen que el programa sea más estructural y más fácil de entender.
Generalmente el procedimiento regresa al mismo punto desde donde fue llamado.
; aqui va el codigo
; del procedimiento...
RET
nombre ENDP
nombre - es el nombre del procedimiento, el mismo nombre debe estar en la parte superior e inferior, esto
se utiliza para verificar el cierre correcto de los procedimientos.
Probablemente ya sepa que la instrucción RET se utiliza para regresar al sistema operativo. La misma
instrucción se utiliza para regresar del procedimiento (en realidad, el sistema operativo ve su programa
como un procedimiento especial).
PROC y ENDP son directivas de compilación, por lo que no están ensambladas en ningún código de máquina
real. El compilador simplemente recuerda la dirección del procedimiento.
29
U.T.N. Facultad Regional Venado Tuerto
Catedra: Arquitectura de Computadoras
ORG 100h
CALL m1
MOV AX, 2
m1 PROC
MOV BX, 5
RET ; retorna al lugar desde donde se invoco el procedimiento.
m1 ENDP
END
El ejemplo anterior llama al procedimiento m1, realiza MOV BX, 5 y regresa a la siguiente instrucción
después de CALL: MOV AX, 2.
Hay varias formas de pasar parámetros a un procedimiento, la forma más sencilla de pasar parámetros es
mediante registros, aquí hay otro ejemplo de un procedimiento que recibe dos parámetros en los registros
AL y BL, multiplica estos parámetros y devuelve el resultado en el registro AX:
ORG 100h
MOV AL, 1
MOV BL, 2
CALL m2
CALL m2
CALL m2
CALL m2
m2 PROC
MUL BL ; AX = AL * BL.
RET ; retorna al lugar desde donde se lo llamo.
m2 ENDP
END
30
U.T.N. Facultad Regional Venado Tuerto
Catedra: Arquitectura de Computadoras
En el ejemplo anterior, el valor del registro AL se actualiza cada vez que se llama al procedimiento, el
registro BL permanece sin cambios, por lo que este algoritmo calcula 2 en potencia de 4.
entonces el resultado final en el registro AX es 16 (o 10h).
PILA
La pila es un área de memoria para guardar datos temporales. La instrucción CALL utiliza la pila para
mantener la dirección de retorno del procedimiento, la instrucción RET obtiene este valor de la pila y
regresa a ese desplazamiento. Lo mismo sucede cuando la instrucción INT llama a una interrupción,
almacena en el registro de bandera de la pila, el segmento de código y el desplazamiento. La instrucción
IRET se utiliza para regresar de una llamada de interrupción.
PUSH REG
PUSH SREG
PUSH memory
PUSH immediate
REG: AX, BX, CX, DX, DI, SI, BP, SP.
31
U.T.N. Facultad Regional Venado Tuerto
Catedra: Arquitectura de Computadoras
POP REG
POP SREG
POP memory
REG: AX, BX, CX, DX, DI, SI, BP, SP.
Es muy importante realizar la misma cantidad de PUSH y POP; de lo contrario, la pila podría dañarse y será
imposible regresar al sistema operativo. Como ya sabe, utilizamos la instrucción RET para regresar al sistema
operativo, por lo que cuando se inicia el programa hay una dirección de retorno en la pila (generalmente es
0000h).
Las instrucciones PUSH y POP son especialmente útiles porque no tenemos demasiados registros con los que
operar, así que aquí tienes un truco:
Almacene el valor original del registro en la pila (usando PUSH).
32
U.T.N. Facultad Regional Venado Tuerto
Catedra: Arquitectura de Computadoras
RET
END
ORG 100h
RET
END
El intercambio ocurre porque la pila usa el algoritmo LIFO (Last In First Out), por lo que cuando presionamos
1212h y luego 3434h, en el pop obtendremos primero 3434h y solo después 1212h.
El área de memoria de la pila se establece mediante el registro SS (Segmento de pila) y el registro SP
(Puntero de pila). Generalmente, el sistema operativo establece los valores de estos registros al iniciar el
programa.
33
U.T.N. Facultad Regional Venado Tuerto
Catedra: Arquitectura de Computadoras
Para archivos COM, el segmento de pila es generalmente el segmento de código y el puntero de pila se
establece en el valor 0FFFEh. En la dirección SS:0FFFEh se almacena una dirección de retorno para la
instrucción RET que se ejecuta al final del programa.
Puede ver visualmente la operación de la pila haciendo clic en el botón [Apilar] en la ventana del emulador.
La parte superior de la pila está marcada con el signo "<".
34
U.T.N. Facultad Regional Venado Tuerto
Catedra: Arquitectura de Computadoras
Bibliografìa y fuente:
Link de descarga: [Link]
Fuente: tutorial de ayuda de emu8086
35