* ldso : gnu hash support.
@ 2012-08-06 22:49 boris brezillon
2012-08-06 23:09 ` John Spencer
0 siblings, 1 reply; 3+ messages in thread
From: boris brezillon @ 2012-08-06 22:49 UTC (permalink / raw)
To: musl
Hi,
This patch adds support for gnu hash section (this was requested in a
previous mail : hm, libc crashes loading libc).
I've done some tests and it seems to work (algorithm described here :
https://blogs.oracle.com/ali/entry/gnu_hash_elf_sections).
BTW, I really like this new libc (clean code, light and efficient
implementation).
I plan to use it in my future projects and I'd like to contribute to
it's development.
Let me know if you need some help.
Regards,
Boris Brezillon
---
src/ldso/dynlink.c | 125 +++++++++++++++++++++++++++++++++++++++++++++++-----
1 file changed, 115 insertions(+), 10 deletions(-)
diff --git a/src/ldso/dynlink.c b/src/ldso/dynlink.c
index 31ef684..0c8d75a 100644
--- a/src/ldso/dynlink.c
+++ b/src/ldso/dynlink.c
@@ -52,6 +52,7 @@ struct dso {
int refcnt;
Sym *syms;
+ uint32_t hashalg;
uint32_t *hashtab;
char *strings;
unsigned char *map;
@@ -66,6 +67,15 @@ struct dso {
char buf[];
};
+struct hash_algo {
+ uint32_t (*hash) (const char *);
+ Sym *(*lookup) (const char *s, uint32_t h, struct dso *dso);
+};
+
+#define SYSV_HASH_ALG_IDX 0
+#define GNU_HASH_ALG_IDX 1
+#define HASH_ALG_CNT 2
+
#include "reloc.h"
void __init_ssp(size_t *);
@@ -94,7 +104,7 @@ static void decode_vec(size_t *v, size_t *a, size_t cnt)
}
}
-static uint32_t hash(const char *s0)
+static uint32_t sysv_hash(const char *s0)
{
const unsigned char *s = (void *)s0;
uint_fast32_t h = 0;
@@ -105,7 +115,16 @@ static uint32_t hash(const char *s0)
return h & 0xfffffff;
}
-static Sym *lookup(const char *s, uint32_t h, struct dso *dso)
+static uint32_t gnu_hash (const char *s0)
+{
+ const unsigned char *s = (void *)s0;
+ uint_fast32_t h = 5381;
+ for (unsigned char c = *s; c != '\0'; c = *++s)
+ h = h * 33 + c;
+ return h & 0xffffffff;
+}
+
+static Sym *sysv_lookup(const char *s, uint32_t h, struct dso *dso)
{
size_t i;
Sym *syms = dso->syms;
@@ -118,20 +137,86 @@ static Sym *lookup(const char *s, uint32_t h,
struct dso *dso)
return 0;
}
+static Sym *gnu_lookup(const char *s, uint32_t h1, struct dso *dso)
+{
+ size_t i;
+ Sym *sym;
+ char *strings = dso->strings;
+ uint32_t *hashtab = dso->hashtab;
+ uint32_t nbuckets = hashtab[0];
+ size_t *maskwords = (size_t *)(hashtab + 4);
+ uint32_t *buckets = hashtab + 4 + (hashtab[2] * (sizeof(size_t) /
sizeof(uint32_t)));
+ uint32_t symndx = hashtab[1];
+ Sym *syms = dso->syms;
+ uint32_t shift2 = hashtab[3];
+ uint32_t h2 = h1 >> shift2;
+ uint32_t *hashvals = buckets + nbuckets;
+ uint32_t *hashval;
+ size_t c = sizeof(size_t) * 8;
+ size_t n = (h1 / c) & (hashtab[2] - 1);
+ size_t bitmask = (1 << (h1 % c)) | (1 << (h2 % c));
+
+ if ((maskwords[n] & bitmask) != bitmask)
+ return 0;
+
+ n = buckets[h1 % nbuckets];
+ if (!n)
+ return 0;
+
+ sym = syms + n;
+ hashval = hashvals + n - symndx;
+
+ for (h1 &= ~1; 1; sym++) {
+ h2 = *hashval++;
+ if ((h1 == (h2 & ~1)) && !strcmp(s, strings + sym->st_name))
+ return sym;
+
+ if (h2 & 1)
+ break;
+ }
+
+ return 0;
+}
+
+static struct hash_algo hashalgs[] = {
+ {
+ .hash = sysv_hash,
+ .lookup = sysv_lookup,
+ },
+ {
+ .hash = gnu_hash,
+ .lookup = gnu_lookup,
+ },
+};
+
+
#define OK_TYPES (1<<STT_NOTYPE | 1<<STT_OBJECT | 1<<STT_FUNC | 1<<STT_COMMON)
#define OK_BINDS (1<<STB_GLOBAL | 1<<STB_WEAK)
static void *find_sym(struct dso *dso, const char *s, int need_def)
{
- uint32_t h = hash(s);
void *def = 0;
- if (h==0x6b366be && !strcmp(s, "dlopen")) rtld_used = 1;
- if (h==0x6b3afd && !strcmp(s, "dlsym")) rtld_used = 1;
- if (h==0x595a4cc && !strcmp(s, "__stack_chk_fail")) ssp_used = 1;
+ uint32_t computed[HASH_ALG_CNT / 32 + 1];
+ uint32_t hashes[HASH_ALG_CNT];
+ memset (computed, 0, sizeof (computed));
+ if (!strcmp(s, "dlopen")) rtld_used = 1;
+ if (!strcmp(s, "dlsym")) rtld_used = 1;
+ if (!strcmp(s, "__stack_chk_fail")) ssp_used = 1;
for (; dso; dso=dso->next) {
Sym *sym;
+ uint32_t h;
if (!dso->global) continue;
- sym = lookup(s, h, dso);
+
+ if (!(computed[dso->hashalg / 32] & (1 << (dso->hashalg % 32)))) {
+ h = hashalgs[dso->hashalg].hash(s);
+ hashes[dso->hashalg] = h;
+ computed[dso->hashalg / 32] |= (1 << (dso->hashalg % 32));
+ }
+ else {
+ h = hashes[dso->hashalg];
+ }
+
+ sym = hashalgs[dso->hashalg].lookup(s, h, dso);
if (sym && (!need_def || sym->st_shndx) && sym->st_value
&& (1<<(sym->st_info&0xf) & OK_TYPES)
&& (1<<(sym->st_info>>4) & OK_BINDS)) {
@@ -320,11 +405,17 @@ static int path_open(const char *name, const
char *search, char *buf, size_t buf
static void decode_dyn(struct dso *p)
{
+ size_t *v = p->dynv;
size_t dyn[DYN_CNT] = {0};
decode_vec(p->dynv, dyn, DYN_CNT);
p->syms = (void *)(p->base + dyn[DT_SYMTAB]);
p->hashtab = (void *)(p->base + dyn[DT_HASH]);
+ 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;
+ }
}
static struct dso *load_library(const char *name)
@@ -786,6 +877,9 @@ static void *do_dlsym(struct dso *p, const char
*s, void *ra)
size_t i;
uint32_t h;
Sym *sym;
+ uint32_t computed[HASH_ALG_CNT / 32 + 1];
+ uint32_t hashes[HASH_ALG_CNT];
+
if (p == RTLD_NEXT) {
for (p=head; p && (unsigned char *)ra-p->map>p->map_len; p=p->next);
if (!p) p=head;
@@ -798,12 +892,23 @@ static void *do_dlsym(struct dso *p, const char
*s, void *ra)
if (!res) goto failed;
return res;
}
- h = hash(s);
- sym = lookup(s, h, p);
+ memset (computed, 0, sizeof (computed));
+ h = hashalgs[p->hashalg].hash(s);
+ computed[p->hashalg / 32] |= (1 << (p->hashalg % 32));
+ hashes[p->hashalg] = h;
+ sym = hashalgs[p->hashalg].lookup(s, h, p);
if (sym && sym->st_value && (1<<(sym->st_info&0xf) & OK_TYPES))
return p->base + sym->st_value;
if (p->deps) for (i=0; p->deps[i]; i++) {
- sym = lookup(s, h, p);
+ if (!(computed[p->deps[i]->hashalg / 32] & (1 <<
(p->deps[i]->hashalg % 32)))) {
+ h = hashalgs[p->deps[i]->hashalg].hash(s);
+ hashes[p->deps[i]->hashalg] = h;
+ computed[p->deps[i]->hashalg / 32] |= (1 << (p->deps[i]->hashalg % 32));
+ }
+ else {
+ h = hashes[p->deps[i]->hashalg];
+ }
+ sym = hashalgs[p->deps[i]->hashalg].lookup(s, h, p->deps[i]);
if (sym && sym->st_value && (1<<(sym->st_info&0xf) & OK_TYPES))
return p->deps[i]->base + sym->st_value;
}
--
1.7.9.5
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: ldso : gnu hash support.
2012-08-06 23:09 ` John Spencer
@ 2012-08-06 23:08 ` boris brezillon
0 siblings, 0 replies; 3+ messages in thread
From: boris brezillon @ 2012-08-06 23:08 UTC (permalink / raw)
To: musl
[-- Attachment #1: Type: text/plain, Size: 270 bytes --]
Sure
2012/8/7 John Spencer <maillist-musl@barfooze.de>:
> On 08/07/2012 12:49 AM, boris brezillon wrote:
>>
>> Hi,
>>
>> This patch adds support for gnu hash section
>
>
> the indentation seems to be messed up.. can you resend with the patch as a
> file attachment ?
>
[-- Attachment #2: 0001-Add-gnu-hash-support.patch --]
[-- Type: application/octet-stream, Size: 6101 bytes --]
From 28edcc77f5096d17be29da1be1c3972c2356d269 Mon Sep 17 00:00:00 2001
From: Boris BREZILLON <b.brezillon@overkiz.com>
Date: Mon, 6 Aug 2012 20:17:01 +0200
Subject: [PATCH] Add gnu hash support.
---
src/ldso/dynlink.c | 125 +++++++++++++++++++++++++++++++++++++++++++++++-----
1 file changed, 115 insertions(+), 10 deletions(-)
diff --git a/src/ldso/dynlink.c b/src/ldso/dynlink.c
index 31ef684..0c8d75a 100644
--- a/src/ldso/dynlink.c
+++ b/src/ldso/dynlink.c
@@ -52,6 +52,7 @@ struct dso {
int refcnt;
Sym *syms;
+ uint32_t hashalg;
uint32_t *hashtab;
char *strings;
unsigned char *map;
@@ -66,6 +67,15 @@ struct dso {
char buf[];
};
+struct hash_algo {
+ uint32_t (*hash) (const char *);
+ Sym *(*lookup) (const char *s, uint32_t h, struct dso *dso);
+};
+
+#define SYSV_HASH_ALG_IDX 0
+#define GNU_HASH_ALG_IDX 1
+#define HASH_ALG_CNT 2
+
#include "reloc.h"
void __init_ssp(size_t *);
@@ -94,7 +104,7 @@ static void decode_vec(size_t *v, size_t *a, size_t cnt)
}
}
-static uint32_t hash(const char *s0)
+static uint32_t sysv_hash(const char *s0)
{
const unsigned char *s = (void *)s0;
uint_fast32_t h = 0;
@@ -105,7 +115,16 @@ static uint32_t hash(const char *s0)
return h & 0xfffffff;
}
-static Sym *lookup(const char *s, uint32_t h, struct dso *dso)
+static uint32_t gnu_hash (const char *s0)
+{
+ const unsigned char *s = (void *)s0;
+ uint_fast32_t h = 5381;
+ for (unsigned char c = *s; c != '\0'; c = *++s)
+ h = h * 33 + c;
+ return h & 0xffffffff;
+}
+
+static Sym *sysv_lookup(const char *s, uint32_t h, struct dso *dso)
{
size_t i;
Sym *syms = dso->syms;
@@ -118,20 +137,86 @@ static Sym *lookup(const char *s, uint32_t h, struct dso *dso)
return 0;
}
+static Sym *gnu_lookup(const char *s, uint32_t h1, struct dso *dso)
+{
+ size_t i;
+ Sym *sym;
+ char *strings = dso->strings;
+ uint32_t *hashtab = dso->hashtab;
+ uint32_t nbuckets = hashtab[0];
+ size_t *maskwords = (size_t *)(hashtab + 4);
+ uint32_t *buckets = hashtab + 4 + (hashtab[2] * (sizeof(size_t) / sizeof(uint32_t)));
+ uint32_t symndx = hashtab[1];
+ Sym *syms = dso->syms;
+ uint32_t shift2 = hashtab[3];
+ uint32_t h2 = h1 >> shift2;
+ uint32_t *hashvals = buckets + nbuckets;
+ uint32_t *hashval;
+ size_t c = sizeof(size_t) * 8;
+ size_t n = (h1 / c) & (hashtab[2] - 1);
+ size_t bitmask = (1 << (h1 % c)) | (1 << (h2 % c));
+
+ if ((maskwords[n] & bitmask) != bitmask)
+ return 0;
+
+ n = buckets[h1 % nbuckets];
+ if (!n)
+ return 0;
+
+ sym = syms + n;
+ hashval = hashvals + n - symndx;
+
+ for (h1 &= ~1; 1; sym++) {
+ h2 = *hashval++;
+ if ((h1 == (h2 & ~1)) && !strcmp(s, strings + sym->st_name))
+ return sym;
+
+ if (h2 & 1)
+ break;
+ }
+
+ return 0;
+}
+
+static struct hash_algo hashalgs[] = {
+ {
+ .hash = sysv_hash,
+ .lookup = sysv_lookup,
+ },
+ {
+ .hash = gnu_hash,
+ .lookup = gnu_lookup,
+ },
+};
+
+
#define OK_TYPES (1<<STT_NOTYPE | 1<<STT_OBJECT | 1<<STT_FUNC | 1<<STT_COMMON)
#define OK_BINDS (1<<STB_GLOBAL | 1<<STB_WEAK)
static void *find_sym(struct dso *dso, const char *s, int need_def)
{
- uint32_t h = hash(s);
void *def = 0;
- if (h==0x6b366be && !strcmp(s, "dlopen")) rtld_used = 1;
- if (h==0x6b3afd && !strcmp(s, "dlsym")) rtld_used = 1;
- if (h==0x595a4cc && !strcmp(s, "__stack_chk_fail")) ssp_used = 1;
+ uint32_t computed[HASH_ALG_CNT / 32 + 1];
+ uint32_t hashes[HASH_ALG_CNT];
+ memset (computed, 0, sizeof (computed));
+ if (!strcmp(s, "dlopen")) rtld_used = 1;
+ if (!strcmp(s, "dlsym")) rtld_used = 1;
+ if (!strcmp(s, "__stack_chk_fail")) ssp_used = 1;
for (; dso; dso=dso->next) {
Sym *sym;
+ uint32_t h;
if (!dso->global) continue;
- sym = lookup(s, h, dso);
+
+ if (!(computed[dso->hashalg / 32] & (1 << (dso->hashalg % 32)))) {
+ h = hashalgs[dso->hashalg].hash(s);
+ hashes[dso->hashalg] = h;
+ computed[dso->hashalg / 32] |= (1 << (dso->hashalg % 32));
+ }
+ else {
+ h = hashes[dso->hashalg];
+ }
+
+ sym = hashalgs[dso->hashalg].lookup(s, h, dso);
if (sym && (!need_def || sym->st_shndx) && sym->st_value
&& (1<<(sym->st_info&0xf) & OK_TYPES)
&& (1<<(sym->st_info>>4) & OK_BINDS)) {
@@ -320,11 +405,17 @@ static int path_open(const char *name, const char *search, char *buf, size_t buf
static void decode_dyn(struct dso *p)
{
+ size_t *v = p->dynv;
size_t dyn[DYN_CNT] = {0};
decode_vec(p->dynv, dyn, DYN_CNT);
p->syms = (void *)(p->base + dyn[DT_SYMTAB]);
p->hashtab = (void *)(p->base + dyn[DT_HASH]);
+ 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;
+ }
}
static struct dso *load_library(const char *name)
@@ -786,6 +877,9 @@ static void *do_dlsym(struct dso *p, const char *s, void *ra)
size_t i;
uint32_t h;
Sym *sym;
+ uint32_t computed[HASH_ALG_CNT / 32 + 1];
+ uint32_t hashes[HASH_ALG_CNT];
+
if (p == RTLD_NEXT) {
for (p=head; p && (unsigned char *)ra-p->map>p->map_len; p=p->next);
if (!p) p=head;
@@ -798,12 +892,23 @@ static void *do_dlsym(struct dso *p, const char *s, void *ra)
if (!res) goto failed;
return res;
}
- h = hash(s);
- sym = lookup(s, h, p);
+ memset (computed, 0, sizeof (computed));
+ h = hashalgs[p->hashalg].hash(s);
+ computed[p->hashalg / 32] |= (1 << (p->hashalg % 32));
+ hashes[p->hashalg] = h;
+ sym = hashalgs[p->hashalg].lookup(s, h, p);
if (sym && sym->st_value && (1<<(sym->st_info&0xf) & OK_TYPES))
return p->base + sym->st_value;
if (p->deps) for (i=0; p->deps[i]; i++) {
- sym = lookup(s, h, p);
+ if (!(computed[p->deps[i]->hashalg / 32] & (1 << (p->deps[i]->hashalg % 32)))) {
+ h = hashalgs[p->deps[i]->hashalg].hash(s);
+ hashes[p->deps[i]->hashalg] = h;
+ computed[p->deps[i]->hashalg / 32] |= (1 << (p->deps[i]->hashalg % 32));
+ }
+ else {
+ h = hashes[p->deps[i]->hashalg];
+ }
+ sym = hashalgs[p->deps[i]->hashalg].lookup(s, h, p->deps[i]);
if (sym && sym->st_value && (1<<(sym->st_info&0xf) & OK_TYPES))
return p->deps[i]->base + sym->st_value;
}
--
1.7.9.5
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: ldso : gnu hash support.
2012-08-06 22:49 ldso : gnu hash support boris brezillon
@ 2012-08-06 23:09 ` John Spencer
2012-08-06 23:08 ` boris brezillon
0 siblings, 1 reply; 3+ messages in thread
From: John Spencer @ 2012-08-06 23:09 UTC (permalink / raw)
To: musl
On 08/07/2012 12:49 AM, boris brezillon wrote:
> Hi,
>
> This patch adds support for gnu hash section
the indentation seems to be messed up.. can you resend with the patch as
a file attachment ?
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2012-08-06 23:09 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-08-06 22:49 ldso : gnu hash support boris brezillon
2012-08-06 23:09 ` John Spencer
2012-08-06 23:08 ` boris brezillon
Code repositories for project(s) associated with this public inbox
https://git.vuxu.org/mirror/musl/
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).