From 7e7344e2f4ebf22d7c6c4ba76a775ffc8c6c2f48 Mon Sep 17 00:00:00 2001 From: John Polstra Date: Sat, 2 Aug 1997 04:56:44 +0000 Subject: Implement dlsym(RTLD_NEXT, symbol). --- gnu/usr.bin/ld/rtld/rtld.c | 76 ++++++++++++++++++++++++++++++++++++++-------- include/link.h | 4 ++- lib/csu/i386/crt0.c | 21 ++++++++----- lib/csu/i386/dlfcn.h | 7 +++++ lib/csu/i386/dlopen.3 | 22 ++++++++++++++ libexec/rtld-aout/rtld.c | 76 ++++++++++++++++++++++++++++++++++++++-------- sys/sys/link_aout.h | 4 ++- sys/sys/link_elf.h | 4 ++- 8 files changed, 179 insertions(+), 35 deletions(-) diff --git a/gnu/usr.bin/ld/rtld/rtld.c b/gnu/usr.bin/ld/rtld/rtld.c index b2c478c903a2..ea33fe897a1c 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$ + * $Id: rtld.c,v 1.46 1997/02/22 15:46:48 peter Exp $ */ #include @@ -204,9 +204,10 @@ static int __dlclose __P((void *)); static void *__dlsym __P((void *, char *)); static char *__dlerror __P((void)); static void __dlexit __P((void)); +static void *__dlsym3 __P((void *, char *, void *)); static struct ld_entry ld_entry = { - __dlopen, __dlclose, __dlsym, __dlerror, __dlexit + __dlopen, __dlclose, __dlsym, __dlerror, __dlexit, __dlsym3 }; void xprintf __P((char *, ...)); @@ -411,7 +412,7 @@ struct _dynamic *dp; (void)close(crtp->crt_ldfd); anon_close(); - return LDSO_VERSION_HAS_DLEXIT; + return LDSO_VERSION_HAS_DLSYM3; } void @@ -1896,26 +1897,77 @@ __dlclose(fd) return 0; } +/* + * This form of dlsym is obsolete. Current versions of crt0 don't call + * it. It can still be called by old executables that were linked with + * old versions of crt0. + */ static void * __dlsym(fd, sym) void *fd; char *sym; { - struct so_map *smp = (struct so_map *)fd, *src_map = NULL; + if (fd == RTLD_NEXT) { + generror("RTLD_NEXT not supported by this version of" + " /usr/lib/crt0.o"); + return NULL; + } + return __dlsym3(fd, sym, NULL); +} + + static void * +__dlsym3(fd, sym, retaddr) + void *fd; + char *sym; + void *retaddr; +{ + struct so_map *smp; + struct so_map *src_map; struct nzlist *np; long addr; - /* - * Restrict search to passed map if dlopen()ed. - */ - if (smp != NULL && LM_PRIVATE(smp)->spd_flags & RTLD_DL) - src_map = smp; + if (fd == RTLD_NEXT) { + /* Find the shared object that contains the caller. */ + for (smp = link_map_head; smp != NULL; smp = smp->som_next) { + void *textbase = smp->som_addr + LM_TXTADDR(smp); + void *textlimit = LM_ETEXT(smp); - np = lookup(sym, &src_map, 1); - if (np == NULL) + if (textbase <= retaddr && retaddr < textlimit) + break; + } + if (smp == NULL) { + generror("Cannot determine caller's shared object"); + return NULL; + } + smp = smp->som_next; + if (smp != NULL && LM_PRIVATE(smp)->spd_flags & RTLD_RTLD) + smp = smp->som_next; + if (smp == NULL) { + generror("No next shared object for RTLD_NEXT"); + return NULL; + } + do { + src_map = smp; + np = lookup(sym, &src_map, 1); + } while (np == NULL && (smp = smp->som_next) != NULL); + } else { + smp = (struct so_map *)fd; + src_map = NULL; + + /* + * Restrict search to passed map if dlopen()ed. + */ + if (smp != NULL && LM_PRIVATE(smp)->spd_flags & RTLD_DL) + src_map = smp; + + np = lookup(sym, &src_map, 1); + } + + if (np == NULL) { + generror("Undefined symbol"); return NULL; + } - /* Fixup jmpslot so future calls transfer directly to target */ addr = np->nz_value; if (src_map) addr += (long)src_map->som_addr; diff --git a/include/link.h b/include/link.h index 937fffea543f..0b55dca0fad9 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.12 1997/05/07 02:26:34 eivind Exp $ + * $Id: link.h,v 1.13 1997/05/07 20:00:00 eivind Exp $ */ /* @@ -167,6 +167,7 @@ struct so_debug { */ #define LDSO_VERSION_NONE 0 /* FreeBSD2.0, 2.0.5 */ #define LDSO_VERSION_HAS_DLEXIT 1 /* includes dlexit in ld_entry */ +#define LDSO_VERSION_HAS_DLSYM3 2 /* includes 3-argument dlsym */ /* * Entry points into ld.so - user interface to the run-time linker. @@ -179,6 +180,7 @@ struct ld_entry { void *(*dlsym) __P((void *, char *)); /* NONE */ char *(*dlerror) __P((void)); /* NONE */ void (*dlexit) __P((void)); /* HAS_DLEXIT */ + void *(*dlsym3) __P((void *, char *, void *)); /* HAS_DLSYM3 */ }; /* diff --git a/lib/csu/i386/crt0.c b/lib/csu/i386/crt0.c index 5f7e4ab724ce..4d217fb08cea 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$ + * $Id: crt0.c,v 1.29 1997/02/22 14:57:44 peter Exp $ */ #include @@ -94,6 +94,8 @@ static char empty[1]; char *__progname = empty; char **environ; +static int ldso_version; + extern unsigned char etext; extern unsigned char eprol asm ("eprol"); extern start() asm("start"); @@ -194,7 +196,6 @@ __do_dynamic_link () struct exec hdr; char *ldso; int (*entry)(); - int ret; #ifdef DEBUG /* Provision for alternate ld.so - security risk! */ @@ -254,14 +255,14 @@ __do_dynamic_link () crt.crt_ldentry = NULL; entry = (int (*)())(crt.crt_ba + sizeof hdr); - ret = (*entry)(CRT_VERSION_BSD_4, &crt); + ldso_version = (*entry)(CRT_VERSION_BSD_4, &crt); ld_entry = crt.crt_ldentry; - if (ret == -1 && ld_entry == NULL) { + if (ldso_version == -1 && ld_entry == NULL) { /* if version 4 not recognised, try version 3 */ - ret = (*entry)(CRT_VERSION_BSD_3, &crt); + ldso_version = (*entry)(CRT_VERSION_BSD_3, &crt); ld_entry = _DYNAMIC.d_entry; } - if (ret == -1) { + if (ldso_version == -1) { _PUTMSG("ld.so failed"); if (ld_entry != NULL) { char *msg = (ld_entry->dlerror)(); @@ -277,7 +278,7 @@ __do_dynamic_link () } - if (ret >= LDSO_VERSION_HAS_DLEXIT) + if (ldso_version >= LDSO_VERSION_HAS_DLEXIT) atexit(ld_entry->dlexit); return; @@ -316,7 +317,11 @@ char *name; if (ld_entry == NULL) return NULL; - return (ld_entry->dlsym)(fd, name); + if (ldso_version >= LDSO_VERSION_HAS_DLSYM3) { + void *retaddr = *(&fd - 1); /* XXX - ABI/machine dependent */ + return (ld_entry->dlsym3)(fd, name, retaddr); + } else + return (ld_entry->dlsym)(fd, name); } diff --git a/lib/csu/i386/dlfcn.h b/lib/csu/i386/dlfcn.h index feadf90bc6c7..b6817fe03b26 100644 --- a/lib/csu/i386/dlfcn.h +++ b/lib/csu/i386/dlfcn.h @@ -43,6 +43,13 @@ #define RTLD_LAZY 1 /* Bind function calls lazily */ #define RTLD_NOW 2 /* Bind function calls immediately */ +/* + * Special handle argument for dlsym(). It causes the search for the + * symbol to begin in the next shared object after the one containing + * the caller. + */ +#define RTLD_NEXT ((void *) -1) + __BEGIN_DECLS void *dlopen __P((char *, int)); void *dlsym __P((void *, char *)); diff --git a/lib/csu/i386/dlopen.3 b/lib/csu/i386/dlopen.3 index 82651c6b510f..efd59be557f2 100644 --- a/lib/csu/i386/dlopen.3 +++ b/lib/csu/i386/dlopen.3 @@ -152,6 +152,28 @@ returns a null pointer if the symbol cannot be found, and sets an error condition which may be queried with .Fn dlerror . .Pp +If +.Fn dlsym +is called with the special +.Fa handle +.Dv RTLD_NEXT , +then the search for the symbol is limited to the shared objects +which were loaded after the one issuing the call to +.Fn dlsym . +Thus, if the function is called from the main program, all +the shared libraries are searched. +If it is called from a shared library, all subsequent shared +libraries are searched. +.Dv RTLD_NEXT +is useful for implementing wrappers around library functions. +For example, a wrapper function +.Fn getpid +could access the +.Dq real +.Fn getpid +with +.Li dlsym(RTLD_NEXT, \&"_getpid\&") . +.Pp .Fn dlerror returns a null-terminated character string describing the last error that occurred during a call to diff --git a/libexec/rtld-aout/rtld.c b/libexec/rtld-aout/rtld.c index b2c478c903a2..ea33fe897a1c 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$ + * $Id: rtld.c,v 1.46 1997/02/22 15:46:48 peter Exp $ */ #include @@ -204,9 +204,10 @@ static int __dlclose __P((void *)); static void *__dlsym __P((void *, char *)); static char *__dlerror __P((void)); static void __dlexit __P((void)); +static void *__dlsym3 __P((void *, char *, void *)); static struct ld_entry ld_entry = { - __dlopen, __dlclose, __dlsym, __dlerror, __dlexit + __dlopen, __dlclose, __dlsym, __dlerror, __dlexit, __dlsym3 }; void xprintf __P((char *, ...)); @@ -411,7 +412,7 @@ struct _dynamic *dp; (void)close(crtp->crt_ldfd); anon_close(); - return LDSO_VERSION_HAS_DLEXIT; + return LDSO_VERSION_HAS_DLSYM3; } void @@ -1896,26 +1897,77 @@ __dlclose(fd) return 0; } +/* + * This form of dlsym is obsolete. Current versions of crt0 don't call + * it. It can still be called by old executables that were linked with + * old versions of crt0. + */ static void * __dlsym(fd, sym) void *fd; char *sym; { - struct so_map *smp = (struct so_map *)fd, *src_map = NULL; + if (fd == RTLD_NEXT) { + generror("RTLD_NEXT not supported by this version of" + " /usr/lib/crt0.o"); + return NULL; + } + return __dlsym3(fd, sym, NULL); +} + + static void * +__dlsym3(fd, sym, retaddr) + void *fd; + char *sym; + void *retaddr; +{ + struct so_map *smp; + struct so_map *src_map; struct nzlist *np; long addr; - /* - * Restrict search to passed map if dlopen()ed. - */ - if (smp != NULL && LM_PRIVATE(smp)->spd_flags & RTLD_DL) - src_map = smp; + if (fd == RTLD_NEXT) { + /* Find the shared object that contains the caller. */ + for (smp = link_map_head; smp != NULL; smp = smp->som_next) { + void *textbase = smp->som_addr + LM_TXTADDR(smp); + void *textlimit = LM_ETEXT(smp); - np = lookup(sym, &src_map, 1); - if (np == NULL) + if (textbase <= retaddr && retaddr < textlimit) + break; + } + if (smp == NULL) { + generror("Cannot determine caller's shared object"); + return NULL; + } + smp = smp->som_next; + if (smp != NULL && LM_PRIVATE(smp)->spd_flags & RTLD_RTLD) + smp = smp->som_next; + if (smp == NULL) { + generror("No next shared object for RTLD_NEXT"); + return NULL; + } + do { + src_map = smp; + np = lookup(sym, &src_map, 1); + } while (np == NULL && (smp = smp->som_next) != NULL); + } else { + smp = (struct so_map *)fd; + src_map = NULL; + + /* + * Restrict search to passed map if dlopen()ed. + */ + if (smp != NULL && LM_PRIVATE(smp)->spd_flags & RTLD_DL) + src_map = smp; + + np = lookup(sym, &src_map, 1); + } + + if (np == NULL) { + generror("Undefined symbol"); return NULL; + } - /* Fixup jmpslot so future calls transfer directly to target */ addr = np->nz_value; if (src_map) addr += (long)src_map->som_addr; diff --git a/sys/sys/link_aout.h b/sys/sys/link_aout.h index 937fffea543f..0b55dca0fad9 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.12 1997/05/07 02:26:34 eivind Exp $ + * $Id: link.h,v 1.13 1997/05/07 20:00:00 eivind Exp $ */ /* @@ -167,6 +167,7 @@ struct so_debug { */ #define LDSO_VERSION_NONE 0 /* FreeBSD2.0, 2.0.5 */ #define LDSO_VERSION_HAS_DLEXIT 1 /* includes dlexit in ld_entry */ +#define LDSO_VERSION_HAS_DLSYM3 2 /* includes 3-argument dlsym */ /* * Entry points into ld.so - user interface to the run-time linker. @@ -179,6 +180,7 @@ struct ld_entry { void *(*dlsym) __P((void *, char *)); /* NONE */ char *(*dlerror) __P((void)); /* NONE */ void (*dlexit) __P((void)); /* HAS_DLEXIT */ + void *(*dlsym3) __P((void *, char *, void *)); /* HAS_DLSYM3 */ }; /* diff --git a/sys/sys/link_elf.h b/sys/sys/link_elf.h index 937fffea543f..0b55dca0fad9 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.12 1997/05/07 02:26:34 eivind Exp $ + * $Id: link.h,v 1.13 1997/05/07 20:00:00 eivind Exp $ */ /* @@ -167,6 +167,7 @@ struct so_debug { */ #define LDSO_VERSION_NONE 0 /* FreeBSD2.0, 2.0.5 */ #define LDSO_VERSION_HAS_DLEXIT 1 /* includes dlexit in ld_entry */ +#define LDSO_VERSION_HAS_DLSYM3 2 /* includes 3-argument dlsym */ /* * Entry points into ld.so - user interface to the run-time linker. @@ -179,6 +180,7 @@ struct ld_entry { void *(*dlsym) __P((void *, char *)); /* NONE */ char *(*dlerror) __P((void)); /* NONE */ void (*dlexit) __P((void)); /* HAS_DLEXIT */ + void *(*dlsym3) __P((void *, char *, void *)); /* HAS_DLSYM3 */ }; /* -- cgit v1.2.3