2 * @(#)dlfcn.c 1.11 revision of 96/04/10 20:12:51
3 * This is an unpublished work copyright (c) 1992 HELIOS Software GmbH
4 * 30159 Hannover, Germany
8 * Changes marked with `--jwe' were made on April 7 1996 by John W. Eaton
9 * <jwe@bevo.che.wisc.edu> to support g++ and/or use with Octave.
13 * This makes my life easier with Octave. --jwe
23 #include <sys/types.h>
30 * We simulate dlopen() et al. through a call to load. Because AIX has
31 * no call to find an exported symbol we read the loader section of the
32 * loaded module and build a list of exported symbols and their virtual
37 char *name
; /* the symbols's name */
38 void *addr
; /* its relocated virtual address */
42 * xlC uses the following structure to list its constructors and
43 * destructors. This is gleaned from the output of munch.
46 void (*init
)(void); /* call static constructors */
47 void (*term
)(void); /* call static destructors */
50 typedef void (*GccCDtorPtr
)(void);
53 * The void * handle returned from dlopen is actually a ModulePtr.
55 typedef struct Module
{
57 char *name
; /* module name for refcounting */
58 int refCnt
; /* the number of references */
59 void *entry
; /* entry point from load */
60 struct dl_info
*info
; /* optional init/terminate functions */
61 CdtorPtr cdtors
; /* optional C++ constructors */
62 GccCDtorPtr gcc_ctor
; /* g++ constructors --jwe */
63 GccCDtorPtr gcc_dtor
; /* g++ destructors --jwe */
64 int nExports
; /* the number of exports found */
65 ExportPtr exports
; /* the array of exports */
69 * We keep a list of all loaded modules to be able to call the fini
70 * handlers and destructors at atexit() time.
72 static ModulePtr modList
;
75 * The last error from one of the dl* routines is kept in static
76 * variables here. Each error is returned only once to the caller.
78 static char errbuf
[BUFSIZ
];
82 * The `fixed' gcc header files on AIX 3.2.5 provide a prototype for
86 extern char *strdup(const char *);
88 static void caterr(char *);
89 static int readExports(ModulePtr
);
90 static void terminate(void);
91 static void *findMain(void);
93 void *dlopen(const char *path
, int mode
)
96 static void *mainModule
;
99 * Upon the first call register a terminate handler that will
100 * close all libraries. Also get a reference to the main module
101 * for use with loadbind.
104 if ((mainModule
= findMain()) == NULL
)
109 * Scan the list of modules if we have the module already loaded.
111 for (mp
= modList
; mp
; mp
= mp
->next
)
112 if (strcmp(mp
->name
, path
) == 0) {
116 if ((mp
= (ModulePtr
)calloc(1, sizeof(*mp
))) == NULL
) {
118 snprintf (errbuf
, sizeof(errbuf
), "calloc: %s", strerror(errno
));
121 if ((mp
->name
= strdup(path
)) == NULL
) {
123 snprintf (errbuf
, sizeof(errbuf
), "strdup: %s", strerror(errno
));
128 * load should be declared load(const char *...). Thus we
129 * cast the path to a normal char *. Ugly.
131 if ((mp
->entry
= (void *)load((char *)path
, L_NOAUTODEFER
, NULL
)) == NULL
) {
135 snprintf (errbuf
, sizeof(errbuf
),
136 "dlopen: %s: ", path
);
138 * If AIX says the file is not executable, the error
139 * can be further described by querying the loader about
142 if (errno
== ENOEXEC
) {
143 char *tmp
[BUFSIZ
/sizeof(char *)];
144 if (loadquery(L_GETMESSAGES
, tmp
, sizeof(tmp
)) == -1)
150 for (p
= tmp
; *p
; p
++)
162 if (loadbind(0, mainModule
, mp
->entry
) == -1) {
165 snprintf (errbuf
, sizeof(errbuf
),
166 "loadbind: %s", strerror(errno
));
170 * If the user wants global binding, loadbind against all other
173 if (mode
& RTLD_GLOBAL
) {
175 for (mp1
= mp
->next
; mp1
; mp1
= mp1
->next
)
176 if (loadbind(0, mp1
->entry
, mp
->entry
) == -1) {
179 snprintf (errbuf
, sizeof(errbuf
),
185 if (readExports(mp
) == -1) {
190 * If there is a dl_info structure, call the init function.
192 if (mp
->info
= (struct dl_info
*)dlsym(mp
, "dl_info")) {
198 * If the shared object was compiled using xlC we will need
199 * to call static constructors (and later on dlclose destructors).
201 if (mp
->cdtors
= (CdtorPtr
)dlsym(mp
, "__cdtors")) {
202 CdtorPtr cp
= mp
->cdtors
;
203 while (cp
->init
|| cp
->term
) {
204 if (cp
->init
&& cp
->init
!= (void (*)(void))0xffffffff)
209 * If the shared object was compiled using g++, we will need
210 * to call global constructors using the _GLOBAL__DI function,
211 * and later, global destructors using the _GLOBAL_DD
214 } else if (mp
->gcc_ctor
= (GccCDtorPtr
)dlsym(mp
, "_GLOBAL__DI")) {
216 mp
->gcc_dtor
= (GccCDtorPtr
)dlsym(mp
, "_GLOBAL__DD");
223 * Attempt to decipher an AIX loader error message and append it
224 * to our static error message buffer.
226 static void caterr(char *s
)
230 while (*p
>= '0' && *p
<= '9')
233 case L_ERROR_TOOMANY
:
234 strlcat(errbuf
, "to many errors", sizeof(errbuf
));
237 strlcat(errbuf
, "can't load library", sizeof(errbuf
));
238 strlcat(errbuf
, p
, sizeof(errbuf
));
241 strlcat(errbuf
, "can't find symbol", sizeof(errbuf
));
242 strlcat(errbuf
, p
, sizeof(errbuf
));
245 strlcat(errbuf
, "bad RLD", sizeof(errbuf
));
246 strlcat(errbuf
, p
, sizeof(errbuf
));
249 strlcat(errbuf
, "bad exec format in", sizeof(errbuf
));
250 strlcat(errbuf
, p
, sizeof(errbuf
));
253 strlcat(errbuf
, strerror(atoi(++p
)), sizeof(errbuf
));
256 strlcat(errbuf
, s
, sizeof(errbuf
));
261 void *dlsym(void *handle
, const char *symbol
)
263 ModulePtr mp
= (ModulePtr
)handle
;
268 * Could speed up the search, but I assume that one assigns
269 * the result to function pointers anyways.
271 for (ep
= mp
->exports
, i
= mp
->nExports
; i
; i
--, ep
++)
272 if (strcmp(ep
->name
, symbol
) == 0)
275 snprintf (errbuf
, sizeof(errbuf
),
276 "dlsym: undefined symbol %s", symbol
);
289 int dlclose(void *handle
)
291 ModulePtr mp
= (ModulePtr
)handle
;
295 if (--mp
->refCnt
> 0)
297 if (mp
->info
&& mp
->info
->fini
)
300 CdtorPtr cp
= mp
->cdtors
;
301 while (cp
->init
|| cp
->term
) {
302 if (cp
->term
&& cp
->init
!= (void (*)(void))0xffffffff)
307 * If the function to handle global destructors for g++
308 * exists, call it. --jwe
310 } else if (mp
->gcc_dtor
) {
313 result
= unload(mp
->entry
);
316 snprintf (errbuf
, sizeof(errbuf
),
317 "%s", strerror(errno
));
322 for (ep
= mp
->exports
, i
= mp
->nExports
; i
; i
--, ep
++)
330 for (mp1
= modList
; mp1
; mp1
= mp1
->next
)
331 if (mp1
->next
== mp
) {
332 mp1
->next
= mp
->next
;
341 static void terminate(void)
348 * Build the export table from the XCOFF .loader section.
350 static int readExports(ModulePtr mp
)
360 if ((ldp
= ldopen(mp
->name
, ldp
)) == NULL
) {
364 if (errno
!= ENOENT
) {
366 snprintf(errbuf
, sizeof(errbuf
),
372 * The module might be loaded due to the LIBPATH
373 * environment variable. Search for the loaded
374 * module using L_GETINFO.
376 if ((buf
= malloc(size
)) == NULL
) {
378 snprintf(errbuf
, sizeof(errbuf
),
383 while ((i
= loadquery(L_GETINFO
, buf
, size
)) == -1 && errno
== ENOMEM
) {
386 if ((buf
= malloc(size
)) == NULL
) {
388 snprintf(errbuf
, sizeof(errbuf
),
396 snprintf(errbuf
, sizeof(errbuf
),
403 * Traverse the list of loaded modules. The entry point
404 * returned by load() does actually point to the data
407 lp
= (struct ld_info
*)buf
;
409 if (lp
->ldinfo_dataorg
== mp
->entry
) {
410 ldp
= ldopen(lp
->ldinfo_filename
, ldp
);
413 if (lp
->ldinfo_next
== 0)
416 lp
= (struct ld_info
*)((char *)lp
+ lp
->ldinfo_next
);
421 snprintf (errbuf
, sizeof(errbuf
),
422 "readExports: %s", strerror(errno
));
426 if (TYPE(ldp
) != U802TOCMAGIC
) {
428 snprintf(errbuf
, sizeof(errbuf
), "readExports: bad magic");
429 while(ldclose(ldp
) == FAILURE
)
434 * Get the padding for the data section. This is needed for
435 * AIX 4.1 compilers. This is used when building the final
436 * function pointer to the exported symbol.
438 if (ldnshread(ldp
, _DATA
, &shdata
) != SUCCESS
) {
440 snprintf(errbuf
, sizeof(errbuf
),
441 "readExports: cannot read data section header");
442 while(ldclose(ldp
) == FAILURE
)
446 if (ldnshread(ldp
, _LOADER
, &sh
) != SUCCESS
) {
448 snprintf(errbuf
, sizeof(errbuf
),
449 "readExports: cannot read loader section header");
450 while(ldclose(ldp
) == FAILURE
)
455 * We read the complete loader section in one chunk, this makes
456 * finding long symbol names residing in the string table easier.
458 if ((ldbuf
= (char *)malloc(sh
.s_size
)) == NULL
) {
460 snprintf (errbuf
, sizeof(errbuf
),
461 "readExports: %s", strerror(errno
));
462 while(ldclose(ldp
) == FAILURE
)
466 if (FSEEK(ldp
, sh
.s_scnptr
, BEGINNING
) != OKFSEEK
) {
468 snprintf(errbuf
, sizeof(errbuf
),
469 "readExports: cannot seek to loader section");
471 while(ldclose(ldp
) == FAILURE
)
475 if (FREAD(ldbuf
, sh
.s_size
, 1, ldp
) != 1) {
477 snprintf(errbuf
, sizeof(errbuf
),
478 "readExports: cannot read loader section");
480 while(ldclose(ldp
) == FAILURE
)
484 lhp
= (LDHDR
*)ldbuf
;
485 ls
= (LDSYM
*)(ldbuf
+LDHDRSZ
);
487 * Count the number of exports to include in our export table.
489 for (i
= lhp
->l_nsyms
; i
; i
--, ls
++) {
490 if (!LDR_EXPORT(*ls
))
494 if ((mp
->exports
= (ExportPtr
)calloc(mp
->nExports
, sizeof(*mp
->exports
))) == NULL
) {
496 snprintf (errbuf
, sizeof(errbuf
),
497 "readExports: %s", strerror(errno
));
499 while(ldclose(ldp
) == FAILURE
)
504 * Fill in the export table. All entries are relative to
505 * the entry point we got from load.
508 ls
= (LDSYM
*)(ldbuf
+LDHDRSZ
);
509 for (i
= lhp
->l_nsyms
; i
; i
--, ls
++) {
511 char tmpsym
[SYMNMLEN
+1];
512 if (!LDR_EXPORT(*ls
))
514 if (ls
->l_zeroes
== 0)
515 symname
= ls
->l_offset
+lhp
->l_stoff
+ldbuf
;
518 * The l_name member is not zero terminated, we
519 * must copy the first SYMNMLEN chars and make
520 * sure we have a zero byte at the end.
522 strlcpy (tmpsym
, ls
->l_name
,
526 ep
->name
= strdup(symname
);
527 ep
->addr
= (void *)((unsigned long)mp
->entry
+
528 ls
->l_value
- shdata
.s_vaddr
);
532 while(ldclose(ldp
) == FAILURE
)
538 * Find the main modules entry point. This is used as export pointer
539 * for loadbind() to be able to resolve references to the main part.
541 static void * findMain(void)
549 if ((buf
= malloc(size
)) == NULL
) {
551 snprintf (errbuf
, sizeof(errbuf
),
552 "findMail: %s", strerror(errno
));
555 while ((i
= loadquery(L_GETINFO
, buf
, size
)) == -1 && errno
== ENOMEM
) {
558 if ((buf
= malloc(size
)) == NULL
) {
560 snprintf (errbuf
, sizeof(errbuf
),
561 "findMail: %s", strerror(errno
));
567 snprintf (errbuf
, sizeof(errbuf
),
568 "findMail: %s", strerror(errno
));
573 * The first entry is the main module. The entry point
574 * returned by load() does actually point to the data
577 lp
= (struct ld_info
*)buf
;
578 ret
= lp
->ldinfo_dataorg
;