Vistas de página en total

domingo, 5 de mayo de 2013

MAIN

 MAIN.MAC - CABECERA PRINCIPAL


   Primero y ante todo decir que el código que voy a implementar no usa muchas directivas ya creadas en MASM y TASM.  Debido a que yo daba clases de Ensamblador y a que comencé con ASM, preferí inicialmente crear directivas propias a usar las que tenía el compilado TASM 2.0. (rutina en vez de proc, modelo en vez de model, _data en vez de .data... etc). De esta forma podía demostrar que realmente las directivas eran definibles. 
    Por eso, aunque muchos digan que lo que estoy haciendo  ya está construido en el compilador, quiero que vean que muchas de las directivas del TASM 2.0 son prescindibles, y que un buen programador puede usar un pequeño compilador y realizar cualquier tarea.
    Esto es importante para los que hemos tenido que compilar con otros compiladores mucho más simples, por ejemplo para otros microprocesadores, y en los que hemos querido aplicar las mismas reglas de programación que con el 8086.
    
     Por eso ruego paciencia. Primero aplicaré mis directivas, y veremos como resulta un código casi idéntico al del ensamblador TASM 2.0.  Así veremos, sin necesidad de desensamblar, lo que realmente hacen esas directivas, que simplifican el código, pero que ocultan cosas, al programador, que se deben conocer y entender.
    Sin embargo, si pensamos usar standares y acoplarnos a códigos de alto nivel, nos conviene usar las directivas incorporadas en el compilador TASM, para compatibilizar de forma sencilla el código con otros lenguajes de alto nivel.
   Por eso a partir de la entrada 50 del blog haré una comparativa de las dos formas y comenzaré a aplicar directamente el código TASM 2.0.

FUNCIONES ACOPLADAS EN MAIN.MAC
    

  Todo lo que iré poniendo ahora será para generar ficheros .exe. Más adelante, Cuando hayamos implementado programas ya con las directivas del TAM completas, lo generaremos en .com.

 Como siempre habrá una cabecera ".mac", bueno ".inc" si se desea, con las macros y definiciones de las funciones. Cuando simplifique los programas a versión completa las llamaré ".inc" para distinguirlas.

  En esta cabecera, como cabecera de inicialización de programa incluyo algunas sentencias de precompilación, que servirán para asignar memoria, segmentos, pila y por supuesto la estructura de lista de argumentos.
       
     Rutina (equivale a proc+ arg en TASM)
     Permite crear estructura para el paso de parámetros través de pila, de esta manera será muy sencillo declarar una función y pasarla hasta 10 variables . Declara  al tiempo la función como publica, al modo que lo hace "C", pero sin apenas darnos cuenta. Se verá mejor cuando coloque la función Graphics.

  _modelo (equivale a model en TASM)
     Sirve para definir el tipo de programa .com o .exe. si no se usa es .exe. Esto se usará paa definr los segmetos
      EN esta macro creamos una constante que podemos identificar en la macro _data, para asignar la zona de datos a DS o CS, según el programa sea . com o .exe. Esto no evitará tener que utilizar dos librerías (una para como y otra para exe) , si no queremos tener que compilar todas las librerías cada vez que hagamos un programa.
   Pero sí nos permitirá tener un programa único para cada librería y una de muy  forma simple compilarlo para uno y otro modo.

  _code (equivale a .code en TASM) 
      Nos define el comienzo de la zona de código.

  _data (equivale a .data en TASM) 
    Nos define el comienzo de la zona de datos. Puede estar antes o después del code, aunque en las funciones es recomendable que esté detrás.

   _end  (equivalente a end en TASM)
        Cierra el programa en caso un programa se debe indicar el nombre de la rutina principal
  _stack (equivale a .stack en TASM)
         Nos inicializa la pila al tamaño indicado en NUMERO

   Todas estas macros crean un entorno de trabajo equivalente al estandar de TASM y MASM, pero sin usar su directivas. Como solo usa if y macro con ellas puede crearse el entrono equivalente a TASM pero en el compilador inicial ASM. Todas estas macros pueden ser eliminadas y substituidas por las directivas equivalentes del TASM 2.0. Cosa que haremos más adelante.

   Con estas  macros podemos ver como se pueden crear no solo llamadas a funciones sino nuevas directivas de compilación. A partir de la entrada 50 del blog veremos como crear con las macros directivas de PROGRAMACIÓN ESTRUCTURADA tales como FOR o WHILE.

 Otras macros más interesantes aún pues no las tiene el TASM son:

   dim - Permite crear una variable compleja tomando una estructura como plantilla.
   asigdata - Nos permitirá reasignar una zona de memoria al segmento de datos.

   of_reg- devuelve la dirección del registro indicado de una tabla que se encuentre en memoria, creada bajo una estructura.

    exit- Fin de programa con salida al sistema.

   encriptar y desencriptar- Funciones especiales que permitirán encriptar parte de los datos del programa, de manera que no sean legibles mediante un Dump del código, pero si sean legibles una vez inicializado el programa.

   string, char, integer Definición de los tres tipos de variables más importantes. Serán usadas en la inicialización de los datos, por lo que están incluidas en el main como definición de variables.

   main - comienzo del programa. Es la encargada de llamar a la linea de comandos si se definieron parámetros y la encargada de asignar la zona de datos si se definió con la macro _data. Así mismo prepara el PSP para que la salvar la dirección de vuelta al sistema.

     Dentro del main existe una directiva por la cual si no se ha añadido la cabecera argum.mac, y por lo tanto no se ha definido la variable externa _line_comand, no se llamará a la función de la librería correspondiente. De esta forma, si no necesitamos argumentos no consumiremos código innecesario.
  Main parece una forma de iniciar el programa pero es mucho más, en realidad  inicializa el programa., reserva la memoria, recoge los argumentos de la línea de comando, y prepara la ejecución. Por ello tomé este nombre para crear una rutina especial, a la que llamaré siempre al inicio del programa ejecutable. Se encargará de inicializar la memoria, la pila del sistema y recoger los argumentos de la linea de comandos, para que posteriormente mediante argv argc  tratarlos.
   En el caso del main  no incluimos la función directamente en la cabecera, pues en este caso el tamaño de la función supera al código de llamada.

  Esta rutina no tendrá argumentos, y será llamada simplemente main
 
   Con esta cabecera estamos creando un entorno de trabajo equivalente al TASM completo, pero sin usar sus directivas más complejas.


