/[ascend]/trunk/base/generic/utilities/ascDynaLoad.c
ViewVC logotype

Annotation of /trunk/base/generic/utilities/ascDynaLoad.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 59 - (hide annotations) (download) (as text)
Sun Oct 30 01:38:20 2005 UTC (14 years, 3 months ago) by jds
File MIME type: text/x-csrc
File size: 77454 byte(s)
- prototype unit test suite based on CUnit added.
- unit tests for base/generic/general and base/generic/utilites added.
- 2nd manual rework of doxygen documentation in general and utilities.
- bug fixes (mostly general & utilities) found during test development.
- added asc_assert prototype to redirect failures to Asc_Panic() and enable decoupling assertions from NDEBUG.
- some modifications of interface & implementation to facilitate testing.
- utilities/ascPrint & utilities/ascMalloc functions now always included in base libs to minimize recompilation when an interface chooses different options.
1 aw0a 1 /*
2     * -----------------------------------------------------------------
3     * Copyright 1993 D.I.S. - Universita` di Pavia - Italy
4     * -----------------------------------------------------------------
5     *
6     * Permission to use, copy, modify, distribute this software
7     * and its documentation foar any purpose is hereby granted without
8     * fee, provided that the above copyright notice appear in all
9     * copies and that both that copyright notice and this permission
10     * notice appear in supporting documentation, and that the name of
11     * D.I.S. not be used in advertising or publicity pertaining to
12     * distribution of the software without specific, written prior per-
13     * mission. D.I.S. makes no representations about the suitability
14     * of this software for any purpose. It is provided "as is" without
15     * express or implied warranty.
16     *
17     * D.I.S. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, IN-
18     * CLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
19     * NO EVENT SHALL D.I.S. BE LIABLE FOR ANY SPECIAL, INDIRECT OR
20     * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
21     * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
22     * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNEC-
23     * TION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
24     */
25    
26     /*
27     * Small changes made by Michael Moore (mdm@cis.ohio-state.edu)
28     * December 24th, 1993.
29     * The tcl sections ripped out by Kirk Abbott (ka0p@edrc.cmu.edu)
30     * September 3rd, 1994.
31     * To date the architectures supported are:
32     * sun - pure sunos, defines also handle MACH.
33     * osf,
34     * solaris,
35     * hpux
36     * sgi
37     * ultrix
38 jds 59 * Windows
39 aw0a 1 *
40     * Remember that under most systems, profiling does not work
41     * with dynamic libraries. !
42     */
43    
44     #include <stdio.h>
45     #include <stdlib.h>
46 ben.allan 45 #include <stdarg.h>
47 aw0a 1 #include "utilities/ascConfig.h"
48     #include "utilities/ascPrint.h"
49 ben.allan 16 #include "utilities/ascMalloc.h"
50 jds 59
51 aw0a 1 struct ascend_dlrecord {
52 jds 59 char *path; /* library name */
53 aw0a 1 void *dlreturn; /* return from dlopen */
54     struct ascend_dlrecord *next;
55     };
56    
57 jds 59 /* Linked list of library names & dlopen() return values. */
58 aw0a 1 static
59     struct ascend_dlrecord *g_ascend_dllist = NULL;
60    
61     /*
62 jds 59 * Adds a record of the path and handle to the list.
63     * If it fails to do this, returns 1, else 0.
64 aw0a 1 */
65     static
66     int AscAddRecord(void *dlreturn, CONST char *path)
67     {
68     struct ascend_dlrecord *new;
69     char *keeppath;
70     if (dlreturn == NULL || path == NULL) {
71     return 1;
72     }
73 jds 59 keeppath = strdup((char *)path);
74 aw0a 1 if (keeppath==NULL) return 1;
75     new = (struct ascend_dlrecord *)malloc(sizeof(struct ascend_dlrecord));
76     if (new==NULL) {
77     free(keeppath);
78     return 1;
79     }
80     new->next = g_ascend_dllist; /* insert at head */
81     g_ascend_dllist = new;
82     new->path = keeppath;
83     new->dlreturn = dlreturn;
84     return 0;
85     }
86    
87     /*
88     * Finds a record of the path given and returns the associated handle.
89     * If it fails to do this, returns NULL.
90     */
91     static
92     void *AscFindDLRecord(CONST char *path)
93     {
94     struct ascend_dlrecord *new;
95     if (path == NULL) {
96     return NULL;
97     }
98     new = g_ascend_dllist;
99     while (new != NULL && strcmp(new->path,path) != 0) {
100     /* advance new until no more new or new with path found */
101     new = new->next;
102     }
103     return (new != NULL) ? new->dlreturn : NULL;
104     }
105    
106     /*
107     * Finds and returns the handle to path, if one matches, and
108 jds 59 * deletes the record from the list. Returns NULL if not found.
109 aw0a 1 */
110     static
111     void *AscDeleteRecord(char *path)
112     {
113     struct ascend_dlrecord *nextptr, *lastptr, *old;
114     void *dlreturn = NULL;
115 jds 59
116     if ((g_ascend_dllist==NULL) || (NULL == path)) return NULL;
117    
118 aw0a 1 if (strcmp(path,g_ascend_dllist->path)==0) {
119     /* head case */
120     old = g_ascend_dllist;
121     g_ascend_dllist = old->next;
122     dlreturn = old->dlreturn;
123     free(old->path);
124     free(old);
125     } else {
126     lastptr = g_ascend_dllist;
127     nextptr = lastptr->next;
128     while (nextptr != NULL && strcmp(nextptr->path,path) != 0) {
129     lastptr = nextptr;
130     nextptr = nextptr->next;
131     }
132     /* so either nextptr is NULL and not in list, or nextptr is
133     * what we want to delete and lastptr is the link to it.
134     */
135     if (nextptr != NULL) {
136     old = nextptr;
137     lastptr->next = nextptr->next;
138     dlreturn = old->dlreturn;
139     free(old->path);
140     free(old);
141     }
142     }
143     return dlreturn;
144     }
145    
146     /*
147 jds 59 * Checks the list for a conflicting handle so we can issue
148 aw0a 1 * a more helpful warning, if need be, than the standard message.
149     */
150 jds 59 static
151 aw0a 1 void AscCheckDuplicateLoad(CONST char *path)
152     {
153     struct ascend_dlrecord *r;
154 jds 59
155     if (NULL == path) {
156     FPRINTF(stderr,"Null path in AscCheckDuplicateLoad\n");
157     return;
158     }
159    
160 aw0a 1 r = g_ascend_dllist;
161     while (r != NULL) {
162     if (strcmp(path,r->path)==0) {
163     FPRINTF(stderr,"Attempt to load already loaded %s\n",path);
164     return;
165     }
166     r = r->next;
167     }
168     }
169    
170     #ifdef __WIN32__
171     #include <windows.h>
172     int Asc_DynamicLoad(CONST char *path, CONST char *initFun)
173     {
174     #define ASCDL_OK /* this line should appear inside each Asc_DynamicLoad */
175     HINSTANCE xlib;
176     int (*install)();
177    
178 jds 59 if (NULL == path) {
179     FPRINTF(stderr,"Asc_DynamicLoad failed: Null path\n");
180     return 1;
181     }
182    
183 aw0a 1 AscCheckDuplicateLoad(path); /* whine if we've see it before */
184     /*
185     * If the named library does not exist, if it's not loadable or if
186     * it does not define the named install proc, report an error
187     */
188    
189     xlib = LoadLibrary(path);
190     if (xlib == NULL) {
191     FPRINTF(stderr,"Asc_DynamicLoad: LoadLibrary failed\n");
192     return 1;
193     }
194 jds 59 if (NULL != initFun) {
195     install = (int (*)())GetProcAddress(xlib,initFun);
196     if (install == NULL) {
197     FPRINTF(stderr,"Asc_DynamicLoad: Required function %s not found\n", initFun);
198     (void)FreeLibrary(xlib);
199     return 1;
200 aw0a 1 }
201     }
202 jds 59 if (0 != AscAddRecord(xlib,path)) {
203     FPRINTF(stderr,"Asc_DynamicLoad failed to record library (%s)\n",path);
204 aw0a 1 }
205 jds 59 return (initFun == NULL) ? 0 : (*install)();
206 aw0a 1 }
207     #endif /* __WIN32__ */
208     #if defined(sun) || defined(linux)
209     #ifndef MACH
210     #include <dlfcn.h>
211    
212     int Asc_DynamicLoad(CONST char *path, CONST char *initFun)
213     {
214     #define ASCDL_OK /* this line should appear inside each Asc_DynamicLoad */
215     void *xlib;
216     int (*install)();
217    
218 jds 59 if (NULL == path) {
219     FPRINTF(stderr,"Asc_DynamicLoad failed: Null path\n");
220     return 1;
221     }
222    
223 aw0a 1 AscCheckDuplicateLoad(path); /* whine if we've see it before */
224     /*
225     * If the named library does not exist, if it's not loadable or if
226     * it does not define the named install proc, report an error
227     */
228     xlib = dlopen(path, 1);
229     install = (int (*)())dlsym(xlib, initFun);
230     if ((xlib == NULL) || (install==NULL)) {
231     FPRINTF(stderr,"%s\n",(char *)dlerror());
232     if ( xlib != NULL ) dlclose(xlib);
233     return 1;
234     }
235 jds 59 if (0 != AscAddRecord(xlib,path)) {
236     FPRINTF(stderr,"Asc_DynamicLoad failed to record library (%s)\n",path);
237 aw0a 1 }
238 jds 59 return (initFun == NULL) ? 0 : (*install)();
239 aw0a 1 }
240    
241     int DynamicLoad(CONST char *path, CONST char *initFun)
242     {
243     void *xlib;
244     int (*install)();
245    
246 jds 59 if (NULL == path) {
247     FPRINTF(stderr,"DynamicLoad failed: Null path\n");
248     return 1;
249     }
250    
251 aw0a 1 /*
252     * If the named library does not exist, if it's not loadable or if
253     * it does not define the named install proc, report an error
254     */
255     xlib = dlopen(path, 1);
256     install = (int (*)())dlsym(xlib, initFun);
257     if ((xlib == NULL) || (install==NULL)) {
258     FPRINTF(stderr,"%s\n",(char *)dlerror());
259     if ( xlib != NULL ) dlclose(xlib);
260     return 1;
261     }
262     /*
263 jds 59 * Try to install the extension and report success or failure
264 aw0a 1 */
265     return (*install)();
266     }
267     #else /* MACH */
268     int DynamicLoad(CONST char *path, CONST char *initFun)
269     {
270     return 0;
271     }
272     #endif /* MACH */
273     #endif /* sun */
274    
275    
276    
277     #ifdef __osf__
278     #include <dlfcn.h>
279     int Asc_DynamicLoad(CONST char *path, CONST char *initFun)
280     {
281     #define ASCDL_OK /* this line should appear inside each Asc_DynamicLoad */
282     void *xlib;
283     int (*install)();
284 jds 59
285     if (NULL == path) {
286     FPRINTF(stderr,"Asc_DynamicLoad failed: Null path\n");
287     return 1;
288     }
289    
290 aw0a 1 AscCheckDuplicateLoad(path); /* whine if we've see it before */
291    
292     /*
293     * If the named library does not exist, if it's not loadable or if
294     * it does not define the named install proc, report an error
295     */
296     xlib = dlopen((char *)path, 1);
297     install = (int (*)())dlsym(xlib,(char *)initFun);
298     if ((xlib == NULL) || (install==NULL)) {
299     FPRINTF(stderr,"%s\n",(char *)dlerror());
300     if ( xlib != NULL ) dlclose(xlib);
301     return 1;
302     }
303 jds 59 if (0 != AscAddRecord(xlib,path)) {
304     FPRINTF(stderr,"Asc_DynamicLoad failed to record library (%s)\n",path);
305 aw0a 1 }
306 jds 59 return (initFun == NULL) ? 0 : (*install)();
307 aw0a 1 }
308     int DynamicLoad(CONST char *path, CONST char *initFun)
309     {
310     void *xlib;
311     int (*install)();
312    
313 jds 59 if (NULL == path) {
314     FPRINTF(stderr,"DynamicLoad failed: Null path\n");
315     return 1;
316     }
317    
318 aw0a 1 /*
319     * If the named library does not exist, if it's not loadable or if
320     * it does not define the named install proc, report an error
321     */
322     xlib = dlopen((char *)path, 1);
323     install = (int (*)())dlsym(xlib,(char *)initFun);
324     if ((xlib == NULL) || (install==NULL)) {
325     FPRINTF(stderr,"%s\n",(char *)dlerror());
326     if ( xlib != NULL ) dlclose(xlib);
327     return 1;
328     }
329     /*
330 jds 59 * Try to install the extension and report success or failure
331 aw0a 1 */
332     return (*install)();
333     }
334     #endif /* osf */
335    
336     #if defined(solaris) || defined(_AIX)
337     #if defined(solaris)
338     #include <dlfcn.h>
339     #else
340     /* under aix we have do also define dlopen and the rest of the
341     * dl interface, so swipe it from tcl.
342     * :r ../compat/dlfcn.h
343     * :r tclLoadAix.c
344     */
345     /*
346     * dlfcn.h --
347     *
348     * This file provides a replacement for the header file "dlfcn.h"
349     * on systems where dlfcn.h is missing. It's primary use is for
350 ben.allan 45 * AIX, where tcl emulates the dl library.
351 aw0a 1 *
352     * This file is subject to the following copyright notice, which is
353 ben.allan 45 * different from the notice used elsewhere in tcl but rougly
354 aw0a 1 * equivalent in meaning.
355     *
356     * Copyright (c) 1992,1993,1995,1996, Jens-Uwe Mager, Helios Software GmbH
357     * Not derived from licensed software.
358     *
359     * Permission is granted to freely use, copy, modify, and redistribute
360     * this software, provided that the author is not construed to be liable
361     * for any results of using the software, alterations are clearly marked
362     * as such, and this notice is not modified.
363     *
364     * SCCS: @(#) dlfcn.h 1.4 96/09/17 09:05:59
365     */
366    
367     /*
368     * @(#)dlfcn.h 1.4 revision of 95/04/25 09:36:52
369     * This is an unpublished work copyright (c) 1992 HELIOS Software GmbH
370     * 30159 Hannover, Germany
371     */
372    
373     #ifndef __dlfcn_h__
374     #define __dlfcn_h__
375    
376     /*_#ifndef _TCL */
377     /*_#include <tcl.h> */
378     /*_#endif */
379    
380     #ifdef __cplusplus
381     extern "C" {
382     #endif
383    
384     /*
385     * Mode flags for the dlopen routine.
386     */
387     #define RTLD_LAZY 1 /* lazy function call binding */
388     #define RTLD_NOW 2 /* immediate function call binding */
389     #define RTLD_GLOBAL 0x100 /* allow symbols to be global */
390    
391     /*
392     * To be able to intialize, a library may provide a dl_info structure
393     * that contains functions to be called to initialize and terminate.
394     */
395     struct dl_info {
396     void (*init)(void);
397     void (*fini)(void);
398     };
399    
400     void *dlopen(const char *path, int mode);
401     void *dlsym(void *handle, const char *symbol);
402     char *dlerror(void);
403     int dlclose(void *handle);
404    
405     #ifdef __cplusplus
406     }
407     #endif
408    
409     /*
410     * tclLoadAix.c --
411     *
412     * This file implements the dlopen and dlsym APIs under the
413 ben.allan 45 * AIX operating system, to enable the tcl "load" command to
414 aw0a 1 * work. This code was provided by Jens-Uwe Mager.
415     *
416     * This file is subject to the following copyright notice, which is
417 ben.allan 45 * different from the notice used elsewhere in tcl. The file has
418 aw0a 1 * been modified to incorporate the file dlfcn.h in-line.
419     *
420     * Copyright (c) 1992,1993,1995,1996, Jens-Uwe Mager, Helios Software GmbH
421     * Not derived from licensed software.
422    
423     * Permission is granted to freely use, copy, modify, and redistribute
424     * this software, provided that the author is not construed to be liable
425     * for any results of using the software, alterations are clearly marked
426     * as such, and this notice is not modified.
427     *
428     * SCCS: @(#) tclLoadAix.c 1.11 96/10/07 10:41:24
429     *
430     * Note: this file has been altered from the original in a few
431 ben.allan 45 * ways in order to work properly with tcl.
432 aw0a 1 */
433    
434     /*
435     * @(#)dlfcn.c 1.7 revision of 95/08/14 19:08:38
436     * This is an unpublished work copyright (c) 1992 HELIOS Software GmbH
437     * 30159 Hannover, Germany
438     */
439    
440     #include <stdio.h>
441     #include <errno.h>
442     #include <string.h>
443     #include <stdlib.h>
444     #include <sys/types.h>
445     #include <sys/ldr.h>
446     #include <a.out.h>
447     #include <ldfcn.h>
448    
449     /*
450     * We simulate dlopen() et al. through a call to load. Because AIX has
451     * no call to find an exported symbol we read the loader section of the
452     * loaded module and build a list of exported symbols and their virtual
453     * address.
454     */
455    
456     typedef struct {
457     char *name; /* the symbols's name */
458     void *addr; /* its relocated virtual address */
459     } Export, *ExportPtr;
460    
461     /*
462     * xlC uses the following structure to list its constructors and
463     * destructors. This is gleaned from the output of munch.
464     */
465     typedef struct {
466     void (*init)(void); /* call static constructors */
467     void (*term)(void); /* call static destructors */
468     } Cdtor, *CdtorPtr;
469    
470     /*
471     * The void * handle returned from dlopen is actually a ModulePtr.
472     */
473     typedef struct Module {
474     struct Module *next;
475     char *name; /* module name for refcounting */
476     int refCnt; /* the number of references */
477     void *entry; /* entry point from load */
478     struct dl_info *info; /* optional init/terminate functions */
479     CdtorPtr cdtors; /* optional C++ constructors */
480     int nExports; /* the number of exports found */
481     ExportPtr exports; /* the array of exports */
482     } Module, *ModulePtr;
483    
484     /*
485     * We keep a list of all loaded modules to be able to call the fini
486     * handlers and destructors at atexit() time.
487     */
488     static ModulePtr modList;
489    
490     /*
491     * The last error from one of the dl* routines is kept in static
492     * variables here. Each error is returned only once to the caller.
493     */
494     static char errbuf[BUFSIZ];
495     static int errvalid;
496    
497     static void caterr(char *);
498     static int readExports(ModulePtr);
499     static void terminate(void);
500     static void *findMain(void);
501    
502     void *dlopen(const char *path, int mode)
503     {
504     register ModulePtr mp;
505     static void *mainModule;
506    
507     /*
508     * Upon the first call register a terminate handler that will
509     * close all libraries. Also get a reference to the main module
510     * for use with loadbind.
511     */
512     if (!mainModule) {
513     if ((mainModule = findMain()) == NULL)
514     return NULL;
515     atexit(terminate);
516     }
517     /*
518     * Scan the list of modules if we have the module already loaded.
519     */
520     for (mp = modList; mp; mp = mp->next)
521     if (strcmp(mp->name, path) == 0) {
522     mp->refCnt++;
523     return (void *) mp;
524     }
525     if ((mp = (ModulePtr)calloc(1, sizeof(*mp))) == NULL) {
526     errvalid++;
527     strcpy(errbuf, "calloc: ");
528     strcat(errbuf, strerror(errno));
529     return (void *) NULL;
530     }
531     mp->name = malloc((unsigned) (strlen(path) + 1));
532     strcpy(mp->name, path);
533     /*
534     * load should be declared load(const char *...). Thus we
535     * cast the path to a normal char *. Ugly.
536     */
537     if ((mp->entry = (void *)load((char *)path, L_NOAUTODEFER, NULL)) == NULL) {
538     free(mp->name);
539     free(mp);
540     errvalid++;
541     strcpy(errbuf, "dlopen: ");
542     strcat(errbuf, path);
543     strcat(errbuf, ": ");
544     /*
545     * If AIX says the file is not executable, the error
546     * can be further described by querying the loader about
547     * the last error.
548     */
549     if (errno == ENOEXEC) {
550     char *tmp[BUFSIZ/sizeof(char *)];
551     if (loadquery(L_GETMESSAGES, tmp, sizeof(tmp)) == -1)
552     strcpy(errbuf, strerror(errno));
553     else {
554     char **p;
555     for (p = tmp; *p; p++)
556     caterr(*p);
557     }
558     } else
559     strcat(errbuf, strerror(errno));
560     return (void *) NULL;
561     }
562     mp->refCnt = 1;
563     mp->next = modList;
564     modList = mp;
565     if (loadbind(0, mainModule, mp->entry) == -1) {
566     dlclose(mp);
567     errvalid++;
568     strcpy(errbuf, "loadbind: ");
569     strcat(errbuf, strerror(errno));
570     return (void *) NULL;
571     }
572     /*
573     * If the user wants global binding, loadbind against all other
574     * loaded modules.
575     */
576     if (mode & RTLD_GLOBAL) {
577     register ModulePtr mp1;
578     for (mp1 = mp->next; mp1; mp1 = mp1->next)
579     if (loadbind(0, mp1->entry, mp->entry) == -1) {
580     dlclose(mp);
581     errvalid++;
582     strcpy(errbuf, "loadbind: ");
583     strcat(errbuf, strerror(errno));
584     return (void *) NULL;
585     }
586     }
587     if (readExports(mp) == -1) {
588     dlclose(mp);
589     return (void *) NULL;
590     }
591     /*
592     * If there is a dl_info structure, call the init function.
593     */
594     if (mp->info = (struct dl_info *)dlsym(mp, "dl_info")) {
595     if (mp->info->init)
596     (*mp->info->init)();
597     } else
598     errvalid = 0;
599     /*
600     * If the shared object was compiled using xlC we will need
601     * to call static constructors (and later on dlclose destructors).
602     */
603     if (mp->cdtors = (CdtorPtr)dlsym(mp, "__cdtors")) {
604     while (mp->cdtors->init) {
605     (*mp->cdtors->init)();
606     mp->cdtors++;
607     }
608     } else
609     errvalid = 0;
610     return (void *) mp;
611     }
612    
613     /*
614     * Attempt to decipher an AIX loader error message and append it
615     * to our static error message buffer.
616     */
617     static void caterr(char *s)
618     {
619     register char *p = s;
620    
621     while (*p >= '0' && *p <= '9')
622     p++;
623     switch(atoi(s)) {
624     case L_ERROR_TOOMANY:
625     strcat(errbuf, "to many errors");
626     break;
627     case L_ERROR_NOLIB:
628     strcat(errbuf, "can't load library");
629     strcat(errbuf, p);
630     break;
631     case L_ERROR_UNDEF:
632     strcat(errbuf, "can't find symbol");
633     strcat(errbuf, p);
634     break;
635     case L_ERROR_RLDBAD:
636     strcat(errbuf, "bad RLD");
637     strcat(errbuf, p);
638     break;
639     case L_ERROR_FORMAT:
640     strcat(errbuf, "bad exec format in");
641     strcat(errbuf, p);
642     break;
643     case L_ERROR_ERRNO:
644     strcat(errbuf, strerror(atoi(++p)));
645     break;
646     default:
647     strcat(errbuf, s);
648     break;
649     }
650     }
651    
652     void *dlsym(void *handle, const char *symbol)
653     {
654     register ModulePtr mp = (ModulePtr)handle;
655     register ExportPtr ep;
656     register int i;
657    
658     /*
659     * Could speed up the search, but I assume that one assigns
660     * the result to function pointers anyways.
661     */
662     for (ep = mp->exports, i = mp->nExports; i; i--, ep++)
663     if (strcmp(ep->name, symbol) == 0)
664     return ep->addr;
665     errvalid++;
666     strcpy(errbuf, "dlsym: undefined symbol ");
667     strcat(errbuf, symbol);
668     return NULL;
669     }
670    
671     char *dlerror(void)
672     {
673     if (errvalid) {
674     errvalid = 0;
675     return errbuf;
676     }
677     return NULL;
678     }
679    
680     int dlclose(void *handle)
681     {
682     register ModulePtr mp = (ModulePtr)handle;
683     int result;
684     register ModulePtr mp1;
685    
686     if (--mp->refCnt > 0)
687     return 0;
688     if (mp->info && mp->info->fini)
689     (*mp->info->fini)();
690     if (mp->cdtors)
691     while (mp->cdtors->term) {
692     (*mp->cdtors->term)();
693     mp->cdtors++;
694     }
695     result = unload(mp->entry);
696     if (result == -1) {
697     errvalid++;
698     strcpy(errbuf, strerror(errno));
699     }
700     if (mp->exports) {
701     register ExportPtr ep;
702     register int i;
703     for (ep = mp->exports, i = mp->nExports; i; i--, ep++)
704     if (ep->name)
705     free(ep->name);
706     free(mp->exports);
707     }
708     if (mp == modList)
709     modList = mp->next;
710     else {
711     for (mp1 = modList; mp1; mp1 = mp1->next)
712     if (mp1->next == mp) {
713     mp1->next = mp->next;
714     break;
715     }
716     }
717     free(mp->name);
718     free(mp);
719     return result;
720     }
721    
722     static void terminate(void)
723     {
724     while (modList)
725     dlclose(modList);
726     }
727    
728     /*
729     * Build the export table from the XCOFF .loader section.
730     */
731     static int readExports(ModulePtr mp)
732     {
733     LDFILE *ldp = NULL;
734     SCNHDR sh, shdata;
735     LDHDR *lhp;
736     char *ldbuf;
737     LDSYM *ls;
738     int i;
739     ExportPtr ep;
740    
741     if ((ldp = ldopen(mp->name, ldp)) == NULL) {
742     struct ld_info *lp;
743     char *buf;
744     int size = 4*1024;
745     if (errno != ENOENT) {
746     errvalid++;
747     strcpy(errbuf, "readExports: ");
748     strcat(errbuf, strerror(errno));
749     return -1;
750     }
751     /*
752     * The module might be loaded due to the LIBPATH
753     * environment variable. Search for the loaded
754     * module using L_GETINFO.
755     */
756     if ((buf = malloc(size)) == NULL) {
757     errvalid++;
758     strcpy(errbuf, "readExports: ");
759     strcat(errbuf, strerror(errno));
760     return -1;
761     }
762     while ((i = loadquery(L_GETINFO, buf, size)) == -1 && errno == ENOMEM) {
763     free(buf);
764     size += 4*1024;
765     if ((buf = malloc(size)) == NULL) {
766     errvalid++;
767     strcpy(errbuf, "readExports: ");
768     strcat(errbuf, strerror(errno));
769     return -1;
770     }
771     }
772     if (i == -1) {
773     errvalid++;
774     strcpy(errbuf, "readExports: ");
775     strcat(errbuf, strerror(errno));
776     free(buf);
777     return -1;
778     }
779     /*
780     * Traverse the list of loaded modules. The entry point
781     * returned by load() does actually point to the data
782     * segment origin.
783     */
784     lp = (struct ld_info *)buf;
785     while (lp) {
786     if (lp->ldinfo_dataorg == mp->entry) {
787     ldp = ldopen(lp->ldinfo_filename, ldp);
788     break;
789     }
790     if (lp->ldinfo_next == 0)
791     lp = NULL;
792     else
793     lp = (struct ld_info *)((char *)lp + lp->ldinfo_next);
794     }
795     free(buf);
796     if (!ldp) {
797     errvalid++;
798     strcpy(errbuf, "readExports: ");
799     strcat(errbuf, strerror(errno));
800     return -1;
801     }
802     }
803     if (TYPE(ldp) != U802TOCMAGIC) {
804     errvalid++;
805     strcpy(errbuf, "readExports: bad magic");
806     while(ldclose(ldp) == FAILURE)
807     ;
808     return -1;
809     }
810     /*
811     * Get the padding for the data section. This is needed for
812     * AIX 4.1 compilers. This is used when building the final
813     * function pointer to the exported symbol.
814     */
815     if (ldnshread(ldp, _DATA, &shdata) != SUCCESS) {
816     errvalid++;
817     strcpy(errbuf, "readExports: cannot read data section header");
818     while(ldclose(ldp) == FAILURE)
819     ;
820     return -1;
821     }
822     if (ldnshread(ldp, _LOADER, &sh) != SUCCESS) {
823     errvalid++;
824     strcpy(errbuf, "readExports: cannot read loader section header");
825     while(ldclose(ldp) == FAILURE)
826     ;
827     return -1;
828     }
829     /*
830     * We read the complete loader section in one chunk, this makes
831     * finding long symbol names residing in the string table easier.
832     */
833     if ((ldbuf = (char *)malloc(sh.s_size)) == NULL) {
834     errvalid++;
835     strcpy(errbuf, "readExports: ");
836     strcat(errbuf, strerror(errno));
837     while(ldclose(ldp) == FAILURE)
838     ;
839     return -1;
840     }
841     if (FSEEK(ldp, sh.s_scnptr, BEGINNING) != OKFSEEK) {
842     errvalid++;
843     strcpy(errbuf, "readExports: cannot seek to loader section");
844     free(ldbuf);
845     while(ldclose(ldp) == FAILURE)
846     ;
847     return -1;
848     }
849     if (FREAD(ldbuf, sh.s_size, 1, ldp) != 1) {
850     errvalid++;
851     strcpy(errbuf, "readExports: cannot read loader section");
852     free(ldbuf);
853     while(ldclose(ldp) == FAILURE)
854     ;
855     return -1;
856     }
857     lhp = (LDHDR *)ldbuf;
858     ls = (LDSYM *)(ldbuf+LDHDRSZ);
859     /*
860     * Count the number of exports to include in our export table.
861     */
862     for (i = lhp->l_nsyms; i; i--, ls++) {
863     if (!LDR_EXPORT(*ls))
864     continue;
865     mp->nExports++;
866     }
867     if ((mp->exports = (ExportPtr)calloc(mp->nExports, sizeof(*mp->exports))) == NULL) {
868     errvalid++;
869     strcpy(errbuf, "readExports: ");
870     strcat(errbuf, strerror(errno));
871     free(ldbuf);
872     while(ldclose(ldp) == FAILURE)
873     ;
874     return -1;
875     }
876     /*
877     * Fill in the export table. All entries are relative to
878     * the entry point we got from load.
879     */
880     ep = mp->exports;
881     ls = (LDSYM *)(ldbuf+LDHDRSZ);
882     for (i = lhp->l_nsyms; i; i--, ls++) {
883     char *symname;
884     char tmpsym[SYMNMLEN+1];
885     if (!LDR_EXPORT(*ls))
886     continue;
887     if (ls->l_zeroes == 0)
888     symname = ls->l_offset+lhp->l_stoff+ldbuf;
889     else {
890     /*
891     * The l_name member is not zero terminated, we
892     * must copy the first SYMNMLEN chars and make
893     * sure we have a zero byte at the end.
894     */
895     strncpy(tmpsym, ls->l_name, SYMNMLEN);
896     tmpsym[SYMNMLEN] = '\0';
897     symname = tmpsym;
898     }
899     ep->name = malloc((unsigned) (strlen(symname) + 1));
900     strcpy(ep->name, symname);
901     ep->addr = (void *)((unsigned long)mp->entry +
902     ls->l_value - shdata.s_vaddr);
903     ep++;
904     }
905     free(ldbuf);
906     while(ldclose(ldp) == FAILURE)
907     ;
908     return 0;
909     }
910    
911     /*
912     * Find the main modules entry point. This is used as export pointer
913     * for loadbind() to be able to resolve references to the main part.
914     */
915     static void * findMain(void)
916     {
917     struct ld_info *lp;
918     char *buf;
919     int size = 4*1024;
920     int i;
921     void *ret;
922    
923     if ((buf = malloc(size)) == NULL) {
924     errvalid++;
925     strcpy(errbuf, "findMain: ");
926     strcat(errbuf, strerror(errno));
927     return NULL;
928     }
929     while ((i = loadquery(L_GETINFO, buf, size)) == -1 && errno == ENOMEM) {
930     free(buf);
931     size += 4*1024;
932     if ((buf = malloc(size)) == NULL) {
933     errvalid++;
934     strcpy(errbuf, "findMain: ");
935     strcat(errbuf, strerror(errno));
936     return NULL;
937     }
938     }
939     if (i == -1) {
940     errvalid++;
941     strcpy(errbuf, "findMain: ");
942     strcat(errbuf, strerror(errno));
943     free(buf);
944     return NULL;
945     }
946     /*
947     * The first entry is the main module. The entry point
948     * returned by load() does actually point to the data
949     * segment origin.
950     */
951     lp = (struct ld_info *)buf;
952     ret = lp->ldinfo_dataorg;
953     free(buf);
954     return ret;
955     }
956    
957     #endif /* __dlfcn_h__ */
958    
959     #endif /* solaris or aix dlfcn */
960    
961     int Asc_DynamicLoad(CONST char *path, CONST char *initFun)
962     {
963     #define ASCDL_OK /* this line should appear inside each Asc_DynamicLoad */
964     void *xlib;
965     int (*install)();
966 jds 59
967     if (NULL == path) {
968     FPRINTF(stderr,"Asc_DynamicLoad failed: Null path\n");
969     return 1;
970     }
971    
972 aw0a 1 AscCheckDuplicateLoad(path); /* whine if we've see it before */
973    
974     /*
975     * If the named library does not exist, if it's not loadable or if
976     * it does not define the named install proc, report an error
977     */
978     xlib = dlopen(path, 1);
979     install = (int (*)())dlsym(xlib, initFun);
980     if ((xlib == NULL) || (install==NULL)) {
981     FPRINTF(stderr,"%s\n",(char *)dlerror());
982     if ( xlib != NULL ) dlclose(xlib);
983     return 1;
984     }
985 jds 59 if (0 != AscAddRecord(xlib,path)) {
986     FPRINTF(stderr,"Asc_DynamicLoad failed to record library (%s)\n",path);
987 aw0a 1 }
988 jds 59 return (initFun == NULL) ? 0 : (*install)();
989 aw0a 1 }
990    
991     int DynamicLoad(CONST char *path, CONST char *initFun)
992     {
993     void *xlib;
994     int (*install)();
995    
996 jds 59 if (NULL == path) {
997     FPRINTF(stderr,"DynamicLoad failed: Null path\n");
998     return 1;
999     }
1000    
1001 aw0a 1 /*
1002     * If the named library does not exist, if it's not loadable or if
1003     * it does not define the named install proc, report an error
1004     */
1005     xlib = dlopen(path, 1);
1006     install = (int (*)())dlsym(xlib, initFun);
1007     if ((xlib == NULL) || (install==NULL)) {
1008     FPRINTF(stderr,"%s\n",(char *)dlerror());
1009     if ( xlib != NULL ) dlclose(xlib);
1010     return 1;
1011     }
1012     /*
1013 jds 59 * Try to install the extension and report success or failure
1014 aw0a 1 */
1015     return (*install)();
1016     }
1017     #endif /* solaris, aix */
1018    
1019    
1020     #ifdef _SGI_SOURCE
1021     #include <dlfcn.h>
1022     int Asc_DynamicLoad(CONST char *path, CONST char *initFun)
1023     {
1024     #define ASCDL_OK /* this line should appear inside each Asc_DynamicLoad */
1025     void *xlib;
1026     int (*install)();
1027 jds 59
1028     if (NULL == path) {
1029     FPRINTF(stderr,"Asc_DynamicLoad failed: Null path\n");
1030     return 1;
1031     }
1032    
1033 aw0a 1 AscCheckDuplicateLoad(path); /* whine if we've see it before */
1034    
1035     /*
1036     * If the named library does not exist, if it's not loadable or if
1037     * it does not define the named install proc, report an error
1038     */
1039     xlib = dlopen(path, 1);
1040     install = (int (*)())dlsym(xlib, initFun);
1041     if ((xlib == NULL) || (install==NULL)) {
1042     FPRINTF(stderr,"%s\n",(char *)dlerror());
1043     if ( xlib != NULL ) dlclose(xlib);
1044     return 1;
1045     }
1046 jds 59 if (0 != AscAddRecord(xlib,path)) {
1047     FPRINTF(stderr,"Asc_DynamicLoad failed to record library (%s)\n",path);
1048 aw0a 1 }
1049 jds 59 return (initFun == NULL) ? 0 : (*install)();
1050 aw0a 1 }
1051    
1052     int DynamicLoad(CONST char *path, CONST char *initFun)
1053     {
1054     void *xlib;
1055     int (*install)();
1056    
1057 jds 59 if (NULL == path) {
1058     FPRINTF(stderr,"DynamicLoad failed: Null path\n");
1059     return 1;
1060     }
1061    
1062 aw0a 1 /*
1063     * If the named library does not exist, if it's not loadable or if
1064     * it does not define the named install proc, report an error
1065     */
1066     xlib = dlopen(path, 1);
1067     install = (int (*)())dlsym(xlib, initFun);
1068     if ((xlib == NULL) || (install==NULL)) {
1069     FPRINTF(stderr,"%s\n",(char *)dlerror());
1070     if ( xlib != NULL ) dlclose(xlib);
1071     return 1;
1072     }
1073     /*
1074 jds 59 * Try to install the extension and report success or failure
1075 aw0a 1 */
1076     return (*install)();
1077     }
1078     #endif /* _SGI_SOURCE */
1079    
1080    
1081     #ifdef __hpux
1082     /*
1083     * Modified to work with HP/UX 9.X Operating System.
1084     * Michael Moore (mdm@cis.ohio-state.edu)
1085     * December 24th, 1993.
1086     * Further modified by Kirk Abbott (ka0p@edrc.cmu.edu)
1087     * to fit in with the ASCEND system.
1088     */
1089    
1090     #include <dl.h>
1091     #include <errno.h>
1092    
1093     int Asc_DynamicLoad(CONST char *path, CONST char *initFun)
1094     {
1095     #define ASCDL_OK /* this line should appear inside each Asc_DynamicLoad */
1096     shl_t xlib;
1097     int (*install)();
1098     int i;
1099 jds 59
1100     if (NULL == path) {
1101     FPRINTF(stderr,"Asc_DynamicLoad failed: Null path\n");
1102     return 1;
1103     }
1104    
1105 aw0a 1 AscCheckDuplicateLoad(path); /* whine if we've see it before */
1106    
1107     /*
1108     * If the named library does not exist, if it's not loadable or if
1109     * it does not define the named install proc, report an error
1110     */
1111     xlib = shl_load(path, BIND_IMMEDIATE | BIND_VERBOSE, 0L);
1112     if (xlib == (shl_t) NULL) {
1113     FPRINTF(stderr,"Unable to load shared library : %s\n",strerror(errno));
1114     return 1;
1115     }
1116 jds 59 if (NULL != initFun) {
1117     i = shl_findsym(&xlib, initFun, TYPE_PROCEDURE, &install);
1118     if (i == -1) {
1119     FPRINTF(stderr,"Unable to find needed symbol %s %s\n",
1120     initFun, strerror(errno));
1121     shl_unload(xlib); /* baa */
1122     return 1;
1123 aw0a 1 }
1124 jds 59 if (install == NULL) {
1125     FPRINTF(stderr,"Unable to find needed symbol %s\n",initFun);
1126     FPRINTF(stderr,"Error type unknown\n");
1127     shl_unload(xlib); /* baa */
1128     return 1;
1129     }
1130 aw0a 1 }
1131 jds 59 if (0 != AscAddRecord(xlib,path)) {
1132     FPRINTF(stderr,"Asc_DynamicLoad failed to record library (%s)\n",path);
1133 aw0a 1 }
1134 jds 59 return (initFun == NULL) ? 0 : (*install)();
1135 aw0a 1 }
1136    
1137     int DynamicLoad(CONST char *path, CONST char *initFun)
1138     {
1139     shl_t xlib;
1140     int (*install)();
1141     int i;
1142    
1143 jds 59 if (NULL == path) {
1144     FPRINTF(stderr,"DynamicLoad failed: Null path\n");
1145     return 1;
1146     }
1147    
1148 aw0a 1 /*
1149     * If the named library does not exist, if it's not loadable or if
1150     * it does not define the named install proc, report an error
1151     */
1152     xlib = shl_load(path, BIND_IMMEDIATE | BIND_VERBOSE, 0L);
1153     if (xlib == (shl_t) NULL) {
1154     FPRINTF(stderr,"Unable to load shared library : %s\n",strerror(errno));
1155     return 1;
1156     }
1157     i = shl_findsym(&xlib, initFun, TYPE_PROCEDURE, &install);
1158     if (i == -1) {
1159     FPRINTF(stderr,"Unable to find needed symbol %s %s\n",
1160     initFun, strerror(errno));
1161     return 1;
1162     }
1163     if (install == NULL) {
1164     FPRINTF(stderr,"Unable to find needed symbol %s\n",initFun);
1165     FPRINTF(stderr,"Error type unknown\n");
1166     return 1;
1167     }
1168     /*
1169     * Try to install the extension and report success or failure
1170     */
1171     return (*install)();
1172     }
1173     #endif /* __hpux */
1174    
1175    
1176    
1177     #ifdef ultrix
1178     /*
1179     * Ultrix 4.x Dynamic Loader Library Version 1.0
1180     *
1181     * dl.h--
1182     * header file for the Dynamic Loader Library
1183     *
1184     *
1185     * Copyright (c) 1993 Andrew K. Yu, University of California at Berkeley
1186     * All rights reserved.
1187     *
1188     * Permission to use, copy, modify, and distribute this software and its
1189     * documentation for educational, research, and non-profit purposes and
1190     * without fee is hereby granted, provided that the above copyright
1191     * notice appear in all copies and that both that copyright notice and
1192     * this permission notice appear in supporting documentation. Permission
1193     * to incorporate this software into commercial products can be obtained
1194     * from the author. The University of California and the author make
1195     * no representations about the suitability of this software for any
1196     * purpose. It is provided "as is" without express or implied warranty.
1197     *
1198     */
1199     #include <filehdr.h>
1200     #include <syms.h>
1201     #include <reloc.h>
1202     #include <scnhdr.h>
1203     #include <fcntl.h>
1204     #include <ar.h>
1205    
1206     typedef long CoreAddr;
1207    
1208    
1209     typedef struct ScnInfo {
1210     CoreAddr addr; /* starting address of the section */
1211     SCNHDR hdr; /* section header */
1212     RELOC *relocEntries; /* relocation entries */
1213     } ScnInfo;
1214    
1215     typedef enum {
1216     DL_NEEDRELOC, /* still need relocation */
1217     DL_RELOCATED, /* no relocation necessary */
1218     DL_INPROG /* relocation in progress */
1219     } dlRStatus;
1220    
1221     typedef struct JmpTbl {
1222     char *block; /* the jump table memory block */
1223     struct JmpTbl *next; /* next block */
1224     } JmpTbl;
1225    
1226     typedef struct dlFile {
1227     char *filename; /* file name of the object file */
1228    
1229     int textSize; /* used by mprotect */
1230     CoreAddr textAddress; /* start addr of text section */
1231     long textVaddr; /* vaddr of text section in obj file */
1232     CoreAddr rdataAddress; /* start addr of rdata section */
1233     long rdataVaddr; /* vaddr of text section in obj file */
1234     CoreAddr dataAddress; /* start addr of data section */
1235     long dataVaddr; /* vaddr of text section in obj file */
1236     CoreAddr bssAddress; /* start addr of bss section */
1237     long bssVaddr; /* vaddr of text section in obj file */
1238    
1239     int nsect; /* number of sections */
1240     ScnInfo *sect; /* details of each section (array) */
1241    
1242     int issExtMax; /* size of string space */
1243     char *extss; /* extern sym string space (in core) */
1244     int iextMax; /* maximum number of Symbols */
1245     pEXTR extsyms; /* extern syms */
1246    
1247     dlRStatus relocStatus; /* what relocation needed? */
1248     int needReloc;
1249    
1250     JmpTbl *jmptable; /* the jump table for R_JMPADDR */
1251    
1252     struct dlFile *next; /* next member of the archive */
1253     } dlFile;
1254    
1255     typedef struct dlSymbol {
1256     char *name; /* name of the symbol */
1257     long addr; /* address of the symbol */
1258     dlFile *objFile; /* from which file */
1259     } dlSymbol;
1260    
1261     /*
1262     * prototypes for the dl* interface
1263     */
1264     extern void *dlopen(/* char *filename, int mode */);
1265     extern void *dlsym(/* void *handle, char *name */);
1266     extern void dlclose(/* void *handle */);
1267     extern char *dlerror(/* void */);
1268    
1269     #define DL_LAZY 0 /* lazy resolution */
1270     #define DL_NOW 1 /* immediate resolution */
1271    
1272     /*
1273     * Miscellaneous utility routines:
1274     */
1275     extern char **dl_undefinedSymbols(/* int *count */);
1276     extern void dl_printAllSymbols(/* void *handle */);
1277     extern void dl_setLibraries(/* char *libs */);
1278    
1279     /* here we are in ultrix land */
1280     int Asc_DynamicLoad(CONST char *path, CONST char *initFun)
1281     {
1282     #define ASCDL_OK /* this line should appear inside each Asc_DynamicLoad */
1283     void *xlib;
1284     int (*install)();
1285    
1286 jds 59 if (NULL == path) {
1287     FPRINTF(stderr,"Asc_DynamicLoad failed: Null path\n");
1288     return 1;
1289     }
1290    
1291 aw0a 1 AscCheckDuplicateLoad(path); /* whine if we've see it before */
1292     /*
1293     * If the named library does not exist, if it's not loadable or if
1294     * it does not define the named install proc, report an error
1295     */
1296     xlib = dlopen(path, 1);
1297     install = (int (*)())dlsym(xlib, initFun);
1298     if ((xlib == NULL) || (install==NULL)) {
1299     FPRINTF(stderr,"%s\n",(char *)dlerror());
1300     if ( xlib != NULL ) dlclose(xlib);
1301     return 1;
1302     }
1303 jds 59 if (0 != AscAddRecord(xlib,path)) {
1304     FPRINTF(stderr,"Asc_DynamicLoad failed to record library (%s)\n",path);
1305 aw0a 1 }
1306 jds 59 return (initFun == NULL) ? 0 : (*install)();
1307 aw0a 1 }
1308     /*
1309     * This is where we put a wrapper around all of the
1310     * ultrix based dynamic loading code.
1311     */
1312     int DynamicLoad(CONST char *path, CONST char *initFun)
1313     {
1314     void *xlib;
1315     int (*install)();
1316    
1317 jds 59 if (NULL == path) {
1318     FPRINTF(stderr,"DynamicLoad failed: Null path\n");
1319     return 1;
1320     }
1321    
1322 aw0a 1 /*
1323     * If the named library does not exist, if it's not loadable or if
1324     * it does not define the named install proc, report an error
1325     */
1326     xlib = dlopen(path, 1);
1327     install = (int (*)())dlsym(xlib, initFun);
1328     if ((xlib == NULL) || (install==NULL)) {
1329     FPRINTF(stderr,"%s\n",(char *)dlerror());
1330     if ( xlib != NULL ) dlclose(xlib);
1331     return 1;
1332     }
1333     /*
1334 jds 59 * Try to install the extension and report success or failure
1335 aw0a 1 */
1336     return (*install)();
1337     }
1338    
1339    
1340     /*
1341     * dlPriv.h--
1342     * the Private header file for the Dynamic Loader Library. Normal
1343     * users should have no need to include this file.
1344     *
1345     *
1346     * Copyright (c) 1993 Andrew K. Yu, University of California at Berkeley
1347     * All rights reserved.
1348     *
1349     * Permission to use, copy, modify, and distribute this software and its
1350     * documentation for educational, research, and non-profit purposes and
1351     * without fee is hereby granted, provided that the above copyright
1352     * notice appear in all copies and that both that copyright notice and
1353     * this permission notice appear in supporting documentation. Permission
1354     * to incorporate this software into commercial products can be obtained
1355     * from the author. The University of California and the author make
1356     * no representations about the suitability of this software for any
1357     * purpose. It is provided "as is" without express or implied warranty.
1358     *
1359     */
1360    
1361     extern dlSymbol *dl_hashSearchSymbol();
1362     extern dlSymbol *dl_hashInsertSymbolStrIdx();
1363    
1364     #define STRCOPY(x) (char *)strcpy((char *)malloc(strlen(x)+1), x)
1365    
1366     #define HASHTABSZ 1001
1367    
1368     typedef struct HEnt_ {
1369     dlSymbol *symbol;
1370     struct HEnt_ *next;
1371     } HEnt;
1372    
1373     typedef struct JmpTblHdr {
1374     int current; /* current empty slot */
1375     int max; /* max no. of slots */
1376     int dummy[2]; /* padding to make this 4 words */
1377     } JmpTblHdr;
1378    
1379     extern HEnt **dlHashTable;
1380     extern int _dl_undefinedSymbolCount;
1381    
1382     extern dlFile *_dl_openObject();
1383     extern void _dl_closeObject();
1384    
1385     extern int _dl_loadSections();
1386     extern int _dl_loadSymbols();
1387    
1388     dlFile *_dl_loadEntireArchive();
1389    
1390    
1391    
1392     /*
1393     * dlArch.c--
1394     * handles loading of library archives.
1395     *
1396     *
1397     * Copyright (c) 1993 Andrew K. Yu, University of California at Berkeley
1398     * All rights reserved.
1399     *
1400     * Permission to use, copy, modify, and distribute this software and its
1401     * documentation for educational, research, and non-profit purposes and
1402     * without fee is hereby granted, provided that the above copyright
1403     * notice appear in all copies and that both that copyright notice and
1404     * this permission notice appear in supporting documentation. Permission
1405     * to incorporate this software into commercial products can be obtained
1406     * from the author. The University of California and the author make
1407     * no representations about the suitability of this software for any
1408     * purpose. It is provided "as is" without express or implied warranty.
1409     *
1410     */
1411     #include <stdio.h>
1412     #include <strings.h>
1413     /* #include <sys/types.h> */
1414     /* #include <sys/stat.h> */
1415    
1416     /*
1417     * Sometimes, you might want to have undefined symbols searched from
1418     * standard libraries like libc.a and libm.a automatically. dl_setLibraries
1419     * is the interface to do this. dl_stdLibraries contain an arrary of
1420     * strings specifying the libraries to be searched.
1421     */
1422     char **dl_stdLibraries= NULL;
1423    
1424     static int searchArchive();
1425     static int readArchiveRanlibs();
1426     static int archGetObjectName();
1427     static int archLoadObject();
1428     static int loadArchSections();
1429    
1430     /*****************************************************************************
1431     * *
1432     * Searching of pre-set libraries *
1433     * *
1434     *****************************************************************************/
1435    
1436     /*
1437     * dl_searchLibraries returns 1 if undefined symbols are found during the
1438     * searching. 0 otherwise.
1439     */
1440     int dl_searchLibraries()
1441     {
1442     char **libs= dl_stdLibraries;
1443     int result= 0;
1444    
1445     if (dl_stdLibraries && _dl_undefinedSymbolCount) {
1446     while(*libs) {
1447     result|= searchArchive(*libs);
1448     libs++;
1449     }
1450     }
1451     return (result);
1452     }
1453    
1454     /*
1455     * dl_setLibraries--
1456     * takes a string of the form <library>[:<library> ... ] which
1457     * specifies the libraries to be searched automatically when there are
1458     * undefined symbols.
1459     *
1460     * eg. dl_setLibraries("/usr/lib/libc_G0.a:/usr/lib/libm_G0.a");
1461     */
1462     void dl_setLibraries( libs )
1463     char *libs;
1464     {
1465     char *name, *t;
1466     char **stnlib;
1467     int numlibs= 0;
1468     int maxlibs= 4;
1469    
1470     if(!libs)
1471     return;
1472     stnlib= (char **)malloc(sizeof(char *) * maxlibs);
1473     name=t= libs;
1474     while(*t!='\0') {
1475     while(*t!=':' && *t!='\0')
1476     t++;
1477     if (t-name>0) {
1478     stnlib[numlibs]= strncpy((char*)malloc(t-name+1),name,t-name);
1479     stnlib[numlibs++][t-name]='\0';
1480     if(numlibs==maxlibs-1) {
1481     maxlibs*= 2;
1482     stnlib= (char **)realloc(stnlib, sizeof(char *) * maxlibs);
1483     }
1484     }
1485     if (*t==':') {
1486     t++;
1487     name= t;
1488     }
1489     }
1490     stnlib[numlibs]= NULL;
1491     if (dl_stdLibraries) {
1492     char **s= dl_stdLibraries;
1493     while(*s!=NULL) {
1494     free(*s);
1495     s++;
1496     }
1497     free(dl_stdLibraries);
1498     }
1499     dl_stdLibraries= stnlib;
1500    
1501     return;
1502     }
1503    
1504     /*****************************************************************************
1505     * *
1506     * Internal Rountines *
1507     * *
1508     *****************************************************************************/
1509    
1510     static int searchArchive( archname )
1511     char *archname;
1512     {
1513     int found= 0, done;
1514     struct ranlib *pran;
1515     char *pstr;
1516     int i;
1517     int fd;
1518    
1519     /*
1520     * opens the archive file and reads in the ranlib hashtable
1521     */
1522     if ((fd=readArchiveRanlibs(archname, &pran, &pstr)) < 0) {
1523     FPRINTF(stderr, "dl: cannot open \"%s\"", archname);
1524     return 0;
1525     }
1526     /*
1527     * look through our symbol hash table and see if we find anything.
1528     * We have to scan until no undefined symbols can be found in the
1529     * archive. (Note that bringing in an object file might require another
1530     * object file in the archive. We'll have missed the symbol if we
1531     * do this one pass and the symbol happens to be inserted into buckets
1532     * we've examined already.)
1533     */
1534     do {
1535     done= 1;
1536     for(i=0; i < HASHTABSZ; i++) {
1537     HEnt *ent= dlHashTable[i];
1538     struct ranlib *r;
1539     while(ent) {
1540     if (!ent->symbol->objFile) {
1541     r= (struct ranlib *)ranlookup(ent->symbol->name);
1542     if (r->ran_off) {
1543     /*
1544     * we've found the undefined symbol in the archive
1545     */
1546     #if DEBUG
1547     PRINTF("*** found %s in ", ent->symbol->name);
1548     #endif
1549     if (archLoadObject(fd, r->ran_off)) {
1550     found= 1;
1551     done= 0;
1552     }
1553     }
1554     }
1555     ent=ent->next;
1556     }
1557     }
1558     } while (!done);
1559     /*
1560     * be a good citizen.
1561     */
1562     free(pran);
1563     free(pstr);
1564     close(fd);
1565    
1566     return found;
1567     }
1568    
1569     /*
1570     * readArchiveRanlibs--
1571     * opens a library and reads in the ranlib hash table and its
1572     * associated string table. It returns -1 if fails, the opened
1573     * file descriptor otherwise. It also inits the ranhashtable.
1574     */
1575     static int readArchiveRanlibs( archfile, pran, pstr )
1576     char *archfile; struct ranlib **pran; char **pstr;
1577     {
1578     int numRanlibs, numStrings;
1579     struct ranlib *ranlibs;
1580     char *strings;
1581     ARHDR ar_hdr;
1582     int fd, size;
1583     char mag[SARMAG];
1584    
1585     *pran= NULL;
1586     *pstr= NULL;
1587     /*
1588     * opens the library and check the magic string
1589     */
1590     if ((fd= open(archfile, O_RDONLY)) < 0 ||
1591     read(fd, mag, SARMAG)!=SARMAG ||
1592     strncmp(mag, ARMAG, SARMAG)!=0) {
1593     close(fd);
1594     return -1;
1595     }
1596     /*
1597     * reads in the archive header (not used) and the number of ranlibs.
1598     */
1599     if (read(fd, &ar_hdr, sizeof(ARHDR))!=sizeof(ARHDR) ||
1600     read(fd, &numRanlibs, sizeof(int))!= sizeof(int)) {
1601     close(fd);
1602     return -1;
1603     }
1604     /*
1605     * reads in the ranlib hash table and the string table size.
1606     */
1607     size= sizeof(struct ranlib)*numRanlibs;
1608     ranlibs= (struct ranlib *)malloc(size);
1609     if (read(fd, ranlibs, size)!=size ||
1610     read(fd, &numStrings, sizeof(int))!=sizeof(int)) {
1611     close(fd);
1612     return -1;
1613     }
1614     /*
1615     * reads in the string table.
1616     */
1617     strings= (char *)malloc(numStrings);
1618     if (read(fd, strings, numStrings)!=numStrings) {
1619     close(fd);
1620     return -1;
1621     }
1622     *pran= ranlibs;
1623     *pstr= strings;
1624     ranhashinit(ranlibs, strings, numRanlibs);
1625     return fd;
1626     }
1627    
1628     static int archLoadObject( fd, offset )
1629     int fd; int offset;
1630     {
1631     dlFile *dlfile;
1632     FILHDR filhdr;
1633     ARHDR arhdr;
1634     char ar_name[17];
1635    
1636     if (lseek(fd, offset, SEEK_SET)==-1 ||
1637     read(fd, &arhdr, sizeof(ARHDR))!=sizeof(ARHDR) ||
1638     read(fd, &filhdr, sizeof(filhdr))!=sizeof(filhdr))
1639     return 0;
1640     sscanf(arhdr.ar_name, "%16s", ar_name);
1641     ar_name[16]='\0';
1642     #if DEBUG
1643     PRINTF("%.16s\n", ar_name);
1644     #endif
1645    
1646     dlfile= (dlFile *)malloc(sizeof(dlFile));
1647     bzero(dlfile, sizeof(dlFile));
1648     dlfile->filename= STRCOPY(ar_name);
1649     dlfile->relocStatus= DL_NEEDRELOC;
1650    
1651     if (!_dl_loadSymbols(dlfile, fd, filhdr, offset+sizeof(ARHDR)) ||
1652     !_dl_loadSections(dlfile, fd, offset+sizeof(ARHDR))) {
1653     _dl_closeObject(dlfile);
1654     return 0;
1655     }
1656    
1657     if (!_dl_enterExternRef(dlfile)) {
1658     _dl_closeObject(dlfile);
1659     return 0;
1660     }
1661    
1662     /*
1663     * need to relocate now and see if we need to bring in more files.
1664     */
1665     _dl_relocateSections(dlfile);
1666    
1667     return 1;
1668     }
1669    
1670     dlFile *_dl_loadEntireArchive( filename, fd )
1671     char *filename; int fd;
1672     {
1673     dlFile *dlfile, *df;
1674     int offset;
1675     FILHDR filhdr;
1676     ARHDR arhdr;
1677     int size;
1678     struct stat stat_buf;
1679    
1680     /*
1681     * read in the header of the symbol list (the so-called symdef)
1682     */
1683     if (lseek(fd, SARMAG, SEEK_SET)==-1 ||
1684     read(fd, &arhdr, sizeof(arhdr))!=sizeof(arhdr)) {
1685     return 0;
1686     }
1687     /*
1688     * go after each member of the archive:
1689     */
1690     fstat(fd, &stat_buf);
1691     sscanf(arhdr.ar_size, "%d", &size);
1692     offset= SARMAG + sizeof(ARHDR) + size;
1693     dlfile= NULL;
1694     while( offset < stat_buf.st_size) {
1695     if (!lseek(fd, offset, SEEK_SET)==-1 ||
1696     read(fd, &arhdr, sizeof(arhdr))!=sizeof(arhdr) ||
1697     read(fd, &filhdr, sizeof(filhdr))!=sizeof(filhdr)) {
1698     _dl_closeObject(dlfile);
1699     return NULL;
1700     }
1701     offset+= sizeof(ARHDR);
1702     if (!(df=_dl_openObject(fd, filename, filhdr, offset, DL_LAZY))) {
1703     _dl_closeObject(dlfile);
1704     return NULL;
1705     }
1706     sscanf(arhdr.ar_size, "%d", &size);
1707     offset+= size;
1708     df->next= dlfile;
1709     dlfile= df;
1710     }
1711    
1712     return dlfile;
1713     }
1714    
1715     /*
1716     * dlRef.c--
1717     * handles symbol references
1718     *
1719     *
1720     * Copyright (c) 1993 Andrew K. Yu, University of California at Berkeley
1721     * All rights reserved.
1722     *
1723     * Permission to use, copy, modify, and distribute this software and its
1724     * documentation for educational, research, and non-profit purposes and
1725     * without fee is hereby granted, provided that the above copyright
1726     * notice appear in all copies and that both that copyright notice and
1727     * this permission notice appear in supporting documentation. Permission
1728     * to incorporate this software into commercial products can be obtained
1729     * from the author. The University of California and the author make
1730     * no representations about the suitability of this software for any
1731     * purpose. It is provided "as is" without express or implied warranty.
1732     *
1733     */
1734    
1735     HEnt **dlHashTable; /* hash table for the symbols */
1736     int _dl_undefinedSymbolCount= 0; /* number of undefined symbols */
1737    
1738     static unsigned hash();
1739    
1740     /*****************************************************************************
1741     * *
1742     * Hash Table for symbols *
1743     * *
1744     *****************************************************************************/
1745    
1746     /*
1747     * hash is taken from Robert Sedgewick's "Algorithms in C" (p.233). Okay, so
1748     * this is not the most sophisticated hash function in the world but this
1749     * will do the job quite nicely.
1750     */
1751     static unsigned hash( str )
1752     char *str;
1753     {
1754     int h;
1755     for(h=0; *str!='\0'; str++)
1756     h = (64*h + *str) % HASHTABSZ;
1757     return h;
1758     }
1759    
1760     void _dl_hashInit()
1761     {
1762     dlHashTable= (HEnt **)malloc(sizeof(HEnt *) * HASHTABSZ);
1763     bzero(dlHashTable, sizeof(HEnt *) * HASHTABSZ);
1764     return;
1765     }
1766    
1767     dlSymbol *dl_hashInsertSymbolStrIdx( extSs, idx, found )
1768     char *extSs; long idx; int *found;
1769     {
1770     dlSymbol *symbol;
1771     char *symname= extSs + idx;
1772     int hval= hash(symname);
1773     HEnt *ent, *prev, *e;
1774    
1775     prev= e= dlHashTable[hval];
1776     while(e) {
1777     if(!strcmp(e->symbol->name, symname)) {
1778     *found= 1;
1779     return (e->symbol); /* return existing symbol */
1780     }
1781     prev= e;
1782     e= e->next;
1783     }
1784     ent= (HEnt *)malloc(sizeof(HEnt));
1785     symbol= (dlSymbol *)malloc(sizeof(dlSymbol));
1786     bzero(symbol, sizeof(dlSymbol));
1787     symbol->name= symname;
1788     ent->symbol= symbol;
1789     ent->next= NULL;
1790     if (!prev) {
1791     dlHashTable[hval]= ent;
1792     }else {
1793     prev->next= ent;
1794     }
1795     *found= 0;
1796     return symbol;
1797     }
1798    
1799     dlSymbol *dl_hashSearchSymbol( symname )
1800     char *symname;
1801     {
1802     int hval= hash(symname);
1803     HEnt *ent= dlHashTable[hval];
1804     while(ent) {
1805     if(!strcmp(ent->symbol->name, symname))
1806     return ent->symbol;
1807     ent= ent->next;
1808     }
1809     return NULL;
1810     }
1811    
1812     /*****************************************************************************
1813     * *
1814     * Entering External References *
1815     * *
1816     *****************************************************************************/
1817    
1818     int _dl_enterInitialExternRef( dlfile )
1819     dlFile *dlfile;
1820     {
1821     char *extSs= dlfile->extss;
1822     pEXTR extsyms= dlfile->extsyms;
1823     dlSymbol *symbol;
1824     int i, found;
1825    
1826     /*
1827     * this is done by init. Just enter the symbols and values:
1828     * (It cannot contain undefined symbols and the multiple defs.)
1829     */
1830     for(i=0; i < dlfile->iextMax ; i++) {
1831     pEXTR esym= &extsyms[i];
1832    
1833     symbol= dl_hashInsertSymbolStrIdx(extSs, esym->asym.iss, &found);
1834     if (found) {
1835     _dl_setErrmsg("init error: symbol \"%s\" multiply defined",
1836     extSs+esym->asym.iss);
1837     return 0;
1838     }
1839     symbol->addr= esym->asym.value;
1840     symbol->objFile= dlfile;
1841     }
1842     free(dlfile->extsyms);
1843     dlfile->extsyms= NULL;
1844     dlfile->iextMax= 0;
1845     return 1;
1846     }
1847    
1848     int _dl_enterExternRef( dlfile )
1849     dlFile *dlfile;
1850     {
1851     int i;
1852     char *extSs= dlfile->extss;
1853     dlSymbol *symbol;
1854     int found;
1855     long textAddress= (long)dlfile->textAddress - dlfile->textVaddr;
1856     long rdataAddress= (long)dlfile->rdataAddress - dlfile->rdataVaddr;
1857     long dataAddress= (long)dlfile->dataAddress - dlfile->dataVaddr;
1858     long bssAddress= (long)dlfile->bssAddress - dlfile->bssVaddr;
1859    
1860     for(i=0; i < dlfile->iextMax ; i++) {
1861     pEXTR esym= &dlfile->extsyms[i];
1862     int found;
1863    
1864     if (esym->asym.sc!=scNil && esym->asym.sc!=scUndefined) {
1865     symbol= dl_hashInsertSymbolStrIdx(extSs, esym->asym.iss,
1866     &found);
1867     if (symbol->objFile!=NULL) {
1868     _dl_setErrmsg("\"%s\" multiply defined",
1869     extSs+esym->asym.iss);
1870     return 0;
1871     }
1872     if (found) {
1873     /*
1874     * finally, we now have the undefined symbol. (A kludge
1875     * here: the symbol name of the undefined symbol is
1876     * malloc'ed. We need to free it.)
1877     */
1878     free(symbol->name);
1879     symbol->name= extSs+esym->asym.iss;
1880     _dl_undefinedSymbolCount--;
1881     }
1882     switch(esym->asym.sc) {
1883     case scAbs:
1884     symbol->addr= esym->asym.value;
1885     break;
1886     case scText:
1887     symbol->addr= textAddress + esym->asym.value;
1888     break;
1889     case scData:
1890     symbol->addr= dataAddress + esym->asym.value;
1891     break;
1892     case scBss:
1893     symbol->addr= bssAddress + esym->asym.value;
1894     break;
1895     case scRData:
1896     symbol->addr= rdataAddress + esym->asym.value;
1897     break;
1898     case scCommon: {
1899     char *block= (char *)malloc(esym->asym.value);
1900     bzero(block, esym->asym.value);
1901     symbol->addr= (long)block;
1902     break;
1903     }
1904     default:
1905     FPRINTF(stderr, "dl: extern symbol in unexpected section (%d)\n",
1906     esym->asym.sc);
1907     break;
1908     }
1909     symbol->objFile= dlfile;
1910     }
1911     }
1912     return 1;
1913     }
1914    
1915     /*****************************************************************************
1916     * *
1917     * Misc. utilities *
1918     * *
1919     *****************************************************************************/
1920    
1921     /*
1922     * dl_undefinedSymbols--
1923     * returns the number of undefined symbols in count and an array of
1924     * strings of the undefined symbols. The last element of the array
1925     * is guaranteed to be NULL.
1926     */
1927     char **dl_undefinedSymbols( count )
1928     int *count;
1929     {
1930     char **syms= NULL;
1931     int i, j;
1932    
1933     *count= _dl_undefinedSymbolCount;
1934     if (_dl_undefinedSymbolCount) {
1935     syms= (char **)malloc(sizeof(char *) * (_dl_undefinedSymbolCount+1));
1936     for(i=0, j=0; i<HASHTABSZ && j<_dl_undefinedSymbolCount; i++) {
1937     HEnt *ent= dlHashTable[i];
1938     while(ent) {
1939     if (!ent->symbol->objFile) {
1940     syms[j++]= STRCOPY(ent->symbol->name);
1941     if (j==_dl_undefinedSymbolCount)
1942     break;
1943     }
1944     ent=ent->next;
1945     }
1946     }
1947     syms[j]=NULL;
1948     }
1949     return syms;
1950     }
1951    
1952     /*
1953     * dl_printAllSymbols--
1954     * aids debugging. Prints out symbols in the hash table that matches
1955     * the file handle. For library archives, prints those that matches
1956     * any member or the archive. A NULL handle matches everything.
1957     */
1958     void dl_printAllSymbols( handle )
1959     void *handle;
1960     {
1961     int i, count= 0;
1962    
1963     for(i=0; i < HASHTABSZ; i++) {
1964     HEnt *ent= dlHashTable[i];
1965     while(ent) {
1966     if (!handle || handle==ent->symbol->objFile) {
1967     PRINTF("(%3d) %-20s addr=0x%x dlfile=0x%x\n",
1968     i, ent->symbol->name, ent->symbol->addr,
1969     ent->symbol->objFile);
1970     count++;
1971     }else if (((dlFile *)handle)->next) {
1972     dlFile *dlfile= ((dlFile *)handle)->next;
1973     while(dlfile) {
1974     if (dlfile==ent->symbol->objFile) {
1975     PRINTF("(%3d) %-20s addr=0x%x dlfile=0x%x\n",
1976     i, ent->symbol->name, ent->symbol->addr,
1977     ent->symbol->objFile);
1978     count++;
1979     }
1980     dlfile= dlfile->next;
1981     }
1982     }
1983     ent= ent->next;
1984     }
1985     }
1986     PRINTF("total number of symbols= %d\n", count);
1987     return;
1988     }
1989    
1990    
1991     /*
1992     * dlReloc.c--
1993     * handles the relocation
1994     *
1995     *
1996     * Copyright (c) 1993 Andrew K. Yu, University of California at Berkeley
1997     * All rights reserved.
1998     *
1999     * Permission to use, copy, modify, and distribute this software and its
2000     * documentation for educational, research, and non-profit purposes and
2001     * without fee is hereby granted, provided that the above copyright
2002     * notice appear in all copies and that both that copyright notice and
2003     * this permission notice appear in supporting documentation. Permission
2004     * to incorporate this software into commercial products can be obtained
2005     * from the author. The University of California and the author make
2006     * no representations about the suitability of this software for any
2007     * purpose. It is provided "as is" without express or implied warranty.
2008     *
2009     */
2010    
2011     #include <sys/mman.h>
2012     #include <mips/cachectl.h>
2013    
2014     static void patchLongjump();
2015     static void protectText();
2016    
2017     int _dl_relocateSections(dlfile)
2018     dlFile *dlfile;
2019     {
2020     long textAddress= dlfile->textAddress - dlfile->textVaddr;
2021     long rdataAddress= dlfile->rdataAddress - dlfile->rdataVaddr;
2022     long dataAddress= dlfile->dataAddress - dlfile->dataVaddr;
2023     long bssAddress= dlfile->bssAddress - dlfile->bssVaddr;
2024     int i, j;
2025     int hasUndefined= 0;
2026     pEXTR extsyms= dlfile->extsyms;
2027     char *extSs= dlfile->extss;
2028    
2029     if (dlfile->relocStatus==DL_RELOCATED) /* just in case */
2030     return 1;
2031    
2032     /* prevent circular relocation */
2033     dlfile->relocStatus= DL_INPROG;
2034    
2035     for(i=0; i < dlfile->nsect; i++) {
2036     SCNHDR *hdr= &(dlfile->sect[i].hdr);
2037     RELOC *relocEnt= dlfile->sect[i].relocEntries;
2038     long sectAddr= dlfile->sect[i].addr - hdr->s_vaddr;
2039     long relocAddr;
2040     int *addr;
2041     int undefinedCount= 0;
2042    
2043     for(j= 0; j < hdr->s_nreloc; j++) {
2044     if (relocEnt->r_extern) {
2045     pEXTR esym= &extsyms[relocEnt->r_symndx];
2046     char *symname= extSs + esym->asym.iss;
2047     dlSymbol *symbol;
2048    
2049     symbol= dl_hashSearchSymbol(symname);
2050     if(!symbol || !symbol->objFile) {
2051     RELOC *rents= dlfile->sect[i].relocEntries;
2052     int found;
2053    
2054     if (j!=undefinedCount)
2055     rents[undefinedCount]=rents[j];
2056     if (!symbol) {
2057     (void)dl_hashInsertSymbolStrIdx(STRCOPY(symname), 0,
2058     &found);
2059     _dl_undefinedSymbolCount++;
2060     }
2061     undefinedCount++;
2062     relocEnt++;
2063     continue; /* skip this one */
2064     }
2065     if(symbol->objFile->relocStatus==DL_NEEDRELOC) {
2066     /*
2067     * trigger an avalanche of relocates! (In fact, we
2068     * don't need to relocate unless the symbol references
2069     * unrelocated text but we do it anyway.)
2070     *
2071     * if we fail to relocate the object file containing the
2072     * symbol, we treat it as undefined and keep it around
2073     * to trigger relocation next time.
2074     */
2075     if (!_dl_relocateSections(symbol->objFile)) {
2076     RELOC *rents= dlfile->sect[i].relocEntries;
2077    
2078     if (j!=undefinedCount)
2079     rents[undefinedCount]=rents[j];
2080     undefinedCount++;
2081     relocEnt++;
2082     continue; /* skip this one */
2083     }
2084     }
2085     relocAddr= symbol->addr;
2086     }else {
2087     switch(relocEnt->r_symndx) {
2088     case R_SN_TEXT:
2089     relocAddr= textAddress;
2090     break;
2091     case R_SN_RDATA:
2092     relocAddr= rdataAddress;
2093     break;
2094     case R_SN_DATA:
2095     relocAddr= dataAddress;
2096     break;
2097     case R_SN_BSS:
2098     relocAddr= bssAddress;
2099     break;
2100     case R_SN_NULL:
2101     case R_SN_SDATA:
2102     case R_SN_SBSS:
2103     _dl_setErrmsg("unknown section %d referenced",
2104     relocEnt->r_symndx);
2105     return 0;
2106     break;
2107     case R_SN_INIT:
2108     case R_SN_LIT8:
2109     case R_SN_LIT4:
2110     /*
2111     * I've never encounter these. (-G 0 should kill the
2112     * LIT4's and LIT8's. I'm not sure if INIT is even used.)
2113     */
2114     _dl_setErrmsg("section %d not implemented",
2115     relocEnt->r_symndx);
2116     return 0;
2117     break;
2118     default:
2119     FPRINTF(stderr, "dl: unknown section %d\n",
2120     relocEnt->r_symndx);
2121     }
2122     }
2123     addr= (int *)(sectAddr + relocEnt->r_vaddr);
2124     switch(relocEnt->r_type) {
2125     case R_ABS:
2126     break;
2127     case R_REFWORD:
2128     *addr += relocAddr;
2129     break;
2130     case R_JMPADDR:
2131     /*
2132     * relocAddr has the absolute address when referenced symbol
2133     * is external; otherwise, need to add the most significant
2134     * 4 bits of the address of the instruction to the jump target.
2135     */
2136     patchLongjump(dlfile, addr, relocAddr,
2137     (relocEnt->r_extern)?0:relocEnt->r_vaddr);
2138     break;
2139     case R_REFHI: {
2140     RELOC *nxtRent= relocEnt+1;
2141     if (nxtRent->r_type != R_REFLO) {
2142     /* documentation says this will not happen: */
2143     FPRINTF(stderr, "dl: R_REFHI not followed by R_REFLO\n");
2144    
2145     /*
2146     * use old way-- just relocate R_REFHI. This will break if
2147     * R_REFLO has a negative offset.
2148     */
2149     if((short)(relocAddr&0xffff) < 0) {
2150     *addr += (((unsigned)relocAddr>>16)+ 1);
2151     }else {
2152     *addr += ((unsigned)relocAddr>> 16);
2153     }
2154     }else {
2155     int hi_done= 0;
2156     int hi_newaddr=0;
2157     /*
2158     * documentation lies again. You can have more than
2159     * one R_REFLO following a R_REFHI.
2160     */
2161     while(j<hdr->s_nreloc && nxtRent->r_type==R_REFLO) {
2162     int *lo_addr= (int *)(sectAddr + nxtRent->r_vaddr);
2163     int oldaddr, newaddr;
2164     int temphi;
2165    
2166     oldaddr= ((*addr)<<16) + (short)((*lo_addr) & 0xffff);
2167     newaddr= relocAddr + oldaddr;
2168     if((short)(newaddr&0xffff) < 0) {
2169     temphi= (((unsigned)newaddr>>16)+ 1);
2170     }else {
2171     temphi= ((unsigned)newaddr>> 16);
2172     }
2173     if(!hi_done) {
2174     hi_newaddr= temphi;
2175     hi_done=1;
2176     }else {
2177     if(temphi!=hi_newaddr) {
2178     FPRINTF(stderr, "dl: REFHI problem: %d %d don't match\n",
2179     temphi, hi_newaddr);
2180     }
2181     }
2182     *lo_addr &= 0xffff0000;
2183     *lo_addr |= (newaddr & 0xffff);
2184     j++; /* the following R_REFLO(s) has been relocated */
2185     relocEnt++;
2186     nxtRent++;
2187     }
2188     *addr &= 0xffff0000; /* mask the immediate fields */
2189     *addr |= (hi_newaddr & 0xffff);
2190     }
2191     break;
2192     }
2193     case R_REFLO:
2194     /*
2195     * shouldn't be here (REFHI should have taken care of these)
2196     * -- just in case
2197     */
2198     FPRINTF(stderr, "dl: warning: dangling R_REFLO.\n");
2199     *addr += (relocAddr & 0xffff);
2200     break;
2201     case R_GPREL:
2202     FPRINTF(stderr,"dl: Hopeless: $gp used.\n");
2203     break;
2204     default:
2205     FPRINTF(stderr,"dl: This local relocation not implemented yet.\n");
2206     }
2207     relocEnt++;
2208     }
2209     hdr->s_nreloc= undefinedCount;
2210     if(undefinedCount>0) {
2211     hasUndefined= 1;
2212     }else {
2213     free(dlfile->sect[i].relocEntries);
2214     dlfile->sect[i].relocEntries= NULL;
2215     }
2216     }
2217     dlfile->relocStatus= hasUndefined? DL_NEEDRELOC : DL_RELOCATED;
2218     if(!hasUndefined) {
2219     free(dlfile->extsyms);
2220     dlfile->extsyms= NULL;
2221     dlfile->iextMax= 0;
2222     protectText(dlfile);
2223     }
2224     return (!hasUndefined);
2225     }
2226    
2227     /*
2228     * patchLongjump patches R_JMPADDR references. The problem is that the
2229     * immediate field is only 28 bits and the references are often out of
2230     * range. We need to jump to a near place first (ie. the jmptable here)
2231     * and do a "jr" to jump farther away.
2232     */
2233     static void patchLongjump( dlfile, addr, relocAddr, vaddr )
2234     dlFile *dlfile; int *addr; long relocAddr; long vaddr;
2235     {
2236     int *patch, instr;
2237     JmpTbl *jmptable= dlfile->jmptable;
2238     JmpTblHdr *jhdr= (jmptable) ? (JmpTblHdr *)jmptable->block : NULL;
2239    
2240     if (!jmptable || jhdr->current==jhdr->max) {
2241     int pagesize;
2242    
2243     /* need new jump table */
2244     jmptable= (JmpTbl *)malloc(sizeof(JmpTbl));
2245     pagesize= getpagesize();
2246     jmptable->block= (char *)valloc(pagesize);
2247     bzero(jmptable->block, pagesize);
2248     jmptable->next= dlfile->jmptable;
2249     jhdr= (JmpTblHdr *)jmptable->block;
2250     jhdr->current= 0;
2251     jhdr->max= (pagesize - sizeof(JmpTblHdr))/16;
2252     dlfile->jmptable= jmptable;
2253     }
2254    
2255     if ((unsigned)addr>>28!=relocAddr>>28) {
2256     patch= (int *)jmptable->block + jhdr->current*4 + 4;
2257     jhdr->current++;
2258     if ((unsigned)patch>>28!=(unsigned)patch>>28) {
2259     FPRINTF(stderr,"dl: out of luck! Can't jump.\n");
2260     return;
2261     }
2262     if ((*addr)&0x3ffffff) {
2263     relocAddr+= (*addr & 0x3ffffff)<<2;
2264     }
2265     if (vaddr) {
2266     relocAddr+= (vaddr & 0xf0000000);
2267     }
2268     if (relocAddr&0x3) {
2269     FPRINTF(stderr,"dl: relocation address not word-aligned!\n");
2270     }
2271     /* lui $at, hiOffset */
2272     *patch= 0x3c010000 | (relocAddr>>16);
2273     /* ori $at, $at, loOffset */
2274     *(patch+1)=0x34210000|(relocAddr&0xffff);
2275     /* jr $at */
2276     *(patch+2)= 0x00200008;
2277     /* nop */
2278     *(patch+3)= 0;
2279     *addr &= 0xfc000000; /* leave the jal */
2280     *addr |= (((long)patch>>2) & 0x3ffffff);
2281     }else {
2282     if (relocAddr&0x3) {
2283     FPRINTF(stderr,"dl: relocation address not word-aligned!\n");
2284     }
2285     *addr += (relocAddr>>2) & 0x3ffffff;
2286     }
2287     return;
2288     }
2289    
2290     /*
2291     * change memory protection so that text and the jumptables cannot be
2292     * accidentally overwritten.
2293     */
2294     static void protectText( dlfile )
2295     dlFile *dlfile;
2296     {
2297     int pagesize= getpagesize();
2298     JmpTbl *jmptable= dlfile->jmptable;
2299    
2300     if (dlfile->textAddress) {
2301     /* protect the text */
2302     if (mprotect((char *)dlfile->textAddress, dlfile->textSize,
2303     PROT_EXEC) == -1) {
2304     FPRINTF(stderr, "dl: fail to protect text of %s\n", dlfile->filename);
2305     }
2306     /* flush the caches */
2307     if (cacheflush((char *)dlfile->textAddress, dlfile->textSize,
2308     BCACHE) != 0) {
2309     FPRINTF(stderr, "dl: fail to flush text of %s\n", dlfile->filename);
2310     }
2311     /* protect jump tables, if any */
2312     while(jmptable) {
2313     if (mprotect((char *)jmptable->block, pagesize,
2314     PROT_EXEC) == -1) {
2315     FPRINTF(stderr, "dl: fail to protect a jump table of %s\n",
2316     dlfile->filename);
2317     }
2318     /* flush the caches */
2319     if (cacheflush((char *)jmptable->block, pagesize, BCACHE) != 0) {
2320     FPRINTF(stderr, "dl: fail to flush a jump table of %s\n", dlfile->filename);
2321     }
2322     jmptable= jmptable->next;
2323     }
2324     }
2325     return;
2326     }
2327    
2328     /*
2329     * dlInterf.c--
2330     * implements the dl* interface
2331     *
2332     *
2333     * Copyright (c) 1993 Andrew K. Yu, University of California at Berkeley
2334     * All rights reserved.
2335     *
2336     * Permission to use, copy, modify, and distribute this software and its
2337     * documentation for educational, research, and non-profit purposes and
2338     * without fee is hereby granted, provided that the above copyright
2339     * notice appear in all copies and that both that copyright notice and
2340     * this permission notice appear in supporting documentation. Permission
2341     * to incorporate this software into commercial products can be obtained
2342     * from the author. The University of California and the author make
2343     * no representations about the suitability of this software for any
2344     * purpose. It is provided "as is" without express or implied warranty.
2345     *
2346     */
2347     #include <stdio.h>
2348     #include <varargs.h>
2349    
2350     static char errmsg[500]; /* the error message buffer */
2351    
2352     static int _dl_openFile();
2353    
2354     #define OBJECT_MAGIC(x) \
2355     ((x)==MIPSEBMAGIC || (x)==MIPSELMAGIC || (x)==SMIPSEBMAGIC || \
2356     (x)==SMIPSELMAGIC || (x)==MIPSEBUMAGIC || (x)==MIPSELUMAGIC)
2357    
2358    
2359     /*****************************************************************************
2360     * *
2361     * dl_init, dl_open, dl_sym, dl_close, dl_error interface routines *
2362     * *
2363     *****************************************************************************/
2364    
2365     /*
2366     * dl_init--
2367     * takes the pathname of the current executable and reads in the
2368     * symbols. It returns 1 if successful and 0 otherwise.
2369     */
2370     int dl_init( filename )
2371     char *filename;
2372     {
2373     int fd;
2374     dlFile *dlfile;
2375     FILHDR filhdr;
2376    
2377     if (!filename) return 0;
2378    
2379     /*
2380     * open the executable for extracting the symbols
2381     */
2382     if((fd=_dl_openFile(filename, &filhdr, 0)) < 0) {
2383     _dl_setErrmsg("cannot open \"%s\"", filename);
2384     return 0;
2385     }
2386     /*
2387     * create a dlFile entry for the executable
2388     */
2389     dlfile= (dlFile *)malloc(sizeof(dlFile));
2390     bzero(dlfile, sizeof(dlFile));
2391     dlfile->filename= STRCOPY(filename);
2392     dlfile->relocStatus= DL_RELOCATED;
2393    
2394     /*
2395     * load in and enter the symbols
2396     */
2397     _dl_hashInit();
2398     if (!_dl_loadSymbols(dlfile, fd, filhdr, 0)) {
2399     _dl_closeObject(dlfile);
2400     _dl_setErrmsg("Cannot load symbol table from \"%s\"", filename);
2401     return 0;
2402     }
2403     if (!_dl_enterInitialExternRef(dlfile)) {
2404     _dl_closeObject(dlfile);
2405     return 0;
2406     }
2407    
2408     close(fd);
2409    
2410     return 1;
2411     }
2412    
2413     /*
2414     * dl_open--
2415     * opens the object file or library archive specified by filename
2416     * It can be opened with either DL_LAZY or DL_NOW mode. DL_LAZY does
2417     * no perform symbol resolution until a symbol in the file is accessed.
2418     * DL_NOW performs symbol resolution at load time. It returns a
2419     * handle if successful, NULL otherwise.
2420     */
2421     void *dlopen( filename, mode )
2422     char *filename; int mode;
2423     {
2424     int fd;
2425     dlFile *dlfile;
2426     FILHDR filhdr;
2427    
2428     if((fd=_dl_openFile(filename, &filhdr, 0)) < 0) {
2429     _dl_setErrmsg("cannot open \"%s\"", filename);
2430     return NULL;
2431     }
2432    
2433     /*
2434     * determine whether we have an object file or a library
2435     */
2436     if (OBJECT_MAGIC(filhdr.f_magic)) {
2437     /*
2438     * an ordinary object file.
2439     */
2440     dlfile= _dl_openObject(fd, filename, filhdr, 0, mode);
2441     close(fd);
2442     }else if (!strncmp((char*)&filhdr, ARMAG, SARMAG)) {
2443     dlFile *df;
2444    
2445     /*
2446     * a library: load in every object file.
2447     */
2448     if ((dlfile=_dl_loadEntireArchive(filename, fd))==NULL) {
2449     close(fd);
2450     _dl_setErrmsg("Cannot load archive \"%s\"", filename);
2451     return NULL;
2452     }
2453    
2454     /*
2455     * do the relocation now if mode==DL_NOW. (note that we couldn't
2456     * relocate in the above loop since archive members might reference
2457     * each other.)
2458     */
2459     if (mode==DL_NOW) {
2460     int search= 0;
2461    
2462     df= dlfile;
2463     while(df) {
2464     if (!_dl_relocateSections(df))
2465     search= 1;
2466     df= df->next;
2467     }
2468     if (search) {
2469     if (!dl_searchLibraries()) {
2470     _dl_setErrmsg("\"%s\" contains undefined symbols",
2471     filename);
2472     _dl_closeObject(dlfile);
2473     return NULL;
2474     }
2475     df= dlfile; /* one more time */
2476     while(df) {
2477     if (!_dl_relocateSections(df)) {
2478     _dl_setErrmsg("\"%s\" contains undefined symbols",
2479     filename);
2480     _dl_closeObject(dlfile);
2481     return NULL;
2482     }
2483     df= df->next;
2484     }
2485     }
2486     }
2487     }else {
2488     _dl_setErrmsg("\"%s\" neither an object file nor an archive",
2489     filename);
2490     }
2491    
2492     return (void *)dlfile;
2493     }
2494    
2495    
2496     /*
2497     * dl_sym--
2498     * returns the location of the specified symbol. handle is not
2499     * actually used. It returns NULL if unsuccessful.
2500     */
2501     void *dlsym( handle, name )
2502     void *handle; char *name;
2503     {
2504     dlFile *dlfile;
2505     dlSymbol *symbol;
2506    
2507     symbol = dl_hashSearchSymbol(name);
2508     if (symbol) {
2509     dlfile= symbol->objFile;
2510     /*
2511     * might have undefined symbols or have not been relocated yet.
2512     */
2513     if (dlfile->relocStatus==DL_NEEDRELOC) {
2514     if (!_dl_relocateSections(dlfile)) {
2515     if (dl_searchLibraries()) {
2516     /* find some undefined symbols, try again! */
2517     _dl_relocateSections(dlfile);
2518     }
2519     }
2520     }
2521     /*
2522     * only returns the symbol if the relocation has completed
2523     */
2524     if (dlfile->relocStatus==DL_RELOCATED)
2525     return (void *)symbol->addr;
2526     }
2527     if (symbol) {
2528     _dl_setErrmsg("\"%s\" has undefined symbols", dlfile->filename);
2529     }else {
2530     _dl_setErrmsg("no such symbol \"%s\"", name);
2531     }
2532     return NULL;
2533     }
2534    
2535     /*
2536     * dl_close--
2537     * closes the file and deallocate all resources hold by the file.
2538     * note that any references to the deallocated resources will result
2539     * in undefined behavior.
2540     */
2541     void dlclose( handle )
2542     void *handle;
2543     {
2544     _dl_closeObject((dlFile *)handle);
2545     return;
2546     }
2547    
2548     /*
2549     * dl_error--
2550     * returns the error message string of the previous error.
2551     */
2552     char *dlerror()
2553     {
2554     return errmsg;
2555     }
2556    
2557     /*****************************************************************************
2558     * *
2559     * Object files handling Rountines *
2560     * *
2561     *****************************************************************************/
2562    
2563     dlFile *_dl_openObject( fd, filename, filhdr, offset, mode )
2564     int fd; char *filename; FILHDR filhdr; int offset; int mode;
2565     {
2566     dlFile *dlfile;
2567    
2568     dlfile= (dlFile *)malloc(sizeof(dlFile));
2569     bzero(dlfile, sizeof(dlFile));
2570     dlfile->relocStatus= DL_NEEDRELOC;
2571     dlfile->filename= STRCOPY(filename);
2572    
2573     if (!_dl_loadSymbols(dlfile, fd, filhdr, offset) ||
2574     !_dl_loadSections(dlfile, fd, offset)) {
2575     _dl_setErrmsg("Cannot load symbol table or sections from \"%s\"",
2576     filename);
2577     _dl_closeObject(dlfile);
2578     return NULL;
2579     }
2580    
2581     if (!_dl_enterExternRef(dlfile)) {
2582     _dl_closeObject(dlfile);
2583     return NULL;
2584     }
2585    
2586     if(mode==DL_NOW) {
2587     if (!_dl_relocateSections(dlfile)) {
2588     /*
2589     * attempt to search the "standard" libraries before aborting
2590     */
2591     if (!dl_searchLibraries() ||
2592     !_dl_relocateSections(dlfile)) {
2593    
2594     _dl_setErrmsg("\"%s\" contains undefined symbols",
2595     filename);
2596     _dl_closeObject(dlfile);
2597     return NULL;
2598     }
2599     }
2600     }else {
2601     dlfile->relocStatus= DL_NEEDRELOC;
2602     }
2603    
2604     return dlfile;
2605     }
2606    
2607     void _dl_closeObject( dlfile )
2608     dlFile *dlfile;
2609     {
2610     int i;
2611     dlFile *next;
2612    
2613     while(dlfile) {
2614     next= dlfile->next;
2615     if (dlfile->filename)
2616     free(dlfile->filename);
2617     if (dlfile->sect)
2618     free(dlfile->sect);
2619     if (dlfile->extss)
2620     free(dlfile->extss);
2621     if (dlfile->extsyms)
2622     free(dlfile->extsyms);
2623     /* frees any symbols associated with it */
2624     for(i=0; i < HASHTABSZ; i++) {
2625     HEnt *ent= dlHashTable[i], *prev, *t;
2626     prev= dlHashTable[i];
2627     while(ent) {
2628     if (ent->symbol->objFile==dlfile) {
2629     t= ent->next;
2630     if (prev==dlHashTable[i]) {
2631     dlHashTable[i]= prev= ent->next;
2632     }else {
2633     prev->next= ent->next;
2634     }
2635     free(ent);
2636     ent= t;
2637     }else {
2638     prev= ent;
2639     ent=ent->next;
2640     }
2641     }
2642     }
2643     free(dlfile);
2644     dlfile= next;
2645     }
2646     }
2647    
2648     int _dl_loadSymbols( dlfile, fd, filhdr, offset )
2649     dlFile *dlfile; int fd; FILHDR filhdr; int offset;
2650     {
2651     SCNHDR *scnhdr;
2652     HDRR symhdr;
2653     char *pssext;
2654     pEXTR pext;
2655     int nscn, size, i;
2656    
2657     /*
2658     * load in section headers (don't need this for the executable during
2659     * init)
2660     */
2661     if (dlfile->relocStatus!=DL_RELOCATED) {
2662     nscn= filhdr.f_nscns;
2663     scnhdr= (SCNHDR *)malloc(sizeof(SCNHDR) * nscn);
2664     if (lseek(fd, filhdr.f_opthdr, SEEK_CUR)==-1 ||
2665     read(fd, scnhdr, sizeof(SCNHDR)*nscn)!= sizeof(SCNHDR)*nscn)
2666     return 0;
2667     }
2668     /*
2669     * load in symbolic header
2670     */
2671     if (lseek(fd, offset+filhdr.f_symptr, SEEK_SET)==-1 ||
2672     read(fd, &symhdr, sizeof(symhdr))!=sizeof(symhdr) ||
2673     symhdr.magic!=magicSym)
2674     return 0;
2675     /*
2676     * read external strings table
2677     */
2678     size= symhdr.issExtMax;
2679     pssext= (char *)malloc(size);
2680     if (lseek(fd, offset+symhdr.cbSsExtOffset, SEEK_SET)==-1 ||
2681     read(fd, pssext, size)!=size)
2682     return 0;
2683     /*
2684