
      ASM por AeSoft. (leccin 11).
      --------------------------------------------------------------------
      - PROGRAMAS EN MS-DOS:
      - PROGRAMAS (COM)
      - PROGRAMAS (EXE)
      - PSP (Prefijo de Segmento de Programa)
      - BLOQUE DE ENTORNO
      - COLA DE ORDENES
      - PSEUDO_INSTRUCCIONES
      - MODELOS Y EJEMPLOS
      - CREAR EL PROGRAMA EJECUTABLE (ENSAMBLAR-LINKAR)
      --------------------------------------------------------------------

      Hola de nuevo a todos los seguidores del curso de asm (ASM por AEsoft).
      En las 10 primeras lecciones hemos tratado lo que he considerado
      imprescindible para poder empezar a programar en ensamblador.

      Hemos estudiado el ordenador sobre el que vamos a trabajar, las
      principales instrucciones ASM para programarlo, las funciones ms
      importantes (a este nivel del curso) que nos ofrece el DOS, la BIOS
      y el Driver de Teclado... y algunas cosas ms que he considerado
      necesarias antes de meternos a programar.

      Pues bien, ha llegado el momento. Vamos a empezar a programar.
      En esta leccin estudiaremos los dos tipos de programas con los
      que contamos en MS-DOS: programas COM  y  programas EXE.

      Adems, trataremos las estructuras de datos asociadas:
      Prefijo de Segmento de Programa, Bloque de Entorno, Cola de Ordenes,
      etc...

      ... Y muchas ms cosas interesantes.


      - PROGRAMAS EN MS-DOS
      ---------------------
      Bajo el sistema operativo MS-DOS y todos los compatibles como DR-DOS,
      PC-DOS, etc.. tenemos 2 modelos diferentes de programas ejecutables:
      El modelo COM y el modelo EXE.
      En siguientes apartados veremos sus diferencias, ventajas y desventajas.
      En este apartado vamos a ver lo que tienen en comn.

      Como hemos dicho, estos dos modelos de programas son los nicos que
      reconoce el DOS. Dejaremos a un lado los Ficheros De Proceso Por Lotes
      o ficheros BATCH (Extensin BAT), ya que aunque son ejecutables, no
      hay cdigo ejecutable directamente por el procesador dentro de ellos,
      sino llamadas a otros programas y comandos propios pertenecientes a un
      pseudo-lenguaje de programacin BATCH.
      No les daremos por tanto la condicin de Programa, sino de Fichero de
      Proceso Por Lotes.

      Ambos programas (COM y EXE) se cargan y ejecutan en el rea de programas
      transitorios (TPA) (siempre que haya memoria suficiente para hacerlo),
      llamndose por tanto 'Programas transitorios'.
      Todos los programas se cargan para su ejecucin en el TPA, pero hay
      programas especiales que se quedan residentes antes de terminar su
      ejecucin. Estos programas se llaman 'Programas Residentes', y la zona
      de memoria donde se encuentran se denomina 'Area de Programas Residentes'.

      Como podemos ver, cuando dejamos un programa residente, estamos
      robando memoria al TPA para agrandar el Area de Programas Residentes.
      De forma similar, cuando desinstalamos un Programa Residente de la
      memoria, el TPA crece de acuerdo al tamao de dicho Programa.
      (Este tema lo veremos en profundidad al tratar los Programas Residentes).

      Sigamos con las generalidades:

      Al programa que se va a ejecutar se le puede indicar que ejecute
      una determinada tarea de las que ofrece al usuario mediante lo que
      se llama Cola De Ordenes, que no es ni ms ni menos que los parmetros
      que se le pasan a un programa a continuacin del nombre de programa.

      Ejemplo: ARJ A FILE *.*
      En este ejemplo, la Cola De Ordenes est formada por todo lo que hay
      a la derecha de 'ARJ' (nombre del programa), esto es, 'A FILE *.*'.
      Atendiendo a la Cola De Ordenes pasada al programa, ste realizar una
      de las tareas posibles u otra. En este caso, la Cola De Ordenes le
      indicara al programa que comprima (A) en el fichero FILE todos
      los archivos del directorio actual (*.*).

      La Cola De Ordenes es el conjunto de parmetros que se le pasan al
      programa para que realice una determinada tarea. Mediante estos
      parmetros, un programa puede realizar la tarea solicitada por el
      usuario de entre toda una serie de tareas diferentes soportadas por
      el programa. Esto ofrece una gran versatilidad a los programas.

      (Vase el apartado dedicado a la Cola de Ordenes).

      Por supuesto, tambin podemos hacer programas que no acepten ningn
      parmetro, por lo tanto, se ignorar cualquier informacin pasada al
      programa mediante la Cola De Ordenes, y se ejecutar el programa sin
      ms.

      De hecho es as como vamos a trabajar en un principio, ya que los
      programas que empecemos a hacer sern tan concisos que slo realizarn
      una determinada tarea.

      Conforme avancemos en el Curso, ya tendremos tiempo de realizar programas
      suficientemente complejos que necesiten de parmetros para seleccionar
      una de sus mltiples tareas ofrecidas.

      Pero bueno, eso ser ms adelante. Volvamos ahora a lo que nos toca...
      Hemos dicho que la Cola de Ordenes es pasada al programa para que
      ste sepa la tarea que debe realizar. Ahora la cuestin es:
      Dnde se almacena dicha Cola de Ordenes para que el programa pueda
      acceder a ella?
      La respuesta a este interrogante nos lleva a otro de los apartados de
      esta leccin: El Prefijo de Segmento de Programa (PSP).
      Como adelanto, decir que el PSP es una zona de datos de 256 bytes
      (100H bytes) utilizada para diferentes propsitos: Almacenar la
      Cola de Ordenes, servir de Buffer de Fichero por defecto, resguardar
      ciertos vectores de interrupcin, etc..
      Para cada programa en memoria (ya sea transitorio  residente) existe
      un PSP asociado.

      (Vase el apartado dedicado al PSP).

      Aparte del PSP, el DOS ofrece a cada programa otra estructura de datos
      llamada Bloque de Entorno (Environment Block).
      Este Bloque de Entorno contiene informacin acerca de distintas
      Variables de Entorno, como son el Path, Prompt y otras tantas.
      Adems de estas variables, el Bloque de Entorno ofrece el nombre
      del programa dueo del PSP y de dicho Bloque. Aunque no lo parezca en un
      principio, esta ltima informacin nos puede ser muy til en
      determinados programas.

      (Vase el apartado dedicado al Bloque de Entorno).



      - PROGRAMAS .COM
      ----------------
      El nombre de COM viene de 'Copy Of Memory', y quiere decir algo as como
      que el contenido del fichero COM formado por las instrucciones y datos
      que componen el programa, es una copia exacta del programa una vez
      cargado en memoria.

      Los programas COM se cargan en memoria a partir de la direccin 100h,
      justo a continuacin del PSP. Por tanto, cuando creemos nuestro
      programa COM debemos indicarle al ensamblador que utilicemos (MASM,
      TASM, etc) que nuestro programa empezar a partir de dicha direccin 100H.
      Esto lo hacemos mediante la pseudo_instruccin ORG 100H.
      Esta instruccin no genera ningn cdigo ejecutable, simplemente le
      indica al ensamblador con el que estamos trabajando que el cdigo que
      genere debe empezar (ORiGen) en la direccin 100h.

      Todos los accesos a variables, saltos en el programa, etc.. se harn
      teniendo en cuenta que el programa empieza en la direccin 100h, y no
      en la 00h. Si no utilizramos la instruccin ORG 100h, el cdigo
      ejecutable resultante estara construido en base a una direccin de
      comienzo 00h. Al cargar el programa en memoria para su ejecucin (a
      partir de la direccin 100h), habra 100h bytes de diferencia en todos
      los accesos  a memoria, saltos, llamadas a procedimientos, etc.

      Otra cosa importante a tener en cuenta es la pila.
      Cuando el DOS carga un programa COM en memoria para su ejecucin,
      sita la pila justo al final del segmento en el que se carga el programa.
      Vamos a ver cmo quedara el programa en memoria mediante un grfico:



CS:0000 --->+---------------------------------------+
DS:0000 -                                         
ES:0000 -   Prefijo de Segmento de Programa (PSP) 
SS:0000 -+            256 (100h) Bytes             
         +->+---------------------------------------
CS:0100 -+                                         
(CS:IP)          Cdigo y datos del Programa       
                                                   
CS:FFFF -+                                         
DS:FFFF -                                         
ES:FFFF -               Pila (Stack)              
                                                  
         +->+---------------------------------------+
         
SS:FFFF -+
(SS:SP)


      Todos los registros de Segmento, incluido SS (registro de Segmento
      de Pila) se inicializan con valor 0, apuntando as al principio del
      segmento donde se carga el programa, en definitiva, apuntando al
      principio del PSP, ya que dicho PSP se sita justo al principio del
      segmento.

      El registro IP (Puntero de Instruccin) se inicializa con valor 100h
      para que apunte a la primera instruccin del programa.
      La primera instruccin del programa se encuentra justo despus del
      PSP y normalmente suele ser un salto (JMP).
      Esto es as ya que los datos suelen estar antes que el cdigo del
      programa.

            +---------------------------------------+
                            PSP                         Lo enmarcado entre
CS:0100  -->--------------------------------------- -+  esta llave es el
(CS:IP)        Salto hacia el CODIGO DEL PROGRAMA      contenido del programa
            ---------------------------------------    antes de cargarlo en
                      DATOS DEL PROGRAMA               memoria para su
            ---------------------------------------  +- ejecucin.
                                                       Una vez que se carga
                      CODIGO DEL PROGRAMA              un programa en memoria
                                                       para su ejecucin,
                                                       el PSP y la PILA se
            --------------------------------------- -+  consideran parte de
                           PILA                         dicho programa.
            +---------------------------------------+



      Hemos dicho que los datos suelen estar antes que el cdigo en el
      programa. Hay varios motivos para que esto sea as, por una parte
      es ms cmodo para el programador tener los datos al principio del
      programa, es obvio, no?
      El compilador tambin agradecer que se definan los datos antes de
      referirse a ellos en el cdigo.

      Ahora nos surge un problema: Si situamos los datos al principio del
      programa (Offset 100h) el procesador tomar estos datos como instrucciones
      y las ejecutar, es decir, se ejecutaran los datos!
      Para remediarlo, al principio del programa incluimos una instruccin de
      salto (JMP) hacia el cdigo del programa, saltando as los datos.

;*****
                                       +------------------------------------+
           JMP Codigo_Programa          Salto hacia el CODIGO DEL PROGRAMA 
           ;Inicio_Datos               +------------------------------------
           ;[Datos del programa]                DATOS DEL PROGRAMA         
           ;Fin_Datos                                                      
                                       +------------------------------------
Codigo_Programa:                                                           
           ;Inicio_Codigo_Programa                                         
           ;[Codigo del Programa]               CODIGO DEL PROGRAMA        
           ;Fin_Codigo_Programa                                            
                                       +------------------------------------+
