Resolve dlsym(3) and friends directly so that dlsym(RTLD_NEXT,...) works.

Previously dlsym resolved to the version in crt0.o or libc which would
mean that the caller's shared object couldn't be determined correctly
using __builtin_return_address(0).

Mainly from FreeBSD, but adapted by me. Benefits of this solutions are:

	- backward comptibility maintained
	- existing broken binaries are fixed with a new ld.elf_so
	- __mainprog_obj can be removed from crt0.o
	- we do the same thing as FreeBSD

Fixes PR 22067.

OKed by Jason and Christos.
This commit is contained in:
skrll 2003-08-12 09:18:38 +00:00
parent b4c1c6117c
commit d900731978
10 changed files with 126 additions and 149 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: common.c,v 1.12 2003/07/26 19:24:26 salo Exp $ */
/* $NetBSD: common.c,v 1.13 2003/08/12 09:18:42 skrll Exp $ */
/*
* Copyright (c) 1995 Christopher G. Demetriou
@ -74,13 +74,4 @@ _rtld_setup(cleanup, obj)
atexit(cleanup);
}
#ifdef __weak_alias
__weak_alias(dlopen,_dlopen);
__weak_alias(dlclose,_dlclose);
__weak_alias(dlsym,_dlsym);
__weak_alias(dlerror,_dlerror);
__weak_alias(dladdr,_dladdr);
#endif
#include <dlfcn_stubs.c>
#endif /* DYNAMIC */

View File

@ -1,4 +1,4 @@
/* $NetBSD: common.h,v 1.8 2003/07/26 19:24:26 salo Exp $ */
/* $NetBSD: common.h,v 1.9 2003/08/12 09:18:42 skrll Exp $ */
/*
* Copyright (c) 1995 Christopher G. Demetriou
@ -75,8 +75,6 @@ extern void _fini __P((void));
#ifdef DYNAMIC
void _rtld_setup __P((void (*)(void), const Obj_Entry *obj));
const Obj_Entry *__mainprog_obj;
/*
* Arrange for _DYNAMIC to be weak and undefined (and therefore to show up
* as being at address zero, unless something else defines it). That way,

View File

@ -1,4 +1,4 @@
/* $NetBSD: dlfcn_elf.c,v 1.3 2002/07/20 08:54:04 yamt Exp $ */
/* $NetBSD: dlfcn_elf.c,v 1.4 2003/08/12 09:18:43 skrll Exp $ */
/*
* Copyright (c) 2000 Takuya SHIOZAKI
@ -27,7 +27,7 @@
#include <sys/cdefs.h>
#if defined(LIBC_SCCS) && !defined(lint)
__RCSID("$NetBSD: dlfcn_elf.c,v 1.3 2002/07/20 08:54:04 yamt Exp $");
__RCSID("$NetBSD: dlfcn_elf.c,v 1.4 2003/08/12 09:18:43 skrll Exp $");
#endif /* LIBC_SCCS and not lint */
#include "namespace.h"
@ -35,11 +35,6 @@ __RCSID("$NetBSD: dlfcn_elf.c,v 1.3 2002/07/20 08:54:04 yamt Exp $");
#define ELFSIZE ARCH_ELFSIZE
#include "rtld.h"
#ifdef __weak_extern
__weak_extern(__mainprog_obj)
#endif
extern const Obj_Entry *__mainprog_obj;
#ifdef __weak_alias
__weak_alias(dlopen,__dlopen)
__weak_alias(dlclose,__dlclose)
@ -48,4 +43,54 @@ __weak_alias(dlerror,__dlerror)
__weak_alias(dladdr,__dladdr)
#endif
#include <dlfcn_stubs.c>
/*
* For ELF, the dynamic linker directly resolves references to its
* services to functions inside the dynamic linker itself. These
* weak-symbol stubs are necessary so that "ld" won't complain about
* undefined symbols. The stubs are executed only when the program is
* linked statically, or when a given service isn't implemented in the
* dynamic linker. They must return an error if called, and they must
* be weak symbols so that the dynamic linker can override them.
*/
static char dlfcn_error[] = "Service unavailable";
/*ARGSUSED*/
void *
dlopen(const char *name, int mode)
{
return NULL;
}
/*ARGSUSED*/
int
dlclose(void *fd)
{
return -1;
}
/*ARGSUSED*/
void *
dlsym(void *handle, const char *name)
{
return NULL;
}
/*ARGSUSED*/
__aconst char *
dlerror()
{
return dlfcn_error;
}
/*ARGSUSED*/
int
dladdr(const void *addr, Dl_info *dli)
{
return 0;
}

View File

