Sunteți pe pagina 1din 33

2.1.1.- Movimientos.

MOV (transferencia).

Sintaxis: MOV destino, origen

La instrucción de transferencia de datos por excelencia es MOV.


Transfiere datos de longitud byte o palabra del operando origen al
operando destino. Pueden ser operando origen y operando destino
cualquier registro o posición de memoria direccionada de las
formas ya vistas, con la única condición de que origen y destino
tengan la misma dimensión.Con la instrucción MOV diremos que se
pueden realizar todo tipo de movimientos teniendo en cuenta las
siguientes restricciones:

1. No se puede realizar una transferencia de datos entre dos


posiciones de memoria directamente.

Por ejemplo, para hacer la operación

DATO1 ← DATO2

La instrucción MOV DATO2, DATO1 sería incorrecta. Lo que sí sería


correcto sería utilizar el registro DX, u otro, como puente y hacer:
MOV DX, DATO1

MOV DATO2, DX

2. Tampoco se puede hacer una transferencia directa entre dos


registros de segmento. Por eso, como en el caso anterior, si fuera
preciso se utilizaría un registro como puente.
3. Asimismo, tampoco se puede cargar en los registros de segmento
un dato utilizando direccionamiento inmediato, es decir, una
constante, por lo que también habrá que recurrir a un registro
puente cuando sea preciso.

XCHG (intercambiar).
Sintaxis: XCHG destino, origen

Una instrucción útil pero no imprescindible es XCHG. Intercambia el


contenido de los operandos origen y destino. No pueden utilizarse
registros de segmentos como operandos

Por ejemplo, si queremos intercambiar los contenidos de los


registros AX y BX, podemos hacer:

MOV AUX, AX
MOV AX, BX
MOV BX, AUX

En donde AUX es una variable auxiliar que hace de puente, o


simplemente utilizar:

XCHG AX, BX
XLAT (traducción).

Sintaxis: XLAT tabla

La instrucción XLAT tabla carga en el registro AL el contenido de la


posición [BX][AL], en donde el registro BX ha de apuntar al
comienzo de una tabla. Dicho de otra manera, AL hace de índice de
la tabla y de almacén destino del contenido de la tabla.
Por ejemplo, el siguiente programa:

DATOS SEGMENT
TABLA DB 2, 3, 5, 8, 16, 23
DATOS ENDS

CODIGO SEGMENT
MOVE BX, OFFSET TABLA ;Inicializa BX con la dirección donde
comienza la tabla
MOVE AL, 5
XLAT TABLA
CODIGO ENDS
Hace que al final el contenido de AL sea 16 ya que es el quinto
elemento de la tabla y AL antes de XLAT TABLA contenía el valor 5.

LEA (carga dirección efectiva).


Sintaxis: LEA destino, origen

Transfiere el desplazamiento del operando fuente al operando


destino. Otras instrucciones pueden a continuación utilizar el
registro como desplazamiento para acceder a los datos que
constituyen el objetivo. El operando destino no puede ser un
registro de segmento. En general, esta instrucción es equivalente a
MOV destino, OFFSET fuente y de hecho los buenos ensambladores
(TASM) la codifican como MOV para economizar un byte de
memoria. Sin embargo, LEA es en algunos casos más potente que
MOV al permitir indicar registros de índice y desplazamiento para
calcular el offset:

LEA DX, DATOS [SI]

En el ejemplo de arriba, el valor depositado en DX es el OFFSET de


la etiqueta DATOS más el registro SI. Esa sola instrucción es
equivalente a estas dos:

MOV DX, OFFSET DATOS


ADD DX, SI

INSTRUCCIONES DE ENTRADA SALIDA (E/S).

IN (entrada).

Sintaxis: IN acumulador, puerto

Transfiere datos desde el puerto indicado hasta el registro AL o AX,


dependiendo de la longitud byte o palabra respectivamente. El
puerto puede especificarse mediante una constante (0 a 255) o a
través del valor contenido en DX (0 a 65535).
Ejemplo:
IN AX, 0FH
IN AL, DX

OUT (salida).
Sintaxis: OUT puerto, acumulador

Transfiere un byte o palabra del registro AL o AX a un puerto de


salida. El puerto puede especificarse con un valor fijo entre 0 y 255
ó a través del valor contenido en el registro DX (de 0 a 65535).
Ejemplo:
OUT 12H, AX
OUT DX, AL

2.1.2.- Pila.

POP (Extraer de la pila).


Sintaxis: POP destino

Transfiere el elemento palabra que se encuentra en lo alto de la pila


(apuntado por SP) al operando destino que a de ser tipo palabra, e
incrementa en dos el registro SP. La instrucción POP CS, poco útil,
no funciona correctamente en los 286 y superiores.
Ejemplos:
POP AX
POP PEPE

PUSH (Introduce en la pila).


Sintaxis: PUSH origen

Decrementa el puntero de pila (SP) en 2 y luego transfiere la palabra


especificada en el operando origen a la cima de la pila. El registro
CS aquí sí se puede especificar como origen, al contrario de lo que
afirman algunas publicaciones.
Ejemplo:
PUSH CS

2.1.3.- Matemáticos.

ADD (suma).
Sintaxis: ADD destino, origen
Suma los operandos origen y destino almacenando el resultado en
el operando destino. Se activa el acarreo si se desborda el registro
destino durante la suma.

Ejemplos:
ADD AX, BX
ADD CL, DH

INC (Incrementar).
Sintaxis: INC destino

Incrementa el operando destino. El operando destino puede ser byte


o palabra. Obsérvese que esta instrucción no modifica el bit de
acarreo (CF) y no es posible detectar un desbordamiento por este
procedimiento (utilícese ZF).
Ejemplos:
INC AL
INC ES: [DI]
INC SS: [BP+4]
INC WORD PTR CS: [BX+DI+7]

CMP (Comparación).
Sintaxis: CMP destino, origen

Resta origen de destino sin retornar ningún resultado. Los


operandos quedan inalterados, paro los indicadores pueden ser
consultados mediante instrucciones de bifurcación condicional. Los
operandos pueden ser de tipo byte o palabra pero ambos de la
misma dimensión.

Ejemplo:

CMP BX, MEM_PAL


CMP CH, CL

DEC (Decrementar).
Sintaxis: DEC destino

Resta una unidad del operando destino. El operando puede ser byte
o palabra. Obsérvese que esta instrucción no modifica el bit de
acarreo (CF) y no es posible detectar un desbordamiento por este
procedimiento (utilícese ZF).
Ejemplo:
DEC AX

SUB (Resta).
Sintaxis: SUB destino, origen

Resta el operando destino al operando origen, colocando el


resultado en el operando destino. Los operandos pueden tener o no
signo, siendo necesario que sean del mismo tipo, byte o palabra.
Ejemplos:
SUB AL, BL
SUB DX, DX

IMUL (multiplicación entera con signo).


Sintaxis: IMUL origen (origen no puede ser operando inmediato en
8086, sí en 286)

Multiplica un operando origen con signo de longitud byte o palabra


por AL o AX respectivamente. Si origen es un byte el resultado se
guarda en AH (byte más significativo) y en AL (menos significativo),
si origen es una palabra el resultado es devuelto en DX (parte alta) y
AX (parte baja).

Ejemplo:

IMUL BX
IMUL CH

MUL (multiplicación sin signo).


Sintaxis: MUL origen (origen no puede ser operando inmediato)

Multiplica el contenido sin signo del acumulador por el operando


origen. Si el operando destino es un byte el acumulador es AL
guardando el resultado en AH y AL, si el contenido de AH es distinto
de 0 activa los indicadores CF y OF.

Ejemplo

MUL BYTE PTR DS: [DI]


MUL DX
MUL CL

DIV (División sin signo).


Sintaxis: DIV origen (origen no puede ser operando inmediato).

Divide, sin considerar el signo, un número contenido en el


acumulador y su extensión (AH, AL si el operando es de tipo byte o
DX, AX si el operando es palabra) entre el operando fuente. El
cociente se guarda en AL o AX y el resto en AH o DX según el
operando sea byte o palabra respectivamente. DX o AH deben ser
cero antes de la operación.

Ejemplo:
DIV BL
DIV MEM_PAL

2.1.4.- Ajustes.

CBW (Conversión de byte en palabra).


Sintaxis: CBW

Copia el bit 7 del registro AL en todos los bits del registro AH, es
decir, expande el signo de AL a AX como paso previo a una
operación de 16 bits.

CWD (conversión de palabra a doble palabra).


Sintaxis: CWD

Expande el signo del registro AX sobre el registro DX, copiando el


bit más significativo de
AH en todo DX.

2.1.5.- Comparación.
CMP (Comparación).
Sintaxis: CMP destino, origen

Resta origen de destino sin retornar ningún resultado. Los


operandos quedan inalterados, paro los indicadores pueden ser
consultados mediante instrucciones de bifurcación condicional. Los
operandos pueden ser de tipo byte o palabra pero ambos de la
misma dimensión.

Ejemplo:

CMP BX, MEM_PAL


CMP CH, CL

CMPS/CMPSB/CMPSW (Compara cadenas).


Sintaxis: CMPS cadena_destino, cadena_origen
CMPSB (bytes)
CMPSW (palabras)

Compara dos cadenas restando al origen el destino. Ninguno de los


operandos se alteran, pero los indicadores resultan afectados. La
cadena origen se direcciona con registro SI sobre el segmento de
datos DS y la cadena destino se direcciona con el registro DI sobre
el segmento extra ES. Los registros DI y SI se autoincrementan o
autodecrementan según el valor del indicador DF (véanse CLD y
STD) en una o dos unidades, dependiendo de si se trabaja con bytes
o con palabras. Cadena origen y cadena destino son dos operandos
redundantes que sólo indican el tipo del dato (byte o palabra) a
comparar, es más cómodo colocar CMPSB o CMPSW para indicar
bytes/palabras. Si se indica un registro de segmento, éste sustituirá
en la cadena origen al DS ordinario.

Ejemplo:

LEA SI, ORIGEN


LEA DI, DESTINO
CMPSB

A veces un programa debe cambiar el flujo del programa en forma


incondicional o bajo una condición (Para tomar una decisión), por lo
tanto debe haber instrucciones que permitan cambiar el flujo de un
programa sin ningún requisito, o en caso de que una condición se
cumpla.