;*****


      Unos prrafos ms arriba hemos dicho que la pila se sita justo al
      final del segmento (El registro SP apunta al Offset 0FFFFh).
      Ya sabemos de otras lecciones que la pila crece (mediante los sucesivos
      PUSH's) hacia direcciones ms bajas de memoria.
      Tenemos entonces que la pila crece en direccin al final del programa,
      el cual se encuentra al principio del segmento.
      Es importante tener esto presente, ya que puede ser motivo de graves
      errores. Aunque no es normal, se puede dar el caso de que al crecer
      la pila debido a mltiples Apilamientos (PSUH's), sta machaque el
      cdigo del programa.
      Esto puede suceder en determinados casos como:

      - El cdigo del programa COM es muy grande, ocupa casi todo el segmento.
        Entonces, por muy poco que crezca la pila, acabar machacando dicho
        cdigo del programa.

      - Aunque el cdigo del programa no sea demasiado extenso, el uso que
        se hace de la pila es excesivo (mediante apilamientos). Por ejemplo,
        en funciones recurrentes(*) que pasan los parmetros a travs de la
        pila. En estos casos, la pila puede crecer tanto que acabe machacando
        al programa, por pequeo que ste sea.

        (*) Una funcin recurrente es aquella que puede invocarse a s misma.
        Si no se depura bien dicha funcin, puede derivar en infinitas
        llamadas a s misma. En cada una de estas llamadas, la pila crece,
        de tal manera que al cabo de unas cuantos cientos o miles de estas
        llamadas, la pila acaba machacando al programa.

      - Etc...



      Recapitulemos..
      Tenemos un slo segmento para el programa COM. Los primeros 256 (100h)
      bytes de dicho segmento estn ocupados por el PSP. A continuacin nos
      encontramos con el programa, y al final del segmento tenemos la Pila,
      la cual crece en direccin al programa.
      En un primer momento, todos los registros de segmento (DS, CS, ES y SS)
      apuntan al principio del segmento (Offset 0000h).
      El registro IP apunta al Offset 100h, primera instruccin del programa,
      justo a continuacin del PSP. Como los datos del programa se suelen
      depositar al principio del mismo, dicha instruccin situada en el
      Offset 100h suele ser un salto hacia el principio del cdigo del
      programa.
      El registro SP (Puntero de Pila) apunta al Offset 0FFFFh (ltimo byte
      del segmento). La pila crece de direcciones ms altas 0FFFFh hacia
      direcciones ms bajas.

      Una caracterstica importante relacionada con la forma en que el
      DOS le cede el control a los programas COM es la siguiente:

        Una vez que un programa COM toma el control, el DOS reserva toda
        la memoria libre para este programa. Es decir, por muy pequeo
        que sea el programa COM, el DOS le d toda la memoria libre del
        sistema.

      En la prxima leccin ampliaremos informacin relacionada con este
      punto, inconvenientes que conlleva y soluciones.




      - PROGRAMAS .EXE
      ----------------
      A diferencia de los programas COM (los cuales cuentan como mximo con
      un segmento (64 Ks) para cdigo, datos y pila, es decir, para todo el
      programa), los programas EXE disponen de toda la memoria del Area de
      Programas Transitorios (TPA) para su uso.

      En un programa EXE, los datos, pila y cdigo se definen en segmentos
      independientes. Se utiliza un segmento distinto para cada una de
      esas tres principales estructuras. Aunque, en realidad, podemos tener
      varios segmentos de datos, cada uno accesible de forma independiente.
      (Ver modelo de programa EXE).

      El fichero EXE cuenta con una cabecera que le indica al DOS como ubicar
      cada uno de los diferentes segmentos definidos en memoria.
      Esta cabecera la proporciona el programa LINK, nosotros no debemos
      preocuparnos por ella.

      Una vez que el DOS ha cargado el programa EXE en memoria para su
      ejecucin, ste quedara de la siguiente manera:


ES:0000 -+
         +-> +--------------------------------------+
DS:0000 -+    Prefijo de Segmento de Programa (PSP)
             +--------------------------------------
                                                   
CS:IP   --->    Segmento de Cdigo del Programa    
                                                   
             +--------------------------------------
                                                   
                      Segmento de Datos            
                                                   
SS:0000 ---> +--------------------------------------
                                                   
                      Segmento de Pila             
                                                   
SS:SP   ---> +--------------------------------------+


      Como podemos ver, el PSP se sita al principio de todo segmento de
      programa, como ocurra con los programas COM.

      En un principio ES y DS apuntan al PSP, ms tarde deberemos hacer
      que DS apunte a nuestro segmento de datos para poder acceder a stos.

      El par de registros CS:IP apuntan a la primera instruccin de nuestro
      programa. Esta primera instruccin a ejecutar viene dada por la
      pseudo_instruccin END (Fin de Programa).
      (Ver el apartado dedicado a las pseudo_instrucciones).

      El par de registros SS:SP apuntan a la base de la pila (ya que an no hay
      ninguno), y a la vez apuntan a la cima de la pila (ya que el primer
      elemento que se introduzca en la pila se har segn la direccin de
      SS:SP).

      En el grfico vemos que los tres segmentos (cdigo, datos y pila) siguen
      este orden, pero eso no tiene por qu ser as.
      Dependiendo de la memoria libre que haya en el sistema, y la distribucin
      de esa memoria libre, estos tres segmentos pueden estar en cualquier
      posicin de la memoria, y en cualquier orden.


      Una vez que nuestro programa toma el control, har accesible su segmento
      de datos (como podemos ver en el modelo y en el ejemplo de progs EXE),
      obteniendo la siguiente representacin grfica:


ES:0000 ---> +--------------------------------------+
              Prefijo de Segmento de Programa (PSP)
             +--------------------------------------
                                                   
CS:IP   --->    Segmento de Cdigo del Programa    
                                                   
DS:0000 ---> +--------------------------------------
                                                   
                      Segmento de Datos            
                                                   
SS:0000 ---> +--------------------------------------
                                                   
                      Segmento de Pila             
                                                   
SS:SP(**)--> +--------------------------------------+


(**) En caso de haber utilizado algn PUSH en las instrucciones de
     inicializacin, SS:SP no apuntaran al final del segmento de pila como
     muestra el dibujo, sino unas posiciones ms hacia el inicio de la pila:

     SS:0000 ---> +--------------------------------------
                                                        
                           Segmento de Pila             
     SS:SP   --->                                       
                  +--------------------------------------+



     Cabe resaltar que con los programas EXE no tenemos el inconveniente que
     se nos plantea con los programas COM (relativo al consumo total de la
     memoria al cargarse para su ejecucin).
     Gracias al uso de la cabecera con que cuentan los programas EXE, el
     DOS slo reserva para dichos programas la cantidad justa de memoria
     que se necesita para ubicar cada uno de sus segmentos.



     En la prxima leccin ampliaremos informacin relativa al apartado
     de programas COM y EXE. Por ahora ya es bastante extensa la leccin.







      - Prefijo de Segmento de Programa (PSP)
      ---------------------------------------

      Estructura del PSP:


      0000H  +----------------------------------------+
                Int 20h  (Terminar Programa)          (2 Bytes)
      0002H  +----------------------------------------
                Direccin de Inicio del Segmento      (2 Bytes)
                que hay a continuacin del Programa  
      0004H  +----------------------------------------
                (Reservado)                           (1 Byte)
      0005H  +----------------------------------------
                Llamada lejana (Far-Call) al          (5 Bytes)
                Distribuidor de funciones del DOS    
      000AH  +----------------------------------------
                Resguardo del vector de interrupcin  (4 Bytes)
                Int 22h (Gestor de Terminacin)      
      000EH  +----------------------------------------
                Resguardo del vector de interrupcin  (4 Bytes)
                Int 23h (Gestor de CTRL+C)           
      0012H  +----------------------------------------
                Resguardo del vector de interrupcin  (4 Bytes)
                Int 24h (Gestor de Errores Crticos) 
      0016H  +----------------------------------------
                (Reservado)                           (22 Bytes)
      002CH  +----------------------------------------
                Direccin del Segmento de Entorno     (2 Bytes)
      002EH  +----------------------------------------
                (Reservado)                           (46 Bytes)
      005CH  +----------------------------------------
                Primer FCB (Bloque de Control de      (16 Bytes)
                Fichero) por defecto                 
      006CH  +----------------------------------------
                Segundo FCB (Bloque de Control de     (20 Bytes)
                Fichero) por defecto                 
      0080H  +----------------------------------------
                Parmetros pasados al programa        (128 Bytes)
                           y                         
                DTA (Area de Transferencia de Disco) 
                por defecto                          
             +----------------------------------------+
                                                Total:  (256 Bytes)


      * Offset 0000H *
      El primer campo del PSP contiene una instruccin cdigo mquina (20CD).
      Se trata de la instruccin (Int 20h). Esta instruccin genera la
      Interrupcin 20h, utilizada para terminar la ejecucin del programa.
      Esta instruccin (como ya vimos en la leccin 10) ha quedado obsoleta,
      sustituyndose su uso por la funcin 4Ch de la INT 21h.
      Por tanto no le daremos mayor importancia a este primer campo del PSP.


      * Offset 0002H *
      En este campo se almacena la direccin del siguiente segmento de memoria
      a continuacin de nuestro programa.

      +-------------------------+  -+
          PSP                     
          Cdigo, datos           +- Programa
          Pila                    
      +-------------------------+  -+
      +-------------------------+  -+ --> Inicio del siguiente segmento.
         Segmento ajeno a         
         Nuestro Programa         
                                  +- Siguiente segmento al programa.
                                  
      +-------------------------+  -+

      Mediante este campo podemos saber el tamao del bloque de memoria en el
      que se ha cargado el programa. Restando a la direccin de segmento
      almacenada en el offset 0002h la direccin de inicio del segmento
      donde se ha cargado el PSP, tenemos el tamao del bloque (en prrafos)
      que contiene a nuestro programa.

      Si multiplicamos ese valor por 16 (un prrafo=16 bytes) obtendremos el
      tamao (en bytes) de memoria que ha suministrado el DOS para nuestro
      programa.


      * Offset 0004H *
      Campo Reservado.


      * Offset 0005H *
      Aqu nos encontramos con una curiosa forma de acceder a las funciones
      de la INT 21h. Este mtodo de acceso que vamos a ver ha quedado obsoleto,
      pero se sigue manteniendo en el PSP por motivos de compatibilidad.

      Se trata de una llamada lejana (FAR-CALL) al distribuidor de funciones
      del DOS. Este distribuidor de funciones es una rutina que ejecuta una
      de las funciones(*) de la INT 21H. La funcin a ejecutar en este caso se
      indica mediante el registro CL, y no AH (como es costumbre).

      (*)Mediante este tipo de llamadas slo se puede acceder a las funciones
      numeradas de la 00h a la 24h. Es decir, CL slo debe contener un nmero
      comprendido entre el 00h y el 24h al realizar este tipo de llamadas
      a la INT 21H.


      * Offset 000AH *
      En estos 4 bytes se almacena el contenido del vector de interrupcin 22h,
      es decir, la direccin donde comienza la rutina de atencin a la INT 22H.
      De esta manera, aunque durante la ejecucin del programa se modifique
      el valor de este vector de interrupcin, este campo (000AH) sirve para
      resguardar el valor original.

      El vector INT 22h contiene la direccin de la rutina que recibe el control
      cuando se finaliza el programa mediante uno de los siguientes mtodos:
      - INT 20H
      - INT 27H
      - INT 21H (funciones 00H, 31H, 4CH)


      * Offset 000EH *
      En estos 4 bytes se almacena el contenido del vector de interrupcin 23h,
      es decir, la direccin donde comienza la rutina de atencin a la INT 23H.
      La INT 23h se ejecuta cada vez que el DOS detecta la pulsacin de la
      combinacin de teclas CTRL+C, y provoca la interrupcin del programa
      en curso.

      Si la variable de sistema BREAK est con valor OFF (BREAK=OFF), la
      deteccin de CTRL+C slo se produce en las funciones de Entrada/Salida
      de caracteres.
      Si (BREAK=ON), adems de en dichas funciones de E/S, se comprobar la
      pulsacin de CTRL+C en la mayora de las restantes funciones del DOS.

      En muchos programas se deshabilita el efecto de la INT 23H (CTRL+C) para
      que el usuario no pueda interrumpir dicho programa.
      Mediante el campo 000EH, el DOS se asegura que al salir del programa en
      curso se mantenga el antiguo valor del vector INT 23H.


      * Offset 0012H *
      En estos 4 bytes se almacena el contenido del vector de interrupcin 24h,
      es decir, la direccin donde comienza la rutina de atencin a la INT 24H.
      La INT 24h contiene la direccin del Gestor de Errores Crticos.
      El Gestor de Errores Crticos recibe el control (mediante la INT 24H)
      cada vez que se produce un Error Crtico.
      Ejemplos de errores crticos son:
      - Intentar escribir en una disquetera vaca (sin disquete),
      - Intentar escribir en un disquete protegido contra escritura,
      - Error de CRC (Cdigo de Redundancia Cclica) en los datos
        leidos/escritos.
      - Que la impresora se quede sin papel cuando se le manda imprimir,
      - etc.

      (Cuando estudiemos Programacin de Residentes, trataremos en profundidad
      esta INT 24h, la cual nos ser muy til y necesaria).


      * Offset 002CH *
      En este campo se almacena la direccin de inicio del segmento de memoria
      que contiene el Bloque de Entorno.
      (Ver el apartado - Bloque de Entorno - para ms informacin).


      * Offset 005CH *
      Este campo contiene al primer Bloque de Control de Fichero (FCB) por
      defecto. Este FCB est compuesto por varios campos:
      - Unos que ofrecen variada informacin acerca de un determinado fichero,
      - Y los restantes que se utilizan para el Control del Fichero.

      El mtodo de acceso a ficheros mediante FCB dej de utilizarse a partir
      de la versin 2.0 del MS-DOS, en favor del mtodo Handle (mucho ms
      cmodo y verstil).
      Todas las funciones de manejo de ficheros que vimos en la leccin 10
      se basan en el mtodo Handle. No merece la pena (al menos en un principio)
      siquiera enumerar las funciones FCB.

      Si se sigue incluyendo soporte FCB en el DOS es simplemente por motivos
      de compatibilidad con programas antiguos.
      Veamos la estructura de un FCB (por curiosidad):

      0000H +----------------------------+
             Identificador de la Unidad  (1 Byte)
             (A, B, C, etc)             
      0001H +----------------------------
                 Nombre del fichero      (8 Bytes)
      0009H +----------------------------
                Extensin del fichero    (3 Bytes)
      000CH +----------------------------
                 Nmero de este FCB      (2 Bytes)
      000EH +----------------------------
                 Tamao de Registro      (2 Bytes)
      0010H +----------------------------
                 Tamao de Fichero       (4 Bytes)
      0014H +----------------------------
             Fecha de Creacin o         (2 Bytes)
             Actualizacin del Fichero  
      0016H +----------------------------
             Hora de Creacin o          (2 Bytes)
             Actualizacin del Fichero  
      0018H +----------------------------
                   (Reservado)           (8 Bytes)
      0020H +----------------------------
              Nmero de Registro Actual  (1 Byte)
      0021H +----------------------------
             Nmero de Registro Relativo (4 Bytes)
            +----------------------------+

            Todos los campos donde aparece la palabra 'Registro' se emplean
            para leer/escribir de forma aleatoria (no secuencial) en el fichero.

            En el mtodo Handle (el que se utiliza a partir de la v 2.0 del
            MS-DOS) se emplea la funcin 42h de la INT 21h para desplazarse
            por el fichero, y luego las funciones de lectura/escritura con el
            tamao de bloque (Registro en FCB) a leer/escribir.


      * Offset 006CH *
      Este campo contiene al segundo Bloque de Control de Fichero (FCB) por
      defecto.
      (Lo indicado para el campo anterior es aplicable a ste).


      * Offset 0080H *
      Este campo cumple dos cometidos:
      - Almacena la Cola de Ordenes que el usuario le ha pasado al programa.
      - Sirve como buffer de fichero por defecto (DTA por defecto).

      El problema es que los 128 bytes de este campo no se reparten entre la
      Cola de Ordenes y el DTA por defecto, sino que ambas informaciones se
      solapan.  Ambas estructuras de datos usan estos 128 bytes por separado:

      Este campo contendr el contenido de la Cola de Ordenes hasta que se
      produzca la primera transferencia de datos a/desde un fichero (usando
      el mtodo FCB). Es decir, en primer lugar este campo almacena la Cola de
      Ordenes. El programador lo que debe hacer es salvar el contenido de este
      campo (Cola de Ordenes) a la zona de datos del programa antes de realizar
      el primer acceso a ficheros mediante el mtodo FCB.
      De esto se desprende que este campo es provisional para almacenar la
      Cola de Ordenes, quedando destinado a realizar las veces de buffer de
      fichero por defecto (DTA por defecto).

      Teniendo en cuenta que las funciones FCB han quedado obsoletas y no
      se deben utilizar salvo casos excepcionales, el problema de solapamiento
      expuesto no se debe tener en cuenta, ya que al no ser invocada ninguna
      funcin FCB, la Cola de Ordenes no ser 'machacada'.

      De cualquier manera (y sobre todo, para los casos en que se utilice alguna
      funcin FCB) suele ser una buena prctica salvar la Cola de Ordenes a un
      'lugar seguro' dentro de la zona de datos del programa.

      (Vase el apartado dedicado a la Cola de Ordenes).





      - Bloque de Entorno (Environment Block)
      ---------------------------------------
        El Bloque de Entorno es una zona de memoria que cumple dos cometidos
        bien diferenciados.
        Por una parte, almacena las distintas Variables de Entorno, as como
        el valor de dichas variables.
        Por otra parte, ofrece una cadena ASCIIZ con la va de acceso al
        programa dueo de este Bloque de Entorno.

        Las Variables de Entorno se sitan al principio del Bloque de Entorno,
        separadas unas de otras por el byte 00h.
        Al final de la ltima Variable de Entorno se sitan dos bytes con
        valor 00h que indican el fin de las Variables de Entorno y el comienzo
        del nombre de programa.

        A continuacin de los dos bytes con valor 00h que indican el final
        de las Variables de Entorno, nos encontramos con otros dos bytes antes
        de poder acceder al nombre del programa.
        Estos dos bytes (1 palabra) contendrn el valor 0001h si el programa
        no se trata del COMMAND.COM, por tanto para acceder al nombre del
        programa, simplemente tenemos que buscar el valor 01h desde el
        principio del Bloque de Entorno.


        Vamos a tratar el tema desde un punto de vista prctico. Lo que
        aparece a continuacin es el contenido del Bloque de Entorno de un
        programa de prueba que he hecho para tal efecto.

        ;***Ejemplo de Bloque de Entorno.

        COMSPEC=C:\DOS\COMMAND.COM PATH=C:\;C:\WINDOWS;C:\UTIL;
        C:\DOS;C:\SANBIT60;C:\RATON;C:\ENSAMBLA;C:\SCAN PROMPT=
        $P$G TEMP=C:\WINDOWS\TEMP CLIPPER=f:50   C:\CURSOASM\BE.COM 

        ;***Fin del Ejemplo de Bloque de Entorno.

        En el bloque de Entorno pasado al programa de prueba (BE.COM) podemos
        ver en primer lugar la cadena de variables de Entorno con sus
        respectivos valores.

             1.- COMSPEC=C:\DOS\COMMAND.COM
             2.- PATH=C:\;C:\WINDOWS;C:\UTIL;C:\DOS;C:\SANBIT60;
                 C:\RATON;C:\ENSAMBLA;C:\SCAN
             3.- PROMPT=$P$G
             4.- TEMP=C:\WINDOWS\TEMP
             5.- CLIPPER=f:50

        Las tres primeras variables son variables de Sistema.
        La primera de ellas COMSPEC indica la va de acceso al COMMAND.COM
        o cualquier otro Intrprete de Comandos que indiquemos, como
        por ejemplo el 4DOS.
        La segunda y tercera variable son de sobra conocidas por todos, no?

        Las variables 4 y 5 se definen mediante la orden SET dentro del
        AUTOEXEC.BAT.
        Mediante esta orden SET podemos crear variables de Entorno a nuestro
        gusto. Es otra forma de indicarle una determinada configuracin a un
        programa.

        Por ejemplo: Hemos creado un programa llamado HEXA.COM, el cual puede
        ejecutarse en idioma Ingls o Espaol.
        Adems, el programa necesita un buffer de disco para su trabajo.
        Este buffer tendr una longitud a gusto del usuario.
        Pues bien, hay varias maneras de hacerle llegar toda esta informacin
        al programa. Principalmente, podemos:

        - Utilizar la Cola de Ordenes para pasarle los parmetros oportunos
          al programa. Esta sera la opcin ms cmoda y 'Elegante'.

        - Utilizar un fichero de configuracin desde donde el programa
          tomara esta informacin. Esta opcin se suele utilizar cuando
          hay demasiados parmetros a tener en cuenta en el programa.
          Como por ejemplo: Tarjeta grfica utilizada, Utilizacin o no del
          ratn, Utilizacin o no de Joystick, datos personales del usuario,
          etc.. En programas que requieren de tantos datos, es imprescindible
          la utilizacin de un fichero de configuracin.

        - Finalmente, podemos hacerle llegar los parmetros a travs de una
          variable de Entorno. Esto lo haramos incluyendo una orden SET dentro
          del AUTOEXEC.BAT con el formato:
          SET VARIABLE_ENTORNO=CONTENIDO_DE_LA_VARIABLE.
          En el ejemplo que estamos tratando (HEXA.COM), la orden SET quedara
          de la forma: SET HEXA=ESP;64
          Dicha orden indicara que va a haber una nueva variable de entorno
          que se va a llamar HEXA, cuyo contenido son dos informaciones
          separadas por el carcter (;). La primera informacin indica el
          idioma (ESP). La segunda informacin indica que el usuario quiere
          un buffer de 64 Ks.

          La ventaja que tiene utilizar una variable de Entorno para pasar
          informacin a los programas es que esa informacin va a ser
          accesible por cualquier programa que lo desee. De esta forma si
          tenemos una aplicacin con varios programas que necesitan de una
          informacin para su buen funcionamiento, sta sera una buena
          opcin. No lo es tanto crear una variable de entorno para ser
          utilizada por un slo programa. Por tanto, en el ejemplo del
          programa HEXA.COM la opcin de la Variable de Entorno no sera
          la ms acertada. Pero bueno, ah est la informacin, y que cada
          uno la utilice a su gusto.


       Volvamos a generalizar...
       Cada una de las variables de Entorno se separa de las contiguas por
       medio de un byte separador con valor 00h. En el ejemplo puede parecer
       que ese byte separador sea un simple carcter de espacio, pero no es
       as, lo que ocurre es que el cdigo 00h se representa en pantalla como
       un carcter en blanco, al igual que ocurre con el cdigo 32 (Espacio).
       Bueno, ya que estamos... :-)  Hay un tercer carcter que se representa
       en pantalla como blanco: el cdigo 255.

       Un viejo truco para crear directorios 'Ocultos' consiste en
       insertar cdigos 255 en el nombre de directorio. As, un usario
       ajeno a nuestro sistema, creer que estos caracteres son blancos y no
       conseguir introducir correctamente el nombre de directorio.

       Era gracioso ver cmo los profesores intentaban entrar en directorios
       sin poder conseguirlo. Ponan cada cara... :-)))

       Bien... El grupo de variables de Entorno se cierra con dos bytes
       con valor 00h.
       Tras estos dos bytes nos encontramos con una palabra con valor 0001h.
       Al tratarse de una palabra, se almacena en memoria de la forma
       0100h. Ya vimos en lecciones anteriores el porqu de esta peculiar
       manera de almacenar las palabras en memoria.

       Si echamos un vistazo al bloque de Entorno del ejemplo, veremos el
       monigote sonriente (cdigo 01h), luego un carcter en blanco, que es
       en realidad un cdigo 00h. Y a partir de ah tenemos la cadena ASCIIZ
       con la va de acceso al nombre del programa. En este caso, tal cadena
       es C:\CURSOASM\BE.COM


       A continuacin se ampla informacin prctica relacionada con el
       Bloque de Entorno mediante dos programas ampliamente comentados.
       Estos dos programas son en realidad uno slo escrito dos veces,
       una vez en formato de programa COM; y otra vez escrito en formato EXE.
       Sirvan estas dos versiones para ver diferencias y similitudes entre
       la forma de crear programas COM y programas EXE.



      - Cola de Ordenes
      -----------------
       Como hemos visto a lo largo de las referencias que hemos hecho a la
       Cola de Ordenes en el resto de la leccin, dicha estructura de datos
       no es ms que el conjunto de parmetros que se le pasan al programa
       al ejecutarlo.
       Pues bien, lo dicho anteriormente hay que ampliarlo:

       Cuando el DOS le pasa los parmetros al programa a travs del
       Offset 80h del PSP, no slo le pasa todos y cada uno de los parmetros
       tal y como los ha introducido el usuario a continuacin del nombre
       del programa, sino que incluye un byte que precede a toda la cadena
       de parmetros, el cual indica el tamao (en bytes) de dicha cadena
       de parmetros.

       Es decir, en el Offset 80h del PSP encontramos un byte que nos indica
       el tamao de la cadena de parmetros que vamos a encontrar a
       continuacin, a partir del Offset 81h.

       Luego la Cola de Ordenes est formada por un byte contador, en el
       Offset 80h; y la cadena de parmetros que ha introducido el usuario,
       a partir del Offset 81h.


       Retomemos el ejemplo del programa HEXA.COM...
       Lo queramos ejecutar en Espaol (Castellano para los lingistas :-)
       y con un buffer de 64 Ks.
       Ya habamos visto cmo se le poda pasar esta informacin (parmetros)
       al programa mediante una Variable de Entorno. Ahora veremos cmo se
       hace mediante parmetros en la lnea de Comandos (COMMAND.COM), que
       es lo normal:

       HEXA ESP;64

       La lnea anterior ejecuta el programa HEXA con dos parmetros separados
       por el smbolo ';'.
       En realidad, slo el usuario y el programa saben que se trata de dos
       parmetros separados por tal smbolo, ya que el DOS slo reconoce una
       cadena de parmetros de 7 bytes de longitud ' ESP;64'.
       Es decir, el DOS no reconoce varios parmetros independientes, sino una
       cadena de parmetros, por tanto los smbolos de separacin como ';',
       '/', etc... forman parte de la sintaxis que imponga el programa en s.
       Para el DOS cada uno de estos smbolos son simplemente un byte ms en
       la cadena de parmetros.

       Una vez ejecutado el programa HEXA con los parmetros anteriores, el
       campo 80h del PSP contendra la Cola de Ordenes tal como sigue:

        ESP;64

       Podemos ver en primer lugar el smbolo ''. Este smbolo tiene el cdigo
       ASCII 07h. Esto quiere decir que la cadena de parmetros que vamos
       a encontrar a continuacin (Offset 81h) tiene una longitud de 7 bytes.

       A continuacin del byte contador '' encontramos la cadena de parmetros
       introducidos por el usuario: ' ESP;64'.

       Podemos observar que el espacio que separa el nombre del programa de la
       cadena de parmetros se considera parte de la cadena de parmetros.
       En definitiva, cualquier carcter que se introduzca a continuacin del
       nombre del programa se considera parmetro.
       Esto no parece que tenga mucho sentido en un principio, ya que si
       despus del nombre del programa introducimos un carcter distinto de
       espacio, este nombre de programa cambia, ya no es el mismo, por tanto
       no estamos ejecutando el mismo programa.
       Es decir, si despus del nombre de programa HEXA introducimos un carcter
       distinto de espacio (por ejemplo, el carcter 'C'), ya no estamos
       intentando ejecutar el programa HEXA, sino el programa HEXAC.
       Por tanto, el nico carcter que en un principio debera introducirse
       a continuacin del nombre del programa sera el espacio.
       Siendo esto as, no se debera considerar parte de la cadena de
       parmetros, ya que sera informacin intil. Mejor dicho, no sera
       informacin, ya que de antemano sabramos que el primer carcter iba
       a ser un espacio en blanco...

       Como deca, esto no parece tener mucho sentido si no fuera porque hay
       ciertos caracteres especiales como '/' que el DOS acepta que se escriban
       justo a continuacin del nombre del programa, y se consideran inicio de
       la cadena de parmetros
       De tal forma que HEXA/ESP;64 ejecuta el programa HEXA con el siguiente
       valor en la Cola de Ordenes (Offset 80h): '/ESP;64'



      - Pseudo_Instrucciones
      ----------------------
      Pseudo_Instrucciones son aquellas instrucciones que aparecen en el
      cdigo fuente del programa y no generan cdigo ejecutable alguno.
      Tienen como misin ofrecer cierta informacin al ensamblador necesaria
      durante el proceso de ensamblaje.
      Vamos a enumerar y estudiar las ms comunes:

