#!/bin/sh
# This is a shell archive (shar 3.24)
# made 04/26/1998 16:50 UTC by jum@ibm
# Source directory /helios/ddpi/dl/rs6000
#
# existing files WILL be overwritten
#
# This shar contains:
# length  mode       name
# ------ ---------- ------------------------------------------
#   9303 -rw-rw-r-- README
#    832 -rw-rw-r-- Makefile
#    961 -r--r--r-- dlfcn.h
#  13756 -r--r--r-- dlfcn.c
#     32 -rw-rw-r-- dl.exp
#
if touch 2>&1 | fgrep '[-amc]' > /dev/null
 then TOUCH=touch
 else TOUCH=true
fi
# ============= README ==============
echo "x - extracting README (Text)"
sed 's/^X//' << 'SHAR_EOF' > README &&
XCopyright (c) 1992,1993,1995,1996,1997,1998 Jens-Uwe Mager,
XHELIOS Software GmbH, 30827 Garbsen, Germany
XNot derived from licensed software.
X
XPermission is granted to freely use, copy, modify, and redistribute
Xthis software, provided that the author is not construed to be liable
Xfor any results of using the software, alterations are clearly marked
Xas such, and this notice is not modified.
X
Xlibdl.a
X-------
X
XThis is an emulation library to emulate the SunOS/System V.4 functions
Xto access the runtime linker. The functions are emulated by using the
XAIX load() function and by reading the .loader section of the loaded
Xmodule to find the exports. The to be loaded module should be linked as
Xfollows (if using AIX 3):
X
X	cc -o module.so -bM:SRE -bE:module.exp -e _nostart $(OBJS)
X
XFor AIX 4:
X
X	cc -o module.so -bM:SRE -bE:module.exp -bnoentry $(OBJS)
X
XIf you want to reference symbols from the main part of the program in a
Xloaded module, you will have to link against the export file of the
Xmain part:
X
X	cc -o main -bE:main.exp $(MAIN_OBJS)
X	cc -o module.so -bM:SRE -bI:main.exp -bE:module.exp -bnoentry $(OBJS)
X
XNote that you explicitely have to specify what functions are supposed
Xto be accessible from your loaded modules, this is different from
XSunOS/System V.4 where any global is automatically exported. If you
Xwant to export all globals, the following script might be of help:
X
X#!/bin/sh
X/usr/ucb/nm -g $* | awk '$2 == "B" || $2 == "D" { print $3 }'
X
XThe module export file contains the symbols to be exported. Because
Xthis library uses the loader section, the final module.so file can be
Xstripped. C++ users should build their shared objects using the script
XmakeC++SharedLib (part of the IBM C++ compiler), this will make sure
Xthat constructors and destructors for static and global objects will be
Xcalled upon loading and unloading the module. GNU C++ users should use
Xthe -shared option to g++ to link the shared object:
X
X	g++ -o module.so -shared $(OBJS)
X
XIf the shared object does have permissions for anybody, the shared
Xobject will be loaded into the shared library segment and it will stay
Xthere even if the main application terminates. If you rebuild your
Xshared object after a bugfix and you want to make sure that you really
Xget the newest version you will have to use the "slibclean" command
Xbefore starting the application again to garbage collect the shared
Xlibrary segment. If the performance utilities (bosperf) are installed
Xyou can use the following command to see what shared objects are
Xloaded:
X
X/usr/lpp/bosperf/genkld | sort | uniq
X
XFor easier debugging you can avoid loading the shared object into the
Xshared library segment alltogether by removing permissions for others
Xfrom the module.so file:
X
Xchmod o-rwx module.so
X
XThis will ensure you get a fresh copy of the shared object for every
Xdlopen() call which is loaded into the application's data segment.
X
XUsage
X-----
X
Xvoid *dlopen(const char *path, int mode);
X
XThis routine loads the module pointed to by path and reads its export
Xtable. If the path does not contain a '/' character, dlopen will search
Xfor the module using the LIBPATH environment variable. It returns an
Xopaque handle to the module or NULL on error. The mode parameter can be
Xeither RTLD_LAZY (for lazy function binding) or RTLD_NOW for immediate
Xfunction binding. The AIX implementation currently does treat RTLD_NOW
Xthe same as RTLD_LAZY. The flag RTLD_GLOBAL might be or'ed into the
Xmode parameter to allow loaded modules to bind to global variables or
Xfunctions in other loaded modules loaded by dlopen(). If RTLD_GLOBAL is
Xnot specified, only globals from the main part of the executable or
Xshared libraries are used to look for undefined symbols in loaded
Xmodules.
X
X
Xvoid *dlsym(void *handle, const char *symbol);
X
XThis routine searches for the symbol in the module referred to by
Xhandle and returns its address. If the symbol could not be found, the
Xfunction returns NULL. The return value must be casted to a proper
Xfunction pointer before it can be used. SunOS/System V.4 allows handle
Xto be a NULL pointer to refer to the module the call is made from, this
Xis not implemented.
X
Xint dlclose(void *handle);
X
XThis routine unloads the module referred to by the handle and disposes
Xof any local storage. this function returns -1 on failure. Any function
Xpointers obtained through dlsym() should be considered invalid after
Xclosing a module.
X
XAs AIX caches shared objects in the shared library segment, function
Xpointers obtained through dlsym() might still work even though the
Xmodule has been unloaded. This can introduce subtle bugs that will
Xsegment fault later if AIX garbage collects or immediatly on
XSunOS/System V.4 as the text segment is unmapped.
X
Xchar *dlerror(void);
X
XThis routine can be used to retrieve a text message describing the most
Xrecent error that occured on on of the above routines. This function
Xreturns NULL if there is no error information.
X
XInitialization and termination handlers
X---------------------------------------
X
XThe emulation provides for an initialization and a termination
Xhandler.  The dlfcn.h file contains a structure declaration named
Xdl_info with following members:
X
X	void (*init)(void);
X	void (*fini)(void);
X
XThe init function is called upon first referencing the library. The
Xfini function is called at dlclose() time or when the process exits.
XThe module should declare a variable named dl_info that contains this
Xstructure which must be exported.  These functions correspond to the
Xdocumented _init() and _fini() functions of SunOS 4.x, but these are
Xappearently not implemented in SunOS.  When using SunOS 5.0, these
Xcorrespond to #pragma init and #pragma fini respectively. At the same
Xtime any static or global C++ object's constructors or destructors will
Xbe called.
X
XBUGS
X----
X
XPlease note that there is currently a problem with implicitely loaded
Xshared C++ libaries: if you refer to a shared C++ library from a loaded
Xmodule that is not yet used by the main program, the dlopen() emulator
Xdoes not notice this and does not call the static constructors for the
Ximplicitely loaded library. This can be easily demonstrated by
Xreferencing the C++ standard streams from a loaded module if the main
Xprogram is a plain C program.
X
XJens-Uwe Mager
X
XHELIOS Software GmbH
XSteinriede 3
X30827 Garbsen
XGermany
X
XPhone:		+49 5131 709320
XFAX:		+49 5131 709325
XInternet:	jum@helios.de
X
XRevison History
X---------------
X
XSCCS/s.dlfcn.c:
X
XD 1.13 98/04/26 18:46:51 jum 15 14	00015/00001/00565
XMRs:
XCOMMENTS:
XAIX 4.3 is missing the defines for BEGINNING, FSEEK and FREAD
Xfrom ldfcn.h. Compensate by defining these if not already defined.
X
XD 1.12 97/04/09 22:20:49 jum 14 13	00055/00059/00511
XMRs:
XCOMMENTS:
XFixed the way I did misuse the entry point as the origin of the loaded
Xmodule, this worked only if no entry point was used for linking the module.
XThe new code now does use the loader information to look for the module
Xwhich contains the TOC entry the pointer returned by load() points to, as
Xdiscussed via email with Steve Wilson (steve@ascend.com).
X
XD 1.11 96/04/10 20:12:51 jum 13 12	00037/00000/00533
XMRs:
XCOMMENTS:
XIntegrated the changes from John W. Eaton <jwe@bevo.che.wisc.edu> to initialize
Xg++ generated shared objects.
X
XD 1.10 96/02/15 17:42:44 jum 12 10	00012/00007/00521
XMRs:
XCOMMENTS:
Xthe C++ constructor and destructor chains are now called properly for either
XxlC 2 or xlC 3 (CSet++).
X
XD 1.9 95/09/22 11:09:38 markus 10 9	00001/00008/00527
XMRs:
XCOMMENTS:
XFix version number
X
XD 1.8 95/09/22 10:14:34 markus 9 8	00008/00001/00527
XMRs:
XCOMMENTS:
XAdded version number for dl lib
X
XD 1.7 95/08/14 19:08:38 jum 8 6	00026/00004/00502
XMRs:
XCOMMENTS:
XIntegrated the fixes from Kirk Benell (kirk@rsinc.com) to allow loading of
Xshared objects generated under AIX 4. Fixed bug that symbols with exactly
X8 characters would use garbage characters from the following symbol value.
X
XD 1.6 95/04/25 09:38:03 jum 6 5	00046/00006/00460
XMRs:
XCOMMENTS:
Xadded handling of C++ static constructors and destructors, added RTLD_GLOBAL to bind against other loaded modules
X
XD 1.5 93/02/14 20:14:17 jum 5 4	00002/00000/00464
XMRs:
XCOMMENTS:
Xadded path to dlopen error message to make clear where there error occured.
X
XD 1.4 93/01/03 19:13:56 jum 4 3	00061/00005/00403
XMRs:
XCOMMENTS:
Xto allow calling symbols in the main module call load with L_NOAUTODEFER and 
Xdo a loadbind later with the main module.
X
XD 1.3 92/12/27 20:59:55 jum 3 2	00066/00008/00342
XMRs:
XCOMMENTS:
Xadded search by L_GETINFO if module got loaded by LIBPATH
X
XD 1.2 92/08/16 17:45:43 jum 2 1	00074/00006/00276
XMRs:
XCOMMENTS:
Ximplemented initialize and terminate functions, added reference counting to avoid multiple loads of the same library
X
XD 1.1 92/08/02 18:08:45 jum 1 0	00282/00000/00000
XMRs:
XCOMMENTS:
XErstellungsdatum und -uhrzeit 92/08/02 18:08:45 von jum
X
XSCCS/s.dlfcn.h:
X
XD 1.4 95/04/25 09:36:52 jum 4 3	00018/00004/00028
XMRs:
XCOMMENTS:
Xadded RTLD_GLOBAL, include and C++ guards
X
XD 1.3 92/12/27 20:58:32 jum 3 2	00001/00001/00031
XMRs:
XCOMMENTS:
Xwe always have prototypes on RS/6000
X
XD 1.2 92/08/16 17:45:11 jum 2 1	00009/00000/00023
XMRs:
XCOMMENTS:
Xadded dl_info structure to implement initialize and terminate functions
X
XD 1.1 92/08/02 18:08:45 jum 1 0	00023/00000/00000
XMRs:
XCOMMENTS:
XErstellungsdatum und -uhrzeit 92/08/02 18:08:45 von jum
X
SHAR_EOF
$TOUCH -am 0426184898 README &&
chmod 0664 README ||
echo "restore of README failed"
set `wc -c README`;Wc_c=$1
if test "$Wc_c" != "9303"; then
	echo original size 9303, current size $Wc_c