Existen instrucciones para éste propósito. Son las instrucciones de


saltos incondicionales y condicionales, que saltan a un determinado
punto si se cumpla la condición.

2.2.1.- Salto Incondicional.

Empecemos por el salto sin condiciones, con el que podremos


cambiar el control a cualquier punto del programa. Sería como el
“Goto” del Basic, simplemente transferir el control a otro punto del
programa. La orden es JMP (de Jump, salto) Si record is a ‚estas
alturas los registros CS: IP, se podrá ver que‚ es lo que hace
realmente la instrucción, y no es mas que incrementar o decremento
IP para llegar a la zona del programa a la que queremos transferir el
control (IP es el Offset que indica la zona de memoria que contiene
la siguiente instrucción a ejecutar, y CS el
segmento).

El formato mas sencillo para el salto sería JMP 03424h, lo que


saltaría a esa zona. Pero es digamos que “algo pesado” calcular en
que‚ dirección va a estar esa instrucción, con lo que utilizaremos
etiquetas. La única instrucción que existe para éste fin es JMP
(Abreviatura de JUMP, que significa en inglés SALTAR). La sintaxis
es la siguiente:

JMP XXXXXXXX: Es la ubicación de la instrucción en donde se


continuará el programa (A partir de ésta se ejecutan las siguientes).
Ejemplo:
XXXX: 0100 MOV AX, 1000
XXXX: 0103 JMP 0107
XXXX: 0105 XOR AX, AX
XXXX: 0107 INT 20

En éste caso al ejecutarse la instrucción de salto incondicional


(JMP), se continúa la ejecución a partir de la instrucción (INT 20h),
no ejecutándose la instrucción XOR (Ésta instrucción realiza la
operación XOR de el operando 2 sobre el operando 1) que
provocaría el borrado de registro AX (Que provocaría que AX tome
el valor 0), si se ejecuta.

2.2.2.- Salto Condicional.

Esta una lista de saltos condicionales divididos sin signo – y con


signo Los valores sin signo solo pueden ser positivos, mientras
trabajamos con valores sin signo, el BIT mas alto es el que dice si
es positivo o no. Por lo tanto un valor hexadecimal como FFFF
equivaldría a 65535 si el valor esta sin signo, y –1 si no lo esta. Hay
también una sesión con saltos condicionales que no chequea si el
valor tiene signo o no.

Saltos condicionales sin signo

Salta si
JA
superior

JAE
Salta si superior o igual
JB Salta si menor
JBE Salta si menor o igual
Salta si no es superior, como
JNA
JBE
Salta si no superior o igual
JNAE
(como JB)
Salta si no es menor (Como
JNB
JBE también)
Salta si no es menor o igual
JNBE
(como JA)

Saltos condicionales con signo


Salta si es
JG
grande
Salta si es grande o
JGE
igual
JL Salta si es menos
Salta si es menos o
JLE
igual
Salta si no es grande,
JNG
como JLE
Salta si no es grande o
JNGE
igual como JGLE
Salta si no es inferior,
JNL
como JGE
Salta si no es inferior o
JNLE
igual, como JG

Saltos condicionales, no importa si tienen signo o no.

JZ Salta si es cero

JE Salta si es igual, como JZ


JNZ Salta si no es 0
Salta si no es igual, como
JNE
JNZ

Dependiendo de la instrucción previa (CMP en nuestro caso) el flag


0 es colocado. Por lo tanto, lo que realmente hace JE (o JZ) verificar
el flag 0. Si este esta puesto (zeroflag=1) saltara, de lo contrario no
lo hará.

LOOP (bucle).

Decrementa el registro contador CX; si CX es cero, ejecuta la


siguiente instrucción, en caso contrario transfiere el control a la
dirección resultante de sumar a IP + desplazamiento. El
desplazamiento debe estar comprendido entre -128 y +127.

Ejemplo:
MOV CX,10
BUCLE:
.......
.......
LOOP BUCLE

Con las mismas características que la instrucción anterior:

LOOPE/LOOPZ Bucle si igual, si cero. Z=1 y CX<>0

LOOPNE/LOOPNZ Bucle si no igual, si no cero. Z=0 y CX<>0

LOOP (COM) Ilustración de LOOP


.MODEL SMALL
.CODE
ORG 100H
MAIN PROC NEAR
MOV AX,01 ;Iniciación de AX,
MOV BX,01 ;BX y
MOV CX,01 ;CX a 01
MOV CX,10 ;Iniciar
A20: ;Número de iteraciones
ADD AX, 01 ;Sumar 01 a AX
ADD BX, AX ;Sumar AX a BX
SHL DX, 1 ;Multiplicar por dos a DX
LOOP A20 ;Iterar si es diferente de cero
MOV AX, 4C00H ;Salida a DOS
MAIN ENDP
END MAIN

AND (y lógico).

Realiza una operación de Y lógico entre el operando origen y


destino quedando el resultado en el destino. Son válidos operandos
byte o palabra, pero ambos del mismo tipo.

Ejemplos:
AND AX, BX
AND BL, BYTE PTR ES:[SI+10H]
NOT (No lógico).

Realiza el complemento a uno del operando destino, invirtiendo