---   Pseudo_Instrucciones de cara al listado del cdigo fuente (PAGE y TITLE):
      Se utilizan para indicar el formato del listado del cdigo fuente,
      en caso de que se solicite.

      PAGE: La pseudo_instruccin PAGE le indica al ensamblador el nmero de
            lneas que tendr cada pgina del listado, as como el nmero de
            columnas de que constar cada lnea.
            Sintaxis: PAGE X,Y
                      Donde X es el nmero de lneas por pgina.
                            Y es el nmero de caracteres por lnea.

            Los valores por defecto para PAGE son X=60, Y=132.
            O sea: PAGE 60,132

     TITLE: Mediante esta pseudo_instruccin ofrecemos un 'ttulo' o nombre
            de programa que ser utilizado como cabecera de pgina en caso
            de que solicite un listado del cdigo fuente.
            Podemos utilizar cualquier texto que queramos, pero lo recomendable
            es utilizar el nombre del programa en cuestin, y a continuacin
            (si lo deseamos) un comentario acerca del programa. Es decir, si
            nuestro programa se llama CAPTU y se trata de un capturador de
            pantallas, utilizaremos la pseudo_instruccin:
            TITLE CAPTU_Capturador de pantallas.

            Disponemos de 60 caracteres de longitud para indicar el nombre
            del programa y cualquier comentario adicional.

            Sintaxis: TITLE *Texto*
            Donde *Texto* es una cadena de 60 caracteres como mximo, que
            por regla general constar del nombre del programa en primer
            lugar, y adicionalmente (si se desea), un comentario acerca del
            programa.


