* [PATCH v2] selftests/vDSO: support DT_GNU_HASH
@ 2024-09-15 6:49 Fangrui Song
2024-09-19 15:37 ` Shuah Khan
0 siblings, 1 reply; 7+ messages in thread
From: Fangrui Song @ 2024-09-15 6:49 UTC (permalink / raw)
To: Shuah Khan, linux-kselftest; +Cc: linux-kernel, Xi Ruoyao, Fangrui Song
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>
--
Changes from v1:
* fix style of a multi-line comment. ignore false positive suggestions from checkpath.pl: `ELF(Word) *`
---
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..dbc946dee4b1 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.662.g92d0881bb0-goog
^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH v2] selftests/vDSO: support DT_GNU_HASH
2024-09-15 6:49 [PATCH v2] selftests/vDSO: support DT_GNU_HASH Fangrui Song
@ 2024-09-19 15:37 ` Shuah Khan
2024-11-27 11:44 ` Xi Ruoyao
0 siblings, 1 reply; 7+ messages in thread
From: Shuah Khan @ 2024-09-19 15:37 UTC (permalink / raw)
To: Fangrui Song, Shuah Khan, linux-kselftest
Cc: linux-kernel, Xi Ruoyao, Shuah Khan
On 9/15/24 00:49, 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>
> --
> Changes from v1:
> * fix style of a multi-line comment. ignore false positive suggestions from checkpath.pl: `ELF(Word) *`
> ---
> tools/testing/selftests/vDSO/parse_vdso.c | 105 ++++++++++++++++------
> 1 file changed, 79 insertions(+), 26 deletions(-)
>
Quick note that this will be picked up after the merge window closes.
thanks,
-- Shuah
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH v2] selftests/vDSO: support DT_GNU_HASH
2024-09-19 15:37 ` Shuah Khan
@ 2024-11-27 11:44 ` Xi Ruoyao
2024-12-04 0:04 ` Shuah Khan
0 siblings, 1 reply; 7+ messages in thread
From: Xi Ruoyao @ 2024-11-27 11:44 UTC (permalink / raw)
To: Shuah Khan, Fangrui Song, Shuah Khan, linux-kselftest; +Cc: linux-kernel
On Thu, 2024-09-19 at 09:37 -0600, Shuah Khan wrote:
> On 9/15/24 00:49, 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>
> > --
> > Changes from v1:
> > * fix style of a multi-line comment. ignore false positive suggestions from checkpath.pl: `ELF(Word) *`
> > ---
> > tools/testing/selftests/vDSO/parse_vdso.c | 105 ++++++++++++++++------
> > 1 file changed, 79 insertions(+), 26 deletions(-)
> >
>
> Quick note that this will be picked up after the merge window closes.
Hi Shuah,
The patch seems forgotten.
--
Xi Ruoyao <xry111@xry111.site>
School of Aerospace Science and Technology, Xidian University
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH v2] selftests/vDSO: support DT_GNU_HASH
2024-11-27 11:44 ` Xi Ruoyao
@ 2024-12-04 0:04 ` Shuah Khan
2024-12-04 22:30 ` Shuah Khan
0 siblings, 1 reply; 7+ messages in thread
From: Shuah Khan @ 2024-12-04 0:04 UTC (permalink / raw)
To: Xi Ruoyao, Fangrui Song, Shuah Khan, linux-kselftest
Cc: linux-kernel, Shuah Khan
On 11/27/24 04:44, Xi Ruoyao wrote:
> On Thu, 2024-09-19 at 09:37 -0600, Shuah Khan wrote:
>> On 9/15/24 00:49, 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>
>>> --
>>> Changes from v1:
>>> * fix style of a multi-line comment. ignore false positive suggestions from checkpath.pl: `ELF(Word) *`
>>> ---
>>> tools/testing/selftests/vDSO/parse_vdso.c | 105 ++++++++++++++++------
>>> 1 file changed, 79 insertions(+), 26 deletions(-)
>>>
>>
>> Quick note that this will be picked up after the merge window closes.
>
> Hi Shuah,
>
> The patch seems forgotten.
>
Thank for the reminder. I will pick this up now.
thanks,
-- Shuah
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH v2] selftests/vDSO: support DT_GNU_HASH
2024-12-04 0:04 ` Shuah Khan
@ 2024-12-04 22:30 ` Shuah Khan
2024-12-06 13:07 ` [PATCH v3] " Xi Ruoyao
0 siblings, 1 reply; 7+ messages in thread
From: Shuah Khan @ 2024-12-04 22:30 UTC (permalink / raw)
To: Xi Ruoyao, Fangrui Song, Shuah Khan, linux-kselftest
Cc: linux-kernel, Shuah Khan
On 12/3/24 17:04, Shuah Khan wrote:
> On 11/27/24 04:44, Xi Ruoyao wrote:
>> On Thu, 2024-09-19 at 09:37 -0600, Shuah Khan wrote:
>>> On 9/15/24 00:49, 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>
>>>> --
>>>> Changes from v1:
>>>> * fix style of a multi-line comment. ignore false positive suggestions from checkpath.pl: `ELF(Word) *`
>>>> ---
>>>> tools/testing/selftests/vDSO/parse_vdso.c | 105 ++++++++++++++++------
>>>> 1 file changed, 79 insertions(+), 26 deletions(-)
>>>>
>>>
>>> Quick note that this will be picked up after the merge window closes.
>>
>> Hi Shuah,
>>
>> The patch seems forgotten.
>>
>
> Thank for the reminder. I will pick this up now.
>
Please rebase the patch to 6.13-rc1 and send it.
thanks,
-- Shuah
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH v3] selftests/vDSO: support DT_GNU_HASH
2024-12-04 22:30 ` Shuah Khan
@ 2024-12-06 13:07 ` Xi Ruoyao
2024-12-09 23:26 ` Shuah
0 siblings, 1 reply; 7+ messages in thread
From: Xi Ruoyao @ 2024-12-06 13:07 UTC (permalink / raw)
To: Shuah Khan, Fangrui Song, linux-kselftest; +Cc: linux-kernel, Xi Ruoyao
From: Fangrui Song <i@maskray.me>
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 <i@maskray.me>
Tested-by: Xi Ruoyao <xry111@xry111.site>
Signed-off-by: Xi Ruoyao <xry111@xry111.site> # rebase
---
tools/testing/selftests/vDSO/parse_vdso.c | 110 ++++++++++++++++------
1 file changed, 82 insertions(+), 28 deletions(-)
diff --git a/tools/testing/selftests/vDSO/parse_vdso.c b/tools/testing/selftests/vDSO/parse_vdso.c
index 28f35620c499..2fe5e983cb22 100644
--- a/tools/testing/selftests/vDSO/parse_vdso.c
+++ b/tools/testing/selftests/vDSO/parse_vdso.c
@@ -53,6 +53,7 @@ static struct vdso_info
/* Symbol table */
ELF(Sym) *symtab;
const char *symstrings;
+ ELF(Word) *gnu_hash;
ELF_HASH_ENTRY *bucket, *chain;
ELF_HASH_ENTRY nbucket, nchain;
@@ -81,6 +82,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;
@@ -123,6 +134,7 @@ void vdso_init_from_sysinfo_ehdr(uintptr_t base)
*/
ELF_HASH_ENTRY *hash = 0;
vdso_info.symstrings = 0;
+ vdso_info.gnu_hash = 0;
vdso_info.symtab = 0;
vdso_info.versym = 0;
vdso_info.verdef = 0;
@@ -143,6 +155,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
@@ -155,17 +172,27 @@ 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;
@@ -209,6 +236,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;
@@ -216,29 +263,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];
-
- for (; chain != STN_UNDEF; chain = vdso_info.chain[chain]) {
- ELF(Sym) *sym = &vdso_info.symtab[chain];
-
- /* 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);
+ ELF(Word) i;
+
+ if (vdso_info.gnu_hash) {
+ uint32_t h1 = gnu_hash(name), h2, *hashval;
+
+ 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;
base-commit: 40384c840ea1944d7c5a392e8975ed088ecf0b37
--
2.47.1
^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH v3] selftests/vDSO: support DT_GNU_HASH
2024-12-06 13:07 ` [PATCH v3] " Xi Ruoyao
@ 2024-12-09 23:26 ` Shuah
0 siblings, 0 replies; 7+ messages in thread
From: Shuah @ 2024-12-09 23:26 UTC (permalink / raw)
To: Xi Ruoyao, Shuah Khan, Fangrui Song, linux-kselftest; +Cc: linux-kernel
On 12/6/24 06:07, Xi Ruoyao wrote:
> From: Fangrui Song <i@maskray.me>
>
> 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 <i@maskray.me>
> Tested-by: Xi Ruoyao <xry111@xry111.site>
> Signed-off-by: Xi Ruoyao <xry111@xry111.site> # rebase
> ---
Thank you. Applied to linux-kselftest next for Linux 6.14-rc1.
thanks,
-- Shuah
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2024-12-09 23:26 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-09-15 6:49 [PATCH v2] selftests/vDSO: support DT_GNU_HASH Fangrui Song
2024-09-19 15:37 ` Shuah Khan
2024-11-27 11:44 ` Xi Ruoyao
2024-12-04 0:04 ` Shuah Khan
2024-12-04 22:30 ` Shuah Khan
2024-12-06 13:07 ` [PATCH v3] " Xi Ruoyao
2024-12-09 23:26 ` Shuah
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox