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);
82 void *dlopen(char *path, int mode)
84 register ModulePtr mp;
85 static void *mainModule;
88 * Upon the first call register a terminate handler that will
89 * close all libraries. Also get a reference to the main module
90 * for use with loadbind.
93 if ((mainModule = findMain()) == NULL)
98 * Scan the list of modules if have the module already loaded.
100 for (mp = modList; mp; mp = mp->next)
101 if (strcmp(mp->name, path) == 0) {
105 Newz(1000,mp,1,Module);
108 strcpy(errbuf, "Newz: ");
109 strcat(errbuf, strerror(errno));
113 if ((mp->name = savepv(path)) == NULL) {
115 strcpy(errbuf, "savepv: ");
116 strcat(errbuf, strerror(errno));
121 * load should be declared load(const char *...). Thus we
122 * cast the path to a normal char *. Ugly.
124 if ((mp->entry = (void *)load((char *)path, L_NOAUTODEFER, NULL)) == NULL) {
128 strcpy(errbuf, "dlopen: ");
129 strcat(errbuf, path);
130 strcat(errbuf, ": ");
132 * If AIX says the file is not executable, the error
133 * can be further described by querying the loader about
136 if (errno == ENOEXEC) {
137 char *tmp[BUFSIZ/sizeof(char *)];
138 if (loadquery(L_GETMESSAGES, tmp, sizeof(tmp)) == -1)
139 strcpy(errbuf, strerror(errno));
142 for (p = tmp; *p; p++)
146 strcat(errbuf, strerror(errno));
152 if (loadbind(0, mainModule, mp->entry) == -1) {
155 strcpy(errbuf, "loadbind: ");
156 strcat(errbuf, strerror(errno));
159 if (readExports(mp) == -1) {
167 * Attempt to decipher an AIX loader error message and append it
168 * to our static error message buffer.
170 static void caterr(char *s)
172 register char *p = s;
174 while (*p >= '0' && *p <= '9')
177 case L_ERROR_TOOMANY:
178 strcat(errbuf, "to many errors");
181 strcat(errbuf, "can't load library");
185 strcat(errbuf, "can't find symbol");
189 strcat(errbuf, "bad RLD");
193 strcat(errbuf, "bad exec format in");
197 strcat(errbuf, strerror(atoi(++p)));
205 void *dlsym(void *handle, const char *symbol)
207 register ModulePtr mp = (ModulePtr)handle;
208 register ExportPtr ep;
212 * Could speed up search, but I assume that one assigns
213 * the result to function pointers anyways.
215 for (ep = mp->exports, i = mp->nExports; i; i--, ep++)
216 if (strcmp(ep->name, symbol) == 0)
219 strcpy(errbuf, "dlsym: undefined symbol ");
220 strcat(errbuf, symbol);
233 int dlclose(void *handle)
235 register ModulePtr mp = (ModulePtr)handle;
237 register ModulePtr mp1;
239 if (--mp->refCnt > 0)
241 result = unload(mp->entry);
244 strcpy(errbuf, strerror(errno));
247 register ExportPtr ep;
249 for (ep = mp->exports, i = mp->nExports; i; i--, ep++)
252 safefree(mp->exports);
257 for (mp1 = modList; mp1; mp1 = mp1->next)
258 if (mp1->next == mp) {
259 mp1->next = mp->next;
268 static void terminate(void)
274 /* Added by Wayne Scott
275 * This is needed because the ldopen system call calls
276 * calloc to allocated a block of date. The ldclose call calls free.
277 * Without this we get this system calloc and perl's free, resulting
278 * in a "Bad free" message. This way we always use perl's malloc.
280 void *calloc(size_t ne, size_t sz)
284 out = (void *) safemalloc(ne*sz);
290 * Build the export table from the XCOFF .loader section.
292 static int readExports(ModulePtr mp)
302 if ((ldp = ldopen(mp->name, ldp)) == NULL) {
306 if (errno != ENOENT) {
308 strcpy(errbuf, "readExports: ");
309 strcat(errbuf, strerror(errno));
313 * The module might be loaded due to the LIBPATH
314 * environment variable. Search for the loaded
315 * module using L_GETINFO.
317 if ((buf = safemalloc(size)) == NULL) {
319 strcpy(errbuf, "readExports: ");
320 strcat(errbuf, strerror(errno));
323 while ((i = loadquery(L_GETINFO, buf, size)) == -1 && errno == ENOMEM) {
326 if ((buf = safemalloc(size)) == NULL) {
328 strcpy(errbuf, "readExports: ");
329 strcat(errbuf, strerror(errno));
335 strcpy(errbuf, "readExports: ");
336 strcat(errbuf, strerror(errno));
341 * Traverse the list of loaded modules. The entry point
342 * returned by load() does actually point to the data
345 lp = (struct ld_info *)buf;
347 if (lp->ldinfo_dataorg == mp->entry) {
348 ldp = ldopen(lp->ldinfo_filename, ldp);
351 if (lp->ldinfo_next == 0)
354 lp = (struct ld_info *)((char *)lp + lp->ldinfo_next);
359 strcpy(errbuf, "readExports: ");
360 strcat(errbuf, strerror(errno));
364 if (TYPE(ldp) != U802TOCMAGIC) {
366 strcpy(errbuf, "readExports: bad magic");
367 while(ldclose(ldp) == FAILURE)
371 if (ldnshread(ldp, _LOADER, &sh) != SUCCESS) {
373 strcpy(errbuf, "readExports: cannot read loader section header");
374 while(ldclose(ldp) == FAILURE)
379 * We read the complete loader section in one chunk, this makes
380 * finding long symbol names residing in the string table easier.
382 if ((ldbuf = (char *)safemalloc(sh.s_size)) == NULL) {
384 strcpy(errbuf, "readExports: ");
385 strcat(errbuf, strerror(errno));
386 while(ldclose(ldp) == FAILURE)
390 if (FSEEK(ldp, sh.s_scnptr, BEGINNING) != OKFSEEK) {
392 strcpy(errbuf, "readExports: cannot seek to loader section");
394 while(ldclose(ldp) == FAILURE)
398 /* This first case is a hack, since it assumes that the 3rd parameter to
399 FREAD is 1. See the redefinition of FREAD above to see how this works. */
401 if (FREAD(ldbuf, sh.s_size, 1, ldp) != sh.s_size) {
403 if (FREAD(ldbuf, sh.s_size, 1, ldp) != 1) {
406 strcpy(errbuf, "readExports: cannot read loader section");
408 while(ldclose(ldp) == FAILURE)
412 lhp = (LDHDR *)ldbuf;
413 ls = (LDSYM *)(ldbuf+LDHDRSZ);
415 * Count the number of exports to include in our export table.
417 for (i = lhp->l_nsyms; i; i--, ls++) {
418 if (!LDR_EXPORT(*ls))
422 Newz(1001, mp->exports, mp->nExports, Export);
423 if (mp->exports == NULL) {
425 strcpy(errbuf, "readExports: ");
426 strcat(errbuf, strerror(errno));
428 while(ldclose(ldp) == FAILURE)
433 * Fill in the export table. All entries are relative to
434 * the entry point we got from load.
437 ls = (LDSYM *)(ldbuf+LDHDRSZ);
438 for (i = lhp->l_nsyms; i; i--, ls++) {
440 if (!LDR_EXPORT(*ls))
442 if (ls->l_zeroes == 0)
443 symname = ls->l_offset+lhp->l_stoff+ldbuf;
445 symname = ls->l_name;
446 ep->name = savepv(symname);
447 ep->addr = (void *)((unsigned long)mp->entry + ls->l_value);
451 while(ldclose(ldp) == FAILURE)
457 * Find the main modules entry point. This is used as export pointer
458 * for loadbind() to be able to resolve references to the main part.
460 static void * findMain(void)
468 if ((buf = safemalloc(size)) == NULL) {
470 strcpy(errbuf, "findMain: ");
471 strcat(errbuf, strerror(errno));
474 while ((i = loadquery(L_GETINFO, buf, size)) == -1 && errno == ENOMEM) {
477 if ((buf = safemalloc(size)) == NULL) {
479 strcpy(errbuf, "findMain: ");
480 strcat(errbuf, strerror(errno));
486 strcpy(errbuf, "findMain: ");
487 strcat(errbuf, strerror(errno));
492 * The first entry is the main module. The entry point
493 * returned by load() does actually point to the data
496 lp = (struct ld_info *)buf;
497 ret = lp->ldinfo_dataorg;
504 * Platform: SunOS/Solaris, possibly others which use dlopen.
505 * Author: Paul Marquess (pmarquess@bfsec.bt.co.uk)
506 * Created: 10th July 1994
509 * 15th July 1994 - Added code to explicitly save any error messages.
510 * 3rd August 1994 - Upgraded to v3 spec.
511 * 9th August 1994 - Changed to use IV
512 * 10th August 1994 - Tim Bunce: Added RTLD_LAZY, switchable debugging,
513 * basic FreeBSD support, removed ClearError
523 #include "dlutils.c" /* SaveError() etc */
529 (void)dl_generic_private_init();
532 MODULE = DynaLoader PACKAGE = DynaLoader
535 (void)dl_private_init();
539 dl_load_file(filename, flags=0)
543 DLDEBUG(1,PerlIO_printf(PerlIO_stderr(), "dl_load_file(%s,%x):\n", filename,flags));
545 warn("Can't make loaded symbols global on this platform while loading %s",filename);
546 RETVAL = dlopen(filename, 1) ;
547 DLDEBUG(2,PerlIO_printf(PerlIO_stderr(), " libref=%x\n", RETVAL));
548 ST(0) = sv_newmortal() ;
550 SaveError("%s",dlerror()) ;
552 sv_setiv( ST(0), (IV)RETVAL);
556 dl_find_symbol(libhandle, symbolname)
560 DLDEBUG(2,PerlIO_printf(PerlIO_stderr(), "dl_find_symbol(handle=%x, symbol=%s)\n",
561 libhandle, symbolname));
562 RETVAL = dlsym(libhandle, symbolname);
563 DLDEBUG(2,PerlIO_printf(PerlIO_stderr(), " symbolref = %x\n", RETVAL));
564 ST(0) = sv_newmortal() ;
566 SaveError("%s",dlerror()) ;
568 sv_setiv( ST(0), (IV)RETVAL);
577 # These functions should not need changing on any platform:
580 dl_install_xsub(perl_name, symref, filename="$Package")
585 DLDEBUG(2,PerlIO_printf(PerlIO_stderr(), "dl_install_xsub(name=%s, symref=%x)\n",
587 ST(0)=sv_2mortal(newRV((SV*)newXS(perl_name, (void(*)())symref, filename)));