From c7a169280d51359f8206e86cf0f6289e902d0c2e Mon Sep 17 00:00:00 2001 From: Matthew Lugg Date: Wed, 12 Aug 2026 12:18:15 +0100 Subject: [PATCH] std.elf: add definitions for SHT_HASH header and hash function --- lib/std/elf.zig | 41 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 36 insertions(+), 5 deletions(-) diff --git a/lib/std/elf.zig b/lib/std/elf.zig index e4e905cea761ff6cbfbc81bcbd2fc44fdc8704ad..35266dc1d2a57ce32d94dd13a0e35a2c20275356 100644 --- a/lib/std/elf.zig +++ b/lib/std/elf.zig @@ -3290,13 +3290,11 @@ pub const gnu_hash = struct { /// Calculate the hash value for a name pub fn calculate(name: []const u8) u32 { - var hash: u32 = 5381; - + var h: u32 = 5381; for (name) |char| { - hash = (hash << 5) +% hash +% char; + h = (h << 5) +% h +% char; } - - return hash; + return h; } test calculate { @@ -3308,6 +3306,39 @@ pub const gnu_hash = struct { } }; +/// Things for the `SHT.HASH` section type. +/// +/// Resources: +/// * https://refspecs.linuxfoundation.org/elf/gabi4+/ch5.dynamic.html#hash +/// * https://flapenguin.me/elf-dt-hash +pub const hash = struct { + pub fn calculate(name: []const u8) u32 { + var h: u32 = 0; + for (name) |c| { + h = (h << 4) +% c; + const g = h & 0xF000_0000; + h = (h ^ (g >> 24)) & ~g; + } + return h; + } + + /// The header of a `SHT.HASH` section. Immediately followed by: + /// * `buckets: [nbucket]u32` + /// * `chains: [nchain]u32` + /// + /// The bucket for a symbol named `name` is `std.elf.hash.calculate(name) % nbuckets`. + /// + /// `buckets[b]` is the index of the first symbol in bucket `b`. If bucket `b` is empty then the + /// value is 0 (`STN_UNDEF`). + /// + /// `chain[sym_index]` is the index of the next symbol in the same bucket as `sym_index`. If + /// `sym_index` is the last symbol in its bucket then the value is 0 (`STN_UNDEF`). + pub const Header = extern struct { + nbucket: u32, + nchain: u32, + }; +}; + pub const EhdrFlags = packed union(Word) { int: u32, loongarch: Loongarch, -- 2.54.0