           INTRODUCCION AL ASM: USO DE LOS PROGRAMAS ENSAMBLADORES
           =======================================================

   Como anticipamos en el anterior captulo, comenzaremos aqu con el uso de
los ensambladores comerciales. Despus de algo de teora, veremos el famoso
'Hello, world' tal y como quedara en lenguaje ensamblador.

   Para entender bien todo el proceso desde el fichero fuente, que suele llevar
la extensin '.ASM', hasta el programa que reside en memoria una vez que el DOS
lo ha cargado, haremos el camino de atrs a delante, es decir, comenzando en el
programa final y acabando en el '.ASM'.

   Un programa en memoria, una vez cargado, suele consistir en un bloque de
bytes (desde unas decenas de bytes hasta algunos cientos de kilobytes), en el
que residen tanto el cdigo como los datos y la pila del programa. Ya que la
longitud total puede ser superior a 64 KB, no se puede usar un solo valor de
segmento para acceder a todo el cdigo y a todo los datos del programa. Para
posibilitar el acceso a todo el bloque de programa, este bloque est dividido
en varios bloques distintos, normalmente alineados para comenzar en direcciones
mltiplos de 16d. A estos bloques lgicos (ya que la divisin no es fsica), se
les denomina 'segmentos'; no hay que confundir este trmino con los 'segmentos'
que vimos al ver la arquitectura segmentada de los 80x86: aquellos 'segmentos'
eran siempre de 64K bytes, mientras que estos 'segmentos' pueden tener cual-
quier longitud menor o igual a 64K bytes.

   Estos bloques lgicos o segmentos se clasifican en funcin de lo que contie-
nen. Principalmente, pueden contener cdigo, datos, o constituir espacio para
la pila. Por tanto, se habla de 'segmentos de datos', 'segmentos de cdigo', y
'segmento de pila' (no suele haber ms que un segmento de pila).

   Durante la ejecucin del programa, CS suele contener un valor de forma que
CS:0 sea el primer byte de uno de los segmentos de cdigo, mientras que DS
suele contener un valor de manera que DS:0 sea el primer byte de uno de los
segmentos de datos. SS se suele mantener inalterado a lo largo del programa,
apuntando al segmento de pila.

   Para saltar de un punto del programa a otro que resida en otro segmento, es
necesario modificar tanto CS como IP, mientras que si el destino reside en el
mismo segmento que la instruccin de salto basta con modificar IP. De la misma
forma, para acceder a una variable que resida en el segmento de datos apuntado
por DS no es necesario modificar DS, mientras que si la variable reside en otro
segmento de datos es necesario cargar DS o ES para que apunte al principio del
otro segmento antes de acceder a la variable. Como podemos intuir, el acceso
a cdigo y datos 'cercanos' (que residan en el CS y DS actuales) es mucho ms
cmodo, adems de ligeramente ms rpido, que el acceso a cdigo y datos leja-
nos (en otros segmentos que los apuntados por CS y DS).

   Ms adelante volveremos a este galimatas de segmentos y veremos lo que son
los famosos 'modelos' estndar de memoria. Por ahora, dejemos este tema y siga-
mos.

   Esta imagen de memoria la crea el DOS a partir del fichero '.EXE' que el
usuario ha ordenado ejecutar (ms adelante veremos las peculiaridades de los
'.COM'). Lo que el DOS hace no es smplemente cargar el '.EXE' tal y como est
en el disco y saltar a la primera direccin del '.EXE', sino que el proceso de
carga es bastante complejo. En realidad, el '.EXE' es el bloque que hemos
visto, compuesto de varios bloques lgicos (llamados segmentos), y precedido de
una cabecera de longitud variable. El estudio detallado de esta cabecera queda
fuera de nuestro mbito, pero nos interesa saber el contenido aproximado.

   Los primeros dos bytes del '.EXE' son la cadena 'MZ', que lo identifican
como '.EXE'. La cabecera indica, adems, su propia longitud, un CRC para el
fichero completo (es decir, una suma utilizada para verificar la integridad del
fichero), el punto - dentro del bloque de cdigo y datos - al que hay que sal-
tar (el punto de entrada al programa), los valores iniciales de SS y SP para
apuntar a la pila, y algn detalle ms. Pero, adems de todo esto, lo ms
importante de la cabecera es la llamada 'tabla de reubicacin'.

   En un sistema MSDOS, los programas deben ser capaces de correr en cualquier
