Skip to content

Commit

Permalink
Add support for DT_RELR/DT_ANDROID_RELA relocations
Browse files Browse the repository at this point in the history
This commit adds the support for the (new) relative relocations
as well as the Android packed relocation format.

Resolve: #111 #991
  • Loading branch information
romainthomas committed Feb 3, 2024
1 parent 0fe1a84 commit 00e4a68
Show file tree
Hide file tree
Showing 24 changed files with 1,391 additions and 300 deletions.
39 changes: 38 additions & 1 deletion api/python/lief/ELF.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,10 @@ class Binary(lief.Binary):
def add_pltgot_relocation(self, relocation: lief.ELF.Relocation) -> lief.ELF.Relocation: ...
def add_symtab_symbol(self, symbol: lief.ELF.Symbol) -> lief.ELF.Symbol: ...
@overload
def dynsym_idx(self, name: str) -> int: ...
@overload
def dynsym_idx(self, symbol: lief.ELF.Symbol) -> int: ...
@overload
def export_symbol(self, symbol: lief.ELF.Symbol) -> lief.ELF.Symbol: ...
@overload
def export_symbol(self, symbol_name: str, value: int = ...) -> lief.ELF.Symbol: ...
Expand Down Expand Up @@ -437,6 +441,10 @@ class Binary(lief.Binary):
def segment_from_offset(self, offset: int) -> lief.ELF.Segment: ...
def segment_from_virtual_address(self, address: int) -> lief.ELF.Segment: ...
def strip(self) -> None: ...
@overload
def symtab_idx(self, name: str) -> int: ...
@overload
def symtab_idx(self, symbol: lief.ELF.Symbol) -> int: ...
def virtual_address_to_offset(self, virtual_address: int) -> Union[int,lief.lief_errors]: ...
@overload
def write(self, output: str) -> None: ...
Expand Down Expand Up @@ -547,6 +555,7 @@ class Binary(lief.Binary):

class Builder:
class config_t:
android_rela: bool
dt_hash: bool
dyn_str: bool
dynamic_section: bool
Expand All @@ -558,6 +567,7 @@ class Builder:
notes: bool
preinit_array: bool
rela: bool
relr: bool
static_symtab: bool
sym_verdef: bool
sym_verneed: bool
Expand Down Expand Up @@ -1576,6 +1586,26 @@ class ParserConfig:
def all(self) -> lief.ELF.ParserConfig: ...

class Relocation(lief.Relocation):
class ENCODING:
ANDROID_SLEB: ClassVar[Relocation.ENCODING] = ...
REL: ClassVar[Relocation.ENCODING] = ...
RELA: ClassVar[Relocation.ENCODING] = ...
RELR: ClassVar[Relocation.ENCODING] = ...
UNKNOWN: ClassVar[Relocation.ENCODING] = ...
__name__: str
def __init__(self, *args, **kwargs) -> None: ...
@staticmethod
def from_value(arg: int, /) -> lief.ELF.Relocation.ENCODING: ...
def __ge__(self, other) -> bool: ...
def __gt__(self, other) -> bool: ...
def __hash__(self) -> int: ...
def __index__(self) -> Any: ...
def __int__(self) -> int: ...
def __le__(self, other) -> bool: ...
def __lt__(self, other) -> bool: ...
@property
def value(self) -> int: ...

class PURPOSE:
DYNAMIC: ClassVar[Relocation.PURPOSE] = ...
NONE: ClassVar[Relocation.PURPOSE] = ...
Expand Down Expand Up @@ -2545,16 +2575,23 @@ class Relocation(lief.Relocation):
@overload
def __init__(self, arch: lief.ELF.ARCH) -> None: ...
@overload
def __init__(self, address: int, type: lief.ELF.Relocation.TYPE, is_rela: bool = ...) -> None: ...
def __init__(self, address: int, type: lief.ELF.Relocation.TYPE, encoding: lief.ELF.Relocation.ENCODING) -> None: ...
def r_info(self, clazz: lief.ELF.Header.CLASS) -> int: ...
@property
def encoding(self) -> lief.ELF.Relocation.ENCODING: ...
@property
def has_section(self) -> bool: ...
@property
def has_symbol(self) -> bool: ...
@property
def is_android_packed(self) -> bool: ...
@property
def is_rel(self) -> bool: ...
@property
def is_rela(self) -> bool: ...
@property
def is_relatively_encoded(self) -> bool: ...
@property
def section(self) -> lief.ELF.Section: ...
@property
def symbol_table(self) -> lief.ELF.Section: ...
Expand Down
28 changes: 28 additions & 0 deletions api/python/src/ELF/objects/pyBinary.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,34 @@ void create<Binary>(nb::module_& m) {
"Patch the imported " RST_CLASS_REF(lief.ELF.Symbol) " with the ``address``"_doc,
"symbol"_a, "address"_a)

