diff --git a/api/python/src/ELF/objects/pyRelocation.cpp b/api/python/src/ELF/objects/pyRelocation.cpp index 71487dcba0..9f89921310 100644 --- a/api/python/src/ELF/objects/pyRelocation.cpp +++ b/api/python/src/ELF/objects/pyRelocation.cpp @@ -106,6 +106,13 @@ void create(py::module& m) { )delim", py::return_value_policy::reference) + .def_property_readonly("symbol_table", + static_cast(&Relocation::symbol_table), + R"delim( + the symbol table :class:`~lief.ELF.Section` which the relocation references + )delim", + py::return_value_policy::reference) + .def_property_readonly("is_rela", static_cast>(&Relocation::is_rela), "``True`` if the relocation **uses** the :attr:`~lief.ELF.Relocation.addend` proprety") diff --git a/doc/sphinx/changelog.rst b/doc/sphinx/changelog.rst index 7a093bcc03..6fa5aff30b 100644 --- a/doc/sphinx/changelog.rst +++ b/doc/sphinx/changelog.rst @@ -1,6 +1,13 @@ Changelog ========= +0.14.0 - Not Released Yet +------------------------- + +:ELF: + + * Fix relocation issue when using `-Wl,--emit-relocs` (c.f. :issue:`897` / :pr:`898` by :github_user:`adamjseitz`) + 0.13.0 - April 9, 2023 ---------------------- diff --git a/include/LIEF/ELF/Relocation.hpp b/include/LIEF/ELF/Relocation.hpp index c22743b638..16f194e802 100644 --- a/include/LIEF/ELF/Relocation.hpp +++ b/include/LIEF/ELF/Relocation.hpp @@ -119,17 +119,23 @@ class LIEF_API Relocation : public LIEF::Relocation { //! True if the relocation has an associated section bool has_section() const; - //! Section associated with this relocation. - //! If no section is tied to this relocation, it returns a nullptr + //! The section to which the relocation applies. + //! If no section to which the relocation applies is associtated to this relocation, it returns a nullptr Section* section(); const Section* section() const; + //! The associated symbol table. + //! If no symbol table section is associated with this relocation, it returns a nullptr + Section* symbol_table(); + const Section* symbol_table() const; + void addend(int64_t addend); void type(uint32_t type); void purpose(RELOCATION_PURPOSES purpose); void info(uint32_t v); void symbol(Symbol* symbol); void section(Section* section); + void symbol_table(Section* section); void accept(Visitor& visitor) const override; @@ -146,6 +152,7 @@ class LIEF_API Relocation : public LIEF::Relocation { ARCH architecture_ = ARCH::EM_NONE; RELOCATION_PURPOSES purpose_ = RELOCATION_PURPOSES::RELOC_PURPOSE_NONE; Section* section_{nullptr}; + Section* symbol_table_{nullptr}; uint32_t info_ = 0; }; diff --git a/src/ELF/Parser.tcc b/src/ELF/Parser.tcc index 2a774f7568..3d08db4ef0 100644 --- a/src/ELF/Parser.tcc +++ b/src/ELF/Parser.tcc @@ -1342,21 +1342,20 @@ ok_error_t Parser::parse_section_relocations(const Section& section) { std::is_same::value, "REL_T must be Elf_Rel || Elf_Rela"); // A relocation section can reference two other sections: a symbol table, - // identified by the sh_info section header entry, and a section to modify, - // identified by the sh_link - // BUT: in practice sh_info and sh_link are inverted + // identified by the sh_link section header entry, and a section to modify, + // identified by the sh_info + // See Figure 4-12 in https://refspecs.linuxbase.org/elf/gabi4+/ch4.sheader.html#sh_link Section* applies_to = nullptr; const size_t sh_info = section.information(); if (sh_info > 0 && sh_info < binary_->sections_.size()) { applies_to = binary_->sections_[sh_info].get(); } - // FIXME: Use it - // Section* section_associated = nullptr; - // if (section.link() > 0 and section.link() < binary_->sections_.size()) { - // const size_t sh_link = section.link(); - // section_associated = binary_->sections_[sh_link]; - // } + Section* symbol_table = nullptr; + if (section.link() > 0 and section.link() < binary_->sections_.size()) { + const size_t sh_link = section.link(); + symbol_table = binary_->sections_[sh_link].get(); + } const uint64_t offset_relocations = section.file_offset(); const uint8_t shift = std::is_same::value ? 8 : 32; @@ -1375,15 +1374,16 @@ ok_error_t Parser::parse_section_relocations(const Section& section) { auto reloc = std::make_unique(*rel_hdr); reloc->architecture_ = binary_->header_.machine_type(); reloc->section_ = applies_to; + reloc->symbol_table_ = symbol_table; if (binary_->header().file_type() == ELF::E_TYPE::ET_REL && binary_->segments().size() == 0) { reloc->purpose(RELOCATION_PURPOSES::RELOC_PURPOSE_OBJECT); } const auto idx = static_cast(rel_hdr->r_info >> shift); - if (idx > 0 && idx < binary_->dynamic_symbols_.size()) { + if (idx > 0 && idx < binary_->dynamic_symbols_.size() && (symbol_table == nullptr || symbol_table->type() == LIEF::ELF::ELF_SECTION_TYPES::SHT_DYNSYM)) { reloc->symbol_ = binary_->dynamic_symbols_[idx].get(); - } else if (idx < binary_->static_symbols_.size()) { + } else if (idx < binary_->static_symbols_.size() && (symbol_table == nullptr || symbol_table->type() == LIEF::ELF::ELF_SECTION_TYPES::SHT_SYMTAB)) { reloc->symbol_ = binary_->static_symbols_[idx].get(); } if (reloc_hash.insert(reloc.get()).second) { diff --git a/src/ELF/Relocation.cpp b/src/ELF/Relocation.cpp index 9690dc3f7b..e12a97e2d8 100644 --- a/src/ELF/Relocation.cpp +++ b/src/ELF/Relocation.cpp @@ -129,6 +129,14 @@ Section* Relocation::section() { return const_cast(static_cast(this)->section()); } +const Section* Relocation::symbol_table() const { + return symbol_table_; +} + +Section* Relocation::symbol_table() { + return const_cast(static_cast(this)->symbol_table()); +} + bool Relocation::is_rela() const { return isRela_; } diff --git a/tests/elf/test_parser.py b/tests/elf/test_parser.py index 3b61b7d17f..46932dd861 100644 --- a/tests/elf/test_parser.py +++ b/tests/elf/test_parser.py @@ -60,3 +60,16 @@ def test_issue_845(): target = lief.parse(get_sample('ELF/issue_845.elf')) assert len(target.segments) > 1 assert len(target.segments[1].content) == 0 + +def test_issue_897(): + """ + Issue #897 / PR: #898 + """ + target = lief.parse(get_sample('ELF/test_897.elf')) + rel1 = target.get_relocation(0x1b39) + assert rel1.symbol.name == "__init_array_start" + assert rel1.symbol_table.name == ".symtab" + + rel2 = target.get_relocation(0x1b50) + assert rel2.symbol.name == "__init_array_end" + assert rel2.symbol_table.name == ".symtab"