Skip to content

Commit

Permalink
Merge pull request #898 from adamjseitz/reloc-symbol-table
Browse files Browse the repository at this point in the history
Utilize SH_LINK section metadata to resolve relocation's target symbol table
  • Loading branch information
romainthomas committed Apr 19, 2023
2 parents 6749446 + bf7f36b commit fe2f20a
Show file tree
Hide file tree
Showing 6 changed files with 55 additions and 13 deletions.
7 changes: 7 additions & 0 deletions api/python/src/ELF/objects/pyRelocation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,13 @@ void create<Relocation>(py::module& m) {
)delim",
py::return_value_policy::reference)

.def_property_readonly("symbol_table",
static_cast<Section* (Relocation::*)(void)>(&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<getter_t<bool>>(&Relocation::is_rela),
"``True`` if the relocation **uses** the :attr:`~lief.ELF.Relocation.addend` proprety")
Expand Down
7 changes: 7 additions & 0 deletions doc/sphinx/changelog.rst
Original file line number Diff line number Diff line change
@@ -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
----------------------

Expand Down
11 changes: 9 additions & 2 deletions include/LIEF/ELF/Relocation.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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;
};

Expand Down
22 changes: 11 additions & 11 deletions src/ELF/Parser.tcc
Original file line number Diff line number Diff line change
Expand Up @@ -1342,21 +1342,20 @@ ok_error_t Parser::parse_section_relocations(const Section& section) {
std::is_same<REL_T, Elf_Rela>::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<ELF_T, details::ELF32>::value ? 8 : 32;
Expand All @@ -1375,15 +1374,16 @@ ok_error_t Parser::parse_section_relocations(const Section& section) {
auto reloc = std::make_unique<Relocation>(*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<uint32_t>(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) {
Expand Down
8 changes: 8 additions & 0 deletions src/ELF/Relocation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,14 @@ Section* Relocation::section() {
return const_cast<Section*>(static_cast<const Relocation*>(this)->section());
}

const Section* Relocation::symbol_table() const {
return symbol_table_;
}

Section* Relocation::symbol_table() {
return const_cast<Section*>(static_cast<const Relocation*>(this)->symbol_table());
}

bool Relocation::is_rela() const {
return isRela_;
}
Expand Down
13 changes: 13 additions & 0 deletions tests/elf/test_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"

0 comments on commit fe2f20a

Please sign in to comment.