Subject: ld.elf_so DAG (was Re: PTL2 (pkgsrc/devel/ptl2) doesn't work with i386/ELF)
To: None <k-abe@kuroneko.media.osaka-cu.ac.jp>
From: msaitoh <msaitoh@spa.is.uec.ac.jp>
List: tech-kern
Date: 10/20/1999 16:46:11
Please test following patch.
This patch fixes PR#5890 and PR#8572. This patch is stoled from FreeBSD :)
diff -cr src/libexec/ld.elf_so/headers.c src/libexec/ld.newelf_so/headers.c
*** src/libexec/ld.elf_so/headers.c Tue Mar 2 21:15:44 1999
--- src/libexec/ld.newelf_so/headers.c Tue Oct 12 07:43:20 1999
***************
*** 258,268 ****
int phnum;
caddr_t entry;
{
! Obj_Entry *obj = CNEW(Obj_Entry);
const Elf_Phdr *phlimit = phdr + phnum;
const Elf_Phdr *ph;
int nsegs = 0;
for (ph = phdr; ph < phlimit; ++ph) {
switch (ph->p_type) {
--- 258,269 ----
int phnum;
caddr_t entry;
{
! Obj_Entry *obj;
const Elf_Phdr *phlimit = phdr + phnum;
const Elf_Phdr *ph;
int nsegs = 0;
+ obj = _rtld_obj_new();
for (ph = phdr; ph < phlimit; ++ph) {
switch (ph->p_type) {
***************
*** 270,275 ****
--- 271,280 ----
assert((const Elf_Phdr *) ph->p_vaddr == phdr);
obj->phdr = (const Elf_Phdr *) ph->p_vaddr;
obj->phsize = ph->p_memsz;
+ break;
+
+ case Elf_pt_interp:
+ obj->interp = (const char *) ph->p_vaddr;
break;
case Elf_pt_load:
diff -cr src/libexec/ld.elf_so/load.c src/libexec/ld.newelf_so/load.c
*** src/libexec/ld.elf_so/load.c Tue Jun 29 09:00:16 1999
--- src/libexec/ld.newelf_so/load.c Thu Oct 14 03:13:46 1999
***************
*** 66,84 ****
bool dodebug;
{
Obj_Entry *obj;
for (obj = _rtld_objlist->next; obj != NULL; obj = obj->next)
if (strcmp(obj->path, filepath) == 0)
break;
! if (obj == NULL) { /* First use of this object, so we must map it in */
! int fd;
!
if ((fd = open(filepath, O_RDONLY)) == -1) {
_rtld_error("Cannot open \"%s\"", filepath);
return NULL;
}
! obj = _rtld_map_object(filepath, fd);
(void)close(fd);
if (obj == NULL) {
free(filepath);
--- 66,106 ----
bool dodebug;
{
Obj_Entry *obj;
+ int fd = -1;
+ struct stat sb;
for (obj = _rtld_objlist->next; obj != NULL; obj = obj->next)
if (strcmp(obj->path, filepath) == 0)
break;
! /*
! * If we didn't find a match by pathname, open the file and check
! * again by device and inode. This avoids false mismatches caused
! * by multiple links or ".." in pathnames.
! *
! * To avoid a race, we open the file and use fstat() rather than
! * using stat().
! */
! if (obj == NULL) {
if ((fd = open(filepath, O_RDONLY)) == -1) {
_rtld_error("Cannot open \"%s\"", filepath);
return NULL;
}
! if (fstat(fd, &sb) == -1) {
! _rtld_error("Cannot fstat \"%s\"", filepath);
! close(fd);
! return NULL;
! }
! for (obj = _rtld_objlist->next; obj != NULL; obj = obj->next) {
! if (obj->ino == sb.st_ino && obj->dev == sb.st_dev) {
! close(fd);
! break;
! }
! }
! }
!
! if (obj == NULL) { /* First use of this object, so we must map it in */
! obj = _rtld_map_object(filepath, fd, &sb);
(void)close(fd);
if (obj == NULL) {
free(filepath);
***************
*** 124,130 ****
--- 146,159 ----
for (needed = obj->needed; needed != NULL;
needed = needed->next) {
const char *name = obj->strtab + needed->name;
+ #if 0
char *libpath = _rtld_find_library(name, obj);
+ #else
+ char *libpath;
+ dbg(("called from _rtld_load_needed_objects\n"));
+ libpath = _rtld_find_library(name, obj);
+ dbg(("returned from _rtld_load_needed_objects\n"));
+ #endif
if (libpath == NULL) {
status = -1;
diff -cr src/libexec/ld.elf_so/map_object.c src/libexec/ld.newelf_so/map_object.c
*** src/libexec/ld.elf_so/map_object.c Sat Aug 7 20:09:46 1999
--- src/libexec/ld.newelf_so/map_object.c Thu Oct 14 03:14:50 1999
***************
*** 33,40 ****
--- 33,42 ----
#include <errno.h>
#include <stddef.h>
+ #include <stdlib.h>
#include <string.h>
#include <unistd.h>
+ #include <sys/stat.h>
#include <sys/types.h>
#include <sys/mman.h>
***************
*** 56,64 ****
* for the shared object. Returns NULL on failure.
*/
Obj_Entry *
! _rtld_map_object(path, fd)
const char *path;
int fd;
{
Obj_Entry *obj;
union {
--- 58,67 ----
* for the shared object. Returns NULL on failure.
*/
Obj_Entry *
! _rtld_map_object(path, fd, sb)
const char *path;
int fd;
+ const struct stat *sb;
{
Obj_Entry *obj;
union {
***************
*** 72,77 ****
--- 75,81 ----
int nsegs;
Elf_Phdr *phdyn;
Elf_Phdr *phphdr;
+ Elf_Phdr *phinterp;
caddr_t mapbase;
size_t mapsize;
Elf_Off base_offset;
***************
*** 137,146 ****
phdr = (Elf_Phdr *) (u.buf + u.hdr.e_phoff);
phlimit = phdr + u.hdr.e_phnum;
nsegs = 0;
! phdyn = NULL;
! phphdr = NULL;
while (phdr < phlimit) {
switch (phdr->p_type) {
case Elf_pt_load:
#ifdef __mips__
--- 141,152 ----
phdr = (Elf_Phdr *) (u.buf + u.hdr.e_phoff);
phlimit = phdr + u.hdr.e_phnum;
nsegs = 0;
! phdyn = phphdr = phinterp = NULL;
while (phdr < phlimit) {
switch (phdr->p_type) {
+ case Elf_pt_interp:
+ phinterp = phdr;
+ break;
case Elf_pt_load:
#ifdef __mips__
***************
*** 250,256 ****
/* Non-file portion of BSS mapped above. */
#endif
! obj = CNEW(Obj_Entry);
obj->mapbase = mapbase;
obj->mapsize = mapsize;
obj->textsize = round_up(segs[0]->p_vaddr + segs[0]->p_memsz) -
--- 256,266 ----
/* Non-file portion of BSS mapped above. */
#endif
! obj = _rtld_obj_new();
! if (sb != NULL) {
! obj->dev = sb->st_dev;
! obj->ino = sb->st_ino;
! }
obj->mapbase = mapbase;
obj->mapsize = mapsize;
obj->textsize = round_up(segs[0]->p_vaddr + segs[0]->p_memsz) -
***************
*** 265,270 ****
--- 275,319 ----
(obj->relocbase + phphdr->p_vaddr);
obj->phsize = phphdr->p_memsz;
}
+ if (phinterp != NULL)
+ obj->interp = (const char *) (obj->relocbase + phinterp->p_vaddr);
+
+ return obj;
+ }
+
+ void
+ _rtld_obj_free(obj)
+ Obj_Entry *obj;
+ {
+ Objlist_Entry *elm;
+
+ free(obj->path);
+ while (obj->needed != NULL) {
+ Needed_Entry *needed = obj->needed;
+ obj->needed = needed->next;
+ free(needed);
+ }
+ while (SIMPLEQ_FIRST(&obj->dldags) != NULL) {
+ elm = SIMPLEQ_FIRST(&obj->dldags);
+ SIMPLEQ_REMOVE_HEAD(&obj->dldags, elm, link);
+ free(elm);
+ }
+ while (SIMPLEQ_FIRST(&obj->dagmembers) != NULL) {
+ elm = SIMPLEQ_FIRST(&obj->dagmembers);
+ SIMPLEQ_REMOVE_HEAD(&obj->dagmembers, elm, link);
+ free(elm);
+ }
+ free(obj);
+ }
+
+ Obj_Entry *
+ _rtld_obj_new(void)
+ {
+ Obj_Entry *obj;
+
+ obj = CNEW(Obj_Entry);
+ SIMPLEQ_INIT(&obj->dldags);
+ SIMPLEQ_INIT(&obj->dagmembers);
return obj;
}
diff -cr src/libexec/ld.elf_so/reloc.c src/libexec/ld.newelf_so/reloc.c
*** src/libexec/ld.elf_so/reloc.c Sun Aug 22 20:19:13 1999
--- src/libexec/ld.newelf_so/reloc.c Tue Oct 12 11:53:40 1999
***************
*** 150,156 ****
#ifndef __sparc__
int
_rtld_relocate_nonplt_object(obj, rela, dodebug)
! const Obj_Entry *obj;
const Elf_RelA *rela;
bool dodebug;
{
--- 150,156 ----
#ifndef __sparc__
int
_rtld_relocate_nonplt_object(obj, rela, dodebug)
! Obj_Entry *obj;
const Elf_RelA *rela;
bool dodebug;
{
***************
*** 378,384 ****
int
_rtld_relocate_plt_object(obj, rela, addrp, bind_now, dodebug)
! const Obj_Entry *obj;
const Elf_RelA *rela;
caddr_t *addrp;
bool bind_now;
--- 378,384 ----
int
_rtld_relocate_plt_object(obj, rela, addrp, bind_now, dodebug)
! Obj_Entry *obj;
const Elf_RelA *rela;
caddr_t *addrp;
bool bind_now;
***************
*** 435,441 ****
caddr_t
_rtld_bind(obj, reloff)
! const Obj_Entry *obj;
Elf_Word reloff;
{
const Elf_RelA *rela;
--- 435,441 ----
caddr_t
_rtld_bind(obj, reloff)
! Obj_Entry *obj;
Elf_Word reloff;
{
const Elf_RelA *rela;
diff -cr src/libexec/ld.elf_so/rtld.c src/libexec/ld.newelf_so/rtld.c
*** src/libexec/ld.elf_so/rtld.c Fri Aug 20 20:10:44 1999
--- src/libexec/ld.newelf_so/rtld.c Thu Oct 14 03:35:29 1999
***************
*** 59,64 ****
--- 59,66 ----
#include "sysident.h"
#endif
+ #define END_SYM "_end"
+
/*
* Debugging support.
*/
***************
*** 86,95 ****
--- 88,104 ----
Obj_Entry *_rtld_objmain; /* The main program shared object */
Obj_Entry _rtld_objself; /* The dynamic linker shared object */
char _rtld_path[] = _PATH_RTLD;
+ unsigned long curmark; /* Current mark value */
+ Elf_Sym _rtld_sym_zero; /* For resolving undefined weak refs. */
#ifdef VARPSZ
int _rtld_pagesz; /* Page size, as provided by kernel */
#endif
+ Objlist _rtld_list_global = /* Objects dlopened with RTLD_GLOBAL */
+ SIMPLEQ_HEAD_INITIALIZER(_rtld_list_global);
+ Objlist _rtld_list_main = /* Objects loaded at program startup */
+ SIMPLEQ_HEAD_INITIALIZER(_rtld_list_main);
+
Search_Path *_rtld_default_paths;
Search_Path *_rtld_paths;
/*
***************
*** 108,114 ****
static void _rtld_call_fini_functions __P((Obj_Entry *));
static void _rtld_call_init_functions __P((Obj_Entry *));
static Obj_Entry *_rtld_dlcheck __P((void *));
! static void _rtld_unref_object_dag __P((Obj_Entry *));
static void
_rtld_call_fini_functions(first)
--- 117,130 ----
static void _rtld_call_fini_functions __P((Obj_Entry *));
static void _rtld_call_init_functions __P((Obj_Entry *));
static Obj_Entry *_rtld_dlcheck __P((void *));
! static void _rtld_init_dag __P((Obj_Entry *));
! static void _rtld_init_dag1 __P((Obj_Entry *, Obj_Entry *));
! static void _rtld_objlist_add __P((Objlist *, Obj_Entry *));
! static Objlist_Entry *_rtld_objlist_find __P((Objlist *, const Obj_Entry *));
! static void _rtld_objlist_remove __P((Objlist *, Obj_Entry *));
! static void _rtld_unload_object __P((Obj_Entry *, bool));
! static void _rtld_unref_dag __P((Obj_Entry *));
! static Obj_Entry *_rtld_obj_from_addr __P((const void *));
static void
_rtld_call_fini_functions(first)
***************
*** 257,262 ****
--- 273,279 ----
bool bind_now = 0;
const char *ld_bind_now;
const char **argv;
+ Obj_Entry *obj;
#if defined(RTLD_DEBUG) && !defined(RTLD_RELOCATE_SELF)
int i = 0;
#endif
***************
*** 364,370 ****
if (pAUX_execfd != NULL) { /* Load the main program. */
int fd = pAUX_execfd->au_v;
dbg(("loading main program"));
! _rtld_objmain = _rtld_map_object(argv[0], fd);
close(fd);
if (_rtld_objmain == NULL)
_rtld_die();
--- 381,387 ----
if (pAUX_execfd != NULL) { /* Load the main program. */
int fd = pAUX_execfd->au_v;
dbg(("loading main program"));
! _rtld_objmain = _rtld_map_object(argv[0], fd, NULL);
close(fd);
if (_rtld_objmain == NULL)
_rtld_die();
***************
*** 387,392 ****
--- 404,422 ----
_rtld_objmain->path = xstrdup("main program");
_rtld_objmain->mainprog = true;
+
+ /*
+ * Get the actual dynamic linker pathname from the executable if
+ * possible. (It should always be possible.) That ensures that
+ * gdb will find the right dynamic linker even if a non-standard
+ * one is being used.
+ */
+ if (_rtld_objmain->interp != NULL &&
+ strcmp(_rtld_objmain->interp, _rtld_objself.path) != 0) {
+ free(_rtld_objself.path);
+ _rtld_objself.path = xstrdup(_rtld_objmain->interp);
+ }
+
_rtld_digest_dynamic(_rtld_objmain);
_rtld_linkmap_add(_rtld_objmain);
***************
*** 397,402 ****
--- 427,436 ----
_rtld_objtail = &_rtld_objmain->next;
++_rtld_objmain->refcount;
+ /* Initialize a fake symbol for resolving undefined weak references. */
+ _rtld_sym_zero.st_info = ELF_SYM_INFO(Elf_estb_global, Elf_estt_notype);
+ _rtld_sym_zero.st_shndx = Elf_eshn_absolute;
+
/*
* Pre-load user-specified objects after the main program but before
* any shared object dependencies.
***************
*** 409,414 ****
--- 443,451 ----
if (_rtld_load_needed_objects(_rtld_objmain) == -1)
_rtld_die();
+ for (obj = _rtld_objlist; obj != NULL; obj = obj->next)
+ _rtld_objlist_add(&_rtld_list_main, obj);
+
dbg(("relocating objects"));
if (_rtld_relocate_objects(_rtld_objmain, bind_now, true) == -1)
_rtld_die();
***************
*** 463,469 ****
}
static void
! _rtld_unref_object_dag(root)
Obj_Entry *root;
{
assert(root->refcount != 0);
--- 500,576 ----
}
static void
! _rtld_init_dag(root)
! Obj_Entry *root;
! {
! curmark++;
! _rtld_init_dag1(root, root);
! }
!
! static void
! _rtld_init_dag1(root, obj)
! Obj_Entry *root;
! Obj_Entry *obj;
! {
! const Needed_Entry *needed;
!
! if (obj->mark == curmark)
! return;
! obj->mark = curmark;
! _rtld_objlist_add(&obj->dldags, root);
! _rtld_objlist_add(&root->dagmembers, obj);
! for (needed = obj->needed; needed != NULL; needed = needed->next)
! if (needed->obj != NULL)
! _rtld_init_dag1(root, needed->obj);
! }
!
! /*
! * Note, this is called only for objects loaded by dlopen().
! */
! static void
! _rtld_unload_object(root, do_fini_funcs)
! Obj_Entry *root;
! bool do_fini_funcs;
! {
! _rtld_unref_dag(root);
! if (root->refcount == 0) { /* We are finished with some objects. */
! Obj_Entry *obj;
! Obj_Entry **linkp;
! Objlist_Entry *elm;
!
! /* Finalize objects that are about to be unmapped. */
! if (do_fini_funcs)
! for (obj = _rtld_objlist->next; obj != NULL; obj = obj->next)
! if (obj->refcount == 0 && obj->fini != NULL)
! (*obj->fini)();
!
! /* Remove the DAG from all objects' DAG lists. */
! for (elm = SIMPLEQ_FIRST(&root->dagmembers); elm; elm = SIMPLEQ_NEXT(elm, link))
! _rtld_objlist_remove(&elm->obj->dldags, root);
!
! /* Remove the DAG from the RTLD_GLOBAL list. */
! _rtld_objlist_remove(&_rtld_list_global, root);
!
! /* Unmap all objects that are no longer referenced. */
! linkp = &_rtld_objlist->next;
! while ((obj = *linkp) != NULL) {
! if (obj->refcount == 0) {
! #ifdef RTLD_DEBUG
! dbg(("unloading \"%s\"", obj->path));
! #endif
! munmap(obj->mapbase, obj->mapsize);
! _rtld_linkmap_delete(obj);
! *linkp = obj->next;
! _rtld_obj_free(obj);
! } else
! linkp = &obj->next;
! }
! _rtld_objtail = linkp;
! }
! }
!
! static void
! _rtld_unref_dag(root)
Obj_Entry *root;
{
assert(root->refcount != 0);
***************
*** 472,479 ****
const Needed_Entry *needed;
for (needed = root->needed; needed != NULL;
! needed = needed->next)
! _rtld_unref_object_dag(needed->obj);
}
}
--- 579,586 ----
const Needed_Entry *needed;
for (needed = root->needed; needed != NULL;
! needed = needed->next)
! _rtld_unref_dag(needed->obj);
}
}
***************
*** 490,496 ****
_rtld_debug_state();
--root->dl_refcount;
! _rtld_unref_object_dag(root);
if (root->refcount == 0) { /* We are finished with some objects. */
Obj_Entry *obj;
Obj_Entry **linkp;
--- 597,603 ----
_rtld_debug_state();
--root->dl_refcount;
! _rtld_unref_dag(root);
if (root->refcount == 0) { /* We are finished with some objects. */
Obj_Entry *obj;
Obj_Entry **linkp;
***************
*** 542,574 ****
Obj_Entry **old_obj_tail = _rtld_objtail;
Obj_Entry *obj = NULL;
_rtld_debug.r_state = RT_ADD;
_rtld_debug_state();
if (name == NULL) {
obj = _rtld_objmain;
} else {
char *path = _rtld_find_library(name, _rtld_objmain);
if (path != NULL)
obj = _rtld_load_object(path, true);
}
if (obj != NULL) {
++obj->dl_refcount;
if (*old_obj_tail != NULL) { /* We loaded something new. */
assert(*old_obj_tail == obj);
! /* FIXME - Clean up properly after an error. */
! if (_rtld_load_needed_objects(obj) == -1) {
! --obj->dl_refcount;
! obj = NULL;
! } else if (_rtld_relocate_objects(obj,
! (mode & 3) == RTLD_NOW, true) == -1) {
! --obj->dl_refcount;
obj = NULL;
! } else {
_rtld_call_init_functions(obj);
- }
}
}
_rtld_debug.r_state = RT_CONSISTENT;
--- 649,688 ----
Obj_Entry **old_obj_tail = _rtld_objtail;
Obj_Entry *obj = NULL;
+ dbg(("called from dlopen (%s,%x)\n", name,mode));
_rtld_debug.r_state = RT_ADD;
_rtld_debug_state();
if (name == NULL) {
obj = _rtld_objmain;
+ obj->refcount++;
} else {
+ #if 0
char *path = _rtld_find_library(name, _rtld_objmain);
+ #else
+ char *path;
+ dbg(("called from dlopen (%s)\n", name));
+ path = _rtld_find_library(name, _rtld_objmain);
+ dbg(("returned from dlopen (%s)\n", path));
+ #endif
if (path != NULL)
obj = _rtld_load_object(path, true);
}
if (obj != NULL) {
++obj->dl_refcount;
+ if (mode & RTLD_GLOBAL && _rtld_objlist_find(&_rtld_list_global, obj) == NULL)
+ _rtld_objlist_add(&_rtld_list_global, obj);
if (*old_obj_tail != NULL) { /* We loaded something new. */
assert(*old_obj_tail == obj);
! if (_rtld_load_needed_objects(obj) == -1 || (_rtld_init_dag(obj),
! _rtld_relocate_objects(obj, ((mode & 3) == RTLD_NOW), true)) == -1) {
! _rtld_unload_object(obj, false);
! obj->dl_refcount--;
obj = NULL;
! } else
_rtld_call_init_functions(obj);
}
}
_rtld_debug.r_state = RT_CONSISTENT;
***************
*** 582,604 ****
void *handle;
const char *name;
{
! const Obj_Entry *obj = _rtld_dlcheck(handle);
! const Elf_Sym *def;
const Obj_Entry *defobj;
! if (obj == NULL)
! return NULL;
/*
! * FIXME - This isn't correct. The search should include the whole
! * DAG rooted at the given object.
! */
! def = _rtld_find_symdef(_rtld_objlist, 0, name, obj, &defobj, false);
! if (def != NULL)
! return defobj->relocbase + def->st_value;
! _rtld_error("Undefined symbol \"%s\"", name);
! return NULL;
}
/*
--- 696,810 ----
void *handle;
const char *name;
{
! const Obj_Entry *obj;
! unsigned long hash;
! const Elf_Sym *def;
const Obj_Entry *defobj;
+
+ hash = _rtld_elf_hash(name);
+ def = NULL;
+ defobj = NULL;
+
+ #if 1
+ if (handle == NULL) {
+ #else
+ if (handle == NULL || handle == RTLD_NEXT) {
+ #endif
+ void *retaddr;
! retaddr = __builtin_return_address(0); /* __GNUC__ only */
! if ((obj = _rtld_obj_from_addr(retaddr)) == NULL) {
! _rtld_error("Cannot determine caller's shared object");
! return NULL;
! }
! if (handle == NULL) { /* Just the caller's shared object. */
! def = _rtld_symlook_obj(name, hash, obj, true);
! defobj = obj;
! } else { /* All the shared objects after the caller's */
! while ((obj = obj->next) != NULL) {
! if ((def = _rtld_symlook_obj(name, hash, obj, true)) != NULL) {
! defobj = obj;
! break;
! }
! }
! }
! } else {
! if ((obj = _rtld_dlcheck(handle)) == NULL)
! return NULL;
!
! if (obj->mainprog) {
! /* Search main program and all libraries loaded by it. */
! curmark++;
! def = _rtld_symlook_list(name, hash, &_rtld_list_main, &defobj, true);
! } else {
! /*
! * XXX - This isn't correct. The search should include the whole
! * DAG rooted at the given object.
! */
! def = _rtld_symlook_obj(name, hash, obj, true);
! defobj = obj;
! }
! }
!
! if (def != NULL)
! return defobj->relocbase + def->st_value;
!
! _rtld_error("Undefined symbol \"%s\"", name);
! return NULL;
! }
+ int
+ _rtld_dladdr(addr, info)
+ const void *addr;
+ Dl_info *info;
+ {
+ const Obj_Entry *obj;
+ const Elf_Sym *def;
+ void *symbol_addr;
+ unsigned long symoffset;
+
+ obj = _rtld_obj_from_addr(addr);
+ if (obj == NULL) {
+ _rtld_error("No shared object contains address");
+ return 0;
+ }
+ info->dli_fname = obj->path;
+ info->dli_fbase = obj->mapbase;
+ info->dli_saddr = (void *)0;
+ info->dli_sname = NULL;
+
/*
! * Walk the symbol list looking for the symbol whose address is
! * closest to the address sent in.
! */
! for (symoffset = 0; symoffset < obj->nchains; symoffset++) {
! def = obj->symtab + symoffset;
! /*
! * For skip the symbol if st_shndx is either Elf_eshn_undefined or
! * Elf_eshn_common.
! */
! if (def->st_shndx == Elf_eshn_undefined || def->st_shndx == Elf_eshn_common)
! continue;
!
! /*
! * If the symbol is greater than the specified address, or if it
! * is further away from addr than the current nearest symbol,
! * then reject it.
! */
! symbol_addr = obj->relocbase + def->st_value;
! if (symbol_addr > addr || symbol_addr < info->dli_saddr)
! continue;
!
! /* Update our idea of the nearest symbol. */
! info->dli_sname = obj->strtab + def->st_name;
! info->dli_saddr = symbol_addr;
!
! /* Exact match? */
! if (info->dli_saddr == addr)
! break;
! }
! return 1;
}
/*
***************
*** 673,676 ****
--- 879,949 ----
}
if ((l->l_prev->l_next = l->l_next) != NULL)
l->l_next->l_prev = l->l_prev;
+ }
+
+ static Obj_Entry *
+ _rtld_obj_from_addr(const void *addr)
+ {
+ unsigned long endhash;
+ Obj_Entry *obj;
+
+ endhash = _rtld_elf_hash(END_SYM);
+ for (obj = _rtld_objlist; obj != NULL; obj = obj->next) {
+ const Elf_Sym *endsym;
+
+ if (addr < (void *) obj->mapbase)
+ continue;
+ if ((endsym = _rtld_symlook_obj(END_SYM, endhash, obj, true)) == NULL)
+ continue; /* No "end" symbol?! */
+ if (addr < (void *) (obj->relocbase + endsym->st_value))
+ return obj;
+ }
+ return NULL;
+ }
+
+ static void
+ _rtld_objlist_add(list, obj)
+ Objlist *list;
+ Obj_Entry *obj;
+ {
+ Objlist_Entry *elm;
+
+ elm = NEW(Objlist_Entry);
+ elm->obj = obj;
+ SIMPLEQ_INSERT_TAIL(list, elm, link);
+ }
+
+ static Objlist_Entry *
+ _rtld_objlist_find(Objlist *list, const Obj_Entry *obj)
+ {
+ Objlist_Entry *elm;
+
+ for (elm = SIMPLEQ_FIRST(list); elm; elm = SIMPLEQ_NEXT(elm, link)) {
+ if (elm->obj == obj)
+ return elm;
+ }
+ return NULL;
+ }
+
+ static void
+ _rtld_objlist_remove(list, obj)
+ Objlist *list;
+ Obj_Entry *obj;
+ {
+ Objlist_Entry *elm;
+
+ if ((elm = _rtld_objlist_find(list, obj)) != NULL) {
+ if ((list)->sqh_first == (elm)) {
+ SIMPLEQ_REMOVE_HEAD(list, elm, link);
+ }
+ else {
+ struct Struct_Objlist_Entry *curelm = (list)->sqh_first;
+ while (curelm->link.sqe_next != (elm))
+ curelm = curelm->link.sqe_next;
+ if((curelm->link.sqe_next =
+ curelm->link.sqe_next->link.sqe_next) == NULL)
+ (list)->sqh_last = &(curelm)->link.sqe_next;
+ }
+ free(elm);
+ }
}
diff -cr src/libexec/ld.elf_so/rtld.h src/libexec/ld.newelf_so/rtld.h
*** src/libexec/ld.elf_so/rtld.h Fri Aug 20 20:10:44 1999
--- src/libexec/ld.newelf_so/rtld.h Tue Oct 19 07:36:47 1999
***************
*** 34,42 ****
--- 34,44 ----
#ifndef RTLD_H
#define RTLD_H
+ #include <dlfcn.h>
#include <stddef.h>
#include <sys/param.h>
#include <sys/types.h>
+ #include <sys/queue.h>
#include <sys/exec_elf.h>
#include "rtldenv.h"
#include "link.h"
***************
*** 89,94 ****
--- 91,103 ----
struct Struct_Obj_Entry;
+ typedef struct Struct_Objlist_Entry {
+ SIMPLEQ_ENTRY(Struct_Objlist_Entry) link;
+ struct Struct_Obj_Entry *obj;
+ } Objlist_Entry;
+
+ typedef SIMPLEQ_HEAD(Struct_Objlist, Struct_Objlist_Entry) Objlist;
+
typedef struct Struct_Needed_Entry {
struct Struct_Needed_Entry *next;
struct Struct_Obj_Entry *obj;
***************
*** 178,183 ****
--- 187,200 ----
int printed:1; /* True if ldd has printed it */
struct link_map linkmap; /* for GDB */
+
+ /* These items are computed by map_object() or by digest_phdr(). */
+ const char *interp; /* Pathname of the interpreter, if any */
+ Objlist dldags; /* Object belongs to these dlopened DAGs (%) */
+ Objlist dagmembers; /* DAG has these members (%) */
+ dev_t dev; /* Object's filesystem's device */
+ ino_t ino; /* Object's inode number */
+ unsigned long mark; /* Set to "curmark" to avoid repeat visits */
} Obj_Entry;
#if defined(_RTLD_SOURCE)
***************
*** 186,195 ****
--- 203,217 ----
extern Search_Path *_rtld_default_paths;
extern Obj_Entry *_rtld_objlist;
extern Obj_Entry **_rtld_objtail;
+ extern Obj_Entry *_rtld_objmain;
extern Obj_Entry _rtld_objself;
extern Search_Path *_rtld_paths;
extern bool _rtld_trust;
extern const char *_rtld_error_message;
+ extern unsigned long curmark;
+ extern Objlist _rtld_list_global;
+ extern Objlist _rtld_list_main;
+ extern Elf_Sym _rtld_sym_zero;
/* rtld_start.S */
void _rtld_bind_start __P((void));
***************
*** 201,206 ****
--- 223,229 ----
void *_rtld_dlopen __P((const char *, int));
void *_rtld_dlsym __P((void *, const char *));
int _rtld_dlclose __P((void *));
+ int _rtld_dladdr __P((const void *, Dl_info *));
void _rtld_debug_state __P((void));
void _rtld_linkmap_add __P((Obj_Entry *));
void _rtld_linkmap_delete __P((Obj_Entry *));
***************
*** 220,230 ****
/* reloc.c */
int _rtld_do_copy_relocations __P((const Obj_Entry *, bool));
! caddr_t _rtld_bind __P((const Obj_Entry *, Elf_Word));
int _rtld_relocate_objects __P((Obj_Entry *, bool, bool));
! int _rtld_relocate_nonplt_object __P((const Obj_Entry *,
const Elf_RelA *, bool));
! int _rtld_relocate_plt_object __P((const Obj_Entry *, const Elf_RelA *,
caddr_t *, bool, bool));
/* search.c */
--- 243,253 ----
/* reloc.c */
int _rtld_do_copy_relocations __P((const Obj_Entry *, bool));
! caddr_t _rtld_bind __P((Obj_Entry *, Elf_Word));
int _rtld_relocate_objects __P((Obj_Entry *, bool, bool));
! int _rtld_relocate_nonplt_object __P((Obj_Entry *,
const Elf_RelA *, bool));
! int _rtld_relocate_plt_object __P((Obj_Entry *, const Elf_RelA *,
caddr_t *, bool, bool));
/* search.c */
***************
*** 235,244 ****
const Elf_Sym *_rtld_symlook_obj __P((const char *, unsigned long,
const Obj_Entry *, bool));
const Elf_Sym *_rtld_find_symdef __P((const Obj_Entry *, Elf_Word,
! const char *, const Obj_Entry *, const Obj_Entry **, bool));
/* map_object.c */
! Obj_Entry *_rtld_map_object __P((const char *, int));
#if defined(__mips__)
/* mips_reloc.c */
--- 258,271 ----
const Elf_Sym *_rtld_symlook_obj __P((const char *, unsigned long,
const Obj_Entry *, bool));
const Elf_Sym *_rtld_find_symdef __P((const Obj_Entry *, Elf_Word,
! const char *, Obj_Entry *, const Obj_Entry **, bool));
! const Elf_Sym *_rtld_symlook_list(const char *, unsigned long,
! Objlist *, const Obj_Entry **, bool in_plt);
/* map_object.c */
! Obj_Entry *_rtld_map_object __P((const char *, int, const struct stat *));
! void _rtld_obj_free(Obj_Entry *);
! Obj_Entry *_rtld_obj_new(void);
#if defined(__mips__)
/* mips_reloc.c */
diff -cr src/libexec/ld.elf_so/symbol.c src/libexec/ld.newelf_so/symbol.c
*** src/libexec/ld.elf_so/symbol.c Tue Mar 2 21:15:47 1999
--- src/libexec/ld.newelf_so/symbol.c Thu Oct 14 03:34:16 1999
***************
*** 73,78 ****
--- 73,110 ----
return h;
}
+ const Elf_Sym *
+ _rtld_symlook_list(const char *name, unsigned long hash, Objlist *objlist,
+ const Obj_Entry **defobj_out, bool in_plt)
+ {
+ const Elf_Sym *symp;
+ const Elf_Sym *def;
+ const Obj_Entry *defobj;
+ const Objlist_Entry *elm;
+
+ def = NULL;
+ defobj = NULL;
+ for (elm = SIMPLEQ_FIRST(objlist); elm; elm = SIMPLEQ_NEXT(elm, link)) {
+ if (elm->obj->mark == curmark)
+ continue;
+ elm->obj->mark = curmark;
+ if ((symp = _rtld_symlook_obj(name, hash, elm->obj, in_plt))
+ != NULL) {
+ if ((def == NULL) ||
+ (ELF_SYM_BIND(symp->st_info) != Elf_estb_weak)) {
+ def = symp;
+ defobj = elm->obj;
+ if (ELF_SYM_BIND(def->st_info)
+ != Elf_estb_weak)
+ break;
+ }
+ }
+ }
+ if (def != NULL)
+ *defobj_out = defobj;
+ return def;
+ }
+
/*
* Search the symbol table of a single shared object for a symbol of
* the given name. Returns a pointer to the symbol, or NULL if no
***************
*** 128,140 ****
const Obj_Entry *obj_list;
Elf_Word r_info;
const char *name;
! const Obj_Entry *refobj;
const Obj_Entry **defobj_out;
bool in_plt;
{
Elf_Word symnum = ELF_R_SYM(r_info);
const Elf_Sym *ref;
const Obj_Entry *obj;
unsigned long hash;
if (name == NULL) {
--- 160,176 ----
const Obj_Entry *obj_list;
Elf_Word r_info;
const char *name;
! Obj_Entry *refobj;
const Obj_Entry **defobj_out;
bool in_plt;
{
Elf_Word symnum = ELF_R_SYM(r_info);
const Elf_Sym *ref;
+ const Elf_Sym *def;
+ const Elf_Sym *symp;
const Obj_Entry *obj;
+ const Obj_Entry *defobj;
+ const Objlist_Entry *elm;
unsigned long hash;
if (name == NULL) {
***************
*** 142,178 ****
name = refobj->strtab + ref->st_name;
}
hash = _rtld_elf_hash(name);
!
if (refobj->symbolic) { /* Look first in the referencing object */
! const Elf_Sym *def;
!
! def = _rtld_symlook_obj(name, hash, refobj, in_plt);
! if (def != NULL) {
! *defobj_out = refobj;
! return def;
}
}
! /*
! * Look in all loaded objects. Skip the referencing object, if
! * we have already searched it.
! */
! for (obj = obj_list; obj != NULL; obj = obj->next) {
! if (obj != refobj || !refobj->symbolic) {
! const Elf_Sym *def;
!
! def = _rtld_symlook_obj(name, hash, obj, in_plt);
! if (def != NULL) {
! *defobj_out = obj;
! return def;
! }
}
}
!
! if (ELF_R_TYPE(r_info) != R_TYPE(NONE)) {
_rtld_error(
"%s: Undefined %ssymbol \"%s\" (reloc type = %d, symnum = %d)",
! refobj->path, in_plt ? "PLT " : "", name,
! ELF_R_TYPE(r_info), symnum);
}
! return NULL;
}
--- 178,245 ----
name = refobj->strtab + ref->st_name;
}
hash = _rtld_elf_hash(name);
! def = NULL;
! defobj = NULL;
! curmark++;
!
if (refobj->symbolic) { /* Look first in the referencing object */
! symp = _rtld_symlook_obj(name, hash, refobj, in_plt);
! refobj->mark = curmark;
! if (symp != NULL) {
! def = symp;
! defobj = refobj;
}
}
!
! /* Search all objects loaded at program start up. */
! if (def == NULL || ELF_SYM_BIND(def->st_info) == Elf_estb_weak) {
! symp = _rtld_symlook_list(name, hash, &_rtld_list_main, &obj, in_plt);
! if (symp != NULL &&
! ((def == NULL) || (ELF_SYM_BIND(symp->st_info) != Elf_estb_weak))) {
! def = symp;
! defobj = obj;
}
}
!
! /* Search all dlopened DAGs containing the referencing object. */
! for (elm = SIMPLEQ_FIRST(&refobj->dldags); elm; elm = SIMPLEQ_NEXT(elm, link)) {
! if ((def != NULL) && (ELF_SYM_BIND(def->st_info) != Elf_estb_weak))
! break;
! symp = _rtld_symlook_list(name, hash, &elm->obj->dagmembers, &obj,
! in_plt);
! if (symp != NULL &&
! ((def == NULL) || (ELF_SYM_BIND(symp->st_info) != Elf_estb_weak))) {
! def = symp;
! defobj = obj;
! }
! }
!
! /* Search all RTLD_GLOBAL objects. */
! if (def == NULL || ELF_SYM_BIND(def->st_info) == Elf_estb_weak) {
! symp = _rtld_symlook_list(name, hash, &_rtld_list_global, &obj, in_plt);
! if (symp != NULL &&
! (def == NULL || ELF_SYM_BIND(symp->st_info) != Elf_estb_weak)) {
! def = symp;
! defobj = obj;
! }
! }
!
! /*
! * If we found no definition and the reference is weak, treat the
! * symbol as having the value zero.
! */
! if (def == NULL && ELF_SYM_BIND(ref->st_info) == Elf_estb_weak) {
! def = &_rtld_sym_zero;
! defobj = _rtld_objmain;
! }
!
! if (def != NULL)
! *defobj_out = defobj;
! else if (ELF_R_TYPE(r_info) != R_TYPE(NONE)) {
_rtld_error(
"%s: Undefined %ssymbol \"%s\" (reloc type = %d, symnum = %d)",
! refobj->path, in_plt ? "PLT " : "", name,
! ELF_R_TYPE(r_info), symnum);
}
! return def;
}
*** src/sys/sys/exec_elf.h.orig Mon Sep 13 20:31:25 1999
--- src/sys/sys/exec_elf.h Tue Oct 19 07:33:34 1999
***************
*** 302,307 ****
--- 302,310 ----
#define ELF_SYM_TYPE(info) ((enum elf_e_symbol_type) ((info) & 0x0F))
+ /* Macro for constructing st_info from field values. */
+ #define ELF_SYM_INFO(bind, type) (((bind) << 4) + ((type) & 0xf))
+
enum elf_e_symbol_section_index {
Elf_eshn_undefined =0,
Elf_eshn_mips_acommon =0xFF00,
----------------------------------------------------------
SAITOH Masanobu (msaitoh@spa.is.uec.ac.jp,
msaitoh@netbsd.org)
University of Electro-Communications