cada uno de sus bits. Los
indicadores no resultan afectados.

Ejemplo:
NOT AX

OR (O lógico).

Realiza una operación O lógico a nivel de bits entre los dos


operandos, almacenándose después el resultado en el operando
destino.

Ejemplo:
OR AX, BX

XOR (O exclusivo).

Operación OR exclusivo a nivel de bits entre los operandos origen y


destino almacenándose el resultado en este último.

Ejemplo:
XOR DI, AX

2.5.- Desplazamiento.

2.5.1- Lineal.

SHL (Desplazamiento lógico a la izquierda).

Mediante esta instrucción podemos desplazar a la izquierda los bits


de un registro o posición de memoria. Esto que puede parecer poco
práctico, es muy útil en determinadas situaciones. Por ejemplo, es
la manera más rápida y cómoda de multiplicar por 2.

SHR (Desplazamiento lógico a la derecha).

Desplaza a la derecha los bits del operando destino el número de


los bits especificados en el segundo operando. Los bits de la
izquierda se llena con cero. Si el número de bits a desplazar es 1 se
puede especificar directamente en el caso en que no ocurra se pone
el valor en CL:

2.5..2- Circular.

RCL (Rotación a la izquierda con acarreo).

Rotar a la izquierda los bits del operando destino junto con el


indicador de acarreo CF el número de bits especificado en el
segundo operando. Si el número de bits a desplazar es 1, se puede
especificar directamente, en caso contrario el valor debe cargarse
en CL y especificar CL como segundo operando. No es conveniente
que CL sea mayor de 7, en bytes; ó 15, en palabras.

RCR (Rotación a la derecha con acarreo).

Rotar a la derecha los bits del operando destino junto con el


indicador de acarreo CF el número de bits especificado en el
segundo operando. Si el número de bits es 1 se puede especificar
directamente; en caso contrario su valor debe cargarse en CL y
especificar CL como segundo operando:

ROL (Rotación a la izquierda).

Rota a la izquierda los bits del operando destino el número de bits


especificado en el segundo operando, que puede ser 1 ó CL
previamente cargado con el valor del número de veces.

ROR (Rotación a la derecha).

Rota a la derecha los bits del operando destino el número de bits


especificado en el segundo operando. Si el número de bits es 1 se
puede poner directamente, en caso contrario debe ponerse a través
de CL.

2.6.- Procesos de Control.

NOP (Operación nula).

Realiza una operación nula, es decir, el microprocesador decodifica


la instrucción y pasa a la siguiente. Realmente se trata de la
instrucción XCHG AX,AX.

ESC (Salida a un coprocesador).


Se utiliza en combinación con procesadores externos, tales como
los coprocesadores de coma flotante o de E/S, y abre al dispositivo
externo el acceso a las direcciones y operandos requeridos. Al
mnemónico ESC le siguen los códigos de operación apropiados
para el coprocesador así como la instrucción y la dirección del
operando necesario.

HLT (Parada hasta interrupción o reset).

El procesador se detiene hasta que se restaura el sistema o se


recibe una interrupción. Como en los PC se producen normalmente
18,2 interrupciones de tipo 8 por segundo (del temporizador)
algunos programadores utilizan HLT para hacer pausas y bucles de
retardo. Sin embargo, el método no es preciso y puede fallar con
ciertos controladores de memoria.

LOCK (Bloquea los buses).

Es una instrucción que se utiliza en aplicaciones de recursos


compartidos para asegurar que no accede simultáneamente a la
memoria más de un procesador. Cuando una instrucción va
precedida por LOCK, el procesador bloquea inmediatamente el bus,
introduciendo una señal por la patilla LOCK.

WAIT (Espera).

Provoca la espera del procesador hasta que se detecta una señal en


la patilla TEST. Ocurre, por ejemplo, cuando el coprocesador ha
terminado una operación e indica su finalización. Suele preceder a
ESC para sincronizar las acciones del procesador y coprocesador.

2.6.1 Banderas.

Las banderas proveen una manera de obtener información acerca


de del estado actual de la máquina y el resultado de procesamiento
de una instrucción. La plataforma IA-32 utiliza un registro de 32 bits
llamado EFLAGS que contiene las banderas. Las banderas más
comunmente usadas son las siguientes:
Bandera Bit Nombre
CF 0 Bandera de acarreo (carry flag)
PF 2 Bandera de paridad (parity flag)
AF 4 Bandera de acarreo auxiliar (adjust flag)
ZF 6 Bandera de cero (zero flag)
SF 7 Bandera de signo (sign flag)
DF 10 Bandera de dirección (direction flag)
OF 11 Bandera de desbordamiento (overflow flag)

La bandera de acarreo se activa cuando se produce acarreo en una


suma o multiplicación, o un "préstamo" en una resta entre números
sin signo. La bandera de paridad se usa para indicar si el resultado,
en un registro, de una operación matemática es válido.

La bandera de paridad se usa para indicar si el resultado, en un


registro, de una operación matemática es válido.

La bandera de acarreo auxiliar se utiliza en operaciones


matemáticas con números decimales codificados en binario (BCD).
Se activa si hay acarreo presente.

La bandera de cero se activa si el resultado de una operación


