preston@felix.UUCP (Preston Bannister) (11/15/87)
The following shell archive contains source that shows how to implement simple shared libraries on the Atari ST. There is also an example library and test program. Let me know what you think. # This is a shell archive. # Remove everything above and including the cut line. # Then run the rest of the file through sh. #----cut here-----cut here-----cut here-----cut here----# #!/bin/sh # shar: Shell Archiver # Run the following text with /bin/sh to create: # lib_init.c # libs.h # lib_inst.c # xtest.c # xlib.c # xlib.h # makefile # readme # libs.c # # This archive created: Fri Nov 13 18:39:13 1987 cat << \SHAR_EOF > lib_init.c /* Basic shared library support */ #include <osbind.h> #include "libs.h" Library LibSupportBase; /* Initialize shared library support */ int InitLibSupport () { register GetLibraryFunction find_lib; find_lib = (GetLibraryFunction)Setexc(LIB_FIND_VECTOR,-1L); if (find_lib) { LibSupportBase = (*find_lib)(LIBSUPPORT_NAME,LIBSUPPORT_VERSION); return (0L != LibSupportBase); } } SHAR_EOF cat << \SHAR_EOF > libs.h /* Definitions for shared library support written November, 1987 by Preston L. Bannister */ #define LIBSUPPORT_NAME "LibSupport" #define LIBSUPPORT_VERSION 1 #define LIB_FIND_VECTOR 0x200 #define LIB_ADD_VECTOR 0x201 typedef long (*Procedure)(); typedef Procedure * Library; typedef Library (*GetLibraryFunction)(); typedef struct _LibLink { struct _LibLink *next; char *name; int version; GetLibraryFunction entrance; } LibLink; extern Library LibSupportBase; extern void InstallLibrary(/*lib,keep*/); extern int InitLibSupport(); #ifndef LIBSUPPORT_IMPLEMENTATION #define AddLibrary (*LibSupportBase[0]) #define FindLibrary (*LibSupportBase[1]) #define ForEachLibrary (*LibSupportBase[2]) #endif SHAR_EOF cat << \SHAR_EOF > lib_inst.c /* Install a shared library */ #include <osbind.h> #include <bios.h> #include <basepage.h> #include "libs.h" typedef void (*vproc)(); /* Install this calling program as a shared library */ void InstallLibrary (lib,keep) LibLink *lib; /* IN link structure for the library to install */ long keep; /* IN amount of memory to keep for library */ { extern int end[]; register vproc add_lib; if (add_lib = (vproc)Setexc(LIB_ADD_VECTOR,-1L)) { (*add_lib)(lib); Ptermres(keep+(long)end-(long)BP,0); } } SHAR_EOF cat << \SHAR_EOF > xtest.c /* Shared library test written November, 1987 by Preston L. Bannister */ #include <debug.h> #include "libs.h" #include "xlib.h" Library XLibBase; /* points to our example library */ main () { if (InitLibSupport()) { printf("Attempting to find library '%s'\n",XLIB_NAME); if (XLibBase = (Library)FindLibrary(XLIB_NAME,XLIB_VERSION)) { printf("XLibBase 0x%08X\n",XLibBase); DEBUG(("Calling XLibP0 @ 0x%08X\n",XLibBase[0])); XLibP0(); DEBUG(("Calling XLibP1 @ 0x%08X\n",XLibBase[1])); XLibP1(); DEBUG(("Calling XLibP2 @ 0x%08X\n",XLibBase[2])); (void)XLibP2(); } else { printf("XLib not availible??\n"); } } exit(0); } SHAR_EOF cat << \SHAR_EOF > xlib.c /* Test Library Implementation */ #include "libs.h" #define XLIB_IMPLEMENTATION #include "xlib.h" #include <debug.h> /*===== Library Entry Points =====*/ void XLibP0 () { DEBUG(("in XLibP0\n")); } void XLibP1 () { DEBUG(("in XLibP1\n")); } void XLibP2 () { DEBUG(("in XLibP2\n")); } /*===== Overhead =====*/ /* array of entry points for this library */ Procedure XLibBase[] = { XLibP0, XLibP1, XLibP2 }; /* This routine is called by FindLibrary when a program wants to use the library. If the version number given by the caller is not acceptable we will return NULL. If we wanted to support more than one version with the same library, we could choose to return a different library base pointer for some versions. */ Library Entrance (version) int version; { DEBUG(("XLib Entrance with version %d\n",version)); if (version==XLIB_VERSION) return XLibBase; return 0L; } /* The link for this library */ LibLink XLib = { 0L, XLIB_NAME, XLIB_VERSION, Entrance }; /* initialization code for library */ int main () { /* install this library */ return InstallLibrary(&XLib,0L); } SHAR_EOF cat << \SHAR_EOF > xlib.h /* Example Library Interface */ #define XLIB_NAME "XLib" #define XLIB_VERSION 1 extern Library XLibBase; #ifndef XLIB_IMPLEMENTATION #define XLibP0 (*XLibBase[0]) #define XLibP1 (*XLibBase[1]) #define XLibP2 (*XLibBase[2]) #endif SHAR_EOF cat << \SHAR_EOF > makefile # makefile for loadable library code DEBUG = -DDEBUGGING CFLAGS = $(DEBUG) COMPILE = $(CC) $(CFLAGS) all : libs.prg xlib.prg xtest.prg # Shared library support code - installed at boot time libs.prg : libs.c $(COMPILE) libs.c # Example shared library xlib.prg : xlib.o lib_inst.o $(COMPILE) xlib.o lib_inst.o # Example program that uses the example shared library xtest.prg : xtest.o lib_init.o $(COMPILE) xtest.o lib_init.o libs.prg xlib.o xtest.o lib_inst.o lib_init.o : libs.h # Note! The order of installation is very important! install : libs.prg xlib.prg -rm c:\auto\libs.prg c:\auto\xlib.prg cp libs.prg xlib.prg c:\auto SRC = c:\include\debug.h libs.h libs.c xlib.h xlib.c xtest.c shar : shar readme makefile $(SRC) > libs.sh BIN = libs.prg xlib.prg xtest.prg arc : $(BIN) arc -u libs.arc readme makefile $(SRC) $(BIN) clean : $(RM) *.o *.prg libs.arc libs.sh SHAR_EOF cat << \SHAR_EOF > readme Shared Library Support - Experimental ------------------------------------- The included files make up the pieces you need to create and use shared libraries on the Atari ST. Note that this is a experimental version. I would like your feedback, especially constructive comments! :-) Shared libraries are a useful way of factoring the common code out of your programs. If you have a number of programs that use many of the same routines then you may want to use a shared library. In this scheme, shared libraries are installed at boot time. Each library maintains an array of pointers to it's externally accessible entry points. Programs that use a shared library acquire a pointer to the library's entry points. An entry point is called by jumping through the array. The program LIBS.PRG (containing the basic shared library support) should be placed in your AUTO folder, followed by the shared libraries themselves. An example library XLIB.PRG is included in this distribution. At boot time GEM will execute LIBS.PRG, installing the needed shared libraries support. As each library is executed it will perform any needed initialization and install itself in memory. Note that the order of the files in the AUTO folder is critical. The program LIBS.PRG must preceed any libraries. Also note that if a library is dependent on the presence of another library, then the library on which it depends must be installed first. One of the interested possibilities offered by this scheme is the ability to easily make incremental changes to existing libraries to which you may not have the source. If there is a known bug in a library, you could come up with a 'patch' that replaces the offending entry in the library's jump table with a pointer to your own routine. Support routines ---------------- -- int InitLibSupport() Called by any program using shared libraries to initialize the shared library support. Returns 0 if the shared library support is NOT installed. -- InstallLibrary(lib_link,keep) Called by a library to install itself. -- Library FindLibrary(lib_name,lib_version) Called by a program to find an installed library. Returns 0 if the library is not found, or a pointer to the library's array of entry points. This distribution contains the following: LIBS.H - included by all code using shared libraries LIBS.C - terminate & stay resident library support LIB_INIT.C - module linked in by programs using libraries LIB_INST.C - module linked in by installable libraries XLIB.H - interface to example library XLIB.C - example library XTEST.C - program that uses example library MAKEFILE - to put all of the above together This code was developed using Mark Williams C. SHAR_EOF cat << \SHAR_EOF > libs.c /* Shared library support. written October, 1987 by Preston L. Bannister */ #include <osbind.h> #include <bios.h> #include <basepage.h> #include <debug.h> #define LIBSUPPORT_IMPLEMENTATION #include "libs.h" LibLink *Libraries; /*===== entry points =====*/ /* Add a new library to the list of installed libraries. */ void AddLibrary (lib) LibLink *lib; /* IN a new library link */ { ENTER(AddLibrary); lib->next = Libraries; Libraries = lib; LEAVE(AddLibrary); } /* Find an installed library to match the given name and version. Returns a NULL pointer if the library was not found or if the entrance routine of the library itself decided it was not compatible with the given version. */ Library FindLibrary (name,version) char *name; /* IN name of the library to find */ int version; /* IN version number of library */ { LibLink *p = Libraries; ENTER(FindLibrary); DEBUG(("Looking for '%s'\n",name)); for (p=Libraries; p; p=p->next) { DEBUG(("Examining '%s'\n",p->name)); if (strcmp(name,p->name)==0) { LEAVE(FindLibrary:FoundIt); return ((*p->entrance)(version)); } } LEAVE(FindLibrary:NotFound); return 0L; } /* For each installed library, call the given procedure with a pointer to the given data and a pointer to the library link structure. */ void ForEachLibrary (proc,data) int (*proc)(); int *data; { LibLink *p = Libraries; ENTER(ForEachLibrary); for (p=Libraries; p; p=p->next) { if ((*proc)(data,p)) break; } LEAVE(ForEachLibrary); } /*===== =====*/ Procedure LibSupportBase[] = { AddLibrary, FindLibrary, ForEachLibrary }; /* Called when client finds this library */ Library Entrance (version) int version; { DEBUG(("In LibSupport Entrance\n")); switch (version) { case LIBSUPPORT_VERSION: return LibSupportBase; } return 0L; } LibLink LibSupport = { 0L, LIBSUPPORT_NAME, LIBSUPPORT_VERSION, Entrance }; main () { extern int end[]; DEBUG(("\nInstalling LibSupport\n")); Libraries = &LibSupport; Setexc(LIB_FIND_VECTOR,FindLibrary); DEBUG(("LibSupport vector 0x%04x set to 0x%08X FindLibrary\n", LIB_FIND_VECTOR,FindLibrary)); Setexc(LIB_ADD_VECTOR,AddLibrary); DEBUG(("LibSupport vector 0x%04x set to 0x%08X AddLibrary\n", LIB_ADD_VECTOR,AddLibrary)); Ptermres((long)end-(long)BP,0); DEBUG(("LibSupport installation failed!\n")); return 1; } SHAR_EOF # End of shell archive exit 0 -- Preston L. Bannister USENET : ucbvax!trwrb!felix!preston BIX : plb CompuServe : 71350,3505 GEnie : p.bannister