.def("dynsym_idx",
nb::overload_cast<const std::string&>(&Binary::dynsym_idx, nb::const_),
R"doc(
Get the symbol index in the **dynamic** symbol from the given name or
return -1 if the symbol does not exist.
)doc"_doc, "name"_a)

.def("dynsym_idx",
nb::overload_cast<const Symbol&>(&Binary::dynsym_idx, nb::const_),
R"doc(
Get the symbol index in the **dynamic** symbol table for the given symbol
or return -1 if the symbol does not exist
)doc"_doc, "symbol"_a)

.def("symtab_idx",
nb::overload_cast<const std::string&>(&Binary::symtab_idx, nb::const_),
R"doc(
Get the symbol index in the ``.symtab`` section from the given name or
return -1 if the symbol does not exist.
)doc"_doc, "name"_a)

.def("symtab_idx",
nb::overload_cast<const Symbol&>(&Binary::symtab_idx, nb::const_),
R"doc(
Get the symbol index in the ``.symtab`` section or return -1 if the
symbol does not exist
)doc"_doc, "symbol"_a)

.def("has_section",
&Binary::has_section,
"Check if a " RST_CLASS_REF(lief.ELF.Section) " with the given name exists in the binary"_doc,
Expand Down
2 changes: 2 additions & 0 deletions api/python/src/ELF/objects/pyBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ void create<Builder>(nb::module_& m) {
.def_rw("jmprel", &Builder::config_t::jmprel, "Rebuild :attr:`~lief.ELF.DynamicEntry.TAG.JMPREL`"_doc)
.def_rw("notes", &Builder::config_t::notes, "Rebuild `PT_NOTES` segment(s)"_doc)
.def_rw("preinit_array", &Builder::config_t::preinit_array, "Rebuild :attr:`~lief.ELF.DynamicEntry.TAG.PREINIT_ARRAY`"_doc)
.def_rw("relr", &Builder::config_t::relr, "Rebuild :attr:`~lief.ELF.DynamicEntry.TAG.RELR`"_doc)
.def_rw("android_rela", &Builder::config_t::android_rela, "Rebuild :attr:`~lief.ELF.DynamicEntry.TAG.ANDROID_RELA`"_doc)
.def_rw("rela", &Builder::config_t::rela, "Rebuild :attr:`~lief.ELF.DynamicEntry.TAG.RELA`"_doc)
.def_rw("static_symtab", &Builder::config_t::static_symtab, "Rebuild `.symtab` section"_doc)
.def_rw("sym_verdef", &Builder::config_t::sym_verdef, "Rebuild :attr:`~lief.ELF.DynamicEntry.TAG.VERDEF`"_doc)
Expand Down
35 changes: 33 additions & 2 deletions api/python/src/ELF/objects/pyRelocation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,22 @@ void create<Relocation>(nb::module_& m) {
.value("DYNAMIC", Relocation::PURPOSE::DYNAMIC)
.value("OBJECT", Relocation::PURPOSE::OBJECT);

enum_<Relocation::ENCODING>(reloc, "ENCODING")
.value("UNKNOWN", Relocation::ENCODING::UNKNOWN)
.value("ANDROID_SLEB", Relocation::ENCODING::ANDROID_SLEB,
"The relocation is using the packed Android-SLEB128 format"_doc)
.value("REL", Relocation::ENCODING::REL,
"The relocation is using the regular Elf_Rel structure"_doc)
.value("RELR", Relocation::ENCODING::RELR,
"The relocation is using the relative relocation format"_doc)
.value("RELA", Relocation::ENCODING::RELA,
"The relocation is using the regular Elf_Rela structure"_doc);

reloc
.def(nb::init<>())
.def(nb::init<ARCH>(), "arch"_a)
.def(nb::init<uint64_t, Relocation::TYPE, bool>(),
"address"_a, "type"_a = Relocation::TYPE::UNKNOWN, "is_rela"_a = false)
.def(nb::init<uint64_t, Relocation::TYPE, Relocation::ENCODING>(),
"address"_a, "type"_a, "encoding"_a)

.def_prop_rw("addend",
nb::overload_cast<>(&Relocation::addend, nb::const_),
Expand Down Expand Up @@ -115,6 +126,26 @@ void create<Relocation>(nb::module_& m) {
&Relocation::is_rel,
"``True`` if the relocation **doesn't use** the :attr:`~lief.ELF.Relocation.addend` proprety"_doc)

.def("r_info", &Relocation::r_info,
R"delim(
(re)Compute the raw ``r_info`` attribute based on the given ELF class
)delim"_doc, "clazz"_a)

.def_prop_ro("is_relatively_encoded", &Relocation::is_relatively_encoded,
"True if the relocation is using the relative encoding"_doc)

.def_prop_ro("is_android_packed", &Relocation::is_android_packed,
"True if the relocation is using the Android packed relocation format"_doc)

.def_prop_ro("is_rel", &Relocation::is_rel,
R"delim(
Check if the relocation uses the implicit addend
(i.e. not present in the ELF structure)
)delim"_doc)

.def_prop_ro("encoding", &Relocation::encoding,
"The encoding of the relocation")

LIEF_DEFAULT_STR(Relocation);
}

Expand Down
3 changes: 3 additions & 0 deletions doc/sphinx/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ Changelog
* ``RELOC_x86_64``, ``RELOC_i386``, ... have been re-scoped **and merged**
into :class:`lief.ELF.Relocation.TYPE`

* Add support for Android packed relocation format (``DT_ANDROID_REL{A}``)
* Add support for relative relocation format (``DT_RELR``)

:CMake:

* ``LIEFConfig.cmake`` is now installed in ``<prefix>/lib/cmake/LIEF/``
Expand Down
12 changes: 12 additions & 0 deletions include/LIEF/ELF/Binary.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,7 @@ class LIEF_API Binary : public LIEF::Binary {
it_dynamic_symbols dynamic_symbols() {
return dynamic_symbols_;
}

it_const_dynamic_symbols dynamic_symbols() const {
return dynamic_symbols_;
}
Expand Down Expand Up @@ -721,6 +722,17 @@ class LIEF_API Binary : public LIEF::Binary {
//! Check if the binary uses the ``NX`` protection (Non executable stack)
bool has_nx() const override;

//! Symbol index in the dynamic symbol table or -1 if the symbol
//! does not exist.
int64_t dynsym_idx(const std::string& name) const;

int64_t dynsym_idx(const Symbol& sym) const;

//! Symbol index from the `.symtab` section or -1 if the symbol is not present
int64_t symtab_idx(const std::string& name) const;

int64_t symtab_idx(const Symbol& sym) const;

//! Return the ELF::Section from the given @p offset. Return a nullptr
//! if a section can't be found
//!
Expand Down
8 changes: 8 additions & 0 deletions include/LIEF/ELF/Builder.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ class LIEF_API Builder {
bool jmprel = true; /// Rebuild DT_JMPREL
bool notes = false; /// Disable note building since it can break the default layout
bool preinit_array = true; /// Rebuild DT_PREINIT_ARRAY
bool relr = true; /// Rebuild DT_RELR
bool android_rela = true; /// Rebuild DT_ANDROID_REL[A]
bool rela = true; /// Rebuild DT_REL[A]
bool static_symtab = true; /// Rebuild `.symtab`
bool sym_verdef = true; /// Rebuild DT_VERDEF
Expand Down Expand Up @@ -140,6 +142,12 @@ class LIEF_API Builder {
template<typename ELF_T>
ok_error_t build_dynamic_relocations();

template<typename ELF_T>
ok_error_t build_relative_relocations();

template<typename ELF_T>
ok_error_t build_android_relocations();

template<typename ELF_T>
ok_error_t build_pltgot_relocations();

Expand Down
14 changes: 14 additions & 0 deletions include/LIEF/ELF/Parser.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ class Binary;
class Segment;
class Symbol;
class Note;
class Relocation;

//! Class which parses and transforms an ELF file into a ELF::Binary object
class LIEF_API Parser : public LIEF::Parser {
Expand Down Expand Up @@ -188,6 +189,17 @@ class LIEF_API Parser : public LIEF::Parser {
ok_error_t parse_pltgot_relocations(uint64_t offset, uint64_t size);


//! Parse *relative* relocations
template<typename ELF_T>
ok_error_t parse_relative_relocations(uint64_t offset, uint64_t size);

//! Parse Android packed relocations
template<typename ELF_T>
ok_error_t parse_packed_relocations(uint64_t offset, uint64_t size);

template<typename ELF_T>
ok_error_t process_dynamic_table();

//! Parse relocations using LIEF::ELF::Section.
//! Section relocations are usually found in object files
template<typename ELF_T, typename REL_T>
Expand Down Expand Up @@ -241,6 +253,8 @@ class LIEF_API Parser : public LIEF::Parser {
//! Check if the given Section is wrapped by the given segment
static bool check_section_in_segment(const Section& section, const Segment& segment);

bool bind_symbol(Relocation& R);

std::unique_ptr<BinaryStream> stream_;
std::unique_ptr<Binary> binary_;
ParserConfig config_;
Expand Down
56 changes: 49 additions & 7 deletions include/LIEF/ELF/Relocation.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include "LIEF/Abstract/Relocation.hpp"

#include "LIEF/ELF/enums.hpp"
#include "LIEF/ELF/Header.hpp"

namespace LIEF {
namespace ELF {
Expand Down Expand Up @@ -52,6 +53,14 @@ class LIEF_API Relocation : public LIEF::Relocation {
OBJECT = 3, ///< The relocation is used in an object file
};

enum class ENCODING {
UNKNOWN = 0,
REL, ///< The relocation is using the regular Elf_Rel structure
RELA, ///< The relocation is using the regular Elf_Rela structure
RELR, ///< The relocation is using the relative relocation format
ANDROID_SLEB, ///< The relocation is using the packed Android-SLEB128 format
};

static constexpr uint64_t R_BIT = 27;
static constexpr uint64_t R_MASK = (uint64_t(1) << R_BIT) - 1;

Expand Down Expand Up @@ -122,10 +131,7 @@ class LIEF_API Relocation : public LIEF::Relocation {
return static_cast<uint32_t>(type) & R_MASK;
}

template<class T>
LIEF_LOCAL Relocation(const T& header, PURPOSE purpose, ARCH arch);

Relocation(uint64_t address, TYPE type = TYPE::UNKNOWN, bool is_rela = false);
Relocation(uint64_t address, TYPE type, ENCODING enc);

Relocation() = default;
Relocation(ARCH arch) {
Expand All @@ -150,20 +156,40 @@ class LIEF_API Relocation : public LIEF::Relocation {
/// Check if the relocation uses the explicit addend() field
/// (this is usually the case for 64 bits binaries)
bool is_rela() const {
return isRela_;
return encoding_ == ENCODING::RELA;
}

/// Check if the relocation uses the implicit addend
/// (i.e. not present in the ELF structure)
bool is_rel() const {
return !isRela_;
return encoding_ == ENCODING::REL;
}

/// True if the relocation is using the relative encoding
bool is_relatively_encoded() const {
return encoding_ == ENCODING::RELR;
}

/// True if the relocation is using the Android packed relocation format
bool is_android_packed() const {
return encoding_ == ENCODING::ANDROID_SLEB;
}

/// Relocation info which contains, for instance, the symbol index
uint32_t info() const {
return info_;
}

/// (re)Compute the *raw* `r_info` attribute based on the given ELF class
uint64_t r_info(Header::CLASS clazz) const {
if (clazz == Header::CLASS::NONE) {
return 0;
}
return clazz == Header::CLASS::ELF32 ?
uint32_t(info()) << 8 | to_value(type()) :
uint64_t(info()) << 32 | (to_value(type()) & 0xffffffffL);
}

/// Target architecture for this relocation
ARCH architecture() const {
return architecture_;
Expand All @@ -173,6 +199,19 @@ class LIEF_API Relocation : public LIEF::Relocation {
return purpose_;
}

/// The encoding of the relocation
ENCODING encoding() const {
return encoding_;
}

/// True if the semantic of the relocation is `<ARCH>_RELATIVE`
bool is_relative() const {
return type_ == TYPE::AARCH64_RELATIVE || type_ == TYPE::X86_64_RELATIVE ||
type_ == TYPE::X86_RELATIVE || type_ == TYPE::ARM_RELATIVE ||
type_ == TYPE::HEX_RELATIVE || type_ == TYPE::PPC64_RELATIVE ||
type_ == TYPE::PPC_RELATIVE;
}

/// Return the size (in **bits**) of the value associated with this relocation
/// Return -1 if the size can't be determined
size_t size() const override;
Expand Down Expand Up @@ -247,9 +286,12 @@ class LIEF_API Relocation : public LIEF::Relocation {
LIEF_API friend std::ostream& operator<<(std::ostream& os, const Relocation& entry);

private:
template<class T>
LIEF_LOCAL Relocation(const T& header, PURPOSE purpose, ENCODING enc, ARCH arch);

TYPE type_ = TYPE::UNKNOWN;
int64_t addend_ = 0;
bool isRela_ = false;
ENCODING encoding_ = ENCODING::UNKNOWN;
Symbol* symbol_ = nullptr;
ARCH architecture_ = ARCH::NONE;
PURPOSE purpose_ = PURPOSE::NONE;
Expand Down
Loading

0 comments on commit 00e4a68

Please sign in to comment.