aritmético lógica es cero.

La bandera de signo muestra el bit más significativo del resultado


de una operación, el cual denota el signo del número.

La bandera de dirección controla la selección de autoincremento


(D=0) o autodecremento (D=1) de los registros %edi o %esi durante
las operaciones con cadenas de caracteres. La bandera de dirección
sólo se utiliza con las instrucciones para el manejo de cadenas de
caracteres.

La bandera de desbordamiento se utiliza en la aritmética de enteros


con signo cuando un número sobrepasa la capacidad de
representación del registro.
2.6.2.- Cadenas.

CMPS/CMPSB/CMPSW (Compara cadenas).

Compara dos cadenas restando al origen el destino. Ninguno de los


operandos se alteran, pero los indicadores resultan afectados. La
cadena origen se direcciona con registro SI sobre el segmento de
datos DS y la cadena destino se direcciona con el registro DI sobre
el segmento extra ES. Los registros DI y SI se autoincrementan o
autodecrementan según el valor del indicador DF en una o dos
unidades, dependiendo de si se trabaja con bytes o con palabras.
Cadena origen y cadena destino son dos operandos redundantes
que sólo indican el tipo del dato (byte o palabra) a comparar, es más
cómodo colocar CMPSB o CMPSW para indicar bytes/palabras. Si se
indica un registro de segmento, éste sustituirá en la cadena origen
al DS ordinario.

Ejemplo:

LEA SI, ORIGEN


LEA DI, DESTINO
CMPSB

MOVS/MOVSB/MOVSW (Mover cadena).

Transfiere un byte o una palabra de la cadena origen direccionada


por DS:SI a la cadena destino direccionada por ES:DI,
incrementando o decrementando a continuación los registros SI y DI
según el valor de DF en una o dos unidades, dependiendo de si se
trabaja con bytes o con palabras. Cadena origen y cadena destino
son dos operandos redundantes que sólo indican el tipo del dato
(byte o palabra) a comparar, es más cómodo colocar MOVSB o
MOVSW para indicar bytes/palabras. Si se indica un registro de
segmento, éste sustituirá en la cadena origen al DS ordinario.

Ejemplo:
LEA SI, ORIGEN
LEA DI, DESTINO
MOVSW

STOS/STOSB/STOSW (Almacena cadena).

Transfiere el operando origen almacenado en AX o AL, al destino


direccionado por el registro DI sobre el segmento extra. Tras la
operación, DI se incrementa o decrementa según el indicador DF
(véanse CLD y STD) para apuntar al siguiente elemento de la
cadena. Cadena_destino es un operando redundante que sólo indica
el tipo del dato (byte o palabra) a cargar, es más cómodo colocar
STOSB o STOSW para indicar bytes/palabras.

Ejemplo:
LEA DI, DESTINO
MOV AX, 1991
STOSW

REP/REPE/REPZ/REPNE/REPNZ (Repetir).

REP repetir operación de cadena


REPE/REPZ repetir operación de cadena si igual/si cero
REPNE/REPNZ repetir operación de cadena si no igual (si no 0)

Estas instrucciones se pueden colocar como prefijo de otra


instrucción de manejo de cadenas, con objeto de que la misma se
repita un número determinado de veces incondicionalmente o hasta
que se verifique alguna condición. El número de veces se indica en
CX.

Prefijo Función Instrucciones


-------------------- ------------------------------------------- ------------------
MOVS,
REP Repetir CX veces
STOS
Repetir CX veces mientras CMPS,
REPE/REPZ
ZF=1 SCAS
Repetir CX veces mientras CMPS,
REPNE/REPNZ
ZF=0 SCAS
3.1.- Macros

Introducción.
Para cada instrucción simbólica que usted codifica, el ensamblador
genera una instrucción de lenguaje de maquina. El ensamblador
tiene facilidades que el programador puede utilizar para definir
macros. Primero hay que definir un nombre especifico para la
macro, junto con el conjunto de instrucciones en lenguaje
ensamblador que la macro va a generar. Después, siempre que
necesite codificar el conjunto de instrucciones, solo hay que
codificar el nombre de la macro y el ensamblador genera de forma
automática las instrucciones que han sido definidas en la macro.

Las macros son útiles para los siguientes propósitos:

* Simplificar y reducir la cantidad de codificación repetitiva.


* Reducir errores causados por la codificación repetitiva.
* Linealizar un programa en lenguaje ensamblador para hacerlo
mas legible.

3.1.1 Internas.

Para definir una macro, se utiliza la directiva MACRO. El formato de


esta directiva es :

(nombre_de_macro) MACRO (lista_parámetros)

Una macro consta de tres partes esenciales:


a) CABECERA: Contiene el nombre de la macro, la pseudo-op
MACRO y opcionalmente, variables ficticias que serán pasadas
desde la macro.

b) CUERPO: Contiene el código real que será insertado en cualquier


programa que llame al nombre de la macro.

c) FIN: Debe incluir la sentencia ENDM.

Ejemplo de una macro sencilla:


INICIO MACRO ; Define macro
MOV AX, DATA ; cuerpo de
MOV DS, AX ; la definición
MOV ES, AX ; de la macro
ENDM

Internas.

