#!/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 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 * 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 X#endif X X#include X#include X#include X#include X#include X#include X#include X#include 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