Lenguaje ensablador

Anuncio
LENGUAJE ENSAMBLADOR
Conjunto de instrucciones que entiende el microprocesador y que ejecuta una
serie de operaciones. Es un lenguaje de bajo nivel cercano al hardware.
Índice:
1.- Organización interna.
2.- Segmentación de memoria.
3.- Modos de direccionamiento.
4.- Formato de instrucciones.
5.- La familia Intel 80x86.
¿Qué es arquitectura software?
Son los atributos visibles por el programador. El compilador como generador
automático de código. No tiene que haber una correspondencia real con la capa física.
Es el “contrato” entre el fabricante del procesador y el programador. La arquitectura
software del 80x86 data de 1978 y no ha evolucionado casi nada. Las cosas que se han
añadido son:



Extensiones en el tamaño de la palabra.
Extensiones 386 para el modo protegido.
Anexos al repertorio para multimedia (computación vectorial).
- MMX
- SSE y SSE2
Típico repertorio CISC, el repertorio de instrucciones es del tipo
CISC: juego de instrucciones complejo, es algo antiguo.

1.-Organización interna:
Registros de propósito general:
Los ve el programador y el compilador, hay mas registros pero no son
accesibles.
15
8
0
15
0
AH
AL
AX
BP
BH
BL
BX
SI
CH
CL
CX
DI
DH
DL
DX
SP
H-> parte alta del registro.
L -> parte baja del registro.
Pág. 2
AX [registro acumulador] = sirve para operaciones de producto, división, entrada y
salida y transferencia optimizadas.
BX [registro base] = puntero a dirección base (datos).
CX [registro contador] = es el contador de bucles, desplazamientos, rotaciones y
repetición de cadenas.
DX [registro de datos] = Producto, división y entrada y salida.
BP [puntero base] = Puntero a direcciones base (pila).
SI [índice fuente] = Fuente en manejo de cadenas.
DI [índice destino] = Destino en manejo de cadenas.
SP [puntero a pila] = Puntero a la cima de la pila.
Estos registros no son de propósito general pero los llamamos así.
Registros de propósito general:







Almacenamiento temporal de variables.
Algunos se pueden tratar en ancho palabra (16 bits) o byte.
- Registro X, 16 bits.
- Registro L y H, 8 bits.
Usos dedicados que generan las limitaciones.
Modelo híbrido (acumulador y banco de registros) heredado de
arquitecturas anteriores.
Las operaciones entre operandos que residen en memoria no están
permitidas con lo que algunos de los operandos debe residir
temporalmente en estos registros.
BP utilizado para pasar argumentos a pila.
Las máquinas actuales tienen 128 registros, pero la máquina se
encarga de mapear y asignarlos a los 8.
Registros de segmento:
15
0
CS
Segmento de código.
DS
Segmento de datos.
SS
Segmento de pila.
ES
Segmento extra (datos).
Sirven para diferenciar las diferentes porciones de memoria de un programa.
Los programas manejan diferentes áreas de memoria:

Datos (DS, ES) -> hacen referencia a esta parte de memoria.
Pág. 3



Código (texto) -> programa propiamente dicho, lo que escribimos
(DS).
Pila (SS).
Heap (SS).
Todo esto está derivado del modelo de Von Neuman.
Todas las direcciones son relativas a alguno de los registros de segmento,
esto viene por defecto. Es una idea importante.
CS = Las direcciones de este segmento contiene instrucciones. [Code Segment]
DS = Estas direcciones contienen datos declarados por el programa (reserva de memoria
estática). [Data Segment]
SS = es la pila -> almacenamiento temporal de datos (parámetros de función). [Stack
Segment]
ES = datos de cadenas. [Extra Segment]
Otros registros:
Flags
Estado del procesador.
IP
Puntero de instrucción -> indica por donde vamos en el
programa.
15
0
O
D
I
T
S
Z
A
P
C
Acarreo (C) = si es 1 el resultado de una operación genera acarreo.
Paridad (P) = es 1 si el resultado contiene un número par de bits a 1.
Acarreo Auxiliar (A) = es 1 si el resultado genera acarreo en los 4 bits de menos pero.
Se usa en aritmética BCD.
Cero (Z) = es 1 si el resultado es cero.
Signo (S) = copia el bit de mayor pero del resultado (independientemente de la
interpretación del resultado).
Trap (T) = si es 1 el procesador genera una interrupción de paso a paso después de
ejecutar cada instrucción.
Interrupción (I) = si es 1 las interrupciones serán reconocidas.
Dirección (D) = si es 1 las operaciones con cadenas se realizan de las posiciones altas a
las bajas.
Desbordamiento (O) = overflow. Es 1 si el resultado es demasiado grande (o pequeño)
para los limites de representación.
2.-Segmentación de memoria:
Pág. 4
El mapa de memoria que “ve” el 80x86 NO es “plano”.
Los registros de 16 bits solo pueden direccional 216 posiciones de memoria
(65635 posiciones = 64 K)
¿Cómo alcanzar un espacio de direcciones mayor? El acceso a memoria se
realiza en segmentos de 64 K. Esto provoca complicaciones excesivas en los accesos a
memoria.
La capacidad de direccionamiento es de 1 M (220). La dirección completa se
consigue mediante la combinación de dos direcciones: segmento y desplazamiento
(offset):
Segmento: desplazamiento.
Base: desplazamiento.
La dirección física se calcula:
Base x 16 + desplazamiento -> añado 4 ceros a la parte mas baja de la
dirección (x16) y luego le sumo el desplazamiento.
Ejemplo:

La dirección 53C2:107A es:
53C20 h
+ 107A h
54C9A h

x16 (x10 h)
dirección física
La dirección B100:046C es:
B1000 h
+ 046C h
B146C h
x16 (x10 h)
dirección física
Características:
La misma dirección física puede ser accedida con diferentes combinaciones
base:desplazamiento.
Ejemplo:
La dirección física 7A26B h puede ser:
Pág. 5
7A26 : 000B
7A00 : 026B
751C : 50AB
Esto es una complicación para el programador y tiene problemas de seguridad
(se puede borrar cosas ya escritas) pantallas azules del Windows 98.
La base (segmento) apunta a párrafos (de 16 posiciones). Corresponde a las
bases que se les añaden los 0 al final.
En ensamblador no se representan las direcciones como base:desplazamiento,
aunque algunos depuradores lo admitan. Los desplazamientos llevan asociados una base
por defecto. Cuando es necesario especificar se hace de manera simbólica (usando el
nombre del registro segmento) -> prefijo.
Tabla de segmentos empleados por defecto para cada uno de los registros de
desplazamiento que se encuentran en la primera columna:
Offset
IP
SP
BP
BX
SI
DI
Base
CS
Sí
No
Prefijo
Prefijo
Prefijo
Prefijo
SS
No
Sí
Por defecto
Prefijo
Prefijo
Prefijo
DS
No
No
Prefijo
Por defecto
Por defecto
Por defecto
ES
No
No
Prefijo
Prefijo
Prefijo
Por defecto (cadenas)
Representación en ensamblador:
Las direcciones pueden ser Near o Far:
 Near: solo el desplazamiento; la base toma el valor en curso de la
dada por defecto.
 Far: se requiere la especificación de la base y del desplazamiento.
3.- MODOS DE DIRECCIONAMIENTO:
Son los mecanismos que determinan la ubicación de los operandos. Hay tres
posibles ubicaciones:



Inmediatos (en la propia instrucción)
En registros
En memoria:
- Directos
- Absolutos
- Inmediatos
- Relativos.
INTEL.
ESTRUCTURA DE
COMPUTADORES.
Pág. 6

(Implícitos) -> sobreentendidos.
Momento en que se actualiza el modo de direccionamiento:



Inmediatos: tiempo de ensamblado.
En registros: tiempo de diseño(programación o compilación)
En memoria:
- Absolutos: tiempo de carga -> interviene el S.O.
- Relativos: tiempo de ejecución.
Absoluto
DIRECTO
Relativo
A registro
A memoria
A página base
A registro
Base
Base + desplazamiento
Índice
Contador de programa
Puntero a pila
INDIRECTO
IMPLÍCITO
3.1. – Inmediato: MOV AL, 15h
IP
0000
CS
DS
0100
0000
Dirección
01000
01001
8B
IP
0002
CS
DS
0100
0000
…
…
AX
BX
AX XX15
BX
…
…
Banco de registros
Memoria
Dirección
01000
01001
01002
Banco de registros
8B
Memoria
Antes Después
3.2. – Directo absoluto a registro: MOV AX, BX
IP
0000
CS
DS
0100
0000
Dirección
01000
01001
8B
IP
0002
CS
DS
0100
0000
…
…
AX XXXX
BX 7EA6
AX 7EA6
BX 7EA6
…
…
Banco de registros
Memoria
Banco de registros
Antes Después
Dirección
01000
01001
01002
8B
…
Memoria
Pág. 7
3.3. – Directo absoluto a memoria: MOV CX, ETIQUETA
IP
0000
CS
DS
0100
0200
Dirección
01000
01001
01002
01003
8B
0E
34
12
IP
0002
CS
DS
0100
0200
…
…
AX
BX
AX
BX
CX XXXX
03234
03235
Banco de registros
ED
BE
Dirección
01000
01001
01002
01003
01004
8B
0E
34
12
…
CX BEED
Memoria
Banco de registros
Memoria
Antes Después
ETIQUETA = 1234h
DS = 0200h · 16h = 02000h
+
ETIQUETA =
1234h
------------------------------------------03234h
3.4. – Directo relativo a registro (indirecto a memoria): MOV [BX] + ARTICULO, AL
IP
0000
CS
DS
0100
0500
Dirección
01000
01001
01002
01003
8B
87
00
50
IP
0002
CS
DS
0100
0500
…
…
AX XXFC
BX 1000
CX
AX XXFC
BX 1000
CX
0B000
0B001
Banco de registros
XX
XX
Memoria
Banco de registros
Antes Después
DS = 0500h · 16h = 05000h
Artículo =
5000h
+
BX = 1000h
------------------------------------------0B000h
Dirección
01000
01001
01002
01003
01004
0B000
0B001
8B
87
00
50
…
FC
XX
Memoria
Pág. 8
3.5. – Directo relativo a registro (indirecto a memoria): MOV DL, VECTOR[SI]
IP
0000
CS
DS
0100
B000
Dirección
01000
01001
01002
01003
01004
8A
94
00
AD
XX
IP
0002
CS
DS
0100
B000
…
…
AX
BX XXXX
CX
AX
BX XXED
CX
ED
BA000
Banco de registros
Memoria
Dirección
01000
01001
01002
01003
01004
8A
94
00
AD
XX
ED
BA000
Banco de registros
Memoria
Antes Después
DS = B000h · 16h = B0000h
+
ETIQUETA =
A000h
------------------------------------------BA000h
Vector = A000h
3.6. – Directo relativo a registro (indirecto a memoria): MOV AH, [BX][SI] + ARRAY
IP
0000
CS
DS
0100
0200
Dirección
01000
01001
01002
01003
01004
IP
0002
CS
DS
0100
0200
…
…
AX
BX
AX
BX
1000
CX
Banco de registros
06234
1000
06234
CX
Memoria
Dirección
01000
01001
01002
01003
01004
Banco de registros
Memoria
Antes Después
DS = 0200h · 16h = 02000h
Array =
1234h
+
BX = 1000h
SI = 2000h
------------------------------------------06234h
4.- FORMATO DE INSTRUCCIONES:
Es la codificación binaria de las instrucciones de máquina. El formato debe
proporcionar información acerca de:
- Operación a realizar.
- Operandos y resultado.
- Siguiente instrucción (secuencia implícita).
El 80x86 cuenta con dos formatos: formato general y formato especial (con
campo de extensión o con prefijo).
Formato general:
Pág. 9
Lo tienen todos:
Byte 1
Código
Byte 2
d
w
Mod
Byte 3
reg
Byte 4
r/m
Desplazamiento o dato inmediato
r/m y Mod = especifica un operando registro o memoria.
Reg = especifica un operando registro.
W = determina el tamaño de los operandos.
D = determina el operando fuente y destino.
Código = código de operación.
El primer byte contiene tres clases de información: código de operación -> los 6
primeros bits contienen el código de la operación a realizar. El bit de dirección de
registro (D) especifica si el operando dado por el campo de registro (operando Reg) en
el segundo byte es el operando fuente o destino: si D = 1 tengo que Reg = operando
destino, si D = 0 tengo que Reg = operando fuente. El bit de tamaño de dato (W)
especifica si la operación será realizada sobre datos de 8 o 16 bits. W = 0 8 bits, W = 1
16 bits.
El segundo byte contiene los siguientes operandos: una siempre es un registro
que viene dado por reg, el otro puede ser registro o memoria que viene dado por Mod y
r/m. No se advierten las operaciones entra dos operandos ubicados en memoria.
Campo Reg:
El tamaño W nos dice si es byte (8 bits) W = 0.
Word (16 bits) W = 1.
Campo Mod y R/M
Mod = 11 referenciamos registro
Mod 01 -> se le suma desplazamiento 8 bits
Mod 10 -> se le suma desplazamiento 16 bits
MOD = 11
REG – R/M
W=0
000
001
010
011
100
101
110
111
AL
CL
DL
BL
AH
CH
DH
BH
W=1
AX
CX
DX
BX
SP
BP
SI
DI
MOD = 00
MOD = 01
MOD = 10
DS:[BX]+[SI]
DS: [BX]+[DI]
SS:[BP]+[SI]
SS:[BP]+[DI]
DS: [SI]
DS: [DI]
Dirección
DS: [BX]
DS:[BX]+[SI]+D8
DS:[BX]+[DI]+D8
SS:[BP]+[SI]+D8
SS:[BP]+[DI]+D8
DS: [SI] + D8
DS: [DI] + D8
SS: [BP] + D8
DS: [BX] + D8
DS:[BX]+[SI]+D16
DS:[BX]+[DI]+D16
SS:[BP]+[SI]+D16
SS:[BP]+[DI]+D16
DS: [SI] + D16
DS: [DI] + D16
SS: [BP] + D16
DS: [BX] + D16
Pág. 10
Dirección -> ese código se reserva para dar direcciones absolutas a memoria.
Formato especial con campo de extensiones:
Se necesitan 2 bytes para determinar la operación a realizar.
Byte 1
Byte 2
Byte 3
Byte 4
Byte 5
Byte 6
MOD REG R/M
Campo de extensión
Desplazamiento y/o dato inmediato.
Se usa para aumentar el número de operaciones. Tiene que esperar a leer el
segundo byte para saber cuál es la operación concreta que tiene que realizar.
Los campos Mod y R/M dan lugar al operando (registro o memoria). El campo
REG da el código de operación completando el campo de extensión.
Campo de extensión
80, 81, 82, 83
D0, D1, D2, D3
F6, F7
FE, FF
Grupo
Inmediatos
Desplazamientos
Grupo I
Grupo II
Formato especial con prefijo:
Byte 0
Byte 1
Byte 2
Prefijo
PREFIJO
CS
DS
SS
ES
REP
REPZ / REPE
REPNZ / REPENE
LOCK
Ejemplo:
EFECTO
Modificamos la base por defecto
Repetición de instrucción de cadena
Sincronización con coprocesador
Pág. 11
MOV AX, [BX] [SI]
DS x 16 + [BX] [SI]
CS : MOV AX, [BX][SI]
CS x 16 + [BX] [SI]
Ejercicio:
La instrucción MOV BL, AL mueve el byte contenido en el registro fuente
AL al registro BL. Escribir el código máquina de la instrucción sabiendo que el
código de operación es 1000102.
En el primer byte los primeros 6 bits especifican la operación y debe ser:
Código de operación = 1000102
El bit D indica si el registro que señala el campo REG del segundo byte es el
operando fuente o el destino. Codificamos el registro AL en el campo REG y por tanto
D será igual a 0. El bit W debe indicar una operación de tamaño = 0 (byte valor 0).
Primer byte
1000 10002 = 88 h
En el segundo byte, REG, indica el operando limite que es AL. Su código
correspondiente es: REG = 000.
Como el segundo operando es también un registro MOD debe valer 11. El
campo R/M debe especificar que el registro destino es BL y su codificación es 011. Esto
da:
MOD = 11
R/M = 011
Segundo byte = 1100 00112 = C3 h
El código hexadecimal completo para la instrucción es:
MOV BL, AL = 88 C3 h
También se podría haber puesto D = 1, REG = 011 y R/M = 000.
5.- LA FAMILIA INTEL 80x86
1971 -> Llamado 4004
 Fecha de comercialización: noviembre 1971.
 Frecuencia de reloj: 108 Khz.
 Número de transistores: 2300 (tecnología 10 micras)
 Diseñado para calcular.
1972 -> 8008 (solo tiene el registro AX acumulador).
1974 -> 8880
 Para diseñar control de semáforos y Altaír (primer PC).
 Memoria direccionable 64 Kbytes.
 Añade bus de datos 8 bits.
 Tamaño registros 8 bits.
1976 -> 8085
Pág. 12
1978 -> 8086
 Es híbrido (acumulador y banco de registros) porque hereda las
características de los anteriores.
 Ancho bus de datos16 bits
 Memoria direccionable 1 Mbyte.
1979 -> 8088
1985 -> Intel 386
1989 -> Intel 486
1993 -> Intel Pentium Processor
1995 -> Intel Pentium Pro Processor
1997 -> Intel Pentium MMX (multimedia extensions)
1998 -> Intel Pentium II
1999 -> Intel Pentium III
El desarrollo de las tecnologías de fabricación permite que el número de transistores
integrados de los microprocesadores aumente cada 18 meses. La progresión del
desarrollo de procesadores puede visualizarse en una gráfica de acuerdo a la ley de
Moore.
Pág. 13
INSTRUCCIONES DE TRANSFERENCIA 80x86:
1.- Generalidades.
2.- Movimiento de datos.
3.- Estructura de signo.
4.- Transferencia de puntero.
5.- Transferencia con la pila.
6.- Entrada / Salida.
1.- Generalidades:
El primer operando es el operando destino. El segundo operando es el operando
fuente. No se pueden realizar operaciones donde ambos operandos residan en memoria.
Las instrucciones de transferencia NO alteran el registro de estado.
Los ejemplos son de dos clases:
- En ensamblador puro [RO88]
- En ensamblador con directivas [Mi87], directivas-> instrucciones
para el programa ensamblador que suponen una ayuda para el
programador: soporte de etiquetas, punteros a direcciones que
resuelve el sistema operativo en tiempo de carga, etc...
2.- Movimiento de datos:
MOV: {registro/memoria}, {registro/memoria/inmediato}
Transfiere un byte o una palabra desde fuente a destino. El operando fuente no
se destruye. Ambos operandos deben ser del mismo tamaño.
Ejemplo:
; AX = FFFF h
; BX = 1234 h
MOV AX, BX
; AX = 1234 h
; BX = 1234 h
Restricciones:
No se puede mover datos entre dos posiciones de memoria; hay que utilizar un
registro intermedio:
MOV AX, mem1
MOV mem1, AX
No se puede mover un intermedio a un registro de segmento; hay que usar un
registro intermedio. (Método de seguridad)
MOV AX, 1234 h
; AX = 1234 h
Pág. 14
MOV DS, AX
; DS = 1234 h
El registro de segmento CS no puede ser destino.
XCHG:{registro/memoria}, {registro/memoria}
Intercambia el contenido de los operandos. Es útil para evitar el uso de una
variable temporal.
Ejemplo:
; AX = FFFF h
; BX = 0000 h
XCHG AX, BX
; AX = 0000 h
; BX = FFFF h
XLAT: {memoria}
En este caso memoria es el desplazamiento sobre DS. Prefijo XLAT memoria.
En este caso el segmento viene dado por el prefijo y el puntero a memoria será:
Prefijo : memoria
La instrucción XLAT carga en AL un valor de una tabla de memoria. Es útil
para traducir entre sistemas de codificación. La tabla debe ser de de bytes y no puede
tener mas de 256 bytes; el primero tiene desplazamiento 0. La base de la tabla se coloca
en BX y el puntero en AL.
AL <- [BX+AL]
Ejemplo:
TABLA DB 1, 2, 3, 4, 5, 6, 7
MOV BX, OFFSET TABLA
MOV AL, 4
XLAT TABLA
; declaración
; carga BX
; 5º valor
; AL = 5
Esto es equivalente a:
MOV AL TABLA [4]
Ejemplo:
Tabla que permite traducir ASCII a EBCDIC.
El código ASCII sirve de índice, por ejemplo el índice
32 apunta al “2” en EBCDIC.
Valor
XX
XX
…
F0
F1
…
Dirección
TABLA[0]
TABLA[1]
…
TABLA[30]
TABLA[31]
…
Pág. 15
LAHF:
Carga los 8 bits más bajos del registro de estado (banderas de estado) en AH.
AH <- banderas de estado (bits 0, 2, 4, 6, 7)
SAHF:
Recupera las banderas de estado desde AH.
Banderas de estado<-AH
Las instrucciones de transferencia de las banderas de estado se suelen usar para
mover dicho byte de estado entre coprocesadores. Para manejar el conjunto completo
del registro de estado se deben usar instrucciones de transferencia con la pila: PUSHF,
POPF.
3.- Extensión de signo:
Antes de poder mover datos de diferentes tamaño es necesario extender
adecuadamente el signo. El procedimiento es distinto si el número es considerado con
signo o sin signo, pero es el programador el que debe tenerlo en cuenta ya que la
máquina no advierte la diferencia. Cuando el valor tiene signo se usa CBW o CWD.
Cuando el valor es sin signo se rellena con ceros.
CBW:
Sirve para convertir byte en palabra. Copia el bit 7 del registro AL en todo el
registro AH.
CWD:
Sirve para convertir palabra en doble palabra. Copia el bit 15 del registro AX en
el registro DX.
Doble palabra -> DX: AX
Ejemplo con signo:
mem8
mem16
.DATA
DB -5
DW -5
.CODE
MOV AL, mem8
CBW
MOV AX, mem16
CWD
; declaración
; declaración
; carga AL = F8 h
; AX = FFFB h (-5)
; Carga AX = FFFB h
; DX = FFFF h
; DX : AX = (-5)
Pág. 16
Ejemplo sin signo:
mem8
mem16
.DATA
DB 251
DW 251
; declaración (FB h)
; declaración (FFFB h)
.CODE
MOV AL, mem8
XOR AH, AH
MOV AX, mem16
XOR DX, DX
; carga AL = F8 h (251)
; AX = 00FB h (251)
; Carga AX = FFFB h
; DX : AX = 0000 FFFF h
4.- Transferencia de punteros:
Usamos instrucciones para cargar punteros a memoria en registros. Los punteros
pueden ser:


Near -> dentro de un registro, no excede 64 k posiciones; basta
conocer el desplazamiento. El comando es LEA.
Far -> entre segmentos excede los límites del segmento y se
requiere una base y un desplazamiento. Los comandos son LES y
LDS.
LEA: {registro, memoria}
Carga un puntero near en un registro, el puntero es la dirección efectiva de la
posición de memoria especificada en el operando fuente. El operando destino puede ser
cualquiera de propósito general. No están permitidos los registros de segmento. El
operando fuente es una posición de memoria especificada por cualquier modo de
direccionamiento.
Ejemplo:
Transfiere el desplazamiento del operando fuente al destino
LEA AX, 1234 (SI)
; si SI = 1000 h
; AX = 1234 +1000
; AX = 2234 h
Advertencias respecto a LEA:
LEA DX, cadena
MOV DX, OFFSET cadena
Dan el mismo resultado pero es más rápida la segunda ya que la posición de
cadena en el área de datos es conocida en tiempo de ensamblado. Usaremos LEA
cuando queremos transferir un desplazamiento no conocido en tiempo de diseño:
LEA DX, cadena [SI]
Pág. 17
MOV DX, OFFSET cadena [SI] : no funciona.
LES: {registro, memoria}
Transfiere un puntero far (32 bits ) especificado como base y desplazamiento al
registro dado en el operando destino y el registro ES.
ES -> salva la base.
El registro destino salva el desplazamiento, no se aceptan los registros de
segmento. El operando fuente es una posición de memoria de tamaño doble palabra (32
bits).
Los punteros en memoria se salvan por este orden:
Palabra de menor peso -> desplazamiento
Palabra de mayor peso -> base.
Ejemplo:
Dirección
VALOR
PTR -> 1234 : 5678
LES DI, PTR
; DI = 5678 h
; ES = 1234 h
PTR (0)
PTR (1)
PTR (2)
PTR (3)
78
56
34
12
LDS: {registro, memoria}
Transfiere un puntero far (32 bits ) especificado como base y desplazamiento al
registro dado en el operando destino y el registro DS.
DS -> salva la base
Registro destino-> salva el desplazamiento (no se aceptan los registros de
segmento)
El operando fuente es una posición de memoria de tamaño doble palabra (32
bits)
Ejemplo:
cadena
puntero
array
.DATA
DB “Esto es una cadena”
DD cadena
DD 100 DUP (?)
.CODE
; cadena
; salvo PTR
; reservo array
Pág. 18
LES DI, puntero
LDS SI, array (BX)
; ES : DI <- ptr
; DS : SI <- array (BX)
5.- Transferencia con pila:
La pila es un área de memoria para almacenar datos temporalmente; dos causas:
paso de parámetros a procedimientos y salvar el valor de registro cuando deben ser
utilizados por otra variable.
El acceso a la pila no es aleatorio sino secuencial según marca el puntero de pila
(SP); es del tipo LIFO.
En el 8086 el SP comienza en las posiciones más altas y avanza hacia las más
bajas. Las instrucciones que trabajan con la pila solo especifican un operando ya que el
otro es implícito (la cima de la pila). Estas instrucciones también actúan de manera
implícita sobre el puntero de pila (SP): decrementándolo cuando introducen datos y
incrementándolo cuando sacan datos y aumentándolo al sacarlos.
Las transferencias son de tamaño palabra (16 bits). El SP se actualiza de dos en
dos. Si queremos realizar operaciones e tamaño byte seremos nosotros los que
actualizaremos SP.
PUSH: {registro/memoria}
Pone una palabra nueva en la pila. Decrementa el SP en 2 y coloca el operando
en la pila. El operando nunca puede ser CS.
SP <- SP – 2
SS : SP <- operando
Posiciones
altas
SP
SP
AH
AX
Antes de PUSH AX
Después de PUSH AX
Posiciones
bajas
Ejemplo:
PUSH AX
; pone AX en la cima de la pila.
Es equivalente a:
SUB SP, 2
MOV [SP], AX
; SP <- SP + 2
; SS : SP <- AX
No funcionaría, daría error
sintáctico. Habría que hacer:
SUB SP, 2
MOV BP, SP
MOV [BP], AX
Pág. 19
POP: {registro /memoria}
Saca palabra de la pila. Copia el dato que esta en la cima de la pila en el
operando especificado e incrementa el SP en dos. El operando nunca puede ser CS.
Operando <- SS : SP
SP <- SP + 2
Ejemplo:
POP AX
; carga AX con el valor cima de la pila
Es equivalente a:
MOV AX, [SP]
ADD SP, 2
; AX <- SS : SP
; SP <- SP + 2
Las instrucciones PUSH y POP se usan casi siempre por parejas cuando el uso
de la pila se debe a falta de almacenamiento temporal. Las variables salvadas en la pila
con PUSH normalmente se sacan de la misma, en orden inverso, con POP. Así
normalmente tendré el mismo número de PUSH que de POP.
PUSH AX
PUSH BX
…
POP BX
POP AX
Ejemplo:
MOV CX, 10
EXTERNO:
INTERNO:
…..
…..
…..
…..
PUSH CX
MOV CX, 20
…..
…..
; salvamos contador externo
…..
…..
LOOP INTERNO
…..
POP CX
LOOP EXTERNO
; se ejecuta 20 veces
; recupera el bucle del contador
; se ejecuta 10 veces
Pág. 20
Sin embargo es posible devolver la pila a la situación original actualizando el
valor de SP adecuadamente. Para acceder a parámetros en la pila podemos usar BP.
Ejemplo:
MOV BP, SP
PUSH AX
PUSH BX
PUSH CX
…..
…..
MOV AX, [BP - 6]
MOV BX, [BP - 4]
MOV CX, [BP - 2]
…..
…..
ADD SP, 6
; salvo el marco de la pila
; SP = BP - 2
; SP = BP - 4
; SP = BP - 6
; recupero el tercer parámetro
; BX <- SS : BP - 4
; CX <- SS : BP - 2
; devuelve el SP a su valor inicial
PUSHF:
Transfiere el registro de estado completo a la pila.
SP <- SP – 2
SS : SP <- registro de estado
POPF:
Carga el registro de estado completo con el contenido de la cima de la pila.
Registro de estado <- SS : SP
SP <- SP +2
Sirve para modificar flags que de otra forma no se podrían tocar, como el Trap
(paso a paso)…
6.- Entrada / Salida:
Los mapas de memoria y de entrada / salida en las maquinas 80x86 son
disjuntos. Cuando se emite una dirección en el bus de direcciones es necesario
especificar si es de memoria o de entrada / salida. Por esto contamos con instrucciones
especificas de entrada / salida. IN -> Señal IO / M = 1, señal RD activa; OUT -> señal
IO / M = 1, señal WR activa.
IN: Acc, (puerto / DX)
Carga el acumulador con un valor leído en el puerto de entrada / salida
especificado por el operando fuente. El puerto puede ser un incremento de tamaño byte
Pág. 21
(puertos 0 - 255). Por encima de este punto hay que darlo como DX (puertos 0 –
65536). El tamaño de la transferencia viene dado por Acc. Si es AX -> tamaño palabra.
Si es AL -> tamaño byte.
Ejemplos:
IN AX, 12h ; leer sobre AX una palabra del puerto 12h.
IN AL, DX ; leer sobre AL un byte del puerto especificado en DX.
OUT: (puerto / DX), Acc
Escribe el contenido del acumulador en el puerto especificado del procesador. El
puerto puede ser un incremento de tamaño byte (puertos 0 - 255). Por encima de este
punto hay que darlo como DX (puertos 0 – 65536). El tamaño de la transferencia viene
dado por Acc. Si es AX = tamaño palabra. Si es AL = tamaño byte.
Normalmente las entradas y salidas se realizan mediante llamadas al sistema
operativo (que a su vez realiza llamadas a la BIOS).
INT 21 h -> bajo D.O.S.
API -> bajo Windows
Sin embargo estas instrucciones proporcionan un método para entrada salida
directamente. ¡OJO! Pueden dar problemas de portabilidad.
Ejemplo:
OUT 12h, AX ; Transferir el valor de AX al puerto 12h.
OUT DX, AL ; Transferir el valor de AL al puerto especificado en DX.
Pág. 22
INSTRUCCIONES DE PROCESO ARITMETICAS:
1.- Generalidades.
2.- Suma.
3.- Resta.
4.- Multiplicación.
5.- División.
6.- Operaciones en BCD.
1.- Generalidades:
El primer operando es el destino de la operación realizada. Reemplaza su valor
inicial por el resultado. No se pueden realizar operaciones donde ambos operandos
residan en memoria. Todas las operaciones aritméticas afectan al registro de estado.
2.- Sumas:
Realizan sumas:
ADD (registro / memoria), (registro / memoria / inmediato)
ADC (registro / memoria), (registro / memoria / inmediato)
INC (registro / memoria)
Por si mismo suman valores de tamaño byte o palabra. En conjunción pueden
realizar sumas de 32 bits. Con las instrucciones de ajuste ASCII pueden operar con
números BCD.
ADD: (registro/memoria) (registro/memoria/inmediato)
Suma los operandos y salva el resultado en el operando destino. Los operandos
deben ser del mismo tipo (byte o palabra). Las banderas afectadas son: CF, PF, AZ, ZF,
SF y OF. La operación puede ser interpretada tanto con signo como sin signo. Es
responsabilidad del programador interpretar correctamente el resultado. Si hay
desbordamiento es posible numero con signo OF = 1. Si hay desbordamiento es posible
numero sin signo CF = 1.
Ejemplo:
Programa:
.DATA
mem8 DB 29
.CODE
AL
MOV AL,26
1A=00011010
INC AL
ADD AL,76
1B=00011011
67=01100111
OF
CF
NV 0 = no NC 0 =
overflow
no carry
NV 0
NC 0
NV 0
NC 0
Sin signo
Con signo
26
26
27
103
27
103
Pág. 23
ADD AL, mem8
8E=10001110
OV 1 = NC 0
overflow
MOV AH, AL
ADD AL, AH
1C=00011100
OV 1
142
CY 1 = 28
carry
carry**
* Porque el rango con signo es [-128,127] estamos trabajando con 8 bits.
En realidad lo que quiere decir este resultado es que hay un error.
** rango = [0, 255]. Me e excedido 28 sobre 256.
-114 +
desbordamiento*
+
27: 11011
+ 76: 1001100
01100111
+ 39: 100111
10001110
+ 10001110
100011100
En el ejemplo anterior el programador puede gobernar la secuencia del programa
en función del estado que considere oportuno. Usará el estado condicional que lee el
estado deseado -> desbordamiento si opera con signo, acarreo si opera sin signo.
ADC: (registro/memoria) (registro/memoria/inmediato)
Suma igual que ADD pero incluye en la suma la bandera de acarreo CF. Las
banderas afectadas son: CF, PF, AF, ZF, SF y OF. Sirve para realizar sumas de tamaño
32 bits. Utilizaremos dos registros, es conveniente que sean DX : AX. La suma de
menor peso se realiza con ADD y la suma de mayor pero se realiza con ADC.
Suma los dos operandos e incrementa el resultado en uno si está activada la
bandera de acarreo CF. Los operandos deben ser del mismo tipo (byte o palabra).
Ejemplo: suma de números de 32 bits:
Fuente = DX, CX Destino = BX, AX
ADD AX, CX ; sumar palabras inferiores
ADC BX, DX ; sumar palabras superiores con acarreo
Ejemplo:
mem32
.DATA
DD 316423
.CODE
MOV AX, 43981
XOR DX, DX
ADD AX, WORD PTR mem32[0]
ADC DX, WORD PTR mem32[2]
DX:AX = 43981
+ 316423
360404
INC: (registro / memoria)
Las banderas afectadas son PF, AF, ZF, SF y OF. No modifica la bandera de
acarreo. Funciona como un contador no saturado (da “vueltas” al contador).
Pág. 24
3.- Restas:
Las instrucciones que realizan restas son:
SUB (registro/memoria) (registro/memoria/inmediato)
SBB (registro/memoria) (registro/memoria/inmediato)
DEC (registro/memoria)
NEG (registro/memoria)
Por si mismas restan valores de tamaño byte o palabra. En conjunción pueden
realizar restas de 32 bits. Con las instrucciones de ajuste ASCII pueden trabajar con
números BCD.
SUB: (registro/memoria) (registro/memoria/inmediato)
Resta los operandos y salva el resultado en el operando destino.
Operando destino <- operando destino – fuente.
Las banderas que se usan son CF, PF, AF, ZF, SF y OF. La operación puede ser
interpretada tanto sin signo como con signo. Es responsabilidad del programador
interpretarlo correctamente.
Ejemplo:
Programa
AL
OF
SF
Sin
Signo
Con Signo
.DATA
mem8 DB 122
.CODE
MOV AL, 95
5F = 01011111
NV 0
PL 0
95
95
DEC AL
5E = 01010110
NV 0
PL 0
94
94
SUB AL, 23
47 = 01000111
NV 0
PL 0
71
71
SUB AL, mem8
CD = 11001101
NV 0
NG 1
205
+
signo**
-51
5E = 01010110
OV 1
NG 1
MOV AH, 119
SUB AL, AH
85
+
desbordamiento*
* -51 -119 = -170; 256 -170 = 86
** 71 – 122 = -51 → 256 -51 = 205
SBB: (registro/memoria) (registro/memoria/inmediato)
Resta igual que SUB pero incluye en la suma la bandera de acarreo CF. Las
banderas que utiliza son = CF, PF, AF, ZF, SF y OF. La resta de menor peso se realiza
con SUB, y la resta de mayor peso con SBB. Sirve para realizar restas de tamaño 32
Pág. 25
bits. Utiliza dos registros, es conveniente que sean DX : AX. Si el flag de carry CF está
activo decrementa una unidad al resultado final de la operación.
Ejemplo:
mem32a
mem32b
.DATA
DD 316423
DD 156739
.CODE
MOV AX, WORD PTR, mem32a[0]
MOV DX, WORD PTR, mem32a[2]
SUB AX, WORD PTR, mem32b[0]
SUB DX, WORD PTR, mem32b[2]
DX : AX = 316423
- 156739
159684
DEC: (registro/memoria)
Las banderas que usa es PF, AF, ZF, SF y OF. No modifica la bandera de
acarreo ya que trata al operando como un número sin signo. Funciona como un
contador no saturado (da “vueltas” al contador).
NEG: (registro/memoria)
Calcula el negativo de operando en complemento a dos, es decir, resta el
operando de cero y devuelve el resultado en el mismo operando. Es equivalente a:
NOT (registro/memoria).
INC (registro/memoria).
Afecta a todas las banderas de estado.
4.- Multiplicación:
Las instrucciones que realizan multiplicaciones son:
MUL (registro/memoria) -> Números sin signo.
IMUL (registro/memoria) -> Números con signo.
AX <- operando fuente * AL <- 8 bits, resultado 16
DX : AX <- operando fuente * AX <- 16 bits, resultado 32
Si la mitad superior es no cero se indica con CF y OF.
Operando en 16 bits, CF = OF = 1 si la parte alta de DX ≠ 0.
Ejemplo:
mem16
.DATA
DW -30000
.CODE
; multiplicar 8 bits sin signo.
Pág. 26
MOV AL, 23
MOV BL, 24
; carga AL 23
; carga BL 24
MUL BL
; AX = 522, CF, OF
; multiplicar 16 bits con signo
; carga AX 50
; DX : AX = -150000, CF, OF
MOV AX, 50
IMUL, mem16
Excede AL
Excede AX
Multiplicar es una operación muy lenta. Muchas veces es conveniente sustituir
por:
 Desplazamientos a la izquierda si el factor es potencia de dos.
 Salto condicional para evaluar si es: 0 -> sustituir por cero.