punto de la memoria. Las instrucciones de los procesadores 80x86 son en muchos
casos relativas (es decir, un salto suele ser 'salta 10 bytes ms adelante' y
no 'salta a la direccin 310'), con lo que gran parte del cdigo funciona en
cualquier punto de la memoria. Pero existen algunas instrucciones que utilizan
direcciones absolutas, como por ejemplo cargar en un registro la direccin
completa de una variable (offset y segmento). Estas instrucciones tienen que
ser distintas cuando los datos estn en la zona baja de la memoria o en la zona
alta. Para solucionar este problema, un '.EXE' lleva en la cabecera una tabla
en la que se indican todas las instrucciones que necesitan ser modificadas al
cargar el programa.

   Por tanto, el proceso de carga es el siguiente (realizado por el MSDOS):

			- Carga del '.EXE' en dos partes: cabecera y bloque de programa.
			- Recorrido de la tabla de reubicacin, arreglando cada referencia
			  marcada en la tabla.
			- Inicializacin de los registros de segmento, tal y como viene
			  especificado en la cabecera, y salto al punto de entrada.

   Hay que especificar dos cosas en es punto, antes de pasar a los ficheros
'.OBJ': la primera, que todas las referencias de la tabla de reubicacin no son
para instrucciones, sino que algunas pueden ser para datos. Esto ocurre en el
caso de que una variable esttica, al ser declarada, sea inicializada con un
valor que dependa de la situacin el memoria de otra variable. La segunda pun-
tualizacin es que el MSDOS se encarga de inicializar algunos registros de seg-
mento antes de entrar al programa, pero no todos. CS, evidentemente, apunta al
segmento de cdigo que contien el punto de entrada. SS apunta ya al segmento de
pila. Pero DS, en principio, no apunta a ningn sitio en concreto. Por ello,
las primeras instrucciones de un programa ASM suelen ser para inicializar DS
apuntando al segmento de datos que vayamos a usar.

   Un fichero '.EXE' como los que hemos visto lo construye un programa que se
incluye con cualquier compilador o ensamblador, llamado enlazador o LINKer (en
spanglish). Los linkers de Microsoft suelen llamarse LINK.EXE, mientras que los
de Borland se llaman siempre TLINK.EXE.

   Un linker toma como entrada un conjunto de uno o varios ficheros llamados
'ficheros objeto', y genera como salida un fichero '.EXE' (opcionalmente, el
TLINK puede generar un '.COM', mientras que con el LINK es necesario convertir
el '.EXE' resultante en '.COM' con la utilidad EXE2BIN). Los ficheros objeto
tienen extensin '.OBJ', y son ficheros generados directamente por los ensam-
bladores y compiladores a partir de nuestros listados con el cdigo fuente.

   Un fichero '.OBJ' contiene varios bloques, que son los que se usan luego
para construir los segmentos que van en el '.EXE'. Adems de estos bloques, los
ficheros '.OBJ' llevan tambin algunas referencias que luego debern ser in-
cluidas en la tabla de reubicacin del '.EXE'. Pero lo que diferencia princi-
palmente a un '.OBJ' de un '.EXE' (aparte del formato de fichero), son algo
llamado 'referencias externas' y 'declaraciones pblicas'.

   Para facilitar el trabajo del programador, los lenguajes actuales permiten
que un programa '.EXE' se construya a partir de cdigo de varios listados
diferentes. Adems, cada uno de estos 'mdulos' (que as se llaman) puede estar
escrito en un lenguaje diferente, siempre que tengamos un compilador para ese
lenguaje que genere ficheros '.OBJ' estndar. Una de las complicaciones que
esta posibilidad aade, es que es necesario poder acceder desde un mdulo a
funciones y variables declaradas en otro mdulo. Lo que se hace es permitir a
cualquier mdulo hacer declaraciones externas, en las que se indica al compila-
dor que una variable o funcin est en algn otro mdulo con el que luego
linkaremos ste. As, el '.OBJ' generado incluye precisamente una referencia
externa con el nombre de la funcin o variable. El mdulo que define una varia-
ble o funcin a la que se quiere acceder desde otro mdulo debe declarar a sta
como 'pblica', de manera que el '.OBJ' generado lleve una pequea indicacin
advirtiendo que la variable de ese nombre est en ese mdulo, junto con la
direccin de sta. El linker es el que se encarga de resolver todas estas refe-
rencias, modificar todas las instrucciones que sea posible en este punto y
dejar las que no se puedan arreglar en la tabla de reubicacin del '.EXE'.

   Otra de las cosas que hace el linker es 'unir' los segmentos de distintos
