ENCONTRADO EN LOS SUBURBIOS DEL INTERNET.. EL ENLACE ESTA EN EL TITULO!! SALUDOS
EL LENGUAJE ENSAMBLADOR
1.- UN EJEMPLO CLASICO.
En esta parte se describe lo que es el lenguaje ensamblador, no al ensamblador o al proceso de ensamblado. Aquí se tratará todo lo concerniente con el lenguaje ensamblador y el conjunto de directivas del Microsoft Macro Assembler v4.0. Si bien esto puede resultar bastante extenso y complejo, aquí sólo se describirán las instrucciones y directivas básicas.
Para comenzar veamos un pequeño ejemplo que ilustra el formato del programa fuente. Este ejemplo está completamente desarrollado en lenguaje ensamblador que usa servicios o funciones de MS-DOS (system calls) para imprimir el mensaje Hola mundo!! en pantalla.
; HOLA.ASM
; Programa clasico de ejemplo. Despliega una leyenda en pantalla.
STACK SEGMENT STACK ; Segmento de pila
DW 64 DUP (?) ; Define espacio en la pila
STACK ENDS
DATA SEGMENT ; Segmento de datos
SALUDO DB "Hola mundo!!",13,10,"$" ; Cadena
DATA ENDS
CODE SEGMENT ; Segmento de Codigo
ASSUME CS:CODE, DS:DATA, SS:STACK
INICIO: ; Punto de entrada al programa
MOV AX,DATA ; Pone direccion en AX
MOV DS,AX ; Pone la direccion en los registros
MOV DX,OFFSET SALUDO ; Obtiene direccion del mensaje
MOV AH,09H ; Funcion: Visualizar cadena
INT 21H ; Servicio: Funciones alto nivel DOS
MOV AH,4CH ; Funcion: Terminar
INT 21H
CODE ENDS
END INICIO ; Marca fin y define INICIO
La descripción del programa es como sigue:
1.- Las declaraciones SEGMENT y ENDS definen los segmentos a usar.
2.- La variable SALUDO en el segmento DATA, define la cadena a ser desplegada. El signo de dólares al final de la cadena (denominado centinela) es requerido por la función de visualización de la cadena de MS-DOS. La cadena incluye los códigos para carriage-return y line-feed.
3.- La etiqueta START en el segmento de código marca el inicio de las instrucciones del programa.
4.- La declaración DW en el segmento de pila define el espacio para ser usado por el stack del programa.
5.- La declaración ASSUME indica que registros de segmento se asociarán con las etiquetas declaradas en las definiciones de segmentos.
6.- Las primeras dos instrucciones cargan la dirección del segmento de datos en el registro DS. Estas instrucciones no son necesarias para los segmentos de código y stack puesto que la dirección del segmento de código siempre es cargado en el registro CS y la dirección de la declaración del stack segment es automáticamente cargada en el registro SS.
7.- Las últimas dos instrucciones del segmento CODE usa la función 4CH de MS-DOS para regresar el control al sistema operativo. Existen muchas otras formas de hacer esto, pero ésta es la más recomendada.
8.- La directiva END indica el final del código fuente y especifica a START como punto de arranque.
2.- EL FORMATO DEL ENSAMBLADOR.
De acuerdo a las convenciones y notación seguidas en el manual del Microsoft Macro Assembler, y que usaremos nosotros también, tenemos:
Notación Significado
Negritas Comandos, símbolos y parámetros a ser usados como se
muestra.
Itálicas Todo aquello que debe ser reemplazado por el usuario
[ ] Indican un parámetro opcional
,,, Denota un parámetros que puede repetirse varias veces
¦ Separa dos valores mutuamente excluyentes
letra chica Usada para ejemplos. Código y lo que aparece en pantalla.
Cada programa en lenguaje ensamblador es creado a partir de un archivo fuente de código ensamblador. Estos son archivos de texto que contienen todas las declaraciones de datos e instrucciones que componen al programa y que se agrupan en áreas o secciones, cada una con un propósito especial. Las sentencias en ensamblador tienen la siguiente sintaxis:
[nombre] mnemónico [operandos] [;comentarios]
En cuanto a la estructura, todos los archivos fuente tienen la misma forma: cero o más segmentos de programa seguidos por una directiva END. No hay una regla sobre la estructura u orden que deben seguir las diversas secciones o áreas en la creación del código fuente de un programa en ensamblador. Sin embargo la mayoría de los programas tiene un segmento de datos, un segmento de código y un segmento de stack, los cuales pueden ser puestos en cualquier lugar.
Para la definición de datos y declaración de instrucciones y operandos el MASM reconoce el conjunto de caracteres formado por letras mayúsculas, letras minúsculas (excluyendo caracteres acentuados, ñ, Ñ), números, y los símbolos: ? @ _ $ : . [ ] ( ) ‹ › { } + - / * & % ! ´ ~ ¦ \ = # ˆ ; , " ‘
La declaración de números requiere tener presente ciertas consideraciones. En el MASM un entero se refiere a un número entero: combinación de dígitos hexadecimales, octales, decimales o binarios, más una raíz opcional. La raíz se especifica con B, Q u O, D, o H. El ensamblador usará siempre la raíz decimal por defecto, si se omite la especificación de la raíz (la cual se puede cambiar con la directiva .RADIX). Así nosotros podemos especificar un entero de la siguiente manera: dígitos, dígitosB, dígitosQ o dígitosO, dígitosD, dígitosH. Si una D o B aparecen al final de un número, éstas siempre se considerarán un indicador de raíz, e.g. 11B será tratado como 112 (210), mientras que si se trata del número 11B16 debe introducirse como 11Bh.
Para los números reales tenemos al designador R, que sólo puede ser usado con números hexadecimales de 8, 16, ó 20 dígitos de la forma dígitosR. También puede usarse una de las directivas DD, DQ, y DT con el formato [+¦-]dígitos.dígitos[E[+¦-]igitos].
Las cadenas de carácter y constantes alfanuméricas son formadas como ´caracteres´ o "caracteres" . Para referencias simbólicas se utilizan cadenas especiales denominadas nombres. Los nombres son cadenas de caracteres que no se entrecomillan y que deben comenzar con una A..Z ¦ a..z ¦ _ ¦ $ ¦ @ los caracteres restantes pueden ser cualquiera de los permitidos, y solamente los 31 primeros caracteres son reconocidos.
3.- DIRECTIVAS.
El MASM posee un conjunto de instrucciones que no pertenecen al lenguaje ensamblador propiamente sino que son instrucciones que únicamente son reconocidas por el ensamblador y que han sido agregadas para facilitar la tarea de ensamblado, tanto para el programador como para el programa que lo lleva a cabo. Dichas instrucciones son denominadas directivas. En general, las directivas son usadas para especificar la organización de memoria, realizar ensamblado condicional, definir macros, entrada, salida, control de archivos, listados, cross-reference, direcciones e información acerca de la estructura de un programa y las declaraciones de datos. El apéndice D proporciona una lista completa de estas directivas.
* Conjunto de instrucciones.- Dentro de las directivas más importantes, tenemos las que establecen el conjunto de instrucciones a soportar para un microprocesador en especial:
.8086(defecto).- Activa las instrucciones para el 8086 y 8088 e inhibe las del 80186 y 80286.
.8087(defecto).- Activa instrucciones para el 8087 y desactiva las del 80287.
.186.- Activa las instrucciones del 80186.
.286c.- Activa instrucciones del 80286 en modo no protegido.
.286p.- Activa instrucciones del 80286 en modo protegido y no protegido.
.287.- Activa las instrucciones para el 80287.
* Declaración de segmentos.- En lo que respecta a la estructura del programa tenemos las directivas SEGMENT y ENDS que marcan el inicio y final de un segmento del programa. Un segmento de programa es una colección de instrucciones y/o datos cuyas direcciones son todas relativas para el mismo registro de segmento. Su sintaxis es:
nombre SEGMENT [alineación] [combinación] [´clase´]
nombre ENDS
El nombre del segmento es dado por nombre, y debe ser único. Segmentos con el mismo nombre se tratan como un mismo segmento. Las opciones alineación, combinación, y clase proporcionan información al LINK sobre cómo ajustar los segmentos. Para alineación tenemos los siguientes valores: byte (usa cualquier byte de dirección), word (usa cualquier palabra de dirección, 2 bytes/word), para (usa direcciones de párrafos, 16 bytes/párrafo, deafult), y page (usa direcciones de página, 256 bytes/page). combinación define cómo se combinarán los segmentos con el mismo nombre. Puede asumir valores de: public (concatena todos los segmentos en uno solo), stack (igual al anterior, pero con direcciones relativas al registro SS, common (crea segmentos sobrepuestos colocando el inicio de todos en una misma dirección), memory (indica al LINK tratar los segmentos igual que MASM con public, at address (direccionamiento relativo a address). clase indica el tipo de segmento, señalados con cualquier nombre. Cabe señalar que en la definición está permitido el anidar segmentos, pero no se permite de ninguna manera el sobreponerlos.
* Fin de código fuente.- Otra directiva importante es la que indica el final de un módulo. Al alcanzarla el ensamblador ignorará cualquier otra declaración que siga a ésta. Su sintaxis es:
END [expresión]
la opción expresión permite definir la dirección en la cual el programa iniciará.
* Asignación de segmentos.- La directiva ASSUME permite indicar cuales serán los valores por defecto que asumirán los registros de segmento. Existen dos formas de hacer esto:
ASSUME registrosegmento:nombre,,,
ASSUME NOTHING
NOTHING cancela valores previos.
* Etiquetas.- Las etiquetas son declaradas
nombre:
donde nombre constituye una cadena de caracteres.
* Declaración de datos.- Estos se declaran según el tipo, mediante la regla
[nombre] directiva valor,,,
donde directiva puede ser DB (bytes), DW (palabras), DD (palabra doble), DQ (palabra cuádruple), DT (diez bytes). También pueden usarse las directivas LABEL (crea etiquetas de instrucciones o datos), EQU (crea símbolos de igualdad) , y el símbolo = ( asigna absolutos) para declarar símbolos. Estos tienen la siguiente sintaxis:
nombre = expresión
nombre EQU expresión
nombre LABEL tipo
donde tipo puede ser BYTE, WORD, DWORD, QWORD, TBYTE, NEAR, FAR.
* Declaración de estructuras.- Para la declaración de estructuras de datos se emplea la directiva STRUC. Su sintaxis es:
nombre STRUC
campos
nombre ENDS
4.- CONJUNTO DE INSTRUCCIONES.
El juego completo de instrucciones reconocidas por los procesadores Intel 8086 a 80286, junto con los coprocesadores 8087 y 80287, se enlistan en el apéndice E. Como puede verse en dicho apéndice, la mayoría de las instrucciones requieren algunos operandos o expresiones para trabajar, y lo cual es válido también para las directivas. Los operandos representan valores, registros o localidades de memoria a ser accedidas de alguna manera. Las expresiones combinan operandos y operadores aritméticos y lógicos para calcular en valor o la dirección a acceder.
Los operandos permitidos se enlistan a continuación:
Constantes.- Pueden ser números, cadenas o expresiones que representan un valor fijo. Por ejemplo, para cargar un registro con valor constante usaríamos la instrucción MOV indicando el registro y el valor que cargaríamos dicho registro.
mov ax,9
mov al,´c´
mov bx,65535/3
mov cx,count
para el último ejemplo count sólo será válido si este fue declarado con la directiva EQU.
Directos.- Aquí se debe especificar la dirección de memoria a acceder en la forma segmento:offset.
mov ax,ss:0031h
mov al,data:0
mov bx,DGROUP:block
Relocalizables.- Por medio de un símbolo asociado a una dirección de memoria y que puede ser usado también para llamados.
mov ax, value
call main
mov al,OFFSET dgroup:tabla
mov bx, count
para el último ejemplo count sólo será válido si fue declarado con la directiva DW.
Contador de localización.- Usado para indicar la actual localización en el actual segmento durante el ensamblado. Representado con el símbolo $ y también conocido como centinela.
help DB ´OPCIONES´,13,10
F1 DB ´ F1 salva pantalla´,13,10
.
.
.
F10 DB ´ F10 exit´,13,10,´$
DISTANCIA = $-help
Registros.- Cuando se hace referencia a cualquiera de los registros de propósito general, apuntadores, índices, o de segmento.
Basados.- Un operador basado representa una dirección de memoria relativa a uno de los registros de base (BP o BX). Su sintaxis es:
desplazamiento[BP]
desplazamiento[BX]
[desplazamiento][BP]
[BP+desplazamiento]
[BP].desplazamiento
[BP]+desplazamiento
en cada caso la dirección efectiva es la suma del desplazamiento y el contenido del registro.
mov ax,[BP]
mov al,[bx]
mov bx,12[bx]
mov bx,fred[bp]
Indexado.- Un operador indexado representa una dirección de memoria relativa a uno de los registros índice (SI o DI). Su sintaxis es:
desplazamiento[DI]
desplazamiento[SI]
[desplazamiento][DI]
[DI+desplazamiento]
[DI].desplazamiento
[DI]+desplazamiento
en cada caso la dirección efectiva es la suma del desplazamiento y el contenido del registro.
mov ax,[si]
mov al,[di]
mov bx,12[di]
mov bx,fred[si]
Base-indexados.- Un operador base-indexado representa una dirección de memoria relativa a la combinación de los registros de base e índice. Su sintaxis es:
desplazamiento[BP][SI]
desplazamiento[BX][DI]
desplazamiento[BX][SI]
desplazamiento[BP][DI]
[desplazamiento][BP][DI]
[BP+DI+desplazamiento]
[BP+DI].desplazamiento
[DI]+desplazamiento+[BP]
en cada caso la dirección efectiva es la suma del desplazamiento y el contenido del registro.
mov ax,[BP][si]
mov al,[bx+di]
mov bx,12[bp+di]
mov bx,fred[bx][si]
Estructuras.- Su sintaxis es variable.campo. variable es el nombre con que se declaró la estructura, y campo es el nombre del campo dentro de la estructura.
date STRUC
mes DW ?
dia DW ?
aa DW ?
date ENDS
actual date ‹´ja´,´01´,´84´›
mov ax,actual.dia
mov actual.aa, ´85´
Operadores y expresiones.- Se cuenta con los siguientes operadores:
-aritméticos
expresión1 * expresión2
expresión1 / expresión2
expresión1 MOD expresión2
expresión1 + expresión2
expresión1 - expresión2
+ expresión
- expresión
-de corrimiento
expresión1 SHR contador
expresión1 SHL contador
-relacionales
expresión1 EQ expresión2
expresión1 NE expresión2
expresión1 LT expresión2
expresión1 LE expresión2
expresión1 GT expresión2
expresión1 GE expresión2
- de bit
NOT expresión
expresión1 AND expresión2
expresión1 OR expresión2
expresión1 XOR expresión2
-de índice
[expresión1] [expresión2]
ejemplos:
mov al, string[3]
mov string[last],al
mov cx,dgroup:[1] ; igual a mov cx,dgroup:1
-de apuntador
tipo PTR expresión
tipo puede ser BYTE ó 1, WORD ó 2, DWORD ó 4, QWORD ó 8, TBYTE ó 10, NEAR ó 0FFFFh, FAR ó 0FFFEh. Ejemplos:
call FAR PTR subrout3
mov BYTE ptr [array], 1
add al, BYTE ptr [full_word]
-de nombre de campo
estructura.campo
ejemplos:
inc month.day
mov time.min,0
mov [bx].dest
-de propósito especial.
OFFSET expresión.- Regresa el desplazamiento del operando
mov bx, OFFSET dgroup:array
mov bx, offset subrout3
SHORT etiqueta.- Para un salto de menos de 128 bytes
jmp SHORT loop
LENGTH variable.- Regresa el número de elementos de variable según su tipo
mov cx,length array
SIZE variable.- Regresa el tamaño en bytes alojados para variable
mov cx,size array
SEG expresión.- Regresa el valor del segmento para expresión
mov ax, SEG saludo
5.- MACROS Y PROCEDIMIENTOS.
La manera más fácil de modularizar un programa es dividirlo en dos o más partes. Para esto, es necesario que datos, símbolos, y demás valores de un módulo sean reconocidos por el otro u otros módulos. Para este tipo de declaraciones globales existen dos directivas:
PUBLIC nombre,,, que hace la variable, etiqueta o símbolo absoluto disponible para todos los programas.
EXTRN nombre:tipo,,, que especifica una variable, etiqueta o símbolo externos identificados por nombre y tipo (que puede ser BYTE, WORD, DWORD, QWORD, TBYTE, NEAR, FAR, o ABS, éste último para números absolutos).
El siguiente ejemplo ilustra el uso de las directivas. El primer listado corresponde al módulo principal, mientras que el segundo al módulo que contiene una rutina. Ambos módulos son archivos que se editan por separado, se ensamblan por separado, pero se ligan juntos.
MODULO PRINCIPAL: MAIN.ASM
NAME main
PUBLIC exit
EXTRN print:near
stack SEGMENT word stack 'STACK'
DW 64 DUP(?)
stack ENDS
data SEGMENT word public 'DATA'
data ENDS
code SEGMENT byte public 'CODE'
ASSUME cs:code, ds:data
start:
mov ax,data ; carga localizacion del segmento
mov ds,ax ; en el registro DS
jmp print ; va a PRINT en el otro modulo
exit:
mov ah,4ch
int 21h
code ENDS
END start
SUBMODULO: TASK.ASM
NAME task
PUBLIC print
EXTRN exit:near
data SEGMENT word public 'DATA'
entrada DB "Entrando a un submodulo....",13,10,"$"
salida DB ".......saliendo del submodulo.",01,07,13,10,"$"
data ENDS
code SEGMENT byte public 'CODE'
ASSUME cs:code, ds:data
print:
mov ah,06h ; Funcion para borrar pantalla
mov al,0 ; todas las lineas
mov cx,0 ; de 0,0
mov dh,24d
mov dl,79d
mov bh,0 ; atributo en lineas vacias
int 10h ; Servicio de e/s video
mov dx, OFFSET entrada
mov ah,09h
int 21h
mov dx, OFFSET salida
int 21h
jmp exit ; Regresa al otro modulo
code ENDS
END
La declaración de macros se hace a través de las directivas MACRO y ENDM. Su sintaxis es:
nombre MACRO [parámetros,,,]
declaraciones
ENDM
parámetros son los valores que se substituirán en la macro cada vez que se haga referencia a ésta.
Para la definición de procedimientos se emplean las directivas PROC y ENDP. Su sintaxis es:
nombre PROC [distancia]
sentencias
nombre ENDP
distancia, que puede ser NEAR (defecto) o FAR permiten indicar el tipo de acciones a realizar en brincos y llamados a subrutinas. nombre se puede usar como dirección en llamados o brincos.
6.- INTERRUPCIONES.
Como se mencionó anteriormente la PC esta constituida lógicamente por su BIOS y sistema operativo. La mayoría de las rutinas que controlan al computador están grabadas en el ROM del BIOS, aunque muchas rutinas son establecidas por el sistema operativo y se cargan en RAM al momento de encender al computador. Estas rutinas son denominadas interrupciones y son activadas mediante la instrucción: INT número. Una interrupción es una operación que invoca la ejecución de una rutina específica que suspende la ejecución del programa que la llamó, de tal manera que el sistema toma control del computador colocando en el stack el contenido de los registros CS e IP. El programa suspendido vuelve a activarse cuando termina la ejecución de la interrupción y son restablecidos los registros salvados. Existen dos razones para ejecutar una interrupción: (1) intencionalmente como petición para la entrada o salida de datos de un dispositivo, y (2) un error serio y no intencional, como sobreflujo o división por cero.
El operando de una interrupción indica cuál es la rutina a activar. La dirección de la rutina es localizada por medio de una tabla que el sistema mantiene a partir de la dirección 0000:0000h. Existen 256 entradas de 4 bytes de longitud, y cada interrupción proporciona varias funciones. Las interrupciones de 00h a 1Fh corresponden al BIOS y de 20h a FFh son del DOS y BASIC. El apéndice F proporciona una lista de las interrupciones para equipo XT.
0 comments:
Post a Comment