1-> sustituir por el multiplicando.
5.- División:
Realizan divisiones:
DIV {registro / memoria} -> números sin signo
IDIV {registro / memoria} -> números con signo
Operados:
Dividendo -> AX o DX : AX
Divisor -> operando fuente (excepto AX y/o DX)
Operaciones de 16 bits entre 8 bits:
AH (resto) / AL (cociente) <- AX ÷ operando fuente.
Operaciones de 32 bits entre 16 bits:
DX (resto) / AX (cociente) <- DX : AX ÷ operando fuente.
Operaciones de 16 bits entre 16 bits:
Es necesario extender el dividendo a 32 bits (con o sin signo).
Si el divisor es 0 o el cociente excede el registro acumulador el procesador
genera una interrupción cero (INT 0). Bajo DOS por defecto el programa termina y
devuelve el control al DOS. Para solucionarlo se debe comprobar si es cero antes de
operar (mandar a rutina – se pierde tiempo-) o reescribir la rutina de atención a la INT 0.
Ejemplo:
mem16
mem32
.DATA
DW -2000
DD 500000 ; 11110100001001000002
.CODE
MOV AX, 700
; carga el dividendo
Pág. 27
MOV BL, 36
DIV BL
; carga el divisor
; divide entre BL (cociente : AL = 19)
(resto : AH = 16)
MOV AX, WORD PTR mem32[0] ; cargamos dividendo en DX : AH
MOV DX, WORD PTR mem32[2]
IDIV mem16
; cociente : AX = -250;
; resto : DX = 0;
Ejemplo:
mem16
mem32
.DATA
DW -2000
DD 500000
.CODE
MOV AX, WORD PTR mem16
CWD
MOV BX, -421
IDIV BX
; divide 16 bits con signo entre 16 bt
; extendemos a DX : AX
; cociente : AX = 4
; resto : DX = -326
Dividir es una operación muy lenta. Muchas veces es conveniente sustituir por:
desplazamientos a derecha si el factor es potencia de dos, salto condicional para evaluar
si el divisor es 1 que se sustituiría por el dividendo o cambiar divisiones por
multiplicaciones: numero / 5 es lo mismo que el número + 0.2. No siempre se puede
hacer. Hay que saber el divisor en tiempo de ensamblado.
6.- Operaciones en BCD:
Hay dos tipos de instrucciones. Una de ellas son las de ajuste ASCII que es el
BCD desempaquetado y las operaciones que se pueden realizar son la suma, la resta, la
multiplicación y la división. El otro tipo de instrucciones son las de ajuste decimal, son
el BCD empaquetado, utiliza la suma y la resta.
El BCD son números decimales codificados en binario.
Ejemplo:
109
‘9’ BCD -> 1001
‘0’ BCD -> 0000
‘1’ BCD -> 0001
En binario no tiene por qué ser así la codificación. Trabaja con 4 bits, por tanto
en 1 byte se pueden escribir dos dígitos BCD. Cuando se aprovechan los dos dígitos se
llama empaquetado. Si no, entonces en el primer dígito se pone un 0 y en el segundo se
pone el carácter BCD, entones se llama BCD desempaquetado. El BCD se inventó para
procesar los números en calculadoras pequeñas.
AAA: Ajuste ASCII en suma. Ajusta el resultado después de una suma
Pág. 28
Ejemplo:
Resultado en AL
MOV AX, 9
MOV BX, 3
ADD AL, BL
AAA
; AL = 0C h
; AL = O2 h
; AH = 01 h, cf
(Desempaquetado)
Se activa el flag de acarreo porque al sumar dos dígitos BCD me he pasado de 9,
que es el límite de representación. El ajuste ASCII se hace solo sobre resultados que
estén el AL.
AAS: ajusta el resultado después de una resta.
Ejemplo:
MOV AX, 103 h
MOV BX, 4
SUB AL, BL
AAS
; AL = 0FF h (-1)
; AL = 09 h
; AH = O h
; cf
AAM: ajusta el resultado después de una multiplicación.
Ejemplo:
MOV AX, 903 h
MUL AH
AMM
; AL = 1B h
; AL = 02 h
; AH = 07 h
No usar IMUL
AAD: ajusta el resultado antes de una división.
Ejemplo:
MOV AX, 205 h
MOV BL, 2
AAD
DIV BL
AAM
; dividendo BCD desempaquetado
; divisor
; AX = 19 h
; AL = 0C h
; AH = 01 h
; AX = 0102h
; resto perdido
Con BCD empaquetado:
DAA: ajusta el resultado después de una suma.
Pág. 29
Ejemplo:
MOV AX, 8833 h
ADD AL, AH
DAA
; AL = 0BB h
; 121 -> CF = 1
; AL = 21 h
DAS: ajusta el resultado después de una resta.
Ejemplo:
MOV AX, 3883 h
SUB AL, AH
DAS
; AL = 04B h
; 45 -> CF = 0
; AL = 45 h
Pág. 30
INTRUCCIONES DE PROCESO (LÓGICAS):
Índice:
1.- Generalidades.
2.- Operaciones lógicas.
3.- Desplazamientos y rotaciones.
1.- Generalidades:
El primer operando es el destino de la operación realizada reemplazando su
valor inicial por el resultado. Las instrucciones lógicas alteran el registro de estado. No
se pueden realizar operaciones donde ambos operandos residan en memoria. Las
instrucciones lógicas realizan operaciones booleanas sobre bits individuales. Cada
resultado en el bit i-ésimo solo depende de los bits i-ésimos de los operandos de entrada
que son los más rápidos. No conllevan propagaciones de acarreos, etc., no son funciones
del peso (≠ f(peso)).
El repertorio del 80x86 da soporte a las operaciones lógicas AND, OR, XOR
entre dos operandos (diádicas) y a la NOT de un operando (monárica). Se suelen usar
combinando un operando con una “máscara”. La máscara tiene diferentes formas
dependiendo de la operación, se utiliza para modificar o extraer información de unos
bits y obviar la de otras. Las instrucciones no han de confundirse con los operadores, las
primeras operan en tiempo de ejecución, las segundas son órdenes para el ensamblador,
se distinguen por el contexto.
2.- Operaciones Lógicas:
AND (registro/memoria) (registro/memoria/inmediato)
Realiza la operación lógica AND. Se puede usar para poner a cero un bit
independientemente de su valor actual, la máscara contendrá un 0 allá donde queramos
colocar un cero y un 1 donde queramos dejar intacto el bit original.
Ejemplo: Convertir un character a mayúsculas y comprobar si es Y
MOV AX, 035h
AND AX, 0FBh
AAND AX, 0FBh
MOV AH, 7
INT 21 h
AND AL, 1101 1111b
CMP AL, ‘Y’
JE YES
YES: .
.
.
; 0011 0101
; 1111 1011
; 0011 0001 ← FBh es una mascara, pone a 0 el bit
; 0011 0001
; 1111 1000
; 0011 0000
; Servicio 7 de INT 21 h
; entrada carácter sin eco
; convierte a mayúsculas.
; ¿es ‘Y’?
; si es ‘Y’ salta a la rutina
; si no es ‘Y’ continúa
; rutina
Pág. 31
OR (registro/memoria) (registro/memoria/inmediato)
Realiza la operación lógica OR. Se puede usar para poner a 1 un bit
independientemente de su valor actual. La máscara contendrá un 1 allá donde queramos
colocar un 1 y un 0 donde queramos dejar intacto el bit original. También se usa para
comparar con 0.
Ejemplo:
MOV AX, O35 h
OR AX, 08h
OR AX, 07h
OR BX, BX
=
JG
JL
CMP BX, 0
;
0011 0101
; or
0000 1000
;
0011 1101
;
0011 1101
; or
0000 0111
;
0011 1111
; ¿es BX = 0?
; ocupa dos bytes, tarda 2 ciclos
; si BX positivo
; si BX negativo
; si BX cero
; ocupa tres bytes, tarda tres ciclos
Es más sencillo hacer OR que hacer la comparación.
XOR (registro/memoria) (registro/memoria/inmediato)
Realiza la operación lógica XOR. Se puede usar para conmutar el valor de bits
específico. La máscara tendrá un 1 allá donde quieras conmutar. También se usa para
poner a cero un registro.
Ejemplo:
MOV AX, 035 h
XOR AX, 08h
;
0011 0101
; xor 0000 1000
;
0011 1101
;
;
0011 1101
XOR AX, 07
; xor 0000 0111
;
0011 1010
XOR CX, CX
; ocupa dos bytes, tarda 3 ciclos
; actualiza el estado
MOV CX, 0
; ocupa 3 bytes, tarda 4 ciclos.
; no actualiza el estado
SUB CX, CX
; ocupa 2 bytes tarda 3 ciclos
; actualiza el estado.
Normalmente se usa XOR aunque es igual que SUB.
NOT (registro/memoria)
Complementa todos los bits del operador. Un uso típico es invertir el significado
de una máscara.
Pág. 32
Ejemplo:
mascara
.DATA
DB 0001 0000 b
. CODE
MOV AX, 0D743
OR AL, mascara
NOT mascara
AND AH, mascara
; AL = 0100 0011
; or
0001 0000
;
0101 0011
; invierte el significado
; AH = 1100 0111
; and 1110 1111
;
1100 0111
Si el destino es de tipo byte:
destino = FFh – destino
Si el destino es de tipo palabra:
destino = FFFFh – destino
Ejemplo:
AL = F2h = 1111 00102
NOT AL ; AL = ODh = 0000 11012
3.- Desplazamientos y rotaciones:
Conjunto de operaciones para desplazar y rotar bits a derecha e izquierda.
Algunas conservan el signo si es necesario. Pasan por el acarreo. El operando fuente es
el contador, es decir, es el número de bits que se van a desplazar. El 1 es privilegiado, se
hace en menos tiempo porque la máquina solo sabe desplazar de uno en uno.
* Desplazamientos:
SHL {registro/memoria}, {CL/1}; Desplazamiento a la izquierda.
7
0
CF ←         ← 0
Shift Left
SHR {registro/memoria}, {CL/1}; Desplazamiento a la derecha.
7
0
0 →         → CF
Shift Right
SAL {registro/memoria}, {CL/1}; Desplazamiento aritmético a la
izquierda.
7
0
CF ←         ← 0
Shift Arithmetic
Left
SAR {registro/memoria}, {CL/1}; Desplazamiento aritmético a la
derecha. Respeta el signo, al copiar el 7º bit sobre sí mismo.
7
0
Shift Arithmetic
        → CF
