mirror of
https://github.com/SerenityOS/serenity
synced 2024-10-17 13:22:58 +00:00
LibELF: Don't recompute the same ELF hashes over and over
When performing a global symbol lookup, we were recomputing the symbol hashes once for every dynamic object searched. The hash function was at the very top of a profile (15%) of program startup. With this change, the hash function is no longer visible among the top stacks in the profile. :^)
This commit is contained in:
parent
af6a633468
commit
d6af3302e8
|
@ -38,6 +38,7 @@
|
|||
#include <LibELF/DynamicLinker.h>
|
||||
#include <LibELF/DynamicLoader.h>
|
||||
#include <LibELF/DynamicObject.h>
|
||||
#include <LibELF/Hashes.h>
|
||||
#include <dlfcn.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/types.h>
|
||||
|
@ -64,8 +65,12 @@ bool g_do_breakpoint_trap_before_entry { false };
|
|||
Optional<DynamicObject::SymbolLookupResult> DynamicLinker::lookup_global_symbol(const StringView& symbol)
|
||||
{
|
||||
Optional<DynamicObject::SymbolLookupResult> weak_result;
|
||||
|
||||
auto gnu_hash = compute_gnu_hash(symbol);
|
||||
auto sysv_hash = compute_sysv_hash(symbol);
|
||||
|
||||
for (auto& lib : g_global_objects) {
|
||||
auto res = lib->lookup_symbol(symbol);
|
||||
auto res = lib->lookup_symbol(symbol, gnu_hash, sysv_hash);
|
||||
if (!res.has_value())
|
||||
continue;
|
||||
if (res.value().bind == STB_GLOBAL)
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include <AK/StringBuilder.h>
|
||||
#include <LibELF/DynamicLinker.h>
|
||||
#include <LibELF/DynamicLoader.h>
|
||||
#include <LibELF/Hashes.h>
|
||||
#include <LibELF/Validation.h>
|
||||
#include <assert.h>
|
||||
#include <dlfcn.h>
|
||||
|
@ -142,7 +143,7 @@ bool DynamicLoader::validate()
|
|||
|
||||
void* DynamicLoader::symbol_for_name(const StringView& name)
|
||||
{
|
||||
auto result = m_dynamic_object->hash_section().lookup_symbol(name);
|
||||
auto result = m_dynamic_object->hash_section().lookup_symbol(name, compute_gnu_hash(name), compute_sysv_hash(name));
|
||||
if (!result.has_value())
|
||||
return nullptr;
|
||||
auto symbol = result.value();
|
||||
|
|
|
@ -249,14 +249,8 @@ DynamicObject::RelocationSection DynamicObject::plt_relocation_section() const
|
|||
return RelocationSection(Section(*this, m_plt_relocation_offset_location, m_size_of_plt_relocation_entry_list, m_size_of_relocation_entry, "DT_JMPREL"));
|
||||
}
|
||||
|
||||
auto DynamicObject::HashSection::lookup_symbol(const StringView& name) const -> Optional<Symbol>
|
||||
auto DynamicObject::HashSection::lookup_elf_symbol(const StringView& name, u32 hash_value) const -> Optional<Symbol>
|
||||
{
|
||||
return (this->*(m_lookup_function))(name);
|
||||
}
|
||||
|
||||
auto DynamicObject::HashSection::lookup_elf_symbol(const StringView& name) const -> Optional<Symbol>
|
||||
{
|
||||
u32 hash_value = compute_sysv_hash(name);
|
||||
u32* hash_table_begin = (u32*)address().as_ptr();
|
||||
size_t num_buckets = hash_table_begin[0];
|
||||
|
||||
|
@ -279,7 +273,7 @@ auto DynamicObject::HashSection::lookup_elf_symbol(const StringView& name) const
|
|||
return {};
|
||||
}
|
||||
|
||||
auto DynamicObject::HashSection::lookup_gnu_symbol(const StringView& name) const -> Optional<Symbol>
|
||||
auto DynamicObject::HashSection::lookup_gnu_symbol(const StringView& name, u32 hash_value) const -> Optional<Symbol>
|
||||
{
|
||||
// Algorithm reference: https://ent-voy.blogspot.com/2011/02/
|
||||
// TODO: Handle 64bit bloomwords for ELF_CLASS64
|
||||
|
@ -299,7 +293,7 @@ auto DynamicObject::HashSection::lookup_gnu_symbol(const StringView& name) const
|
|||
const u32* const buckets = &bloom_words[num_maskwords];
|
||||
const u32* const chains = &buckets[num_buckets];
|
||||
|
||||
BloomWord hash1 = compute_gnu_hash(name);
|
||||
BloomWord hash1 = hash_value;
|
||||
BloomWord hash2 = hash1 >> shift2;
|
||||
const BloomWord bitmask = (1 << (hash1 % bloom_word_size)) | (1 << (hash2 % bloom_word_size));
|
||||
|
||||
|
@ -431,7 +425,12 @@ static const char* name_for_dtag(Elf32_Sword d_tag)
|
|||
|
||||
auto DynamicObject::lookup_symbol(const StringView& name) const -> Optional<SymbolLookupResult>
|
||||
{
|
||||
auto result = hash_section().lookup_symbol(name);
|
||||
return lookup_symbol(name, compute_gnu_hash(name), compute_sysv_hash(name));
|
||||
}
|
||||
|
||||
auto DynamicObject::lookup_symbol(const StringView& name, u32 gnu_hash, u32 sysv_hash) const -> Optional<SymbolLookupResult>
|
||||
{
|
||||
auto result = hash_section().lookup_symbol(name, gnu_hash, sysv_hash);
|
||||
if (!result.has_value())
|
||||
return {};
|
||||
auto symbol = result.value();
|
||||
|
|
|
@ -184,27 +184,22 @@ public:
|
|||
public:
|
||||
HashSection(const Section& section, HashType hash_type)
|
||||
: Section(section.m_dynamic, section.m_section_offset, section.m_section_size_bytes, section.m_entry_size, section.m_name)
|
||||
, m_hash_type(hash_type)
|
||||
{
|
||||
switch (hash_type) {
|
||||
case HashType::SYSV:
|
||||
m_lookup_function = &HashSection::lookup_elf_symbol;
|
||||
break;
|
||||
case HashType::GNU:
|
||||
m_lookup_function = &HashSection::lookup_gnu_symbol;
|
||||
break;
|
||||
default:
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
}
|
||||
|
||||
Optional<Symbol> lookup_symbol(const StringView& name) const;
|
||||
Optional<Symbol> lookup_symbol(const StringView& name, u32 gnu_hash, u32 sysv_hash) const
|
||||
{
|
||||
if (m_hash_type == HashType::SYSV)
|
||||
return lookup_elf_symbol(name, sysv_hash);
|
||||
return lookup_gnu_symbol(name, gnu_hash);
|
||||
}
|
||||
|
||||
private:
|
||||
Optional<Symbol> lookup_elf_symbol(const StringView& name) const;
|
||||
Optional<Symbol> lookup_gnu_symbol(const StringView& name) const;
|
||||
Optional<Symbol> lookup_elf_symbol(const StringView& name, u32 hash) const;
|
||||
Optional<Symbol> lookup_gnu_symbol(const StringView& name, u32 hash) const;
|
||||
|
||||
typedef Optional<Symbol> (HashSection::*LookupFunction)(const StringView&) const;
|
||||
LookupFunction m_lookup_function {};
|
||||
HashType m_hash_type {};
|
||||
};
|
||||
|
||||
unsigned symbol_count() const { return m_symbol_count; }
|
||||
|
@ -256,7 +251,9 @@ public:
|
|||
unsigned bind { STB_LOCAL };
|
||||
const ELF::DynamicObject* dynamic_object { nullptr }; // The object in which the symbol is defined
|
||||
};
|
||||
|
||||
Optional<SymbolLookupResult> lookup_symbol(const StringView& name) const;
|
||||
Optional<SymbolLookupResult> lookup_symbol(const StringView& name, u32 gnu_hash, u32 sysv_hash) const;
|
||||
|
||||
// Will be called from _fixup_plt_entry, as part of the PLT trampoline
|
||||
VirtualAddress patch_plt_entry(u32 relocation_offset);
|
||||
|
|
Loading…
Reference in a new issue