MAIN.MAC
; Copyright (C) 2013  José Ángel Moneo Fernández

;    This program is free software: you can redistribute it and/or modify
;    it under the terms of the GNU General Public License as published by
;    the Free Software Foundation, either version 3 of the License, or
;   (at your option) any later version.

;    This program is distributed in the hope that it will be useful,
;    but WITHOUT ANY WARRANTY; without even the implied warranty of
;    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;    GNU General Public License for more details.

;    You should have received a copy of the GNU General Public License
;    along with this program.  If not, see <http://www.gnu.org/licenses/>.
   ;Declaracion de una rutina (función) con paso de variables
    Esta macro crea una estructura de compilación para ser usada  posteriormente en la recogida de los datos pasados a la función.

;define modelo .com o .exe para definir forma de colocar assume en _data
_modelo macro tipo
   tipo equ 1
endm


rutina macro nombre,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10
   nombre&p struc
         dd ?
   irp arg,<arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10>
          ifnb <arg>
             arg  dw ?
          endif
        endm
    nombre&p  ends
        public nombre
nombre proc near

        push bp
        mov bp,sp
        endm


_end macro nombre
 ends  
   end nombre
endm

;genera la cabecera de datos
_data macro
ifndef com
    ends  ;asegura el cierre del segmento anterior
    data segment byte public 'data'
endif
endm

_code macro
    code segment byte public 'code'
    assume cs:code
ifdef com
  assume ds:code
else
    assume ds:data ; esto nos obliga a definir siempre un data aunque sea vacío
 endif
endm

;genera una pila con el tama¤o indicado
_stack macro NUMERO
     pila segment byte stack 'stack'
          db NUMERO dup (0)
     pila ends
     assume ss:pila
 endm


;coloca en pila de direccion del PSP para salir al dos y llama
;a la gesti¢n de la linea de comandos si se ha usado parametros
main macro
    push ds
    xor ax, ax
    push ax
ifdef _lin_comand
    call _lin_comand
endif
ifdef data
    asigdata data
endif
endm

;asigna un nuevo segmento de datos de trabajo
asigdata macro etiq
    assume ds:etiq
    mov ax, etiq
    mov ds, ax
endm

;dimensiona una tabla de numero de elementos con una estructura regis
dim macro tablas,regis,numero
        tablas regis numero dup (<>)
endm


; devuelve la direccion de un registro en una tabla en memoria
of_reg macro dest,lista,numero
      mov dest,offset lista[numero*type(lista)]
endm

;Sale al sistema devolviendo un codigo
exit macro codigo
     mov ah,4ch
ifdif <codigo>,<al>
     mov al,codigo
endif
     int 21h
endm

;encripta una zona de datos con un codigo dado
encriptar macro inicio,bytes,codigo
ifndef _encriptar
     extrn _encriptar:near
endif
         xor ax,ax
         push ax
         mov ax,codigo
         push ax
         mov ax,bytes
         push ax
         lea ax,inicio
         push ax
         call _encriptar
         add sp,8
 endm

;desencripta una zona de datos con un codigo dado
desencriptar macro inicio,bytes,codigo
ifndef _encriptar
        extrn _encriptar:near
endif
         mov ax,28h
         push ax
         mov ax,codigo
         push ax
         mov ax,bytes
         push ax
         lea ax,inicio
         push ax
         call _encriptar
         add sp,8
 endm

;define una cadena de entrada de texto para el scanf
string macro nombre,long
     nombre db long+1,0,long+2 dup (0)
endm

char macro var,ini
  ifb <ini>
      var db ?
  else
      var db ini
  endif
endm

integer macro var,ini
  ifb <ini>
      var dd ?
  else
      var dd ini
  endif
endm

No hay comentarios:

Publicar un comentario

Si tienes algún comentario, duda o sugerencia, o si quieres aportar algún código creado a partir de las librerías expuestas aquí, por favor, indícamelo.