diff options
-rw-r--r-- | gnu/usr.bin/ld/rtld/rtld.c | 300 | ||||
-rw-r--r-- | include/link.h | 20 | ||||
-rw-r--r-- | lib/csu/i386/c++rt0.c | 10 | ||||
-rw-r--r-- | lib/csu/i386/crt0.c | 10 | ||||
-rw-r--r-- | libexec/rtld-aout/rtld.c | 300 | ||||
-rw-r--r-- | sys/sys/link_aout.h | 20 | ||||
-rw-r--r-- | sys/sys/link_elf.h | 20 |
7 files changed, 526 insertions, 154 deletions
diff --git a/gnu/usr.bin/ld/rtld/rtld.c b/gnu/usr.bin/ld/rtld/rtld.c index e0547af..dbbae89 100644 --- a/gnu/usr.bin/ld/rtld/rtld.c +++ b/gnu/usr.bin/ld/rtld/rtld.c @@ -27,7 +27,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * $Id: rtld.c,v 1.23 1995/04/21 04:57:50 nate Exp $ + * $Id: rtld.c,v 1.24 1995/05/30 05:01:49 rgrimes Exp $ */ #include <sys/param.h> @@ -83,6 +83,7 @@ struct somap_private { #define RTLD_MAIN 1 #define RTLD_RTLD 2 #define RTLD_DL 4 +#define RTLD_INIT 8 unsigned long a_text; /* text size, if known */ unsigned long a_data; /* initialized data size */ unsigned long a_bss; /* uninitialized data size */ @@ -159,9 +160,10 @@ static void *__dlopen __P((char *, int)); static int __dlclose __P((void *)); static void *__dlsym __P((void *, char *)); static char *__dlerror __P((void)); +static void __dlexit __P((void)); static struct ld_entry ld_entry = { - __dlopen, __dlclose, __dlsym, __dlerror + __dlopen, __dlclose, __dlsym, __dlerror, __dlexit }; void xprintf __P((char *, ...)); @@ -169,6 +171,9 @@ static void load_objects __P(( struct crt_ldso *, struct _dynamic *)); static struct so_map *map_object __P((struct sod *, struct so_map *)); static int unmap_object __P((struct so_map *)); +static struct so_map *load_object __P((struct sod *, struct so_map *, + int, int)); +static int unload_object __P((struct so_map *)); static struct so_map *alloc_link_map __P(( char *, struct sod *, struct so_map *, caddr_t, struct _dynamic *)); @@ -177,7 +182,8 @@ static inline int check_text_reloc __P(( struct relocation_info *, caddr_t)); static int reloc_map __P((struct so_map *)); static void reloc_copy __P((struct so_map *)); -static void init_map __P((struct so_map *, char *)); +static void init_map __P((struct so_map *, char *, int)); +static void call_map __P((struct so_map *, char *)); static char *rtfindlib __P((char *, int, int, int *)); void binder_entry __P((void)); long binder __P((jmpslot_t *)); @@ -289,7 +295,7 @@ struct _dynamic *dp; for (smp = link_map_head; smp; smp = smp->som_next) { if (LM_PRIVATE(smp)->spd_flags & RTLD_RTLD) continue; - init_map(smp, ".init"); + init_map(smp, ".init", 0); } /* Fill in some field in main's __DYNAMIC structure */ @@ -323,7 +329,7 @@ struct _dynamic *dp; /* Close our file descriptor */ (void)close(crtp->crt_ldfd); anon_close(); - return 0; + return LDSO_VERSION_HAS_DLEXIT; } @@ -459,6 +465,42 @@ alloc_link_map(path, sodp, parent, addr, dp) return smp; } + static struct so_map * +find_object(sodp, smp) + struct sod *sodp; + struct so_map *smp; +{ + char *path, *name = (char *)(sodp->sod_name + LM_LDBASE(smp)); + int usehints = 0; + struct so_map *p; + + if (sodp->sod_library) { + usehints = 1; +again: + path = rtfindlib(name, sodp->sod_major, + sodp->sod_minor, &usehints); + if (path == NULL) { + generror ("Can't find shared library \"%s\"", + name); + return NULL; + } + } else { + if (careful && *name != '/') { + generror ("Shared library path must start with \"/\" for \"%s\"", + name); + return NULL; + } + path = name; + } + + /* Check if already loaded */ + for (p = link_map_head; p; p = p->som_next) + if (p->som_path && strcmp(p->som_path, path) == 0) + break; + + return p; +} + /* * Map object identified by link object LOP which was found * in link map LMP. @@ -612,8 +654,7 @@ unmap_object(smp) return -1; } } - free((caddr_t) smp->som_sod->sod_name); - free(smp->som_sod); + if (smp->som_path) free(smp->som_path); free(smp); return 0; } @@ -763,7 +804,42 @@ reloc_copy(smp) } static void -init_map(smp, sym) +init_map(smp, sym, dependants) + struct so_map *smp; + char *sym; + int dependants; +{ + struct so_map *src_map = smp; + struct nzlist *np; + + if (LM_PRIVATE(smp)->spd_flags & RTLD_INIT) + return; + + LM_PRIVATE(smp)->spd_flags |= RTLD_INIT; + + if (dependants) { + struct sod *sodp; + struct so_map *smp2; + long next; + + next = LD_NEED(smp->som_dynamic); + + while (next) { + sodp = (struct sod *)(LM_LDBASE(smp) + next); + smp2 = find_object(sodp, smp); + if (smp2) + init_map(smp2, sym, dependants); + next = sodp->sod_next; + } + } + + np = lookup(sym, &src_map, 1); + if (np) + (*(void (*)())(src_map->som_addr + np->nz_value))(); +} + +static void +call_map(smp, sym) struct so_map *smp; char *sym; { @@ -776,6 +852,119 @@ init_map(smp, sym) } /* + * Load an object with all its dependant objects, recording the type of the + * object and optionally calling its init function. + */ +static struct so_map * +load_object(sodp, parent, type, init) + struct sod *sodp; + struct so_map *parent; + int type; + int init; +{ + struct so_map* smp; + + /* + * Find or map the object. + */ + smp = map_object(sodp, parent); + if (smp == NULL) return NULL; + + /* + * The first time the object is mapped, load it's dependant objects and + * relocate it. + */ + if (LM_PRIVATE(smp)->spd_refcount++ == 0) { + struct sod *sodp; + struct so_map *smp2; + long next; + + next = LD_NEED(smp->som_dynamic); + + /* + * Load dependant objects but defer initialisation until later. + * When all the dependants (and sub dependants, etc.) have been + * loaded and relocated, it is safe to call the init functions, + * using a recursive call to init_map. This ensures that if init + * code in the dependants calls code in the parent, it will work + * as expected. + */ + while (next) { + sodp = (struct sod *)(LM_LDBASE(smp) + next); + /* + * Dependant objects (of both dlopen and main) don't get a + * specific type. + */ + if ((smp2 = load_object(sodp, smp, 0, 0)) == NULL) { +#ifdef DEBUG +xprintf("ld.so: map_object failed on cascaded %s %s (%d.%d): %s\n", + smp->sod_library ? "library" : "file", smp->sod_name, + smp->sod_major, smp->sod_minor, strerror(errno)); +#endif + unload_object(smp); + return NULL; + } + next = sodp->sod_next; + } + + LM_PRIVATE(smp)->spd_flags |= type; + if (reloc_map(smp) < 0) { + unload_object(smp); + return NULL; + } + reloc_copy(smp); + if (init) { + init_map(smp, ".init", 1); + } + } + + return smp; +} + +/* + * Unload an object, recursively unloading dependant objects. + */ +static int +unload_object(smp) + struct so_map *smp; +{ + struct so_map *smp2; + struct sod *sodp; + long next; + + if (--LM_PRIVATE(smp)->spd_refcount != 0) + return -1; + + /* + * Call destructors for the object (before unloading its dependants + * since destructors may use them. Only call destructors if constructors + * have been called. + */ + if (LM_PRIVATE(smp)->spd_flags & RTLD_INIT) + call_map(smp, ".fini"); + + /* + * Unmap any dependant objects first. + */ + next = LD_NEED(smp->som_dynamic); + while (next) { + sodp = (struct sod *)(LM_LDBASE(smp) + next); + smp2 = find_object(sodp, smp); + if (smp2) + unload_object(smp2); + next = sodp->sod_next; + } + + /* + * Remove from address space. + */ + if (unmap_object(smp) < 0) + return -1; + + return 0; +} + +/* * Run-time common symbol table. */ @@ -1262,6 +1451,7 @@ static struct so_map dlmap = { static char dlerror_buf [DLERROR_BUF_SIZE]; static char *dlerror_msg = NULL; + static void * __dlopen(name, mode) char *name; @@ -1286,24 +1476,19 @@ __dlopen(name, mode) sodp->sod_library = 0; sodp->sod_major = sodp->sod_minor = 0; - if ((smp = map_object(sodp, &dlmap)) == NULL) { + if ((smp = load_object(sodp, &dlmap, RTLD_DL, 1)) == NULL) { #ifdef DEBUG xprintf("%s: %s\n", name, dlerror_buf); #endif return NULL; } - if (dl_cascade(smp) == 0) - return NULL; - - if (LM_PRIVATE(smp)->spd_refcount++ == 0) { - LM_PRIVATE(smp)->spd_flags |= RTLD_DL; - if (reloc_map(smp) < 0) - return NULL; - reloc_copy(smp); - init_map(smp, ".init"); - init_map(smp, "_init"); - } + /* + * If this was newly loaded, call the _init() function in the + * object as per manpage. + */ + if (LM_PRIVATE(smp)->spd_refcount == 1) + call_map(smp, "__init"); return smp; } @@ -1318,13 +1503,25 @@ __dlclose(fd) xprintf("dlclose(%s): refcount = %d\n", smp->som_path, LM_PRIVATE(smp)->spd_refcount); #endif - if (--LM_PRIVATE(smp)->spd_refcount != 0) - return 0; - /* Dismantle shared object map and descriptor */ - init_map(smp, "_fini"); + if (smp == NULL) { + generror("NULL argument to dlclose"); + return -1; + } + + if (LM_PRIVATE(smp)->spd_refcount > 1) { + LM_PRIVATE(smp)->spd_refcount--; + return 0; + } + + /* + * Call the function _fini() in the object as per manpage. + */ + call_map(smp, "__fini"); - if (unmap_object(smp) < 0) + free((void*) smp->som_sod->sod_name); + free(smp->som_sod); + if (unload_object(smp) < 0) return -1; return 0; @@ -1369,6 +1566,18 @@ __dlerror __P((void)) return err; } + static void +__dlexit __P((void)) +{ + struct so_map *smp; + + for (smp = link_map_head; smp; smp = smp->som_next) { + if (LM_PRIVATE(smp)->spd_flags & (RTLD_RTLD|RTLD_MAIN)) + continue; + call_map(smp, ".fini"); + } +} + /* * Generate an error message that can be later be retrieved via dlerror. */ @@ -1413,44 +1622,3 @@ char *fmt; va_end(ap); } -static int -dl_cascade(smp) - struct so_map *smp; -{ - struct sod *sodp; - struct so_map *smp2; - long next; - - next = LD_NEED(smp->som_dynamic); - - while (next) { - sodp = (struct sod *)(LM_LDBASE(smp) + next); - if ((smp2 = map_object(sodp, smp)) == NULL) { -#ifdef DEBUG -xprintf("ld.so: map_object failed on cascaded %s %s (%d.%d): %s\n", - smp->sod_library ? "library" : "file", smp->sod_name, - smp->sod_major, smp->sod_minor, strerror(errno)); -#endif - return 0; - } -#if 0 - /* - * XXX - this doesn't work for some reason. not - * at all sure why. -mrg - */ - if (dl_cascade(smp2) == 0) - return 0; -#endif - - if (LM_PRIVATE(smp2)->spd_refcount++ == 0) { - LM_PRIVATE(smp2)->spd_flags |= RTLD_DL; - reloc_map(smp2); - reloc_copy(smp2); - init_map(smp2, ".init"); - init_map(smp2, "_init"); - } - - next = sodp->sod_next; - } - return 1; -} diff --git a/include/link.h b/include/link.h index 38c9c40..15277a7 100644 --- a/include/link.h +++ b/include/link.h @@ -27,7 +27,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * $Id: link.h,v 1.3 1995/02/07 13:26:39 jkh Exp $ + * $Id: link.h,v 1.4 1995/03/04 17:49:20 nate Exp $ */ /* @@ -163,13 +163,22 @@ struct so_debug { }; /* + * Version returned to crt0 from ld.so + */ +#define LDSO_VERSION_NONE 0 /* FreeBSD2.0, 2.0.5 */ +#define LDSO_VERSION_HAS_DLEXIT 1 /* includes dlexit in ld_entry */ + +/* * Entry points into ld.so - user interface to the run-time linker. + * Entries are valid for the given version numbers returned by ld.so + * to crt0. */ struct ld_entry { - void *(*dlopen) __P((char *, int)); - int (*dlclose) __P((void *)); - void *(*dlsym) __P((void *, char *)); - char *(*dlerror) __P((void)); + void *(*dlopen) __P((char *, int)); /* NONE */ + int (*dlclose) __P((void *)); /* NONE */ + void *(*dlsym) __P((void *, char *)); /* NONE */ + char *(*dlerror) __P((void)); /* NONE */ + void (*dlexit) __P((void)); /* HAS_DLEXIT */ }; /* @@ -246,7 +255,6 @@ struct crt_ldso { #define CRT_VERSION_BSD_3 3 #define CRT_VERSION_BSD_4 4 - /* * Maximum number of recognized shared object version numbers. */ diff --git a/lib/csu/i386/c++rt0.c b/lib/csu/i386/c++rt0.c index df85907..aa28109 100644 --- a/lib/csu/i386/c++rt0.c +++ b/lib/csu/i386/c++rt0.c @@ -27,7 +27,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * $Id: c++rt0.c,v 1.1 1994/03/09 17:12:59 nate Exp $ + * $Id: c++rt0.c,v 1.2 1995/05/30 05:39:36 rgrimes Exp $ */ /* @@ -61,6 +61,7 @@ __ctors(void) } extern void __init() asm(".init"); +extern void __fini() asm(".fini"); void __init(void) @@ -74,7 +75,12 @@ __init(void) if (!initialized) { initialized = 1; __ctors(); - atexit(__dtors); } } + +void +__fini(void) +{ + __dtors(); +} diff --git a/lib/csu/i386/crt0.c b/lib/csu/i386/crt0.c index f6f0759..7959e66 100644 --- a/lib/csu/i386/crt0.c +++ b/lib/csu/i386/crt0.c @@ -27,7 +27,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * $Id: crt0.c,v 1.15 1995/02/07 13:27:29 jkh Exp $ + * $Id: crt0.c,v 1.16 1995/02/24 07:51:13 phk Exp $ */ @@ -194,6 +194,7 @@ __do_dynamic_link () struct exec hdr; char *ldso; int (*entry)(); + int ret; #ifdef DEBUG /* Provision for alternate ld.so - security risk! */ @@ -259,11 +260,16 @@ __do_dynamic_link () crt.crt_prog = __progname; entry = (int (*)())(crt.crt_ba + sizeof hdr); - if ((*entry)(CRT_VERSION_BSD_3, &crt) == -1) { + ret = (*entry)(CRT_VERSION_BSD_3, &crt); + if (ret == -1) { _FATAL("ld.so failed\n"); } ld_entry = _DYNAMIC.d_entry; + + if (ret >= LDSO_VERSION_HAS_DLEXIT) + atexit(ld_entry->dlexit); + return; } diff --git a/libexec/rtld-aout/rtld.c b/libexec/rtld-aout/rtld.c index e0547af..dbbae89 100644 --- a/libexec/rtld-aout/rtld.c +++ b/libexec/rtld-aout/rtld.c @@ -27,7 +27,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * $Id: rtld.c,v 1.23 1995/04/21 04:57:50 nate Exp $ + * $Id: rtld.c,v 1.24 1995/05/30 05:01:49 rgrimes Exp $ */ #include <sys/param.h> @@ -83,6 +83,7 @@ struct somap_private { #define RTLD_MAIN 1 #define RTLD_RTLD 2 #define RTLD_DL 4 +#define RTLD_INIT 8 unsigned long a_text; /* text size, if known */ unsigned long a_data; /* initialized data size */ unsigned long a_bss; /* uninitialized data size */ @@ -159,9 +160,10 @@ static void *__dlopen __P((char *, int)); static int __dlclose __P((void *)); static void *__dlsym __P((void *, char *)); static char *__dlerror __P((void)); +static void __dlexit __P((void)); static struct ld_entry ld_entry = { - __dlopen, __dlclose, __dlsym, __dlerror + __dlopen, __dlclose, __dlsym, __dlerror, __dlexit }; void xprintf __P((char *, ...)); @@ -169,6 +171,9 @@ static void load_objects __P(( struct crt_ldso *, struct _dynamic *)); static struct so_map *map_object __P((struct sod *, struct so_map *)); static int unmap_object __P((struct so_map *)); +static struct so_map *load_object __P((struct sod *, struct so_map *, + int, int)); +static int unload_object __P((struct so_map *)); static struct so_map *alloc_link_map __P(( char *, struct sod *, struct so_map *, caddr_t, struct _dynamic *)); @@ -177,7 +182,8 @@ static inline int check_text_reloc __P(( struct relocation_info *, caddr_t)); static int reloc_map __P((struct so_map *)); static void reloc_copy __P((struct so_map *)); -static void init_map __P((struct so_map *, char *)); +static void init_map __P((struct so_map *, char *, int)); +static void call_map __P((struct so_map *, char *)); static char *rtfindlib __P((char *, int, int, int *)); void binder_entry __P((void)); long binder __P((jmpslot_t *)); @@ -289,7 +295,7 @@ struct _dynamic *dp; for (smp = link_map_head; smp; smp = smp->som_next) { if (LM_PRIVATE(smp)->spd_flags & RTLD_RTLD) continue; - init_map(smp, ".init"); + init_map(smp, ".init", 0); } /* Fill in some field in main's __DYNAMIC structure */ @@ -323,7 +329,7 @@ struct _dynamic *dp; /* Close our file descriptor */ (void)close(crtp->crt_ldfd); anon_close(); - return 0; + return LDSO_VERSION_HAS_DLEXIT; } @@ -459,6 +465,42 @@ alloc_link_map(path, sodp, parent, addr, dp) return smp; } + static struct so_map * +find_object(sodp, smp) + struct sod *sodp; + struct so_map *smp; +{ + char *path, *name = (char *)(sodp->sod_name + LM_LDBASE(smp)); + int usehints = 0; + struct so_map *p; + + if (sodp->sod_library) { + usehints = 1; +again: + path = rtfindlib(name, sodp->sod_major, + sodp->sod_minor, &usehints); + if (path == NULL) { + generror ("Can't find shared library \"%s\"", + name); + return NULL; + } + } else { + if (careful && *name != '/') { + generror ("Shared library path must start with \"/\" for \"%s\"", + name); + return NULL; + } + path = name; + } + + /* Check if already loaded */ + for (p = link_map_head; p; p = p->som_next) + if (p->som_path && strcmp(p->som_path, path) == 0) + break; + + return p; +} + /* * Map object identified by link object LOP which was found * in link map LMP. @@ -612,8 +654,7 @@ unmap_object(smp) return -1; } } - free((caddr_t) smp->som_sod->sod_name); - free(smp->som_sod); + if (smp->som_path) free(smp->som_path); free(smp); return 0; } @@ -763,7 +804,42 @@ reloc_copy(smp) } static void -init_map(smp, sym) +init_map(smp, sym, dependants) + struct so_map *smp; + char *sym; + int dependants; +{ + struct so_map *src_map = smp; + struct nzlist *np; + + if (LM_PRIVATE(smp)->spd_flags & RTLD_INIT) + return; + + LM_PRIVATE(smp)->spd_flags |= RTLD_INIT; + + if (dependants) { + struct sod *sodp; + struct so_map *smp2; + long next; + + next = LD_NEED(smp->som_dynamic); + + while (next) { + sodp = (struct sod *)(LM_LDBASE(smp) + next); + smp2 = find_object(sodp, smp); + if (smp2) + init_map(smp2, sym, dependants); + next = sodp->sod_next; + } + } + + np = lookup(sym, &src_map, 1); + if (np) + (*(void (*)())(src_map->som_addr + np->nz_value))(); +} + +static void +call_map(smp, sym) struct so_map *smp; char *sym; { @@ -776,6 +852,119 @@ init_map(smp, sym) } /* + * Load an object with all its dependant objects, recording the type of the + * object and optionally calling its init function. + */ +static struct so_map * +load_object(sodp, parent, type, init) + struct sod *sodp; + struct so_map *parent; + int type; + int init; +{ + struct so_map* smp; + + /* + * Find or map the object. + */ + smp = map_object(sodp, parent); + if (smp == NULL) return NULL; + + /* + * The first time the object is mapped, load it's dependant objects and + * relocate it. + */ + if (LM_PRIVATE(smp)->spd_refcount++ == 0) { + struct sod *sodp; + struct so_map *smp2; + long next; + + next = LD_NEED(smp->som_dynamic); + + /* + * Load dependant objects but defer initialisation until later. + * When all the dependants (and sub dependants, etc.) have been + * loaded and relocated, it is safe to call the init functions, + * using a recursive call to init_map. This ensures that if init + * code in the dependants calls code in the parent, it will work + * as expected. + */ + while (next) { + sodp = (struct sod *)(LM_LDBASE(smp) + next); + /* + * Dependant objects (of both dlopen and main) don't get a + * specific type. + */ + if ((smp2 = load_object(sodp, smp, 0, 0)) == NULL) { +#ifdef DEBUG +xprintf("ld.so: map_object failed on cascaded %s %s (%d.%d): %s\n", + smp->sod_library ? "library" : "file", smp->sod_name, + smp->sod_major, smp->sod_minor, strerror(errno)); +#endif + unload_object(smp); + return NULL; + } + next = sodp->sod_next; + } + + LM_PRIVATE(smp)->spd_flags |= type; + if (reloc_map(smp) < 0) { + unload_object(smp); + return NULL; + } + reloc_copy(smp); + if (init) { + init_map(smp, ".init", 1); + } + } + + return smp; +} + +/* + * Unload an object, recursively unloading dependant objects. + */ +static int +unload_object(smp) + struct so_map *smp; +{ + struct so_map *smp2; + struct sod *sodp; + long next; + + if (--LM_PRIVATE(smp)->spd_refcount != 0) + return -1; + + /* + * Call destructors for the object (before unloading its dependants + * since destructors may use them. Only call destructors if constructors + * have been called. + */ + if (LM_PRIVATE(smp)->spd_flags & RTLD_INIT) + call_map(smp, ".fini"); + + /* + * Unmap any dependant objects first. + */ + next = LD_NEED(smp->som_dynamic); + while (next) { + sodp = (struct sod *)(LM_LDBASE(smp) + next); + smp2 = find_object(sodp, smp); + if (smp2) + unload_object(smp2); + next = sodp->sod_next; + } + + /* + * Remove from address space. + */ + if (unmap_object(smp) < 0) + return -1; + + return 0; +} + +/* * Run-time common symbol table. */ @@ -1262,6 +1451,7 @@ static struct so_map dlmap = { static char dlerror_buf [DLERROR_BUF_SIZE]; static char *dlerror_msg = NULL; + static void * __dlopen(name, mode) char *name; @@ -1286,24 +1476,19 @@ __dlopen(name, mode) sodp->sod_library = 0; sodp->sod_major = sodp->sod_minor = 0; - if ((smp = map_object(sodp, &dlmap)) == NULL) { + if ((smp = load_object(sodp, &dlmap, RTLD_DL, 1)) == NULL) { #ifdef DEBUG xprintf("%s: %s\n", name, dlerror_buf); #endif return NULL; } - if (dl_cascade(smp) == 0) - return NULL; - - if (LM_PRIVATE(smp)->spd_refcount++ == 0) { - LM_PRIVATE(smp)->spd_flags |= RTLD_DL; - if (reloc_map(smp) < 0) - return NULL; - reloc_copy(smp); - init_map(smp, ".init"); - init_map(smp, "_init"); - } + /* + * If this was newly loaded, call the _init() function in the + * object as per manpage. + */ + if (LM_PRIVATE(smp)->spd_refcount == 1) + call_map(smp, "__init"); return smp; } @@ -1318,13 +1503,25 @@ __dlclose(fd) xprintf("dlclose(%s): refcount = %d\n", smp->som_path, LM_PRIVATE(smp)->spd_refcount); #endif - if (--LM_PRIVATE(smp)->spd_refcount != 0) - return 0; - /* Dismantle shared object map and descriptor */ - init_map(smp, "_fini"); + if (smp == NULL) { + generror("NULL argument to dlclose"); + return -1; + } + + if (LM_PRIVATE(smp)->spd_refcount > 1) { + LM_PRIVATE(smp)->spd_refcount--; + return 0; + } + + /* + * Call the function _fini() in the object as per manpage. + */ + call_map(smp, "__fini"); - if (unmap_object(smp) < 0) + free((void*) smp->som_sod->sod_name); + free(smp->som_sod); + if (unload_object(smp) < 0) return -1; return 0; @@ -1369,6 +1566,18 @@ __dlerror __P((void)) return err; } + static void +__dlexit __P((void)) +{ + struct so_map *smp; + + for (smp = link_map_head; smp; smp = smp->som_next) { + if (LM_PRIVATE(smp)->spd_flags & (RTLD_RTLD|RTLD_MAIN)) + continue; + call_map(smp, ".fini"); + } +} + /* * Generate an error message that can be later be retrieved via dlerror. */ @@ -1413,44 +1622,3 @@ char *fmt; va_end(ap); } -static int -dl_cascade(smp) - struct so_map *smp; -{ - struct sod *sodp; - struct so_map *smp2; - long next; - - next = LD_NEED(smp->som_dynamic); - - while (next) { - sodp = (struct sod *)(LM_LDBASE(smp) + next); - if ((smp2 = map_object(sodp, smp)) == NULL) { -#ifdef DEBUG -xprintf("ld.so: map_object failed on cascaded %s %s (%d.%d): %s\n", - smp->sod_library ? "library" : "file", smp->sod_name, - smp->sod_major, smp->sod_minor, strerror(errno)); -#endif - return 0; - } -#if 0 - /* - * XXX - this doesn't work for some reason. not - * at all sure why. -mrg - */ - if (dl_cascade(smp2) == 0) - return 0; -#endif - - if (LM_PRIVATE(smp2)->spd_refcount++ == 0) { - LM_PRIVATE(smp2)->spd_flags |= RTLD_DL; - reloc_map(smp2); - reloc_copy(smp2); - init_map(smp2, ".init"); - init_map(smp2, "_init"); - } - - next = sodp->sod_next; - } - return 1; -} diff --git a/sys/sys/link_aout.h b/sys/sys/link_aout.h index 38c9c40..15277a7 100644 --- a/sys/sys/link_aout.h +++ b/sys/sys/link_aout.h @@ -27,7 +27,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * $Id: link.h,v 1.3 1995/02/07 13:26:39 jkh Exp $ + * $Id: link.h,v 1.4 1995/03/04 17:49:20 nate Exp $ */ /* @@ -163,13 +163,22 @@ struct so_debug { }; /* + * Version returned to crt0 from ld.so + */ +#define LDSO_VERSION_NONE 0 /* FreeBSD2.0, 2.0.5 */ +#define LDSO_VERSION_HAS_DLEXIT 1 /* includes dlexit in ld_entry */ + +/* * Entry points into ld.so - user interface to the run-time linker. + * Entries are valid for the given version numbers returned by ld.so + * to crt0. */ struct ld_entry { - void *(*dlopen) __P((char *, int)); - int (*dlclose) __P((void *)); - void *(*dlsym) __P((void *, char *)); - char *(*dlerror) __P((void)); + void *(*dlopen) __P((char *, int)); /* NONE */ + int (*dlclose) __P((void *)); /* NONE */ + void *(*dlsym) __P((void *, char *)); /* NONE */ + char *(*dlerror) __P((void)); /* NONE */ + void (*dlexit) __P((void)); /* HAS_DLEXIT */ }; /* @@ -246,7 +255,6 @@ struct crt_ldso { #define CRT_VERSION_BSD_3 3 #define CRT_VERSION_BSD_4 4 - /* * Maximum number of recognized shared object version numbers. */ diff --git a/sys/sys/link_elf.h b/sys/sys/link_elf.h index 38c9c40..15277a7 100644 --- a/sys/sys/link_elf.h +++ b/sys/sys/link_elf.h @@ -27,7 +27,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * $Id: link.h,v 1.3 1995/02/07 13:26:39 jkh Exp $ + * $Id: link.h,v 1.4 1995/03/04 17:49:20 nate Exp $ */ /* @@ -163,13 +163,22 @@ struct so_debug { }; /* + * Version returned to crt0 from ld.so + */ +#define LDSO_VERSION_NONE 0 /* FreeBSD2.0, 2.0.5 */ +#define LDSO_VERSION_HAS_DLEXIT 1 /* includes dlexit in ld_entry */ + +/* * Entry points into ld.so - user interface to the run-time linker. + * Entries are valid for the given version numbers returned by ld.so + * to crt0. */ struct ld_entry { - void *(*dlopen) __P((char *, int)); - int (*dlclose) __P((void *)); - void *(*dlsym) __P((void *, char *)); - char *(*dlerror) __P((void)); + void *(*dlopen) __P((char *, int)); /* NONE */ + int (*dlclose) __P((void *)); /* NONE */ + void *(*dlsym) __P((void *, char *)); /* NONE */ + char *(*dlerror) __P((void)); /* NONE */ + void (*dlexit) __P((void)); /* HAS_DLEXIT */ }; /* @@ -246,7 +255,6 @@ struct crt_ldso { #define CRT_VERSION_BSD_3 3 #define CRT_VERSION_BSD_4 4 - /* * Maximum number of recognized shared object version numbers. */ |