tools/testing/selftests/vDSO/parse_vdso.c | 105 ++++++++++++++++------ 1 file changed, 79 insertions(+), 26 deletions(-)
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(-)
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;
--
2.46.0.76.ge559c4bf1a-goog
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;
--
Xi Ruoyao <xry111@xry111.site>
School of Aerospace Science and Technology, Xidian University
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
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;
--
Xi Ruoyao <xry111@xry111.site>
School of Aerospace Science and Technology, Xidian University
© 2016 - 2026 Red Hat, Inc.