Message ID | 20240815032614.2747224-1-maskray@google.com (mailing list archive) |
---|---|
State | New |
Headers | show |
Series | selftests/vDSO: support DT_GNU_HASH | expand |
On Wed, 2024-08-14 at 20:26 -0700, Fangrui Song wrote: > glibc added support for DT_GNU_HASH in 2006 and DT_HASH has been > obsoleted for more than one decade in many Linux distributions. > > Many vDSOs support DT_GNU_HASH. This patch adds selftests support. > > Signed-off-by: Fangrui Song <maskray@google.com> Tested-by: Xi Ruoyao <xry111@xry111.site> > --- > tools/testing/selftests/vDSO/parse_vdso.c | 105 ++++++++++++++++------ > 1 file changed, 79 insertions(+), 26 deletions(-) > > diff --git a/tools/testing/selftests/vDSO/parse_vdso.c b/tools/testing/selftests/vDSO/parse_vdso.c > index 4ae417372e9e..35cb545da13e 100644 > --- a/tools/testing/selftests/vDSO/parse_vdso.c > +++ b/tools/testing/selftests/vDSO/parse_vdso.c > @@ -47,6 +47,7 @@ static struct vdso_info > /* Symbol table */ > ELF(Sym) *symtab; > const char *symstrings; > + ELF(Word) *gnu_hash; > ELF(Word) *bucket, *chain; > ELF(Word) nbucket, nchain; > > @@ -75,6 +76,16 @@ static unsigned long elf_hash(const char *name) > return h; > } > > +static uint32_t gnu_hash(const char *name) > +{ > + const unsigned char *s = (void *)name; > + uint32_t h = 5381; > + > + for (; *s; s++) > + h += h * 32 + *s; > + return h; > +} > + > void vdso_init_from_sysinfo_ehdr(uintptr_t base) > { > size_t i; > @@ -117,6 +128,7 @@ void vdso_init_from_sysinfo_ehdr(uintptr_t base) > */ > ELF(Word) *hash = 0; > vdso_info.symstrings = 0; > + vdso_info.gnu_hash = 0; > vdso_info.symtab = 0; > vdso_info.versym = 0; > vdso_info.verdef = 0; > @@ -137,6 +149,11 @@ void vdso_init_from_sysinfo_ehdr(uintptr_t base) > ((uintptr_t)dyn[i].d_un.d_ptr > + vdso_info.load_offset); > break; > + case DT_GNU_HASH: > + vdso_info.gnu_hash = > + (ELF(Word) *)((uintptr_t)dyn[i].d_un.d_ptr + > + vdso_info.load_offset); > + break; > case DT_VERSYM: > vdso_info.versym = (ELF(Versym) *) > ((uintptr_t)dyn[i].d_un.d_ptr > @@ -149,17 +166,26 @@ void vdso_init_from_sysinfo_ehdr(uintptr_t base) > break; > } > } > - if (!vdso_info.symstrings || !vdso_info.symtab || !hash) > + if (!vdso_info.symstrings || !vdso_info.symtab || > + (!hash && !vdso_info.gnu_hash)) > return; /* Failed */ > > if (!vdso_info.verdef) > vdso_info.versym = 0; > > /* Parse the hash table header. */ > - vdso_info.nbucket = hash[0]; > - vdso_info.nchain = hash[1]; > - vdso_info.bucket = &hash[2]; > - vdso_info.chain = &hash[vdso_info.nbucket + 2]; > + if (vdso_info.gnu_hash) { > + vdso_info.nbucket = vdso_info.gnu_hash[0]; > + /* The bucket array is located after the header (4 uint32) and the bloom > + filter (size_t array of gnu_hash[2] elements). */ > + vdso_info.bucket = vdso_info.gnu_hash + 4 + > + sizeof(size_t) / 4 * vdso_info.gnu_hash[2]; > + } else { > + vdso_info.nbucket = hash[0]; > + vdso_info.nchain = hash[1]; > + vdso_info.bucket = &hash[2]; > + vdso_info.chain = &hash[vdso_info.nbucket + 2]; > + } > > /* That's all we need. */ > vdso_info.valid = true; > @@ -203,6 +229,26 @@ static bool vdso_match_version(ELF(Versym) ver, > && !strcmp(name, vdso_info.symstrings + aux->vda_name); > } > > +static bool check_sym(ELF(Sym) *sym, ELF(Word) i, const char *name, > + const char *version, unsigned long ver_hash) > +{ > + /* Check for a defined global or weak function w/ right name. */ > + if (ELF64_ST_TYPE(sym->st_info) != STT_FUNC) > + return false; > + if (ELF64_ST_BIND(sym->st_info) != STB_GLOBAL && > + ELF64_ST_BIND(sym->st_info) != STB_WEAK) > + return false; > + if (strcmp(name, vdso_info.symstrings + sym->st_name)) > + return false; > + > + /* Check symbol version. */ > + if (vdso_info.versym && > + !vdso_match_version(vdso_info.versym[i], version, ver_hash)) > + return false; > + > + return true; > +} > + > void *vdso_sym(const char *version, const char *name) > { > unsigned long ver_hash; > @@ -210,29 +256,36 @@ void *vdso_sym(const char *version, const char *name) > return 0; > > ver_hash = elf_hash(version); > - ELF(Word) chain = vdso_info.bucket[elf_hash(name) % vdso_info.nbucket]; > + ELF(Word) i; > > - for (; chain != STN_UNDEF; chain = vdso_info.chain[chain]) { > - ELF(Sym) *sym = &vdso_info.symtab[chain]; > + if (vdso_info.gnu_hash) { > + uint32_t h1 = gnu_hash(name), h2, *hashval; > > - /* Check for a defined global or weak function w/ right name. */ > - if (ELF64_ST_TYPE(sym->st_info) != STT_FUNC) > - continue; > - if (ELF64_ST_BIND(sym->st_info) != STB_GLOBAL && > - ELF64_ST_BIND(sym->st_info) != STB_WEAK) > - continue; > - if (sym->st_shndx == SHN_UNDEF) > - continue; > - if (strcmp(name, vdso_info.symstrings + sym->st_name)) > - continue; > - > - /* Check symbol version. */ > - if (vdso_info.versym > - && !vdso_match_version(vdso_info.versym[chain], > - version, ver_hash)) > - continue; > - > - return (void *)(vdso_info.load_offset + sym->st_value); > + i = vdso_info.bucket[h1 % vdso_info.nbucket]; > + if (i == 0) > + return 0; > + h1 |= 1; > + hashval = vdso_info.bucket + vdso_info.nbucket + > + (i - vdso_info.gnu_hash[1]); > + for (;; i++) { > + ELF(Sym) *sym = &vdso_info.symtab[i]; > + h2 = *hashval++; > + if (h1 == (h2 | 1) && > + check_sym(sym, i, name, version, ver_hash)) > + return (void *)(vdso_info.load_offset + > + sym->st_value); > + if (h2 & 1) > + break; > + } > + } else { > + i = vdso_info.bucket[elf_hash(name) % vdso_info.nbucket]; > + for (; i; i = vdso_info.chain[i]) { > + ELF(Sym) *sym = &vdso_info.symtab[i]; > + if (sym->st_shndx != SHN_UNDEF && > + check_sym(sym, i, name, version, ver_hash)) > + return (void *)(vdso_info.load_offset + > + sym->st_value); > + } > } > > return 0;
On Wed, 2024-08-14 at 20:26 -0700, Fangrui Song wrote: > glibc added support for DT_GNU_HASH in 2006 and DT_HASH has been > obsoleted for more than one decade in many Linux distributions. > > Many vDSOs support DT_GNU_HASH. This patch adds selftests support. > > Signed-off-by: Fangrui Song <maskray@google.com> > --- Ping. Some context: I'd change LoongArch vDSO to use the toolchain default instead of forcing DT_HASH (note that LoongArch is launched decades after all major distros switched to DT_GNU_HASH), but without the selftest support we'll lose test coverage. And now ARM64 has already lost test coverage after commit 48f6430505c0. > tools/testing/selftests/vDSO/parse_vdso.c | 105 ++++++++++++++++----- > - > 1 file changed, 79 insertions(+), 26 deletions(-) > > diff --git a/tools/testing/selftests/vDSO/parse_vdso.c > b/tools/testing/selftests/vDSO/parse_vdso.c > index 4ae417372e9e..35cb545da13e 100644 > --- a/tools/testing/selftests/vDSO/parse_vdso.c > +++ b/tools/testing/selftests/vDSO/parse_vdso.c > @@ -47,6 +47,7 @@ static struct vdso_info > /* Symbol table */ > ELF(Sym) *symtab; > const char *symstrings; > + ELF(Word) *gnu_hash; > ELF(Word) *bucket, *chain; > ELF(Word) nbucket, nchain; > > @@ -75,6 +76,16 @@ static unsigned long elf_hash(const char *name) > return h; > } > > +static uint32_t gnu_hash(const char *name) > +{ > + const unsigned char *s = (void *)name; > + uint32_t h = 5381; > + > + for (; *s; s++) > + h += h * 32 + *s; > + return h; > +} > + > void vdso_init_from_sysinfo_ehdr(uintptr_t base) > { > size_t i; > @@ -117,6 +128,7 @@ void vdso_init_from_sysinfo_ehdr(uintptr_t base) > */ > ELF(Word) *hash = 0; > vdso_info.symstrings = 0; > + vdso_info.gnu_hash = 0; > vdso_info.symtab = 0; > vdso_info.versym = 0; > vdso_info.verdef = 0; > @@ -137,6 +149,11 @@ void vdso_init_from_sysinfo_ehdr(uintptr_t base) > ((uintptr_t)dyn[i].d_un.d_ptr > + vdso_info.load_offset); > break; > + case DT_GNU_HASH: > + vdso_info.gnu_hash = > + (ELF(Word) > *)((uintptr_t)dyn[i].d_un.d_ptr + > + vdso_info.load_offset); > + break; > case DT_VERSYM: > vdso_info.versym = (ELF(Versym) *) > ((uintptr_t)dyn[i].d_un.d_ptr > @@ -149,17 +166,26 @@ void vdso_init_from_sysinfo_ehdr(uintptr_t base) > break; > } > } > - if (!vdso_info.symstrings || !vdso_info.symtab || !hash) > + if (!vdso_info.symstrings || !vdso_info.symtab || > + (!hash && !vdso_info.gnu_hash)) > return; /* Failed */ > > if (!vdso_info.verdef) > vdso_info.versym = 0; > > /* Parse the hash table header. */ > - vdso_info.nbucket = hash[0]; > - vdso_info.nchain = hash[1]; > - vdso_info.bucket = &hash[2]; > - vdso_info.chain = &hash[vdso_info.nbucket + 2]; > + if (vdso_info.gnu_hash) { > + vdso_info.nbucket = vdso_info.gnu_hash[0]; > + /* The bucket array is located after the header (4 > uint32) and the bloom > + filter (size_t array of gnu_hash[2] elements). */ > + vdso_info.bucket = vdso_info.gnu_hash + 4 + > + sizeof(size_t) / 4 * > vdso_info.gnu_hash[2]; > + } else { > + vdso_info.nbucket = hash[0]; > + vdso_info.nchain = hash[1]; > + vdso_info.bucket = &hash[2]; > + vdso_info.chain = &hash[vdso_info.nbucket + 2]; > + } > > /* That's all we need. */ > vdso_info.valid = true; > @@ -203,6 +229,26 @@ static bool vdso_match_version(ELF(Versym) ver, > && !strcmp(name, vdso_info.symstrings + aux- > >vda_name); > } > > +static bool check_sym(ELF(Sym) *sym, ELF(Word) i, const char *name, > + const char *version, unsigned long ver_hash) > +{ > + /* Check for a defined global or weak function w/ right name. > */ > + if (ELF64_ST_TYPE(sym->st_info) != STT_FUNC) > + return false; > + if (ELF64_ST_BIND(sym->st_info) != STB_GLOBAL && > + ELF64_ST_BIND(sym->st_info) != STB_WEAK) > + return false; > + if (strcmp(name, vdso_info.symstrings + sym->st_name)) > + return false; > + > + /* Check symbol version. */ > + if (vdso_info.versym && > + !vdso_match_version(vdso_info.versym[i], version, > ver_hash)) > + return false; > + > + return true; > +} > + > void *vdso_sym(const char *version, const char *name) > { > unsigned long ver_hash; > @@ -210,29 +256,36 @@ void *vdso_sym(const char *version, const char > *name) > return 0; > > ver_hash = elf_hash(version); > - ELF(Word) chain = vdso_info.bucket[elf_hash(name) % > vdso_info.nbucket]; > + ELF(Word) i; > > - for (; chain != STN_UNDEF; chain = vdso_info.chain[chain]) { > - ELF(Sym) *sym = &vdso_info.symtab[chain]; > + if (vdso_info.gnu_hash) { > + uint32_t h1 = gnu_hash(name), h2, *hashval; > > - /* Check for a defined global or weak function w/ > right name. */ > - if (ELF64_ST_TYPE(sym->st_info) != STT_FUNC) > - continue; > - if (ELF64_ST_BIND(sym->st_info) != STB_GLOBAL && > - ELF64_ST_BIND(sym->st_info) != STB_WEAK) > - continue; > - if (sym->st_shndx == SHN_UNDEF) > - continue; > - if (strcmp(name, vdso_info.symstrings + sym- > >st_name)) > - continue; > - > - /* Check symbol version. */ > - if (vdso_info.versym > - && !vdso_match_version(vdso_info.versym[chain], > - version, ver_hash)) > - continue; > - > - return (void *)(vdso_info.load_offset + sym- > >st_value); > + i = vdso_info.bucket[h1 % vdso_info.nbucket]; > + if (i == 0) > + return 0; > + h1 |= 1; > + hashval = vdso_info.bucket + vdso_info.nbucket + > + (i - vdso_info.gnu_hash[1]); > + for (;; i++) { > + ELF(Sym) *sym = &vdso_info.symtab[i]; > + h2 = *hashval++; > + if (h1 == (h2 | 1) && > + check_sym(sym, i, name, version, > ver_hash)) > + return (void *)(vdso_info.load_offset > + > + sym->st_value); > + if (h2 & 1) > + break; > + } > + } else { > + i = vdso_info.bucket[elf_hash(name) % > vdso_info.nbucket]; > + for (; i; i = vdso_info.chain[i]) { > + ELF(Sym) *sym = &vdso_info.symtab[i]; > + if (sym->st_shndx != SHN_UNDEF && > + check_sym(sym, i, name, version, > ver_hash)) > + return (void *)(vdso_info.load_offset > + > + sym->st_value); > + } > } > > return 0;
On 8/26/24 00:07, Xi Ruoyao wrote: > On Wed, 2024-08-14 at 20:26 -0700, Fangrui Song wrote: >> glibc added support for DT_GNU_HASH in 2006 and DT_HASH has been >> obsoleted for more than one decade in many Linux distributions. >> >> Many vDSOs support DT_GNU_HASH. This patch adds selftests support. >> >> Signed-off-by: Fangrui Song <maskray@google.com> >> --- > > Ping. > > Some context: I'd change LoongArch vDSO to use the toolchain default > instead of forcing DT_HASH (note that LoongArch is launched decades > after all major distros switched to DT_GNU_HASH), but without the > selftest support we'll lose test coverage. > > And now ARM64 has already lost test coverage after commit 48f6430505c0. > I am seeing several checkpatch errors - please fix them and send me v2. thanks, -- Shuah
On Tue, Aug 27, 2024 at 10:12 PM Shuah Khan <skhan@linuxfoundation.org> wrote: > > On 8/26/24 00:07, Xi Ruoyao wrote: > > On Wed, 2024-08-14 at 20:26 -0700, Fangrui Song wrote: > >> glibc added support for DT_GNU_HASH in 2006 and DT_HASH has been > >> obsoleted for more than one decade in many Linux distributions. > >> > >> Many vDSOs support DT_GNU_HASH. This patch adds selftests support. > >> > >> Signed-off-by: Fangrui Song <maskray@google.com> > >> --- > > > > Ping. > > > > Some context: I'd change LoongArch vDSO to use the toolchain default > > instead of forcing DT_HASH (note that LoongArch is launched decades > > after all major distros switched to DT_GNU_HASH), but without the > > selftest support we'll lose test coverage. > > > > And now ARM64 has already lost test coverage after commit 48f6430505c0. > > > > I am seeing several checkpatch errors - please fix them and send me v2. > > thanks, > -- Shuah > The applicable change is: --- i/tools/testing/selftests/vDSO/parse_vdso.c +++ w/tools/testing/selftests/vDSO/parse_vdso.c @@ -177,7 +177,7 @@ void vdso_init_from_sysinfo_ehdr(uintptr_t base) if (vdso_info.gnu_hash) { vdso_info.nbucket = vdso_info.gnu_hash[0]; /* The bucket array is located after the header (4 uint32) and the bloom - filter (size_t array of gnu_hash[2] elements). */ + * filter (size_t array of gnu_hash[2] elements). */ vdso_info.bucket = vdso_info.gnu_hash + 4 + sizeof(size_t) / 4 * vdso_info.gnu_hash[2]; } else { Other checkpatch.pl output is not actionable. `ELF(Sym) *sym` instead of `ELF(Sym) * sym` has the correct spacing (used in this file and elsewhere ElfW in the code base).
On 8/27/24 07:37, Fangrui Song wrote: > On Tue, Aug 27, 2024 at 10:12 PM Shuah Khan <skhan@linuxfoundation.org> wrote: >> >> On 8/26/24 00:07, Xi Ruoyao wrote: >>> On Wed, 2024-08-14 at 20:26 -0700, Fangrui Song wrote: >>>> glibc added support for DT_GNU_HASH in 2006 and DT_HASH has been >>>> obsoleted for more than one decade in many Linux distributions. >>>> >>>> Many vDSOs support DT_GNU_HASH. This patch adds selftests support. >>>> >>>> Signed-off-by: Fangrui Song <maskray@google.com> >>>> --- >>> >>> Ping. >>> >>> Some context: I'd change LoongArch vDSO to use the toolchain default >>> instead of forcing DT_HASH (note that LoongArch is launched decades >>> after all major distros switched to DT_GNU_HASH), but without the >>> selftest support we'll lose test coverage. >>> >>> And now ARM64 has already lost test coverage after commit 48f6430505c0. >>> >> >> I am seeing several checkpatch errors - please fix them and send me v2. >> >> thanks, >> -- Shuah >> > > The applicable change is: > > --- i/tools/testing/selftests/vDSO/parse_vdso.c > +++ w/tools/testing/selftests/vDSO/parse_vdso.c > @@ -177,7 +177,7 @@ void vdso_init_from_sysinfo_ehdr(uintptr_t base) > if (vdso_info.gnu_hash) { > vdso_info.nbucket = vdso_info.gnu_hash[0]; > /* The bucket array is located after the header (4 > uint32) and the bloom > - filter (size_t array of gnu_hash[2] elements). */ > + * filter (size_t array of gnu_hash[2] elements). */ > vdso_info.bucket = vdso_info.gnu_hash + 4 + > sizeof(size_t) / 4 * vdso_info.gnu_hash[2]; > } else { > > > Other checkpatch.pl output is not actionable. `ELF(Sym) *sym` instead > of `ELF(Sym) * sym` has the correct spacing (used in this file and > elsewhere ElfW in the code base). > > Okay. Send v2 with the actionable change. thanks, -- Shuah
diff --git a/tools/testing/selftests/vDSO/parse_vdso.c b/tools/testing/selftests/vDSO/parse_vdso.c index 4ae417372e9e..35cb545da13e 100644 --- a/tools/testing/selftests/vDSO/parse_vdso.c +++ b/tools/testing/selftests/vDSO/parse_vdso.c @@ -47,6 +47,7 @@ static struct vdso_info /* Symbol table */ ELF(Sym) *symtab; const char *symstrings; + ELF(Word) *gnu_hash; ELF(Word) *bucket, *chain; ELF(Word) nbucket, nchain; @@ -75,6 +76,16 @@ static unsigned long elf_hash(const char *name) return h; } +static uint32_t gnu_hash(const char *name) +{ + const unsigned char *s = (void *)name; + uint32_t h = 5381; + + for (; *s; s++) + h += h * 32 + *s; + return h; +} + void vdso_init_from_sysinfo_ehdr(uintptr_t base) { size_t i; @@ -117,6 +128,7 @@ void vdso_init_from_sysinfo_ehdr(uintptr_t base) */ ELF(Word) *hash = 0; vdso_info.symstrings = 0; + vdso_info.gnu_hash = 0; vdso_info.symtab = 0; vdso_info.versym = 0; vdso_info.verdef = 0; @@ -137,6 +149,11 @@ void vdso_init_from_sysinfo_ehdr(uintptr_t base) ((uintptr_t)dyn[i].d_un.d_ptr + vdso_info.load_offset); break; + case DT_GNU_HASH: + vdso_info.gnu_hash = + (ELF(Word) *)((uintptr_t)dyn[i].d_un.d_ptr + + vdso_info.load_offset); + break; case DT_VERSYM: vdso_info.versym = (ELF(Versym) *) ((uintptr_t)dyn[i].d_un.d_ptr @@ -149,17 +166,26 @@ void vdso_init_from_sysinfo_ehdr(uintptr_t base) break; } } - if (!vdso_info.symstrings || !vdso_info.symtab || !hash) + if (!vdso_info.symstrings || !vdso_info.symtab || + (!hash && !vdso_info.gnu_hash)) return; /* Failed */ if (!vdso_info.verdef) vdso_info.versym = 0; /* Parse the hash table header. */ - vdso_info.nbucket = hash[0]; - vdso_info.nchain = hash[1]; - vdso_info.bucket = &hash[2]; - vdso_info.chain = &hash[vdso_info.nbucket + 2]; + if (vdso_info.gnu_hash) { + vdso_info.nbucket = vdso_info.gnu_hash[0]; + /* The bucket array is located after the header (4 uint32) and the bloom + filter (size_t array of gnu_hash[2] elements). */ + vdso_info.bucket = vdso_info.gnu_hash + 4 + + sizeof(size_t) / 4 * vdso_info.gnu_hash[2]; + } else { + vdso_info.nbucket = hash[0]; + vdso_info.nchain = hash[1]; + vdso_info.bucket = &hash[2]; + vdso_info.chain = &hash[vdso_info.nbucket + 2]; + } /* That's all we need. */ vdso_info.valid = true; @@ -203,6 +229,26 @@ static bool vdso_match_version(ELF(Versym) ver, && !strcmp(name, vdso_info.symstrings + aux->vda_name); } +static bool check_sym(ELF(Sym) *sym, ELF(Word) i, const char *name, + const char *version, unsigned long ver_hash) +{ + /* Check for a defined global or weak function w/ right name. */ + if (ELF64_ST_TYPE(sym->st_info) != STT_FUNC) + return false; + if (ELF64_ST_BIND(sym->st_info) != STB_GLOBAL && + ELF64_ST_BIND(sym->st_info) != STB_WEAK) + return false; + if (strcmp(name, vdso_info.symstrings + sym->st_name)) + return false; + + /* Check symbol version. */ + if (vdso_info.versym && + !vdso_match_version(vdso_info.versym[i], version, ver_hash)) + return false; + + return true; +} + void *vdso_sym(const char *version, const char *name) { unsigned long ver_hash; @@ -210,29 +256,36 @@ void *vdso_sym(const char *version, const char *name) return 0; ver_hash = elf_hash(version); - ELF(Word) chain = vdso_info.bucket[elf_hash(name) % vdso_info.nbucket]; + ELF(Word) i; - for (; chain != STN_UNDEF; chain = vdso_info.chain[chain]) { - ELF(Sym) *sym = &vdso_info.symtab[chain]; + if (vdso_info.gnu_hash) { + uint32_t h1 = gnu_hash(name), h2, *hashval; - /* Check for a defined global or weak function w/ right name. */ - if (ELF64_ST_TYPE(sym->st_info) != STT_FUNC) - continue; - if (ELF64_ST_BIND(sym->st_info) != STB_GLOBAL && - ELF64_ST_BIND(sym->st_info) != STB_WEAK) - continue; - if (sym->st_shndx == SHN_UNDEF) - continue; - if (strcmp(name, vdso_info.symstrings + sym->st_name)) - continue; - - /* Check symbol version. */ - if (vdso_info.versym - && !vdso_match_version(vdso_info.versym[chain], - version, ver_hash)) - continue; - - return (void *)(vdso_info.load_offset + sym->st_value); + i = vdso_info.bucket[h1 % vdso_info.nbucket]; + if (i == 0) + return 0; + h1 |= 1; + hashval = vdso_info.bucket + vdso_info.nbucket + + (i - vdso_info.gnu_hash[1]); + for (;; i++) { + ELF(Sym) *sym = &vdso_info.symtab[i]; + h2 = *hashval++; + if (h1 == (h2 | 1) && + check_sym(sym, i, name, version, ver_hash)) + return (void *)(vdso_info.load_offset + + sym->st_value); + if (h2 & 1) + break; + } + } else { + i = vdso_info.bucket[elf_hash(name) % vdso_info.nbucket]; + for (; i; i = vdso_info.chain[i]) { + ELF(Sym) *sym = &vdso_info.symtab[i]; + if (sym->st_shndx != SHN_UNDEF && + check_sym(sym, i, name, version, ver_hash)) + return (void *)(vdso_info.load_offset + + sym->st_value); + } } return 0;
glibc added support for DT_GNU_HASH in 2006 and DT_HASH has been obsoleted for more than one decade in many Linux distributions. Many vDSOs support DT_GNU_HASH. This patch adds selftests support. Signed-off-by: Fangrui Song <maskray@google.com> --- tools/testing/selftests/vDSO/parse_vdso.c | 105 ++++++++++++++++------ 1 file changed, 79 insertions(+), 26 deletions(-)