fi
# ============= Makefile ==============
echo "x - extracting Makefile (Text)"
sed 's/^X//' << 'SHAR_EOF' > Makefile &&
X# %W% revision of %E%  %U%
X# This is an unpublished work copyright (c) 1992 HELIOS Software GmbH
X# 30827 Garbsen, Germany
X
X# Do not edit at HELIOS, edit GNUmakefile instead!
X
XSHELL=/bin/sh
XIPATH=
XDEFS=
XDEBUGFLAGS=-g -DDEBUG
XNODEBUGFLAGS=-O
XCFLAGS=$(IPATH) $(DEFS) $(NODEBUGFLAGS)
XTARGET=libdl.a
XDEST=/usr/local/lib
XHDRS=dlfcn.h
XSRCS=dlfcn.c
X#NOSTART=-e _nostart	# for AIX 3
XNOSTART=-bnoentry	# for AIX 4
XOBJS=$(SRCS:%.c=%.o)
X
Xall:		$(TARGET) dlfcn.c
X
Xdlfcn.o:	dlfcn.h
X
X$(TARGET):	$(OBJS) dl.exp
X		$(CC) $(CFLAGS) -o $@ $(OBJS) -bE:dl.exp -bM:SRE $(NOSTART) -lld
X
Xlint:
X		lint $(IPATH) $(DEFS) $(SRCS) >lintout
X
Xinfo:
X		sccs info
X
Xclean:
X		rm -f lintout a.out core *.o *-lg *% *~ tags deps%
X
Xclobber:	clean
X		rm -f $(TARGET) deps
X
Xinstall:	all
X		cp $(TARGETS) $(DEST)
X
Xshar:
X		shar README Makefile dlfcn.h dlfcn.c dl.exp >dlfcn.shar
SHAR_EOF
$TOUCH -am 0426184598 Makefile &&
chmod 0664 Makefile ||
echo "restore of Makefile failed"
set `wc -c Makefile`;Wc_c=$1
if test "$Wc_c" != "832"; then
	echo original size 832, current size $Wc_c
