Volver menú revistas Volver página anterior

El Amiga Me Encanta ha conseguido el permiso por escrito de IDG Comunications España para ofrecer los artículos de la revista Amiga World España.

N° 38 - Diciembre 1992

     LIBRERIAS     

 

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

Volver menú revistas Volver página anterior