diff mbox series

[1/2] scripts/glibcelf.py: Add hashing support

Message ID 11d0aa3cb1c97a02853bc9b1a68f4f64fb4a5c13.1660903960.git.fweimer@redhat.com
State New
Headers show
Series Check ld.so/libc.so consistency during startup | expand

Commit Message

Florian Weimer Aug. 19, 2022, 10:16 a.m. UTC
ELF and GNU hashes can now be computed using the elf_hash and
gnu_hash functions.
---
 elf/tst-glibcelf.py | 19 +++++++++++++++++++
 scripts/glibcelf.py | 19 +++++++++++++++++++
 2 files changed, 38 insertions(+)

Comments

Carlos O'Donell Aug. 23, 2022, 3:13 p.m. UTC | #1
On 8/19/22 06:16, Florian Weimer via Libc-alpha wrote:
> ELF and GNU hashes can now be computed using the elf_hash and
> gnu_hash functions.

Reviewed-by: Carlos O'Donell <carlos@redhat.com>
Tested-by: Carlos O'Donell <carlos@redhat.com>

> ---
>  elf/tst-glibcelf.py | 19 +++++++++++++++++++
>  scripts/glibcelf.py | 19 +++++++++++++++++++
>  2 files changed, 38 insertions(+)
> 
> diff --git a/elf/tst-glibcelf.py b/elf/tst-glibcelf.py
> index bf15a3bad4..e5026e2289 100644
> --- a/elf/tst-glibcelf.py
> +++ b/elf/tst-glibcelf.py
> @@ -240,6 +240,24 @@ def check_constant_values(cc):
>              error('{}: glibcelf has {!r}, <elf.h> has {!r}'.format(
>                  name, glibcelf_value, elf_h_value))
>  
> +def check_hashes():
> +    for name, expected_elf, expected_gnu in (
> +            ('', 0, 0x1505),
> +            ('PPPPPPPPPPPP', 0, 0x9f105c45),
> +            ('GLIBC_2.0', 0xd696910, 0xf66c3dd5),
> +            ('GLIBC_2.34', 0x69691b4, 0xc3f3f90c),
> +            ('GLIBC_PRIVATE', 0x963cf85, 0x692a260)):
> +        for convert in (lambda x: x, lambda x: x.encode('UTF-8')):
> +            name = convert(name)
> +            actual_elf = glibcelf.elf_hash(name)
> +            if actual_elf != expected_elf:
> +                error('elf_hash({!r}): {:x} != 0x{:x}'.format(
> +                    name, actual_elf, expected_elf))
> +            actual_gnu = glibcelf.gnu_hash(name)
> +            if actual_gnu != expected_gnu:
> +                error('gnu_hash({!r}): {:x} != 0x{:x}'.format(
> +                    name, actual_gnu, expected_gnu))
> +
>  def main():
>      """The main entry point."""
>      parser = argparse.ArgumentParser(
> @@ -251,6 +269,7 @@ def main():
>      check_duplicates()
>      check_constant_prefixes()
>      check_constant_values(cc=args.cc)
> +    check_hashes()
>  
>      if errors_encountered > 0:
>          print("note: errors encountered:", errors_encountered)
> diff --git a/scripts/glibcelf.py b/scripts/glibcelf.py
> index de0509130e..5c8f46f590 100644
> --- a/scripts/glibcelf.py
> +++ b/scripts/glibcelf.py
> @@ -1158,5 +1158,24 @@ class Image:
>          self._stringtab[sh_link] = strtab
>          return strtab
>  
> +def elf_hash(s):
> +    """Computes the ELF hash of the string."""
> +    acc = 0
> +    for ch in s:
> +        if type(ch) is not int:
> +            ch = ord(ch)
> +        acc = ((acc << 4) + ch) & 0xffffffff
> +        top = acc & 0xf0000000
> +        acc = (acc ^ (top >> 24)) & ~top
> +    return acc
> +
> +def gnu_hash(s):
> +    """Computes the GNU hash of the string."""
> +    h = 5381
> +    for ch in s:
> +        if type(ch) is not int:
> +            ch = ord(ch)
> +        h = (h * 33 + ch) & 0xffffffff
> +    return h
>  
>  __all__ = [name for name in dir() if name[0].isupper()]
Florian Weimer Aug. 23, 2022, 5:34 p.m. UTC | #2
* Carlos O'Donell:

> On 8/19/22 06:16, Florian Weimer via Libc-alpha wrote:
>> ELF and GNU hashes can now be computed using the elf_hash and
>> gnu_hash functions.
>
> Reviewed-by: Carlos O'Donell <carlos@redhat.com>
> Tested-by: Carlos O'Donell <carlos@redhat.com>

I've pushed this separately.

Thanks,
Florian
diff mbox series

Patch

diff --git a/elf/tst-glibcelf.py b/elf/tst-glibcelf.py
index bf15a3bad4..e5026e2289 100644
--- a/elf/tst-glibcelf.py
+++ b/elf/tst-glibcelf.py
@@ -240,6 +240,24 @@  def check_constant_values(cc):
             error('{}: glibcelf has {!r}, <elf.h> has {!r}'.format(
                 name, glibcelf_value, elf_h_value))
 
+def check_hashes():
+    for name, expected_elf, expected_gnu in (
+            ('', 0, 0x1505),
+            ('PPPPPPPPPPPP', 0, 0x9f105c45),
+            ('GLIBC_2.0', 0xd696910, 0xf66c3dd5),
+            ('GLIBC_2.34', 0x69691b4, 0xc3f3f90c),
+            ('GLIBC_PRIVATE', 0x963cf85, 0x692a260)):
+        for convert in (lambda x: x, lambda x: x.encode('UTF-8')):
+            name = convert(name)
+            actual_elf = glibcelf.elf_hash(name)
+            if actual_elf != expected_elf:
+                error('elf_hash({!r}): {:x} != 0x{:x}'.format(
+                    name, actual_elf, expected_elf))
+            actual_gnu = glibcelf.gnu_hash(name)
+            if actual_gnu != expected_gnu:
+                error('gnu_hash({!r}): {:x} != 0x{:x}'.format(
+                    name, actual_gnu, expected_gnu))
+
 def main():
     """The main entry point."""
     parser = argparse.ArgumentParser(
@@ -251,6 +269,7 @@  def main():
     check_duplicates()
     check_constant_prefixes()
     check_constant_values(cc=args.cc)
+    check_hashes()
 
     if errors_encountered > 0:
         print("note: errors encountered:", errors_encountered)
diff --git a/scripts/glibcelf.py b/scripts/glibcelf.py
index de0509130e..5c8f46f590 100644
--- a/scripts/glibcelf.py
+++ b/scripts/glibcelf.py
@@ -1158,5 +1158,24 @@  class Image:
         self._stringtab[sh_link] = strtab
         return strtab
 
+def elf_hash(s):
+    """Computes the ELF hash of the string."""
+    acc = 0
+    for ch in s:
+        if type(ch) is not int:
+            ch = ord(ch)
+        acc = ((acc << 4) + ch) & 0xffffffff
+        top = acc & 0xf0000000
+        acc = (acc ^ (top >> 24)) & ~top
+    return acc
+
+def gnu_hash(s):
+    """Computes the GNU hash of the string."""
+    h = 5381
+    for ch in s:
+        if type(ch) is not int:
+            ch = ord(ch)
+        h = (h * 33 + ch) & 0xffffffff
+    return h
 
 __all__ = [name for name in dir() if name[0].isupper()]