fi
# ============= dlfcn.h ==============
echo "x - extracting dlfcn.h (Text)"
sed 's/^X//' << 'SHAR_EOF' > dlfcn.h &&
X/*
X * @(#)dlfcn.h	1.4 revision of 95/04/25  09:36:52
X * This is an unpublished work copyright (c) 1992 HELIOS Software GmbH
X * 30159 Hannover, Germany
X */
X
X#ifndef __dlfcn_h__
X#define __dlfcn_h__
X
X#ifdef __cplusplus
Xextern "C" {
X#endif
X
X/*
X * Mode flags for the dlopen routine.
X */
X#define RTLD_LAZY	1	/* lazy function call binding */
X#define RTLD_NOW	2	/* immediate function call binding */
X#define RTLD_GLOBAL	0x100	/* allow symbols to be global */
X
X/*
X * To be able to intialize, a library may provide a dl_info structure
X * that contains functions to be called to initialize and terminate.
X */
Xstruct dl_info {
X	void (*init)(void);
X	void (*fini)(void);
X};
X
X#if __STDC__ || defined(_IBMR2)
Xvoid *dlopen(const char *path, int mode);
Xvoid *dlsym(void *handle, const char *symbol);
Xchar *dlerror(void);
Xint dlclose(void *handle);
X#else
Xvoid *dlopen();
Xvoid *dlsym();
Xchar *dlerror();
Xint dlclose();
X#endif
X
X#ifdef __cplusplus
X}
X#endif
X
X#endif /* __dlfcn_h__ */
SHAR_EOF
$TOUCH -am 0425093895 dlfcn.h &&
chmod 0444 dlfcn.h ||
echo "restore of dlfcn.h failed"
set `wc -c dlfcn.h`;Wc_c=$1
if test "$Wc_c" != "961"; then
	echo original size 961, current size $Wc_c