mdulos en uno slo. Ya que cada segmento del '.OBJ' va acompaado de un nombre
y de algunos datos, si estos coinciden el linker supone que se ha hecho as
intencionadamente y los une en uno slo, poniendo uno a continuacin del otro.
Las reglas que sigue el linker para reconocer los segmentos y actuar en conse-
cuencia  son, junto con el eslabn perdido, uno de los misterios ms ignotos de
la humanidad. Ahora en serio, las reglas que siguen en LINK y el TLINK para
reconocer el segmento de pila, etc... son ligeramente distintas, pero existe
una manera de hacer todo esto sin preocuparse de los nombres de los segmentos,
y, por ejemplo, linkar un mdulo ASM con uno escrito en C y conseguir fundir
los segmentos de cdigo y datos de los dos mdulos. Para esto usaremos carcte-
rsticas del MASM 5.0 y superiores, y del TASM 1.0 y superiores, por lo que os
recomiendo que consigis al menos estas versiones de los ensambladores (con uno
de los dos vale).

   Adems de los ficheros '.OBJ', un linker puede tambier linkar ficheros
'.LIB'. Un '.LIB' o fichero de librera es un fichero que contiene un conjunto
de ficheros '.OBJ', uno detrs de otro, que por alguna razn se suelen usar
conjuntamente. Adems, el '.LIB' lleva un ndice hasheado para encontrar rpi-
damente las referencias a smbolos del '.LIB'. Cuando el linker encuentra una
referencia a un smbolo externo, primero lo busca en los '.OBJ' especificados
por el usuario, y en caso de no encontrarlo busca en los ndices de las '.LIB'
especificadas. Si lo encuentra, extrae el '.OBJ' de la '.LIB' en el que apare-
ce el smbolo (variable o funcin) y lo aade al '.EXE' generado. Por ejemplo,
todas las funciones que un compilador de C provee al programador vienen en una
librera (llamada librera estndar). Es bastante sencillo extraer de un '.LIB'
los '.OBJ' que lo componen, aunque la mayora de los gestores de librera no lo
permiten.

   Ahora que ya sabemos cmo son los '.OBJ', el estudio del listado fuente de
programa en ASM resulta bastante sencillo: un listado fuente en lenguaje ensam-
blador es prcticamente una imagen del '.OBJ' que se quiere generar. El
listado est dividido en fragmentos, denominados 'segmentos', que son los blo-
ques que el '.OBJ' lleva para el linker. Estos segmentos pueden ser de cdigo
o de datos. Adems, podemos encontrar declaraciones PUBLIC (smbolos que se
exportan en el '.OBJ' para uso y disfrute generalizado de los dems mdulos);
podemos tambin encontrar declaraciones EXTRN (smbolos que se indican en el
'.OBJ' al linker para ser buscados entre los dems mdulos).

   Veamos ya cmo quedara en ASM el famoso 'Hello, world!':

=================8<============================8<===========================
PILA	SEGMENT STACK 'STACK'	; Abre el segmento de pila
	DW 100h DUP (?)				; 200h (512d) bytes de pila
PILA	ENDS					; Cierra el segmento de pila

DATOS	SEGMENT 'DATA'			; Abre el segmento de datos
Msg	DB 'Hello, world!$'			; Mensaje a imprimir
DATOS	ENDS					; Cierra el segmento de datos

CODIGO	SEGMENT 'CODE'			; Abre el segmento de cdigo
	ASSUME CS:CODIGO, DS:DATOS, SS:PILA
Entrada	PROC					; Abre el procedimiento 'Entrada'
	mov	ax,DATOS				; Valor de segmento para 'DATOS'
	mov	ds,ax					; Para acceder a 'Msg'
	mov	dx,OFFSET Msg			; Para la int 21h, servicio 9
	mov	ah,9					; Especifica servicio9
	int	21h						; Invoca servicio 9: imprimir cadena
	mov	ax,4C00h				; Servicio 4Ch, valor de retorno 0
	int	21h						; Invoca servicio 4Ch: retorno al DOS
Entrada	ENDP					; Cierra el procedimiento 'Entrada'
CODIGO	ENDS					; Cierra el segmento 'CODIGO'

	END Entrada					; Fin del programa, punto de entrada 'Entrada'
=================8<============================8<===========================

   Los ensambladores ms modernos permiten una manera ms sencilla de escribir
este programa, usando las directivas de segmento simplificadas, pero creo que
es mejor ver primero la forma 'clsica' y luego la simplificada, con lo que la
comprensin es mucho mayor.

   Como vemos, el listado est dividido en tres partes principales, que corres-
