about summary refs log tree commit diff
diff options
context:
space:
mode:
authorRich Felker <dalias@aerifal.cx>2015-09-22 22:48:21 +0000
committerRich Felker <dalias@aerifal.cx>2015-09-22 23:11:38 +0000
commitd47d9a50f2568927af51e21b2f2120409db1ab44 (patch)
tree15c7eee29f65ed87ff0f24f2c8f54219b77d41a5
parente9e770dfd6224a5ff7932b6115a35005dce7be29 (diff)
downloadmusl-d47d9a50f2568927af51e21b2f2120409db1ab44.tar.gz
musl-d47d9a50f2568927af51e21b2f2120409db1ab44.tar.xz
musl-d47d9a50f2568927af51e21b2f2120409db1ab44.zip
fix dlsym lookup of function symbols on fdpic
previously these resolved to the code address rather than the address
of the function descriptor.

the conditions for accepting or rejecting symbols are quite
inconsistent between the different points in the dynamic linker code
where such decisions are made. this commit attempts to be at least as
correct as anything already there, but does not improve consistency.
it has been tested to correctly avoid symbols that are merely
references to functions defined in other modules, at least in simple
usage, but at some point all symbol lookup logic should be reviewed
and refactored/unified.
-rw-r--r--src/ldso/dynlink.c6
1 files changed, 6 insertions, 0 deletions
diff --git a/src/ldso/dynlink.c b/src/ldso/dynlink.c
index f144aa59..0c3b36ce 100644
--- a/src/ldso/dynlink.c
+++ b/src/ldso/dynlink.c
@@ -1757,6 +1757,8 @@ static void *do_dlsym(struct dso *p, const char *s, void *ra)
 		if (!def.sym) goto failed;
 		if ((def.sym->st_info&0xf) == STT_TLS)
 			return __tls_get_addr((size_t []){def.dso->tls_id, def.sym->st_value});
+		if (DL_FDPIC && (def.sym->st_info&0xf) == STT_FUNC)
+			return def.dso->funcdescs + (def.sym - def.dso->syms);
 		return laddr(def.dso, def.sym->st_value);
 	}
 	if (invalid_dso_handle(p))
@@ -1770,6 +1772,8 @@ static void *do_dlsym(struct dso *p, const char *s, void *ra)
 	}
 	if (sym && (sym->st_info&0xf) == STT_TLS)
 		return __tls_get_addr((size_t []){p->tls_id, sym->st_value});
+	if (DL_FDPIC && sym && sym->st_shndx && (sym->st_info&0xf) == STT_FUNC)
+		return p->funcdescs + (sym - p->syms);
 	if (sym && sym->st_value && (1<<(sym->st_info&0xf) & OK_TYPES))
 		return laddr(p, sym->st_value);
 	if (p->deps) for (i=0; p->deps[i]; i++) {
@@ -1782,6 +1786,8 @@ static void *do_dlsym(struct dso *p, const char *s, void *ra)
 		}
 		if (sym && (sym->st_info&0xf) == STT_TLS)
 			return __tls_get_addr((size_t []){p->deps[i]->tls_id, sym->st_value});
+		if (DL_FDPIC && sym && sym->st_shndx && (sym->st_info&0xf) == STT_FUNC)
+			return p->deps[i]->funcdescs + (sym - p->deps[i]->syms);
 		if (sym && sym->st_value && (1<<(sym->st_info&0xf) & OK_TYPES))
 			return laddr(p->deps[i], sym->st_value);
 	}