From 709355e1f6dad17234606486400568bc87a37d79 Mon Sep 17 00:00:00 2001 From: Rich Felker Date: Fri, 23 Aug 2013 11:15:40 -0400 Subject: add recursive rpath support to dynamic linker previously, rpath was only honored for direct dependencies. in other words, if A depends on B and B depends on C, only B's rpath (if any), not A's rpath, was being searched for C. this limitation made rpath-based deployment difficult in the presence of multiple levels of library dependency. at present, $ORIGIN processing in rpath is still unsupported. --- src/ldso/dynlink.c | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) (limited to 'src/ldso') diff --git a/src/ldso/dynlink.c b/src/ldso/dynlink.c index ad987b8f..8c5b9625 100644 --- a/src/ldso/dynlink.c +++ b/src/ldso/dynlink.c @@ -72,7 +72,8 @@ struct dso { signed char global; char relocated; char constructed; - struct dso **deps; + struct dso **deps, *needed_by; + char *rpath; void *tls_image; size_t tls_len, tls_size, tls_align, tls_id, tls_offset; void **new_dtv; @@ -95,7 +96,7 @@ void *__install_initial_tls(void *); void __init_libc(char **, char *); static struct dso *head, *tail, *ldso, *fini_head; -static char *env_path, *sys_path, *r_path; +static char *env_path, *sys_path; static unsigned long long gencnt; static int ssp_used; static int runtime; @@ -455,13 +456,15 @@ static void decode_dyn(struct dso *p) p->strings = (void *)(p->base + dyn[DT_STRTAB]); if (dyn[0]&(1<hashtab = (void *)(p->base + dyn[DT_HASH]); + if (dyn[0]&(1<rpath = (void *)(p->strings + dyn[DT_RPATH]); if (search_vec(p->dynv, dyn, DT_GNU_HASH)) p->ghashtab = (void *)(p->base + *dyn); if (search_vec(p->dynv, dyn, DT_VERSYM)) p->versym = (void *)(p->base + *dyn); } -static struct dso *load_library(const char *name) +static struct dso *load_library(const char *name, struct dso *needed_by) { char buf[2*NAME_MAX+2]; const char *pathname; @@ -521,7 +524,9 @@ static struct dso *load_library(const char *name) if (strlen(name) > NAME_MAX) return 0; fd = -1; if (env_path) fd = path_open(name, env_path, buf, sizeof buf); - if (fd < 0 && r_path) fd = path_open(name, r_path, buf, sizeof buf); + for (p=needed_by; fd < 0 && p; p=p->needed_by) + if (p->rpath) + fd = path_open(name, p->rpath, buf, sizeof buf); if (fd < 0) { if (!sys_path) { char *prefix = 0; @@ -601,6 +606,7 @@ static struct dso *load_library(const char *name) p->dev = st.st_dev; p->ino = st.st_ino; p->refcnt = 1; + p->needed_by = needed_by; p->name = p->buf; strcpy(p->name, pathname); /* Add a shortname only if name arg was not an explicit pathname. */ @@ -642,13 +648,9 @@ static void load_deps(struct dso *p) size_t i, ndeps=0; struct dso ***deps = &p->deps, **tmp, *dep; for (; p; p=p->next) { - for (i=0; p->dynv[i]; i+=2) { - if (p->dynv[i] != DT_RPATH) continue; - r_path = (void *)(p->strings + p->dynv[i+1]); - } for (i=0; p->dynv[i]; i+=2) { if (p->dynv[i] != DT_NEEDED) continue; - dep = load_library(p->strings + p->dynv[i+1]); + dep = load_library(p->strings + p->dynv[i+1], p); if (!dep) { snprintf(errbuf, sizeof errbuf, "Error loading shared library %s: %m (needed by %s)", @@ -666,7 +668,6 @@ static void load_deps(struct dso *p) *deps = tmp; } } - r_path = 0; } } @@ -679,7 +680,7 @@ static void load_preload(char *s) for (z=s; *z && !isspace(*z); z++); tmp = *z; *z = 0; - load_library(s); + load_library(s, 0); *z = tmp; } } @@ -1153,7 +1154,7 @@ void *dlopen(const char *file, int mode) p = 0; errflag = 1; goto end; - } else p = load_library(file); + } else p = load_library(file, 0); if (!p) { snprintf(errbuf, sizeof errbuf, noload ? -- cgit v1.2.1