Una macro interna es aquella que se declara y se llaman dentro del


mismo programa.

3.1.2 Externas o Bibliotecas de Macros.

Una de las facilidades que ofrece el uso de las macros es la


creación de bibliotecas, las cuales son grupos de macros que
pueden ser incluidas en un programa desde un archivo diferente.

La creación de estas bibliotecas es muy sencilla, unicamente


tenemos que escribir un archivo con todas las macros que se
necesitarán y guardarlo como archivo de texto.

Para llamar a estas macros solo es necesario utilizar la instrucción


Include NombreDelArchivo, en la parte de nuestro programa donde
escribiriamos normalmente las macros, esto es, al principio de
nuestro programa (antes de la declaración del modelo de memoria).
Suponiendo que se guardó el archivo de las macros con el nombre
de MACROS.TXT la instrucción Include se utilizaría de la siguiente
forma:

;Inicio del programa


Include MACROS.TXT
.MODEL SMALL
.DATA
;Aqui van los datos
.CODE
Inicio:
;Aqui se inserta el código del programa
.STACK
;Se define la pila
End Inicio
;Termina nuestro programa

3.2.- Procedimientos.

Definición de procedimientos

Un procedimiento es un conjunto de instrucciones que tienen la


finalidad de ejecutar una tarea especifica dentro de un programa.
Los procedimientos son muy similares a las macros.

Un procedimiento se declara una sola vez en el codigo fuente y


cuando el programa se ensambla y ejecuta, el procedimiento se
coloca en memoria para que pueda ser utilizado por el programa.

A continuación se presentan los pasos necesarios para ejecutar un


procedimiento:

1.-Se encuentra la llamada Call


2.-El microprocesador almacena en la Pila el contenido del IP
3.-Se coloca en el IP el valor del desplazamiento correspondiente al
Procedimiento
4.-El microprocesador ejecuta las instrucciones del procedimiento
5.-El procedimiento termina cuando se encuentra la instrucción Ret
6.-Se saca de la pila el valor original del IP y se continua el flujo del
programa.

Un procedimiento se declara de la siguiente forma:

PROC nombre

instrucción

instrucción...

RET

ENDP NOMBRE

3.2.1 Procedimientos internos.

Los procedimientos internos son aquellos que se declaran y se


mismo programa, también son llamados procedimientos locales. Un
ejemplo de procedimiento interno es el siguiente:

;Procedimiento: GotoXY
;Descripción: Coloca el cursor una posición especifica de la pantalla
;Parámetros: Dl=X,Dh=Y
;**********************************************************************
PROC GotoXY
xor bh,bh
mov ah,02h
int 10h
ret
endp GotoXY

3.2.2 Procedimientos externos.


Los procedimientos externos, a diferencia de los internos, se
declaran en módulos o programas separados al programa donde el
procedimiento es llamado, en otras palabras, la llamada al
procedimiento se encuentra en un programa y el procedimiento en
otro.

Para poder utilizar procedimientos externos, es necesario que sean


declarados como públicos en el programa donde se encuentran y
que sean llamados como externos en el programa donde serán
usados. Se debe contar con tres directivas de ensamble: .PUBLIC
para declarar los procedimientos como públicos, .EXTERN para
indicar que el procedimiento que se va a usar está fuera del
programa y .INCLUDE para enlazar el programa que contiene los
procedimientos con el programa que los llama.

PUBLIC PROC1 ; Se define como público


PROC1 PROC FAR ; comienzo del procedimiento (lejano)
(instrucciones) ; Instrucciones del procedimiento
RET ;Instrucción para retornar
PROC1 ENDP ; Final del procedimiento

Para llamar a un procedimiento se utiliza la instrucción CALL:

CALL nombre_procedimiento

Por ejemplo Este programa muestra la forma de utilizar


procedimientos y datos externos en los programas por medio de las
directivas de inclusión include y public.

.MODEL TINY
.INCLUDE proc2.ASM ;Incluir el archivo proc2.asm
;el cual contiene la variable de cadena
;Cad1 y los procedimientos externos
;usados en este programa.
.DATA
Cad2 db 'Esta es una cadena de prueba 2...',13,10,'$'
.CODE
INICIO: ;Punto de entrada al programa
Mov Dl,20 ;X=20
Mov Dh,10 ;Y=10
Call GotoXY ;GotoXY 20,10
Lea DX,Cad2 ;DX->Cad2 en Proc3.asm
Call Imprime_Cad ;Imprime Cad2
Lea DX,Cad1 ;DX->Cad1 en Proc2.asm
Call Imprime_Cad ;Imprime Cad1
Mov AX,04C00h ;Fin del programa
Int 21h ;
END INICIO
END

4.1.-Directivas para compilación híbrida.

Introducción.
La programación hibrida es utilizada en los casos en donde el
código en ensamblador dificulta la estructuración del programa,
proporciona un mecanismo por medio del cual podemos aprovechar
las ventajas del lenguaje ensamblador y los lenguajes de alto nivel,
todo esto con el fin escribir programas más rápidos y eficientes.

Ejemplo de un programa con un bloque de instrucciones en


