From mboxrd@z Thu Jan 1 00:00:00 1970 X-Msuck: nntp://news.gmane.org/gmane.linux.lib.musl.general/1459 Path: news.gmane.org!not-for-mail From: Szabolcs Nagy Newsgroups: gmane.linux.lib.musl.general Subject: Re: ldso : dladdr support Date: Wed, 8 Aug 2012 13:52:02 +0200 Message-ID: <20120808115202.GL30810@port70.net> References: <5020DA13.6080803@gmail.com> <20120807114627.GG30810@port70.net> <50212306.6070402@gmail.com> <20120807230933.GC27715@brightrain.aerifal.cx> <502237A1.1000805@gmail.com> Reply-To: musl@lists.openwall.com NNTP-Posting-Host: plane.gmane.org Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii X-Trace: dough.gmane.org 1344426747 17591 80.91.229.3 (8 Aug 2012 11:52:27 GMT) X-Complaints-To: usenet@dough.gmane.org NNTP-Posting-Date: Wed, 8 Aug 2012 11:52:27 +0000 (UTC) To: musl@lists.openwall.com Original-X-From: musl-return-1460-gllmg-musl=m.gmane.org@lists.openwall.com Wed Aug 08 13:52:27 2012 Return-path: Envelope-to: gllmg-musl@plane.gmane.org Original-Received: from mother.openwall.net ([195.42.179.200]) by plane.gmane.org with smtp (Exim 4.69) (envelope-from ) id 1Sz4oB-0005U3-Jm for gllmg-musl@plane.gmane.org; Wed, 08 Aug 2012 13:52:15 +0200 Original-Received: (qmail 32665 invoked by uid 550); 8 Aug 2012 11:52:14 -0000 Mailing-List: contact musl-help@lists.openwall.com; run by ezmlm Precedence: bulk List-Post: List-Help: List-Unsubscribe: List-Subscribe: Original-Received: (qmail 32656 invoked from network); 8 Aug 2012 11:52:14 -0000 Content-Disposition: inline In-Reply-To: <502237A1.1000805@gmail.com> User-Agent: Mutt/1.5.21 (2010-09-15) Xref: news.gmane.org gmane.linux.lib.musl.general:1459 Archived-At: * musl [2012-08-08 11:55:45 +0200]: > Here is the new patch for dladdr + gnu hash support. > > On 08/08/2012 01:09, Rich Felker wrote: > > don't remember which) where I described some optimizations that should > > be present if gnu hash is to be supported. Basically, the dynamic > > linker should keep track of whether there's one of the two hashes > > that's supported by ALL loaded libs, and in that case, only ever use > > that hash, to avoid computing two different hashes. > The hash for given algo is only computed once (if needed). > That's the reason for the computed table. > If all libs uses the same hash algo, the other will never be computed. a lib can support both hash tables (so it's non-trivial to use the one that all libs support, eg instead of a single alg index a bit mask should be used) > +#define SYSV_HASH_ALG_IDX 0 > +#define GNU_HASH_ALG_IDX 1 > +#define HASH_ALG_CNT 2 if we go with this approach then use shorter names (thes are only used locally) eg. SYSV_HASH, GNU_HASH, NHASH > + for (h1 &= (uint32_t)-2;; sym++) { > + h2 = *hashval++; > + if ((h1 == (h2 & ~1)) && !strcmp(s, strings + sym->st_name)) these is still a ~1 looking at it now probably writing out & 0xfffffffe is the cleanest > + static uint32_t precomp[HASH_ALG_CNT][3] = { > + {0x6b366be, 0x6b3afd, 0x595a4cc}, > + {0xf9040207, 0xf4dc4ae, 0x1f4039c9}, > + }; > + uint32_t h[HASH_ALG_CNT]; > + uint8_t computed[HASH_ALG_CNT] = {0, 0}; > + uint8_t alg = dso->hashalg; > + if (alg == SYSV_HASH_ALG_IDX) > + h[alg] = sysv_hash(s); > + else > + h[alg] = gnu_hash(s); > + > + computed[alg] = 1; > + > + if (h[alg] == precomp[alg][0] && !strcmp(s, "dlopen")) rtld_used = 1; > + if (h[alg] == precomp[alg][1] && !strcmp(s, "dlsym")) rtld_used = 1; > + if (h[alg] == precomp[alg][2] && !strcmp(s, "__stack_chk_fail")) ssp_used = 1; > + > for (; dso; dso=dso->next) { > Sym *sym; > + > if (!dso->global) continue; > - sym = lookup(s, h, dso); > + > + alg = dso->hashalg; > + if (!computed[alg]) { > + if (alg == SYSV_HASH_ALG_IDX) { > + h[alg] = sysv_hash(s); > + sym = sysv_lookup(s, h[alg], dso); > + } > + else { > + h[alg] = gnu_hash(s); > + sym = gnu_lookup(s, h[alg], dso); > + } > + computed[alg] = 1; > + } else { > + if (alg == SYSV_HASH_ALG_IDX) > + sym = sysv_lookup(s, h[alg], dso); > + else > + sym = gnu_lookup(s, h[alg], dso); > + } instead of arrays i'd write alg = dso->hashalg; if (alg == SYSV_HASH) { if (sysv_ok) { ... sysv_ok = 1; } sym = sysv_lookup(s, sysv_h, dso); } else { } since there are many ifs anyway the table approach is nicer when all data and functions are in a table: if (!ok[alg]) { h[alg] = hash[alg](s); ok[alg] = 1; } sym = lookup[alg](s, h[alg], dso); > + p->hashalg = SYSV_HASH_ALG_IDX; > p->strings = (void *)(p->base + dyn[DT_STRTAB]); > + for (; v[0]; v+=2) if (v[0] == DT_GNU_HASH) { > + p->hashtab = (void *)(p->base + v[1]); > + p->hashalg = GNU_HASH_ALG_IDX; > + } so it seems gnu hash is used whenever it's present i'm not sure if that's the right default.. another possibility is to have a plain find_sym function which is simple and only supports sysv hash and whenever it encounters a lib that has no sysv hash in it a find_sym_gnu is called that does the hard work (so using gnu only libs is penalized, i don't know how common that case is though)