3 * Written: 8/31/94 by Wayne Scott (wscott@ichips.intel.com)
5 * All I did was take Jens-Uwe Mager's libdl emulation library for
6 * AIX and merged it with the dl_dlopen.xs file to create a dynamic library
7 * package that works for AIX.
9 * I did change all malloc's, free's, strdup's, calloc's to use the perl
10 * equilvant. I also removed some stuff we will not need. Call fini()
11 * on statup... It can probably be trimmed more.
15 * @(#)dlfcn.c 1.5 revision of 93/02/14 20:14:17
16 * This is an unpublished work copyright (c) 1992 Helios Software GmbH
17 * 3000 Hannover 1, Germany
27 #include <sys/types.h>
32 /* If using PerlIO, redefine these macros from <ldfcn.h> */
34 #define FSEEK(ldptr,o,p) PerlIO_seek(IOPTR(ldptr),(p==BEGINNING)?(OFFSET(ldptr)+o):o,p)
35 #define FREAD(p,s,n,ldptr) PerlIO_read(IOPTR(ldptr),p,s*n)
39 * We simulate dlopen() et al. through a call to load. Because AIX has
40 * no call to find an exported symbol we read the loader section of the
41 * loaded module and build a list of exported symbols and their virtual
46 char *name; /* the symbols's name */
47 void *addr; /* its relocated virtual address */
51 * The void * handle returned from dlopen is actually a ModulePtr.
53 typedef struct Module {
55 char *name; /* module name for refcounting */
56 int refCnt; /* the number of references */
57 void *entry; /* entry point from load */
58 int nExports; /* the number of exports found */
59 ExportPtr exports; /* the array of exports */
63 * We keep a list of all loaded modules to be able to call the fini
64 * handlers at atexit() time.
66 static ModulePtr modList;
69 * The last error from one of the dl* routines is kept in static
70 * variables here. Each error is returned only once to the caller.
72 static char errbuf[BUFSIZ];
75 static void caterr(char *);
76 static int readExports(ModulePtr);
77 static void terminate(void);
78 static void *findMain(void);
80 char *strerrorcat(char *str, int err) {
82 strerror_r(err, buf, sizeof(buf));
86 char *strerrorcpy(char *str, int err) {
88 strerror_r(err, buf, sizeof(buf));
94 void *dlopen(char *path, int mode)
96 register ModulePtr mp;
97 static void *mainModule;
100 * Upon the first call register a terminate handler that will
101 * close all libraries. Also get a reference to the main module
102 * for use with loadbind.
105 if ((mainModule = findMain()) == NULL)
110 * Scan the list of modules if have the module already loaded.
112 for (mp = modList; mp; mp = mp->next)
113 if (strcmp(mp->name, path) == 0) {
117 Newz(1000,mp,1,Module);
120 strcpy(errbuf, "Newz: ");
121 strerrorcat(errbuf, errno);
125 if ((mp->name = savepv(path)) == NULL) {
127 strcpy(errbuf, "savepv: ");
128 strerrorcat(errbuf, errno);
133 * load should be declared load(const char *...). Thus we
134 * cast the path to a normal char *. Ugly.
136 if ((mp->entry = (void *)load((char *)path, L_NOAUTODEFER, NULL)) == NULL) {
140 strcpy(errbuf, "dlopen: ");
141 strcat(errbuf, path);
142 strcat(errbuf, ": ");
144 * If AIX says the file is not executable, the error
145 * can be further described by querying the loader about
148 if (errno == ENOEXEC) {
149 char *tmp[BUFSIZ/sizeof(char *)];
150 if (loadquery(L_GETMESSAGES, tmp, sizeof(tmp)) == -1)
151 strerrorcpy(errbuf, errno);
154 for (p = tmp; *p; p++)
158 strerrorcat(errbuf, errno);
164 if (loadbind(0, mainModule, mp->entry) == -1) {
167 strcpy(errbuf, "loadbind: ");
168 strerrorcat(errbuf, errno);
171 if (readExports(mp) == -1) {
179 * Attempt to decipher an AIX loader error message and append it
180 * to our static error message buffer.
182 static void caterr(char *s)
184 register char *p = s;
186 while (*p >= '0' && *p <= '9')
189 case L_ERROR_TOOMANY:
190 strcat(errbuf, "to many errors");
193 strcat(errbuf, "can't load library");
197 strcat(errbuf, "can't find symbol");
201 strcat(errbuf, "bad RLD");
205 strcat(errbuf, "bad exec format in");
209 strerrorcat(errbuf, atoi(++p));
217 void *dlsym(void *handle, const char *symbol)
219 register ModulePtr mp = (ModulePtr)handle;
220 register ExportPtr ep;
224 * Could speed up search, but I assume that one assigns
225 * the result to function pointers anyways.
227 for (ep = mp->exports, i = mp->nExports; i; i--, ep++)
228 if (strcmp(ep->name, symbol) == 0)
231 strcpy(errbuf, "dlsym: undefined symbol ");
232 strcat(errbuf, symbol);
245 int dlclose(void *handle)
247 register ModulePtr mp = (ModulePtr)handle;
249 register ModulePtr mp1;
251 if (--mp->refCnt > 0)
253 result = unload(mp->entry);
256 strerrorcpy(errbuf, errno);
259 register ExportPtr ep;
261 for (ep = mp->exports, i = mp->nExports; i; i--, ep++)
264 safefree(mp->exports);
269 for (mp1 = modList; mp1; mp1 = mp1->next)
270 if (mp1->next == mp) {
271 mp1->next = mp->next;
280 static void terminate(void)
286 /* Added by Wayne Scott
287 * This is needed because the ldopen system call calls
288 * calloc to allocated a block of date. The ldclose call calls free.
289 * Without this we get this system calloc and perl's free, resulting
290 * in a "Bad free" message. This way we always use perl's malloc.
292 void *calloc(size_t ne, size_t sz)
296 out = (void *) safemalloc(ne*sz);
302 * Build the export table from the XCOFF .loader section.
304 static int readExports(ModulePtr mp)
314 if ((ldp = ldopen(mp->name, ldp)) == NULL) {
318 if (errno != ENOENT) {
320 strcpy(errbuf, "readExports: ");
321 strerrorcat(errbuf, errno);
325 * The module might be loaded due to the LIBPATH
326 * environment variable. Search for the loaded
327 * module using L_GETINFO.
329 if ((buf = safemalloc(size)) == NULL) {
331 strcpy(errbuf, "readExports: ");
332 strerrorcat(errbuf, errno);
335 while ((i = loadquery(L_GETINFO, buf, size)) == -1 && errno == ENOMEM) {
338 if ((buf = safemalloc(size)) == NULL) {
340 strcpy(errbuf, "readExports: ");
341 strerrorcat(errbuf, errno);
347 strcpy(errbuf, "readExports: ");
348 strerrorcat(errbuf, errno);
353 * Traverse the list of loaded modules. The entry point
354 * returned by load() does actually point to the data
357 lp = (struct ld_info *)buf;
359 if (lp->ldinfo_dataorg == mp->entry) {
360 ldp = ldopen(lp->ldinfo_filename, ldp);
363 if (lp->ldinfo_next == 0)
366 lp = (struct ld_info *)((char *)lp + lp->ldinfo_next);
371 strcpy(errbuf, "readExports: ");
372 strerrorcat(errbuf, errno);
376 if (TYPE(ldp) != U802TOCMAGIC) {
378 strcpy(errbuf, "readExports: bad magic");
379 while(ldclose(ldp) == FAILURE)
383 if (ldnshread(ldp, _LOADER, &sh) != SUCCESS) {
385 strcpy(errbuf, "readExports: cannot read loader section header");
386 while(ldclose(ldp) == FAILURE)
391 * We read the complete loader section in one chunk, this makes
392 * finding long symbol names residing in the string table easier.
394 if ((ldbuf = (char *)safemalloc(sh.s_size)) == NULL) {
396 strcpy(errbuf, "readExports: ");
397 strerrorcat(errbuf, errno);
398 while(ldclose(ldp) == FAILURE)
402 if (FSEEK(ldp, sh.s_scnptr, BEGINNING) != OKFSEEK) {
404 strcpy(errbuf, "readExports: cannot seek to loader section");
406 while(ldclose(ldp) == FAILURE)
410 /* This first case is a hack, since it assumes that the 3rd parameter to
411 FREAD is 1. See the redefinition of FREAD above to see how this works. */
413 if (FREAD(ldbuf, sh.s_size, 1, ldp) != sh.s_size) {
415 if (FREAD(ldbuf, sh.s_size, 1, ldp) != 1) {
418 strcpy(errbuf, "readExports: cannot read loader section");
420 while(ldclose(ldp) == FAILURE)
424 lhp = (LDHDR *)ldbuf;
425 ls = (LDSYM *)(ldbuf+LDHDRSZ);
427 * Count the number of exports to include in our export table.
429 for (i = lhp->l_nsyms; i; i--, ls++) {
430 if (!LDR_EXPORT(*ls))
434 Newz(1001, mp->exports, mp->nExports, Export);
435 if (mp->exports == NULL) {
437 strcpy(errbuf, "readExports: ");
438 strerrorcat(errbuf, errno);
440 while(ldclose(ldp) == FAILURE)
445 * Fill in the export table. All entries are relative to
446 * the entry point we got from load.
449 ls = (LDSYM *)(ldbuf+LDHDRSZ);
450 for (i = lhp->l_nsyms; i; i--, ls++) {
452 if (!LDR_EXPORT(*ls))
454 if (ls->l_zeroes == 0)
455 symname = ls->l_offset+lhp->l_stoff+ldbuf;
457 symname = ls->l_name;
458 ep->name = savepv(symname);
459 ep->addr = (void *)((unsigned long)mp->entry + ls->l_value);
463 while(ldclose(ldp) == FAILURE)
469 * Find the main modules entry point. This is used as export pointer
470 * for loadbind() to be able to resolve references to the main part.
472 static void * findMain(void)
480 if ((buf = safemalloc(size)) == NULL) {
482 strcpy(errbuf, "findMain: ");
483 strerrorcat(errbuf, errno);
486 while ((i = loadquery(L_GETINFO, buf, size)) == -1 && errno == ENOMEM) {
489 if ((buf = safemalloc(size)) == NULL) {
491 strcpy(errbuf, "findMain: ");
492 strerrorcat(errbuf, errno);
498 strcpy(errbuf, "findMain: ");
499 strerrorcat(errbuf, errno);
504 * The first entry is the main module. The entry point
505 * returned by load() does actually point to the data
508 lp = (struct ld_info *)buf;
509 ret = lp->ldinfo_dataorg;
516 * Platform: SunOS/Solaris, possibly others which use dlopen.
517 * Author: Paul Marquess (pmarquess@bfsec.bt.co.uk)
518 * Created: 10th July 1994
521 * 15th July 1994 - Added code to explicitly save any error messages.
522 * 3rd August 1994 - Upgraded to v3 spec.
523 * 9th August 1994 - Changed to use IV
524 * 10th August 1994 - Tim Bunce: Added RTLD_LAZY, switchable debugging,
525 * basic FreeBSD support, removed ClearError
535 #include "dlutils.c" /* SaveError() etc */
541 (void)dl_generic_private_init();
544 MODULE = DynaLoader PACKAGE = DynaLoader
547 (void)dl_private_init();
551 dl_load_file(filename, flags=0)
555 DLDEBUG(1,PerlIO_printf(PerlIO_stderr(), "dl_load_file(%s,%x):\n", filename,flags));
557 warn("Can't make loaded symbols global on this platform while loading %s",filename);
558 RETVAL = dlopen(filename, 1) ;
559 DLDEBUG(2,PerlIO_printf(PerlIO_stderr(), " libref=%x\n", RETVAL));
560 ST(0) = sv_newmortal() ;
562 SaveError("%s",dlerror()) ;
564 sv_setiv( ST(0), (IV)RETVAL);
568 dl_find_symbol(libhandle, symbolname)
572 DLDEBUG(2,PerlIO_printf(PerlIO_stderr(), "dl_find_symbol(handle=%x, symbol=%s)\n",
573 libhandle, symbolname));
574 RETVAL = dlsym(libhandle, symbolname);
575 DLDEBUG(2,PerlIO_printf(PerlIO_stderr(), " symbolref = %x\n", RETVAL));
576 ST(0) = sv_newmortal() ;
578 SaveError("%s",dlerror()) ;
580 sv_setiv( ST(0), (IV)RETVAL);
589 # These functions should not need changing on any platform:
592 dl_install_xsub(perl_name, symref, filename="$Package")
597 DLDEBUG(2,PerlIO_printf(PerlIO_stderr(), "dl_install_xsub(name=%s, symref=%x)\n",
599 ST(0)=sv_2mortal(newRV((SV*)newXS(perl_name, (void(*)())symref, filename)));