---   Pseudo_Instrucciones de definicin de segmentos (SEGMENT y ENDS):
      Mediante estas dos pseudo_instrucciones definimos el principio y
      final de cada uno de los diferentes segmentos de nuestro programa:

      - Segmento de cdigo (siempre debemos definirlo, ya trabajemos con
        programas COM o programas EXE).
        Si estamos desarrollando un programa COM, ste ser el nico
        segmento que debamos definir, ya que los restantes segmentos
        (Datos, Pila y Extra) coincidirn con el segmento de cdigo, al
        disponer slo de un segmento de tamao para todo el programa.

      - Si estamos construyendo un programa EXE, debemos definir tambin
        otro de los 3 segmentos restantes: el Segmento de Pila.
        El Segmento de Datos tambin ser imprescindible definirlo, a no ser
        que estemos construyendo un programa en el que no utilicemos variables
        propias. En cuyo caso no es necesario definir el Segmento de Datos,
        ya que no tenemos datos que incluir en l.

        El segmento Extra no se suele definir, ya que normalmente se utiliza
        para acceder a variables y estructuras de datos ajenas al programa, de
        forma que su direccin de inicio se actualiza durante la ejecucin
        del programa, segn ste lo vaya requiriendo.
        Como deca, no se suele definir, pero podemos hacerlo. Podemos
        definir un segmento de datos Extra y asignrselo al registro ES.
        De esta forma podemos tener dos segmentos de datos en nuestro
        programa: Uno direccionado mediante DS y el otro (el Extra) direccionado
        mediante ES.

        En realidad podemos tener incluso cientos de segmentos de datos en
        nuestro programa. Para acceder a cada uno de ellos utilizaremos
        la pseudo_instruccin ASSUME que veremos ms adelante.

     +------------------------------------------------------------------------+
                                                                             
      Nota: Al hablar de segmentos en esta ocasin, no me estoy refiriendo   
            a 64 ks de memoria, sino a una porcin de memoria de un tamao   
            que puede ir de pocos bytes a 64 ks.                             
            En realidad no estamos hablando de segmentos propiamente dichos, 
            sino de porciones de segmento, a las que tratamos como           
            segmentos.  El segmento de datos (por ejemplo) no tiene por qu  
            tener un tamao de 64 ks. En realidad nos dar igual su tamao   
            a la hora de acceder a l. Slo nos es necesario saber su        
            comienzo (De eso se encarga el registro DS) y conocer la         
            direccin dentro de ese segmento de la variable a la que queremos
            acceder (basta con indicar el nombre de la variable para que     
            el ensamblador genere su direccin real durante el proceso de    
            ensamblado-linkado).                                             
                                                                             
     +------------------------------------------------------------------------+


      Cada uno de los segmentos se definen segn el siguiente formato:

      +-----------------------------------+
                                         
        Nombre_seg  SEGMENT  [Opciones]  
                                         
                      .                  
                      .                  
                      .                  
                                         
        Nombre_seg  ENDS                 
                                         
      +-----------------------------------+

      Nombre_seg es el nombre con el que vamos a referirnos al Segmento.
      Como vemos en el modelo, dicho nombre de segmento debe utilizarse
      como encabezamiento y final del segmento.
      Para indicar el inicio de segmento se utiliza la pseudo_instruccin
      SEGMENT, de la forma Nombre_seg SEGMENT [Opciones].
      Para sealar el final del segmento utilizamos la pseudo_instruccin
      ENDS, de la forma Nombre_seg ENDS.

      Mediante [Opciones] se engloban 3 tipos de informaciones adicionales que
      se le pueden pasar al ensamblador al realizar la definicin de segmentos.
      Veamos cada uno de estos tipos:

      - Tipo Alineamiento (Alignment type)
        Mediante esta opcin le indicamos al ensamblador el mtodo que debe
        emplear para situar el principio del segmento en la memoria.
        Hay cuatro mtodos posibles:

           PARA (La direccin de inicio del segmento ser mltiplo de 16.
                 Este es el valor por omisin.
                 Recordemos que un prrafo es igual a 16 bytes, y que la
                 direccin de inicio de un segmento se suele referenciar
                 mediante un nmero de prrafo, ya que se da por supuesto
                 que esta direccin de inicio ser mltiplo de 16).

           BYTE (Se tomar el primer byte libre como direccin de inicio del
                 segmento).

           WORD (La direccin de inicio del segmento ser mltiplo de 2).

           PAGE (La direccin de inicio del segmento ser mltiplo de 256).


      - Tipo Combinacin (Combine type)
        Esta opcin indica si se combinar el segmento que estamos definiendo
        con otro y otros durante el 'linkado'.
        Los valores posibles para esta opcin son:
          STACK, COMMON, PUBLIC, AT expresin, MEMORY.

        El valor STACK lo vamos a utilizar siempre que definamos el segmento
        de Pila.

        Los siguientes valores se utilizan cuando se van a 'linkar' (fusionar)
        diferentes programas en uno slo. En estos casos ser necesario
        utilizar los valores COMMON, PUBLIC, etc.. a la hora de compartir
        variables, procedimientos, etc.

      - Tipo Clase (Class type)
        La opcin Clase se indica encerrando entre apstrofes (comillas simples)
        una entrada. Mediante esta entrada se pueden agrupar diferentes
        segmentos durante el proceso de 'linkado'.


---   Pseudo_Instruccin ASSUME:
      Mediante esta pseudo_operacin relacionamos cada uno de los segmentos
      definidos con su correspondiente registro de segmento.
      As, al segmento de datos le asignaremos el registro DS;
      Al segmento de cdigo le asignaremos el registro CS;
      Al segmento de pila le asignaremos el registro SS;
      Aunque no es normal asignar inicialmente un segmento al registro ES,
      cabe la posibilidad de hacerlo por diversas razones:
      - Que queramos tenerlo apuntando a alguno de los tres segmentos
        principales: cdigo, datos o pila.
      - Que hayamos definido un cuarto segmento y queramos direccionarlo
        mediante el registro ES.
      - Cualquier otra razn no incluida en las dos anteriores.

      En caso de no asignar un segmento a un registro de segmento, caben dos
      posibilidades:
      - Se omite la referencia a dicho registro de segmento.
      - Se utiliza la partcula NOTHING para indicar que dicho segmento no
        ha sido asignado a ningn segmento.

    +-----------------------------------------------------------------------+
                                                                           
     Pongamos un caso prctico:                                            
     Definimos 3 segmentos: Uno de datos llamado DatoSeg; otro de pila     
     llamado PilaSeg y otro de cdigo llamado CodeSeg.                     
     Tras la definicin de estos segmentos debemos asignarles el registro  
     de segmento correspondiente de una de las siguientes formas:          
                                                                           
     - ASSUME CS:CodeSeg, DS:DatoSeg, SS:PilaSeg                           
                                                                           
     - ASSUME CS:CodeSeg, DS:DatoSeg, SS:PilaSeg, ES:NOTHING               
                                                                           
    +-----------------------------------------------------------------------+


     Una vez ms recalcar que ASSUME es una pseudo_operacin, no genera cdigo
     ejecutable. Su funcin es slo la de ofrecer informacin al lenguaje
     ensamblador.

     Por tanto ASSUME debe utilizarse en combinacin del par de instrucciones
     que aparecen enmarcadas ms abajo.
     En el ejemplo anterior, una vez que empezara el cdigo del programa
     deberamos incluir el siguiente par de instrucciones para que en realidad
     DS apuntara al segmento de datos que hemos indicado:

    +-----------------------+
                           
       MOV AX,DatoSeg      
       MOV DS,AX           
                           
    +-----------------------+

    No es necesario hacer lo mismo con CS ni SS, ya que el DOS lo hace
    por s slo al ejecutar el programa. Es decir, debe preparar CS para que
    apunte al segmento de cdigo, sino no se ejecutara el programa. Y debe
    preparar tambin los registros de pila.

    En realidad el DOS prepara tambin los registros DS y ES para que apunten
    al PSP.
    Por tanto si queremos que DS apunte a nuestro segmento de datos tendremos
    que indicarlo como hemos visto arriba.

    El ejemplo anterior pertenece a un programa EXE. Si fuera COM no hara falta
    definir segmento de pila, ya que el DOS sita la pila al final del segmento
    donde se carga el programa.

    Tampoco deberamos haber utilizado las dos instrucciones de arriba para
    asignar a DS su segmento, ya que al disponer slo de un segmento para
    nuestro programa COM, todos los registros de segmento (CS, DS, ES y SS)
    apuntan al principio del segmento donde se carga el programa.




    Pongamos ahora que tenemos dos segmentos de datos, uno llamado Dato_1_Seg y
    otro llamado Dato_2_Seg.
    En un principio queremos que DS apunte a Dato_1_Seg.
    Esto lo hacemos mediante la pseudo_instruccin ASSUME y luego el par
    de instrucciones que hemos visto antes:


        ASSUME DS:Dato_1_Seg

        MOV AX,SEG Dato_1_Seg
        MOV DS,AX


    Tenemos ya los datos incluidos en el segmento Dato_1_Seg direccionables
    mediante DS. Pero en un procedimiento dado de nuestro programa debemos
    acceder a unas variables incluidas en el segundo segmento de datos:
    Dato_2_Seg. Debemos entonces hacer que DS apunte a este otro segmento
    de datos. En este caso, ya no debemos utilizar la Pseudo_instruccin
    ASSUME, ya que causara error al Linkar. Simplemente debemos utilizar
    el par de instrucciones MOV tal como sigue:

        MOV AX,SEG Dato_2_Seg
        MOV DS,AX


    Si pasado un tiempo (unas instrucciones, mejor dicho :-) queremos que DS
    apunte a Dato_1_Seg...
    ... ya sabemos cmo hacerlo, no?


    En caso de que tuviramos ms segmentos de datos (3, 6, incluso 100)
    para acceder a cada uno de esos segmentos de datos, simplemente debemos
    emplear el par de instrucciones MOV para que DS apunte al nuevo segmento.
    Es un poco pesado y lioso, pero as es el tema de los registros.



