diff options
Diffstat (limited to 'elf')
-rw-r--r-- | elf/dl-deps.c | 11 | ||||
-rw-r--r-- | elf/dl-load.c | 2 | ||||
-rw-r--r-- | elf/rtld.c | 31 |
3 files changed, 29 insertions, 15 deletions
diff --git a/elf/dl-deps.c b/elf/dl-deps.c index 3e49fcf..9fe974d 100644 --- a/elf/dl-deps.c +++ b/elf/dl-deps.c @@ -38,6 +38,10 @@ _dl_map_object_deps (struct link_map *map) head.next = NULL; nlist = 1; + /* We use `l_reserved' as a mark bit to detect objects we have already + put in the search list and avoid adding duplicate elements later in + the list. */ + map->l_reserved = 1; /* Process each element of the search list, loading each of its immediate dependencies and appending them to the list as we step through it. @@ -47,11 +51,6 @@ _dl_map_object_deps (struct link_map *map) { struct link_map *l = scanp->map; - /* We use `l_reserved' as a mark bit to detect objects we have - already put in the search list and avoid adding duplicate elements - later in the list. */ - l->l_reserved = 1; - if (l->l_info[DT_NEEDED]) { const char *strtab @@ -79,6 +78,8 @@ _dl_map_object_deps (struct link_map *map) tailp->map = dep; tailp->next = NULL; ++nlist; + /* Set the mark bit that says it's already in the list. */ + dep->l_reserved = 1; } } } diff --git a/elf/dl-load.c b/elf/dl-load.c index f947bb8..f655fda 100644 --- a/elf/dl-load.c +++ b/elf/dl-load.c @@ -479,7 +479,7 @@ _dl_map_object (struct link_map *loader, const char *name, int type) l->l_info[DT_RPATH]->d_un.d_val)); /* If dynamically linked, try the DT_RPATH of the executable itself. */ l = _dl_loaded; - if (fd == -1 && l && l->l_type != lt_loaded) + if (fd == -1 && l && l->l_type != lt_loaded && l->l_info[DT_RPATH]) trypath ((const char *) (l->l_addr + l->l_info[DT_STRTAB]->d_un.d_ptr + l->l_info[DT_RPATH]->d_un.d_val)); @@ -243,17 +243,30 @@ of this helper program; chances are you did not intend to run this program.\n", __close (_dl_zerofd); _dl_zerofd = -1; - /* XXX if kept, move it so l_next list is in dep order because - it will determine gdb's search order. - Perhaps do this always, so later dlopen by name finds it? - XXX But then gdb always considers it present. */ - if (_dl_rtld_map.l_opencount == 0) + /* Remove _dl_rtld_map from the chain. */ + _dl_rtld_map.l_prev->l_next = _dl_rtld_map.l_next; + if (_dl_rtld_map.l_next) + _dl_rtld_map.l_next->l_prev = _dl_rtld_map.l_prev; + + if (_dl_rtld_map.l_opencount) { - /* No DT_NEEDED entry referred to the interpreter object itself, - so remove it from the list of visible objects. */ - _dl_rtld_map.l_prev->l_next = _dl_rtld_map.l_next; + /* Some DT_NEEDED entry referred to the interpreter object itself, so + put it back in the list of visible objects. We insert it into the + chain in symbol search order because gdb uses the chain's order as + its symbol search order. */ + unsigned int i = 1; + while (l->l_searchlist[i] != &_dl_rtld_map) + ++i; + _dl_rtld_map.l_prev = l->l_searchlist[i - 1]; + _dl_rtld_map.l_next = (i + 1 < l->l_nsearchlist ? + l->l_searchlist[i + 1] : NULL); + assert (_dl_rtld_map.l_prev->l_next == _dl_rtld_map.l_next); + _dl_rtld_map.l_prev->l_next = &_dl_rtld_map; if (_dl_rtld_map.l_next) - _dl_rtld_map.l_next->l_prev = _dl_rtld_map.l_prev; + { + assert (_dl_rtld_map.l_next->l_prev == _dl_rtld_map.l_prev); + _dl_rtld_map.l_next->l_prev = &_dl_rtld_map; + } } if (list_only) |