@ -1,102 +0,0 @@
/* $NetBSD: dlfcn_stubs.c,v 1.4 2003/07/26 19:24:41 salo Exp $ */
/*
* Copyright (c) 1995 Christopher G. Demetriou
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed for the
* NetBSD Project. See http://www.NetBSD.org/ for
* information about NetBSD.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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: LICENSE,v 1.2 2000/06/14 15:57:33 cgd Exp>>
*/
/*
* NOT A STANDALONE FILE!
*/
void *
dlopen(name, mode)
const char *name;
int mode;
{
if (__mainprog_obj == NULL)
return NULL;
return (__mainprog_obj->dlopen)(name, mode);
}
int
dlclose(fd)
void *fd;
{
if (__mainprog_obj == NULL)
return -1;
return (__mainprog_obj->dlclose)(fd);
}
void *
dlsym(fd, name)
void *fd;
const char *name;
{
if (__mainprog_obj == NULL)
return NULL;
return (__mainprog_obj->dlsym)(fd, name);
}
#if 0 /* not supported for ELF shlibs, apparently */
int
dlctl(fd, cmd, arg)
void *fd, *arg;
int cmd;
{
if (__mainprog_obj == NULL)
return -1;
return (__mainprog_obj->dlctl)(fd, cmd, arg);
}
#endif
__aconst char *
dlerror()
{
if (__mainprog_obj == NULL)
return ("Dynamic linker interface not available");
return (__mainprog_obj->dlerror)();
}
int
dladdr(const void *addr, Dl_info *dli)
{
if (__mainprog_obj == NULL)
return -1;
return (__mainprog_obj->dladdr)(addr, dli);
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: reloc.c,v 1.80 2003/07/24 10:12:26 skrll Exp $ */
/* $NetBSD: reloc.c,v 1.81 2003/08/12 09:18:46 skrll Exp $ */
/*
* Copyright 1996 John D. Polstra.
@ -196,11 +196,11 @@ _rtld_relocate_objects(Obj_Entry *first, bool bind_now)
obj->version = RTLD_VERSION;
/* Fill in the dynamic linker entry points. */
obj->dlopen = _rtld_dlopen;
obj->dlsym = _rtld_dlsym;
obj->dlerror = _rtld_dlerror;
obj->dlclose = _rtld_dlclose;
obj->dladdr = _rtld_dladdr;
obj->dlopen = dlopen;
obj->dlsym = dlsym;
obj->dlerror = dlerror;
obj->dlclose = dlclose;
obj->dladdr = dladdr;
dbg(("fixing up PLTGOT"));
/* Set the special PLTGOT entries. */

View File

@ -1,4 +1,4 @@
/* $NetBSD: rtld.c,v 1.98 2003/07/24 10:12:26 skrll Exp $ */
/* $NetBSD: rtld.c,v 1.99 2003/08/12 09:18:48 skrll Exp $ */
/*
* Copyright 1996 John D. Polstra.
@ -433,6 +433,9 @@ _rtld(Elf_Addr *sp, Elf_Addr relocbase)
real_environ = _rtld_objmain_sym("environ");
if (real_environ)
*real_environ = environ;
/*
* Set __mainprog_obj for old binaries.
*/
real___mainprog_obj = _rtld_objmain_sym("__mainprog_obj");
if (real___mainprog_obj)
*real___mainprog_obj = _rtld_objmain;
@ -458,7 +461,7 @@ _rtld(Elf_Addr *sp, Elf_Addr relocbase)
void
_rtld_die(void)
{
const char *msg = _rtld_dlerror();
const char *msg = dlerror();
if (msg == NULL)
msg = "Fatal error";
@ -573,7 +576,7 @@ _rtld_unref_dag(Obj_Entry *root)
}
int
_rtld_dlclose(void *handle)
dlclose(void *handle)
{
Obj_Entry *root = _rtld_dlcheck(handle);
@ -593,7 +596,7 @@ _rtld_dlclose(void *handle)
}
char *
_rtld_dlerror(void)
dlerror(void)
{
char *msg = error_message;
@ -602,7 +605,7 @@ _rtld_dlerror(void)
}
void *
_rtld_dlopen(const char *name, int mode)
dlopen(const char *name, int mode)
{
Obj_Entry **old_obj_tail = _rtld_objtail;
Obj_Entry *obj = NULL;
@ -659,7 +662,7 @@ _rtld_objmain_sym(const char *name)
}
void *
_rtld_dlsym(void *handle, const char *name)
dlsym(void *handle, const char *name)
{
const Obj_Entry *obj;
unsigned long hash;
@ -745,7 +748,7 @@ _rtld_dlsym(void *handle, const char *name)
}
int
_rtld_dladdr(const void *addr, Dl_info *info)
dladdr(const void *addr, Dl_info *info)
{
const Obj_Entry *obj;
const Elf_Sym *def, *best_def;

View File

@ -1,4 +1,4 @@
/* $NetBSD: rtld.h,v 1.69 2003/07/24 10:12:26 skrll Exp $ */
/* $NetBSD: rtld.h,v 1.70 2003/08/12 09:18:49 skrll Exp $ */
/*
* Copyright 1996 John D. Polstra.
@ -211,15 +211,20 @@ extern Objlist _rtld_list_main;
extern Elf_Sym _rtld_sym_zero;
/* rtld.c */
/*
* We export these symbols using _rtld_symbol_lookup and is_exported.
*/
char *dlerror(void);
void *dlopen(const char *, int);
void *dlsym(void *, const char *);
int dlclose(void *);
int dladdr(const void *, Dl_info *);
void _rtld_error(const char *, ...)
__attribute__((__format__(__printf__,1,2)));
void _rtld_die(void);
char *_rtld_dlerror(void);
void *_rtld_dlopen(const char *, int);
void *_rtld_objmain_sym(const char *);
void *_rtld_dlsym(void *, const char *);
int _rtld_dlclose(void *);
int _rtld_dladdr(const void *, Dl_info *);
void _rtld_debug_state(void);
void _rtld_linkmap_add(Obj_Entry *);
void _rtld_linkmap_delete(Obj_Entry *);

View File

@ -1,4 +1,4 @@
/* $NetBSD: search.c,v 1.17 2003/07/24 10:12:26 skrll Exp $ */
/* $NetBSD: search.c,v 1.18 2003/08/12 09:18:50 skrll Exp $ */
/*
* Copyright 1996 Matt Thomas <matt@3am-software.com>
@ -127,7 +127,7 @@ _rtld_load_library(const char *name, const Obj_Entry *refobj, int mode)
}
dbg((" Searching for \"%s\" (%p)", name, refobj));
tmperrorp = _rtld_dlerror();
tmperrorp = dlerror();
if (tmperrorp != NULL) {
strncpy(tmperror, tmperrorp, sizeof tmperror);
tmperrorp = tmperror;
@ -165,7 +165,7 @@ pathfound:
if (tmperrorp)
_rtld_error("%s", tmperror);
else
(void)_rtld_dlerror();
(void)dlerror();
return obj;
found:

View File

@ -1,4 +1,4 @@
/* $NetBSD: symbol.c,v 1.32 2003/08/05 19:41:53 skrll Exp $ */
/* $NetBSD: symbol.c,v 1.33 2003/08/12 09:18:50 skrll Exp $ */
/*
* Copyright 1996 John D. Polstra.
@ -53,6 +53,29 @@
#include "debug.h"
#include "rtld.h"
static bool
_rtld_is_exported(const Elf_Sym *def)
{
static Elf_Addr _rtld_exports[] = {
(Elf_Addr)dlopen,
(Elf_Addr)dlclose,
(Elf_Addr)dlsym,
(Elf_Addr)dlerror,
(Elf_Addr)dladdr,
NULL
};
int i;
Elf_Addr value;
value = (Elf_Addr)(_rtld_objself.relocbase + def->st_value);
for (i = 0; _rtld_exports[i] != NULL; i++) {
if (value == _rtld_exports[i])
return true;
}
return false;
}
/*
* Hash function for symbol table lookup. Don't even think about changing
* this. It is specified by the System V ABI.
@ -225,6 +248,20 @@ _rtld_find_symdef(unsigned long symnum, const Obj_Entry *refobj,
}
}
/*
* Search the dynamic linker itself, and possibly resolve the
* symbol from there. This is how the application links to
* dynamic linker services such as dlopen. Only the values listed
* in the "_rtld_exports" array can be resolved from the dynamic linker.
*/
if (def == NULL || ELF_ST_BIND(def->st_info) == STB_WEAK) {
symp = _rtld_symlook_obj(name, hash, &_rtld_objself, in_plt);
if (symp != NULL && _rtld_is_exported(symp)) {
def = symp;
defobj = &_rtld_objself;
}
}
/*
* If we found no definition and the reference is weak, treat the
* symbol as having the value zero.
@ -234,7 +271,7 @@ _rtld_find_symdef(unsigned long symnum, const Obj_Entry *refobj,
def = &_rtld_sym_zero;
defobj = _rtld_objmain;
}
if (def != NULL)
*defobj_out = defobj;
else {

View File

@ -1,4 +1,4 @@
/* $NetBSD: ldd.c,v 1.19 2003/05/28 20:45:39 dsl Exp $ */
/* $NetBSD: ldd.c,v 1.20 2003/08/12 09:18:38 skrll Exp $ */
/*-
* Copyright (c) 1998, 2000 The NetBSD Foundation, Inc.
@ -197,7 +197,7 @@ _rtld_error(const char *fmt, ...)
}
char *
_rtld_dlerror()
dlerror()
{
char *msg = error_message;
error_message = NULL;