---   Pseudo_Instrucciones de definicin de Procedimientos (PROC y ENDP):
      Mediante estas dos pseudo_instrucciones definimos el principio y
      final de cada uno de los diferentes procedimientos de que disponga
      nuestro programa.

      Ya vimos en lecciones anteriores cmo se definan los procedimientos,
      cmo se llamaban, etc. As que no insistiremos ms en este punto.
      Slo decir que la pseudo_instruccin PROC le indica al ensamblador
      que a continuacin comienza un procedimiento; y que la pseudo_instruccin
      ENDP le indica que ha finalizado el procedimiento. Slo informan al
      ensamblador, no generan cdigo ejecutable.
      Tomemos el siguiente modelo de procedimiento.
      As como est, sin ms cdigo dentro que el RET, slo generar el cdigo
      ejecutable C3H (RET).

      Nombre_Proc PROC
             .
             .
             .

            RET
      Nombre_Proc ENDP



---   Pseudo_Instruccin END:
      La pseudo_instruccin END se utiliza para indicarle al ensamblador donde
      acaba nuestro programa, de la misma forma que ENDS le indica donde acaba
      un segmento y ENDP le indica donde acaba un procedimiento.

      Sintaxis: END NombreProg
      Donde NombreProg es el nombre del procedimiento principal de nuestro
      programa si hemos definido un procedimiento principal;  es el nombre
      de la etiqueta que marca el inicio de nuestro programa.
      (Ver los modelos de programas COM y EXE).



---   Pseudo_Instruccin ORG:
      (Tratada en el apartado de programas COM de esta misma leccin)



---   Pseudo_Instrucciones de definicin de datos:
      Nos valdremos de estas pseudo_instrucciones para definir todas las
      variables y constantes propias de nuestro programa.

      * Definicin de variables *
        Para definir variables utilizaremos la inicial de la palabra Define (D),
        seguida de la inicial del tipo de dato que queramos definir:
        B(Byte), W(Word), D(Double_Word  Doble palabra), Q(Cuadruple palabra),
        T(Diez bytes).

        Tenemos entonces que:
        Para definir un BYTE utilizamos la pseudo_instruccin               DB.
        Para definir una PALABRA utilizamos la pseudo_instruccin           DW.
        Para definir una DOBLE_PALABRA utilizamos la pseudo_instruccin     DD.
        Para definir una CUADRUPLE_PALABRA utilizamos la pseudo_instruccin DQ.
        Para definir una VARIABLE_DE_10_BYTES_DE_TAMAO utilizamos la
                                                         pseudo_instruccin DT.


        Hemos visto cmo definir el tipo de dato de nuestra variable.
        Veamos ahora cmo le ponemos el nombre a cada variable.
        En caso de ponerle nombre a la variable (lo ms normal, aunque no es
        obligatorio), dicho nombre estara a la izquierda de la definicin del
        tipo de dato. Es decir: Nombre_Variable Dx
        Donde 'x' es el tipo de dato de la variable (B, W, etc..).
        As, si queremos definir una variable llamada CONTADOR de tamao Byte,
        lo haremos de la siguiente forma: CONTADOR DB


        Hasta aqu sabemos ya cmo ponerle nombre a una variable, y sabemos
        indicar el tipo de dato de que se trata, vamos a ver ahora cmo podemos
        asignarle un valor inicial a esa variable.

        Es obligatorio darle algn valor a la variable que estemos definiendo.
        No podemos decir simplemente el tipo de dato de que se trata, tenemos
        que darle un valor inicial. Por tanto el ejemplo de arriba habra que
        completarlo dndole un valor a la variable CONTADOR.
        An en el caso en que no nos importe el valor que tenga la variable
        en un principio, tendremos que indicrselo al ensamblador mediante el
        smbolo (?).

        Retomamos entonces el ejemplo anterior, y vamos a darle a la variable
        CONTADOR un valor inicial de 210.
        Quedara as la definicin de la variable: CONTADOR DB 210

        En el caso de que nos sea indiferente el valor inicial de la variable,
        lo indicaremos de la siguiente manera: CONTADOR DB ?

        En mi caso concreto, yo nunca uso el smbolo (?). En los casos en que
        defino variables cuyo valor inicial me es indiferente, les doy siempre
        valor 0. Es decir, yo habra definido la variable CONTADOR de la
        siguiente manera: CONTADOR DB 0

        Veamos por ejemplo qu tipo de dato utilizaramos para almacenar el
        valor numrico 237654 (base 10) en una variable llamada ACUMULADOR.
        Este valor es demasiado grande para que quepa en un byte (valor mximo=
        255), tambin es demasiado grande para el tipo Word  palabra (valor
        mximo=65535), sin embargo en el tipo DobleWord  Doble_Palabra s que
        cabe perfectamente. O sea que la definicin (ACUMULADOR DD 237654) sera
        correcta, mientras que las definiciones (ACUMULADOR DB 237654) y
        (ACUMULADOR DW 237654) son errneas.

        Bien, hasta aqu ya sabemos cmo definir variables simples, vamos a ver
        ahora cmo definir variables compuestas (cadenas de caracteres,
        vectores, tablas, etc).

        Mediante una sla definicin de variable podemos crear varios elementos
        del mismo tipo de dato, consiguiendo as un vector o tabla de elementos.
        En definitiva, una cadena de caracteres es una tabla de una dimensin
         vector de elementos de tipo byte  caracter.

        Veamos en primer lugar la sintaxis completa para la definicin de datos:

           [Nombre_Variable] Dx Expresin

        Nombre_Variable es el nombre de la variable que estamos definiendo.
        Los corchetes indican que es optativo dicho nombre. Si no queremos
        ponerle nombre a una variable no se lo ponemos, como ya hemos dicho
        antes.

        A continuacin aparece la Pseudo_instruccin Dx para la definicin del
        tipo de dato, donde x indica el tipo de dato como ya hemos visto.

        Y vamos a lo que queda:
        Expresin: Mediante Expresin englobamos el dato  cadena de datos
        (vector  tabla) asignado/a a una variable.

        Expresin puede ser un slo valor, por ejemplo 2367 (VAR DW 2367);
        Puede ser el smbolo (?) si el valor inicial del dato nos es
        indiferente (VAR DW ?);

        Y puede ser, por otra parte, una cadena de caracteres  una tabla de
        valores numricos o alfanumricos, la cual se puede definir de varias
        formas:

        - Encerrar entre comillas la cadena de caracteres (si se trata de
          datos alfanumricos):
          VAR DB 'Esto es un ejemplo'
          Obsrvese que el tipo de datos es BYTE (DB), ya que estamos definiendo
          elementos del tipo BYTE (caracteres).
          Tenemos una cadena de caracteres  tabla de una dimensin llamada VAR
          de 18 elementos (la longitud total de la cadena 'Esto es un ejemplo').
          Para acceder a cada uno de los elementos de la tabla tendremos que
          utilizar un ndice a continuacin del nombre de la tabla.

          Nota: En ensamblador el primer elemento de una tabla  cadena de
                caracteres es el elemento 0.



          Veamos unos ejemplos:
          + Deseamos introducir en el registro AL el primer elemento de
            la tabla.

            MOV AL,VAR
            Mediante esta simple instruccin se introduce el primer elemento
            de la cadena de caracteres en el registro AL, quedando AL = 'E',
            o lo que es lo mismo AL = 69.
            Como podemos ver, para el primer elemento no es necesario utilizar
            un ndice, ya que en caso de omisin del mismo, el ensamblador
            entiende que se quiere acceder al primer elemento (elemento 0)
            de la tabla.
            La instruccin de arriba sera equivalente a MOV AL,VAR+0

          + En este segundo ejemplo queremos introducir en AL el tercer
            elemento de la cadena de caracteres.

            MOV AL,VAR+2
            Tras esta instruccin, AL quedara con el valor que tuviera el
            tercer elemento de la tabla, dicho valor es 't', luego AL='t'.


          Nota: El ensamblador reconoce el inicio de una tabla, pero nunca
                su final. Es decir, que si intentamos acceder al elemento
                nmero 300 de una tabla  cadena de caracteres que slo
                tiene 20 elementos, el ensamblador asume que esa tabla
                tiene por lo menos esos 300 elementos y accede a ese elemento
                300, que por supuesto no pertenece a la tabla.

                Veamos un ejemplo:
                Tenemos en nuestro segmento de datos las siguientes cadenas
                de caracteres:

                ;****
                   VAR DB 'Esto es un ejemplo'
              FILENAME DB 'C:\CURSOASM\MODECOM.ASM'
                ;****

                Como podemos ver tenemos dos cadenas de caracteres  tablas de
                una dimensin. La primera, llamada VAR, de 18 elementos.
                La segunda, llamada FILENAME, de 23 elementos.

                En nuestro segmento de cdigo nos encontramos con la siguiente
                instruccin:

                              MOV AL,VAR+33

                En principio, esta instruccin parece errnea, ya que la cadena
                VAR tiene slo 18 elementos, pero como deca antes, al
                ensamblador eso no le importa. Es el programador el que
                tiene que preocuparse de utilizar los ndices correctos.
                Por lo tanto, tras la ejecucin de esa instruccin, AL = 'D'.



        - Separar cada uno de los elementos de la cadena mediante comas:
          (Vlido para datos numricos y alfanumricos).

          As, la cadena del ejemplo anterior  VAR DB 'Esto es un ejemplo'
          quedara de esta forma como:
          VAR DB 69,115,116,111,32,101,115,32,117,110,32,101,106,101,109,112
              DB 108,111

          Como podemos ver, hemos descompuesto la cadena inicial en dos
          cadenas ms pequeas para que cupieran en la pantalla.
          Vemos que a la segunda cadena no le hemos dado nombre. En realidad,
          es parte de la primera cadena, pero es necesario volver a definir
          el tipo de datos para que el ensamblador sepa lo que hay a
          continuacin.
          Una vez que obtenemos el ejecutable, tendremos una tira de bytes
           cadena de caracteres con los valores 'Esto es un ejemplo'.

          Otras formas de definir esta cadena podran ser:

          VAR DB 69,115,116,111
              DB 32,101,115,32
              DB 117,110,32,101,106
              DB 101,109,112
              DB 108,111

          O tambin:

          VAR DB 69,'s',116,'o'
              DB 32,'e','s',32
              DB 117,110,' ',101,'j'
              DB 101,109,112,108,'o'

          Tambin esta otra:

          VAR DB 'Esto e'
              DB 's',' ','un'
              DB 101,'j,101,109,112,108,'o'


          Y as miles de formas de definir la misma cadena.


          Veamos ahora un ejemplo en el que deseamos crear un vector de
          7 elementos numricos con los siguientes valores iniciales:
          278,8176,736,3874,7857,22338,76

          El vector, al que vamos a llamar Tabla_num, lo definiremos de
          la siguiente manera:

          Tabla_num dw 278,8176,736,3874,7857,22338,76

          Al igual que en los ejemplos anteriores, podemos definirlo de
          miles de formas diferentes, como:

          Tabla_num dw 278,8176,736
                    dw 3874,7857,22338,76


          O tambin:

          Tabla_num dw 278
                    dw 8176
                    dw 736
                    dw 3874
                    dw 7857
                    dw 22338
                    dw 76

          Etc...


          Veamos ahora cmo hay que utilizar los ndices en una tabla de
          elementos de tipo Word  palabra.
          Tenemos que tener en cuenta que una palabra equivale a dos bytes,
          luego para acceder al siguiente elemento de la tabla deberemos
          incrementar en 2 unidades el ndice.

          Supongamos que queremos introducir en AX el primer elemento de la
          tabla. Esto se hara con la siguiente instruccin:

                 MOV AX,TABLA_NUM         ;AX=278

          Si ahora queremos introducir el segundo elemento, usaramos esta
          otra instruccin:

                 MOV AX,TABLA_NUM+2       ;AX=8176

          Para introducir el quinto elemento, usaramos esta otra instruccin:

                 MOV AX,TABLA_NUM+8       ;AX=7857

          Etc...



        - Utilizar la partcula DUP para crear repeticiones de un mismo valor
           de un conjunto de valores.
          (Vlido para datos numricos y alfanumricos).

          Mediante esta partcula DUP podremos crear repeticiones de un mismo
          valor de forma cmoda. A la hora de definir tablas o grandes
          estructuras de datos con el mismo valor o valor indefinido, esta
          es la mejor opcin.

          Supongamos que queremos definir un vector de 100 elementos de
          tipo BYTE con valor inicial (para cada uno de estos elementos) 37...
          Si lo hiciramos segn hemos visto antes (elemento por elemento, y
          separando por comas cada uno de los elementos) podramos pasar ms
          tiempo definiendo las variables que creando el programa, adems,
          obtendramos un cdigo fuente demasiado grande debido a la definicin
          poco inteligente de las variables.
          Sin embargo utilizando la partcula DUP la definicin propuesta
          en este supuesto quedara as de sencilla:

               VECTOR DB 100 DUP (37)


          Si nos atenemos a la sintaxis establecida al principio del apartado,
          el campo Expresin estara compuesto en este ejemplo por:
            100 DUP (37)
          Lo cual quiere decir que reserve espacio para 100 datos del tipo
          definido anteriormente (Byte en este caso: DB), cada uno de estos
          datos tendrn el valor inicial 37.

          El equivalente a la definicin VECTOR DB 100 DUP (37), prescindiendo
          del DUP, sera algo as como:

              VECTOR DB 37,37,37,37,37,37,37,37,37,37
                     DB 37,37,37,37,37,37,37,37,37,37
                     DB 37,37,37,37,37,37,37,37,37,37
                     DB 37,37,37,37,37,37,37,37,37,37
                     DB 37,37,37,37,37,37,37,37,37,37
                     DB 37,37,37,37,37,37,37,37,37,37
                     DB 37,37,37,37,37,37,37,37,37,37
                     DB 37,37,37,37,37,37,37,37,37,37
                     DB 37,37,37,37,37,37,37,37,37,37
                     DB 37,37,37,37,37,37,37,37,37,37

          Como podemos ver, es mucho ms cmodo utilizar la partcula DUP.
          Adems, reduce sensiblemente el tamao del cdigo fuente de un
          programa.

          Una caracterstica muy importante de la partcula DUP es que acepta
          la recursividad. Es decir, que podemos utilizar un DUP dentro de
          otro DUP ms externo.

          Veamos un ejemplo para aclararlo...
          Supongamos que queremos definir una cadena de caracteres, la cual
          estar formada por 30 subcadenas consecutivas, cada una de las cuales
          a su vez estar compuesta por 10 caracteres con valor 'A', seguidos
          de 30 caracteres con valor 'e', seguidos de 300 caracteres con
          valor 'S'.

          La definicin de esta cadena, sin utilizar la partcula DUP sera
          algo pesadsimo, y ocupara demasiado cdigo fuente.
          Mientras que utilizando la partcula DUP quedara algo as como:

              CADENA DB 30 DUP (10 DUP ('A'),30 DUP ('e'),300 DUP ('S'))



      * Definicin de constantes (Pseudo_instruccin EQU) *
        Mediante la Pseudo_instruccin EQU definiremos las constantes de
        nuestro programa, en caso de utilizar alguna.
        En primer lugar, decir que la definicin de una constante no genera
        ningn dato en el programa ejecutable. Las constantes se utilizan
        por motivos de comodidad y parametrizacin en un programa.


        Supongamos que hacemos un programa para la gestin de los presupuestos,
        dividendos, etc..  de un bufete de abogados.
        Este bufete de abogados en principio est formado por 3 personas.
        En nuestro programa utilizamos miles de veces instrucciones que operan
        con el nmero de personas del bufete, como  son divisin de dividendos
        entre los miembros del bufete, etc.
        Si en nuestro programa utilizamos siempre el nmero 3 para indicar el
        nmero de miembros, qu pasara cuando entrara un cuarto miembro al
        bufete... Tendramos que buscar por todo el programa las instrucciones
        que operan con el nmero de miembros y cambiar el 3 por el 4 para as
        actualizar el programa a la nueva realidad.
        Y de nuevo se nos planteara el problema si entrara un nuevo miembro,
        o si se fuera uno de los que ya estaban.

        La solucin a esto es utilizar una constante en lugar de un nmero
        concreto. As en caso de cambios, slo es necesario cambiar el valor
        de la constante en su definicin, y volver a ensamblar-linkar el
        programa. Ahorrandonos as buscar por todo el programa cualquier
        referencia al nmero de miembros.

            Num_Miembros EQU 3

        Mediante la lnea de arriba definimos una constante llamada
        Num_Miembros, la cual en un principio tendr valor 3.
        En el resto del programa, cada vez que tengamos que utilizar el
        nmero_de_miembros en cualquier operacin, no introduciremos el
        nmero 3, sino la constante Num_Miembros.
        De esta forma, en caso de variacin en el nmero_de_miembros slo
        ser necesario modificar el valor de la constante en su definicin.

        Como hemos dicho anteriormente, la definicin de la constante no
        genera ningn dato en el cdigo ejecutable.
        Lo que hace el ensamblador es sustituir este nombre de constante que
        utilizamos (en este caso Num_Miembros) por su valor asociado.



        Var1 db 'E'
        Var2 db 38,73
        Const EQU 219
        Var3 db 87


        Las definiciones de variables y constante anteriores generaran los
        siguientes datos en el cdigo ejecutable:

              E&IW

        Como podemos ver, entre el cdigo 73 (I) y el cdigo 87 (W) no
        encontramos el valor 219 (), ya que al tratarse de una constante no
        genera cdigo ejecutable.



      - MODELOS DE PROGRAMAS
      ----------------------

      * MODELO DE PROGRAMA COM *

