diff options
author | Andreas Kling <awesomekling@gmail.com> | 2019-11-28 20:53:02 +0100 |
---|---|---|
committer | Andreas Kling <awesomekling@gmail.com> | 2019-11-28 20:53:02 +0100 |
commit | c10a5ac4ade2c70eee46bc401fd875e848393213 (patch) | |
tree | 3a2fa30af4f7fc90499f9656a14d81a1afe67bc0 /Libraries/LibELF | |
parent | 0c4f29f71f43e6eb6689f55aaba69688bce3d643 (diff) | |
download | serenity-c10a5ac4ade2c70eee46bc401fd875e848393213.zip |
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.
Diffstat (limited to 'Libraries/LibELF')
-rw-r--r-- | Libraries/LibELF/ELFImage.cpp | 44 | ||||
-rw-r--r-- | Libraries/LibELF/ELFImage.h | 51 | ||||
-rw-r--r-- | Libraries/LibELF/exec_elf.h | 3 |
3 files changed, 94 insertions, 4 deletions
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<const Elf32_Rel*>(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<const RelocationSection>(m_image.section(0)); + +#ifdef ELFIMAGE_DEBUG + kprintf("Found relocations for %s in %s\n", name(), relocation_section.name()); +#endif + return static_cast<const RelocationSection>(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 <AK/String.h> #include <AK/HashMap.h> #include <AK/OwnPtr.h> +#include <AK/String.h> #include <Kernel/VM/VirtualAddress.h> #include <LibELF/exec_elf.h> @@ -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<typename F> + 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<typename F> 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<String, unsigned> m_sections; bool m_valid { false }; unsigned m_symbol_table_section_index { 0 }; unsigned m_string_table_section_index { 0 }; @@ -154,13 +192,22 @@ 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<typename F> +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<typename F> inline void ELFImage::for_each_symbol(F func) const { for (unsigned i = 0; i < symbol_count(); ++i) { 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_ */ |