Right
Pág. 33
SHL y SAL son la misma operación: desplazar los bits del operando destino a la
izquierda el número de veces indicado en el operando fuente. Los bits de la derecha se
rellenan con ceros. Si el número de bits a desplazar es 1, se puede especificar
directamente, en caso contrario, su valor se guarda en CL.
* Rotaciones:
ROL {registro/memoria}, {CL/1}; Rotación a la izquierda.
7
0
CF ←        
ROR {registro/memoria}, {CL/1}; Rotación a la derecha.
7
0
        → CF
RCL {registro/memoria}, {CL/1}; Rotación a través del carry a la
izquierda.
7
0
← CF ←        
RCR {registro/memoria}, {CL/1}; Rotación a la derecha a través del
carry.
7
0
        → CF →
* Multiplicación y división por constantes:
Desplazar un bit a la derecha es igual a dividir entre dos, desplazar dos bits es
dividir entre cuatro, etc… Desplazar un bit a la izquierda es igual a multiplicar por dos,
etc… Este hecho se puede aprovechar para hacer algunas operaciones más rápidas (en
un factor de 10 incluso).
SHR divide número sin signo. SAR divide números con signo. DIV redondea
por defecto. IDIV redondea por exceso. SHL y SAL funcionan igual para números con
y sin signo.
Ejemplo:
XOR AH, AH
SHL AX, 1
MOV BL, 2
MUL BL
; 0 en AH
; multiplico por 2
; 4 ciclos en 8086
;
; de 74 a 81 ciclos en 8086
; 15 ciclos en 80286
; de 11 a 16 ciclos en 80386.
Pág. 34
Ejemplos con MACROS:
Inicio de la
Macro
Multiplicar x 10
Nombre de la
Macro
Fin de la Macro
Parámetro
MACRO factor
MOV AX, factor
SHL AH, 1
MOV BX, AX
SHL AX, 1
SHL AX, 1
ADD AX, BX
ENDM
; factor es el nº por el que multiplico
; factor es un nº sin signo
; multiplico por 2
; salvo el resultado en BX
; 2º desplazamiento (x4)
; multiplico por 8
; factor x 8 + factor x 2 = factor x 10
Factor es un número sin signo. La macro no es un procedimiento, es una
fracción de código que se copia cuando se la llama en el programa.
Ejemplos con MACROS:
Dividir entre 512
MACRO dividendo
MOV AX, dividendo
SHR AX, 1
XCHG AL, AH
CBW
; dividiendo = parámetro
; salvo dividendo
; AX / 2
; = a desplazar 8
; (AX/2)/256 = AX / 512
; pongo a 0 el byte AH
; seguro que es 0 ya que
; divido entre 512
ENDM
Dividendo es un número sin signo. Desplazamientos multipalabra: cuando la
variable a desplazar es demasiado grande para un registro hay que usar varias
ubicaciones pasando a través del flag de acarreo CF.
Ejemplo:
. DATA
mem32 DD 500.000
.CODE
MOV CX, 4
nuevo:
; vamos a dividir 32 bits sin signo entre 16 bits
; 4 iteraciones en el bucle
; dividir entre 2 en cada pasada
SHR WORD PTR mem32[2],1
RCR WORD PTR mem32[0],1
LOOP nuevo
; desplazo a través de CF
; el CF entra por la izquierda
Pág. 35
INSTRUCCIONES DE CONTROL DE FLUJO 80x86
ÍNDICE:
1.- Bifurcaciones.
2.- Bucles
3.- Procedimientos
4.- Interrupciones.
1.- Bifurcaciones:
Son el método más directo para cambiar el flujo de control de una posición a
otro del programa. Internamente actúan sobre el IP (y CS veces). Los saltos pueden ser:
SHORT ->  128 bytes.
NEAR ->  32 Kbytes.
FAR -> otro segmento (>  32 Kbytes)
La actualización del puntero IP se realiza:
SHORT -> IP = IP + desplazamiento (byte).
NEAR -> IP = IP + desplazamiento (2 byte).
FAR -> IP = desplazamiento, CS = segmento.
Dos modos:
Directo: etiqueta de memoria resuelve en tiempo de compilación o
ensamblado.
Indirecto: se da un puntero que tiene la dirección de salto (se resuelve en
tiempo de ejecución).
JMP: (registro/memoria)
Transfiere el control incondicionalmente al operando. La bifurcación puede ser:

Dentro del mismo segmento: En este caso, IP se sustituye por el valor del
desplazamiento de la instrucción referenciada. El desplazamiento, a su vez,
puede estar:
 Entre -128 y 127: Se genera una instrucción de 2 bytes.
 Inferior a -128 ó superior a 127: Se genera una instrucción de 3 bytes.
 A distinto segmento: CS e IP se sustituyen por los valores correspondientes a
la instrucción referenciada.
 Directa: especificando una etiqueta.
 Indirecta: Especificando una dirección.