;----------------------------- inicio del programa ------------------------

        PAGE      60,132
        TITLE Modelo_COM
        ;CopyRight (C) 1995.  Francisco Jesus Riquelme.  (AeSoft)


CSEG    SEGMENT PARA PUBLIC 'CODIGO'
        ASSUME  CS:CSEG, DS:CSEG, SS:CSEG
        ORG 100H

AEsoft_Prog:

        JMP AEsoft_Code               ;Salto al cdigo del Programa.

;****** INICIO DE LOS DATOS

        ;Aqu se definen los datos del programa.

;****** FIN DE LOS DATOS



;****** INICIO DEL PROGRAMA

AEsoft_Code:

        ;  --+
        ;    
        ;    +-- Aqu estar el programa principal.
        ;    
        ;  --+

        MOV AH,4CH ;Funcin de Terminacin de Programa.
        MOV AL,00  ;Ejecucin del programa exitosa. Para indicar error, dar a
                   ;AL un valor distinto de 00h.
        INT 21H    ;Ejecucin de la funcin (Salir del programa actual).


;****** FIN DEL PROGRAMA



;****** INICIO DE LOS PROCEDIMIENTOS


;Aqu se sitan cada uno de los procedimientos de que conste el programa.

Proc_1 PROC

    ;--+
    ;  
    ;  +- Cdigo del Procedimiento Proc_1
    ;  
    ;--+

    RET
Proc_1 ENDP

;***

Proc_2 PROC

    ;--+
    ;  
    ;  +- Cdigo del Procedimiento Proc_2
    ;  
    ;--+

    RET
Proc_2 ENDP


;***

Proc_n PROC

    ;--+
    ;  
    ;  +- Cdigo del Procedimiento Proc_n
    ;  
    ;--+

    RET
Proc_n ENDP



;****** FIN DE LOS PROCEDIMIENTOS


CSEG    ENDS
        END  AEsoft_Prog
;----------------------------- fin del programa ------------------------




      * MODELO DE PROGRAMA EXE *


;---------------------------- Inicio del Programa -------------------

       PAGE      60,132
       TITLE Modelo_EXE

;***** Inicio de Segmento de Pila

STACK  SEGMENT  PARA STACK 'PILA'
       DW 64 DUP (0)   ;Reservado espacio para 64 palabras. Los lenguajes de
                       ;alto nivel suelen reservar espacio para 1000.
STACK  ENDS

;***** Fin de Segmento de Pila


;***** Inicio de Segmento de Datos

DSEG   SEGMENT  PARA PUBLIC 'DATOS'

       ;--+
       ;  
       ;  +-- Aqu se definen los datos propios del programa.
       ;  
       ;--+

DSEG   ENDS

;***** Fin de Segmento de Datos



;***** Inicio de Segmento de Cdigo

CSEG   SEGMENT  PARA PUBLIC 'CODIGO'
       ASSUME   CS:CSEG, DS:DSEG, SS:STACK

AEsoft_Prg PROC FAR

;**** Comienzo del Procedimiento PRINCIPAL

;A continuacin se actualiza el Registro DS con el valor adecuado.
        MOV AX,DSEG  ;Mediante este par de instrucciones hacemos accesibles
        MOV DS,AX    ;nuestros datos.

        ;--+
        ;  
        ;  +--  Aqu se incluye el cdigo del procedimiento principal.
        ;  
        ;--+

        MOV AH,4CH ;Funcin de Terminacin de Programa.
        MOV AL,00  ;Ejecucin del programa exitosa. Para indicar error, dar
                   ;a AL un valor distinto de 00h.
        INT 21H    ;Ejecuto la funcin (Salgo del programa actual).


;**** Fin del Procedimiento Principal



;************************** Inicio de los Procedimientos

;Aqu se sitan cada uno de los procedimientos de que consta el programa.

Proc_1 PROC

    ;--+
    ;  
    ;  +- Cdigo del Procedimiento Proc_1
    ;  
    ;--+

    RET
Proc_1 ENDP

;***

Proc_2 PROC

    ;--+
    ;  
    ;  +- Cdigo del Procedimiento Proc_2
    ;  
    ;--+

    RET
Proc_2 ENDP


;***

Proc_n PROC

    ;--+
    ;  
    ;  +- Cdigo del Procedimiento Proc_n
    ;  
    ;--+

    RET
Proc_n ENDP


;************************** Fin de los procedimientos

AEsoft_prg ENDP
;***** Fin del Procedimiento principal.


CSEG    ENDS
;***** Fin de Segmento de Cdigo

        END AEsoft_prg
;---------------------------- Fin del Programa -------------------
     




      - EJEMPLOS DE PROGRAMAS
      -----------------------

      * EJEMPLO DE PROGRAMA COM *

;----------------------------- inicio del programa ------------------------

        PAGE    60,132
TITLE   Bloque_Entorno
        ;CopyRight (C) 1995.  Francisco Jesus Riquelme.  (AeSoft)


CSEG    SEGMENT PARA PUBLIC 'CODIGO'
        ASSUME  CS:CSEG, DS:CSEG, SS:CSEG
        ORG 100H

AEsoft_Prog:

        JMP AEsoft_Code               ;Salto al cdigo del Programa.

;****** INICIO DE LOS DATOS

        FILE_HANDLE DW 0              ;Handle del fichero que voy a usar para
                                      ;almacenar el Bloque.
        FILE_NAME db 'FileBlk.inf',0  ;Cadena ASCIIZ con el Nombre del Fichero
                                      ;que almacenar el Bloque.


        MENSAJE_DE_ERROR DB 'Se ha producido un error de Fichero. Programa '
                         DB 'Abortado.$'

                                      ;MENSAJE_DE_ERROR contiene el mensaje
                                      ;que se mostrar por pantalla si se
                                      ;produce un error de fichero.

                                      ;NOTAS:
                                      ; - El mensaje puede ocupar varias lneas.
                                      ; - El mensaje acaba cuando el DOS lee el
                                      ;   carcter $, el cual no es enviado a
                                      ;   la pantalla.



;****** FIN DE LOS DATOS



;****** INICIO DEL PROGRAMA