ensamblador: Este programa muestra como se construye un
programa híbrido utilizando un bloque Asm... End; en Turbo Pascal.
El programa solicita que se introduzcan dos número, después
calcula la suma por medio de la instrucción Add de ensamblador y
finalmente imprime el resultado en la pantalla.

Program hibrido;
Procedure
Limpia_Pantalla;
Assembler;
Asm
Mov AX, 0600h
Mov BH, 18h
Mov CX, 0000h
Mov DX, 184Fh
Int 10h
End;.

En fin podemos mezclar el código ensamblador con el código de


cualquier otro lenguaje que admita este procedimiento. En pascal
antes de escribir el código en ensamblador ay que poner Asm y al
final de nuestro código End.

Por otro lado, Asm nos permite incluir bloques de instrucciones en


lenguaje ensamblador en cualquier parte del programa sin
necesidad de escribir procedimientos completos en ensamblador.

Al trabajar con un lenguaje de alto nivel, en ocasiones nos


encontramos con el problema de que necesitamos que haga
determinada función o trabajo pero desafortunadamente ésta solo
existe en otro lenguaje que no es el que necesitamos utilizar, o
simplemente, no encontramos esa función en ningún lenguaje de
alto nivel.

En este momento el lenguaje ensamblador constituye una


herramienta no solo eficaz, sino simple para producir un parche
para el compilador de nuestro lenguaje preferido.

Tal vez el mayor problema con el que nos enfrentemos sea el de


cómo conectar ambos programas (el de alto y el de bajo niveles) y
cómo pasar variables de un programa al otro.

Para conseguir nuestro objetivo se utilizan pseudo-operadores, es


decir, instrucciones que aparecen en el código fuente del
ensamblador pero que no generan ninguna instrucción de máquina,
pero proporcionan directivas para que el ensamblador pueda operar
con datos, ramificaciones condicionales, generación de listados y
con macros durante el proceso de ensamble.

PUBLIC

El pseudo-operador que nos interesa es del tipo de pseudo-


operadores para datos y se conoce como PUBLIC, el cual permite
que símbolos en el código fuente sean enlazados por otros
programas que se van a enlazar juntos. Para esto, la información es
pasada al linker (enlazador). PUBLIC permite el intercambio de
información intersegmentos.

El formato de este pseudo-operador es PUBLIC número, variable o


rótulo

Ejemplo de uso de PUBLIC:

PUBLIC nombre

Instrucciones

RET

nombre ENDP

4.2.- Funciones en Ensamblador.

Para llamar a las interrupciones es conveniente conocer antes


ciertas estructuras y uniones.
struct WORDREGS { unsigned int ax, bx, cx,
dx, si, di, cflag, flags;
};

struct BYTEREGS { unsigned char al, ah, bl,


bh, cl, ch, dl, dh;
};

union REGS { struct WORDREGS x;


struct BYTEREGS h;
};

struct SREGS { unsigned int es; unsigned


int cs; unsigned int ss; unsigned int ds;
};

struct REGPACK { unsigned r_ax, r_bx,


r_cx, r_dx;
unsigned
r_bp, r_si, r_di, r_ds, r_es, r_flags;
};

A continuación, se listan las funciones que permiten invocar las


interrupciones:
int int86(int interrupción, union REGS *entrada, union REGS
*salida);
int int86x(int interrupción, union REGS *entrada, union REGS
*salida, struct REGS *rsegmento);
void intr(int interrupción, struct REGPACK *registros);

Las dos primeras funciones se basan en la declaración de dos


uniones: una para entrada y otra para salida, que simbolizan los
valores iniciales (antes de llamar a la interrupción) y finales (tras la
llamada) en los registros. Si se desea que la misma unión que indica
los valores iniciales devuelva los finales, se puede indicar por
duplicado:
union REGS regs; regs.h.ah = 0; regs.h.al = 0x13;
/* VGA 320x200 - 256 colores */
int86 (0x10, &regs, &regs); /* cambiar modo de vídeo
*/

LLAMADAS DESDE UN PROGRAMA ESCRITO EN C

Las llamadas desde C varían sensiblemente de las de Pascal. Lo


primero que hay que tener en cuenta es que el orden de los
parámetros es el inverso. Se leen de derecha a izquierda en la
declaración de la función o procedimiento.

Otra característica es que el compilador de C añade al principio del


nombre de la función o procedimiento el carácter de subrayado, por
lo que es necesario hacerlo también en el módulo ensamblador.

La última es que el retorno de la función se debe hacer simplemente


con RET , sin parámetros. El compilador de C se encarga de añadir
el código necesario para eliminar los parámetros de la pila:

Test( i , j , 1); se traduciría en:


mov ax,1
push ax
push WORD PTR DGROUP:_j
push WORD PTR DGROUP:_i
call NEAR PTR_Test
add sp,

En las versiones más modernas del compilador se admiten las


llaves '{' y '}' para agrupar varias sentenciasasm:
asm {
push ax; push cx;
mov cx,dato1
mov ax,0h }
mult: asm {
add ax,dato2
loop mult
mov resultado,ax
pop cx; pop ax;
}

4.3.- Operadores.

Operadores Aritméticos: Pueden emplearse libremente (+), (-), (*) y


(/). En este último caso la división es siempre entera. También se
admiten los operadores MOD (resto de la división) y SHL/SHR
(desplazar a la izquierda/derecha cierto número de bits).

