5 * @(#)dlfcn.c 1.7 revision of 95/08/14 19:08:38
6 * This is an unpublished work copyright (c) 1992 HELIOS Software GmbH
7 * 30159 Hannover, Germany
16 #include "dynloader.h"
21 * AIX 4.3 and up has dlopen() and friends in -ldl.
22 * A la long, the homebrewn dl*() functions below should be obsolete.
26 * We simulate dlopen() et al. through a call to load. Because AIX has
27 * no call to find an exported symbol we read the loader section of the
28 * loaded module and build a list of exported symbols and their virtual
34 char *name
; /* the symbols's name */
35 void *addr
; /* its relocated virtual address */
39 * xlC uses the following structure to list its constructors and
40 * destructors. This is gleaned from the output of munch.
44 void (*init
) (void); /* call static constructors */
45 void (*term
) (void); /* call static destructors */
49 * The void * handle returned from dlopen is actually a ModulePtr.
54 char *name
; /* module name for refcounting */
55 int refCnt
; /* the number of references */
56 void *entry
; /* entry point from load */
57 struct dl_info
*info
; /* optional init/terminate functions */
58 CdtorPtr cdtors
; /* optional C++ constructors */
59 int nExports
; /* the number of exports found */
60 ExportPtr exports
; /* the array of exports */
64 * We keep a list of all loaded modules to be able to call the fini
65 * handlers and destructors at atexit() time.
67 static ModulePtr modList
;
70 * The last error from one of the dl* routines is kept in static
71 * variables here. Each error is returned only once to the caller.
73 static char errbuf
[BUFSIZ
];
76 extern char *strdup(const char *);
77 static void caterr(char *);
78 static int readExports(ModulePtr
);
79 static void terminate(void);
80 static void *findMain(void);
83 dlopen(const char *path
, int mode
)
86 static void *mainModule
;
89 * Upon the first call register a terminate handler that will close all
90 * libraries. Also get a reference to the main module for use with
95 if ((mainModule
= findMain()) == NULL
)
101 * Scan the list of modules if we have the module already loaded.
103 for (mp
= modList
; mp
; mp
= mp
->next
)
104 if (strcmp(mp
->name
, path
) == 0)
109 if ((mp
= (ModulePtr
) calloc(1, sizeof(*mp
))) == NULL
)
112 strcpy(errbuf
, "calloc: ");
113 strcat(errbuf
, strerror(errno
));
116 if ((mp
->name
= strdup(path
)) == NULL
)
119 strcpy(errbuf
, "strdup: ");
120 strcat(errbuf
, strerror(errno
));
126 * load should be declared load(const char *...). Thus we cast the path to
127 * a normal char *. Ugly.
129 if ((mp
->entry
= (void *) load((char *) path
, L_NOAUTODEFER
, NULL
)) == NULL
)
134 strcpy(errbuf
, "dlopen: ");
135 strcat(errbuf
, path
);
136 strcat(errbuf
, ": ");
139 * If AIX says the file is not executable, the error can be further
140 * described by querying the loader about the last error.
142 if (errno
== ENOEXEC
)
144 char *tmp
[BUFSIZ
/ sizeof(char *)];
146 if (loadquery(L_GETMESSAGES
, tmp
, sizeof(tmp
)) == -1)
147 strcpy(errbuf
, strerror(errno
));
152 for (p
= tmp
; *p
; p
++)
157 strcat(errbuf
, strerror(errno
));
163 if (loadbind(0, mainModule
, mp
->entry
) == -1)
167 strcpy(errbuf
, "loadbind: ");
168 strcat(errbuf
, strerror(errno
));
173 * If the user wants global binding, loadbind against all other loaded
176 if (mode
& RTLD_GLOBAL
)
180 for (mp1
= mp
->next
; mp1
; mp1
= mp1
->next
)
181 if (loadbind(0, mp1
->entry
, mp
->entry
) == -1)
185 strcpy(errbuf
, "loadbind: ");
186 strcat(errbuf
, strerror(errno
));
190 if (readExports(mp
) == -1)
197 * If there is a dl_info structure, call the init function.
199 if (mp
->info
= (struct dl_info
*) dlsym(mp
, "dl_info"))
202 (*mp
->info
->init
) ();
208 * If the shared object was compiled using xlC we will need to call static
209 * constructors (and later on dlclose destructors).
211 if (mp
->cdtors
= (CdtorPtr
) dlsym(mp
, "__cdtors"))
213 while (mp
->cdtors
->init
)
215 (*mp
->cdtors
->init
) ();
225 * Attempt to decipher an AIX loader error message and append it
226 * to our static error message buffer.
233 while (*p
>= '0' && *p
<= '9')
237 case L_ERROR_TOOMANY
:
238 strcat(errbuf
, "to many errors");
241 strcat(errbuf
, "cannot load library");
245 strcat(errbuf
, "cannot find symbol");
249 strcat(errbuf
, "bad RLD");
253 strcat(errbuf
, "bad exec format in");
257 strcat(errbuf
, strerror(atoi(++p
)));
266 dlsym(void *handle
, const char *symbol
)
268 ModulePtr mp
= (ModulePtr
) handle
;
273 * Could speed up the search, but I assume that one assigns the result to
274 * function pointers anyways.
276 for (ep
= mp
->exports
, i
= mp
->nExports
; i
; i
--, ep
++)
277 if (strcmp(ep
->name
, symbol
) == 0)
280 strcpy(errbuf
, "dlsym: undefined symbol ");
281 strcat(errbuf
, symbol
);
297 dlclose(void *handle
)
299 ModulePtr mp
= (ModulePtr
) handle
;
303 if (--mp
->refCnt
> 0)
305 if (mp
->info
&& mp
->info
->fini
)
306 (*mp
->info
->fini
) ();
308 while (mp
->cdtors
->term
)
310 (*mp
->cdtors
->term
) ();
313 result
= unload(mp
->entry
);
317 strcpy(errbuf
, strerror(errno
));
324 for (ep
= mp
->exports
, i
= mp
->nExports
; i
; i
--, ep
++)
333 for (mp1
= modList
; mp1
; mp1
= mp1
->next
)
336 mp1
->next
= mp
->next
;
353 * Build the export table from the XCOFF .loader section.
356 readExports(ModulePtr mp
)
367 if ((ldp
= ldopen(mp
->name
, ldp
)) == NULL
)
376 strcpy(errbuf
, "readExports: ");
377 strcat(errbuf
, strerror(errno
));
382 * The module might be loaded due to the LIBPATH environment variable.
383 * Search for the loaded module using L_GETINFO.
385 if ((buf
= malloc(size
)) == NULL
)
388 strcpy(errbuf
, "readExports: ");
389 strcat(errbuf
, strerror(errno
));
392 while ((i
= loadquery(L_GETINFO
, buf
, size
)) == -1 && errno
== ENOMEM
)
396 if ((buf
= malloc(size
)) == NULL
)
399 strcpy(errbuf
, "readExports: ");
400 strcat(errbuf
, strerror(errno
));
407 strcpy(errbuf
, "readExports: ");
408 strcat(errbuf
, strerror(errno
));
414 * Traverse the list of loaded modules. The entry point returned by
415 * load() does actually point to the data segment origin.
417 lp
= (struct ld_info
*) buf
;
420 if (lp
->ldinfo_dataorg
== mp
->entry
)
422 ldp
= ldopen(lp
->ldinfo_filename
, ldp
);
425 if (lp
->ldinfo_next
== 0)
428 lp
= (struct ld_info
*) ((char *) lp
+ lp
->ldinfo_next
);
434 strcpy(errbuf
, "readExports: ");
435 strcat(errbuf
, strerror(errno
));
439 if (TYPE(ldp
) != U802TOCMAGIC
)
442 strcpy(errbuf
, "readExports: bad magic");
443 while (ldclose(ldp
) == FAILURE
)
449 * Get the padding for the data section. This is needed for AIX 4.1
450 * compilers. This is used when building the final function pointer to the
453 if (ldnshread(ldp
, _DATA
, &shdata
) != SUCCESS
)
456 strcpy(errbuf
, "readExports: cannot read data section header");
457 while (ldclose(ldp
) == FAILURE
)
461 if (ldnshread(ldp
, _LOADER
, &sh
) != SUCCESS
)
464 strcpy(errbuf
, "readExports: cannot read loader section header");
465 while (ldclose(ldp
) == FAILURE
)
471 * We read the complete loader section in one chunk, this makes finding
472 * long symbol names residing in the string table easier.
474 if ((ldbuf
= (char *) malloc(sh
.s_size
)) == NULL
)
477 strcpy(errbuf
, "readExports: ");
478 strcat(errbuf
, strerror(errno
));
479 while (ldclose(ldp
) == FAILURE
)
483 if (FSEEK(ldp
, sh
.s_scnptr
, BEGINNING
) != OKFSEEK
)
486 strcpy(errbuf
, "readExports: cannot seek to loader section");
488 while (ldclose(ldp
) == FAILURE
)
492 if (FREAD(ldbuf
, sh
.s_size
, 1, ldp
) != 1)
495 strcpy(errbuf
, "readExports: cannot read loader section");
497 while (ldclose(ldp
) == FAILURE
)
501 lhp
= (LDHDR
*) ldbuf
;
502 ls
= (LDSYM
*) (ldbuf
+ LDHDRSZ
);
505 * Count the number of exports to include in our export table.
507 for (i
= lhp
->l_nsyms
; i
; i
--, ls
++)
509 if (!LDR_EXPORT(*ls
))
513 if ((mp
->exports
= (ExportPtr
) calloc(mp
->nExports
, sizeof(*mp
->exports
))) == NULL
)
516 strcpy(errbuf
, "readExports: ");
517 strcat(errbuf
, strerror(errno
));
519 while (ldclose(ldp
) == FAILURE
)
525 * Fill in the export table. All entries are relative to the entry point
529 ls
= (LDSYM
*) (ldbuf
+ LDHDRSZ
);
530 for (i
= lhp
->l_nsyms
; i
; i
--, ls
++)
533 char tmpsym
[SYMNMLEN
+ 1];
535 if (!LDR_EXPORT(*ls
))
537 if (ls
->l_zeroes
== 0)
538 symname
= ls
->l_offset
+ lhp
->l_stoff
+ ldbuf
;
542 * The l_name member is not zero terminated, we must copy the
543 * first SYMNMLEN chars and make sure we have a zero byte at the
546 strncpy(tmpsym
, ls
->l_name
, SYMNMLEN
);
547 tmpsym
[SYMNMLEN
] = '\0';
550 ep
->name
= strdup(symname
);
551 ep
->addr
= (void *) ((unsigned long) mp
->entry
+
552 ls
->l_value
- shdata
.s_vaddr
);
556 while (ldclose(ldp
) == FAILURE
)
562 * Find the main modules entry point. This is used as export pointer
563 * for loadbind() to be able to resolve references to the main part.
574 if ((buf
= malloc(size
)) == NULL
)
577 strcpy(errbuf
, "findMain: ");
578 strcat(errbuf
, strerror(errno
));
581 while ((i
= loadquery(L_GETINFO
, buf
, size
)) == -1 && errno
== ENOMEM
)
585 if ((buf
= malloc(size
)) == NULL
)
588 strcpy(errbuf
, "findMain: ");
589 strcat(errbuf
, strerror(errno
));
596 strcpy(errbuf
, "findMain: ");
597 strcat(errbuf
, strerror(errno
));
603 * The first entry is the main module. The entry point returned by load()
604 * does actually point to the data segment origin.
606 lp
= (struct ld_info
*) buf
;
607 ret
= lp
->ldinfo_dataorg
;
612 #endif /* HAVE_DLOPEN */