AEsoft_Code:

        ;Primero creo el fichero que va a contener el Bloque de Entorno.
        ;Al crearlo, queda abierto para las siguientes operaciones.

        MOV AH,3CH
        MOV CX,00H                 ;Atributo de Fichero Normal.
        MOV DX,Offset FILE_NAME    ;DS:DX apuntando al nombre del Fichero.
        INT 21H                    ;Ejecuto la funcin.
                                   ;A continuacin compruebo si se ha producido
                                   ;error en la ejecucin de la funcin.

        JC ERROR_FILE ;Si a la vuelta de la ejecucin de la INT 21H el flag Cf
                      ;(Flag de Carry o Acarreo) tiene valor 1, esto quiere
                      ;decir que se ha producido error. Por tanto salto a
                      ;la rutina que trata dicho error, que simplemente dar
                      ;un mensaje de Error al usuario y acto seguido finaliza
                      ;el programa.


        ;Si el control del programa llega hasta aqu, es porque no hay error.
        ;Entonces en AX se devuelve el Handle con el que manejaremos al
        ;fichero recientemente creado.

        MOV FILE_HANDLE,AX ;Almaceno el Handle que asigna el DOS a mi fichero.

        ;Ya tengo el fichero abierto, listo para almacenar el Bloque
        ;de Entorno.


        ;Ahora lo que voy a hacer es 'situarme' en el inicio del Bloque y
        ;copiarlo al fichero.

        MOV AX,WORD PTR CS:[2CH] ;En AX, direccin del Bloque de Entorno.

                  ;A continuacin preparo los registros adecuados para
                  ;invocar a la funcin 40h de la Int 21h (Escritura en
                  ;Fichero).
        MOV DS,AX ;Registro de Segmento DS apuntando al principio del Bloque.
        MOV DX,0  ;El Bloque empieza en el Offset 00h.

        ;Ya tengo los registros DS:DX apuntando al inicio del Bloque.
        ;Ahora lo que debo saber es el tamao de dicho Bloque.
        ;Hemos dicho que el nombre del programa aparece despus del valor
        ;0001h, y que el nombre del programa aparece como una cadena ASCIIZ.
        ;Esto quiere decir que el ltimo byte ser un 00h.
        ;O sea que primero buscamos un byte 01h, saltamos el byte siguiente
        ;que sera el byte alto de la palabra 0001h, y a continuacin buscamos
        ;un byte con valor 00h que nos indica el final del Bloque de Entorno.
        ;Usamos el registro CX (Contador) para llevar la cuenta del total de
        ;bytes de que est compuesto el Bloque de Entorno.

        MOV CX,0  ;Inicializo el registro contador.
        MOV SI,DX ;Resguardo el contenido del registro DX (que voy a necesitar
                  ;luego) utilizando el registro SI con el valor que tena DX.

        CALL LONGITUD_BLOQUE ;Llamo al procedimiento LONGITUD_BLOQUE para
                             ;obtener en CX la longitud del Bloque de Entorno.

        ;Tras la ejecucin del procedimiento LONGITUD_BLOQUE,
        ;ya tengo en CX el total de bytes que componen el Bloque de Entorno.
        ;Tengo tambin el par de registros DS:DX apuntando al inicio del
        ;Bloque.
        MOV AH,40H ;Nmero de la funcin (Escribir en fichero).
        MOV BX,CS:FILE_HANDLE ;(Handle de fichero).
                              ;Debo indicar el segmento donde se encuentra
                              ;la variable FILE_HANDLE, ya que el Registro DS
                              ;no apunta a los datos, sino al Bloque de
                              ;Entorno.
        INT 21H ;Ejecuto la funcin.

        ;Ya tengo copiado a fichero el Bloque de Entorno.

        ;Ahora cierro el fichero. Esto es muy importante.
        ;Todo fichero abierto debe ser cerrado antes de salir del programa.

        MOV AH,3EH ;Nmero de la funcin (Cerrar fichero).
        MOV BX,CS:FILE_HANDLE ;(Handle de fichero).
        INT 21H ;Ejecuto la funcin.

        JC ERROR_FILE ;Si se ha producido error al intentar cerrar el fichero,
                      ;mostrar mensaje y salir del programa.


        ;Si llega hasta aqu el control del programa es porque no se ha
        ;producido ningn error.
        ;A continuacin salgo del programa con cdigo de retorno 0, indicando
        ;que no se ha producido error.


        MOV AH,4CH ;Funcin de Terminacin de Programa.
        MOV AL,00  ;Ejecucin del programa exitosa.
        INT 21H    ;Ejecuto la funcin (Salgo del programa actual).





ERROR_FILE:

       ;Si el control del programa llega hasta aqu, es porque se ha producido
       ;un error al trabajar con el fichero. A continuacin muestro por
       ;pantalla un mensaje al usuario comunicndolo, y finalizo el programa.


       MOV AH,9
       MOV DX,OFFSET CS:MENSAJE_DE_ERROR
       INT 21H    ;Mostrado el mensaje de Error por la pantalla.


       MOV AH,4CH ;Funcin de Terminacin de Programa.
       MOV AL,01  ;Cdigo de Retorno 01 (distinto de 0) que indica Error
                  ;en la ejecucin del programa.
       INT 21H    ;Ejecuto la funcin (Salgo del programa actual).


;****** FIN DEL PROGRAMA



;****** INICIO DE LOS PROCEDIMIENTOS

LONGITUD_BLOQUE PROC

Bucle_Busca_01h:

        CMP BYTE PTR [SI],01h
        JZ Encontrado_01h

        INC SI ;Incremento el contenido del Registro Indice.
        INC CX ;Incremento el nmero de bytes totales del Bloque.

        JMP SHORT Bucle_Busca_01h ;Salto corto (SHORT) hacia el inicio del
                                  ;bucle en busca del siguiente byte para
                                  ;comparar.

Encontrado_01h: ;Al llegar aqu, ya tenemos el byte 01h que indica que
                ;a continuacin encontraremos el nombre del programa.
                ;Pero antes de ese nombre de Programa est el byte alto
                ;de la palabra 0001h. Es decir, tenemos que saltar un
                ;byte 00h antes de llegar al nombre del programa.
                ;Recordad la curiosa forma que tiene el procesador de
                ;almacenar las palabras en la memoria:
                ;El byte bajo (de menor peso), al principio.
                ;El byte alto, a continuacin.
                ;As, la palabra 0001h se almacena en memoria como 0100h.
                ;Si accedemos a este valor a nivel de palabra, no hay
                ;problema, ya que usaremos un registro de tipo palabra para
                ;almacenar el valor, y no nos enteraremos de esta peculiaridad.
                ;Pero si accedemos en modo byte, nos encontramos con que el
                ;primer byte ser el que por lgica debera ser el segundo,
                ;y viceversa. Por tanto, en el programa que nos toca, vamos
                ;a encontrar primero el byte 01h, y luego simplemente saltamos
                ;el siguiente byte, ya que sabemos que va a ser el byte con
                ;valor 00h.

        ADD SI,2
        ADD CX,2
                ;Mediante las dos instrucciones de arriba he saltado el byte
                ;01h que acabo de encontrar al salir del bucle, y he saltado
                ;tambin el byte 00h (byte alto de la palabra 0001h).
                ;Ambos bytes los contabilizo como bytes del Bloque de Entorno
                ;mediante el incremento del registro CX.

        ;A continuacin busco el byte 00h que cierra el nombre de programa
        ;y por tanto el Bloque de Entorno.


Bucle_busca_00h:

        CMP BYTE PTR [SI],00h
        JZ Encontrado_00h

        INC SI ;Incremento el contenido del Registro Indice.
        INC CX ;Incremento el nmero de bytes totales del Bloque.

        JMP SHORT Bucle_Busca_00h ;Salto corto (SHORT) hacia el inicio del
                                  ;bucle en busca del siguiente byte para
                                  ;comparar.


Encontrado_00h:

        INC CX ;Para aadir a la cuenta el byte 00h que cierra el Bloque
               ;de Entorno.

        RET
LONGITUD_BLOQUE ENDP


;****** FIN DE LOS PROCEDIMIENTOS


CSEG    ENDS
        END  AEsoft_Prog



;----------------------------- fin del programa ------------------------




      * EJEMPLO DE PROGRAMA EXE *


;---------------------------- Inicio del Programa -------------------

       PAGE 80,132
       TITLE Bloque_Entorno
       ;CopyRight (C) 1995.  Francisco Jesus Riquelme.  (AeSoft)

;***** Inicio de Segmento de Pila

STACK  SEGMENT  PARA STACK 'PILA'
       DW 64 DUP (0)
STACK  ENDS

;***** Fin de Segmento de Pila


;***** Inicio de Segmento de Datos

DSEG   SEGMENT  PARA PUBLIC 'DATOS'

        FILE_HANDLE DW 0              ;Handle del fichero que voy a usar para
                                      ;almacenar el Bloque.
        FILE_NAME db 'FileBlk.inf',0  ;Cadena ASCIIZ con el Nombre del Fichero
                                      ;que almacenar el Bloque.


        MENSAJE_DE_ERROR DB 'Se ha producido un error de Fichero. Programa '
                         DB 'Abortado.$'

                                      ;MENSAJE_DE_ERROR contiene el mensaje
                                      ;que se mostrar por pantalla si se
                                      ;produce un error de fichero.

                                      ;NOTAS:
                                      ; - El mensaje puede ocupar varias lneas.
                                      ; - El mensaje acaba cuando el DOS lee el
                                      ;   carcter $, el cual no es enviado a
                                      ;   la pantalla.


DSEG   ENDS

;***** Fin de Segmento de Datos



;***** Inicio de Segmento de Cdigo

CSEG   SEGMENT  PARA PUBLIC 'CODIGO'
       ASSUME   CS:CSEG, DS:DSEG, SS:STACK

AEsoft_Prg PROC FAR

;Comienzo del Programa PRINCIPAL.
;Actualiza el Registro DS (Segmento de Datos) con el valor adecuado.
        MOV AX,DSEG
        MOV DS,AX


        ;Primero creo el fichero que va a contener el Bloque de Entorno.
        ;Al crearlo, queda abierto para las siguientes operaciones.

        MOV AH,3CH
        MOV CX,00H                 ;Atributo de Fichero Normal.
        MOV DX,Offset FILE_NAME    ;DS:DX apuntando al nombre del Fichero.
        INT 21H                    ;Ejecuto la funcin.
                                   ;A continuacin compruebo si se ha producido
                                   ;error en la ejecucin de la funcin.

        JC ERROR_FILE ;Si a la vuelta de la ejecucin de la INT 21H el flag Cf
                      ;(Flag de Carry o Acarreo) tiene valor 1, esto quiere
                      ;decir que se ha producido error. Por tanto salto a
                      ;la rutina que trata dicho error, que simplemente dar
                      ;un mensaje de Error al usuario y acto seguido finaliza
                      ;el programa.


        ;Si el control del programa llega hasta aqu, es porque no hay error.
        ;Entonces en AX se devuelve el Handle con el que manejaremos al
        ;fichero recientemente creado.

        MOV FILE_HANDLE,AX ;Almaceno el Handle que asigna el DOS a mi fichero.

        ;Ya tengo el fichero abierto, listo para almacenar el Bloque
        ;de Entorno.


        ;Ahora lo que voy a hacer es 'situarme' en el inicio del Bloque y
        ;copiarlo al fichero.

        MOV AX,WORD PTR ES:[2CH] ;En AX, direccin del Bloque de Entorno.
                                 ;ES apunta desde el principio al PSP, como
                                 ;no hemos modificado su valor, ahora nos
                                 ;valemos de l.
                                 ;DS tambin apuntaba al PSP, pero unas lneas
                                 ;ms arriba hemos modificado su valor para
                                 ;que apunte a nuestro segmento de datos.

                  ;A continuacin preparo los registros adecuados para
                  ;invocar a la funcin 40h de la Int 21h (Escritura en
                  ;Fichero).

        PUSH DS
        POP ES  ;Resguardo la direccin del segmento de datos en el registro
                ;ES, ya que DS va a perder su valor original.
                ;De esta forma no perder la direccin de mi segmento de datos.


        MOV DS,AX ;Registro de Segmento DS apuntando al principio del Bloque.
        MOV DX,0  ;El Bloque empieza en el Offset 00h.

        ;Ya tengo los registros DS:DX apuntando al inicio del Bloque.
        ;Ahora lo que debo saber es el tamao de dicho Bloque.
        ;Hemos dicho que el nombre del programa aparece despus del valor
        ;0001h, y que el nombre del programa aparece como una cadena ASCIIZ.
        ;Esto quiere decir que el ltimo byte ser un 00h.
        ;O sea que primero buscamos un byte 01h, saltamos el byte siguiente
        ;que sera el byte alto de la palabra 0001h, y a continuacin buscamos
        ;un byte con valor 00h que nos indica el final del Bloque de Entorno.
        ;Usamos el registro CX (Contador) para llevar la cuenta del total de
        ;bytes de que est compuesto el Bloque de Entorno.

        MOV CX,0  ;Inicializo el registro contador.
        MOV SI,DX ;Resguardo el contenido del registro DX (que voy a necesitar
                  ;luego) utilizando el registro SI con el valor que tena DX.

        CALL LONGITUD_BLOQUE ;Llamo al procedimiento LONGITUD_BLOQUE para
                             ;obtener en CX la longitud del Bloque de Entorno.

        ;Tras la ejecucin del procedimiento LONGITUD_BLOQUE,
        ;ya tengo en CX el total de bytes que componen el Bloque de Entorno.
        ;Tengo tambin el par de registros DS:DX apuntando al inicio del
        ;Bloque.
        MOV AH,40H ;Nmero de la funcin (Escribir en fichero).
        MOV BX,ES:FILE_HANDLE ;(Handle de fichero).
                              ;Debo indicar el segmento donde se encuentra
                              ;la variable FILE_HANDLE, ya que el Registro DS
                              ;no apunta a los datos, sino al Bloque de
                              ;Entorno.
        INT 21H ;Ejecuto la funcin.

        ;Ya tengo copiado a fichero el Bloque de Entorno.

        ;Ahora cierro el fichero. Esto es muy importante.
        ;Todo fichero abierto debe ser cerrado antes de salir del programa.

        MOV AH,3EH ;Nmero de la funcin (Cerrar fichero).
        MOV BX,ES:FILE_HANDLE ;(Handle de fichero).
        INT 21H ;Ejecuto la funcin.

        JC ERROR_FILE ;Si se ha producido error al intentar cerrar el fichero,
                      ;mostrar mensaje y salir del programa.


        ;Si llega hasta aqu el control del programa es porque no se ha
        ;producido ningn error.
        ;A continuacin salgo del programa con cdigo de retorno 0, indicando
        ;que no se ha producido error.


        MOV AH,4CH ;Funcin de Terminacin de Programa.
        MOV AL,00  ;Ejecucin del programa exitosa.
        INT 21H    ;Ejecuto la funcin (Salgo del programa actual).