Operadores Lógicos: Pueden ser el AND, OR, XOR y NOT. Realizan


las operaciones lógicas en las expresiones.

Operadores relacionales: Devuelven condiciones de cierto (0FFFFh


o 0FFh) o falso (0) evaluando una expresión. Pueden ser: EQ (igual),
NE (no igual), LT (menor que), GT (mayor que), LE (menor o igual
que), GE (mayor o igual que).

Operador PTR: Redefine el atributo de tipo (BYTE, WORD, DWORD,


QWORD, TBYTE) o el de distancia (NEAR o FAR) de un operando de
memoria.

Por ejemplo, si se tiene una tabla definida de la siguiente manera:


Tabla DW 10 DUP (0) ; 10 palabras a 0

Para colocar en AL el primer byte de la misma, la instrucción MOV


AL, tabla es incorrecta, ya que tabla (una cadena 10 palabras) no
cabe en el registro AL. Lo que desea el programador debe
indicirselo en este caso explícitamente al ensamblador de la
siguiente manera:

MOV AL,BYTE PTR tabla

Los operadores de memoria son operadores unarios que devuelven


el resultado de una operación directa de memoria. Estos operadores
se utilizan principalmente para depurar código en lenguaje
ensamblador.
{BY | WO | DW} address

El operador BY devuelve un entero corto que contiene el primer byte de


la dirección (address). Este operador simula BYTE PTR.

El operador WO devuelve un entero corto que contiene el valor de la


palabra, dos bytes, de la dirección (address). Este operador simula la
operación WORD PTRde Microsoft Macro Assembler. El
operador DW devuelve un entero largo que contiene el valor de los
cuatro primeros bytes de la dirección (address). Este operador
simula DWORD PTR.

El especificador de formato x que se utiliza en algunos de estos ejemplos


hace que el resultado se muestre en hexadecimal.

Ejemplos

 Para mostrar el primer byte en la dirección de la variable sum:

BY sum

 Para mostrar la primera palabra en la dirección de la


variable new_set:

WO new_set

 Para mostrar la palabra doble en la dirección de sum:


DW sum

 Para mostrar el byte al que apunta el registro EBP con un


desplazamiento de 6:

BY ebp+6,x

 Para mostrar la palabra a la que apunta el puntero de pila, la última


palabra insertada en la pila:

WO esp,x

 Para mostrar la palabra doble a la que apunta el registro ESI:

DW esi,x

4.4.- Integrar módulos de ensamblador en


lenguajes de alto nivel.

LA SENTENCIA ASM

La sentencia asm permite incluir código ensamblador dentro del


programa C, utilizando los mnemónicos normales del ensamblador.
Sin embargo, el uso de esta posibilidad está más o menos limitado
según la versión del compilador. En Turbo C 2.0, los programas que
utilizan este método es necesario salir a la línea de comandos para
compilarlos con el tradicional compilador de línea, lo cual resulta
poco atractivo. En Turbo C++ 1.0, se puede configurar
adecuadamente el compilador para que localice el Turbo Assembler
y lo utilice automáticamente para ensamblar, sin necesidad de salir
del entorno integrado. Sin embargo, es a partir del Borland C++
cuando se puede trabajar a gusto: en concreto, la versión Borland
C++ 2.0 permite ensamblar sin rodeos código ensamblador incluido
dentro del listado C. El único inconveniente es la limitación del
hardware disponible: para un PC/XT, el Turbo C 2.0 es el único
compilador aceptablemente rápido. Sin embargo, en un 286 es más
recomendable el Turbo C++, mientras que en un 386 modesto (o
incluso en un 286 potente) resulta más interesante emplear el
Borland C++ 2.0: las versiones 3.X de este compilador son las más
adecuadas para un 486 o superior (bajo DOS).

La sintaxis de asm se puede entender fácilmente con un ejemplo.


El propósito del siguiente programa: Eliminar archivos dando la
direccion de donde se encuentra el archivo que se decea borrar y la
extencion del mismo, si no te mandara un error :

#include <stdio.h>
#include <conio.h>

int main(){
int orror=0;
char * dir;
clrscr();
printf("Direccion del archivo:\n");
scanf("%s",dir);
_asm{
asm mov ah,0041h
asm mov dx,dir
asm int 21h
asm jc oorror
asm jmp continuar
}
oorror:
asm mov orror, ax

continuar:
if(orror){
printf("!Error de Archivo!");
}
else{
printf("!Exito al eliminar Archivo!");
}
getch();
return -1;
}

Otro ejemplo es la elaboración de de un programa, es la


elaboración de un reloj hibrido, como se muestra acontinuación:
# include <stdio.h>
# include <conio.h>
void main (void)
{
char bandera, horas, minutos, segundos, centesimas;
clrscr();
bandera=0;
for (;;)
{
_asm{
mov ah,2ch
int 21h
mov horas,ch
mov minutos,cl
mov segundos,dh
mov centesimas,dl
}

if (segundos!=bandera)
{
printf
("\n%i:%i:%i.%i",horas,minutos,segundos,centesimas);
bandera=segundos;
}
}
getch();
}

S-ar putea să vă placă și