Projects STRLCPY LIEF Commits 00e4a684
🤬
  • Add support for `DT_RELR/DT_ANDROID_RELA` relocations

    This commit adds the support for the (new) relative relocations
    as well as the Android packed relocation format.
    
    Resolve: #111 #991
  • Loading...
  • Romain Thomas committed 3 months ago
    00e4a684
    1 parent 0fe1a845
  • ■ ■ ■ ■ ■ ■
    api/python/lief/ELF.pyi
    skipped 368 lines
    369 369   def add_pltgot_relocation(self, relocation: lief.ELF.Relocation) -> lief.ELF.Relocation: ...
    370 370   def add_symtab_symbol(self, symbol: lief.ELF.Symbol) -> lief.ELF.Symbol: ...
    371 371   @overload
     372 + def dynsym_idx(self, name: str) -> int: ...
     373 + @overload
     374 + def dynsym_idx(self, symbol: lief.ELF.Symbol) -> int: ...
     375 + @overload
    372 376   def export_symbol(self, symbol: lief.ELF.Symbol) -> lief.ELF.Symbol: ...
    373 377   @overload
    374 378   def export_symbol(self, symbol_name: str, value: int = ...) -> lief.ELF.Symbol: ...
    skipped 62 lines
    437 441   def segment_from_offset(self, offset: int) -> lief.ELF.Segment: ...
    438 442   def segment_from_virtual_address(self, address: int) -> lief.ELF.Segment: ...
    439 443   def strip(self) -> None: ...
     444 + @overload
     445 + def symtab_idx(self, name: str) -> int: ...
     446 + @overload
     447 + def symtab_idx(self, symbol: lief.ELF.Symbol) -> int: ...
    440 448   def virtual_address_to_offset(self, virtual_address: int) -> Union[int,lief.lief_errors]: ...
    441 449   @overload
    442 450   def write(self, output: str) -> None: ...
    skipped 104 lines
    547 555   
    548 556  class Builder:
    549 557   class config_t:
     558 + android_rela: bool
    550 559   dt_hash: bool
    551 560   dyn_str: bool
    552 561   dynamic_section: bool
    skipped 5 lines
    558 567   notes: bool
    559 568   preinit_array: bool
    560 569   rela: bool
     570 + relr: bool
    561 571   static_symtab: bool
    562 572   sym_verdef: bool
    563 573   sym_verneed: bool
    skipped 1012 lines
    1576 1586   def all(self) -> lief.ELF.ParserConfig: ...
    1577 1587   
    1578 1588  class Relocation(lief.Relocation):
     1589 + class ENCODING:
     1590 + ANDROID_SLEB: ClassVar[Relocation.ENCODING] = ...
     1591 + REL: ClassVar[Relocation.ENCODING] = ...
     1592 + RELA: ClassVar[Relocation.ENCODING] = ...
     1593 + RELR: ClassVar[Relocation.ENCODING] = ...
     1594 + UNKNOWN: ClassVar[Relocation.ENCODING] = ...
     1595 + __name__: str
     1596 + def __init__(self, *args, **kwargs) -> None: ...
     1597 + @staticmethod
     1598 + def from_value(arg: int, /) -> lief.ELF.Relocation.ENCODING: ...
     1599 + def __ge__(self, other) -> bool: ...
     1600 + def __gt__(self, other) -> bool: ...
     1601 + def __hash__(self) -> int: ...
     1602 + def __index__(self) -> Any: ...
     1603 + def __int__(self) -> int: ...
     1604 + def __le__(self, other) -> bool: ...
     1605 + def __lt__(self, other) -> bool: ...
     1606 + @property
     1607 + def value(self) -> int: ...
     1608 + 
    1579 1609   class PURPOSE:
    1580 1610   DYNAMIC: ClassVar[Relocation.PURPOSE] = ...
    1581 1611   NONE: ClassVar[Relocation.PURPOSE] = ...
    skipped 963 lines
    2545 2575   @overload
    2546 2576   def __init__(self, arch: lief.ELF.ARCH) -> None: ...
    2547 2577   @overload
    2548  - def __init__(self, address: int, type: lief.ELF.Relocation.TYPE, is_rela: bool = ...) -> None: ...
     2578 + def __init__(self, address: int, type: lief.ELF.Relocation.TYPE, encoding: lief.ELF.Relocation.ENCODING) -> None: ...
     2579 + def r_info(self, clazz: lief.ELF.Header.CLASS) -> int: ...
     2580 + @property
     2581 + def encoding(self) -> lief.ELF.Relocation.ENCODING: ...
    2549 2582   @property
    2550 2583   def has_section(self) -> bool: ...
    2551 2584   @property
    2552 2585   def has_symbol(self) -> bool: ...
    2553 2586   @property
     2587 + def is_android_packed(self) -> bool: ...
     2588 + @property
    2554 2589   def is_rel(self) -> bool: ...
    2555 2590   @property
    2556 2591   def is_rela(self) -> bool: ...
     2592 + @property
     2593 + def is_relatively_encoded(self) -> bool: ...
    2557 2594   @property
    2558 2595   def section(self) -> lief.ELF.Section: ...
    2559 2596   @property
    skipped 571 lines
  • ■ ■ ■ ■ ■ ■
    api/python/src/ELF/objects/pyBinary.cpp
    skipped 398 lines
    399 399   "Patch the imported " RST_CLASS_REF(lief.ELF.Symbol) " with the ``address``"_doc,
    400 400   "symbol"_a, "address"_a)
    401 401   
     402 + .def("dynsym_idx",
     403 + nb::overload_cast<const std::string&>(&Binary::dynsym_idx, nb::const_),
     404 + R"doc(
     405 + Get the symbol index in the **dynamic** symbol from the given name or
     406 + return -1 if the symbol does not exist.
     407 + )doc"_doc, "name"_a)
     408 + 
     409 + .def("dynsym_idx",
     410 + nb::overload_cast<const Symbol&>(&Binary::dynsym_idx, nb::const_),
     411 + R"doc(
     412 + Get the symbol index in the **dynamic** symbol table for the given symbol
     413 + or return -1 if the symbol does not exist
     414 + )doc"_doc, "symbol"_a)
     415 + 
     416 + .def("symtab_idx",
     417 + nb::overload_cast<const std::string&>(&Binary::symtab_idx, nb::const_),
     418 + R"doc(
     419 + Get the symbol index in the ``.symtab`` section from the given name or
     420 + return -1 if the symbol does not exist.
     421 + )doc"_doc, "name"_a)
     422 + 
     423 + .def("symtab_idx",
     424 + nb::overload_cast<const Symbol&>(&Binary::symtab_idx, nb::const_),
     425 + R"doc(
     426 + Get the symbol index in the ``.symtab`` section or return -1 if the
     427 + symbol does not exist
     428 + )doc"_doc, "symbol"_a)
     429 + 
    402 430   .def("has_section",
    403 431   &Binary::has_section,
    404 432   "Check if a " RST_CLASS_REF(lief.ELF.Section) " with the given name exists in the binary"_doc,
    skipped 376 lines
  • ■ ■ ■ ■ ■ ■
    api/python/src/ELF/objects/pyBuilder.cpp
    skipped 45 lines
    46 46   .def_rw("jmprel", &Builder::config_t::jmprel, "Rebuild :attr:`~lief.ELF.DynamicEntry.TAG.JMPREL`"_doc)
    47 47   .def_rw("notes", &Builder::config_t::notes, "Rebuild `PT_NOTES` segment(s)"_doc)
    48 48   .def_rw("preinit_array", &Builder::config_t::preinit_array, "Rebuild :attr:`~lief.ELF.DynamicEntry.TAG.PREINIT_ARRAY`"_doc)
     49 + .def_rw("relr", &Builder::config_t::relr, "Rebuild :attr:`~lief.ELF.DynamicEntry.TAG.RELR`"_doc)
     50 + .def_rw("android_rela", &Builder::config_t::android_rela, "Rebuild :attr:`~lief.ELF.DynamicEntry.TAG.ANDROID_RELA`"_doc)
    49 51   .def_rw("rela", &Builder::config_t::rela, "Rebuild :attr:`~lief.ELF.DynamicEntry.TAG.RELA`"_doc)
    50 52   .def_rw("static_symtab", &Builder::config_t::static_symtab, "Rebuild `.symtab` section"_doc)
    51 53   .def_rw("sym_verdef", &Builder::config_t::sym_verdef, "Rebuild :attr:`~lief.ELF.DynamicEntry.TAG.VERDEF`"_doc)
    skipped 33 lines
  • ■ ■ ■ ■ ■ ■
    api/python/src/ELF/objects/pyRelocation.cpp
    skipped 42 lines
    43 43   .value("DYNAMIC", Relocation::PURPOSE::DYNAMIC)
    44 44   .value("OBJECT", Relocation::PURPOSE::OBJECT);
    45 45   
     46 + enum_<Relocation::ENCODING>(reloc, "ENCODING")
     47 + .value("UNKNOWN", Relocation::ENCODING::UNKNOWN)
     48 + .value("ANDROID_SLEB", Relocation::ENCODING::ANDROID_SLEB,
     49 + "The relocation is using the packed Android-SLEB128 format"_doc)
     50 + .value("REL", Relocation::ENCODING::REL,
     51 + "The relocation is using the regular Elf_Rel structure"_doc)
     52 + .value("RELR", Relocation::ENCODING::RELR,
     53 + "The relocation is using the relative relocation format"_doc)
     54 + .value("RELA", Relocation::ENCODING::RELA,
     55 + "The relocation is using the regular Elf_Rela structure"_doc);
     56 + 
    46 57   reloc
    47 58   .def(nb::init<>())
    48 59   .def(nb::init<ARCH>(), "arch"_a)
    49  - .def(nb::init<uint64_t, Relocation::TYPE, bool>(),
    50  - "address"_a, "type"_a = Relocation::TYPE::UNKNOWN, "is_rela"_a = false)
     60 + .def(nb::init<uint64_t, Relocation::TYPE, Relocation::ENCODING>(),
     61 + "address"_a, "type"_a, "encoding"_a)
    51 62   
    52 63   .def_prop_rw("addend",
    53 64   nb::overload_cast<>(&Relocation::addend, nb::const_),
    skipped 60 lines
    114 125   .def_prop_ro("is_rel",
    115 126   &Relocation::is_rel,
    116 127   "``True`` if the relocation **doesn't use** the :attr:`~lief.ELF.Relocation.addend` proprety"_doc)
     128 + 
     129 + .def("r_info", &Relocation::r_info,
     130 + R"delim(
     131 + (re)Compute the raw ``r_info`` attribute based on the given ELF class
     132 + )delim"_doc, "clazz"_a)
     133 + 
     134 + .def_prop_ro("is_relatively_encoded", &Relocation::is_relatively_encoded,
     135 + "True if the relocation is using the relative encoding"_doc)
     136 + 
     137 + .def_prop_ro("is_android_packed", &Relocation::is_android_packed,
     138 + "True if the relocation is using the Android packed relocation format"_doc)
     139 + 
     140 + .def_prop_ro("is_rel", &Relocation::is_rel,
     141 + R"delim(
     142 + Check if the relocation uses the implicit addend
     143 + (i.e. not present in the ELF structure)
     144 + )delim"_doc)
     145 + 
     146 + .def_prop_ro("encoding", &Relocation::encoding,
     147 + "The encoding of the relocation")
    117 148   
    118 149   LIEF_DEFAULT_STR(Relocation);
    119 150  }
    skipped 3 lines
  • ■ ■ ■ ■ ■ ■
    doc/sphinx/changelog.rst
    skipped 34 lines
    35 35   * ``RELOC_x86_64``, ``RELOC_i386``, ... have been re-scoped **and merged**
    36 36   into :class:`lief.ELF.Relocation.TYPE`
    37 37   
     38 + * Add support for Android packed relocation format (``DT_ANDROID_REL{A}``)
     39 + * Add support for relative relocation format (``DT_RELR``)
     40 + 
    38 41  :CMake:
    39 42   
    40 43   * ``LIEFConfig.cmake`` is now installed in ``<prefix>/lib/cmake/LIEF/``
    skipped 1358 lines
  • ■ ■ ■ ■ ■ ■
    include/LIEF/ELF/Binary.hpp
    skipped 316 lines
    317 317   it_dynamic_symbols dynamic_symbols() {
    318 318   return dynamic_symbols_;
    319 319   }
     320 + 
    320 321   it_const_dynamic_symbols dynamic_symbols() const {
    321 322   return dynamic_symbols_;
    322 323   }
    skipped 397 lines
    720 721   
    721 722   //! Check if the binary uses the ``NX`` protection (Non executable stack)
    722 723   bool has_nx() const override;
     724 + 
     725 + //! Symbol index in the dynamic symbol table or -1 if the symbol
     726 + //! does not exist.
     727 + int64_t dynsym_idx(const std::string& name) const;
     728 + 
     729 + int64_t dynsym_idx(const Symbol& sym) const;
     730 + 
     731 + //! Symbol index from the `.symtab` section or -1 if the symbol is not present
     732 + int64_t symtab_idx(const std::string& name) const;
     733 + 
     734 + int64_t symtab_idx(const Symbol& sym) const;
    723 735   
    724 736   //! Return the ELF::Section from the given @p offset. Return a nullptr
    725 737   //! if a section can't be found
    skipped 297 lines
  • ■ ■ ■ ■ ■ ■
    include/LIEF/ELF/Builder.hpp
    skipped 65 lines
    66 66   bool jmprel = true; /// Rebuild DT_JMPREL
    67 67   bool notes = false; /// Disable note building since it can break the default layout
    68 68   bool preinit_array = true; /// Rebuild DT_PREINIT_ARRAY
     69 + bool relr = true; /// Rebuild DT_RELR
     70 + bool android_rela = true; /// Rebuild DT_ANDROID_REL[A]
    69 71   bool rela = true; /// Rebuild DT_REL[A]
    70 72   bool static_symtab = true; /// Rebuild `.symtab`
    71 73   bool sym_verdef = true; /// Rebuild DT_VERDEF
    skipped 67 lines
    139 141   
    140 142   template<typename ELF_T>
    141 143   ok_error_t build_dynamic_relocations();
     144 + 
     145 + template<typename ELF_T>
     146 + ok_error_t build_relative_relocations();
     147 + 
     148 + template<typename ELF_T>
     149 + ok_error_t build_android_relocations();
    142 150   
    143 151   template<typename ELF_T>
    144 152   ok_error_t build_pltgot_relocations();
    skipped 54 lines
  • ■ ■ ■ ■ ■ ■
    include/LIEF/ELF/Parser.hpp
    skipped 38 lines
    39 39  class Segment;
    40 40  class Symbol;
    41 41  class Note;
     42 +class Relocation;
    42 43   
    43 44  //! Class which parses and transforms an ELF file into a ELF::Binary object
    44 45  class LIEF_API Parser : public LIEF::Parser {
    skipped 143 lines
    188 189   ok_error_t parse_pltgot_relocations(uint64_t offset, uint64_t size);
    189 190   
    190 191   
     192 + //! Parse *relative* relocations
     193 + template<typename ELF_T>
     194 + ok_error_t parse_relative_relocations(uint64_t offset, uint64_t size);
     195 + 
     196 + //! Parse Android packed relocations
     197 + template<typename ELF_T>
     198 + ok_error_t parse_packed_relocations(uint64_t offset, uint64_t size);
     199 + 
     200 + template<typename ELF_T>
     201 + ok_error_t process_dynamic_table();
     202 + 
    191 203   //! Parse relocations using LIEF::ELF::Section.
    192 204   //! Section relocations are usually found in object files
    193 205   template<typename ELF_T, typename REL_T>
    skipped 46 lines
    240 252   
    241 253   //! Check if the given Section is wrapped by the given segment
    242 254   static bool check_section_in_segment(const Section& section, const Segment& segment);
     255 + 
     256 + bool bind_symbol(Relocation& R);
    243 257   
    244 258   std::unique_ptr<BinaryStream> stream_;
    245 259   std::unique_ptr<Binary> binary_;
    skipped 15 lines
  • ■ ■ ■ ■ ■
    include/LIEF/ELF/Relocation.hpp
    skipped 24 lines
    25 25  #include "LIEF/Abstract/Relocation.hpp"
    26 26   
    27 27  #include "LIEF/ELF/enums.hpp"
     28 +#include "LIEF/ELF/Header.hpp"
    28 29   
    29 30  namespace LIEF {
    30 31  namespace ELF {
    skipped 19 lines
    50 51   PLTGOT = 1, ///< The relocation is associated with the PLT/GOT resolution
    51 52   DYNAMIC = 2, ///< The relocation is used for regulard data/code relocation
    52 53   OBJECT = 3, ///< The relocation is used in an object file
     54 + };
     55 + 
     56 + enum class ENCODING {
     57 + UNKNOWN = 0,
     58 + REL, ///< The relocation is using the regular Elf_Rel structure
     59 + RELA, ///< The relocation is using the regular Elf_Rela structure
     60 + RELR, ///< The relocation is using the relative relocation format
     61 + ANDROID_SLEB, ///< The relocation is using the packed Android-SLEB128 format
    53 62   };
    54 63   
    55 64   static constexpr uint64_t R_BIT = 27;
    skipped 66 lines
    122 131   return static_cast<uint32_t>(type) & R_MASK;
    123 132   }
    124 133   
    125  - template<class T>
    126  - LIEF_LOCAL Relocation(const T& header, PURPOSE purpose, ARCH arch);
    127  - 
    128  - Relocation(uint64_t address, TYPE type = TYPE::UNKNOWN, bool is_rela = false);
     134 + Relocation(uint64_t address, TYPE type, ENCODING enc);
    129 135   
    130 136   Relocation() = default;
    131 137   Relocation(ARCH arch) {
    skipped 18 lines
    150 156   /// Check if the relocation uses the explicit addend() field
    151 157   /// (this is usually the case for 64 bits binaries)
    152 158   bool is_rela() const {
    153  - return isRela_;
     159 + return encoding_ == ENCODING::RELA;
    154 160   }
    155 161   
    156 162   /// Check if the relocation uses the implicit addend
    157 163   /// (i.e. not present in the ELF structure)
    158 164   bool is_rel() const {
    159  - return !isRela_;
     165 + return encoding_ == ENCODING::REL;
     166 + }
     167 + 
     168 + /// True if the relocation is using the relative encoding
     169 + bool is_relatively_encoded() const {
     170 + return encoding_ == ENCODING::RELR;
     171 + }
     172 + 
     173 + /// True if the relocation is using the Android packed relocation format
     174 + bool is_android_packed() const {
     175 + return encoding_ == ENCODING::ANDROID_SLEB;
    160 176   }
    161 177   
    162 178   /// Relocation info which contains, for instance, the symbol index
    skipped 1 lines
    164 180   return info_;
    165 181   }
    166 182   
     183 + /// (re)Compute the *raw* `r_info` attribute based on the given ELF class
     184 + uint64_t r_info(Header::CLASS clazz) const {
     185 + if (clazz == Header::CLASS::NONE) {
     186 + return 0;
     187 + }
     188 + return clazz == Header::CLASS::ELF32 ?
     189 + uint32_t(info()) << 8 | to_value(type()) :
     190 + uint64_t(info()) << 32 | (to_value(type()) & 0xffffffffL);
     191 + }
     192 + 
    167 193   /// Target architecture for this relocation
    168 194   ARCH architecture() const {
    169 195   return architecture_;
    skipped 1 lines
    171 197   
    172 198   PURPOSE purpose() const {
    173 199   return purpose_;
     200 + }
     201 + 
     202 + /// The encoding of the relocation
     203 + ENCODING encoding() const {
     204 + return encoding_;
     205 + }
     206 + 
     207 + /// True if the semantic of the relocation is `<ARCH>_RELATIVE`
     208 + bool is_relative() const {
     209 + return type_ == TYPE::AARCH64_RELATIVE || type_ == TYPE::X86_64_RELATIVE ||
     210 + type_ == TYPE::X86_RELATIVE || type_ == TYPE::ARM_RELATIVE ||
     211 + type_ == TYPE::HEX_RELATIVE || type_ == TYPE::PPC64_RELATIVE ||
     212 + type_ == TYPE::PPC_RELATIVE;
    174 213   }
    175 214   
    176 215   /// Return the size (in **bits**) of the value associated with this relocation
    skipped 70 lines
    247 286   LIEF_API friend std::ostream& operator<<(std::ostream& os, const Relocation& entry);
    248 287   
    249 288   private:
     289 + template<class T>
     290 + LIEF_LOCAL Relocation(const T& header, PURPOSE purpose, ENCODING enc, ARCH arch);
     291 + 
    250 292   TYPE type_ = TYPE::UNKNOWN;
    251 293   int64_t addend_ = 0;
    252  - bool isRela_ = false;
     294 + ENCODING encoding_ = ENCODING::UNKNOWN;
    253 295   Symbol* symbol_ = nullptr;
    254 296   ARCH architecture_ = ARCH::NONE;
    255 297   PURPOSE purpose_ = PURPOSE::NONE;
    skipped 11 lines
  • ■ ■ ■ ■ ■ ■
    include/LIEF/errors.hpp
    skipped 104 lines
    105 105  //! \endcode
    106 106  using ok_error_t = result<ok_t>;
    107 107   
     108 +inline bool is_ok(const ok_error_t& val) {
     109 + return val.has_value();
     110 +}
     111 + 
     112 +inline bool is_err(const ok_error_t& val) {
     113 + return !is_ok(val);
     114 +}
     115 + 
    108 116  }
    109 117   
    110 118   
    skipped 5 lines
  • ■ ■ ■ ■ ■ ■
    src/Abstract/Relocation.cpp
    skipped 60 lines
    61 61   visitor.visit(*this);
    62 62  }
    63 63   
    64  - 
    65  - 
    66  - 
    67  - 
    68 64  bool Relocation::operator<(const Relocation& rhs) const {
    69 65   return address() < rhs.address();
    70 66  }
    skipped 23 lines
  • ■ ■ ■ ■ ■ ■
    src/ELF/Binary.cpp
    skipped 68 lines
    69 69   
    70 70   
    71 71  inline size_t get_relocation_sizeof(const Binary& bin, const Relocation& R) {
    72  - const bool is64 = (bin.type() == Header::CLASS::ELF64);
    73  - const bool is_rela = R.is_rela();
    74  - 
    75  - return is64 ?
    76  - (is_rela ? sizeof(details::Elf64_Rela) : sizeof(details::Elf64_Rel)) :
    77  - (is_rela ? sizeof(details::Elf32_Rela) : sizeof(details::Elf32_Rel));
     72 + const bool is64 = bin.type() == Header::CLASS::ELF64;
     73 + if (R.is_rel() || R.is_rela()) {
     74 + return is64 ?
     75 + (R.is_rela() ? sizeof(details::Elf64_Rela) : sizeof(details::Elf64_Rel)) :
     76 + (R.is_rela() ? sizeof(details::Elf32_Rela) : sizeof(details::Elf32_Rel));
     77 + }
     78 + LIEF_WARN("get_relocation_sizeof() only supports REL/RELA encoding");
     79 + return size_t(-1);
    78 80  }
    79 81   
    80 82  Binary::Binary() :
    81 83   LIEF::Binary(LIEF::Binary::FORMATS::ELF),
    82 84   sizing_info_{std::make_unique<sizing_info_t>()}
    83  -{
    84  - 
    85  -}
     85 +{}
    86 86   
    87 87  size_t Binary::hash(const std::string& name) {
    88 88   if (type_ == Header::CLASS::ELF32) {
    skipped 170 lines
    259 259   }
    260 260  }
    261 261   
     262 + 
     263 +int64_t Binary::symtab_idx(const std::string& name) const {
     264 + if (symtab_symbols_.empty()) {
     265 + return -1;
     266 + }
     267 + 
     268 + auto it = std::find_if(symtab_symbols_.begin(), symtab_symbols_.end(),
     269 + [&name] (const std::unique_ptr<Symbol>& S) {
     270 + return S->name() == name;
     271 + }
     272 + );
     273 + 
     274 + if (it == symtab_symbols_.end()) {
     275 + return -1;
     276 + }
     277 + 
     278 + return std::distance(symtab_symbols_.begin(), it);
     279 +}
     280 + 
     281 +int64_t Binary::symtab_idx(const Symbol& sym) const {
     282 + return symtab_idx(sym.name());
     283 +}
     284 + 
     285 +int64_t Binary::dynsym_idx(const Symbol& sym) const {
     286 + return dynsym_idx(sym.name());
     287 +}
     288 + 
     289 +int64_t Binary::dynsym_idx(const std::string& name) const {
     290 + if (dynamic_symbols_.empty()) {
     291 + return -1;
     292 + }
     293 + 
     294 + auto it = std::find_if(dynamic_symbols_.begin(), dynamic_symbols_.end(),
     295 + [&name] (const std::unique_ptr<Symbol>& S) {
     296 + return S->name() == name;
     297 + }
     298 + );
     299 + if (it == dynamic_symbols_.end()) {
     300 + return -1;
     301 + }
     302 + return std::distance(dynamic_symbols_.begin(), it);
     303 +}
    262 304   
    263 305   
    264 306  Symbol& Binary::export_symbol(const Symbol& symbol) {
    skipped 392 lines
    657 699  }
    658 700   
    659 701  Relocation& Binary::add_dynamic_relocation(const Relocation& relocation) {
     702 + if (!relocation.is_rel() && !relocation.is_rela()) {
     703 + LIEF_WARN("LIEF only supports regulard rel/rela relocations");
     704 + static Relocation None;
     705 + return None;
     706 + }
    660 707   auto relocation_ptr = std::make_unique<Relocation>(relocation);
    661 708   relocation_ptr->purpose(Relocation::PURPOSE::DYNAMIC);
    662 709   relocation_ptr->architecture_ = header().machine_type();
    skipped 1195 lines
    1858 1905   case DynamicEntry::TAG::STRTAB:
    1859 1906   case DynamicEntry::TAG::SYMTAB:
    1860 1907   case DynamicEntry::TAG::RELA:
     1908 + case DynamicEntry::TAG::RELR:
    1861 1909   case DynamicEntry::TAG::REL:
    1862 1910   case DynamicEntry::TAG::JMPREL:
    1863 1911   case DynamicEntry::TAG::INIT:
    skipped 2 lines
    1866 1914   case DynamicEntry::TAG::VERDEF:
    1867 1915   case DynamicEntry::TAG::VERNEED:
    1868 1916   {
    1869  - 
    1870 1917   if (entry->value() >= from) {
    1871 1918   entry->value(entry->value() + shift);
    1872 1919   }
    skipped 48 lines
    1921 1968   
    1922 1969   switch(arch) {
    1923 1970   case ARCH::ARM:
    1924  - {
    1925  - patch_relocations<ARCH::ARM>(from, shift);
    1926  - break;
    1927  - }
     1971 + patch_relocations<ARCH::ARM>(from, shift); return;
    1928 1972   
    1929 1973   case ARCH::AARCH64:
    1930  - {
    1931  - patch_relocations<ARCH::AARCH64>(from, shift);
    1932  - break;
    1933  - }
     1974 + patch_relocations<ARCH::AARCH64>(from, shift); return;
    1934 1975   
    1935 1976   case ARCH::X86_64:
    1936  - {
    1937  - patch_relocations<ARCH::X86_64>(from, shift);
    1938  - break;
    1939  - }
     1977 + patch_relocations<ARCH::X86_64>(from, shift); return;
    1940 1978   
    1941 1979   case ARCH::I386:
    1942  - {
    1943  - patch_relocations<ARCH::I386>(from, shift);
    1944  - break;
    1945  - }
     1980 + patch_relocations<ARCH::I386>(from, shift); return;
    1946 1981   
    1947 1982   case ARCH::PPC:
    1948  - {
    1949  - patch_relocations<ARCH::PPC>(from, shift);
    1950  - break;
    1951  - }
    1952  - 
    1953  - /*
    1954  - case ARCH::PPC64:
    1955  - {
    1956  - patch_relocations<ARCH::PPC64>(from, shift);
    1957  - break;
    1958  - }
    1959  - 
    1960  - case ARCH::RISCV:
    1961  - {
    1962  - patch_relocations<ARCH::RISCV>(from, shift);
    1963  - break;
    1964  - }
    1965  - */
     1983 + patch_relocations<ARCH::PPC>(from, shift); return;
    1966 1984   
    1967 1985   default:
    1968 1986   {
    skipped 1305 lines
  • ■ ■ ■ ■ ■
    src/ELF/Binary.tcc
    skipped 50 lines
    51 51   relocation.address(relocation.address() + shift);
    52 52   }
    53 53   
     54 + if (relocation.encoding() == Relocation::ENCODING::RELR) {
     55 + continue;
     56 + }
     57 + 
    54 58   const Relocation::TYPE type = relocation.type();
    55 59   
    56 60   switch (type) {
    skipped 26 lines
    83 87   if (relocation.address() >= from) {
    84 88   //shift_code(relocation.address(), shift, relocation.size() / 8);
    85 89   relocation.address(relocation.address() + shift);
     90 + }
     91 + 
     92 + if (relocation.encoding() == Relocation::ENCODING::RELR) {
     93 + continue;
    86 94   }
    87 95   
    88 96   const Relocation::TYPE type = relocation.type();
    skipped 64 lines
    153 161   relocation.address(relocation.address() + shift);
    154 162   }
    155 163   
     164 + if (relocation.encoding() == Relocation::ENCODING::RELR) {
     165 + continue;
     166 + }
     167 + 
    156 168   const Relocation::TYPE type = relocation.type();
    157 169   
    158 170   switch (type) {
    skipped 29 lines
    188 200  void Binary::patch_relocations<ARCH::X86_64>(uint64_t from, uint64_t shift) {
    189 201   for (Relocation& relocation : relocations()) {
    190 202   if (relocation.address() >= from) {
    191  - //shift_code(relocation.address(), shift, relocation.size() / 8);
    192 203   relocation.address(relocation.address() + shift);
     204 + }
     205 + 
     206 + if (relocation.encoding() == Relocation::ENCODING::RELR) {
     207 + continue;
    193 208   }
    194 209   
    195 210   const Relocation::TYPE type = relocation.type();
    skipped 57 lines
    253 268   
    254 269  template<class T>
    255 270  void Binary::patch_addend(Relocation& relocation, uint64_t from, uint64_t shift) {
    256  - 
    257 271   if (static_cast<uint64_t>(relocation.addend()) >= from) {
    258 272   relocation.addend(relocation.addend() + shift);
    259 273   }
    skipped 396 lines
  • ■ ■ ■ ■ ■ ■
    src/ELF/Builder.tcc
    skipped 51 lines
    52 52  #include "Object.tcc"
    53 53  #include "ExeLayout.hpp"
    54 54  #include "ObjectFileLayout.hpp"
    55  - 
    56  - 
     55 +#include "internal_utils.hpp"
    57 56   
    58 57  namespace LIEF {
    59 58  namespace ELF {
    skipped 121 lines
    181 180   } else { LIEF_DEBUG("PT_DYNAMIC: -0x{:x} bytes", osize - dynamic_needed_size); }
    182 181   }
    183 182   
    184  - if (binary_->has(DynamicEntry::TAG::RELA) || binary_->has(DynamicEntry::TAG::REL)) {
     183 + if (binary_->has(DynamicEntry::TAG::RELA) ||
     184 + binary_->has(DynamicEntry::TAG::REL))
     185 + {
    185 186   const size_t dyn_reloc_needed_size = layout->dynamic_relocations_size<ELF_T>();
    186 187   if (config_.rela) {
    187 188   const uint64_t osize = binary_->sizing_info_->rela;
    skipped 5 lines
    193 194   }
    194 195   }
    195 196   
     197 + if ((binary_->has(DynamicEntry::TAG::RELR) ||
     198 + binary_->has(DynamicEntry::TAG::ANDROID_RELR)) && config_.relr)
     199 + {
     200 + const size_t relr_reloc_size = layout->relative_relocations_size<ELF_T>();
     201 + const uint64_t osize = binary_->sizing_info_->relr;
     202 + const bool should_relocate = relr_reloc_size > osize || config_.force_relocate;
     203 + if (should_relocate) {
     204 + LIEF_DEBUG("[-] Need to relocate DT_RELR (0x{:x} new bytes)", relr_reloc_size - osize);
     205 + layout->relocate_relr(true);
     206 + } else { LIEF_DEBUG("DT_RELR: -0x{:x} bytes", osize - relr_reloc_size); }
     207 + }
     208 + 
     209 + if ((binary_->has(DynamicEntry::TAG::ANDROID_RELA) ||
     210 + binary_->has(DynamicEntry::TAG::ANDROID_REL)) && config_.android_rela)
     211 + {
     212 + const size_t android_rela_sz = layout->android_relocations_size<ELF_T>();
     213 + const uint64_t osize = binary_->sizing_info_->android_rela;
     214 + const bool should_relocate = android_rela_sz > osize || config_.force_relocate;
     215 + if (should_relocate) {
     216 + LIEF_DEBUG("[-] Need to relocate DT_ANDROID_REL[A] (0x{:x} new bytes)",
     217 + android_rela_sz - osize);
     218 + layout->relocate_android_rela(true);
     219 + } else { LIEF_DEBUG("DT_ANDROID_REL[A]: -0x{:x} bytes", osize - android_rela_sz); }
     220 + }
     221 + 
    196 222   if (config_.jmprel && binary_->has(DynamicEntry::TAG::JMPREL)) {
    197 223   const size_t plt_reloc_needed_size = layout->pltgot_relocations_size<ELF_T>();
    198 224   const uint64_t osize = binary_->sizing_info_->jmprel;
    skipped 24 lines
    223 249   } else { LIEF_DEBUG("DT_SYMTAB: -0x{:x} bytes", osize - dynsym_needed_size); }
    224 250   }
    225 251   
    226  - if (binary_->has(DynamicEntry::TAG::INIT_ARRAY) && binary_->has(DynamicEntry::TAG::INIT_ARRAYSZ) &&
     252 + if (binary_->has(DynamicEntry::TAG::INIT_ARRAY) &&
     253 + binary_->has(DynamicEntry::TAG::INIT_ARRAYSZ) &&
    227 254   config_.init_array)
    228 255   {
    229 256   const size_t needed_size = layout->dynamic_arraysize<ELF_T>(DynamicEntry::TAG::INIT_ARRAY);
    skipped 8 lines
    238 265   } else { LIEF_DEBUG("DT_INIT_ARRAY: -0x{:x} bytes", osize - needed_size); }
    239 266   }
    240 267   
    241  - if (binary_->has(DynamicEntry::TAG::PREINIT_ARRAY) && binary_->has(DynamicEntry::TAG::PREINIT_ARRAYSZ) &&
     268 + if (binary_->has(DynamicEntry::TAG::PREINIT_ARRAY) &&
     269 + binary_->has(DynamicEntry::TAG::PREINIT_ARRAYSZ) &&
    242 270   config_.preinit_array)
    243 271   {
    244 272   const size_t needed_size = layout->dynamic_arraysize<ELF_T>(DynamicEntry::TAG::PREINIT_ARRAY);
    skipped 5 lines
    250 278   } else { LIEF_DEBUG("DT_PREINIT_ARRAY: -0x{:x} bytes", osize - needed_size); }
    251 279   }
    252 280   
    253  - if (binary_->has(DynamicEntry::TAG::FINI_ARRAY) && binary_->has(DynamicEntry::TAG::FINI_ARRAYSZ) &&
     281 + if (binary_->has(DynamicEntry::TAG::FINI_ARRAY) &&
     282 + binary_->has(DynamicEntry::TAG::FINI_ARRAYSZ) &&
    254 283   config_.fini_array)
    255 284   {
    256 285   const size_t needed_size = layout->dynamic_arraysize<ELF_T>(DynamicEntry::TAG::FINI_ARRAY);
    skipped 145 lines
    402 431   
    403 432   if (config_.sym_verneed && binary_->has(DynamicEntry::TAG::VERNEED)) {
    404 433   build_symbol_requirement<ELF_T>();
     434 + }
     435 + 
     436 + if (config_.relr) {
     437 + if (ok_error_t ret = build_relative_relocations<ELF_T>(); !is_ok(ret)) {
     438 + return ret;
     439 + }
     440 + }
     441 + 
     442 + if (config_.android_rela) {
     443 + if (ok_error_t ret = build_android_relocations<ELF_T>(); !is_ok(ret)) {
     444 + return ret;
     445 + }
    405 446   }
    406 447   
    407 448   if (config_.rela) {
    skipped 825 lines
    1233 1274   [] (const Relocation* lhs, const Relocation* rhs) {
    1234 1275   return lhs->address() < rhs->address();
    1235 1276   });
    1236  - for (const Relocation* reloc : relocs) {
     1277 + for (Relocation* reloc : relocs) {
    1237 1278   Section* reloc_section = sec_relo_map.at(section);
    1238 1279   uint32_t symidx = 0;
    1239  - const Symbol* sym = reloc->symbol();
    1240  - if (sym != nullptr) {
    1241  - const auto it_sym = std::find_if(std::begin(binary_->symtab_symbols_), std::end(binary_->symtab_symbols_),
    1242  - [sym] (const std::unique_ptr<Symbol>& s) {
    1243  - return s.get() == sym;
    1244  - });
    1245  - if (it_sym == std::end(binary_->symtab_symbols_)) {
    1246  - LIEF_WARN("Can find the relocation's symbol '{}'", sym->name());
    1247  - continue;
     1280 + 
     1281 + if (const Symbol* symbol = reloc->symbol()) {
     1282 + int64_t symtab_idx = binary_->symtab_idx(*symbol);
     1283 + if (0 <= symtab_idx) {
     1284 + symidx = static_cast<uint32_t>(symtab_idx);
     1285 + } else {
     1286 + LIEF_ERR("Can't find the symbol idx associated with the relocation ({})",
     1287 + symbol->name());
    1248 1288   }
     1289 + }
     1290 + Elf_Xword info = reloc->info();
    1249 1291   
    1250  - symidx = static_cast<uint32_t>(std::distance(std::begin(binary_->symtab_symbols_), it_sym));
     1292 + if (symidx > 0) {
     1293 + if (symidx != info) {
     1294 + LIEF_DEBUG("Fixing symbol idx for {}", to_string(*reloc));
     1295 + }
     1296 + reloc->info(symidx);
    1251 1297   }
    1252 1298   
    1253  - Elf_Xword info = 0;
    1254  - if (std::is_same<ELF_T, details::ELF32>::value) {
    1255  - info = (static_cast<Elf_Xword>(symidx) << 8) | Relocation::to_value(reloc->type());
    1256  - } else {
    1257  - // NOTE: To suppress a warning we require a cast here, this path is not constexpr but only uses Elf64_Xword
    1258  - info = (static_cast<details::ELF64::Elf_Xword>(symidx) << 32) | (Relocation::to_value(reloc->type()) & 0xffffffffL);
    1259  - }
     1299 + uint64_t r_info = reloc->r_info(std::is_same_v<ELF_T, details::ELF32> ?
     1300 + Header::CLASS::ELF32 :
     1301 + Header::CLASS::ELF64);
    1260 1302   
    1261 1303   if (is_rela) {
    1262 1304   Elf_Rela relahdr;
    1263 1305   relahdr.r_offset = static_cast<Elf_Addr>(reloc->address());
    1264  - relahdr.r_info = static_cast<Elf_Xword>(info);
     1306 + relahdr.r_info = static_cast<Elf_Xword>(r_info);
    1265 1307   relahdr.r_addend = static_cast<Elf_Sxword>(reloc->addend());
    1266 1308   section_content[reloc_section].write<Elf_Rela>(relahdr);
    1267 1309   } else {
    1268 1310   Elf_Rel relhdr;
    1269 1311   relhdr.r_offset = static_cast<Elf_Addr>(reloc->address());
    1270  - relhdr.r_info = static_cast<Elf_Xword>(info);
     1312 + relhdr.r_info = static_cast<Elf_Xword>(r_info);
    1271 1313   section_content[reloc_section].write<Elf_Rel>(relhdr);
    1272 1314   }
    1273 1315   }
    skipped 9 lines
    1283 1325  }
    1284 1326   
    1285 1327  template<typename ELF_T>
     1328 +ok_error_t Builder::build_android_relocations() {
     1329 + LIEF_DEBUG("Build DT_ANDROID_REL[A] relocations");
     1330 + if (!config_.android_rela) {
     1331 + return ok();
     1332 + }
     1333 + 
     1334 + /* The relocations might have been update when adding the new segment
     1335 + * (->relocate()). Thus the cache might be invalidated
     1336 + */
     1337 + auto& layout = static_cast<ExeLayout&>(*layout_);
     1338 + const size_t computed_size = layout.android_relocations_size<ELF_T>();
     1339 + const size_t new_size = layout.android_relocations_size<ELF_T>(/*force=*/true);
     1340 + if (computed_size != new_size) {
     1341 + if (computed_size < new_size) {
     1342 + LIEF_ERR("New ANDROID_REL[A] is larger than the in-cache size");
     1343 + return make_error_code(lief_errors::build_error);
     1344 + }
     1345 + LIEF_WARN("New ANDROID_REL[A] is smaller than the in-cache size. It might require padding");
     1346 + }
     1347 + 
     1348 + if (const DynamicEntry* entry = binary_->get(DynamicEntry::TAG::ANDROID_RELA)) {
     1349 + binary_->patch_address(entry->value(), layout.raw_android_rela());
     1350 + if (DynamicEntry* dt_size = binary_->get(DynamicEntry::TAG::ANDROID_RELASZ)) {
     1351 + dt_size->value(layout.raw_android_rela().size());
     1352 + }
     1353 + }
     1354 + else if (const DynamicEntry* entry = binary_->get(DynamicEntry::TAG::ANDROID_REL)) {
     1355 + binary_->patch_address(entry->value(), layout.raw_android_rela());
     1356 + if (DynamicEntry* dt_size = binary_->get(DynamicEntry::TAG::ANDROID_RELSZ)) {
     1357 + dt_size->value(layout.raw_android_rela().size());
     1358 + }
     1359 + }
     1360 + 
     1361 + return ok();
     1362 +}
     1363 + 
     1364 +template<typename ELF_T>
     1365 +ok_error_t Builder::build_relative_relocations() {
     1366 + LIEF_DEBUG("Build DT_RELR relocations");
     1367 + 
     1368 + if (!config_.relr) {
     1369 + return ok();
     1370 + }
     1371 + /* The relocations might have been update when adding the new segment
     1372 + * (->relocate()). Thus the cache might be invalidated
     1373 + */
     1374 + auto& layout = static_cast<ExeLayout&>(*layout_);
     1375 + const size_t computed_size = layout.relative_relocations_size<ELF_T>();
     1376 + const size_t new_size = layout.relative_relocations_size<ELF_T>(/*force=*/true);
     1377 + if (computed_size != new_size) {
     1378 + if (computed_size < new_size) {
     1379 + LIEF_ERR("New RELR is larger than the in-cache size");
     1380 + return make_error_code(lief_errors::build_error);
     1381 + }
     1382 + LIEF_WARN("New RELR is smaller than the in-cache size. It might require padding");
     1383 + }
     1384 + if (const DynamicEntry* entry = binary_->get(DynamicEntry::TAG::RELR)) {
     1385 + binary_->patch_address(entry->value(), layout.raw_relr());
     1386 + if (DynamicEntry* dt_size = binary_->get(DynamicEntry::TAG::RELRSZ)) {
     1387 + dt_size->value(layout.raw_relr().size());
     1388 + }
     1389 + }
     1390 + 
     1391 + if (const DynamicEntry* entry = binary_->get(DynamicEntry::TAG::ANDROID_RELR)) {
     1392 + binary_->patch_address(entry->value(), layout.raw_relr());
     1393 + 
     1394 + if (DynamicEntry* dt_size = binary_->get(DynamicEntry::TAG::ANDROID_RELRSZ)) {
     1395 + dt_size->value(layout.raw_relr().size());
     1396 + }
     1397 + }
     1398 + return ok();
     1399 +}
     1400 + 
     1401 +template<typename ELF_T>
    1286 1402  ok_error_t Builder::build_dynamic_relocations() {
    1287 1403   using Elf_Addr = typename ELF_T::Elf_Addr;
    1288 1404   using Elf_Xword = typename ELF_T::Elf_Xword;
    skipped 17 lines
    1306 1422   return ok();
    1307 1423   }
    1308 1424   
    1309  - LIEF_DEBUG("[+] Building dynamic relocations");
     1425 + DynamicEntry* dt_rela = binary_->get(DynamicEntry::TAG::RELA);
     1426 + DynamicEntry* dt_rel = binary_->get(DynamicEntry::TAG::REL);
     1427 + if (dt_rela == nullptr && dt_rel == nullptr) {
     1428 + return ok();
     1429 + }
     1430 + LIEF_DEBUG("Building DT_REL/DT_RELA");
     1431 + 
    1310 1432   DynamicEntry* dt_reloc = nullptr;
    1311 1433   DynamicEntry* dt_relocsz = nullptr;
    1312 1434   
    1313  - DynamicEntry* dt_rela = binary_->get(DynamicEntry::TAG::RELA);
    1314 1435   
    1315 1436   const bool is_rela = dt_rela != nullptr;
    1316 1437   if (dt_rela != nullptr) {
    skipped 1 lines
    1318 1439   dt_relocsz = binary_->get(DynamicEntry::TAG::RELASZ);
    1319 1440   } else {
    1320 1441   // Fallback on relation type REL
    1321  - dt_reloc = binary_->get(DynamicEntry::TAG::REL);
     1442 + dt_reloc = dt_rel;
    1322 1443   dt_relocsz = binary_->get(DynamicEntry::TAG::RELSZ);
    1323 1444   }
    1324  - 
    1325 1445   
    1326 1446   if (dt_reloc == nullptr) {
    1327 1447   LIEF_ERR("Unable to find the DT_REL/DT_RELA");
    skipped 7 lines
    1335 1455   
    1336 1456   
    1337 1457   vector_iostream content(should_swap());
    1338  - for (const Relocation& relocation : binary_->dynamic_relocations()) {
     1458 + for (Relocation& relocation : binary_->dynamic_relocations()) {
     1459 + if (!relocation.is_rel() && !relocation.is_rela()) {
     1460 + continue;
     1461 + }
    1339 1462   
    1340 1463   // look for symbol index
    1341 1464   uint32_t idx = 0;
    1342  - const Symbol* symbol = relocation.symbol();
    1343  - if (symbol != nullptr) {
    1344  - const std::string& name = symbol->name();
    1345  - const auto it_name = std::find_if(
    1346  - std::begin(binary_->dynamic_symbols_), std::end(binary_->dynamic_symbols_),
    1347  - [&name] (const std::unique_ptr<Symbol>& s) {
    1348  - return s->name() == name;
    1349  - });
    1350  - 
    1351  - if (it_name == std::end(binary_->dynamic_symbols_)) {
    1352  - LIEF_ERR("Unable to find the symbol associated with the relocation");
    1353  - return make_error_code(lief_errors::not_found);
     1465 + if (const Symbol* symbol = relocation.symbol()) {
     1466 + int64_t dynsym_idx = binary_->dynsym_idx(*symbol);
     1467 + if (0 <= dynsym_idx) {
     1468 + idx = static_cast<uint32_t>(dynsym_idx);
     1469 + } else {
     1470 + LIEF_ERR("Can't find the symbol idx associated with the relocation ({})",
     1471 + symbol->name());
    1354 1472   }
    1355  - 
    1356  - idx = static_cast<uint32_t>(std::distance(std::begin(binary_->dynamic_symbols_), it_name));
    1357 1473   }
    1358 1474   
    1359 1475   uint32_t info = relocation.info();
    1360 1476   if (idx > 0) {
    1361  - info = idx;
     1477 + if (idx != info) {
     1478 + LIEF_DEBUG("Fixing symbol idx for {}", to_string(relocation));
     1479 + }
     1480 + relocation.info(idx);
    1362 1481   }
    1363 1482   
    1364  - Elf_Xword r_info = 0;
    1365  - if (std::is_same<ELF_T, details::ELF32>::value) {
    1366  - r_info = (static_cast<Elf_Xword>(info) << 8) | Relocation::to_value(relocation.type());
    1367  - } else {
    1368  - // NOTE: To suppress a warning we require a cast here, this path is not constexpr but only uses Elf64_Xword
    1369  - r_info = (static_cast<details::ELF64::Elf_Xword>(info) << 32) | (Relocation::to_value(relocation.type()) & 0xffffffffL);
    1370  - }
    1371  - 
    1372  - 
     1483 + uint64_t r_info = relocation.r_info(std::is_same_v<ELF_T, details::ELF32> ?
     1484 + Header::CLASS::ELF32 :
     1485 + Header::CLASS::ELF64);
    1373 1486   if (is_rela) {
    1374 1487   Elf_Rela relahdr;
    1375 1488   relahdr.r_offset = static_cast<Elf_Addr>(relocation.address());
    skipped 37 lines
    1413 1526   bool is_rela = false;
    1414 1527   DynamicEntry* dt_pltrel = binary_->get(DynamicEntry::TAG::PLTREL);
    1415 1528   if (dt_pltrel != nullptr) {
    1416  - is_rela = dt_pltrel->value() == static_cast<uint64_t>(DynamicEntry::TAG::RELA);
     1529 + is_rela = DynamicEntry::TAG(dt_pltrel->value()) == DynamicEntry::TAG::RELA;
    1417 1530   }
    1418 1531   DynamicEntry* dt_jmprel = binary_->get(DynamicEntry::TAG::JMPREL);
    1419 1532   DynamicEntry* dt_pltrelsz = binary_->get(DynamicEntry::TAG::PLTRELSZ);
    skipped 8 lines
    1428 1541   }
    1429 1542   
    1430 1543   vector_iostream content(should_swap()); // Section's content
    1431  - for (const Relocation& relocation : binary_->pltgot_relocations()) {
     1544 + for (Relocation& relocation : binary_->pltgot_relocations()) {
    1432 1545   uint32_t idx = 0;
    1433  - const Symbol* symbol = relocation.symbol();
    1434  - if (symbol != nullptr) {
    1435  - // look for symbol index
    1436  - const std::string& name = symbol->name();
    1437  - const auto& it_name = std::find_if(
    1438  - std::begin(binary_->dynamic_symbols_), std::end(binary_->dynamic_symbols_),
    1439  - [&name] (const std::unique_ptr<Symbol>& s) {
    1440  - return s->name() == name;
    1441  - });
    1442  - 
    1443  - if (it_name == std::end(binary_->dynamic_symbols_)) {
    1444  - LIEF_ERR("Unable to find the symbol associated with the relocation");
    1445  - return make_error_code(lief_errors::not_found);
     1546 + if (const Symbol* symbol = relocation.symbol()) {
     1547 + int64_t dynsym_idx = binary_->dynsym_idx(*symbol);
     1548 + if (0 <= dynsym_idx) {
     1549 + idx = static_cast<uint32_t>(dynsym_idx);
     1550 + } else {
     1551 + LIEF_ERR("Can't find the symbol idx associated with the relocation ({})",
     1552 + symbol->name());
    1446 1553   }
     1554 + }
    1447 1555   
    1448  - idx = static_cast<uint32_t>(std::distance(std::begin(binary_->dynamic_symbols_), it_name));
     1556 + uint32_t info = relocation.info();
     1557 + if (idx > 0) {
     1558 + if (idx != info) {
     1559 + LIEF_DEBUG("Fixing symbol idx for {}", to_string(relocation));
     1560 + }
     1561 + relocation.info(idx);
    1449 1562   }
    1450 1563   
    1451  - Elf_Xword info = 0;
    1452  - if constexpr (std::is_same_v<ELF_T, details::ELF32>) {
    1453  - info = (static_cast<Elf_Xword>(idx) << 8) | Relocation::to_value(relocation.type());
    1454  - } else {
    1455  - // NOTE: To suppress a warning we require a cast here, this path is not constexpr but only uses Elf64_Xword
    1456  - info = (static_cast<details::ELF64::Elf_Xword>(idx) << 32) | (Relocation::to_value(relocation.type()) & 0xffffffffL);
    1457  - }
     1564 + uint64_t r_info = relocation.r_info(std::is_same_v<ELF_T, details::ELF32> ?
     1565 + Header::CLASS::ELF32 :
     1566 + Header::CLASS::ELF64);
    1458 1567   
    1459 1568   if (is_rela) {
    1460 1569   Elf_Rela relahdr;
    1461 1570   relahdr.r_offset = static_cast<Elf_Addr>(relocation.address());
    1462  - relahdr.r_info = static_cast<Elf_Xword>(info);
     1571 + relahdr.r_info = static_cast<Elf_Xword>(r_info);
    1463 1572   relahdr.r_addend = static_cast<Elf_Sxword>(relocation.addend());
    1464 1573   
    1465 1574   content.write_conv<Elf_Rela>(relahdr);
    1466 1575   } else {
    1467 1576   Elf_Rel relhdr;
    1468 1577   relhdr.r_offset = static_cast<Elf_Addr>(relocation.address());
    1469  - relhdr.r_info = static_cast<Elf_Xword>(info);
     1578 + relhdr.r_info = static_cast<Elf_Xword>(r_info);
    1470 1579   
    1471 1580   content.write_conv<Elf_Rel>(relhdr);
    1472 1581   }
    skipped 80 lines
    1553 1662   continue;
    1554 1663   }
    1555 1664   uint32_t new_hash = 0;
    1556  - if (std::is_same<ELF_T, details::ELF32>::value) {
     1665 + if constexpr (std::is_same_v<ELF_T, details::ELF32>) {
    1557 1666   new_hash = hash32(svar_name.c_str());
    1558 1667   } else {
    1559 1668   new_hash = hash64(svar_name.c_str());
    skipped 227 lines
  • ■ ■ ■ ■
    src/ELF/DynamicEntryFlags.cpp
    skipped 156 lines
    157 157   
    158 158  std::ostream& DynamicEntryFlags::print(std::ostream& os) const {
    159 159   DynamicEntry::print(os);
    160  - os << " " << fmt::to_string(flags());
     160 + os << fmt::to_string(flags());
    161 161   return os;
    162 162  }
    163 163   
    skipped 54 lines
  • ■ ■ ■ ■ ■ ■
    src/ELF/ExeLayout.hpp
    skipped 48 lines
    49 49  namespace LIEF {
    50 50  namespace ELF {
    51 51   
     52 +inline Relocation::TYPE relative_from_arch(ARCH arch) {
     53 + using TYPE = Relocation::TYPE;
     54 + switch (arch) {
     55 + case ARCH::AARCH64:
     56 + return TYPE::AARCH64_RELATIVE;
     57 + case ARCH::ARM:
     58 + return TYPE::ARM_RELATIVE;
     59 + case ARCH::X86_64:
     60 + return TYPE::X86_64_RELATIVE;
     61 + case ARCH::I386:
     62 + return TYPE::X86_RELATIVE;
     63 + case ARCH::PPC:
     64 + return TYPE::PPC_RELATIVE;
     65 + case ARCH::PPC64:
     66 + return TYPE::PPC64_RELATIVE;
     67 + case ARCH::HEXAGON:
     68 + return TYPE::HEX_RELATIVE;
     69 + default:
     70 + return TYPE::UNKNOWN;
     71 + }
     72 + return TYPE::UNKNOWN;
     73 +}
     74 + 
    52 75  //! Compute the size and the offset of the elements
    53 76  //! needed to rebuild the ELF file.
    54 77  class LIEF_LOCAL ExeLayout : public Layout {
    skipped 340 lines
    395 418   using Elf_Rela = typename ELF_T::Elf_Rela;
    396 419   using Elf_Rel = typename ELF_T::Elf_Rel;
    397 420   const Binary::it_dynamic_relocations& dyn_relocs = binary_->dynamic_relocations();
     421 + const size_t nb_rel_a = std::count_if(dyn_relocs.begin(), dyn_relocs.end(),
     422 + [] (const Relocation& R) {
     423 + return R.is_rel() || R.is_rela();
     424 + }
     425 + );
    398 426   
    399 427   const size_t computed_size = binary_->has(DynamicEntry::TAG::RELA) ?
    400  - dyn_relocs.size() * sizeof(Elf_Rela) :
    401  - dyn_relocs.size() * sizeof(Elf_Rel);
     428 + nb_rel_a * sizeof(Elf_Rela) :
     429 + nb_rel_a * sizeof(Elf_Rel);
    402 430   return computed_size;
    403 431   }
    404 432   
    skipped 53 lines
    458 486   return binary_->interpreter_.size() + 1;
    459 487   }
    460 488   
     489 + template<class ELF_T>
     490 + size_t android_relocations_size(bool force = false) {
     491 + static constexpr uint64_t GROUPED_BY_INFO_FLAG = 1 << 0;
     492 + static constexpr uint64_t GROUPED_BY_OFFSET_DELTA_FLAG = 1 << 1;
     493 + static constexpr uint64_t GROUPED_BY_ADDEND_FLAG = 1 << 2;
     494 + static constexpr uint64_t GROUP_HAS_ADDEND_FLAG = 1 << 3;
     495 + 
     496 + using Elf_Xword = typename ELF_T::Elf_Xword;
     497 + 
     498 + // This code reproduces what the lld linker is doing for generating the
     499 + // packed relocations. See lld/ELF/SyntheticSections.cpp -
     500 + // AndroidPackedRelocationSection:updateAllocSize
     501 + constexpr size_t wordsize = sizeof(typename ELF_T::Elf_Addr);
     502 + const bool is_rela = binary_->has(DynamicEntry::TAG::ANDROID_RELA);
     503 + const Relocation::TYPE relative_reloc = relative_from_arch(binary_->header().machine_type());
     504 + const uint64_t raw_relative_reloc = Relocation::to_value(relative_reloc);
     505 + 
     506 + const Header::CLASS elf_class = std::is_same_v<ELF_T, details::ELF32> ?
     507 + Header::CLASS::ELF32 : Header::CLASS::ELF64;
     508 + 
     509 + if (force) {
     510 + raw_android_rela_.clear();
     511 + }
     512 + 
     513 + if (!raw_android_rela_.empty()) {
     514 + return raw_android_rela_.size();
     515 + }
     516 + 
     517 + std::vector<const Relocation*> android_relocs;
     518 + std::vector<const Relocation*> relative_rels;
     519 + std::vector<const Relocation*> non_relative_rels;
     520 + android_relocs.reserve(20);
     521 + 
     522 + for (const Relocation& R : binary_->relocations()) {
     523 + if (!R.is_android_packed()) {
     524 + continue;
     525 + }
     526 + android_relocs.push_back(&R);
     527 + R.is_relative() ? relative_rels.push_back(&R) :
     528 + non_relative_rels.push_back(&R);
     529 + }
     530 + 
     531 + std::sort(relative_rels.begin(), relative_rels.end(),
     532 + [] (const Relocation* lhs, const Relocation* rhs) {
     533 + return lhs->address() < rhs->address();
     534 + }
     535 + );
     536 + 
     537 + std::vector<const Relocation*> ungrouped_relative;
     538 + std::vector<std::vector<const Relocation*>> relative_groups;
     539 + for (auto i = relative_rels.begin(), e = relative_rels.end(); i != e;) {
     540 + std::vector<const Relocation*> group;
     541 + do {
     542 + group.push_back(*i++);
     543 + } while (i != e && (*(i - 1))->address() + wordsize == (*i)->address());
     544 + 
     545 + if (group.size() < 8) {
     546 + ungrouped_relative.insert(ungrouped_relative.end(),
     547 + group.begin(), group.end());
     548 + } else {
     549 + relative_groups.emplace_back(std::move(group));
     550 + }
     551 + }
     552 + 
     553 + 
     554 + std::sort(non_relative_rels.begin(), non_relative_rels.end(),
     555 + [&elf_class] (const Relocation* lhs, const Relocation* rhs) {
     556 + if (lhs->r_info(elf_class) != rhs->r_info(elf_class)) {
     557 + return lhs->r_info(elf_class) < rhs->r_info(elf_class);
     558 + }
     559 + if (lhs->addend() != rhs->addend()) {
     560 + return lhs->addend() < rhs->addend();
     561 + }
     562 + return lhs->address() < rhs->address();
     563 + }
     564 + );
     565 + 
     566 + std::vector<const Relocation*> ungrouped_non_relative;
     567 + std::vector<std::vector<const Relocation*>> non_relative_group;
     568 + 
     569 + for (auto i = non_relative_rels.begin(),
     570 + e = non_relative_rels.end(); i != e;)
     571 + {
     572 + auto j = i + 1;
     573 + while (j != e && (*i)->r_info(elf_class) == (*j)->r_info(elf_class) &&
     574 + (!is_rela || (*i)->addend() == (*j)->addend()))
     575 + {
     576 + ++j;
     577 + }
     578 + 
     579 + if ((j - i) < 3 || (is_rela && (*i)->addend() != 0)) {
     580 + ungrouped_non_relative.insert(ungrouped_non_relative.end(), i, j);
     581 + } else {
     582 + non_relative_group.emplace_back(i, j);
     583 + }
     584 + i = j;
     585 + }
     586 + 
     587 + std::sort(ungrouped_non_relative.begin(), ungrouped_non_relative.end(),
     588 + [] (const Relocation* lhs, const Relocation* rhs) {
     589 + return lhs->address() < rhs->address();
     590 + }
     591 + );
     592 + 
     593 + const unsigned has_addend_with_rela = is_rela ? GROUP_HAS_ADDEND_FLAG : 0;
     594 + uint64_t offset = 0;
     595 + uint64_t addend = 0;
     596 + 
     597 + vector_iostream ios;
     598 + ios.write('A')
     599 + .write('P')
     600 + .write('S')
     601 + .write('2');
     602 + 
     603 + ios.write_sleb128(android_relocs.size());
     604 + ios.write_sleb128(0);
     605 + 
     606 + for (const std::vector<const Relocation*>& g : relative_groups) {
     607 + ios.write_sleb128(1);
     608 + ios.write_sleb128(GROUPED_BY_OFFSET_DELTA_FLAG | GROUPED_BY_INFO_FLAG |
     609 + has_addend_with_rela);
     610 + ios.write_sleb128(g[0]->address() - offset);
     611 + ios.write_sleb128(raw_relative_reloc);
     612 + if (is_rela) {
     613 + ios.write_sleb128(g[0]->addend() - addend);
     614 + addend = g[0]->addend();
     615 + }
     616 + 
     617 + ios.write_sleb128(g.size() - 1);
     618 + ios.write_sleb128(GROUPED_BY_OFFSET_DELTA_FLAG | GROUPED_BY_INFO_FLAG |
     619 + has_addend_with_rela);
     620 + ios.write_sleb128(wordsize);
     621 + ios.write_sleb128(raw_relative_reloc);
     622 + if (is_rela) {
     623 + auto it = g.begin(); ++it;
     624 + for (; it != g.end(); ++it) {
     625 + ios.write_sleb128((*it)->addend() - addend);
     626 + addend = (*it)->addend();
     627 + }
     628 + }
     629 + offset = g.back()->address();
     630 + }
     631 + 
     632 + if (!ungrouped_relative.empty()) {
     633 + ios.write_sleb128(ungrouped_relative.size());
     634 + ios.write_sleb128(GROUPED_BY_INFO_FLAG | has_addend_with_rela);
     635 + ios.write_sleb128(raw_relative_reloc);
     636 + for (const Relocation* R : ungrouped_relative) {
     637 + ios.write_sleb128(R->address() - offset);
     638 + offset = R->address();
     639 + if (is_rela) {
     640 + ios.write_sleb128(R->addend() - addend);
     641 + addend = R->addend();
     642 + }
     643 + }
     644 + }
     645 + 
     646 + for (const std::vector<const Relocation*>& g: non_relative_group) {
     647 + ios.write_sleb128(g.size());
     648 + ios.write_sleb128(GROUPED_BY_INFO_FLAG);
     649 + ios.write_sleb128(static_cast<Elf_Xword>(g[0]->r_info(elf_class)));
     650 + 
     651 + for (const Relocation* R : g) {
     652 + ios.write_sleb128(R->address() - offset);
     653 + offset = R->address();
     654 + }
     655 + addend = 0;
     656 + }
     657 + 
     658 + if (!ungrouped_non_relative.empty()) {
     659 + ios.write_sleb128(ungrouped_non_relative.size());
     660 + ios.write_sleb128(has_addend_with_rela);
     661 + for (const Relocation* R : ungrouped_non_relative) {
     662 + ios.write_sleb128(R->address() - offset);
     663 + offset = R->address();
     664 + ios.write_sleb128(static_cast<Elf_Xword>(R->r_info(elf_class)));
     665 + if (is_rela) {
     666 + ios.write_sleb128(R->addend() - addend);
     667 + addend = R->addend();
     668 + }
     669 + }
     670 + }
     671 + 
     672 + ios.move(raw_android_rela_);
     673 + return raw_android_rela_.size();
     674 + }
     675 + 
     676 + template<class ELF_T>
     677 + size_t relative_relocations_size(bool force = false) {
     678 + // This code is inspired from LLVM-lld:
     679 + // lld/ELF/SyntheticSections.cpp - RelrSection<ELFT>::updateAllocSize
     680 + // https://github.com/llvm/llvm-project/blob/754a8add57098ef71e4a51a9caa0cc175e94377d/lld/ELF/SyntheticSections.cpp#L1997-L2078
     681 + using Elf_Addr = typename ELF_T::Elf_Addr;
     682 + 
     683 + if (force) {
     684 + raw_relr_.clear();
     685 + }
     686 + 
     687 + if (!raw_relr_.empty()) {
     688 + return raw_relr_.size();
     689 + }
     690 + 
     691 + std::vector<const Relocation*> relr_relocs;
     692 + relr_relocs.reserve(20);
     693 + 
     694 + for (const Relocation& R : binary_->relocations()) {
     695 + if (R.is_relatively_encoded()) {
     696 + relr_relocs.push_back(&R);
     697 + }
     698 + }
     699 + 
     700 + std::unique_ptr<uint64_t[]> offsets(new uint64_t[relr_relocs.size()]);
     701 + for (size_t i = 0; i < relr_relocs.size(); ++i) {
     702 + offsets[i] = relr_relocs[i]->address();
     703 + }
     704 + std::sort(offsets.get(), offsets.get() + relr_relocs.size());
     705 + 
     706 + const size_t wordsize = sizeof(Elf_Addr);
     707 + const size_t nbits = wordsize * 8 - 1;
     708 + 
     709 + vector_iostream raw_relr;
     710 + 
     711 + for (size_t i = 0, e = relr_relocs.size(); i != e;) {
     712 + raw_relr.write<Elf_Addr>(offsets[i]);
     713 + uint64_t base = offsets[i] + wordsize;
     714 + ++i;
     715 + 
     716 + for (;;) {
     717 + uint64_t bitmap = 0;
     718 + for (; i != e; ++i) {
     719 + uint64_t d = offsets[i] - base;
     720 + if (nbits <= (d * wordsize) || (d % wordsize) != 0) {
     721 + break;
     722 + }
     723 + bitmap |= uint64_t(1) << (d / wordsize);
     724 + }
     725 + if (!bitmap) {
     726 + break;
     727 + }
     728 + raw_relr.write<Elf_Addr>((bitmap << 1) | 1);
     729 + base += nbits * wordsize;
     730 + }
     731 + }
     732 + raw_relr.move(raw_relr_);
     733 + return raw_relr_.size();
     734 + }
     735 + 
    461 736   void relocate_dynamic(uint64_t size) {
    462 737   dynamic_size_ = size;
    463 738   }
    skipped 2 lines
    466 741   relocate_dynstr_ = val;
    467 742   }
    468 743   
     744 + void relocate_relr(bool val) {
     745 + relocate_relr_ = val;
     746 + }
     747 + 
     748 + void relocate_android_rela(bool val) {
     749 + relocate_android_rela_ = val;
     750 + }
     751 + 
    469 752   void relocate_shstr(bool val) {
    470 753   relocate_shstrtab_ = val;
    471 754   }
    skipped 82 lines
    554 837   return verdef_info_;
    555 838   }
    556 839   
     840 + const std::vector<uint8_t>& raw_relr() const {
     841 + return raw_relr_;
     842 + }
     843 + 
     844 + const std::vector<uint8_t>& raw_android_rela() const {
     845 + return raw_android_rela_;
     846 + }
     847 + 
    557 848   result<bool> relocate() {
    558 849   /* PT_INTERP segment (optional)
    559 850   *
    skipped 23 lines
    583 874   * .gnu.version_r
    584 875   * .rela.dyn
    585 876   * .rela.plt
     877 + * .relr.dyn
    586 878   * Perm: READ ONLY
    587 879   * Align: 0x1000
    588 880   */
    589  - uint64_t read_segment =
    590  - interp_size_ + sysv_size_ +
    591  - dynsym_size_ +
    592  - sver_size_ + sverd_size_ + sverr_size_ +
    593  - dynamic_reloc_size_ + pltgot_reloc_size_;
     881 + uint64_t read_segment = interp_size_ + sysv_size_ + dynsym_size_ +
     882 + sver_size_ + sverd_size_ + sverr_size_ +
     883 + dynamic_reloc_size_ + pltgot_reloc_size_;
     884 + if (relocate_relr_) {
     885 + read_segment += raw_relr_.size();
     886 + }
     887 + 
     888 + if (relocate_android_rela_) {
     889 + read_segment += raw_android_rela_.size();
     890 + }
    594 891   
    595 892   if (relocate_notes_) {
    596 893   read_segment += raw_notes_.size();
    skipped 53 lines
    650 947   return make_error_code(lief_errors::build_error);
    651 948   }
    652 949   }
    653  - 
    654  - 
    655 950   
    656 951   if (relocate_shstrtab_) {
    657 952   LIEF_DEBUG("[-] Relocate .shstrtab");
    skipped 322 lines
    980 1275   va_r_base += pltgot_reloc_size_;
    981 1276   }
    982 1277   
     1278 + if (relocate_relr_) {
     1279 + DynamicEntry* dt_relr = binary_->get(DynamicEntry::TAG::RELR);
     1280 + if (dt_relr == nullptr) {
     1281 + LIEF_ERR("Can't find DT_RELR");
     1282 + return make_error_code(lief_errors::file_format_error);
     1283 + }
     1284 + 
     1285 + uint64_t offset_r_base = 0;
     1286 + if (auto res = binary_->virtual_address_to_offset(va_r_base)) {
     1287 + offset_r_base = *res;
     1288 + } else {
     1289 + return make_error_code(lief_errors::build_error);
     1290 + }
     1291 + 
     1292 + if (Section* section = binary_->section_from_virtual_address(dt_relr->value())) {
     1293 + section->virtual_address(va_r_base);
     1294 + section->size(raw_relr_.size());
     1295 + section->offset(offset_r_base);
     1296 + section->original_size_ = raw_relr_.size();
     1297 + }
     1298 + 
     1299 + dt_relr->value(va_r_base);
     1300 + va_r_base += raw_relr_.size();
     1301 + }
     1302 + 
     1303 + if (relocate_android_rela_) {
     1304 + DynamicEntry* dt_rel = binary_->get(DynamicEntry::TAG::ANDROID_RELA);
     1305 + if (dt_rel == nullptr) {
     1306 + dt_rel = binary_->get(DynamicEntry::TAG::ANDROID_REL);
     1307 + }
     1308 + 
     1309 + if (dt_rel == nullptr) {
     1310 + LIEF_ERR("Can't find DT_ANDROID_REL[A]");
     1311 + return make_error_code(lief_errors::file_format_error);
     1312 + }
     1313 + 
     1314 + uint64_t offset_r_base = 0;
     1315 + if (auto res = binary_->virtual_address_to_offset(va_r_base)) {
     1316 + offset_r_base = *res;
     1317 + } else {
     1318 + return make_error_code(lief_errors::build_error);
     1319 + }
     1320 + 
     1321 + if (Section* section = binary_->section_from_virtual_address(dt_rel->value())) {
     1322 + section->virtual_address(va_r_base);
     1323 + section->size(raw_android_rela_.size());
     1324 + section->offset(offset_r_base);
     1325 + section->original_size_ = raw_android_rela_.size();
     1326 + }
     1327 + 
     1328 + dt_rel->value(va_r_base);
     1329 + va_r_base += raw_android_rela_.size();
     1330 + }
    983 1331   
    984 1332   if (relocate_gnu_hash_) {
    985 1333   // Update .gnu.hash section / DT_GNU_HASH
    skipped 368 lines
    1354 1702   
    1355 1703   std::vector<uint8_t> raw_gnu_hash_;
    1356 1704   bool relocate_gnu_hash_{false};
     1705 + 
     1706 + std::vector<uint8_t> raw_relr_;
     1707 + bool relocate_relr_{false};
     1708 + 
     1709 + std::vector<uint8_t> raw_android_rela_;
     1710 + bool relocate_android_rela_{false};
    1357 1711   
    1358 1712   uint64_t sysv_size_{0};
    1359 1713   
    skipped 26 lines
  • ■ ■ ■ ■ ■ ■
    src/ELF/Parser.cpp
    skipped 645 lines
    646 646   return ok();
    647 647  }
    648 648   
     649 + 
     650 +bool Parser::bind_symbol(Relocation& R) {
     651 + if (!config_.parse_dyn_symbols) {
     652 + return false;
     653 + }
     654 + const uint32_t idx = R.info();
     655 + if (idx >= binary_->dynamic_symbols_.size()) {
     656 + LIEF_DEBUG("Index #{} is out of range for reloc: {}", idx, to_string(R));
     657 + return false;
     658 + }
     659 + 
     660 + R.symbol_ = binary_->dynamic_symbols_[idx].get();
     661 + 
     662 + return true;
     663 +}
     664 + 
    649 665  }
    650 666  }
    651 667   
  • ■ ■ ■ ■ ■ ■
    src/ELF/Parser.tcc
    skipped 92 lines
    93 93   binary_->sizing_info_->dynamic = size;
    94 94   }
    95 95   
     96 + process_dynamic_table<ELF_T>();
     97 + 
     98 + if (const Section* sec_symbtab = binary_->get(Section::TYPE::SYMTAB)) {
     99 + auto nb_entries = static_cast<uint32_t>((sec_symbtab->size() / sizeof(typename ELF_T::Elf_Sym)));
     100 + nb_entries = std::min(nb_entries, Parser::NB_MAX_SYMBOLS);
     101 + 
     102 + if (sec_symbtab->link() == 0 || sec_symbtab->link() >= binary_->sections_.size()) {
     103 + LIEF_WARN("section->link() is not valid !");
     104 + } else {
     105 + if (config_.parse_symtab_symbols) {
     106 + // We should have:
     107 + // nb_entries == section->information())
     108 + // but lots of compiler not respect this rule
     109 + parse_symtab_symbols<ELF_T>(sec_symbtab->file_offset(), nb_entries,
     110 + *binary_->sections_[sec_symbtab->link()]);
     111 + }
     112 + }
     113 + }
     114 + 
     115 + 
     116 + // Parse Symbols's hash
     117 + // ====================
     118 + if (DynamicEntry* dt_hash = binary_->get(DynamicEntry::TAG::HASH)) {
     119 + if (auto res = binary_->virtual_address_to_offset(dt_hash->value())) {
     120 + parse_symbol_sysv_hash(*res);
     121 + } else {
     122 + LIEF_WARN("Can't convert DT_HASH.virtual_address into an offset (0x{:x})", dt_hash->value());
     123 + }
     124 + }
     125 + 
     126 + 
     127 + if (DynamicEntry* dt_gnu_hash = binary_->get(DynamicEntry::TAG::GNU_HASH)) {
     128 + if (auto res = binary_->virtual_address_to_offset(dt_gnu_hash->value())) {
     129 + parse_symbol_gnu_hash<ELF_T>(*res);
     130 + } else {
     131 + LIEF_WARN("Can't convert DT_GNU_HASH.virtual_address into an offset (0x{:x})", dt_gnu_hash->value());
     132 + }
     133 + }
     134 + 
     135 + if (config_.parse_notes) {
     136 + // Parse Note segment
     137 + // ==================
     138 + for (const Segment& segment : binary_->segments()) {
     139 + if (segment.type() != Segment::TYPE::NOTE) {
     140 + continue;
     141 + }
     142 + parse_notes(segment.file_offset(), segment.physical_size());
     143 + }
     144 + 
     145 + // Parse Note Sections
     146 + // ===================
     147 + for (const Section& section : binary_->sections()) {
     148 + if (section.type() != Section::TYPE::NOTE) {
     149 + continue;
     150 + }
     151 + LIEF_DEBUG("Notes from section: {}", section.name());
     152 + parse_notes(section.offset(), section.size());
     153 + }
     154 + }
    96 155   
    97  - // Parse dynamic symbols
    98  - // =====================
     156 + // Try to parse using sections
     157 + // If we don't have any relocations, we parse all relocation sections
     158 + // otherwise, only the non-allocated sections to avoid parsing dynamic
     159 + // relocations (or plt relocations) twice.
     160 + if (config_.parse_relocations) {
     161 + bool skip_allocated_sections = !binary_->relocations_.empty();
     162 + for (const Section& section : binary_->sections()) {
     163 + if (skip_allocated_sections && section.has(Section::FLAGS::ALLOC)){
     164 + continue;
     165 + }
     166 + if (section.type() == Section::TYPE::REL) {
     167 + parse_section_relocations<ELF_T, typename ELF_T::Elf_Rel>(section);
     168 + }
     169 + else if (section.type() == Section::TYPE::RELA) {
     170 + parse_section_relocations<ELF_T, typename ELF_T::Elf_Rela>(section);
     171 + }
     172 + }
     173 + }
     174 + if (config_.parse_symbol_versions) {
     175 + link_symbol_version();
     176 + }
     177 + 
     178 + if (config_.parse_overlay) {
     179 + parse_overlay();
     180 + }
     181 + return ok();
     182 +}
     183 + 
     184 + 
     185 +template<typename ELF_T>
     186 +ok_error_t Parser::process_dynamic_table() {
    99 187   {
    100 188   DynamicEntry* dt_symtab = binary_->get(DynamicEntry::TAG::SYMTAB);
    101 189   DynamicEntry* dt_syment = binary_->get(DynamicEntry::TAG::SYMENT);
    skipped 7 lines
    109 197   }
    110 198   }
    111 199   }
    112  - 
    113  - // Parse dynamic relocations
    114  - // =========================
    115  - 
    116  - // RELA
    117  - // ----
    118 200   {
    119 201   DynamicEntry* dt_rela = binary_->get(DynamicEntry::TAG::RELA);
    120 202   DynamicEntry* dt_relasz = binary_->get(DynamicEntry::TAG::RELASZ);
    skipped 9 lines
    130 212   }
    131 213   }
    132 214   }
    133  - 
    134  - 
    135  - // REL
    136  - // ---
    137 215   {
    138 216   DynamicEntry* dt_rel = binary_->get(DynamicEntry::TAG::REL);
    139 217   DynamicEntry* dt_relsz = binary_->get(DynamicEntry::TAG::RELSZ);
    skipped 9 lines
    149 227   }
    150 228   }
    151 229   }
     230 + {
     231 + DynamicEntry* dt_relr = binary_->get(DynamicEntry::TAG::RELR);
     232 + DynamicEntry* dt_relrsz = binary_->get(DynamicEntry::TAG::RELRSZ);
    152 233   
    153  - // Parse PLT/GOT Relocations
    154  - // ==========================
     234 + if (dt_relr != nullptr && dt_relrsz != nullptr && config_.parse_relocations) {
     235 + const uint64_t virtual_address = dt_relr->value();
     236 + const uint64_t size = dt_relrsz->value();
     237 + if (auto res = binary_->virtual_address_to_offset(virtual_address)) {
     238 + parse_relative_relocations<ELF_T>(*res, size);
     239 + binary_->sizing_info_->relr = size;
     240 + } else {
     241 + LIEF_WARN("Can't convert DT_RELR.virtual_address into an offset (0x{:x})", virtual_address);
     242 + }
     243 + }
     244 + }
     245 + {
     246 + DynamicEntry* dt_relr = binary_->get(DynamicEntry::TAG::ANDROID_RELR);
     247 + DynamicEntry* dt_relrsz = binary_->get(DynamicEntry::TAG::ANDROID_RELRSZ);
     248 + 
     249 + if (dt_relr != nullptr && dt_relrsz != nullptr && config_.parse_relocations) {
     250 + const uint64_t virtual_address = dt_relr->value();
     251 + const uint64_t size = dt_relrsz->value();
     252 + if (auto res = binary_->virtual_address_to_offset(virtual_address)) {
     253 + parse_relative_relocations<ELF_T>(*res, size);
     254 + binary_->sizing_info_->relr = size;
     255 + } else {
     256 + LIEF_WARN("Can't convert (Android)DT_RELR.virtual_address into an offset (0x{:x})", virtual_address);
     257 + }
     258 + }
     259 + }
     260 + {
     261 + DynamicEntry* dt_rela = binary_->get(DynamicEntry::TAG::ANDROID_RELA);
     262 + DynamicEntry* dt_relasz = binary_->get(DynamicEntry::TAG::ANDROID_RELASZ);
     263 + if (dt_rela == nullptr) {
     264 + dt_rela = binary_->get(DynamicEntry::TAG::ANDROID_REL);
     265 + dt_relasz = binary_->get(DynamicEntry::TAG::ANDROID_RELSZ);
     266 + }
     267 + 
     268 + if (dt_rela != nullptr && dt_relasz != nullptr && config_.parse_relocations) {
     269 + const uint64_t virtual_address = dt_rela->value();
     270 + const uint64_t size = dt_relasz->value();
     271 + if (auto res = binary_->virtual_address_to_offset(virtual_address)) {
     272 + parse_packed_relocations<ELF_T>(*res, size);
     273 + binary_->sizing_info_->android_rela = size;
     274 + } else {
     275 + LIEF_WARN("Can't convert DT_ANDROID_REL[A].virtual_address into an offset (0x{:x})", virtual_address);
     276 + }
     277 + }
     278 + }
    155 279   {
    156 280   DynamicEntry* dt_jmprel = binary_->get(DynamicEntry::TAG::JMPREL);
    157 281   DynamicEntry* dt_pltrelsz = binary_->get(DynamicEntry::TAG::PLTRELSZ);
    skipped 24 lines
    182 306   }
    183 307   }
    184 308   }
    185  - 
    186  - // Parse Symbol Version
    187  - // ====================
    188 309   if (config_.parse_symbol_versions && config_.parse_dyn_symbols) {
    189 310   if (DynamicEntry* dt_versym = binary_->get(DynamicEntry::TAG::VERSYM)) {
    190 311   const uint64_t virtual_address = dt_versym->value();
    skipped 6 lines
    197 318   }
    198 319   }
    199 320   
    200  - 
    201  - // Parse Symbol Version Requirement
    202  - // ================================
    203 321   if (config_.parse_symbol_versions) {
    204 322   DynamicEntry* dt_verneed = binary_->get(DynamicEntry::TAG::VERNEED);
    205 323   DynamicEntry* dt_verneed_num = binary_->get(DynamicEntry::TAG::VERNEEDNUM);
    skipped 11 lines
    217 335   }
    218 336   }
    219 337   
    220  - // Parse Symbol Version Definition
    221  - // ===============================
    222 338   if (config_.parse_symbol_versions) {
    223 339   DynamicEntry* dt_verdef = binary_->get(DynamicEntry::TAG::VERDEF);
    224 340   DynamicEntry* dt_verdef_num = binary_->get(DynamicEntry::TAG::VERDEFNUM);
    skipped 9 lines
    234 350   }
    235 351   }
    236 352   
    237  - if (const Section* sec_symbtab = binary_->get(Section::TYPE::SYMTAB)) {
    238  - auto nb_entries = static_cast<uint32_t>((sec_symbtab->size() / sizeof(typename ELF_T::Elf_Sym)));
    239  - nb_entries = std::min(nb_entries, Parser::NB_MAX_SYMBOLS);
    240  - 
    241  - if (sec_symbtab->link() == 0 || sec_symbtab->link() >= binary_->sections_.size()) {
    242  - LIEF_WARN("section->link() is not valid !");
    243  - } else {
    244  - if (config_.parse_symtab_symbols) {
    245  - // We should have:
    246  - // nb_entries == section->information())
    247  - // but lots of compiler not respect this rule
    248  - parse_symtab_symbols<ELF_T>(sec_symbtab->file_offset(), nb_entries,
    249  - *binary_->sections_[sec_symbtab->link()]);
    250  - }
    251  - }
    252  - }
    253  - 
    254  - 
    255  - // Parse Symbols's hash
    256  - // ====================
    257  - if (DynamicEntry* dt_hash = binary_->get(DynamicEntry::TAG::HASH)) {
    258  - if (auto res = binary_->virtual_address_to_offset(dt_hash->value())) {
    259  - parse_symbol_sysv_hash(*res);
    260  - } else {
    261  - LIEF_WARN("Can't convert DT_HASH.virtual_address into an offset (0x{:x})", dt_hash->value());
    262  - }
    263  - }
    264  - 
    265  - 
    266  - if (DynamicEntry* dt_gnu_hash = binary_->get(DynamicEntry::TAG::GNU_HASH)) {
    267  - if (auto res = binary_->virtual_address_to_offset(dt_gnu_hash->value())) {
    268  - parse_symbol_gnu_hash<ELF_T>(*res);
    269  - } else {
    270  - LIEF_WARN("Can't convert DT_GNU_HASH.virtual_address into an offset (0x{:x})", dt_gnu_hash->value());
    271  - }
    272  - }
    273  - 
    274  - if (config_.parse_notes) {
    275  - // Parse Note segment
    276  - // ==================
    277  - for (const Segment& segment : binary_->segments()) {
    278  - if (segment.type() != Segment::TYPE::NOTE) {
    279  - continue;
    280  - }
    281  - parse_notes(segment.file_offset(), segment.physical_size());
    282  - }
    283  - 
    284  - // Parse Note Sections
    285  - // ===================
    286  - for (const Section& section : binary_->sections()) {
    287  - if (section.type() != Section::TYPE::NOTE) {
    288  - continue;
    289  - }
    290  - LIEF_DEBUG("Notes from section: {}", section.name());
    291  - parse_notes(section.offset(), section.size());
    292  - }
    293  - }
    294  - 
    295  - // Try to parse using sections
    296  - // If we don't have any relocations, we parse all relocation sections
    297  - // otherwise, only the non-allocated sections to avoid parsing dynamic
    298  - // relocations (or plt relocations) twice.
    299  - if (config_.parse_relocations) {
    300  - bool skip_allocated_sections = !binary_->relocations_.empty();
    301  - for (const Section& section : binary_->sections()) {
    302  - if (skip_allocated_sections && section.has(Section::FLAGS::ALLOC)){
    303  - continue;
    304  - }
    305  - if (section.type() == Section::TYPE::REL) {
    306  - parse_section_relocations<ELF_T, typename ELF_T::Elf_Rel>(section);
    307  - }
    308  - else if (section.type() == Section::TYPE::RELA) {
    309  - parse_section_relocations<ELF_T, typename ELF_T::Elf_Rela>(section);
    310  - }
    311  - }
    312  - }
    313  - if (config_.parse_symbol_versions) {
    314  - link_symbol_version();
    315  - }
    316  - 
    317  - if (config_.parse_overlay) {
    318  - parse_overlay();
    319  - }
    320 353   return ok();
    321 354  }
    322  - 
    323 355   
    324 356  template<typename ELF_T>
    325 357  ok_error_t Parser::parse_header() {
    skipped 605 lines
    931 963  }
    932 964   
    933 965   
     966 +template<typename ELF_T>
     967 +ok_error_t Parser::parse_packed_relocations(uint64_t offset, uint64_t size) {
     968 + using Elf_Rela = typename ELF_T::Elf_Rela;
     969 + static constexpr uint64_t GROUPED_BY_INFO_FLAG = 1 << 0;
     970 + static constexpr uint64_t GROUPED_BY_OFFSET_DELTA_FLAG = 1 << 1;
     971 + static constexpr uint64_t GROUPED_BY_ADDEND_FLAG = 1 << 2;
     972 + static constexpr uint64_t GROUP_HAS_ADDEND_FLAG = 1 << 3;
     973 + 
     974 + LIEF_DEBUG("Parsing Android packed relocations");
     975 + if (size < 4) {
     976 + LIEF_ERR("Invalid Android packed relocation header");
     977 + return make_error_code(lief_errors::read_error);
     978 + }
     979 + ScopedStream rel_stream(*stream_, offset);
     980 + 
     981 + const auto H0 = stream_->read<char>().value_or(0);
     982 + const auto H1 = stream_->read<char>().value_or(0);
     983 + const auto H2 = stream_->read<char>().value_or(0);
     984 + const auto H3 = stream_->read<char>().value_or(0);
     985 + 
     986 + LIEF_DEBUG("Header: {} {} {} {}", H0, H1, H2, H3);
     987 + 
     988 + // Check for the Magic: APS2
     989 + if (H0 != 'A' || H1 != 'P' || H2 != 'S' || H3 != '2') {
     990 + LIEF_ERR("Invalid Android packed relocation magic header: "
     991 + "{} {} {} {}", H0, H1, H2, H3);
     992 + return make_error_code(lief_errors::read_error);
     993 + }
     994 + 
     995 + auto res_nb_relocs = rel_stream->read_sleb128();
     996 + if (!res_nb_relocs) {
     997 + LIEF_ERR("Can't read number of relocations");
     998 + return make_error_code(lief_errors::read_error);
     999 + }
     1000 + auto res_rels_offset = rel_stream->read_sleb128();
     1001 + if (!res_rels_offset) {
     1002 + LIEF_ERR("Can't read offset");
     1003 + return make_error_code(lief_errors::read_error);
     1004 + }
     1005 + 
     1006 + uint64_t nb_relocs = *res_nb_relocs;
     1007 + uint64_t r_offset = *res_rels_offset;
     1008 + uint64_t addend = 0;
     1009 + const ARCH arch = binary_->header().machine_type();
     1010 + 
     1011 + LIEF_DEBUG("Nb relocs: {}", nb_relocs);
     1012 + 
     1013 + while (nb_relocs > 0) {
     1014 + auto nb_reloc_group_r = rel_stream->read_sleb128();
     1015 + if (!nb_reloc_group_r) {
     1016 + break;
     1017 + }
     1018 + 
     1019 + uint64_t nb_reloc_group = *nb_reloc_group_r;
     1020 + LIEF_DEBUG(" Nb relocs in group: {}", nb_reloc_group);
     1021 + 
     1022 + if (nb_reloc_group > nb_relocs) {
     1023 + break;
     1024 + }
     1025 + 
     1026 + nb_relocs -= nb_reloc_group;
     1027 + 
     1028 + auto group_flag_r = rel_stream->read_sleb128();
     1029 + if (!group_flag_r) {
     1030 + LIEF_ERR("Can't read group flag");
     1031 + break;
     1032 + }
     1033 + uint64_t group_flag = *group_flag_r;
     1034 + 
     1035 + const bool g_by_info = group_flag & GROUPED_BY_INFO_FLAG;
     1036 + const bool g_by_offset_delta = group_flag & GROUPED_BY_OFFSET_DELTA_FLAG;
     1037 + const bool g_by_addend = group_flag & GROUPED_BY_ADDEND_FLAG;
     1038 + const bool g_has_addend = group_flag & GROUP_HAS_ADDEND_FLAG;
     1039 + 
     1040 + uint64_t group_off_delta =
     1041 + g_by_offset_delta ? rel_stream->read_sleb128().value_or(0) : 0;
     1042 + 
     1043 + uint64_t groupr_info =
     1044 + g_by_info ? rel_stream->read_sleb128().value_or(0) : 0;
     1045 + 
     1046 + if (g_by_addend && g_has_addend) {
     1047 + addend += rel_stream->read_sleb128().value_or(0);
     1048 + }
     1049 + 
     1050 + if (!g_has_addend) {
     1051 + addend = 0;
     1052 + }
     1053 + 
     1054 + for (size_t i = 0; i < nb_reloc_group; ++i) {
     1055 + if (!*rel_stream) {
     1056 + break;
     1057 + }
     1058 + r_offset += g_by_offset_delta ? group_off_delta : rel_stream->read_sleb128().value_or(0);
     1059 + uint64_t info = g_by_info ? groupr_info : rel_stream->read_sleb128().value_or(0);
     1060 + if (g_has_addend && !g_by_addend) {
     1061 + addend += rel_stream->read_sleb128().value_or(0);
     1062 + }
     1063 + 
     1064 + Elf_Rela R;
     1065 + R.r_info = info;
     1066 + R.r_addend = addend;
     1067 + R.r_offset = r_offset;
     1068 + auto reloc = std::unique_ptr<Relocation>(new Relocation(R, Relocation::PURPOSE::DYNAMIC,
     1069 + Relocation::ENCODING::ANDROID_SLEB, arch));
     1070 + bind_symbol(*reloc);
     1071 + binary_->relocations_.push_back(std::move(reloc));
     1072 + }
     1073 + }
     1074 + return ok();
     1075 +}
     1076 + 
     1077 +template<typename ELF_T>
     1078 +ok_error_t Parser::parse_relative_relocations(uint64_t offset, uint64_t size) {
     1079 + LIEF_DEBUG("Parsing relative relocations");
     1080 + using Elf_Relr = typename ELF_T::uint;
     1081 + using Elf_Addr = typename ELF_T::uint;
     1082 + ScopedStream rel_stream(*stream_, offset);
     1083 + 
     1084 + Elf_Addr base = 0;
     1085 + const ARCH arch = binary_->header().machine_type();
     1086 + Relocation::TYPE type = Relocation::TYPE::UNKNOWN;
     1087 + switch (arch) {
     1088 + case ARCH::AARCH64:
     1089 + type = Relocation::TYPE::AARCH64_RELATIVE; break;
     1090 + case ARCH::X86_64:
     1091 + type = Relocation::TYPE::X86_64_RELATIVE; break;
     1092 + case ARCH::ARM:
     1093 + type = Relocation::TYPE::ARM_RELATIVE; break;
     1094 + case ARCH::HEXAGON:
     1095 + type = Relocation::TYPE::HEX_RELATIVE; break;
     1096 + case ARCH::PPC64:
     1097 + type = Relocation::TYPE::PPC64_RELATIVE; break;
     1098 + case ARCH::PPC:
     1099 + type = Relocation::TYPE::PPC_RELATIVE; break;
     1100 + case ARCH::I386:
     1101 + case ARCH::IAMCU:
     1102 + type = Relocation::TYPE::X86_RELATIVE; break;
     1103 + default:
     1104 + break;
     1105 + }
     1106 + 
     1107 + while (rel_stream->pos() < (offset + size)) {
     1108 + auto opt_relr = rel_stream->read<Elf_Relr>();
     1109 + if (!opt_relr) {
     1110 + break;
     1111 + }
     1112 + Elf_Relr rel = *opt_relr;
     1113 + if ((rel & 1) == 0) {
     1114 + Elf_Addr r_offset = rel;
     1115 + auto reloc = std::make_unique<Relocation>(r_offset, type,
     1116 + Relocation::ENCODING::RELR);
     1117 + reloc->purpose(Relocation::PURPOSE::DYNAMIC);
     1118 + binary_->relocations_.push_back(std::move(reloc));
     1119 + base = rel + sizeof(Elf_Addr);
     1120 + } else {
     1121 + for (Elf_Addr offset = base; (rel >>= 1) != 0; offset += sizeof(Elf_Addr)) {
     1122 + if ((rel & 1) != 0) {
     1123 + Elf_Addr r_offset = offset;
     1124 + auto reloc = std::make_unique<Relocation>(r_offset, type,
     1125 + Relocation::ENCODING::RELR);
     1126 + reloc->purpose(Relocation::PURPOSE::DYNAMIC);
     1127 + binary_->relocations_.push_back(std::move(reloc));
     1128 + }
     1129 + }
     1130 + base += (8 * sizeof(Elf_Relr) - 1) * sizeof(Elf_Addr);
     1131 + }
     1132 + }
     1133 + return ok();
     1134 +}
     1135 + 
    934 1136   
    935 1137  template<typename ELF_T, typename REL_T>
    936 1138  ok_error_t Parser::parse_dynamic_relocations(uint64_t relocations_offset, uint64_t size) {
    937  - static_assert(std::is_same<REL_T, typename ELF_T::Elf_Rel>::value ||
    938  - std::is_same<REL_T, typename ELF_T::Elf_Rela>::value, "REL_T must be Elf_Rel || Elf_Rela");
     1139 + static_assert(std::is_same_v<REL_T, typename ELF_T::Elf_Rel> ||
     1140 + std::is_same_v<REL_T, typename ELF_T::Elf_Rela>, "REL_T must be Elf_Rel || Elf_Rela");
    939 1141   LIEF_DEBUG("== Parsing dynamic relocations ==");
    940 1142   
    941 1143   // Already parsed
    skipped 1 lines
    943 1145   return ok();
    944 1146   }
    945 1147   
    946  - const uint8_t shift = std::is_same<ELF_T, details::ELF32>::value ? 8 : 32;
    947  - 
    948 1148   auto nb_entries = static_cast<uint32_t>(size / sizeof(REL_T));
    949 1149   
    950 1150   nb_entries = std::min<uint32_t>(nb_entries, Parser::NB_MAX_RELOCATIONS);
    skipped 1 lines
    952 1152   
    953 1153   stream_->setpos(relocations_offset);
    954 1154   const ARCH arch = binary_->header().machine_type();
     1155 + const Relocation::ENCODING enc =
     1156 + std::is_same_v<REL_T, typename ELF_T::Elf_Rel> ? Relocation::ENCODING::REL :
     1157 + Relocation::ENCODING::RELA;
     1158 + 
    955 1159   for (uint32_t i = 0; i < nb_entries; ++i) {
    956 1160   const auto raw_reloc = stream_->read_conv<REL_T>();
    957 1161   if (!raw_reloc) {
    958 1162   break;
    959 1163   }
    960  - auto reloc = std::make_unique<Relocation>(
    961  - std::move(*raw_reloc), Relocation::PURPOSE::DYNAMIC, arch);
    962 1164   
    963  - const auto idx = static_cast<uint32_t>(raw_reloc->r_info >> shift);
    964  - if (config_.parse_dyn_symbols) {
    965  - if (idx < binary_->dynamic_symbols_.size()) {
    966  - reloc->symbol_ = binary_->dynamic_symbols_[idx].get();
    967  - } else {
    968  - LIEF_WARN("Unable to find the symbol associated with the relocation "
    969  - "(idx: {}) {}", idx, to_string(*reloc));
    970  - }
    971  - }
     1165 + auto reloc = std::unique_ptr<Relocation>(new Relocation(
     1166 + std::move(*raw_reloc), Relocation::PURPOSE::DYNAMIC, enc, arch));
     1167 + bind_symbol(*reloc);
    972 1168   
    973 1169   binary_->relocations_.push_back(std::move(reloc));
    974 1170   }
    skipped 317 lines
    1292 1488   }
    1293 1489   
    1294 1490   const Elf_Off offset_relocations = offset;
    1295  - const uint8_t shift = std::is_same<ELF_T, details::ELF32>::value ? 8 : 32;
    1296 1491   
    1297 1492   auto nb_entries = static_cast<uint32_t>(size / sizeof(REL_T));
    1298 1493   
    1299 1494   nb_entries = std::min<uint32_t>(nb_entries, Parser::NB_MAX_RELOCATIONS);
    1300 1495   
    1301 1496   const ARCH arch = binary_->header_.machine_type();
     1497 + const Relocation::ENCODING enc =
     1498 + std::is_same_v<REL_T, typename ELF_T::Elf_Rel> ? Relocation::ENCODING::REL :
     1499 + Relocation::ENCODING::RELA;
    1302 1500   stream_->setpos(offset_relocations);
    1303 1501   for (uint32_t i = 0; i < nb_entries; ++i) {
    1304 1502   const auto rel_hdr = stream_->read_conv<REL_T>();
    skipped 1 lines
    1306 1504   break;
    1307 1505   }
    1308 1506   
    1309  - auto reloc = std::make_unique<Relocation>(
    1310  - std::move(*rel_hdr), Relocation::PURPOSE::PLTGOT, arch);
    1311  - 
    1312  - const auto idx = static_cast<uint32_t>(rel_hdr->r_info >> shift);
    1313  - if (config_.parse_dyn_symbols &&
    1314  - 0 < idx && idx < binary_->dynamic_symbols_.size())
    1315  - {
    1316  - reloc->symbol_ = binary_->dynamic_symbols_[idx].get();
    1317  - }
    1318  - 
     1507 + auto reloc = std::unique_ptr<Relocation>(new Relocation(
     1508 + std::move(*rel_hdr), Relocation::PURPOSE::PLTGOT, enc, arch));
     1509 + bind_symbol(*reloc);
    1319 1510   binary_->relocations_.push_back(std::move(reloc));
    1320 1511   }
    1321 1512   return ok();
    skipped 61 lines
    1383 1574   const uint64_t offset_relocations = section.file_offset();
    1384 1575   const uint8_t shift = std::is_same<ELF_T, details::ELF32>::value ? 8 : 32;
    1385 1576   
     1577 + const ARCH arch = binary_->header_.machine_type();
     1578 + 
     1579 + const Relocation::ENCODING enc =
     1580 + std::is_same_v<REL_T, typename ELF_T::Elf_Rel> ? Relocation::ENCODING::REL :
     1581 + Relocation::ENCODING::RELA;
     1582 + 
    1386 1583   auto nb_entries = static_cast<uint32_t>(section.size() / sizeof(REL_T));
    1387 1584   nb_entries = std::min<uint32_t>(nb_entries, Parser::NB_MAX_RELOCATIONS);
    1388 1585   
    skipped 5 lines
    1394 1591   break;
    1395 1592   }
    1396 1593   
    1397  - auto reloc = std::make_unique<Relocation>(
    1398  - *rel_hdr, Relocation::PURPOSE::NONE, binary_->header_.machine_type());
     1594 + auto reloc = std::unique_ptr<Relocation>(new Relocation(
     1595 + *rel_hdr, Relocation::PURPOSE::NONE, enc, arch));
     1596 + 
    1399 1597   reloc->section_ = applies_to;
    1400 1598   reloc->symbol_table_ = symbol_table;
    1401 1599   if (binary_->header().file_type() == Header::FILE_TYPE::REL &&
    skipped 295 lines
  • ■ ■ ■ ■ ■ ■
    src/ELF/Relocation.cpp
    skipped 62 lines
    63 63   LIEF::Relocation{other},
    64 64   type_{other.type_},
    65 65   addend_{other.addend_},
    66  - isRela_{other.isRela_},
     66 + encoding_{other.encoding_},
    67 67   architecture_{other.architecture_}
    68 68  {}
    69 69   
    skipped 3 lines
    73 73  }
    74 74   
    75 75  template<class T>
    76  -Relocation::Relocation(const T& header, PURPOSE purpose, ARCH arch) :
     76 +Relocation::Relocation(const T& header, PURPOSE purpose, ENCODING enc, ARCH arch) :
    77 77   LIEF::Relocation{header.r_offset, 0},
     78 + encoding_{enc},
    78 79   architecture_{arch},
    79 80   purpose_{purpose}
    80 81  {
    skipped 14 lines
    95 96   if constexpr (std::is_same_v<T, details::Elf32_Rela> ||
    96 97   std::is_same_v<T, details::Elf64_Rela>)
    97 98   {
    98  - isRela_ = true;
    99 99   addend_ = header.r_addend;
    100 100   }
    101 101  }
    102 102   
    103  -Relocation::Relocation(uint64_t address, TYPE type, bool is_rela) :
     103 +Relocation::Relocation(uint64_t address, TYPE type, ENCODING encoding) :
    104 104   LIEF::Relocation(address, 0),
    105 105   type_(type),
    106  - isRela_(is_rela)
     106 + encoding_(encoding)
    107 107  {
    108 108   if (type != TYPE::UNKNOWN) {
    109 109   auto raw_type = static_cast<uint64_t>(type);
    skipped 31 lines
    141 141   }
    142 142  }
    143 143   
    144  -template Relocation::Relocation(const details::Elf32_Rel&, PURPOSE, ARCH);
    145  -template Relocation::Relocation(const details::Elf32_Rela&, PURPOSE, ARCH);
    146  -template Relocation::Relocation(const details::Elf64_Rel&, PURPOSE, ARCH);
    147  -template Relocation::Relocation(const details::Elf64_Rela&, PURPOSE, ARCH);
     144 +template Relocation::Relocation(const details::Elf32_Rel&, PURPOSE, ENCODING, ARCH);
     145 +template Relocation::Relocation(const details::Elf32_Rela&, PURPOSE, ENCODING, ARCH);
     146 +template Relocation::Relocation(const details::Elf64_Rel&, PURPOSE, ENCODING, ARCH);
     147 +template Relocation::Relocation(const details::Elf64_Rela&, PURPOSE, ENCODING, ARCH);
    148 148   
    149 149  void Relocation::swap(Relocation& other) {
    150 150   std::swap(address_, other.address_);
    151 151   std::swap(type_, other.type_);
    152 152   std::swap(addend_, other.addend_);
    153  - std::swap(isRela_, other.isRela_);
     153 + std::swap(encoding_, other.encoding_);
    154 154   std::swap(symbol_, other.symbol_);
    155 155   std::swap(architecture_, other.architecture_);
    156 156   std::swap(purpose_, other.purpose_);
    skipped 30 lines
  • ■ ■ ■ ■ ■ ■
    src/ELF/SizingInfo.hpp
    skipped 29 lines
    30 30   uint64_t gnu_hash = 0;
    31 31   uint64_t hash = 0;
    32 32   uint64_t rela = 0;
     33 + uint64_t relr = 0;
     34 + uint64_t android_rela = 0;
    33 35   uint64_t jmprel = 0;
    34 36   uint64_t versym = 0;
    35 37   uint64_t verdef = 0;
    skipped 10 lines
  • ■ ■ ■ ■ ■ ■
    tests/elf/test_android_packed_relocations.py
     1 +import lief
     2 +from utils import get_sample
     3 +from pathlib import Path
     4 + 
     5 +def test_chrome_arm64(tmp_path: Path):
     6 + chrome_sample = Path(get_sample("ELF/libmonochrome-arm64.so"))
     7 + chrome = lief.ELF.parse(chrome_sample)
     8 + assert lief.ELF.DynamicEntry.TAG.AARCH64_BTI_PLT in chrome
     9 + 
     10 + packed_relocs = [r for r in chrome.dynamic_relocations if r.is_android_packed]
     11 + assert len(packed_relocs) == 145599
     12 + 
     13 + assert packed_relocs[0].address == 0x6426910
     14 + assert packed_relocs[0].addend == 0x6426910
     15 + assert packed_relocs[0].type == lief.ELF.Relocation.TYPE.AARCH64_RELATIVE
     16 + 
     17 + assert packed_relocs[145576].address == 0x65e3598
     18 + assert packed_relocs[145576].addend == 0
     19 + assert packed_relocs[145576].symbol.name == "memfd_create"
     20 + assert packed_relocs[145576].type == lief.ELF.Relocation.TYPE.AARCH64_GLOB_DAT
     21 + 
     22 + assert packed_relocs[145598].address == 0x6646a48
     23 + assert packed_relocs[145598].addend == 0
     24 + assert packed_relocs[145598].symbol.name == "ioctl"
     25 + assert packed_relocs[145598].type == lief.ELF.Relocation.TYPE.AARCH64_ABS64
     26 + 
     27 + out_simple = tmp_path / "chrome_simple.so"
     28 + chrome.write(out_simple.as_posix())
     29 + original_size = chrome_sample.stat().st_size
     30 + new_size = out_simple.stat().st_size
     31 + assert new_size <= original_size
     32 + 
     33 + new = lief.ELF.parse(out_simple.as_posix())
     34 + 
     35 + new_packed_relocs = [r for r in new.dynamic_relocations if r.is_android_packed]
     36 + assert len(new_packed_relocs) == 145599
     37 + 
     38 + assert new_packed_relocs[0].address == 0x6426910
     39 + assert new_packed_relocs[0].addend == 0x6426910
     40 + assert new_packed_relocs[0].type == lief.ELF.Relocation.TYPE.AARCH64_RELATIVE
     41 + 
     42 + assert new_packed_relocs[145576].address == 0x65e3598
     43 + assert new_packed_relocs[145576].addend == 0
     44 + assert new_packed_relocs[145576].symbol.name == "memfd_create"
     45 + assert new_packed_relocs[145576].type == lief.ELF.Relocation.TYPE.AARCH64_GLOB_DAT
     46 + 
     47 + assert new_packed_relocs[145598].address == 0x6646a48
     48 + assert new_packed_relocs[145598].addend == 0
     49 + assert new_packed_relocs[145598].symbol.name == "ioctl"
     50 + assert new_packed_relocs[145598].type == lief.ELF.Relocation.TYPE.AARCH64_ABS64
     51 + 
     52 + chrome_mod = lief.ELF.parse(chrome_sample)
     53 + chrome_mod_out = tmp_path / "chrome_mod.so"
     54 + builder = lief.ELF.Builder(chrome_mod)
     55 + builder.config.force_relocate = True
     56 + builder.build()
     57 + builder.write(chrome_mod_out.as_posix())
     58 + assert abs(chrome_mod_out.stat().st_size - original_size) < 0x5cf000
     59 + 
     60 + chrome_mod = lief.ELF.parse(chrome_mod_out)
     61 + 
     62 + mod_packed_relocs = [r for r in chrome_mod.dynamic_relocations if r.is_android_packed]
     63 + assert len(mod_packed_relocs) == 145599
     64 + 
     65 + assert mod_packed_relocs[0].address == 0x6426910 + 0x1000
     66 + assert mod_packed_relocs[0].addend == 0x6426910 + 0x1000
     67 + assert mod_packed_relocs[0].type == lief.ELF.Relocation.TYPE.AARCH64_RELATIVE
     68 + 
     69 + assert mod_packed_relocs[145576].address == 0x65e3598 + 0x1000
     70 + assert mod_packed_relocs[145576].addend == 0
     71 + assert mod_packed_relocs[145576].symbol.name == "memfd_create"
     72 + assert mod_packed_relocs[145576].type == lief.ELF.Relocation.TYPE.AARCH64_GLOB_DAT
     73 + 
     74 + assert mod_packed_relocs[145598].address == 0x6646a48 + 0x1000
     75 + assert mod_packed_relocs[145598].addend == 0
     76 + assert mod_packed_relocs[145598].symbol.name == "ioctl"
     77 + assert mod_packed_relocs[145598].type == lief.ELF.Relocation.TYPE.AARCH64_ABS64
     78 + 
     79 + 
     80 +def test_chrome_armv7(tmp_path: Path):
     81 + chrome_sample = Path(get_sample("ELF/libmonochrome-armv7.so"))
     82 + chrome = lief.ELF.parse(chrome_sample)
     83 + 
     84 + packed_relocs = [r for r in chrome.dynamic_relocations if r.is_android_packed]
     85 + assert len(packed_relocs) == 513897
     86 + 
     87 + assert packed_relocs[0].address == 0x471b14c
     88 + assert packed_relocs[0].addend == 0
     89 + assert packed_relocs[0].type == lief.ELF.Relocation.TYPE.ARM_RELATIVE
     90 + 
     91 + assert packed_relocs[513855].address == 0x49bbad0
     92 + assert packed_relocs[513855].addend == 0
     93 + assert packed_relocs[513855].symbol.name == "android_fdsan_exchange_owner_tag"
     94 + assert packed_relocs[513855].type == lief.ELF.Relocation.TYPE.ARM_GLOB_DAT
     95 + 
     96 + assert packed_relocs[513896].address == 0x49fd61c
     97 + assert packed_relocs[513896].addend == 0
     98 + assert packed_relocs[513896].symbol.name == "ioctl"
     99 + assert packed_relocs[513896].type == lief.ELF.Relocation.TYPE.ARM_ABS32
     100 + 
     101 + out_simple = tmp_path / "chrome_simple.so"
     102 + chrome.write(out_simple.as_posix())
     103 + original_size = chrome_sample.stat().st_size
     104 + new_size = out_simple.stat().st_size
     105 + assert new_size <= original_size
     106 + 
     107 + new = lief.ELF.parse(out_simple.as_posix())
     108 + 
     109 + new_packed_relocs = [r for r in new.dynamic_relocations if r.is_android_packed]
     110 + assert len(new_packed_relocs) == 513897
     111 + 
     112 + assert new_packed_relocs[0].address == 0x471b14c
     113 + assert new_packed_relocs[0].addend == 0
     114 + assert new_packed_relocs[0].type == lief.ELF.Relocation.TYPE.ARM_RELATIVE
     115 + 
     116 + assert new_packed_relocs[513855].address == 0x49bbad0
     117 + assert new_packed_relocs[513855].addend == 0
     118 + assert new_packed_relocs[513855].symbol.name == "android_fdsan_exchange_owner_tag"
     119 + assert new_packed_relocs[513855].type == lief.ELF.Relocation.TYPE.ARM_GLOB_DAT
     120 + 
     121 + assert new_packed_relocs[513896].address == 0x49fd61c
     122 + assert new_packed_relocs[513896].addend == 0
     123 + assert new_packed_relocs[513896].symbol.name == "ioctl"
     124 + assert new_packed_relocs[513896].type == lief.ELF.Relocation.TYPE.ARM_ABS32
     125 + 
     126 + chrome_mod = lief.ELF.parse(chrome_sample)
     127 + chrome_mod_out = tmp_path / "chrome_mod.so"
     128 + builder = lief.ELF.Builder(chrome_mod)
     129 + builder.config.force_relocate = True
     130 + builder.build()
     131 + builder.write(chrome_mod_out.as_posix())
     132 + assert abs(chrome_mod_out.stat().st_size - original_size) < 0x5cf000
     133 + 
     134 + chrome_mod = lief.ELF.parse(chrome_mod_out)
     135 + 
     136 + mod_packed_relocs = [r for r in chrome_mod.dynamic_relocations if r.is_android_packed]
     137 + assert len(mod_packed_relocs) == 513897
     138 + 
     139 + assert mod_packed_relocs[0].address == 0x471b14c + 0x1000
     140 + assert mod_packed_relocs[0].addend == 0
     141 + assert mod_packed_relocs[0].type == lief.ELF.Relocation.TYPE.ARM_RELATIVE
     142 + 
     143 + assert mod_packed_relocs[513855].address == 0x49bbad0 + 0x1000
     144 + assert mod_packed_relocs[513855].addend == 0
     145 + assert mod_packed_relocs[513855].symbol.name == "android_fdsan_exchange_owner_tag"
     146 + assert mod_packed_relocs[513855].type == lief.ELF.Relocation.TYPE.ARM_GLOB_DAT
     147 + 
     148 + assert mod_packed_relocs[513896].address == 0x49fd61c + 0x1000
     149 + assert mod_packed_relocs[513896].addend == 0
     150 + assert mod_packed_relocs[513896].symbol.name == "ioctl"
     151 + assert mod_packed_relocs[513896].type == lief.ELF.Relocation.TYPE.ARM_ABS32
     152 + 
  • ■ ■ ■ ■ ■ ■
    tests/elf/test_modify_relocations.py
    skipped 18 lines
    19 19   
    20 20   ls = lief.ELF.parse(sample_path)
    21 21   
    22  - relocation = lief.ELF.Relocation(0x61D370, type=lief.ELF.Relocation.TYPE.X86_64_JUMP_SLOT, is_rela=True)
     22 + relocation = lief.ELF.Relocation(0x61D370, type=lief.ELF.Relocation.TYPE.X86_64_JUMP_SLOT,
     23 + encoding=lief.ELF.Relocation.ENCODING.RELA)
    23 24   
    24 25   symbol = lief.ELF.Symbol()
    25 26   symbol.name = "printf123"
    skipped 19 lines
    45 46   
    46 47   target = lief.ELF.parse(sample_path)
    47 48   
    48  - relocation = lief.ELF.Relocation(0x201028, type=lief.ELF.Relocation.TYPE.X86_64_JUMP_SLOT, is_rela=True)
     49 + relocation = lief.ELF.Relocation(0x201028, type=lief.ELF.Relocation.TYPE.X86_64_JUMP_SLOT,
     50 + encoding=lief.ELF.Relocation.ENCODING.RELA)
    49 51   
    50 52   symbol = lief.ELF.Symbol()
    51 53   symbol.name = "printf123"
    skipped 19 lines
    71 73   
    72 74   target = lief.ELF.parse(sample_path)
    73 75   
    74  - relocation = lief.ELF.Relocation(0x2018, type=lief.ELF.Relocation.TYPE.X86_JUMP_SLOT, is_rela=False)
     76 + relocation = lief.ELF.Relocation(0x2018, type=lief.ELF.Relocation.TYPE.X86_JUMP_SLOT,
     77 + encoding=lief.ELF.Relocation.ENCODING.REL)
    75 78   
    76 79   symbol = lief.ELF.Symbol()
    77 80   symbol.name = "printf123"
    skipped 9 lines
  • ■ ■ ■ ■ ■ ■
    tests/elf/test_parser.py
    1 1  import lief
    2  -from utils import get_sample, is_64bits_platform
     2 +from utils import get_sample, is_64bits_platform, glibc_version
    3 3  from pathlib import Path
    4 4   
    5 5  def test_symbol_count():
    skipped 134 lines
    140 140   elf = lief.ELF.parse(get_sample('ELF/issue_975_aarch64.o'))
    141 141   for note in elf.notes:
    142 142   print(note)
    143  - #assert len(elf.sections) > 0
     143 + 
     144 + 
     145 + 
    144 146   
  • ■ ■ ■ ■ ■ ■
    tests/elf/test_relr_relocations.py
     1 +import lief
     2 +import ctypes
     3 +from utils import get_sample, glibc_version
     4 +from pathlib import Path
     5 + 
     6 + 
     7 +def test_relr_relocations(tmp_path: Path):
     8 + elf = lief.ELF.parse(get_sample('ELF/libm-ubuntu24.so'))
     9 + 
     10 + relr_reloc = [r for r in elf.relocations if r.encoding == lief.ELF.Relocation.ENCODING.RELR]
     11 + assert len(relr_reloc) == 3
     12 + 
     13 + assert relr_reloc[0].address == 0xe9c48
     14 + assert relr_reloc[0].type == lief.ELF.Relocation.TYPE.X86_64_RELATIVE
     15 + 
     16 + assert relr_reloc[1].address == 0xe9c50
     17 + assert relr_reloc[1].type == lief.ELF.Relocation.TYPE.X86_64_RELATIVE
     18 + 
     19 + assert relr_reloc[2].address == 0xea000
     20 + assert relr_reloc[2].type == lief.ELF.Relocation.TYPE.X86_64_RELATIVE
     21 + 
     22 + out = tmp_path / "libm.so.6"
     23 + 
     24 + builder = lief.ELF.Builder(elf)
     25 + builder.config.force_relocate = True
     26 + builder.build()
     27 + builder.write(out.as_posix())
     28 + 
     29 + new = lief.ELF.parse(out.as_posix())
     30 + 
     31 + new_relr_reloc = [r for r in new.relocations if r.encoding == lief.ELF.Relocation.ENCODING.RELR]
     32 + assert len(new_relr_reloc) == 3
     33 + 
     34 + assert new_relr_reloc[0].address == 0x1000 + 0xe9c48
     35 + assert new_relr_reloc[1].address == 0x1000 + 0xe9c50
     36 + assert new_relr_reloc[2].address == 0x1000 + 0xea000
     37 + 
     38 + if (2, 38) <= glibc_version():
     39 + print("Trying to load libm.so")
     40 + out.chmod(0o755)
     41 + lib = ctypes.cdll.LoadLibrary(out.as_posix())
     42 + assert lib.cos is not None
     43 + 
     44 + 
Please wait...
Page is in error, reload to recover