From bd3965a41d725a3165a4aa83a739401be8f1e186 Mon Sep 17 00:00:00 2001 From: Ollrogge Date: Sun, 7 Jan 2024 20:10:39 +0100 Subject: [PATCH] LibELF: Correctly determine symbol amount for DT_GNU_HASH table --- Userland/Libraries/LibELF/DynamicObject.cpp | 37 ++++++++++++++++++--- Userland/Utilities/readelf.cpp | 1 - 2 files changed, 33 insertions(+), 5 deletions(-) diff --git a/Userland/Libraries/LibELF/DynamicObject.cpp b/Userland/Libraries/LibELF/DynamicObject.cpp index f68e65144f493d..efa7ef683ede9d 100644 --- a/Userland/Libraries/LibELF/DynamicObject.cpp +++ b/Userland/Libraries/LibELF/DynamicObject.cpp @@ -216,10 +216,39 @@ void DynamicObject::parse() m_size_of_relocation_table -= m_size_of_plt_relocation_entry_list; } - auto hash_section_address = hash_section().address().as_ptr(); - // TODO: consider base address - it might not be zero - auto num_hash_chains = ((u32*)hash_section_address)[1]; - m_symbol_count = num_hash_chains; + u32 const* hash_table_begin = reinterpret_cast(hash_section().address().as_ptr()); + + if (m_hash_type == HashType::SYSV) { + u32 n_chain = hash_table_begin[1]; + m_symbol_count = n_chain; + return; + } + + // Determine amount of symbols by finding the chain with the highest + // starting index and walking this chain until the end to find the + // maximum index = amount of symbols. + using BloomWord = FlatPtr; + size_t const num_buckets = hash_table_begin[0]; + size_t const num_omitted_symbols = hash_table_begin[1]; + u32 const num_maskwords = hash_table_begin[2]; + BloomWord const* bloom_words = reinterpret_cast(&hash_table_begin[4]); + u32 const* const buckets = reinterpret_cast(&bloom_words[num_maskwords]); + u32 const* const chains = &buckets[num_buckets]; + + size_t highest_chain_idx = 0; + for (size_t i = 0; i < num_buckets; i++) { + if (buckets[i] > highest_chain_idx) { + highest_chain_idx = buckets[i]; + } + } + + size_t amount_symbols = highest_chain_idx; + u32 const* last_chain = &chains[highest_chain_idx - num_omitted_symbols]; + while ((*(last_chain++) & 1) == 0) { + amount_symbols++; + } + + m_symbol_count = amount_symbols + 1; } DynamicObject::Relocation DynamicObject::RelocationSection::relocation(unsigned index) const diff --git a/Userland/Utilities/readelf.cpp b/Userland/Utilities/readelf.cpp index 29e5822023110a..74cf1bccc7d021 100644 --- a/Userland/Utilities/readelf.cpp +++ b/Userland/Utilities/readelf.cpp @@ -565,7 +565,6 @@ ErrorOr serenity_main(Main::Arguments arguments) }); if (object->symbol_count()) { - // FIXME: Add support for init/fini/start/main sections outln(" Num: Value{} Size{} Type Bind Name", addr_padding, addr_padding); object->for_each_symbol([](const ELF::DynamicObject::Symbol& sym) { out(" {:>4}: ", sym.index());