|
Programación
de librerías
ILBM (3ª
Parte)
Por Vicente Santos
|
Las
librerías y su programación siguen ocupando un espacio importante
de nuestra publicación. Con esta segunda entrega se profundiza
en la generación de cabeceras y ficheros.
|
 |
CAPITULO
3.
Al principio de esta serie
vimos que para poder utilizar una librería run-time es nuestros
programas era necesario servirse de diversos ficheros especiales, según
el lenguaje que queramos emplear.
En los más habituales
estos ficheros son: ".bmap" en AmigaBASIC, "pragma"
en C y librerías explorables en C -si no se usan "pragma"-
y (al menos con las de usuario) Ensamblador.
Los tres se obtienen, más
o menos directamente, de unos ficheros que acompañan a todas
las run-time, llamados "file description" -descripción
de fichero-, mas popularmente conocidos por ".fd".
FICHEROS ".FD"
Un ".fd" es un
simple fichero ASCII formado por una serie de directivas, comentarios
y entradas a la librería organizadas de la forma siguiente:
- una línea que empiece
con los caracteres "##" es una directiva.
- Una línea que empiece
con el carácter "*" es un comentario.
- Cualquier otra línea
es una entrada a la librería -cada entrada corresponde a una
función, aunque representada en un formato especial-.
Las directivas son:
- NombreBase: Es la variable
global de tipo puntero en que se guarda la directión en memoria
donde estará la Base.
- bias n: Indica el valor
del primer _LVO de la Base ("n" suele ser 30).
- public: Indica que las
entradas a la libre´ria que van tras ella son accesibles a nuestros
programas -es decir, podemos utilizar las funciones representadas por
cada una-.
- private: Indica que las
entrafas que van tras ella no son accesibles a nuestros programas.
- end: Señala el fin
del fichero.
las entradas a la librería
tienen el siguiente formato:
nombre función (lista
de argumentos) (lista de registros). Tanto los argumentos como los registros
deben estar separados entre coman (",") aunque estos últimos
también pueden separarse con barras inclinadas ("/").
El fichero ".fd"
de nuestra libería, 2ilbm_lib.fd", lo tienen, como ya es
habitual, acompañando a este capítulo.
Como verán en él
aparecen cada una de las directivas comentadas excepto "private",
pues "ilbm.library" -al menos en esta su primera versión-
no contiene funciones que no deban ser utilizadas. bservarán
además que las entrafas estáne n el mismo orden en que
aparecen las funciones en el programa principal que desarrollamos en
el capítulo anterior. Esto debe ser así siempre.
Y ahora que ya tenemos ".fd"
vamos a ver como nos las ingeniamos para convertirlo en algo que pueda
servir para sacarle partido a la librería.
GENERANDO FICHEROS
Vamos a dividir esta sección
en tres apartados, uno apra cada tipo de fichero empleado con los lenguajes
de uso más común.
FICHEROS ".BMAP":
Son los necesarios para AmigaBASIC y aunque nuestra librería
no está pensada para ser utilizada con este lenguaje -sinceramente,
como yo hace siglos que no lo uso no he probado si funciona o no- vamos
a analizarlo y ver la forma de obtenerlos por si alguno de vosotros
esta interesado en emplear ilbm.library en programas BASIC.
Un fichero ".bmap"
tiene la siguiente estructura: noombre de función en caracteres
ASCII, terminado en un byte nulo (Hex. 00), vector de desplazamiento
(_LVO) dado en una palabra (16 bits) con signo negativo y una "tabal
de registros" de los argumentos (un byte por regitro) terminando
con un byte 0. Los registros se especifican de acuerdo a unas convenciones
de codificación preestablecidas que pueden encontrar en el manual
del AmigaBASIC (apéndice F, pág. A-18). En el caso de
funciones que tomen sus argumentos de la pila, al estilo del C, esta
tabla estará vacía.
Como ven son un tanto complejos
pero afortunadamente para obtener los contamos con la ayuda del propio
AmigaBASIC -aunque los valientes que se atrevan pueden intentar obtener
el ".bmap" de ilbm.library a mano-. La ayuda comentada está
en forma de programa en el disco Extras de la versión 1.2 y 1.3
del Workbench, se llama "ConvertFD" y genera ficheros ".bmap"
a partir de ficheros ".fd" automáticamente. Al ejecutarlo
nos informará sobre su uso.
FICHEROS "PRAGMA":
Se utilizan como ficheros de cabecera en lenguaje C para llamar a las
funciones de librerías run-time directamente, lo que evita enlazar
con librerías explorables de rutinas puente a las funciones originales
-más adelante veremos estas-. Esto, además hace que los
programas que usen "pragmas2 se ejecuten más rápidamente.
Hasta hace poco sólo
podían usarse en programas creados con SAS/Lattice, pero desde
la versión 5.0 de Aztec C también pueden emplearse con
este compilador -una ventaja añadida es que los "pragma"
para ambos paquetes son idénticos-.
Estos ficheros tienen la
composición siguiente:
- #pragma: es una instrucción
que forma parte de una rutina especial llamada a la función,
- libcall: idem,
- base: es el puntero a la
Base de la librería,
- rutina: es el nombre de
la función a la que se quiere llamar, -> offset: es el _LVO
a la función desde la Base y -> magic: contiene la descripción
de los registros de los argumentos y del registro en el que la función
devuelve su resultado, codificados según unas convenciones predefinidas
(¿dónde habré oído esto?) que podéis
ver en el manual de vuestro compilador.
Esta información se
completa con un indicador del número total de argumentos pasados
a la función. Al igual que los ".bmap" estos "pragma"
también pueden generarse de forma manual pero esto es todavía
más complicado que con los del BASIC. Una vez más el compilador
vendrá en nuestra ayuda. Tanto Lattice como Aztec incluyen programas
que generan ficheros "pragma" a partir de ".fd".
El de SAS/Lattice es "fd2pragma"
-desconozco el de Azted- y funciona así: (desde Shell o CLI)
fd2pragma ilbm_lib.fd ilbm.h. Una vez generado el fichero y para completarlo
al estilo de los ya incluidos en el directorio ":include/proto7"
del compilador podemos añadir, inmediatamente antes de las sentencias
progama, la declaración del puntero a ILBMBase y los prototipos
de las funciones.
Tal vez alguno se pregunte
porqué no incluyo el listado del fichero de cabecera correspondiente
al "pragma". Pues por una razón muy sencilla: aunque
no lo parezca este tipo de fichero puede presentar problemas según
la versión de "fd2pragma" con la que se cree.
Por ejemplo, la incluida
en Lattice 4.0 genera sentencias incorrectas si las funciones tienen
más de cuatro argumentos. Los que poseáis SAC C 5.10 y
Aztec C 5.0 no tendrán problemas pero es mejor que lo comprueben
leyendo atentamente el manual y analizando alguno de los que incluye
cada compilador para las librerías oficiales.
Si hay sentencias "pragma"
entre caracteres de comentario habrá que llamar a las funciones
correspondientes en la forma tradicional, o sea, enlazando ocn librerías
explorables. Y hablando del rey de Roma...
LIBRERIAS EXPLORABLES
Pues dicho queda: son el
tipo de ficheros necesarios pra programas en C que no utilicen "pragma"
(a la antigua usanza) y para Ensamblador, al menos con run-time de usuario.
Su estructura es la típica de las librerías de compilador,
es decir, una colección de módulos de código objeto
organizados de tal forma que pueda extraer los necesarios para ponerlos
dentro de nuestros programas. Cada módulo es en realidad una
rutina especial, llamada "stub routine" -algo así como
"rutina de anclaje"- que se encarga de poner los argumentos
en los registros apropiados para, a continuación, llamar a la
auténtica función utilizando su vector de salto (_LVO).
La información se completa con la definición de los _LVO
de cada función de la librería run-time -esto es además
muy útil para los programadores en Ensamblador, pues evita los
famosos "_LVOFunción EQU -XX", ya que basta con escirbir
en su lygar "XREF _LVOFuncisn" y dejar que sea el linker quien
se ocupe de averiguar el adecuado a tiempo de enlace-. El problema de
estas librerías explorables es su generación. Para ello
no podemos utilizar directamente los ficheros ".fd". Estos
solo servirán como referencia para conocer los registros utilizados
por cada función y el orden de estas en la run-time, orden que
debemos respetar a rajatabla. La librería debemos escribirla
a mano utilizando -de nuevo- Ensamblador.
Junto a este capítulo
tienen dos programas: "ilbm_stubs.s", en el que se desarrollan
las rutinas "stub" para cada función de "ilbm.library"
y "ilbm_lvos.s" que contiene las definiciones de los vectores
de salto. Para generar la librería explorable, a la que llamaremos
"ilbm.lib", siga los siguientes pasos con máximo cuidado
y atención:
1) Ensamble cada programa
exactamente igual que el del capítulo anterior.
2) Una el código objeto
de ambos, usando el comando JOIN del AmigaDOS de esta forma: JOIN ilbm_stubs.o
ilbm_lvos.o AS ilbm.lib. Naturalmente JOIN y AS pueden teclearse en
minúsculas (yo he usado mayúsculas sólo para resaltarlos).
3) Instale "ilbm.lib"
en el directorio ":lib/" de vuestro compilador, ensamblador
o mejor de ambos (no confundir con el ":Libs/" del Workbench).
|
Una
librería explorable es la típica de las librerías
de compilador,
es decir, una colección de módulos de código
objeto, organizados
de tal forma que se puedan extraer los necesarios para ponerlos
dentro de nuestros programas
|
|
Ahora ya podemos utilziar
"ilbm.library" en nuestro programas. Para ello basta con indicar
al linker que enlace con "ilbm.lib". Por cierto... ¿saben
por qué en los compiladores no hay, aparentemente, librerías
explorables con rutinas "stub" para las run-time oficiales?.
Se supone que tendrían
quee xistir una "exec.lib", "intuition.lib", etc.
Pues es fácil: las "stubs" correspondientes están
TODAS en "Amiga.lib". Y con esto concluímos por ahora.
Ya sólo nos queda escribir algunos ficheros de cabecera para
C y Ensamblador y ver algunos ejemplos sencillos sobre como utilizar
nuestra flamante run-time, pero eso lo dejaremos para el próximo
(y último) capítulo. Ademñas, los listados están
completos en los discos de la revista.
##base _ILBMBase ##bias 30 ##public CheckILBM(fich)(d0) GetBMHeader(fich,bmhd)(d0,a0) GetGfxMode(fich)(d0) GetColMap(fich,colores,planos)(d0,a0,d1) DisplayData(fich,bitmap,mascara,compresion)(d0,a0,d1,d2) PutILBM(fich)(d0) PutBMHeader(fich.bitmap,mascara,compresio,ancho_p,alto_p)(d0,a0,d1,d2,d3,d4) PutGFxMode(fich.modografico)(d0,d1) PutColMap(fich,viewport)(d0,a0) Savedata(fich,bitmap,mascara,compresion,bufmem)(d0,a0,d1,d2,a1) PutILBMSize(fich,fsize)(d0,d1) ##end ************************************************************** * MODULO : ilbm.lvos.s * * DESCRIPCION : definicion de LVOs (Library Vector Offsets). * * DESARROLLO : 19-06-92 - Creacion (V. Santos) * * Correspondiente a version 1.0 de la libreria * ************************************************************** * FICHEROS DE CABECERA ============================================================== INCDIR "sys:devpac/include.cbm/" INCLUDE "exec/types.i" INCLUDE "exec/libraries.i" SECTION_LVO,DATA * DEFINICION DE _LVOs ============================================================== ; LIBINIT inicializa un _LVO igual a -30 para saltar los primeros vectores ; de 6 bytes de las funciones estandar del sistema (Open/Close/Expunge/ExtFunc). LIBINIT ; LIBDEF define el valor actual de _LVO de una etiqueta y salta -6 bytes ; para preparar el siguiente _LVO. Cada etiqueta corresponde a una funcion de ilbm.library ;(el orden de asignaciones debe ser el mismo en que aparecen las funciones "ilbm.s"). LIBDEF _LVOCheckILBM ; asigna valor -30 XDEF _LVOCheckILBM LIBDEF _LVOGetBMHeader ; asigna valor -36 XDEF _LVOGetBMHeader LIBDEF _LVOGetGfxMode : -42 XDEF _LVOGetGfxMode LIBDEF _LVOGetColMap ; -48 XDEF _LVOGetColMap LIBDEF _LVODisplayData ; -54 XDEF _LVODisplayData LIBDEF _LVOPutILBM ; -60 XDEF _LVOPutILBM LIBDEF _LVOPutBMHeader ; -66 XDEF _LVOPutBMHeader LIBDEF _LVOPutGfxMode ; -72 XDEF _LVOPutGfxMode LIBDEF _LVOPutColMap ; -78 XDEF _LVOPutColMap LIBDEF _LVOSaveData ; -84 XDEF _LVOSaveData LIBDEF _LVOPutILBMSize ; -90 XDEF _LVOPutILBMSize END ******************************************************************* * MODULO : ilbm.stubs.s * * DESCRIPCION : rutinas de enlace con funciones de "ilbm.library" * * para programas en C y Ensamblador * * DESARROLLO : 19-06-92 - Creacion (V. Santos) * * Correspondientes a version 1.0 de la libreria * ******************************************************************* * FICHEROS DE CABECERA =================================================================== INCDIR "sys:devpac/include.cbm/" INCLUDE "exec/types.i" INCLUDE "exec/libraries.i" SECTION CSTUB,CODE * REFERENCIAS EXTERNAS =================================================================== XREF _ILBMBase ; a base de libreria XREF _LVOCheckILBM ; a vectores definidos en ilbm_lvos.s XREF _LVOGetBMHeader XREF _LVOGetGfxMode XREF _LVOGetColMap XREF _LVODisplayData XREF _LVOPutILBM XREF _LVOPutBMHeader XREF _LVOPutGfxMode XREF _LVOPutColMap XREF _LVOSaveData XREF _LVOPutILBMSize * DEFINICIONES EXTERNAS =================================================================== ; necesarias para hacer acesibles las rutinas stubs al programa del usuario XDEF _CheckILBM XDEF _GetBMHeader XDEF _GetGfxMode XDEF _GetColMap XDEF _DisplayData XDEF _PutILBM XDEF _PutBMHeader XDEF _PutGfxMode XDEF _PutColMap XDEF _SaveData XDEF _PutILBMSize * RUTINAS STUB ==================================================================== ; Estas rutinas toman los argumentos de la pila, los ponen en los ; registros apropiados y llaman a las funciones de ilbm.library ; a traves de sus vectores (_LVOs). El resultado se devuelve en d0. _CheckILBM: move.l a6,-(sp) ; preservar a6 move.l 8(sp),d0 ; poner argumentos en sus registros move.l _ILBMBase,a6 ; ptro a base de libreria en a6 jsr _LVOCheckILBM(a6) ; llamar a la funcion move.l (sp)+,a6 ; restaurar a6 rts ; volver con resultado en d0 _GetBMHeader: move.l a6,-(sp) move.l 8(sp),d0 move.l 12(sp),a0 move.l _ILBMBase,a6 jsr _LVOGetBMHeader(a6) move.l (sp)+,a6 rts _GetGfxMode: move.l a6,-(sp) move.l 8(sp),d0 move.l _ILBMBase,a6 jsr _LVOGetGfxMode(a6) move.l (sp)+,a6 rts _GetColMap: move.l a6,-(sp) move.l 8(sp),d0 move.l 12(sp),a0 move.l 16(sp),d1 move.l _ILBMBase,a6 jsr _LVOGetColMap(a6) move.l (sp)+,a6 rts _DisplayData: move.l a6,-(sp) move.l 8(sp),d0 move.l 12(sp),a0
|
|