summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRich Felker <dalias@aerifal.cx>2015-09-21 21:47:50 +0000
committerRich Felker <dalias@aerifal.cx>2015-09-21 21:47:50 +0000
commit3958144ede01a7e64a56c0430f053bfd80ff02eb (patch)
treec99ab3049f5b6d2821e0891aa046083070c75082 /src
parentd874064579f4dd8150b0d6ff6d98942af6fcd1c3 (diff)
downloadmusl-3958144ede01a7e64a56c0430f053bfd80ff02eb.tar.gz
factor symbol counting out of dladdr as its own function
the fdpic code will need to count symbols, and it may be useful elsewhere in the future too. counting is trivial as long as sysv hash is present, but for gnu-hash-only libraries it's complex. the behavior of the count is changed slightly: we now include symbols that are not accessible by the gnu hash table in the count. this may make dladdr slightly slower. if this is a problem, dladdr can subtract out the part that should not be accessible. unlike in the old code, subtracting this out is easy even in the fast path where sysv hash is available too.
Diffstat (limited to 'src')
-rw-r--r--src/ldso/dynlink.c39
1 files changed, 20 insertions, 19 deletions
diff --git a/src/ldso/dynlink.c b/src/ldso/dynlink.c
index 8e1d94f3..4b52a5a6 100644
--- a/src/ldso/dynlink.c
+++ b/src/ldso/dynlink.c
@@ -704,6 +704,25 @@ static void decode_dyn(struct dso *p)
p->versym = laddr(p, *dyn);
}
+static size_t count_syms(struct dso *p)
+{
+ if (p->hashtab) return p->hashtab[1];
+
+ size_t nsym, i;
+ uint32_t *buckets = p->ghashtab + 4 + (p->ghashtab[2]*sizeof(size_t)/4);
+ uint32_t *hashval;
+ for (i = nsym = 0; i < p->ghashtab[0]; i++) {
+ if (buckets[i] > nsym)
+ nsym = buckets[i];
+ }
+ if (nsym) {
+ hashval = buckets + p->ghashtab[0] + (nsym - p->ghashtab[1]);
+ do nsym++;
+ while (!(*hashval++ & 1));
+ }
+ return nsym;
+}
+
static struct dso *load_library(const char *name, struct dso *needed_by)
{
char buf[2*NAME_MAX+2];
@@ -1613,7 +1632,6 @@ int __dladdr(const void *addr, Dl_info *info)
Sym *sym;
uint32_t nsym;
char *strings;
- size_t i;
void *best = 0;
char *bestname;
@@ -1625,24 +1643,7 @@ int __dladdr(const void *addr, Dl_info *info)
sym = p->syms;
strings = p->strings;
- if (p->hashtab) {
- nsym = p->hashtab[1];
- } else {
- uint32_t *buckets;
- uint32_t *hashval;
- buckets = p->ghashtab + 4 + (p->ghashtab[2]*sizeof(size_t)/4);
- sym += p->ghashtab[1];
- for (i = nsym = 0; i < p->ghashtab[0]; i++) {
- if (buckets[i] > nsym)
- nsym = buckets[i];
- }
- if (nsym) {
- nsym -= p->ghashtab[1];
- hashval = buckets + p->ghashtab[0] + nsym;
- do nsym++;
- while (!(*hashval++ & 1));
- }
- }
+ nsym = count_syms(p);
for (; nsym; nsym--, sym++) {
if (sym->st_value