[comp.sys.atari.st] Support for shared libraries on the Atari ST

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