|
Message-Id: <1435448915-28419-6-git-send-email-amonakov@ispras.ru> Date: Sun, 28 Jun 2015 02:48:34 +0300 From: Alexander Monakov <amonakov@...ras.ru> To: musl@...ts.openwall.com Subject: [PATCH v2 5/6] dynlink.c: compute modulus via magic multiplication Based on http://ridiculousfish.com/blog/posts/labor-of-division-episode-iii.html Do a little hand-holding for the compiler and fold magic post-shift into 32-bit high word -> low word shift on 64-bit platforms. --- src/ldso/dynlink.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 64 insertions(+), 2 deletions(-) diff --git a/src/ldso/dynlink.c b/src/ldso/dynlink.c index 1c62efe..f181209 100644 --- a/src/ldso/dynlink.c +++ b/src/ldso/dynlink.c @@ -41,6 +41,11 @@ struct td_index { struct td_index *next; }; +struct udiv { + uint32_t mul; + unsigned char s1, s2, inc; +}; + struct dso { unsigned char *base; char *name; @@ -54,6 +59,7 @@ struct dso { Sym *syms; uint32_t *hashtab; uint32_t *ghashtab; + struct udiv gudiv; int16_t *versym; char *strings; unsigned char *map; @@ -140,6 +146,60 @@ static int search_vec(size_t *v, size_t *r, size_t key) return 1; } +static void precompute_udiv(uint32_t div, struct udiv *p) +{ + if (!(div&(div-1))) + return; + int bits = 0, s2adj = (sizeof(long) == 8) ? 32 : 0; +again: + p->s1 = bits; + uint32_t tmp = 1u<<31, quo = tmp/div, rem = tmp%div; + + int log=0; + tmp=div; do log++; while (tmp>>=1); + + int exp, rdshf; + uint32_t pow, rdmul=0; + for (exp=0, pow=1u<<bits; ; exp++, pow<<=1) { + int ovf = rem >= div - rem; + quo *= 2; rem *= 2; + if (ovf) quo++, rem -= div; + + if (exp >= log-bits || div-rem <= pow) + break; + + if (!rdmul && rem <= pow) + rdmul = quo, rdshf = exp; + } + if (exp < log) { + p->mul = quo+1; + p->s2 = exp + s2adj; + p->inc = 0; + } else if (div & 1) { + p->mul = rdmul; + p->s2 = rdshf + s2adj; + p->inc = 1; + } else { + do bits++; while (!((div >>= 1) & 1)); + goto again; + } +} + +static uint32_t umod(uint32_t x, uint32_t div, struct udiv *p) +{ + if (!(div&(div-1))) + return x&(div-1); + uint32_t v = x; + v >>= p->s1; + if (v + p->inc) v += p->inc; + int s32=32, s2=p->s2; + if (sizeof(long) == 8) + s32=s2, s2=0; + v = (1ull * v * p->mul) >> s32; + v >>= s2; + return x-v*div; +} + static uint32_t sysv_hash(const char *s0) { const unsigned char *s = (void *)s0; @@ -178,7 +238,7 @@ static Sym *gnu_lookup(uint32_t h1, uint32_t *hashtab, struct dso *dso, const ch { uint32_t nbuckets = hashtab[0]; uint32_t *buckets = hashtab + 4 + hashtab[2]*(sizeof(size_t)/4); - uint32_t i = buckets[h1 % nbuckets]; + uint32_t i = buckets[umod(h1, nbuckets, &dso->gudiv)]; if (!i) return 0; @@ -696,8 +756,10 @@ static void decode_dyn(struct dso *p) p->rpath_orig = (void *)(p->strings + dyn[DT_RPATH]); if (dyn[0]&(1<<DT_RUNPATH)) p->rpath_orig = (void *)(p->strings + dyn[DT_RUNPATH]); - if (search_vec(p->dynv, dyn, DT_GNU_HASH)) + if (search_vec(p->dynv, dyn, DT_GNU_HASH)) { p->ghashtab = (void *)(p->base + *dyn); + precompute_udiv(p->ghashtab[0], &p->gudiv); + } if (search_vec(p->dynv, dyn, DT_VERSYM)) p->versym = (void *)(p->base + *dyn); }
Powered by blists - more mailing lists
Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.