![]() |
|
Message-ID: <20250822115732.818628-1-hulata@sysart.tech> Date: Fri, 22 Aug 2025 13:57:32 +0200 From: tombo <hulata@...art.tech> To: musl@...ts.openwall.com Cc: tombo <hulata@...art.tech> Subject: [PATCH v2] vdso: add support for GNU hash tables The previous submission had formatting issues, sorry. On some kernels (e.g. AWS Ubuntu's Graviton official AMIs) the arm64 vDSO exports symbols with DT_GNU_HASH but omits DT_HASH. musl's __vdsosym resolver only understands SysV hash, so vDSO symbols fail to resolve and clock_gettime falls back to syscalls. This patch adds a minimal GNU hash lookup implementation to __vdsosym, fixing vDSO usage on affected systems. --- src/internal/vdso.c | 75 +++++++++++++++++++++++++++++++++++++++------ 1 file changed, 66 insertions(+), 9 deletions(-) diff --git a/src/internal/vdso.c b/src/internal/vdso.c index d46d3228..8fa19526 100644 --- a/src/internal/vdso.c +++ b/src/internal/vdso.c @@ -40,6 +40,53 @@ static int checkver(Verdef *def, int vsym, const char *vername, char *strings) #define OK_TYPES (1<<STT_NOTYPE | 1<<STT_OBJECT | 1<<STT_FUNC | 1<<STT_COMMON) #define OK_BINDS (1<<STB_GLOBAL | 1<<STB_WEAK | 1<<STB_GNU_UNIQUE) +static uint32_t gnu_hash(const char *s0) +{ + const unsigned char *s = (const void *)s0; + uint_fast32_t h = 5381; + for (; *s; s++) h += h*32 + *s; + return h; +} + +static Sym *gnu_lookup(uint32_t h1, uint32_t *hashtab, + Sym *syms, char *strings, uint16_t *versym, + Verdef *verdef, const char *vername, const char *s) +{ + uint32_t nbuckets = hashtab[0]; + uint32_t symoffset = hashtab[1]; + uint32_t *buckets = hashtab + 4 + hashtab[2]*(sizeof(size_t)/4); + uint32_t i = buckets[h1 % nbuckets]; + if (!i) return 0; + + uint32_t *hashval = buckets + nbuckets + (i - symoffset); + for (h1 |= 1; ; i++) { + uint32_t h2 = *hashval++; + if ((h1 == (h2|1)) + && (1<<(syms[i].st_info&0xf) & OK_TYPES) + && (1<<(syms[i].st_info>>4) & OK_BINDS) + && syms[i].st_shndx + && !strcmp(s, strings + syms[i].st_name) + && (!versym || !vername || checkver(verdef, versym[i], vername, strings))) + return syms+i; + if (h2 & 1) break; + } + return 0; +} + +static Sym *gnu_lookup_filtered(uint32_t h1, uint32_t *hashtab, + Sym *syms, char *strings, uint16_t *versym, + Verdef *verdef, const char *vername, const char *s) +{ + const size_t *bloomwords = (const void *)(hashtab+4); + size_t bloom_sz = hashtab[2]; + size_t f = bloomwords[(h1 / (8*sizeof(size_t))) & (bloom_sz - 1)]; + size_t fmask = 1ul << (h1 % (8*sizeof(size_t))); + if (!(f & fmask)) return 0; + f >>= (h1 >> hashtab[3]) % (8 * sizeof f); + if (!(f & 1)) return 0; + return gnu_lookup(h1, hashtab, syms, strings, versym, verdef, vername, s); +} + void *__vdsosym(const char *vername, const char *name) { size_t i; @@ -60,6 +107,7 @@ void *__vdsosym(const char *vername, const char *name) char *strings = 0; Sym *syms = 0; Elf_Symndx *hashtab = 0; + uint32_t *ghashtab = 0; /* GNU hash */ uint16_t *versym = 0; Verdef *verdef = 0; @@ -69,22 +117,31 @@ void *__vdsosym(const char *vername, const char *name) case DT_STRTAB: strings = p; break; case DT_SYMTAB: syms = p; break; case DT_HASH: hashtab = p; break; + case DT_GNU_HASH: ghashtab = p; break; case DT_VERSYM: versym = p; break; case DT_VERDEF: verdef = p; break; } } - if (!strings || !syms || !hashtab) return 0; + if (!strings || !syms) return 0; if (!verdef) versym = 0; - for (i=0; i<hashtab[1]; i++) { - if (!(1<<(syms[i].st_info&0xf) & OK_TYPES)) continue; - if (!(1<<(syms[i].st_info>>4) & OK_BINDS)) continue; - if (!syms[i].st_shndx) continue; - if (strcmp(name, strings+syms[i].st_name)) continue; - if (versym && !checkver(verdef, versym[i], vername, strings)) - continue; - return (void *)(base + syms[i].st_value); + if (ghashtab) { + uint32_t h = gnu_hash(name); + Sym *s = gnu_lookup_filtered(h, ghashtab, syms, strings, versym, verdef, vername, name); + if (s) return (void *)(base + s->st_value); + } + + if (hashtab) { + for (i=0; i<hashtab[1]; i++) { + if (!(1<<(syms[i].st_info&0xf) & OK_TYPES)) continue; + if (!(1<<(syms[i].st_info>>4) & OK_BINDS)) continue; + if (!syms[i].st_shndx) continue; + if (strcmp(name, strings+syms[i].st_name)) continue; + if (versym && !checkver(verdef, versym[i], vername, strings)) + continue; + return (void *)(base + syms[i].st_value); + } } return 0; --
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.