76b6d9
commit bd13cb19f5e15e9e9a92a536e755fd93a97a67f6
76b6d9
Author: Florian Weimer <fweimer@redhat.com>
76b6d9
Date:   Fri Aug 19 11:16:32 2022 +0200
76b6d9
76b6d9
    scripts/glibcelf.py: Add hashing support
76b6d9
    
76b6d9
    ELF and GNU hashes can now be computed using the elf_hash and
76b6d9
    gnu_hash functions.
76b6d9
    
76b6d9
    Reviewed-by: Carlos O'Donell <carlos@redhat.com>
76b6d9
    Tested-by: Carlos O'Donell <carlos@redhat.com>
76b6d9
76b6d9
diff --git a/elf/tst-glibcelf.py b/elf/tst-glibcelf.py
76b6d9
index bf15a3bad4479e08..e5026e2289df206b 100644
76b6d9
--- a/elf/tst-glibcelf.py
76b6d9
+++ b/elf/tst-glibcelf.py
76b6d9
@@ -240,6 +240,24 @@ def check_constant_values(cc):
76b6d9
             error('{}: glibcelf has {!r}, <elf.h> has {!r}'.format(
76b6d9
                 name, glibcelf_value, elf_h_value))
76b6d9
 
76b6d9
+def check_hashes():
76b6d9
+    for name, expected_elf, expected_gnu in (
76b6d9
+            ('', 0, 0x1505),
76b6d9
+            ('PPPPPPPPPPPP', 0, 0x9f105c45),
76b6d9
+            ('GLIBC_2.0', 0xd696910, 0xf66c3dd5),
76b6d9
+            ('GLIBC_2.34', 0x69691b4, 0xc3f3f90c),
76b6d9
+            ('GLIBC_PRIVATE', 0x963cf85, 0x692a260)):
76b6d9
+        for convert in (lambda x: x, lambda x: x.encode('UTF-8')):
76b6d9
+            name = convert(name)
76b6d9
+            actual_elf = glibcelf.elf_hash(name)
76b6d9
+            if actual_elf != expected_elf:
76b6d9
+                error('elf_hash({!r}): {:x} != 0x{:x}'.format(
76b6d9
+                    name, actual_elf, expected_elf))
76b6d9
+            actual_gnu = glibcelf.gnu_hash(name)
76b6d9
+            if actual_gnu != expected_gnu:
76b6d9
+                error('gnu_hash({!r}): {:x} != 0x{:x}'.format(
76b6d9
+                    name, actual_gnu, expected_gnu))
76b6d9
+
76b6d9
 def main():
76b6d9
     """The main entry point."""
76b6d9
     parser = argparse.ArgumentParser(
76b6d9
@@ -251,6 +269,7 @@ def main():
76b6d9
     check_duplicates()
76b6d9
     check_constant_prefixes()
76b6d9
     check_constant_values(cc=args.cc)
76b6d9
+    check_hashes()
76b6d9
 
76b6d9
     if errors_encountered > 0:
76b6d9
         print("note: errors encountered:", errors_encountered)
76b6d9
diff --git a/scripts/glibcelf.py b/scripts/glibcelf.py
76b6d9
index de0509130ed9ad47..5c8f46f590722384 100644
76b6d9
--- a/scripts/glibcelf.py
76b6d9
+++ b/scripts/glibcelf.py
76b6d9
@@ -1158,5 +1158,24 @@ class Image:
76b6d9
         self._stringtab[sh_link] = strtab
76b6d9
         return strtab
76b6d9
 
76b6d9
+def elf_hash(s):
76b6d9
+    """Computes the ELF hash of the string."""
76b6d9
+    acc = 0
76b6d9
+    for ch in s:
76b6d9
+        if type(ch) is not int:
76b6d9
+            ch = ord(ch)
76b6d9
+        acc = ((acc << 4) + ch) & 0xffffffff
76b6d9
+        top = acc & 0xf0000000
76b6d9
+        acc = (acc ^ (top >> 24)) & ~top
76b6d9
+    return acc
76b6d9
+
76b6d9
+def gnu_hash(s):
76b6d9
+    """Computes the GNU hash of the string."""
76b6d9
+    h = 5381
76b6d9
+    for ch in s:
76b6d9
+        if type(ch) is not int:
76b6d9
+            ch = ord(ch)
76b6d9
+        h = (h * 33 + ch) & 0xffffffff
76b6d9
+    return h
76b6d9
 
76b6d9
 __all__ = [name for name in dir() if name[0].isupper()]