ERROR_FILE:

       ;Si el control del programa llega hasta aqu, es porque se ha producido
       ;un error al trabajar con el fichero. A continuacin muestro por
       ;pantalla un mensaje al usuario comunicndolo, y finalizo el programa.


       MOV AH,9
       MOV DX,OFFSET ES:MENSAJE_DE_ERROR
       INT 21H    ;Mostrado el mensaje de Error por la pantalla.



      MOV AH,4CH
      MOV AL,1 ;Cdigo de Retorno que indica Error en la ejecucin del Programa.
      INT 21H  ;Finaliza el programa y vuelve al proceso padre con cdigo de
               ;Error.

;**** FIN DEL PROGRAMA PRINCIPAL



;************************** Procedimientos:

LONGITUD_BLOQUE PROC

Bucle_Busca_01h:

        CMP BYTE PTR [SI],01h
        JZ Encontrado_01h

        INC SI ;Incremento el contenido del Registro Indice.
        INC CX ;Incremento el nmero de bytes totales del Bloque.

        JMP SHORT Bucle_Busca_01h ;Salto corto (SHORT) hacia el inicio del
                                  ;bucle en busca del siguiente byte para
                                  ;comparar.

Encontrado_01h: ;Al llegar aqu, ya tenemos el byte 01h que indica que
                ;a continuacin encontraremos el nombre del programa.
                ;Pero antes de ese nombre de Programa est el byte alto
                ;de la palabra 0001h. Es decir, tenemos que saltar un
                ;byte 00h antes de llegar al nombre del programa.
                ;Recordad la curiosa forma que tiene el procesador de
                ;almacenar las palabras en la memoria:
                ;El byte bajo (de menor peso), al principio.
                ;El byte alto, a continuacin.
                ;As, la palabra 0001h se almacena en memoria como 0100h.
                ;Si accedemos a este valor a nivel de palabra, no hay
                ;problema, ya que usaremos un registro de tipo palabra para
                ;almacenar el valor, y no nos enteraremos de esta peculiaridad.
                ;Pero si accedemos en modo byte, nos encontramos con que el
                ;primer byte ser el que por lgica debera ser el segundo,
                ;y viceversa. Por tanto, en el programa que nos toca, vamos
                ;a encontrar primero el byte 01h, y luego simplemente saltamos
                ;el siguiente byte, ya que sabemos que va a ser el byte con
                ;valor 00h.

        ADD SI,2
        ADD CX,2
                ;Mediante las dos instrucciones de arriba he saltado el byte
                ;01h que acabo de encontrar al salir del bucle, y he saltado
                ;tambin el byte 00h (byte alto de la palabra 0001h).
                ;Ambos bytes los contabilizo como bytes del Bloque de Entorno
                ;mediante el incremento del registro CX.

        ;A continuacin busco el byte 00h que cierra el nombre de programa
        ;y por tanto el Bloque de Entorno.


Bucle_busca_00h:

        CMP BYTE PTR [SI],00h
        JZ Encontrado_00h

        INC SI ;Incremento el contenido del Registro Indice.
        INC CX ;Incremento el nmero de bytes totales del Bloque.

        JMP SHORT Bucle_Busca_00h ;Salto corto (SHORT) hacia el inicio del
                                  ;bucle en busca del siguiente byte para
                                  ;comparar.


Encontrado_00h:

        INC CX ;Para aadir a la cuenta el byte 00h que cierra el Bloque
               ;de Entorno.

        RET
LONGITUD_BLOQUE ENDP


;************************** Fin de los procedimientos

AEsoft_prg ENDP
CSEG    ENDS
        END AEsoft_prg

;***** Fin de Segmento de Cdigo


;---------------------------- Fin del Programa -------------------






      - CREAR EL PROGRAMA EJECUTABLE (ENSAMBLAR-LINKAR)
      --------------------------------------------------------------------
      En este apartado vamos a ver cmo convertir nuestro cdigo fuente
      en ejecutable.

      Segn hayamos creado el cdigo fuente podremos obtener dos modelos
      diferentes de ejecutable: COM y EXE.
      Si hemos seguido ciertas reglas necesarias para poder conseguir un
      programa COM, podremos obtener los dos formatos mediante el mismo
      cdigo fuente.
      Si no hemos seguido esas reglas, slo podremos obtener un programa EXE.

      A la hora de ensamblar-linkar necesitaremos de un paquete Ensamblador,
      con su Programa Ensamblador, su Linkador, etc.
      Los ms potentes segn mi criterio son MASM (de MicroSoft) y TASM (de
      Borland). Aparte de estos dos paquetes, en el mercado existen varios
      ms, algunos son shareware.

      En caso de utilizar un Ensamblador diferente a MASM y TASM, chale un
      vistazo a la documentacin que acompaa al programa, ya que hay ciertos
      Ensambladores muy peculiares.  Los hay, por ejemplo, que obtienen el
      programa COM sin necesidad de crear OBJ ni EXE intermedios.


      Lo mencionado a continuacin es vlido para MASM y TASM.


      * CREAR EXE *
      Para obtener un programa EXE a partir de un cdigo fuente (ASM) deberemos
      seguir los siguientes pasos:
      Supongamos que nuestro cdigo fuente tiene por nombre PROG.ASM

        1. Ensamblar el cdigo fuente.

             MASM PROG.ASM;
             (TASM en caso de utilizar Turbo Assembler)


           El programa MASM es el 'Ensamblador'.  Mediante este paso conseguimos
           el fichero OBJ (Objeto). Este fichero OBJ an no est listo para
           ser ejecutado, ya que en l pueden existir referencias a datos,
           procedimientos, etc.. que se dejan en blanco para ser completadas
           por el programa LINK, ya que a MASM no se le d toda la informacin
           necesaria para poder completar estas referencias.

           La sintaxis completa a emplear con el programa MASM se indica
           a continuacin:

-------------------------------------------------------------------------------
Usage: masm /options source(.asm),[out(.obj)],[list(.lst)],[cref(.crf)][;]

/a              Alphabetize segments
/b<number>      Set I/O buffer size, 1-63 (in 1K blocks)
/c              Generate cross-reference
/d              Generate pass 1 listing
/D<sym>[=<val>] Define symbol
/e              Emulate floating point instructions and IEEE format
/I<path>        Search directory for include files
/l[a]           Generate listing, a-list all
/M{lxu}         Preserve case of labels: l-All, x-Globals, u-Uppercase Globals
/n              Suppress symbol tables in listing
/p              Check for pure code
/s              Order segments sequentially
/t              Suppress messages for successful assembly
/v              Display extra source statistics
/w{012}         Set warning level: 0-None, 1-Serious, 2-Advisory
/X              List false conditionals
/z              Display source line for each error message
/Zi             Generate symbolic information for CodeView
/Zd             Generate line-number information
-------------------------------------------------------------------------------

Esta pantalla de ayuda se consigue mediante la orden MASM /H






        2. Linkar (fusionar) los ficheros Objeto (OBJ).
           Convertir el fichero OBJ (Objeto) en EXE (Ejecutable).

           Mediante este paso convertimos nuestro fichero OBJ en un fichero
           ejecutable (EXE).
           LINK completa las direcciones que MASM dej pendientes en el mdulo
           Objeto (Fichero OBJ), asignndoles su direccin real.
           Tambin fusiona ('linka') varios mdulos OBJ en un mismo programa
           final (EXE) si as se haba requerido.
           Por ltimo, crea la cabecera del programa EXE necesaria para la
           posterior carga y ejecucin de los distintos segmentos del programa
           por parte del DOS.

               LINK PROG.OBJ;
               (TLINK en caso de utilizar Turbo Assembler)

        Mediante estos dos pasos ya tenemos creado nuestro programa EXE a
        partir del cdigo fuente escrito en ASM.


        Los parmetros (options) vlidos a emplear con el programa LINK se
        indican a continuacin:

-------------------------------------------------------------------------------
Microsoft (R) Overlay Linker  Version 3.61
Copyright (C) Microsoft Corp 1983-1987.  All rights reserved.

Valid options are:
  /BATCH                         /CODEVIEW
  /CPARMAXALLOC                  /DOSSEG
  /DSALLOCATE                    /EXEPACK
  /FARCALLTRANSLATION            /HELP
  /HIGH                          /INFORMATION
  /LINENUMBERS                   /MAP
  /NODEFAULTLIBRARYSEARCH        /NOEXTDICTIONARY
  /NOFARCALLTRANSLATION          /NOGROUPASSOCIATION
  /NOIGNORECASE                  /NOPACKCODE
  /OVERLAYINTERRUPT              /PACKCODE
  /PAUSE                         /QUICKLIBRARY
  /SEGMENTS                      /STACK
-------------------------------------------------------------------------------

Esta pantalla de ayuda se consigue mediante la orden LINK /HELP





        * CREAR COM *
        Para poder obtener un programa COM a partir de un cdigo fuente (ASM)
        debemos proceder como sigue:

          1. Obtener el programa EXE mediante los dos pasos del apartado
             anterior.

          2. Convertir el programa EXE en COM.
             Para llevar a cabo esta conversin existe la utilidad EXE2BIN,
             que como su nombre indica (hay que echarle imaginacin :-)
             convierte los EXE  a (*) BIN.
             *El 2 ese lo utilizan para abreviar la palabra TO, la cual se
             pronuncia igual que TWO (2).

                   EXE2BIN PROG.EXE

             Mediante la lnea anterior obtenemos el fichero BIN.
             Este fichero BIN debemos convertirlo en fichero COM, por fin.
             Para hacer esta tarea existe una orden de sistema operativo
             llamada REN. :-)
             El contenido del fichero BIN est listo ya para ser ejecutado
             como si de un COM se tratara, en realidad su contenido es
             una COpia_de_Memoria (COM).
             Pero como el DOS no ejecuta BIN, tendremos que cambiarle su
             extensin a COM (que s ejecuta).

                  REN PROG.BIN PROG.COM

             Ya tenemos el programa listo para ser ejecutado como COM.

             Nota: En lugar de utilizar la orden  REN PROG.BIN PROG.COM
                   es preferible la orden COPY PROG.BIN PROG.COM, ya que
                   en cuanto hagamos la primera revisin o mejora del programa,
                   la orden REN PROG.BIN PROG.COM no funcionar al existir
                   ya el PROG.COM.


             Nota2: Hay utilidades EXE2BIN que no devuelven un fichero BIN,
                    sino un fichero COM. En este caso, un trabajo que nos
                    ahorramos de cambiarle el nombre.

             Nota3: Para poder obtener un programa COM, el cdigo fuente debe
                    cumplir los siguientes requisitos:
                    - Incluir la pseudo_instruccin (ORG 100H) como ya se
                      indic en el apartado de programas COM.
                    - No hacer ninguna referencia a segmentos definidos en
                      el programa.
                      Es decir, un programa COM no puede tener instrucciones
                      como la siguiente (MOV AX,CSEG).

                   (Ver modelo y ejemplo de programa COM).

            Nota4: Al linkar un fichero OBJ preparado para funcionar como COM,
                   el Linkador nos dar un mensaje de advertencia (Warning)
                   indicndonos que falta por definir el segmento de pila.
                   Eso lo hace porque no sabe si vamos a convertir el programa
                   EXE resultante a formato COM.

                   No debemos hacer caso a este mensaje.




      Bueno, pues eso es todo por esta leccin.

      saluDOS.
      Francisco Jesus Riquelme.
