2 * See README.dlfcn for license
5 * @(#)dlfcn.c 1.11 revision of 96/04/10 20:12:51
6 * This is an unpublished work copyright (c) 1992 HELIOS Software GmbH
7 * 30159 Hannover, Germany
11 * Changes marked with `--jwe' were made on April 7 1996 by John W. Eaton
12 * <jwe@bevo.che.wisc.edu> to support g++ and/or use with Octave.
16 * This makes my life easier with Octave. --jwe
26 #include <sys/types.h>
33 * We simulate dlopen() et al. through a call to load. Because AIX has
34 * no call to find an exported symbol we read the loader section of the
35 * loaded module and build a list of exported symbols and their virtual
40 char *name
; /* the symbols's name */
41 void *addr
; /* its relocated virtual address */
45 * xlC uses the following structure to list its constructors and
46 * destructors. This is gleaned from the output of munch.
49 void (*init
)(void); /* call static constructors */
50 void (*term
)(void); /* call static destructors */
53 typedef void (*GccCDtorPtr
)(void);
56 * The void * handle returned from dlopen is actually a ModulePtr.
58 typedef struct Module
{
60 char *name
; /* module name for refcounting */
61 int refCnt
; /* the number of references */
62 void *entry
; /* entry point from load */
63 struct dl_info
*info
; /* optional init/terminate functions */
64 CdtorPtr cdtors
; /* optional C++ constructors */
65 GccCDtorPtr gcc_ctor
; /* g++ constructors --jwe */
66 GccCDtorPtr gcc_dtor
; /* g++ destructors --jwe */
67 int nExports
; /* the number of exports found */
68 ExportPtr exports
; /* the array of exports */
72 * We keep a list of all loaded modules to be able to call the fini
73 * handlers and destructors at atexit() time.
75 static ModulePtr modList
;
78 * The last error from one of the dl* routines is kept in static
79 * variables here. Each error is returned only once to the caller.
81 static char errbuf
[BUFSIZ
];
85 * The `fixed' gcc header files on AIX 3.2.5 provide a prototype for
89 extern char *strdup(const char *);
91 static void caterr(char *);
92 static int readExports(ModulePtr
);
93 static void terminate(void);
94 static void *findMain(void);
96 void *dlopen(const char *path
, int mode
)
99 static void *mainModule
;
102 * Upon the first call register a terminate handler that will
103 * close all libraries. Also get a reference to the main module
104 * for use with loadbind.
107 if ((mainModule
= findMain()) == NULL
)
112 * Scan the list of modules if we have the module already loaded.
114 for (mp
= modList
; mp
; mp
= mp
->next
)
115 if (strcmp(mp
->name
, path
) == 0) {
119 if ((mp
= (ModulePtr
)calloc(1, sizeof(*mp
))) == NULL
) {
121 snprintf (errbuf
, sizeof(errbuf
), "calloc: %s", strerror(errno
));
124 if ((mp
->name
= strdup(path
)) == NULL
) {
126 snprintf (errbuf
, sizeof(errbuf
), "strdup: %s", strerror(errno
));
131 * load should be declared load(const char *...). Thus we
132 * cast the path to a normal char *. Ugly.
134 if ((mp
->entry
= (void *)load((char *)path
, L_NOAUTODEFER
, NULL
)) == NULL
) {
138 snprintf (errbuf
, sizeof(errbuf
),
139 "dlopen: %s: ", path
);
141 * If AIX says the file is not executable, the error
142 * can be further described by querying the loader about
145 if (errno
== ENOEXEC
) {
146 char *tmp
[BUFSIZ
/sizeof(char *)];
147 if (loadquery(L_GETMESSAGES
, tmp
, sizeof(tmp
)) == -1)
153 for (p
= tmp
; *p
; p
++)
165 if (loadbind(0, mainModule
, mp
->entry
) == -1) {
168 snprintf (errbuf
, sizeof(errbuf
),
169 "loadbind: %s", strerror(errno
));
173 * If the user wants global binding, loadbind against all other
176 if (mode
& RTLD_GLOBAL
) {
178 for (mp1
= mp
->next
; mp1
; mp1
= mp1
->next
)
179 if (loadbind(0, mp1
->entry
, mp
->entry
) == -1) {
182 snprintf (errbuf
, sizeof(errbuf
),
188 if (readExports(mp
) == -1) {
193 * If there is a dl_info structure, call the init function.
195 if (mp
->info
= (struct dl_info
*)dlsym(mp
, "dl_info")) {
201 * If the shared object was compiled using xlC we will need
202 * to call static constructors (and later on dlclose destructors).
204 if (mp
->cdtors
= (CdtorPtr
)dlsym(mp
, "__cdtors")) {
205 CdtorPtr cp
= mp
->cdtors
;
206 while (cp
->init
|| cp
->term
) {
207 if (cp
->init
&& cp
->init
!= (void (*)(void))0xffffffff)
212 * If the shared object was compiled using g++, we will need
213 * to call global constructors using the _GLOBAL__DI function,
214 * and later, global destructors using the _GLOBAL_DD
217 } else if (mp
->gcc_ctor
= (GccCDtorPtr
)dlsym(mp
, "_GLOBAL__DI")) {
219 mp
->gcc_dtor
= (GccCDtorPtr
)dlsym(mp
, "_GLOBAL__DD");
226 * Attempt to decipher an AIX loader error message and append it
227 * to our static error message buffer.
229 static void caterr(char *s
)
233 while (*p
>= '0' && *p
<= '9')
236 case L_ERROR_TOOMANY
:
237 strlcat(errbuf
, "to many errors", sizeof(errbuf
));
240 strlcat(errbuf
, "can't load library", sizeof(errbuf
));
241 strlcat(errbuf
, p
, sizeof(errbuf
));
244 strlcat(errbuf
, "can't find symbol", sizeof(errbuf
));
245 strlcat(errbuf
, p
, sizeof(errbuf
));
248 strlcat(errbuf
, "bad RLD", sizeof(errbuf
));
249 strlcat(errbuf
, p
, sizeof(errbuf
));
252 strlcat(errbuf
, "bad exec format in", sizeof(errbuf
));
253 strlcat(errbuf
, p
, sizeof(errbuf
));
256 strlcat(errbuf
, strerror(atoi(++p
)), sizeof(errbuf
));
259 strlcat(errbuf
, s
, sizeof(errbuf
));
264 void *dlsym(void *handle
, const char *symbol
)
266 ModulePtr mp
= (ModulePtr
)handle
;
271 * Could speed up the search, but I assume that one assigns
272 * the result to function pointers anyways.
274 for (ep
= mp
->exports
, i
= mp
->nExports
; i
; i
--, ep
++)
275 if (strcmp(ep
->name
, symbol
) == 0)
278 snprintf (errbuf
, sizeof(errbuf
),
279 "dlsym: undefined symbol %s", symbol
);
292 int dlclose(void *handle
)
294 ModulePtr mp
= (ModulePtr
)handle
;
298 if (--mp
->refCnt
> 0)
300 if (mp
->info
&& mp
->info
->fini
)
303 CdtorPtr cp
= mp
->cdtors
;
304 while (cp
->init
|| cp
->term
) {
305 if (cp
->term
&& cp
->init
!= (void (*)(void))0xffffffff)
310 * If the function to handle global destructors for g++
311 * exists, call it. --jwe
313 } else if (mp
->gcc_dtor
) {
316 result
= unload(mp
->entry
);
319 snprintf (errbuf
, sizeof(errbuf
),
320 "%s", strerror(errno
));
325 for (ep
= mp
->exports
, i
= mp
->nExports
; i
; i
--, ep
++)
333 for (mp1
= modList
; mp1
; mp1
= mp1
->next
)
334 if (mp1
->next
== mp
) {
335 mp1
->next
= mp
->next
;
344 static void terminate(void)
351 * Build the export table from the XCOFF .loader section.
353 static int readExports(ModulePtr mp
)
363 if ((ldp
= ldopen(mp
->name
, ldp
)) == NULL
) {
367 if (errno
!= ENOENT
) {
369 snprintf(errbuf
, sizeof(errbuf
),
375 * The module might be loaded due to the LIBPATH
376 * environment variable. Search for the loaded
377 * module using L_GETINFO.
379 if ((buf
= malloc(size
)) == NULL
) {
381 snprintf(errbuf
, sizeof(errbuf
),
386 while ((i
= loadquery(L_GETINFO
, buf
, size
)) == -1 && errno
== ENOMEM
) {
389 if ((buf
= malloc(size
)) == NULL
) {
391 snprintf(errbuf
, sizeof(errbuf
),
399 snprintf(errbuf
, sizeof(errbuf
),
406 * Traverse the list of loaded modules. The entry point
407 * returned by load() does actually point to the data
410 lp
= (struct ld_info
*)buf
;
412 if (lp
->ldinfo_dataorg
== mp
->entry
) {
413 ldp
= ldopen(lp
->ldinfo_filename
, ldp
);
416 if (lp
->ldinfo_next
== 0)
419 lp
= (struct ld_info
*)((char *)lp
+ lp
->ldinfo_next
);
424 snprintf (errbuf
, sizeof(errbuf
),
425 "readExports: %s", strerror(errno
));
429 if (TYPE(ldp
) != U802TOCMAGIC
) {
431 snprintf(errbuf
, sizeof(errbuf
), "readExports: bad magic");
432 while(ldclose(ldp
) == FAILURE
)
437 * Get the padding for the data section. This is needed for
438 * AIX 4.1 compilers. This is used when building the final
439 * function pointer to the exported symbol.
441 if (ldnshread(ldp
, _DATA
, &shdata
) != SUCCESS
) {
443 snprintf(errbuf
, sizeof(errbuf
),
444 "readExports: cannot read data section header");
445 while(ldclose(ldp
) == FAILURE
)
449 if (ldnshread(ldp
, _LOADER
, &sh
) != SUCCESS
) {
451 snprintf(errbuf
, sizeof(errbuf
),
452 "readExports: cannot read loader section header");
453 while(ldclose(ldp
) == FAILURE
)
458 * We read the complete loader section in one chunk, this makes
459 * finding long symbol names residing in the string table easier.
461 if ((ldbuf
= (char *)malloc(sh
.s_size
)) == NULL
) {
463 snprintf (errbuf
, sizeof(errbuf
),
464 "readExports: %s", strerror(errno
));
465 while(ldclose(ldp
) == FAILURE
)
469 if (FSEEK(ldp
, sh
.s_scnptr
, BEGINNING
) != OKFSEEK
) {
471 snprintf(errbuf
, sizeof(errbuf
),
472 "readExports: cannot seek to loader section");
474 while(ldclose(ldp
) == FAILURE
)
478 if (FREAD(ldbuf
, sh
.s_size
, 1, ldp
) != 1) {
480 snprintf(errbuf
, sizeof(errbuf
),
481 "readExports: cannot read loader section");
483 while(ldclose(ldp
) == FAILURE
)
487 lhp
= (LDHDR
*)ldbuf
;
488 ls
= (LDSYM
*)(ldbuf
+LDHDRSZ
);
490 * Count the number of exports to include in our export table.
492 for (i
= lhp
->l_nsyms
; i
; i
--, ls
++) {
493 if (!LDR_EXPORT(*ls
))
497 if ((mp
->exports
= (ExportPtr
)calloc(mp
->nExports
, sizeof(*mp
->exports
))) == NULL
) {
499 snprintf (errbuf
, sizeof(errbuf
),
500 "readExports: %s", strerror(errno
));
502 while(ldclose(ldp
) == FAILURE
)
507 * Fill in the export table. All entries are relative to
508 * the entry point we got from load.
511 ls
= (LDSYM
*)(ldbuf
+LDHDRSZ
);
512 for (i
= lhp
->l_nsyms
; i
; i
--, ls
++) {
514 char tmpsym
[SYMNMLEN
+1];
515 if (!LDR_EXPORT(*ls
))
517 if (ls
->l_zeroes
== 0)
518 symname
= ls
->l_offset
+lhp
->l_stoff
+ldbuf
;
521 * The l_name member is not zero terminated, we
522 * must copy the first SYMNMLEN chars and make
523 * sure we have a zero byte at the end.
525 strlcpy (tmpsym
, ls
->l_name
,
529 ep
->name
= strdup(symname
);
530 ep
->addr
= (void *)((unsigned long)mp
->entry
+
531 ls
->l_value
- shdata
.s_vaddr
);
535 while(ldclose(ldp
) == FAILURE
)
541 * Find the main modules entry point. This is used as export pointer
542 * for loadbind() to be able to resolve references to the main part.
544 static void * findMain(void)
552 if ((buf
= malloc(size
)) == NULL
) {
554 snprintf (errbuf
, sizeof(errbuf
),
555 "findMail: %s", strerror(errno
));
558 while ((i
= loadquery(L_GETINFO
, buf
, size
)) == -1 && errno
== ENOMEM
) {
561 if ((buf
= malloc(size
)) == NULL
) {
563 snprintf (errbuf
, sizeof(errbuf
),
564 "findMail: %s", strerror(errno
));
570 snprintf (errbuf
, sizeof(errbuf
),
571 "findMail: %s", strerror(errno
));
576 * The first entry is the main module. The entry point
577 * returned by load() does actually point to the data
580 lp
= (struct ld_info
*)buf
;
581 ret
= lp
->ldinfo_dataorg
;