fi
# ============= dlfcn.c ==============
echo "x - extracting dlfcn.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > dlfcn.c &&
X/*
X * @(#)dlfcn.c	1.13 revision of 98/04/26  18:46:51
X * This is an unpublished work copyright (c) 1992 HELIOS Software GmbH
X * 30827 Garbsen, Germany
X */
X
X/*
X * Changes marked with `--jwe' were made on April 7 1996 by John W. Eaton
X * <jwe@bevo.che.wisc.edu> to support g++ and/or use with Octave.
X */
X
X/*
X * This makes my life easier with Octave.  --jwe
X */
X#ifdef HAVE_CONFIG_H
X#include <config.h>
X#endif
X
X#include <stdio.h>
X#include <errno.h>
X#include <string.h>
X#include <stdlib.h>
X#include <sys/types.h>
X#include <sys/ldr.h>
X#include <a.out.h>
X#include <ldfcn.h>
X#include "dlfcn.h"
X
X/*
X * AIX 4.3 does remove some useful definitions from ldfcn.h. Define
X * these here to compensate for that lossage.
X */
X#ifndef BEGINNING
X# define BEGINNING SEEK_SET
X#endif
X#ifndef FSEEK
X# define FSEEK(ldptr,o,p)	fseek(IOPTR(ldptr),(p==BEGINNING)?(OFFSET(ldptr) +o):o,p)
X#endif
X#ifndef FREAD
X# define FREAD(p,s,n,ldptr)	fread(p,s,n,IOPTR(ldptr))
X#endif
X
X/*
X * We simulate dlopen() et al. through a call to load. Because AIX has
X * no call to find an exported symbol we read the loader section of the
X * loaded module and build a list of exported symbols and their virtual
X * address.
X */
X
Xtypedef struct {
X	char		*name;		/* the symbols's name */
X	void		*addr;		/* its relocated virtual address */
X} Export, *ExportPtr;
X
X/*
X * xlC uses the following structure to list its constructors and
X * destructors. This is gleaned from the output of munch.
X */
Xtypedef struct {
X	void (*init)(void);		/* call static constructors */
X	void (*term)(void);		/* call static destructors */
X} Cdtor, *CdtorPtr;
X
Xtypedef void (*GccCDtorPtr)(void);
X
X/*
X * The void * handle returned from dlopen is actually a ModulePtr.
X */
Xtypedef struct Module {
X	struct Module	*next;
X	char		*name;		/* module name for refcounting */
X	int		refCnt;		/* the number of references */
X	void		*entry;		/* entry point from load */
X	struct dl_info	*info;		/* optional init/terminate functions */
X	CdtorPtr	cdtors;		/* optional C++ constructors */
X	GccCDtorPtr	gcc_ctor;	/* g++ constructors  --jwe */
X	GccCDtorPtr	gcc_dtor;	/* g++ destructors  --jwe */
X	int		nExports;	/* the number of exports found */
X	ExportPtr	exports;	/* the array of exports */
X} Module, *ModulePtr;
X
X/*
X * We keep a list of all loaded modules to be able to call the fini
X * handlers and destructors at atexit() time.
X */
Xstatic ModulePtr modList;
X
X/*
X * The last error from one of the dl* routines is kept in static
X * variables here. Each error is returned only once to the caller.
X */
Xstatic char errbuf[BUFSIZ];
Xstatic int errvalid;
X
X/*
X * The `fixed' gcc header files on AIX 3.2.5 provide a prototype for
X * strdup().  --jwe
X */
X#ifndef HAVE_STRDUP
Xextern char *strdup(const char *);
X#endif
Xstatic void caterr(char *);
Xstatic int readExports(ModulePtr);
Xstatic void terminate(void);
Xstatic void *findMain(void);
X
Xvoid *dlopen(const char *path, int mode)
X{
X	register ModulePtr mp;
X	static void *mainModule;
X
X	/*
X	 * Upon the first call register a terminate handler that will
X	 * close all libraries. Also get a reference to the main module
X	 * for use with loadbind.
X	 */
X	if (!mainModule) {
X		if ((mainModule = findMain()) == NULL)
X			return NULL;
X		atexit(terminate);
X	}
X	/*
X	 * Scan the list of modules if we have the module already loaded.
X	 */
X	for (mp = modList; mp; mp = mp->next)
X		if (strcmp(mp->name, path) == 0) {
X			mp->refCnt++;
X			return mp;
X		}
X	if ((mp = (ModulePtr)calloc(1, sizeof(*mp))) == NULL) {
X		errvalid++;
X		strcpy(errbuf, "calloc: ");
X		strcat(errbuf, strerror(errno));
X		return NULL;
X	}
X	if ((mp->name = strdup(path)) == NULL) {
X		errvalid++;
X		strcpy(errbuf, "strdup: ");
X		strcat(errbuf, strerror(errno));
X		free(mp);
X		return NULL;
X	}
X	/*
X	 * load should be declared load(const char *...). Thus we
X	 * cast the path to a normal char *. Ugly.
X	 */
X	if ((mp->entry = (void *)load((char *)path, L_NOAUTODEFER, NULL)) == NULL) {
X		free(mp->name);
X		free(mp);
X		errvalid++;
X		strcpy(errbuf, "dlopen: ");
X		strcat(errbuf, path);
X		strcat(errbuf, ": ");
X		/*
X		 * If AIX says the file is not executable, the error
X		 * can be further described by querying the loader about
X		 * the last error.
X		 */
X		if (errno == ENOEXEC) {
X			char *tmp[BUFSIZ/sizeof(char *)];
X			if (loadquery(L_GETMESSAGES, tmp, sizeof(tmp)) == -1)
X				strcpy(errbuf, strerror(errno));
X			else {
X				char **p;
X				for (p = tmp; *p; p++)
X					caterr(*p);
X			}
X		} else
X			strcat(errbuf, strerror(errno));
X		return NULL;
X	}
X	mp->refCnt = 1;
X	mp->next = modList;
X	modList = mp;
X	if (loadbind(0, mainModule, mp->entry) == -1) {
X		dlclose(mp);
X		errvalid++;
X		strcpy(errbuf, "loadbind: ");
X		strcat(errbuf, strerror(errno));
X		return NULL;
X	}
X	/*
X	 * If the user wants global binding, loadbind against all other
X	 * loaded modules.
X	 */
X	if (mode & RTLD_GLOBAL) {
X		register ModulePtr mp1;
X		for (mp1 = mp->next; mp1; mp1 = mp1->next)
X			if (loadbind(0, mp1->entry, mp->entry) == -1) {
X				dlclose(mp);
X				errvalid++;
X				strcpy(errbuf, "loadbind: ");
X				strcat(errbuf, strerror(errno));
X				return NULL;
X			}
X	}
X	if (readExports(mp) == -1) {
X		dlclose(mp);
X		return NULL;
X	}
X	/*
X	 * If there is a dl_info structure, call the init function.
X	 */
X	if (mp->info = (struct dl_info *)dlsym(mp, "dl_info")) {
X		if (mp->info->init)
X			(*mp->info->init)();
X	} else
X		errvalid = 0;
X	/*
X	 * If the shared object was compiled using xlC we will need
X	 * to call static constructors (and later on dlclose destructors).
X	 */
X	if (mp->cdtors = (CdtorPtr)dlsym(mp, "__cdtors")) {
X		CdtorPtr cp = mp->cdtors;
X		while (cp->init || cp->term) {
X			if (cp->init && cp->init != (void (*)(void))0xffffffff)
X				(*cp->init)();
X			cp++;
X		}
X	/*
X	 * If the shared object was compiled using g++, we will need
X	 * to call global constructors using the _GLOBAL__DI function,
X	 * and later, global destructors using the _GLOBAL_DD
X	 * funciton.  --jwe
X	 */
X	} else if (mp->gcc_ctor = (GccCDtorPtr)dlsym(mp, "_GLOBAL__DI")) {
X		(*mp->gcc_ctor)();
X		mp->gcc_dtor = (GccCDtorPtr)dlsym(mp, "_GLOBAL__DD"); 
X	} else
X		errvalid = 0;
X	return mp;
X}
X
X/*
X * Attempt to decipher an AIX loader error message and append it
X * to our static error message buffer.
X */
Xstatic void caterr(char *s)
X{
X	register char *p = s;
X
X	while (*p >= '0' && *p <= '9')
X		p++;
X	switch(atoi(s)) {
X	case L_ERROR_TOOMANY:
X		strcat(errbuf, "to many errors");
X		break;
X	case L_ERROR_NOLIB:
X		strcat(errbuf, "can't load library");
X		strcat(errbuf, p);
X		break;
X	case L_ERROR_UNDEF:
X		strcat(errbuf, "can't find symbol");
X		strcat(errbuf, p);
X		break;
X	case L_ERROR_RLDBAD:
X		strcat(errbuf, "bad RLD");
X		strcat(errbuf, p);
X		break;
X	case L_ERROR_FORMAT:
X		strcat(errbuf, "bad exec format in");
X		strcat(errbuf, p);
X		break;
X	case L_ERROR_ERRNO:
X		strcat(errbuf, strerror(atoi(++p)));
X		break;
X	default:
X		strcat(errbuf, s);
X		break;
X	}
X}
X
Xvoid *dlsym(void *handle, const char *symbol)
X{
X	register ModulePtr mp = (ModulePtr)handle;
X	register ExportPtr ep;
X	register int i;
X
X	/*
X	 * Could speed up the search, but I assume that one assigns
X	 * the result to function pointers anyways.
X	 */
X	for (ep = mp->exports, i = mp->nExports; i; i--, ep++)
X		if (strcmp(ep->name, symbol) == 0)
X			return ep->addr;
X	errvalid++;
X	strcpy(errbuf, "dlsym: undefined symbol ");
X	strcat(errbuf, symbol);
X	return NULL;
X}
X
Xchar *dlerror(void)
X{
X	if (errvalid) {
X		errvalid = 0;
X		return errbuf;
X	}
X	return NULL;
X}
X
Xint dlclose(void *handle)
X{
X	register ModulePtr mp = (ModulePtr)handle;
X	int result;
X	register ModulePtr mp1;
X
X	if (--mp->refCnt > 0)
X		return 0;
X	if (mp->info && mp->info->fini)
X		(*mp->info->fini)();
X	if (mp->cdtors) {
X		CdtorPtr cp = mp->cdtors;
X		while (cp->init || cp->term) {
X			if (cp->term && cp->init != (void (*)(void))0xffffffff)
X				(*cp->term)();
X			cp++;
X		}
X	/*
X	 * If the function to handle global destructors for g++
X	 * exists, call it.  --jwe
X	 */
X	} else if (mp->gcc_dtor) {
X	        (*mp->gcc_dtor)();
X	}
X	result = unload(mp->entry);
X	if (result == -1) {
X		errvalid++;
X		strcpy(errbuf, strerror(errno));
X	}
X	if (mp->exports) {
X		register ExportPtr ep;
X		register int i;
X		for (ep = mp->exports, i = mp->nExports; i; i--, ep++)
X			if (ep->name)
X				free(ep->name);
X		free(mp->exports);
X	}
X	if (mp == modList)
X		modList = mp->next;
X	else {
X		for (mp1 = modList; mp1; mp1 = mp1->next)
X			if (mp1->next == mp) {
X				mp1->next = mp->next;
X				break;
X			}
X	}
X	free(mp->name);
X	free(mp);
X	return result;
X}
X
Xstatic void terminate(void)
X{
X	while (modList)
X		dlclose(modList);
X}
X
X/*
X * Build the export table from the XCOFF .loader section.
X */
Xstatic int readExports(ModulePtr mp)
X{
X	LDFILE *ldp = NULL;
X	SCNHDR sh, shdata;
X	LDHDR *lhp;
X	char *ldbuf;
X	LDSYM *ls;
X	int i;
X	ExportPtr ep;
X	struct ld_info *lp;
X	char *buf;
X	int size = 4*1024;
X	void *dataorg;
X
X	/*
X	 * The module might be loaded due to the LIBPATH
X	 * environment variable. Search for the loaded
X	 * module using L_GETINFO.
X	 */
X	if ((buf = malloc(size)) == NULL) {
X		errvalid++;
X		strcpy(errbuf, "readExports: ");
X		strcat(errbuf, strerror(errno));
X		return -1;
X	}
X	while ((i = loadquery(L_GETINFO, buf, size)) == -1 && errno == ENOMEM) {
X		free(buf);
X		size += 4*1024;
X		if ((buf = malloc(size)) == NULL) {
X			errvalid++;
X			strcpy(errbuf, "readExports: ");
X			strcat(errbuf, strerror(errno));
X			return -1;
X		}
X	}
X	if (i == -1) {
X		errvalid++;
X		strcpy(errbuf, "readExports: ");
X		strcat(errbuf, strerror(errno));
X		free(buf);
X		return -1;
X	}
X	/*
X	 * Traverse the list of loaded modules. The entry point
X	 * returned by load() does actually point to the TOC
X	 * entry contained in the data segment.
X	 */
X	lp = (struct ld_info *)buf;
X	while (lp) {
X		if ((unsigned long)mp->entry >= (unsigned long)lp->ldinfo_dataorg &&
X		    (unsigned long)mp->entry < (unsigned long)lp->ldinfo_dataorg +
X		      lp->ldinfo_datasize) {
X			dataorg = lp->ldinfo_dataorg;
X			ldp = ldopen(lp->ldinfo_filename, ldp);
X			break;
X		}
X		if (lp->ldinfo_next == 0)
X			lp = NULL;
X		else
X			lp = (struct ld_info *)((char *)lp + lp->ldinfo_next);
X	}
X	free(buf);
X	if (!ldp) {
X		errvalid++;
X		strcpy(errbuf, "readExports: ");
X		strcat(errbuf, strerror(errno));
X		return -1;
X	}
X	if (TYPE(ldp) != U802TOCMAGIC) {
X		errvalid++;
X		strcpy(errbuf, "readExports: bad magic");
X		while(ldclose(ldp) == FAILURE)
X			;
X		return -1;
X	}
X	/*
X	 * Get the padding for the data section. This is needed for
X	 * AIX 4.1 compilers. This is used when building the final
X	 * function pointer to the exported symbol.
X	 */
X	if (ldnshread(ldp, _DATA, &shdata) != SUCCESS) {
X		errvalid++;
X		strcpy(errbuf, "readExports: cannot read data section header");
X		while(ldclose(ldp) == FAILURE)
X			;
X		return -1;
X	}
X	if (ldnshread(ldp, _LOADER, &sh) != SUCCESS) {
X		errvalid++;
X		strcpy(errbuf, "readExports: cannot read loader section header");
X		while(ldclose(ldp) == FAILURE)
X			;
X		return -1;
X	}
X	/*
X	 * We read the complete loader section in one chunk, this makes
X	 * finding long symbol names residing in the string table easier.
X	 */
X	if ((ldbuf = (char *)malloc(sh.s_size)) == NULL) {
X		errvalid++;
X		strcpy(errbuf, "readExports: ");
X		strcat(errbuf, strerror(errno));
X		while(ldclose(ldp) == FAILURE)
X			;
X		return -1;
X	}
X	if (FSEEK(ldp, sh.s_scnptr, BEGINNING) != OKFSEEK) {
X		errvalid++;
X		strcpy(errbuf, "readExports: cannot seek to loader section");
X		free(ldbuf);
X		while(ldclose(ldp) == FAILURE)
X			;
X		return -1;
X	}
X	if (FREAD(ldbuf, sh.s_size, 1, ldp) != 1) {
X		errvalid++;
X		strcpy(errbuf, "readExports: cannot read loader section");
X		free(ldbuf);
X		while(ldclose(ldp) == FAILURE)
X			;
X		return -1;
X	}
X	lhp = (LDHDR *)ldbuf;
X	ls = (LDSYM *)(ldbuf+LDHDRSZ);
X	/*
X	 * Count the number of exports to include in our export table.
X	 */
X	for (i = lhp->l_nsyms; i; i--, ls++) {
X		if (!LDR_EXPORT(*ls))
X			continue;
X		mp->nExports++;
X	}
X	if ((mp->exports = (ExportPtr)calloc(mp->nExports, sizeof(*mp->exports))) == NULL) {
X		errvalid++;
X		strcpy(errbuf, "readExports: ");
X		strcat(errbuf, strerror(errno));
X		free(ldbuf);
X		while(ldclose(ldp) == FAILURE)
X			;
X		return -1;
X	}
X	/*
X	 * Fill in the export table. All entries are relative to
X	 * the beginning of the data origin.
X	 */
X	ep = mp->exports;
X	ls = (LDSYM *)(ldbuf+LDHDRSZ);
X	for (i = lhp->l_nsyms; i; i--, ls++) {
X		char *symname;
X		char tmpsym[SYMNMLEN+1];
X		if (!LDR_EXPORT(*ls))
X			continue;
X		if (ls->l_zeroes == 0)
X			symname = ls->l_offset+lhp->l_stoff+ldbuf;
X		else {
X			/*
X			 * The l_name member is not zero terminated, we
X			 * must copy the first SYMNMLEN chars and make
X			 * sure we have a zero byte at the end.
X			 */
X			strncpy(tmpsym, ls->l_name, SYMNMLEN);
X			tmpsym[SYMNMLEN] = '\0';
X			symname = tmpsym;
X		}
X		ep->name = strdup(symname);
X		ep->addr = (void *)((unsigned long)dataorg +
X					ls->l_value - shdata.s_vaddr);
X		ep++;
X	}
X	free(ldbuf);
X	while(ldclose(ldp) == FAILURE)
X		;
X	return 0;
X}
X
X/*
X * Find the main modules data origin. This is used as export pointer
X * for loadbind() to be able to resolve references to the main part.
X */
Xstatic void * findMain(void)
X{
X	struct ld_info *lp;
X	char *buf;
X	int size = 4*1024;
X	int i;
X	void *ret;
X
X	if ((buf = malloc(size)) == NULL) {
X		errvalid++;
X		strcpy(errbuf, "findMain: ");
X		strcat(errbuf, strerror(errno));
X		return NULL;
X	}
X	while ((i = loadquery(L_GETINFO, buf, size)) == -1 && errno == ENOMEM) {
X		free(buf);
X		size += 4*1024;
X		if ((buf = malloc(size)) == NULL) {
X			errvalid++;
X			strcpy(errbuf, "findMain: ");
X			strcat(errbuf, strerror(errno));
X			return NULL;
X		}
X	}
X	if (i == -1) {
X		errvalid++;
X		strcpy(errbuf, "findMain: ");
X		strcat(errbuf, strerror(errno));
X		free(buf);
X		return NULL;
X	}
X	/*
X	 * The first entry is the main module. The data segment
X	 * starts with the TOC entries for all exports, so the
X	 * data segment origin works as argument for loadbind.
X	 */
X	lp = (struct ld_info *)buf;
X	ret = lp->ldinfo_dataorg;
X	free(buf);
X	return ret;
X}
SHAR_EOF
$TOUCH -am 0426184898 dlfcn.c &&
chmod 0444 dlfcn.c ||
echo "restore of dlfcn.c failed"
set `wc -c dlfcn.c`;Wc_c=$1
if test "$Wc_c" != "13756"; then
	echo original size 13756, current size $Wc_c
fi
# ============= dl.exp ==============
echo "x - extracting dl.exp (Text)"
sed 's/^X//' << 'SHAR_EOF' > dl.exp &&
X#!
Xdlopen
Xdlclose
Xdlsym
Xdlerror
SHAR_EOF
$TOUCH -am 0327144097 dl.exp &&
chmod 0664 dl.exp ||
echo "restore of dl.exp failed"
set `wc -c dl.exp`;Wc_c=$1
if test "$Wc_c" != "32"; then
	echo original size 32, current size $Wc_c
fi
exit 0
