![]() |
|
Message-ID: <CAORiPTPcHA0n-iT7Hk9tpCHknqcPCGnR8GnptxD9XjwGC2FD3w@mail.gmail.com>
Date: Fri, 22 Aug 2025 11:12:47 +0200
From: Tomáš Hulata <hulata@...art.tech>
To: musl@...ts.openwall.com
Subject: [PATCH] vdso: add support for GNU hash tables
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;
--
Best Regardas
Tomáš Hulata
*[ SysArt, **Pixel Federation ]*
Content of type "text/html" skipped
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.