Los saltos pueden ser:
Short: IP = IP + desplazamiento (byte)
Near: IP = IP + desplazamiento (2 bytes)
Far: IP = desplazamiento, CS = segmento
Pág. 36
Dos modos:
Directo: etiqueta de memoria resuelta en tiempo de compilación o ensamblado.
(Se reserva memoria).
Indirecto: Se da un puntero que tiene la dirección de salto (se resuelve en tiempo
de ejecución). No podemos dar saltos cortos con el modo indirecto.
Tamaño del formato (modo directo)
SHORT -> 2 bytes
NEAR -> 3 bytes
FAR -> 5 bytes
11101011 (EBh) desplazamiento_8
11101001 (E9h) desplazamiento_16
11101010 (EAh) desplazamiento_16 segmento
Tamaño del formato (modo indirecto)
SHORT ->no existe
NEAR -> 2 bytes
FAR -> 2 bytes
11111111 (FFh) mod 100 r/m
11111111 (FFh) mod 100 r/m
Cuando el salto es FAR el operando no puede ser un registro ya que no caben los
32 bits de base : desplazamiento. El modo indirecto se emplea para convertir saltos
incondicionales en condicionales.
Ejemplo:
JMP despl. 8
15 ciclos
psw
O
D
I
T
S
Z
A
P
C
Data Memory
AX
BX
CX
DX
SP
BP
SI
DI
PC
Program (Relative to the
Memory CS Register
ppppm
EB
mm
mm
nn
nn
CS
DS
SS
ES
Sign extend
KK to KKKK
ppppm + 1
ppppm + 2
ppppm + 3
0KKKK
0mmmm
+
2
0rrrr
+
Ejemplo:
KK
0mmmm
nnnn0
ppppm
Pág. 37
JMP despl. 16
15 ciclos
JMP dirección
15 ciclos
JMP BX
11 ciclos
JMP [BX]
16 + cálculo EA ciclos
JMP far ptr [DI]
24 + calculo EA ciclos.
EA = dirección efectiva.
Ejemplo:
Captura tecla
Validación
Es 0
SI
Rutina 0
NO
Es 1
SI
Rutina 1
NO
Es 2
SI
NO
NO
Programa en C:
Switch (tecla)
{
case 0
/* rutina 0 */
Break;
Rutina 2
Pág. 38
case 1
/* rutina 1 */
Break;
Case 2
/* rutina 2 */
Break;
En ensamblador:
.CODE
…..
JMP switch
LABEL WORD
DW (caso 0)
DW (caso 1)
DW (caso 2)
MOV AH, O8h
INT 21h
CBW
MOV BX, AX
Casos
switch
; saltar datos
guarda en las
etiqueta las
; puntero casos[0] posiciones de
; puntero casos[1] mem. en las que
; puntero casos[2] se encuentran
; captura tecla
los apartados de
código con el
; AL -> AX
mismo nombre
; salvo tecla
; VALIDACIÓN
;comprueba que sea 0, 1 ó 2
SHL BX, 1
JMP casos [BX]
; multiplico por 2
; salto indirecto al caso
Caso 0
…..
…..
JMP seguir
…...
…..
;break
Caso 1
JMP seguir
…...
…..
;break
Caso 2
JMP seguir
…..
…..
;break
Seguir
; fin switch.
Referencias a etiquetas adelantadas:
Ejemplo:
Etiqueta
JMP etiqueta
…..
…..
…..
Pág. 39
El ensamblador procesa los ficheros fuente secuencialmente (en varias pasadas).
Cuando encuentra “etiqueta” no sabe a que distancia se encuentra (no puede determinar
que espacio reservar para el desplazamiento). Reserva por defecto para una palabra
(salto near) y espera a la segunda pasada para colocar el valor. El código resultante
puede ser incorrecto (si far) o ineficiente (si short). Solución -> marcar la longitud del
salto como short(si acierta el programador se emite un mensaje de error o de aviso). Si
al ejecutar funciona, el salto era short; si da error, habrá que cambiar el código y poner
el salto como far.
Saltos condicionales:
JCC desplazamiento.
Salta o no en función de la condición. Primero evalúa la condición y segundo
actualiza o no IP.
CC = true -> salta
CC = false -> no salta
El desplazamiento se da como una etiqueta que se resuelve en tiempo de
compilación. Los saltos condicionales siempre son SHORT (  128 bytes); si queremos
saltar mas lejos hemos de usar JMP.
Ejemplo:
Construcción de un salto condicional mayor de  128 bytes.
Cerca:
Lejos:
CMP AX, 7
JE cerca
…..
…..
…..
…...
JMP lejos
…..
…..
…..
; código si AX = 7
; salto -> 128 bytes
; Código si AX = 7
Las condiciones se expresan sobre el registro de estado excepto en el caso de
JCXZ que se hace sobre el registro contador CX (buscando un cero). Los mnemónicos
son muy variados pero la funcionalidad se repite: Mnemónicos basados en flags y
mnemónicos basados en comparaciones previas.
Mnemónicos basados en flags:
INSTRUCCIONES:
FUNCIONES:
JO salta con overflow
JNO salta sin overflow
Salta si OF = 1
Salta si OF = 0
Pág. 40
JC salta si carry
JNC
JZ salta si cero
JNZ
JS
JNS
JP
JNP
JPE
JPO
JCXZ
Salta si CF = 1 (= JB)
Salta si CF = 0 (= JAE)
Salta si ZF = 1 (= JE)
Salta si ZF = 0 (= JNE)
Salta si SF = 1
Salta si SF =0
Salta si PF = 1 (= JPE)
Salta si PF = 0 (= JPO)
Salta si PF = 1 (paridad par)
Salta si PF = 0 (paridad impar)
Salta si CX = 0
Ejemplos:
ADD AX, BX
JO desbordamiento
…..
…..
…..
Desbordamiento
SUB AX, DX
JNZ seguir
CALL caso_cero
…..
…..
Seguir:
…..
Mnemónicos basados en comparaciones:
Se usan después de una comparación. CMP = SUB sin salvar el resultado. TEST
= AND sin salvar el resultado.
CMP (registro/memoria) (registro/memoria/inmediato)
Compara dos operandos. Resta fuente de destino, pero no almacena el resultado.
Los operadores quedan inalterados, pero las banderas se actualizan, pudiéndose
consultar a continuación por una instrucción de bifurcación condicional.
TEST (registro/memoria) (registro/memoria/inmediato)
Comparación lógica. Como AND, pero no almacena el resultado en destino.
Mnemónicos basados en comparaciones:
LETRA:
SIGNIFICADO:
G
L
A
B
E
N
Mayor que (número sin signo)
Menor que (número sin signo)
Por encima (número con signo)
Por debajo (número con signo)
Igual
No
Pág. 41
IF (valor 1) operador_relacional (valor 2) THEN
GOTO etiqueta si true
CMP valor 1, valor 2
Jrelación etiqueta (que corresponde al sí verdadero)
Igual
=
CMP
signo
JE
Distinto
≠
JNE
Condición
Salta si
ZF = 1
CMP sin
signo
JE
JNE
Salta si:
ZF = 1
Mayor que >
JG o JNLE
Menor o igual ≤
JLE o JNG
ZF = 0
ZF = 0 and SF =
OF
ZF = 1 SF ≠ OF
JA o JNBE
JBE o JNA
ZF = 0
CF = 0 and ZF =
0
CF = 1 o ZF = 1
Menor que <
JL o JNGE
SF ≠ OF
JB o JNAE
CF = 1
Mayor o igual ≥
JGE o JNL
SF = OF
JAE o JNB
CF = 0
Ejemplos: Las comparaciones hacen referencial con “if … else”
Si CX es menor que -20 entonces DX = 30 sino DX = 20.
Menor:
Seguir:
CMP CX, -20
JL menor
MOV DX, 20
JMP seguir
MOV DX, 30
…..
; if
; then
; else
Si CX es mayor o igual que -20 entonces DX = 20 sino DX = 30.
Nomenor
Seguir
CMP CX, -20
JNL nomenor
MOV DX, 30
JMP seguir
MOV DX, 20
…..
; if
; else
; then
DX = 20 a no ser que CX sea menor que -20 en cuyo caso DX = 30.
Mayor que
MOV DX, 20
CMP CX, -20
JGE mayor que
MOV DX, 30
….
; then
; if
; else
Pág. 42
Este código es el más eficiente, evita el JMP.
Ejemplos:
Bits
.DATA
DB ?
.CODE
…..
…..
; si bit 2 ó bit 4 están a 1 entonces ejecutar el procedimiento A.
TEST bits, 10100b
JZ seguir
CALL procA
Seguir:
; si bit 2 y bit 4 están a 0 entonces ejecutar el procedimiento B
TEST bits, 10100b
JNZ continuar
CALL procB
Continuar:
2.- Bucles:
Instrucciones para crear bucles:
Bucles por contador:
LOOP etiqueta, es equivalente al for.
Bucles por condición:
LOOPE / LOOPZ etiqueta.
LOOPNE / LOOPNZ etiqueta.
Es equivalente al while.
Otros (por ejemplo condición al principio en lugar de al final)
JCXZ etiqueta.
Funcionalidad:
Bucles por contador:
LOOP etiqueta
Contador = contador – 1
IF contador ≠ 0 THEN GOTO etiqueta
LOOPE / LOOPZ etiqueta
Contador = contador -1
IF contador ≠ 0 AND ZF = 1 THEN GOTO etiqueta
LOOPNE / LOOPNZ etiqueta
Contador = contador -1
IF contador ≠ 0 AND ZF = 0 THEN GOTO etiqueta
Pág. 43
Operandos:
Actualiza el contador CX automáticamente (decrementa en 1).
LOOP etiqueta → CX, salto short.
LOOPE / LOOPZ etiqueta → CX, ZF, salto short
LOOPNE / LOOPNZ etiqueta → CX, ZF, salto short.
No actualiza el contador CX automáticamente:
JCXZ etiqueta → CX salto short.
Ejemplo:
Siguiente
MOV CX, 200
…..
…..
…..
LOOP siguiente
Siguiente
MOV CX, 200
…..
…..
…..
DEC CX
redundante
CMP, 0 *
JNE siguiente.
No actualiza
el estado
El primero es más compacto pero el segundo es necesario para comprobar varias
condiciones. Hoy se usa mas el segundo ya que evita el uso dedicado de operando (mas
paralelismo potencial).
* Redundante en código externo, internamente DEC CX no afecta a los flags.
Ejemplo:
MOV CX, 200
…..
…..
…..
; Op. Aritmética*
DEC CX **
JNZ salir ;depende de la op.
CMP CX, 0
JNE siguiente
Salir:
…..
* Operación aritmética o lógica o comparación (en general cualquiera que altere el flag
de cero)
Siguiente
MOV CX, 200
…..
…..
…..
LOOPE siguiente
** Internamente no altera el estado.
Siguiente
Pág. 44
Precauciones:
Si CX es variable hay que comprobar primero que no es vero ya que es en ese
caso se decrementará a -1 y hará 65535 iteraciones.
Repetir:
Seguir
JCXZ seguir
…..
…..
LOOP repetir
…..
; while AX ≠ 128 do tarea
MOV CX, 0FFFFh
…..
CMP AX, 128
LOOPNE repetir.
Repetir
; CX cargado previamente
; comprobar si es 0
; tarea a realizar
; salto del bucle.
; si se le asigna el máximo valor
; al contador, éste no interfiere.
Tiempos:
LOOP:
Se hace el salto -> 17 ciclos.
No se hace el salto -> 5 ciclos.
LOOPE:
Se hace el salto -> 18 ciclos.
No se hace el salto -> 6 ciclos.
LOOPNE:
Se toma el salto -> 19 ciclos.
No se toma el salto -> 5 ciclos.
3.- Procedimientos:
Fracción de código que realiza una tarea especifica. Se escribe una vez y se
llama siempre que haga falta. Forma parte de la imagen del ejecutable. Facilita la
modularidad del código. Algunos compiladores detectan cuantas veces se llama y si son
pocas sustituyen por el código normal para evitar saltos y pasos de parámetros.
No es lo mismo que un objeto. Éste se instancia en memoria cada vez que se
utilice (carga) y se saca de ella cuando se descarga.
Los procedimientos permanecen en el área de código (forman parte de la imagen
del ejecutable).
Instrucciones que se relacionan con los procedimientos:
CALL -> salva el contexto (CS : IP o IP en curso) en la pila y salta al
procedimiento.
RET -> recupera el contexto (información relativa al entorno de procesamiento
principal) y vuelve al programa principal.
Pág. 45
Las directivas que utiliza son:
PROC
ENDP
Marcan el principio y el fin de los procedimientos.
CALL: (registro/memoria)
Salva en la pila la dirección de la siguiente instrucción. Salta a la dirección
especificada.
De tipo far
[SP = SP - 2]
[CS -> PILA]
[CS = nuevo CS]
Método para conseguir el CS : IP
en curso de la pila.
SP = SP – 2
De tipo near IP -> pila
IP = nuevo IP
Se salta a la instrucción siguiente
(así no altera nada)
La dirección de salto se puede dar de forma dos formas:
Directa -> etiqueta
Indirecta -> puntero en registro en memoria.
Los saltos pueden ser:
Near -> solo se da y se salva en la pila IP
Far -> la dirección de salto se muestra como CS : IP.
Ejemplo:
CALL far ptr TAREA -> salto far
Problemática de las
etiquetas adelantadas.
Pág. 46
Definición de procedimientos:
1.etiqueta
etiqueta
PROC [NEAR / FAR]
…..
…..
; código
…..
RET [constante]
;RET= return
ENDP.
Forma más
antigua de
declarar un
procedimiento
2.etiqueta:
…..
…..
RETN [constante]
; código
Retorno de tipo near.
Aquí hay dos
puntos tras la
etiqueta, como si
fuera un salto.
Forma
Moderna.
3.etiqueta:
LABEL FAR
…..
…..
RETF [constante]
; código
Retorno de tipo far.
Ejemplos:
CALL
…..
…..
Tarea PROC
…..
…..
RET *
Tarea ENDP
tarea
CALL NEAR PTR tarea
.....
…..
tarea:
…..
…..
RETN**
* Asume el tipo de salto del CALL
** Supone un CALL near, si fuera far provocaría fallos.
RET [constante]
Devuelve el contexto original de la secuencia de código en curso sacando de la
pila CS : IP o IP dependiendo de si es far o near.
Pág. 47
Como operando relacional tenemos una constante cuyo significado es el número
de bytes a sumar a SP después de retornar.
RET (far)
POP IP, SP + 2
POP CS, SP + 2
RET (near)
POP IP, SP + 2
RETN 3
POP IP, SP + 2
SP + 3
Se suman 3 bytes adicionales
a la cima de la pila.
(Nota: POP IP y POP CS son operaciones que no estás permitidas).
Paso de argumentos: Hay dos posibles maneras: en registros o variables
(memoria) -> variables globales. Inconvenientes: pocos registros, no reentrantes o
anidables. Ventajas: los registros son rápidos, generan pocas dependencias. La otra
posibilidad es a través de la pila (Mejor método). Inconvenientes: sobrecarga de
dependencias y cálculo de direcciones, acceso lento a memoria. Ventajas: anidable,
versátil y gran extensión.
Convenciones de Microsoft: los argumentos se pasan a la pila antes de la
llamada al procedimiento. Después de la llamada, el procedimiento recupera los
argumentos y los procesa. Finalmente se ajusta el puntero de pila para soslayar los
argumentos, se puede hacer en la secuencia principal o con RET n.
Ejemplo:
MOV AX, 10
PUSH AX
PUSH arg2
PUSH CX
CALL sumar
ADD SP, 6
Sumar PROC NEAR
PUSH BP
MOV BP, SP
MOV AX, [BP + 4]
ADD AX, [BP + 6]
ADD AX, [BP + 8]
POP BP
RET
Sumar ENDP
; doy valor al tercer parámetro
; paso el tercer parámetro a la pila
; paso el segundo (de memoria)
; paso el primero
; llamo al procedimiento
; ajusto la pila “destruyendo” los argumentos
; salvo el marco de la pila antigua
; actualizo el nuevo marco
( para este procedimiento).
; recupera el primer argumento
; sumo el primero con el segundo
; sumo con el tercero
; recupero el marco antiguo
; devuelvo el control al programa principal
; el resultado se devuelve en AX.
Uso de variables locales: las variables locales tienen un tiempo de vida limitado
a la ejecución del procedimiento, se reserva memoria para ellas en la pila al comenzar el
procedimiento, se opera con ellas mientras se está ejecutando el procedimiento, se
Pág. 48
destruyen al finalizar el procedimiento. Se crean en la pila y se acceden por su posición
en la pila (respecto al macro).
Ejemplo:
Arg
PUSH AX
CALL Tarea
EQU < [BP + 4] >
Loc EQU < [BP - 2] >
Tarea PROC NEAR
PUSH BP
MOV BP, SP
SUB SP, 2
MOV Loc, 3
ADD AX, Loc
SUB Arg, AX
MOV SP, BP
POP BP
RET 2
Tarea ENDP
; argumento
; llamada al procedimiento
; doy nombre a la posición de la pila ocupada por
; el argumento
; idem con la variable local
; salvo el macro de la pila antigua
; cargo el macro del proceso en curso
; reservo espacio para la variable local
; inicializo la variable local
;
;
; destruyo la variable local
; recupero el macro antiguo
; devuelvo el control al programa principal
; destruyendo el argumento
Posiciones
Bajas
Argumento
SP
IP
Argumento
SP
Old BP
IP
Argumento
SP
BP+4
Old BP
IP
Argumento
SP
BP
Posiciones
Altas
Posiciones
Bajas
BP-2
Loc = 3
Old BP
IP
Argumento
SP
BP
Loc = 3
Old BP
IP
Arg – (Arg + 3)
SP
Loc = 3
Old BP
IP
Argumento
SP
Loc = 3
IP
Argumento
Posiciones
Altas
4.- Interrupciones:
Las interrupciones son procedimientos solicitados por números en lugar de por
dirección (o ‘nombre’). Una interrupción puede dispararse por:
Software: servicios BIOS, S.O., etc.
Dispositivos hardware: E/S, eventos hardware.
SP
Pág. 49
Las interrupciones pueden tener cualquier número entre 0 y 255. Los números
más bajos están reservados para el procesador, la BIOS y el sistema operativo. La
llamada de interrupciones por programa se realiza con la instrucción INT n, siento n
cualquier número entre 0 y 255. En la parte mas baja del mapa de memoria (00000 h) se
guarda una tabla que contiene los “vectores de interrupción”.
Vectores de interrupción: punteros de 32 bits (base y desplazamiento) al
comienzo de las rutinas de servicio a cada interrupción (procedimientos). Los vectores
se guardan secuencialmente indexados por el número de interrupción. Si cada vector
ocupa 4 bytes, el vector de la interrupción n estará en la posición n x 4. En total la tabla
de vectores de interrupción ocupa: 256 * 4 bytes = 1Kbyte. Es responsabilidad del
programador asegurarse de que existe una rutina de servicio para cada interrupción que
utilice.
Para cambiar una rutina de servicio basta con dejar residente en memoria la
nueva y apuntar el vector correspondiente al comienzo de ésta.
Cada programa puede “atender” las instrucciones de forma diferente si así lo
requiere variando el vector (el método es muy flexible).
Ejemplos:
INT 0
división por 0
INT 1
paso a paso
Algunas interrupciones especiales:
INTERRUPCIÓN
0
DESCRIPCIÓN
División por cero. Solicita por el procesador cuando el cociente
De una división es demasiado grande o cuando se intenta
Dividir por cero.
3
Breakpoint. Punto de ruptura. Interrumpe la ejecución de un
programa. Se usa para la depuración.
4
Overflow. Solicitada por INTO si OF=1. La rutina de servicio
por defecto es IRET.
10 h
Servicios BIOS de vídeo.
21h
Llamada a servicios del sistema operativo DOS. Antes de
hacer la llamada con INT 21h se carga en AH el número del
servicio deseado. Los parámetros se pasan en registros.
Pág. 50
INT número:
Cuando se llama a una interrupción se siguen estos pasos:
1)
2)
3)
4)
5)
Búsqueda del vector en la tabla
PUSH flags, CS e IP
TF = 0; IF = 0
Salta la rutina de atención
Ejecuta el código hasta encontrar IRET-> devolvemos un proceso
más pesado ya que con RET solo devolvemos CS e IP y aquí también
tenemos que devolver flags.
6) POP IP, CS y flags.
INT activa el procedimiento de interrupción especificado por el operando. La
dirección del vector de interrupción se calcula multiplicando por 4 el operando, que es
un valor entre 0 y 255. El vector de interrupción se compone de dos palabras :
desplazamiento y segmento. Se bifurca a la dirección especificada por el vector de
interrupción salvando previamente las banderas y la dirección de retorno (CS, IP).
El código generado es de 2 bytes, excepto cuando la interrupción es de tipo 3
(parar la ejecución en un punto del programa : breakpoint) en la que el código generado
es de un solo byte.
Para retornar de una interrupción se utiliza la instrucción IRET.
Lógica de la interrupción :
SP = SP – 2
Flags -> Pila
IF = 0
TF = 0
SP = SP – 2
CS-> Pila
CS = (tipo_interrupción * 4) + 2
SP = SP – 2
IP -> Pila
IP = (tipo_interrupción * 4)
INTO
Interrupción si existe desbordamiento.
Es equivalente a:
JO rutina
…
rutina: INT 4
JO rutina
…
rutina:
; código si OF = 1
IRET
Devuelve el control al programa principal y restaura el estado. Devuelve el
control a la dirección de retorno salvada en la pila por una operación de interrupción
Pág. 51
previa y restaura los registros de banderas (con en la instrucción POPF). Se utiliza para
finalizar un procedimiento de interrupción. Es equivalente a la instrucción RET en un
procedimiento.
CLI
Desactiva la bandera de activación de interrupciones IF y desactiva las
interrupciones enmascaradas. Las interrupciones no enmascaradas NO se pueden
desactivar.
IF = 0 -> no se atienden interrupciones hardware.
STI
Activa las interrupciones enmascaradas
IF = 1 -> se atienden las interrupciones hardware.
Definición de rutinas de interrupción:
Etiqueta
Etiqueta
PROC FAR
.
.
.
IRET
ENDP
;código
Si la rutina no hace nada sólo tiene una instrucción que es IRET.
Cambio de rutinas:
Cambiar el vector -> hay llamadas al sistema para hacerlo (INT 21 h, 25h – set y
INT 21h, 35h – get). Es conveniente salvar la dirección antigua y volver a colocarla
cuando se finalice. Se pueden cambiar todas pero es usual hacerlo con 00h, 04h, 24h
(error crítico), 23h (control-c). Los drivers de los dispositivos pueden ser rutinas de
atención a interrupciones (dejar residente INT 27h). Cuando arranca el ordenador hay
vectores que no apuntan a nada, es responsabilidad del programador que apunten a una
rutina útil.
Ejemplos:
; llamada al DOS para mostrar cadenas
MOV AH, 09h
MOV DX, OFFSET cadena
INT 21 h
; servicio a ejecutar
; argumento
; llamada al DOS
; llamada al BIOS para leer carácter del teclado
XOR AH, AH
INT 16 h
; servicio a ejecutar
; llamada al BIOS
; devuelve ASCII en AL
Pág. 52
Ejemplo:
Cambio de vector de interrupción
mensaje
vector
inicio:
Overflow
Overflow
.DATA
DB “desbordamiento”,13,10,”$”
DD ?
.CODE
MOV AX, @DATA
MOV DS, AX
MOV AX, 3504h
;obtener vector de interrupción de la rutina en AL
INT 21h
;ES:BX dirección de la rutina de interrupción.
MOV WORD PTR VECTOR [2], ES ;salvar dirección de la rutina de
MOV WORD PTR VECTOR [0], BX ;interrupción 4
PUSH DS
MOV AX, CS
MOV DS, AX
;DS:DX apunta al proc Overflow en el código.
MOV DX, OFFSET Overflow
MOV AX, 2504 h
;Carga el vector interrupción apuntado por DS:DX
INT 21 h
;de la interrupción indicada en AL = 4
POP DS
ADD AX, BX
INTO
;llamar a rutina de overflow
LDS DX, vector
;DS:DX = offset vector
MOV AX, 2504 h
INT 21h
;restaurar la rutina de la interrupción de overflow
MOV AX, 4C00h
INT 21h
PROC FAR
STI
; activa interrupciones enmascaradas
MOV AH, 09h
MOV DX, OFFSET mensaje
INT 21 h
;imprimir por pantalla la cadena apuntada por DS:DX
XOR AX, AX
; XOR DX, DX
IRET
ENDP
END INICIO
La nueva rutina de servicio o atención a la interrupción 4 emite un mensaje y
pone a cero el registro desbordado. Antes de terminar el programa se restaura el vector
original.
Pág. 53
OTRAS INSTRUCCIONES 80x86:
Índice:
1.- Procesamiento de cadenas.
1.1 Configuración
1.2 Movimiento de cadenas
1.3 Búsqueda
1.4 Comparaciones
1.5 Paso de caracteres a cadenas
1.6 Lectura de caracteres desde cadenas
1.7 E/S con cadenas
2.- Instrucciones de control.
1.- Procesamiento de cadenas:
El repertorio ofrece un conjunto de instrucciones para la manipulación de
cadenas de caracteres. Están pensadas para disminuir el salto existente entre los
lenguajes de alto nivel y el ensamblador. También permiten disminuir el tamaño de los
ejecutables. Pueden unirse sin restricciones para estructuras de datos que no sean
precisamente cadenas (bytes o palabras).
Las instrucciones de manejo de cadenas son:
Instrucciones
MOVS
SCAS
CMPS
LODS
STOS
INS
OUTS
Descripción
Copia un carácter de una cadena a otro lugar.
Busca un carácter en una cadena
Compara un carácter de una cadena con los de otra
Carga un carácter de una cadena en Acc
Transfiere un carácter de Acc a una cadena
Transfiere un carácter desde un puerto E/S a una cadena
Transfiere un carácter desde una cadena a un puerto de E/S
Tienen una sintaxis similar. Pueden utilizar prefijos de repetición para trabajar
como bucles. Así el programa será mas compacto y ocupará menos. El número de
caracteres que se quieren repetir vendrá dado en CX. Los prefijos de repetición son:
Pág. 54
Prefijo
Descripción
REP
Repite un número de iteraciones especificadas en CX
REPE y REPZ
Repite mientras igual. CX indica el máximo número de
Iteraciones.
REPENE y REPNZ Repite mientras no igual. CX indica el máximo número de
iteraciones.
Sintaxis I:
[prefijo de repetición] instrucción [ES:[destino]], [[segmento:]fuente]
Las intrucciones de manejo de cadenas pueden especificar el operando fuente y/o el
destino aunque no es obligatorio. El tamaño del (los) operando (s) indica el tamaño de
los objetos a procesar. Si no se especifican operandos estos son los valores señalados
por los punteros: DS : SI para el fuente y ES : DI para el destino. El puntero destino
siempre tiene como base ES. Nomalmente se usa prefijo de repetición para completar el
procesamiento de la cadena de manera iterativa (igual que un bucle).
Sintaxis II:
[prefijo de repetición] instrucción B
[prefijo de repetición] instrucción W
Las letras B o W identifican el tamaño de los operandos. Con esta sintaxis no se
permite especificar operandos.
Todo junto: instrucciones, prefijos y operandos:
Instrucción
MOVS
SCAS
CMPS
LODS
STOS
INS
OUTS
Prefijo
REP
REPE/REPNE
REPE/REPNE
---REP
REP
REP
1.1 Configuración:
Fuente/Destino
ambos
destino
ambos
fuente
destino
destino
fuente
Puntero
DS : SI, ES : DI
ES : DI
DS : SI, ES : DI
DS : SI
ES : DI
ES : DI
DS : SI
Pág. 55
1. Dar el valor deseado al flag de dirección. DF = 0 las cadenas se procesan
hacía arriba (de drecciones bajas a altas); instrucciones CLD. DF = 1 las
cadenas se procesan hacia abajo (de direcciones altas a bajas); instrucciones
STD. Si no se especifica se pondrá a cero por defecto.
2. cargar el registro contador CX con el número de caracteres a procesar (si se
quiere un bucle implícito).
3. Cargar la dirección de comienzo de la cadena, fuente en DS : SI y la de la
cadena destino en ES : DI. La cadena fuente puede no estar en el segmento
DS. La cadena destino siempre debe estar en ES.
4. Seleccionar el prefijo de repetición adecuado (si bucle)
5. Seleccionar la instrucción deseada y colocarla junto al prefijo (si bucle).
1.2 Movimiento de cadenas:
MOVS copia datos de un área de memoria a otra.
[REP] MOVS [ES:] destino, [registro de segmento: ] fuente
[REP] MOVSB
[REP] MOVSW
Transfiere un byte o una palabra de la cena fuente (direccionada por SI), en el
segmento de datos, a la cadena destino (direccionada por DI), en el segmento extra.
Actualiza los registros SI y DI para que apunten al siguiente elemento de la cadena.
Si los operadores son de tipo byte, se transfiere un byte y los registros SI y DI
cambian una unidad; si son de tipo word cambian dos unidades. Si la bandera de
dirección DF = 0, SI y DI se incrementan; si DF=1 se decrementan.
Ejemplo:
fuente
destino
.MODEL Small
.DATA
DB 10 DUP (‘0123456789’)
DB 100 DUP (?)
.CODE
MOV AX, @DATA
MOV DS, AX
MOV ES, AX
.
.
CLD
MOV CX, 100
MOV SI, OFFSET fuente
MOV DI, OFFSET destino
REP MOVSB
-------------------.
.
; solapa los 2
; segmentos de datos.
Pág. 56
Repetir:
MOV CX, 100
MOV SI, OFFSET fuente
MOV DI, OFFSET destino
MOV AL, [SI]
MOV [DI], AL
INC SI
INC DI
LOOP repetir
Este último ocupa mas en memoria y e sequivalente al anterior.
A veces es mas rápido mover palabras en lugar de bytes: ¡OJO! Con números
impares de bytes (no completa palabra). La solución es:
MOV CX, contador
SHR CX, 1
REP MOVSW
RCL CX, 1
REP MOVSB
; divide entre 2 -> CF = 1 si es impar.
; copiamos palabras (más eficiente)
; si CF = (impar) -> CX = 1
; copia el último byte si lo hay.
1.3 Búsqueda:
SCAS explora una cadena buscando un carácter específico. El carácter o valor se
almacena en AL o AX. Cada vez que se encuentra un emparejamiento el flag de cero se
pone a 1 (IF [ES : DI] = Acc THEN ZF = 1). Solo tiene sentido utilizr los prefijos que
evalúan ZF.
[REPE / REPNE] SCAS [ES:] destino
[REPE / REPNE] SCASB
[REPE / REPNE] SCASW
Ejemplo:
cadena
longitud
puntero
noesta:
.DATA
DB “Más vale pájaro en mano que ciento volando ”
EQU $-cadena
; longitud cadena
DD cadena
.CODE
.
.
CLD
; bandera de dirección a 0 (hacia arriba)
MOV CX, longitud
; longitud de la cadena al contador
LES DI, puntero
; inicializo ES : DI
MOV AL, ‘v’
; valor a buscar (ASCII de la ‘v’)
REPNE SCASB
; repetir mientras no sea igual
JNZ muestra
; tratar el caso de que no esté (si ZF = 0)
.
; no se ha encontrado salto a la etiqueta
.
; noesta
Pág. 57
.
.
; para cuando encuentra ‘v’
1.4. Comparaciones:
CMPS compara dos cadenas y apunta a la dirección donde swe produce un
emparejamiento o un desemparejamiento. Compara carácter a carácter y si los valores
son iguales ZF = 1. Solo tiene sentido utilizar los prefijos que evaluan ZF. Los punteros
SI y DI apuntan al siguiente carácter. Si finaliza la cuenta sin emparejamientos con
REPNE CMPS entonces ZF = 0. Si finaliza la cuenta sin emparejamientos con REPE
CMPS entonces ZF = 1.
[REPE / REPNE] CMPS [registro de segmento : fuente], [ES:] destino
[REPE / REPNE] CMPSB
[REPE / REPNE] CMPSW
Es la única insrucción que escribe los operandos al revés (aunque no tiene mayor
importancia).
Ejemplo:
cadena1
cadena2
longitud
todos=:
.MODEL large
.DATA
DB “Más vale pájaro en mano que ciento volando”
. FARDATA
; declaración de un segmento extra.
DB “ Más vale pájaro en mano que ciento saltando ”
EQU $ - cadena2
.CODE
MOV AX, @DATA
; vargo los segmentos.
MOV DS, AX
MOV AX, @FARDATA
MOV ES : AX
.
.
CLD
; bandera de dirección a cero
MOV CX, longitud
; longitud de la cadena al contador
MOV SI, OFFSET cadena1 ; inicializo SI
MOV DI, OFFSET cadena2 ; inicializo DI
REPE CMPSB
; repetir mientras igual
JZ todos=
; si toda la cadena es igual
DEC SI
; caso primer carácter no igual
DEC DI
.
.
También JCXZ; si CX =
.
0 he llegado al final sin
.
desemparejamiento.
Pág. 58
1.5. Paso de caracteres a cadenas:
STOS almacena un valor en cada posición de una cadena destino. El valor a
almacenar debe estar en ACC. El prefijo a utilizar es REP.
[REP] STOS [ES:] destino
[REP] STOSB
[REP] STOSW
Ejemplo:
.MODEL small
. DATA
DB 100 dup ?
.CODE
.
.
CLD
MOV AX, ‘aa’
MOV CX, 50
MOV DI, OFFSET destino
REP STOSW
destino
1.6 Lectura de caracteres desde cadenas:
LODS carga un valor de una cadena en el Acc. No se usa con prefijos de
repetición.
LODS [registro de segmento: ] fuente
LODSB
LODSW
Ejemplo:
cadena
Otro:
.DATA
DB 0,1,2,3,4,5,6,7,8,9
.CODE
.
.
CLD
MOV CX, 10
MOV SI, OFFSET cadena
MOV AH, 2
LODSB
ADD AL, 48
MOV DL, AL
INT 21 h
LOOP otro
; servicio de la INT 21h
; sumar 30h es pasar a ASCII
; parámetro del servicio
Pág. 59
1.7. Entrada/Salida con cadenas:
INS lee un puerto y escribe una cadena. OUTS lee una cadena y la escribe en un
puerto. El puerto se da en DX (nunca inmediato) ya que sea implícita o explícitamente.
INS [ES:] destino, DX
INSB
INSW
OUTS DX, [registro de segmento: ] fuente
OUTSB
OUTSW
Ejemplo:
contador
buffer
.DATA
EQU 100
DB contador DUP (?)
.CODE
.
.
CLD
MOV CX, contador
MOV DI, OFFSET buffer
MOV DX, puerto
REP INSB
; transfiere la cadena desde el puerto.
2.- Instrucciones de control:
De manejo de las banderas:
CLC, CLD, CLI, CMC: borrar bandera de acarreo, dirección,
interrupción o complementar acarreo.
STC, STD, STI: poner a 1 la bandera de acarreo, dirección o
interrupción.
De sincronización con coprocesadores (fp, E/S). ESC: indica al coprocesador
que comience una tarea, el procesador principal no se detiene. WAIT: detiene al
procesador principal hasta que, por ejemplo, se finalice el trabajo del coprocesador.
HLT: detiene el proceso hasta que se resetea el sistema o se recibe una NMI
(interrupción no enmascarable) o una IRQ (interrupción hardware) (si permitidas).
NOP: no hace nada; se pierden tres ciclos y pasa a la siguiente instrucción (en realidad
es XCHG AX, AX). Se introduce un retardo.
Pág. 60
PROGRAMACIÓN EN ENSAMBLADOR 80x86
Índice:
1.- Desarrollo de un programa.
2.- Organización de memoria.
3.- Entrada / Salida.
1.- Desarrollo de un programa:
2.- Organización de memoria:
ROM
Memoria de video
RAM
Aplicación
Drivers de dispositivos
Controladores del sistema
BIOS y DOS
Tabla
CODE
DATA
HEAP
1.
2.
3.
4.
Pág. 61
STACK
CODE: Código del programa.
DATA: Datos globales y estáticos.
HEAP: Variables ubicadas dinámicamente
STACK: Datos locales y argumentos de funciones.
Modelos de memoria:






Tiny: código y datos caben en un mismo segmento.
Small: código y datos usan un segmento cada uno. Esos segmentos no tienen por
qué ser disjuntos, normalmente están solapados.
Médium: datos usa un segmento, pero código usa más de uno.
Compact: código usa un segmento, pero datos usa más de uno (los arrays tiene
que ser menores de 64 K, es decir, solo pueden ocupar un segmento).
Large: código y datos usan más de un segmento (los arrays tienen que ser
menores de 64K).
Huge código y datos usan más de un segmento (se usa para arrays mayores de
64K).
Definición de segmentos simplifica con DOSSEG: sólo es posible a partir de la
versión 5.0 del programa ensamblador. Es necesario declarar un modelo de memoria a
utilizar para especificar el tamaño de datos y código a usar (directiva .MODEL
{modelo}). El uso de la directiva DOSSEG permite ordenar os segmentos de forma
consistente.
Segmentos básicos:
Definición usando la directiva DOSSEG
. STACK [tamaño]
. DATA ?
. CODE [nombre]
. FARDATA [nombre]
.DATA
. FARDATA ? [nombre]
. CONST
Inicialización de los registros de segmento: los programas en código
ensamblador deben inicializar los registros de segmento antes de que las
instrucciones…
Inicialización de CS e IP. Etiqueta “dirección de inicio” que identifica la
dirección de comienzo cuando el programa se carga y marcando el final con END
[dirección de inicio]. CS se inicializa a dicho valor en la imagen del ejecutable. El
registro IP normalmente se inicializa a 0. No hay ninguna transferencia explícita en
código (MOV CS, …<- ¡PROHIBIDO!). Cuando el S.O. carga el programa en
memoria, sustituye el valor de CS por el del puntero asignado. Sólo una directiva END
debe tener dirección de inicio.
Inicialización de DS. Se debe inicializar con la dirección del segmento que se
usará para datos. Se debe realizar en dos pasos, porque un registro de segmento no se
puede cargar directamente con un inmediato.
MOV AX, @DATA
MOV DS, AX
Pág. 62
@DATA es una constante predefinida que contiene un puntero al segmento de
datos en la imagen del ejecutable. También podemos usar la directiva DGROUP
MOV AX, DGROUP
MOV DS, AX
DGROUP Hace referencia a un grupo de segmentos que comparten la misma
dirección base, es decir, están solapados. El mismo segmento de datos es accesible
desde diversos segmentos con nombres distintos. Los mismos datos tienen “vistas”
distintas.
Inicialización de SS y SP. El registro segmento de SS se inicia automáticamente
con el valor del último segmento de tipo STACK. El registro SP se inicia
automáticamente al tamaño del segmento de pila. Así SS:SP apuntan inicialmente al
final de la pila. La pila se puede reinicializar a mano:
MOV AX, @DATA
MOV SS, AX
MOV SP, OFFSET STACK ; cima de la pila
También podríamos usar @STACK en vez de @DATA.
Inicialización de ES. No se inicializa automáticamente. Hay que indicar,
primero al ensamblador y luego al procesador que las variables de tipo FAR se van a
acceder utilizando por defecto el registro ES:
ASSUME ES:@FARDATA
; informo al ensamblador
MOV AX, @FARDATA
; prepara al procesador
MOV ES, AX
Si no se indica nada el procesador utiliza el registro DX.
Estructura de un programa en ensamblador:
TITLE Ejemplo
DOSSEG
.MODEL small
.STACK 100h
mensaje
longitud
Inicio:
; uso de convenciones de segmentos de Microsoft
; Definición de modelo de memoria SMALL
; Reserva de pila de 256 bytes
.DATA
DB “Hola a todos”, 13, 10
EQU $-mensaje
.CODE
MOV AX, @DATA
MOV DS, AX
; mensaje a escribir
; localización del segmento de datos
; en el registro DS
MOV CX, longitud
; carga la longitud del mensaje
MOV DX, OFFSET mensaje ; carga la dirección del mensaje
MOV AH, 40h
; carga el nº de servicio de la función DOS
INT 21h
; Llama al MS-DOS para hacer E/S
Pág. 63
MOV AX, 4C00
INT 21h
END Inicio
; Servicio Exit (devolver el control a MSDOS)
Pág. 64
3: ENTRADA / SALIDA
Las operaciones de entrada/salida con dispositivos periféricos a controladores
del sistema se podrían realizar en cada programa. Esta solución no genera aplicaciones
portables. Sobrecarga el desarrollo de aplicaciones. Es más eficiente confiar la
entrada/salida a servicios BIOS o del SO.
Un ejecutable, por tanto, esta orientado:
- A un procesador (código nativo)
- A un modelo de memoria dado por el SO
- A un procedimiento de E/S dado por el SO
En definitiva: Una aplicación tiene una imagen ejecutable orientada a una
plataforma por el par: PROCESADOR – SO. La herramienta de desarrollo
(ensamblador o compilador) también afecta al resultado final.
Las llamadas a la BIOS o al SO se pueden implementar como interrupciones:
- Interrupciones de la BIOS
- Interrupciones del DOS
- APIs
Este sistema proporciona una “máquina virtual” que trabaja de una manera
normalizada. Funciona del mismo modo independientemente de la capa física.
Ejemplos de llamadas BIOS:
- INT 10h: Servicios de video
- INT 13h: Servicios de discos
- INT 14h: Servicios de comunicaciones
- INT 16h: Servicios de teclado
- INT 17h: Servicios del puerto de impresión
Ejemplos de llamadas DOS:
- INT 21h: Servicios del S.O.
- INT 23h: Control+C
- INT 25h: Lectura de disco
- INT 33h: Servicios de Ratón
- INT 67h: Servicios de memoria expandida EMS
Son API’s
Ejemplos llamadas API’s:
Mediante interrupciones:
- INT 33h: Servicios de ratón
- INT 67h. Servicios de memoria expandida EMS
- INT 2Fh: Servicios DPMI (DOS Protected Mode Interface)
- INT 31h
Mediante funciones (llamadas a procedimientos externos)
Servicios de memoria extendida XMS
MOV AX, 0410h
- Driver XMS_CONTROL  INT 2Fh
MOV word ptr CS:[XMS_CONTROL], BX
MOV word ptr CS:[XMS_CONTROL+2], ES
-
Call CS[XMS_CONTROL] con la función en AH
Descargar