From c10a5ac4ade2c70eee46bc401fd875e848393213 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Thu, 28 Nov 2019 20:53:02 +0100 Subject: LibELF: Restore the relocation code from git history This is going to be very useful for implementing kernel modules. We'll also need it for dynamic linking later on. --- Libraries/LibELF/ELFImage.cpp | 44 +++++++++++++++++++++++++++++++++++-- Libraries/LibELF/ELFImage.h | 51 +++++++++++++++++++++++++++++++++++++++++-- Libraries/LibELF/exec_elf.h | 3 +++ 3 files changed, 94 insertions(+), 4 deletions(-) (limited to 'Libraries/LibELF') diff --git a/Libraries/LibELF/ELFImage.cpp b/Libraries/LibELF/ELFImage.cpp index dedfea994c..51d14ba459 100644 --- a/Libraries/LibELF/ELFImage.cpp +++ b/Libraries/LibELF/ELFImage.cpp @@ -106,14 +106,21 @@ bool ELFImage::parse() for (unsigned i = 0; i < section_count(); ++i) { auto& sh = section_header(i); if (sh.sh_type == SHT_SYMTAB) { - ASSERT(!m_symbol_table_section_index); + ASSERT(!m_symbol_table_section_index || m_symbol_table_section_index == i); m_symbol_table_section_index = i; } if (sh.sh_type == SHT_STRTAB && i != header().e_shstrndx) { - ASSERT(!m_string_table_section_index); + ASSERT(!m_string_table_section_index || m_string_table_section_index == i); m_string_table_section_index = i; } } + + // Then create a name-to-index map. + for (unsigned i = 0; i < section_count(); ++i) { + auto& section = this->section(i); + m_sections.set(section.name(), move(i)); + } + return true; } @@ -173,3 +180,36 @@ const ELFImage::ProgramHeader ELFImage::program_header(unsigned index) const ASSERT(index < program_header_count()); return ProgramHeader(*this, index); } + +const ELFImage::Relocation ELFImage::RelocationSection::relocation(unsigned index) const +{ + ASSERT(index < relocation_count()); + auto* rels = reinterpret_cast(m_image.raw_data(offset())); + return Relocation(m_image, rels[index]); +} + +const ELFImage::RelocationSection ELFImage::Section::relocations() const +{ + // FIXME: This is ugly. + char relocation_sectionName[128]; + sprintf(relocation_sectionName, ".rel%s", name()); + +#ifdef ELFIMAGE_DEBUG + kprintf("looking for '%s'\n", relocation_sectionName); +#endif + auto relocation_section = m_image.lookup_section(relocation_sectionName); + if (relocation_section.type() != SHT_REL) + return static_cast(m_image.section(0)); + +#ifdef ELFIMAGE_DEBUG + kprintf("Found relocations for %s in %s\n", name(), relocation_section.name()); +#endif + return static_cast(relocation_section); +} + +const ELFImage::Section ELFImage::lookup_section(const char* name) const +{ + if (auto it = m_sections.find(name); it != m_sections.end()) + return section((*it).value); + return section(0); +} diff --git a/Libraries/LibELF/ELFImage.h b/Libraries/LibELF/ELFImage.h index 143b4005e7..9ad48a50dc 100644 --- a/Libraries/LibELF/ELFImage.h +++ b/Libraries/LibELF/ELFImage.h @@ -1,8 +1,8 @@ #pragma once -#include #include #include +#include #include #include @@ -92,6 +92,7 @@ public: u32 address() const { return m_section_header.sh_addr; } const char* raw_data() const { return m_image.raw_data(m_section_header.sh_offset); } bool is_undefined() const { return m_section_index == SHN_UNDEF; } + const RelocationSection relocations() const; u32 flags() const { return m_section_header.sh_flags; } bool is_writable() const { return flags() & SHF_WRITE; } bool is_executable() const { return flags() & PF_X; } @@ -103,6 +104,38 @@ public: unsigned m_section_index; }; + class RelocationSection : public Section { + public: + RelocationSection(const Section& section) + : Section(section.m_image, section.m_section_index) + { + } + unsigned relocation_count() const { return entry_count(); } + const Relocation relocation(unsigned index) const; + template + void for_each_relocation(F) const; + }; + + class Relocation { + public: + Relocation(const ELFImage& image, const Elf32_Rel& rel) + : m_image(image) + , m_rel(rel) + { + } + + ~Relocation() {} + + unsigned offset() const { return m_rel.r_offset; } + unsigned type() const { return ELF32_R_TYPE(m_rel.r_info); } + unsigned symbol_index() const { return ELF32_R_SYM(m_rel.r_info); } + const Symbol symbol() const { return m_image.symbol(symbol_index()); } + + private: + const ELFImage& m_image; + const Elf32_Rel& m_rel; + }; + unsigned symbol_count() const; unsigned section_count() const; unsigned program_header_count() const; @@ -120,6 +153,10 @@ public: template void for_each_program_header(F) const; + // NOTE: Returns section(0) if section with name is not found. + // FIXME: I don't love this API. + const Section lookup_section(const char* name) const; + bool is_executable() const { return header().e_type == ET_EXEC; } bool is_relocatable() const { return header().e_type == ET_REL; } @@ -136,6 +173,7 @@ private: const char* section_index_to_string(unsigned index) const; const u8* m_buffer { nullptr }; + HashMap m_sections; bool m_valid { false }; unsigned m_symbol_table_section_index { 0 }; unsigned m_string_table_section_index { 0 }; @@ -154,12 +192,21 @@ inline void ELFImage::for_each_section_of_type(unsigned type, F func) const for (unsigned i = 0; i < section_count(); ++i) { auto& section = this->section(i); if (section.type() == type) { - if (!func(section)) + if (func(section) == IterationDecision::Break) break; } } } +template +inline void ELFImage::RelocationSection::for_each_relocation(F func) const +{ + for (unsigned i = 0; i < relocation_count(); ++i) { + if (func(relocation(i)) == IterationDecision::Break) + break; + } +} + template inline void ELFImage::for_each_symbol(F func) const { diff --git a/Libraries/LibELF/exec_elf.h b/Libraries/LibELF/exec_elf.h index 90dca3a6e3..2be5076801 100644 --- a/Libraries/LibELF/exec_elf.h +++ b/Libraries/LibELF/exec_elf.h @@ -775,4 +775,7 @@ struct elf_args { #define ELF_TARG_VER 1 /* The ver for which this code is intended */ +#define R_386_32 1 +#define R_386_PC32 2 + #endif /* _SYS_EXEC_ELF_H_ */ -- cgit v1.2.3