ponden directamente a los segmentos del '.OBJ'. El principio de un segmento se
indica con la directiva del ensamblador 'SEGMENT', y el final con la directiva
'ENDS'. Hay que tener en cuenta que estas directivas no son instrucciones en
ASM, sino que indican al ensamblador cmo debe realizar su trabajo, por lo que
no generan cdigo. Al final del listado siempre debe aparecer la directiva END,
que indica el final del listado. Opcionalmente, puede llevar un argumento cuyo
significado veremos ms tarde.

   El trabajo del ensamblador es bsicamente el siguiente: va leyendo lneas
del fichero '.ASM', que sern siempre directivas. Cuando encuentra una lnea
con la directiva SEGMENT, prepara un buffer para ir introduciendo en l los
datos que ir leyendo. Inicializa un contador interno a 0, para apuntar al
principio de buffer. Entonces, comienza a procesar las lneas de otra forma
hasta que encuentra un ENDS, que indica el final del segmento. El contenido del
buffer ir al '.OBJ' prcticamente tal y como est. Las lneas interiores a un
segmento (entre un SEGMENT y su ENDS correspondiente) se procesan de otra
forma. Aunque algunas pueden ser directivas, la mayora estn destinadas a ge-
nerar cdigo o datos que irn en el '.OBJ'. Despus de almacenar los bytes que
una lnea define en el buffer, el contador interno se incrementa para apuntar
a los siguientes bytes libres. Estas lneas pueden ser lneas de cdigo o lne-
as de datos. Si son de cdigo, la sintxis ser la siguiente:

		ETIQUETA: INSTRUCCION OPERANDO(S) ;COMENTARIO

   Mientras que si son lneas de datos, la sintxis ser la siguiente:

		ETIQUETA D<X> DATOS ;COMENTARIO

   En esta lnea, <X> se sustituye por una letra que indica el tamao de los
datos (B: bytes, W: palabras, D:dobles palabras, ...).

   La etiqueta es un smbolo, en principio nico (no puede haber dos etiquetas
iguales en un mismo listado), que el ensamblador almacena en una tabla de sm-
bolos interna junto con el valor del contador interno al procesar la lnea.
Tambin se almacena el contexto en el que aparece la etiqueta (si es de datos
o de cdigo, el tamao de los datos a los que apunta, el segmento al que perte-
nece...). Se utiliza para referenciar desde otro punto una variable por nombre,
en caso de que se trate de una etiqueta de datos, o para saltar a un punto
determinado desde otro lugar del programa.

   La instruccin y los operandos son cualquier instruccin vlida del 80x86, y
el comentario puede ser cualquier cosa que aclare la instruccin comentada. Los
datos de una lnea del segundo tipo pueden ser nmeros separados por comas,
en cuyo caso se sitan uno detrs del siguiente. Cuando no se quiere iniciali-
zar una variable, se puede poner un smbolo de interrogacin ('?'). Si se quie-
re repetir varias veces una secuencia, se puede utilizar la construccin:

		n DUP (dato, dato, dato)

   Donde 'n' es un nmero que representa cuntas veces se debe repetir la se-
cuencia.

   Estudiemos ahora con detalle el listado HELLO.ASM. Para hacer la prueba, se
puede recortar el listado y salvarlo como HELLO.ASM. Despus, podemos ensamblar
con 'TASM HELLO' o con 'MASM HELLO;'. El linkado lo haremos con 'TLINK HELLO' o
'LINK HELLO;', tras lo cual tendremos el HELLO.EXE en el directorio actual. La
sintxis de la lnea de comandos vara ligeramente de una versin a otra del
mismo compilador, por lo que os recomiendo consultar el manual o hacer algunas
pruebas.

   Las primeras tres lneas del listado proporcionan una segmento para la pila
del programa. Como vemos, el segmento lleva un nombre que le proporcionamos
nosotros, en este caso el nombre 'PILA'. Este nombre es cualquier identificador
vlido en ASM; recordemos que el ensamblador no distingue entre maysculas y
minsculas. Despus de la directiva SEGMENT van varios parmetros opcionales.
Ya que normalmente usaremos las directivas de segmento simplificadas, no entra-
remos a detallar estos parmetros. Si alguien tiene mucho inters puede consul-
tar el manual del ensamblador o la ayuda online de ste, en caso de que tenga.
Como se aprecia, se dejan 100h (256d) palabras sin inicializar para la pila.
Esto suele ser suficiente para programas que no usen la pila intensivamente.

   Las siguientes tres lneas definen otro segmento, que lleva los datos del
programa. En este caso, la nica variable es una cadena con el mensaje a impri-
mir. Cuando tras un DB aparece una cadena entre comillas simples, el ensambla-
dor introduce todos los caracteres, uno detras de otro.

   Para no hacer el mensaje demasiado largo, continuaremos el estudio de ste
listado en el siguiente captulo.

   Salut :-)

   Jon