mirror of
https://github.com/lief-project/LIEF.git
synced 2026-10-11 22:09:53 +00:00
1827 lines
58 KiB
C++
1827 lines
58 KiB
C++
/* Copyright 2021 - 2026 R. Thomas
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
#ifndef LIEF_ELF_EXE_LAYOUT_H
|
|
#define LIEF_ELF_EXE_LAYOUT_H
|
|
#include "LIEF/ELF/Binary.hpp"
|
|
#include "LIEF/ELF/Builder.hpp"
|
|
#include "LIEF/ELF/DynamicEntryArray.hpp"
|
|
#include "LIEF/ELF/DynamicEntryAuxiliary.hpp"
|
|
#include "LIEF/ELF/DynamicEntryFilter.hpp"
|
|
#include "LIEF/ELF/DynamicEntryLibrary.hpp"
|
|
#include "LIEF/ELF/DynamicEntryRpath.hpp"
|
|
#include "LIEF/ELF/DynamicEntryRunPath.hpp"
|
|
#include "LIEF/ELF/DynamicSharedObject.hpp"
|
|
#include "LIEF/ELF/GnuHash.hpp"
|
|
#include "LIEF/ELF/Note.hpp"
|
|
#include "LIEF/ELF/Relocation.hpp"
|
|
#include "LIEF/ELF/Section.hpp"
|
|
#include "LIEF/ELF/Segment.hpp"
|
|
#include "LIEF/ELF/Symbol.hpp"
|
|
#include "LIEF/ELF/SymbolVersionAux.hpp"
|
|
#include "LIEF/ELF/SymbolVersionAuxRequirement.hpp"
|
|
#include "LIEF/ELF/SymbolVersionDefinition.hpp"
|
|
#include "LIEF/ELF/SymbolVersionRequirement.hpp"
|
|
#include "LIEF/ELF/SysvHash.hpp"
|
|
#include "LIEF/ELF/utils.hpp"
|
|
#include "LIEF/errors.hpp"
|
|
#include "LIEF/iostream.hpp"
|
|
#include "LIEF/visibility.h"
|
|
#include <algorithm>
|
|
#include <iterator>
|
|
|
|
#include "ELF/Structures.hpp"
|
|
#include "Layout.hpp"
|
|
#include "internal_utils.hpp"
|
|
#include "logging.hpp"
|
|
|
|
|
|
namespace LIEF::ELF {
|
|
|
|
inline Relocation::TYPE relative_from_arch(ARCH arch) {
|
|
using TYPE = Relocation::TYPE;
|
|
switch (arch) {
|
|
case ARCH::AARCH64: return TYPE::AARCH64_RELATIVE;
|
|
case ARCH::ARM: return TYPE::ARM_RELATIVE;
|
|
case ARCH::X86_64: return TYPE::X86_64_RELATIVE;
|
|
case ARCH::I386: return TYPE::X86_RELATIVE;
|
|
case ARCH::PPC: return TYPE::PPC_RELATIVE;
|
|
case ARCH::PPC64: return TYPE::PPC64_RELATIVE;
|
|
case ARCH::HEXAGON: return TYPE::HEX_RELATIVE;
|
|
default: return TYPE::UNKNOWN;
|
|
}
|
|
return TYPE::UNKNOWN;
|
|
}
|
|
|
|
/// Compute the size and the offset of the elements
|
|
/// needed to rebuild the ELF file.
|
|
class LIEF_LOCAL ExeLayout : public Layout {
|
|
public:
|
|
struct sym_verdef_info_t {
|
|
using list_names_t = std::vector<std::string>;
|
|
std::set<list_names_t> names_list;
|
|
std::unordered_map<const SymbolVersionDefinition*, const list_names_t*>
|
|
def_to_names;
|
|
std::unordered_map<const list_names_t*, size_t> names_offset;
|
|
};
|
|
using Layout::Layout;
|
|
|
|
ExeLayout(const ExeLayout&) = delete;
|
|
ExeLayout& operator=(const ExeLayout&) = delete;
|
|
|
|
ExeLayout(ExeLayout&&) = default;
|
|
ExeLayout& operator=(ExeLayout&&) = default;
|
|
|
|
template<class ELF_T>
|
|
size_t dynamic_size() {
|
|
// The size of the .dynamic / PT_DYNAMIC area
|
|
// is the number of elements times the size of each element (Elf64_Dyn or
|
|
// Elf32_Dyn)
|
|
using Elf_Dyn = typename ELF_T::Elf_Dyn;
|
|
return binary_->dynamic_entries_.size() * sizeof(Elf_Dyn);
|
|
}
|
|
|
|
template<class ELF_T>
|
|
size_t dynstr_size() {
|
|
// The .dynstr section contains:
|
|
// - library names (DT_NEEDED / DT_SONAME / DT_RPATH / DT_RUNPATH)
|
|
// - The symbol names from the .dynsym section
|
|
// - Names associated with:
|
|
// * Symbol definition
|
|
// * Symbol version requirement
|
|
// * Symbol version definition
|
|
if (!raw_dynstr_.empty()) {
|
|
return raw_dynstr_.size();
|
|
}
|
|
|
|
// Start with dynamic entries: NEEDED / SONAME etc.
|
|
vector_iostream raw_dynstr(should_swap());
|
|
raw_dynstr.write<uint8_t>(0);
|
|
|
|
std::vector<std::string_view> opt_list;
|
|
|
|
std::transform(binary_->dynamic_symbols_.begin(),
|
|
binary_->dynamic_symbols_.end(), std::back_inserter(opt_list),
|
|
[](const std::unique_ptr<Symbol>& sym) {
|
|
return static_cast<const Symbol&>(*sym).name();
|
|
});
|
|
|
|
for (std::unique_ptr<DynamicEntry>& entry : binary_->dynamic_entries_) {
|
|
switch (entry->tag()) {
|
|
case DynamicEntry::TAG::NEEDED:
|
|
{
|
|
opt_list.push_back(entry->as<DynamicEntryLibrary>()->name());
|
|
break;
|
|
}
|
|
|
|
case DynamicEntry::TAG::SONAME:
|
|
{
|
|
opt_list.push_back(entry->as<DynamicSharedObject>()->name());
|
|
break;
|
|
}
|
|
|
|
case DynamicEntry::TAG::AUXILIARY:
|
|
{
|
|
opt_list.push_back(entry->as<DynamicEntryAuxiliary>()->name());
|
|
break;
|
|
}
|
|
|
|
case DynamicEntry::TAG::FILTER:
|
|
{
|
|
opt_list.push_back(entry->as<DynamicEntryFilter>()->name());
|
|
break;
|
|
}
|
|
|
|
case DynamicEntry::TAG::RPATH:
|
|
{
|
|
opt_list.push_back(entry->as<DynamicEntryRpath>()->rpath());
|
|
break;
|
|
}
|
|
|
|
case DynamicEntry::TAG::RUNPATH:
|
|
{
|
|
opt_list.push_back(entry->as<DynamicEntryRunPath>()->runpath());
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
}
|
|
}
|
|
}
|
|
// Symbol definition
|
|
for (const SymbolVersionDefinition& svd :
|
|
binary_->symbols_version_definition())
|
|
{
|
|
sym_verdef_info_t::list_names_t aux_names;
|
|
auto saux = svd.symbols_aux();
|
|
aux_names.reserve(saux.size());
|
|
for (const SymbolVersionAux& sva : saux) {
|
|
aux_names.emplace_back(sva.name());
|
|
opt_list.push_back(sva.name());
|
|
}
|
|
auto res = verdef_info_.names_list.insert(std::move(aux_names));
|
|
verdef_info_.def_to_names[&svd] = &*res.first;
|
|
}
|
|
|
|
// Symbol version requirement
|
|
for (const SymbolVersionRequirement& svr :
|
|
binary_->symbols_version_requirement())
|
|
{
|
|
opt_list.push_back(svr.name());
|
|
for (const SymbolVersionAuxRequirement& svar : svr.auxiliary_symbols()) {
|
|
opt_list.push_back(svar.name());
|
|
}
|
|
}
|
|
|
|
size_t offset_counter = raw_dynstr.tellp();
|
|
|
|
std::vector<std::string> string_table_optimized = optimize(
|
|
opt_list, [](const std::string_view& name) { return name; },
|
|
offset_counter, &offset_name_map_
|
|
);
|
|
|
|
for (std::string_view name : string_table_optimized) {
|
|
raw_dynstr.write(name);
|
|
}
|
|
|
|
raw_dynstr.move(raw_dynstr_);
|
|
return raw_dynstr_.size();
|
|
}
|
|
|
|
template<class ELF_T>
|
|
size_t dynsym_size() {
|
|
using Elf_Sym = typename ELF_T::Elf_Sym;
|
|
return binary_->dynamic_symbols_.size() * sizeof(Elf_Sym);
|
|
}
|
|
|
|
template<class ELF_T>
|
|
size_t static_sym_size() {
|
|
using Elf_Sym = typename ELF_T::Elf_Sym;
|
|
return binary_->symtab_symbols_.size() * sizeof(Elf_Sym);
|
|
}
|
|
|
|
template<class ELF_T>
|
|
size_t dynamic_arraysize(DynamicEntry::TAG tag) {
|
|
using uint = typename ELF_T::uint;
|
|
DynamicEntry* entry = binary_->get(tag);
|
|
if (entry == nullptr || !DynamicEntryArray::classof(entry)) {
|
|
return 0;
|
|
}
|
|
return entry->as<const DynamicEntryArray&>()->size() * sizeof(uint);
|
|
}
|
|
|
|
template<class ELF_T>
|
|
size_t note_size() {
|
|
if (!raw_notes_.empty()) {
|
|
return raw_notes_.size();
|
|
}
|
|
|
|
vector_iostream raw_notes(should_swap());
|
|
for (const Note& note : binary_->notes()) {
|
|
size_t pos = raw_notes.tellp();
|
|
// First we have to write the length of the Note's name
|
|
const auto namesz = static_cast<uint32_t>(note.name().size() + 1);
|
|
raw_notes.write<uint32_t>(namesz);
|
|
|
|
// Then the length of the Note's description
|
|
const auto descsz = static_cast<uint32_t>(note.description().size());
|
|
raw_notes.write<uint32_t>(descsz);
|
|
|
|
// Then the note's type
|
|
const uint32_t type = note.original_type();
|
|
raw_notes.write<uint32_t>(type);
|
|
|
|
// Then we write the note's name
|
|
raw_notes.write(note.name());
|
|
|
|
// Alignment
|
|
raw_notes.align(sizeof(uint32_t), 0);
|
|
|
|
// description content (manipulated in 4 byte/uint32_t chunks)
|
|
span<const uint8_t> description = note.description();
|
|
const auto* desc_ptr = reinterpret_cast<const uint32_t*>(description.data());
|
|
size_t i = 0;
|
|
for (; i < description.size() / sizeof(uint32_t); i++) {
|
|
raw_notes.write<uint32_t>(desc_ptr[i]);
|
|
}
|
|
if (description.size() % sizeof(uint32_t) != 0) {
|
|
uint32_t padded = 0;
|
|
auto* ptr = reinterpret_cast<uint8_t*>(&padded);
|
|
memcpy(ptr, desc_ptr + i, description.size() % sizeof(uint32_t));
|
|
raw_notes.write<uint32_t>(padded);
|
|
}
|
|
notes_off_map_.emplace(¬e, pos);
|
|
}
|
|
raw_notes.move(raw_notes_);
|
|
return raw_notes_.size();
|
|
}
|
|
|
|
template<class ELF_T>
|
|
size_t symbol_sysv_hash_size() {
|
|
const SysvHash* sysv_hash = binary_->sysv_hash();
|
|
if (sysv_hash == nullptr) {
|
|
return 0;
|
|
}
|
|
nchain_ = sysv_hash->nchain();
|
|
if (nchain_ != binary_->dynamic_symbols_.size()) {
|
|
LIEF_DEBUG("nchain of .hash section changed from {:d} to {:d}", nchain_,
|
|
binary_->dynamic_symbols_.size());
|
|
nchain_ = binary_->dynamic_symbols_.size();
|
|
}
|
|
return (sysv_hash->nbucket() + nchain_ + /* header */ 2) * sizeof(uint32_t);
|
|
}
|
|
|
|
template<class ELF_T>
|
|
size_t section_table_size() {
|
|
using Elf_Shdr = typename ELF_T::Elf_Shdr;
|
|
return binary_->sections_.size() * sizeof(Elf_Shdr);
|
|
}
|
|
|
|
template<class ELF_T>
|
|
size_t symbol_gnu_hash_size() {
|
|
// Mainly inspired by
|
|
// * https://github.com/llvm-mirror/lld/blob/master/ELF/SyntheticSections.cpp
|
|
//
|
|
// Checking is performed here:
|
|
// * https://github.com/lattera/glibc/blob/a2f34833b1042d5d8eeb263b4cf4caaea138c4ad/elf/dl-lookup.c#L228
|
|
//
|
|
// See also:
|
|
// * p.9, https://www.akkadia.org/drepper/dsohowto.pdf
|
|
using uint = typename ELF_T::uint;
|
|
if (!raw_gnu_hash_.empty()) {
|
|
return raw_gnu_hash_.size();
|
|
}
|
|
uint32_t first_exported_symbol_index = 0;
|
|
if (new_symndx_ >= 0) {
|
|
first_exported_symbol_index = new_symndx_;
|
|
} else {
|
|
LIEF_WARN("First exported symbol index not set");
|
|
}
|
|
|
|
const GnuHash* gnu_hash = binary_->gnu_hash();
|
|
if (gnu_hash == nullptr) {
|
|
return 0;
|
|
}
|
|
|
|
const uint32_t nb_buckets = gnu_hash->nb_buckets();
|
|
const uint32_t symndx = first_exported_symbol_index;
|
|
const uint32_t maskwords = gnu_hash->maskwords();
|
|
const uint32_t shift2 = gnu_hash->shift2();
|
|
|
|
const std::vector<uint64_t>& filters = gnu_hash->bloom_filters();
|
|
if (!filters.empty() && filters[0] == 0) {
|
|
LIEF_DEBUG("Bloom filter is null");
|
|
}
|
|
|
|
if (shift2 == 0) {
|
|
LIEF_DEBUG("Shift2 is null");
|
|
}
|
|
|
|
LIEF_DEBUG("Number of buckets : {:#x}", nb_buckets);
|
|
LIEF_DEBUG("First symbol idx : {:#x}", symndx);
|
|
LIEF_DEBUG("Number of bloom filters : {:#x}", maskwords);
|
|
LIEF_DEBUG("Shift : {:#x}", shift2);
|
|
|
|
// MANDATORY !
|
|
std::stable_sort(binary_->dynamic_symbols_.begin() + symndx,
|
|
binary_->dynamic_symbols_.end(),
|
|
[&nb_buckets](const std::unique_ptr<Symbol>& lhs,
|
|
const std::unique_ptr<Symbol>& rhs) {
|
|
return (dl_new_hash(lhs->name().c_str()) % nb_buckets) <
|
|
(dl_new_hash(rhs->name().c_str()) % nb_buckets);
|
|
});
|
|
Binary::it_dynamic_symbols dynamic_symbols = binary_->dynamic_symbols();
|
|
|
|
vector_iostream raw_gnuhash(should_swap());
|
|
raw_gnuhash.reserve(4 * sizeof(uint32_t) + // header
|
|
maskwords * sizeof(uint) + // bloom filters
|
|
nb_buckets * sizeof(uint32_t) + // buckets
|
|
(dynamic_symbols.size() - symndx) *
|
|
sizeof(uint32_t)); // hash values
|
|
|
|
// Write header
|
|
// =================================
|
|
raw_gnuhash.write<uint32_t>(nb_buckets)
|
|
.write<uint32_t>(symndx)
|
|
.write<uint32_t>(maskwords)
|
|
.write<uint32_t>(shift2);
|
|
|
|
// Compute Bloom filters
|
|
// =================================
|
|
std::vector<uint> bloom_filters(maskwords, 0);
|
|
size_t C = sizeof(uint) * 8; // 32 for ELF, 64 for ELF64
|
|
|
|
for (size_t i = symndx; i < dynamic_symbols.size(); ++i) {
|
|
const uint32_t hash = dl_new_hash(dynamic_symbols[i].name().c_str());
|
|
const size_t pos = (hash / C) & (gnu_hash->maskwords() - 1);
|
|
uint V = (static_cast<uint>(1) << (hash % C)) |
|
|
(static_cast<uint>(1) << ((hash >> gnu_hash->shift2()) % C));
|
|
bloom_filters[pos] |= V;
|
|
}
|
|
for (size_t idx = 0; idx < bloom_filters.size(); ++idx) {
|
|
LIEF_DEBUG("Bloom filter [{:d}]: {:#x}", idx, bloom_filters[idx]);
|
|
}
|
|
|
|
raw_gnuhash.write(bloom_filters);
|
|
|
|
// Write buckets and hash
|
|
// =================================
|
|
int previous_bucket = -1;
|
|
size_t hash_value_idx = 0;
|
|
std::vector<uint32_t> buckets(nb_buckets, 0);
|
|
std::vector<uint32_t> hash_values(dynamic_symbols.size() - symndx, 0);
|
|
|
|
for (size_t i = symndx; i < dynamic_symbols.size(); ++i) {
|
|
LIEF_DEBUG("Processing symbol {}", dynamic_symbols[i].name());
|
|
const uint32_t hash = dl_new_hash(dynamic_symbols[i].name().c_str());
|
|
int bucket = hash % nb_buckets;
|
|
|
|
if (bucket < previous_bucket) {
|
|
LIEF_ERR("Previous bucket is greater than the current one ({} < {})",
|
|
bucket, previous_bucket);
|
|
return 0;
|
|
}
|
|
|
|
if (bucket != previous_bucket) {
|
|
buckets[bucket] = i;
|
|
previous_bucket = bucket;
|
|
if (hash_value_idx > 0) {
|
|
hash_values[hash_value_idx - 1] |= 1;
|
|
}
|
|
}
|
|
|
|
hash_values[hash_value_idx] = hash & ~1;
|
|
++hash_value_idx;
|
|
}
|
|
|
|
if (hash_value_idx > 0) {
|
|
hash_values[hash_value_idx - 1] |= 1;
|
|
}
|
|
|
|
raw_gnuhash.write(buckets).write(hash_values);
|
|
raw_gnuhash.move(raw_gnu_hash_);
|
|
return raw_gnu_hash_.size();
|
|
}
|
|
|
|
template<class ELF_T>
|
|
size_t dynamic_relocations_size() {
|
|
using Elf_Rela = typename ELF_T::Elf_Rela;
|
|
using Elf_Rel = typename ELF_T::Elf_Rel;
|
|
const Binary::it_dynamic_relocations& dyn_relocs =
|
|
binary_->dynamic_relocations();
|
|
const size_t nb_rel_a = std::count_if(dyn_relocs.begin(), dyn_relocs.end(),
|
|
[](const Relocation& R) {
|
|
return R.is_rel() || R.is_rela();
|
|
});
|
|
|
|
const size_t computed_size = binary_->has(DynamicEntry::TAG::RELA) ?
|
|
nb_rel_a * sizeof(Elf_Rela) :
|
|
nb_rel_a * sizeof(Elf_Rel);
|
|
return computed_size;
|
|
}
|
|
|
|
template<class ELF_T>
|
|
size_t pltgot_relocations_size() {
|
|
using Elf_Rela = typename ELF_T::Elf_Rela;
|
|
using Elf_Rel = typename ELF_T::Elf_Rel;
|
|
const Binary::it_pltgot_relocations& pltgot_relocs =
|
|
binary_->pltgot_relocations();
|
|
|
|
const DynamicEntry* dt_rela = binary_->get(DynamicEntry::TAG::PLTREL);
|
|
|
|
const ARCH arch = binary_->header().machine_type();
|
|
|
|
const bool is_rela =
|
|
dt_rela != nullptr && DynamicEntry::from_value(dt_rela->value(), arch) ==
|
|
DynamicEntry::TAG::RELA;
|
|
|
|
if (is_rela) {
|
|
return pltgot_relocs.size() * sizeof(Elf_Rela);
|
|
}
|
|
return pltgot_relocs.size() * sizeof(Elf_Rel);
|
|
}
|
|
|
|
template<class ELF_T>
|
|
size_t symbol_version() {
|
|
return binary_->symbol_version_table_.size() * sizeof(uint16_t);
|
|
}
|
|
|
|
template<class ELF_T>
|
|
size_t symbol_vdef_size() {
|
|
using Elf_Verdef = typename ELF_T::Elf_Verdef;
|
|
using Elf_Verdaux = typename ELF_T::Elf_Verdaux;
|
|
CHECK_FATAL(!binary_->symbols_version_definition().empty() &&
|
|
verdef_info_.def_to_names.empty(),
|
|
"Inconsistent state");
|
|
size_t computed_size =
|
|
binary_->symbols_version_definition().size() * sizeof(Elf_Verdef);
|
|
|
|
for (const sym_verdef_info_t::list_names_t& names : verdef_info_.names_list) {
|
|
computed_size += sizeof(Elf_Verdaux) * names.size();
|
|
}
|
|
return computed_size;
|
|
}
|
|
|
|
template<class ELF_T>
|
|
size_t symbol_vreq_size() {
|
|
using Elf_Verneed = typename ELF_T::Elf_Verneed;
|
|
using Elf_Vernaux = typename ELF_T::Elf_Vernaux;
|
|
size_t computed_size = 0;
|
|
for (const SymbolVersionRequirement& svr :
|
|
binary_->symbols_version_requirement())
|
|
{
|
|
computed_size += sizeof(Elf_Verneed) +
|
|
svr.auxiliary_symbols().size() * sizeof(Elf_Vernaux);
|
|
}
|
|
return computed_size;
|
|
}
|
|
|
|
template<class ELF_T>
|
|
size_t interpreter_size() {
|
|
// Access private field directly as
|
|
// we want to avoid has_interpreter() check
|
|
return binary_->interpreter_.size() + 1;
|
|
}
|
|
|
|
template<class ELF_T>
|
|
size_t android_relocations_size(bool force = false) {
|
|
static constexpr uint64_t GROUPED_BY_INFO_FLAG = 1 << 0;
|
|
static constexpr uint64_t GROUPED_BY_OFFSET_DELTA_FLAG = 1 << 1;
|
|
/* static constexpr uint64_t GROUPED_BY_ADDEND_FLAG = 1 << 2; */
|
|
static constexpr uint64_t GROUP_HAS_ADDEND_FLAG = 1 << 3;
|
|
|
|
using Elf_Xword = typename ELF_T::Elf_Xword;
|
|
|
|
// This code reproduces what the lld linker is doing for generating the
|
|
// packed relocations. See lld/ELF/SyntheticSections.cpp -
|
|
// AndroidPackedRelocationSection:updateAllocSize
|
|
constexpr size_t wordsize = sizeof(typename ELF_T::Elf_Addr);
|
|
const bool is_rela = binary_->has(DynamicEntry::TAG::ANDROID_RELA);
|
|
const Relocation::TYPE relative_reloc =
|
|
relative_from_arch(binary_->header().machine_type());
|
|
const uint64_t raw_relative_reloc = Relocation::to_value(relative_reloc);
|
|
|
|
const Header::CLASS elf_class = std::is_same_v<ELF_T, details::ELF32> ?
|
|
Header::CLASS::ELF32 :
|
|
Header::CLASS::ELF64;
|
|
|
|
if (force) {
|
|
raw_android_rela_.clear();
|
|
}
|
|
|
|
if (!raw_android_rela_.empty()) {
|
|
return raw_android_rela_.size();
|
|
}
|
|
|
|
std::vector<const Relocation*> android_relocs;
|
|
std::vector<const Relocation*> relative_rels;
|
|
std::vector<const Relocation*> non_relative_rels;
|
|
android_relocs.reserve(20);
|
|
|
|
for (const Relocation& R : binary_->relocations()) {
|
|
if (!R.is_android_packed()) {
|
|
continue;
|
|
}
|
|
android_relocs.push_back(&R);
|
|
R.is_relative() ? relative_rels.push_back(&R) :
|
|
non_relative_rels.push_back(&R);
|
|
}
|
|
|
|
std::sort(relative_rels.begin(), relative_rels.end(),
|
|
[](const Relocation* lhs, const Relocation* rhs) {
|
|
return lhs->address() < rhs->address();
|
|
});
|
|
|
|
std::vector<const Relocation*> ungrouped_relative;
|
|
std::vector<std::vector<const Relocation*>> relative_groups;
|
|
for (auto i = relative_rels.begin(), e = relative_rels.end(); i != e;) {
|
|
std::vector<const Relocation*> group;
|
|
do {
|
|
group.push_back(*i++);
|
|
} while (i != e && (*(i - 1))->address() + wordsize == (*i)->address());
|
|
|
|
if (group.size() < 8) {
|
|
ungrouped_relative.insert(ungrouped_relative.end(), group.begin(),
|
|
group.end());
|
|
} else {
|
|
relative_groups.emplace_back(std::move(group));
|
|
}
|
|
}
|
|
|
|
|
|
std::sort(non_relative_rels.begin(), non_relative_rels.end(),
|
|
[elf_class](const Relocation* lhs, const Relocation* rhs) {
|
|
if (lhs->r_info(elf_class) != rhs->r_info(elf_class)) {
|
|
return lhs->r_info(elf_class) < rhs->r_info(elf_class);
|
|
}
|
|
if (lhs->addend() != rhs->addend()) {
|
|
return lhs->addend() < rhs->addend();
|
|
}
|
|
return lhs->address() < rhs->address();
|
|
});
|
|
|
|
std::vector<const Relocation*> ungrouped_non_relative;
|
|
std::vector<std::vector<const Relocation*>> non_relative_group;
|
|
|
|
for (auto i = non_relative_rels.begin(), e = non_relative_rels.end(); i != e;)
|
|
{
|
|
auto j = i + 1;
|
|
while (j != e && (*i)->r_info(elf_class) == (*j)->r_info(elf_class) &&
|
|
(!is_rela || (*i)->addend() == (*j)->addend()))
|
|
{
|
|
++j;
|
|
}
|
|
|
|
if ((j - i) < 3 || (is_rela && (*i)->addend() != 0)) {
|
|
ungrouped_non_relative.insert(ungrouped_non_relative.end(), i, j);
|
|
} else {
|
|
non_relative_group.emplace_back(i, j);
|
|
}
|
|
i = j;
|
|
}
|
|
|
|
std::sort(ungrouped_non_relative.begin(), ungrouped_non_relative.end(),
|
|
[](const Relocation* lhs, const Relocation* rhs) {
|
|
return lhs->address() < rhs->address();
|
|
});
|
|
|
|
const unsigned has_addend_with_rela = is_rela ? GROUP_HAS_ADDEND_FLAG : 0;
|
|
uint64_t offset = 0;
|
|
uint64_t addend = 0;
|
|
|
|
vector_iostream ios(should_swap());
|
|
ios.write('A').write('P').write('S').write('2');
|
|
|
|
ios.write_sleb128(android_relocs.size());
|
|
ios.write_sleb128(0);
|
|
|
|
for (const std::vector<const Relocation*>& g : relative_groups) {
|
|
ios.write_sleb128(1);
|
|
ios.write_sleb128(GROUPED_BY_OFFSET_DELTA_FLAG | GROUPED_BY_INFO_FLAG |
|
|
has_addend_with_rela);
|
|
ios.write_sleb128(g[0]->address() - offset);
|
|
ios.write_sleb128(raw_relative_reloc);
|
|
if (is_rela) {
|
|
ios.write_sleb128(g[0]->addend() - addend);
|
|
addend = g[0]->addend();
|
|
}
|
|
|
|
ios.write_sleb128(g.size() - 1);
|
|
ios.write_sleb128(GROUPED_BY_OFFSET_DELTA_FLAG | GROUPED_BY_INFO_FLAG |
|
|
has_addend_with_rela);
|
|
ios.write_sleb128(wordsize);
|
|
ios.write_sleb128(raw_relative_reloc);
|
|
if (is_rela) {
|
|
auto it = g.begin();
|
|
++it;
|
|
for (; it != g.end(); ++it) {
|
|
ios.write_sleb128((*it)->addend() - addend);
|
|
addend = (*it)->addend();
|
|
}
|
|
}
|
|
offset = g.back()->address();
|
|
}
|
|
|
|
if (!ungrouped_relative.empty()) {
|
|
ios.write_sleb128(ungrouped_relative.size());
|
|
ios.write_sleb128(GROUPED_BY_INFO_FLAG | has_addend_with_rela);
|
|
ios.write_sleb128(raw_relative_reloc);
|
|
for (const Relocation* R : ungrouped_relative) {
|
|
ios.write_sleb128(R->address() - offset);
|
|
offset = R->address();
|
|
if (is_rela) {
|
|
ios.write_sleb128(R->addend() - addend);
|
|
addend = R->addend();
|
|
}
|
|
}
|
|
}
|
|
|
|
for (const std::vector<const Relocation*>& g : non_relative_group) {
|
|
ios.write_sleb128(g.size());
|
|
ios.write_sleb128(GROUPED_BY_INFO_FLAG);
|
|
ios.write_sleb128(static_cast<Elf_Xword>(g[0]->r_info(elf_class)));
|
|
|
|
for (const Relocation* R : g) {
|
|
ios.write_sleb128(R->address() - offset);
|
|
offset = R->address();
|
|
}
|
|
addend = 0;
|
|
}
|
|
|
|
if (!ungrouped_non_relative.empty()) {
|
|
ios.write_sleb128(ungrouped_non_relative.size());
|
|
ios.write_sleb128(has_addend_with_rela);
|
|
for (const Relocation* R : ungrouped_non_relative) {
|
|
ios.write_sleb128(R->address() - offset);
|
|
offset = R->address();
|
|
ios.write_sleb128(static_cast<Elf_Xword>(R->r_info(elf_class)));
|
|
if (is_rela) {
|
|
ios.write_sleb128(R->addend() - addend);
|
|
addend = R->addend();
|
|
}
|
|
}
|
|
}
|
|
|
|
ios.move(raw_android_rela_);
|
|
return raw_android_rela_.size();
|
|
}
|
|
|
|
template<class ELF_T>
|
|
size_t relative_relocations_size(bool force = false) {
|
|
// This code is inspired by LLVM-lld:
|
|
// lld/ELF/SyntheticSections.cpp - RelrSection<ELFT>::updateAllocSize
|
|
// https://github.com/llvm/llvm-project/blob/754a8add57098ef71e4a51a9caa0cc175e94377d/lld/ELF/SyntheticSections.cpp#L1997-L2078
|
|
using Elf_Addr = typename ELF_T::Elf_Addr;
|
|
|
|
if (force) {
|
|
raw_relr_.clear();
|
|
}
|
|
|
|
if (!raw_relr_.empty()) {
|
|
return raw_relr_.size();
|
|
}
|
|
|
|
std::vector<const Relocation*> relr_relocs;
|
|
relr_relocs.reserve(20);
|
|
|
|
for (const Relocation& R : binary_->relocations()) {
|
|
if (R.is_relatively_encoded()) {
|
|
relr_relocs.push_back(&R);
|
|
}
|
|
}
|
|
|
|
std::unique_ptr<uint64_t[]> offsets(new uint64_t[relr_relocs.size()]);
|
|
for (size_t i = 0; i < relr_relocs.size(); ++i) {
|
|
offsets[i] = relr_relocs[i]->address();
|
|
}
|
|
std::sort(offsets.get(), offsets.get() + relr_relocs.size());
|
|
|
|
const size_t wordsize = sizeof(Elf_Addr);
|
|
const size_t nbits = wordsize * 8 - 1;
|
|
|
|
vector_iostream raw_relr(should_swap());
|
|
|
|
for (size_t i = 0, e = relr_relocs.size(); i != e;) {
|
|
raw_relr.write<Elf_Addr>(offsets[i]);
|
|
uint64_t base = offsets[i] + wordsize;
|
|
++i;
|
|
|
|
for (;;) {
|
|
uint64_t bitmap = 0;
|
|
for (; i != e; ++i) {
|
|
uint64_t d = offsets[i] - base;
|
|
if (d >= (nbits * wordsize) || (d % wordsize) != 0) {
|
|
break;
|
|
}
|
|
bitmap |= uint64_t(1) << (d / wordsize);
|
|
}
|
|
if (!bitmap) {
|
|
break;
|
|
}
|
|
raw_relr.write<Elf_Addr>((bitmap << 1) | 1);
|
|
base += nbits * wordsize;
|
|
}
|
|
}
|
|
raw_relr.move(raw_relr_);
|
|
return raw_relr_.size();
|
|
}
|
|
|
|
void relocate_dynamic(uint64_t size) {
|
|
dynamic_size_ = size;
|
|
}
|
|
|
|
void relocate_dynstr(bool val) {
|
|
relocate_dynstr_ = val;
|
|
}
|
|
|
|
void relocate_relr(bool val) {
|
|
relocate_relr_ = val;
|
|
}
|
|
|
|
void relocate_android_rela(bool val) {
|
|
relocate_android_rela_ = val;
|
|
}
|
|
|
|
void relocate_shstr(bool val) {
|
|
relocate_shstrtab_ = val;
|
|
}
|
|
|
|
void relocate_strtab(bool val) {
|
|
relocate_strtab_ = val;
|
|
}
|
|
|
|
void relocate_gnu_hash(bool val) {
|
|
relocate_gnu_hash_ = val;
|
|
}
|
|
|
|
void relocate_sysv_hash(uint64_t size) {
|
|
sysv_size_ = size;
|
|
}
|
|
|
|
void relocate_dynsym(uint64_t size) {
|
|
dynsym_size_ = size;
|
|
}
|
|
|
|
void relocate_symver(uint64_t size) {
|
|
sver_size_ = size;
|
|
}
|
|
|
|
void relocate_symverd(uint64_t size) {
|
|
sverd_size_ = size;
|
|
}
|
|
|
|
void relocate_symverr(uint64_t size) {
|
|
sverr_size_ = size;
|
|
}
|
|
|
|
void relocate_preinit_array(uint64_t size) {
|
|
preinit_size_ = size;
|
|
}
|
|
|
|
void relocate_init_array(uint64_t size) {
|
|
init_size_ = size;
|
|
}
|
|
|
|
void relocate_fini_array(uint64_t size) {
|
|
fini_size_ = size;
|
|
}
|
|
|
|
void relocate_dyn_reloc(uint64_t size) {
|
|
dynamic_reloc_size_ = size;
|
|
}
|
|
|
|
void relocate_plt_reloc(uint64_t size) {
|
|
pltgot_reloc_size_ = size;
|
|
}
|
|
|
|
void relocate_interpreter(uint64_t size) {
|
|
interp_size_ = size;
|
|
}
|
|
|
|
void relocate_notes(bool value) {
|
|
relocate_notes_ = value;
|
|
}
|
|
|
|
void relocate_symtab(size_t size) {
|
|
symtab_size_ = size;
|
|
}
|
|
|
|
const std::vector<uint8_t>& raw_dynstr() const {
|
|
return raw_dynstr_;
|
|
}
|
|
|
|
const std::vector<uint8_t>& raw_shstr() const override {
|
|
return raw_shstrtab_;
|
|
}
|
|
|
|
const std::vector<uint8_t>& raw_gnuhash() const {
|
|
return raw_gnu_hash_;
|
|
}
|
|
|
|
const std::vector<uint8_t>& raw_notes() const {
|
|
return raw_notes_;
|
|
}
|
|
|
|
sym_verdef_info_t& verdef_info() {
|
|
return verdef_info_;
|
|
}
|
|
|
|
const sym_verdef_info_t& verdef_info() const {
|
|
return verdef_info_;
|
|
}
|
|
|
|
const std::vector<uint8_t>& raw_relr() const {
|
|
return raw_relr_;
|
|
}
|
|
|
|
const std::vector<uint8_t>& raw_android_rela() const {
|
|
return raw_android_rela_;
|
|
}
|
|
|
|
result<bool> relocate() {
|
|
const bool needs_interp =
|
|
interp_size_ > 0 && !binary_->has(Segment::TYPE::INTERP);
|
|
|
|
uint64_t read_segment = interp_size_ + sysv_size_ + dynsym_size_ + sver_size_ +
|
|
sverd_size_ + sverr_size_ + dynamic_reloc_size_ +
|
|
pltgot_reloc_size_;
|
|
if (relocate_relr_) {
|
|
read_segment += raw_relr_.size();
|
|
}
|
|
|
|
if (relocate_android_rela_) {
|
|
read_segment += raw_android_rela_.size();
|
|
}
|
|
|
|
if (relocate_notes_) {
|
|
read_segment += raw_notes_.size();
|
|
}
|
|
|
|
if (relocate_dynstr_) {
|
|
read_segment += raw_dynstr_.size();
|
|
}
|
|
|
|
if (relocate_gnu_hash_) {
|
|
read_segment += raw_gnu_hash_.size();
|
|
}
|
|
|
|
const uint64_t read_write_segment =
|
|
init_size_ + preinit_size_ + fini_size_ + dynamic_size_;
|
|
|
|
const size_t required_segments = static_cast<size_t>(needs_interp) +
|
|
static_cast<size_t>(read_segment > 0) +
|
|
static_cast<size_t>(read_write_segment > 0);
|
|
if (required_segments > 0 &&
|
|
binary_->relocate_phdr_table_auto(required_segments) == 0)
|
|
{
|
|
LIEF_ERR("Unable to reserve {} program headers before relocating the "
|
|
"executable layout",
|
|
required_segments);
|
|
return make_error_code(lief_errors::build_error);
|
|
}
|
|
|
|
/* PT_INTERP segment (optional)
|
|
*
|
|
*/
|
|
if (needs_interp) {
|
|
Segment interp_segment;
|
|
interp_segment.alignment(0x8);
|
|
interp_segment.type(Segment::TYPE::INTERP);
|
|
interp_segment.add(Segment::FLAGS::R);
|
|
interp_segment.content(std::vector<uint8_t>(interp_size_));
|
|
if (Segment* interp = binary_->add(interp_segment)) {
|
|
LIEF_DEBUG("Interp Segment: {:#x}:{:#x}", interp->virtual_address(),
|
|
interp->virtual_size());
|
|
} else {
|
|
LIEF_ERR("Failed to add PT_INTERP segment");
|
|
}
|
|
}
|
|
|
|
/* Segment 1.
|
|
* .interp
|
|
* .note.*
|
|
* .gnu.hash
|
|
* .hash
|
|
* .dynsym
|
|
* .dynstr
|
|
* .gnu.version
|
|
* .gnu.version_d
|
|
* .gnu.version_r
|
|
* .rela.dyn
|
|
* .rela.plt
|
|
* .relr.dyn
|
|
* Perm: READ ONLY
|
|
*/
|
|
Segment* new_rsegment = nullptr;
|
|
|
|
if (read_segment > 0) {
|
|
Segment rsegment;
|
|
rsegment.type(Segment::TYPE::LOAD);
|
|
rsegment.add(Segment::FLAGS::R);
|
|
rsegment.content(std::vector<uint8_t>(read_segment));
|
|
new_rsegment = binary_->add(rsegment);
|
|
if (new_rsegment == nullptr) {
|
|
LIEF_ERR("Failed to add R-segment");
|
|
return make_error_code(lief_errors::build_error);
|
|
}
|
|
LIEF_DEBUG("R-Segment: {:#06x}:{:#06x}", new_rsegment->virtual_address(),
|
|
new_rsegment->virtual_size());
|
|
}
|
|
|
|
/* Segment 2
|
|
*
|
|
* .init_array
|
|
* .fini_array
|
|
* .preinit_array
|
|
* .prefini_array
|
|
* .dynamic
|
|
* .got
|
|
* .got.plt
|
|
* Perm: READ | WRITE
|
|
*/
|
|
Segment* new_rwsegment = nullptr;
|
|
Segment rwsegment;
|
|
if (read_write_segment > 0) {
|
|
rwsegment.type(Segment::TYPE::LOAD);
|
|
rwsegment.add(Segment::FLAGS::R | Segment::FLAGS::W);
|
|
rwsegment.content(std::vector<uint8_t>(read_write_segment));
|
|
new_rwsegment = binary_->add(rwsegment);
|
|
if (new_rwsegment != nullptr) {
|
|
LIEF_DEBUG("RW-Segment: {:#x}:{:#x}", new_rwsegment->virtual_address(),
|
|
new_rwsegment->virtual_size());
|
|
} else {
|
|
LIEF_ERR("Failed to add RW-segment");
|
|
return make_error_code(lief_errors::build_error);
|
|
}
|
|
}
|
|
|
|
if (relocate_shstrtab_) {
|
|
LIEF_DEBUG("Relocating .shstrtab");
|
|
|
|
// Remove the current .shstrtab section
|
|
Header& hdr = binary_->header();
|
|
if (hdr.section_name_table_idx() >= binary_->sections_.size()) {
|
|
LIEF_ERR("Section names table index out of range");
|
|
return make_error_code(lief_errors::file_format_error);
|
|
}
|
|
std::unique_ptr<Section>& string_names_section =
|
|
binary_->sections_[hdr.section_name_table_idx()];
|
|
std::string_view sec_name = binary_->shstrtab_name();
|
|
binary_->remove(*string_names_section, /* clear */ true);
|
|
Section sec_str_section(std::string(sec_name), Section::TYPE::STRTAB);
|
|
sec_str_section.content(std::vector<uint8_t>(raw_shstrtab_.size()));
|
|
Section* sec = binary_->add(sec_str_section, /*loaded=*/false,
|
|
/*pos=*/Binary::SEC_INSERT_POS::POST_SECTION);
|
|
if (sec != nullptr) {
|
|
if (auto idx = binary_->get_section_idx(*sec)) {
|
|
hdr.section_name_table_idx(*idx);
|
|
}
|
|
}
|
|
}
|
|
|
|
for (std::unique_ptr<Relocation>& reloc : binary_->relocations_) {
|
|
relocations_addresses_[reloc->address()] = reloc.get();
|
|
}
|
|
|
|
[[maybe_unused]] uint64_t va_r_base =
|
|
new_rsegment != nullptr ? new_rsegment->virtual_address() : 0;
|
|
[[maybe_unused]] uint64_t va_rw_base =
|
|
new_rwsegment != nullptr ? new_rwsegment->virtual_address() : 0;
|
|
|
|
if (interp_size_ > 0) {
|
|
Segment* pt_interp = binary_->get(Segment::TYPE::INTERP);
|
|
if (pt_interp == nullptr) {
|
|
LIEF_ERR("PT_INTERP segment not found");
|
|
return make_error_code(lief_errors::file_format_error);
|
|
}
|
|
|
|
Section* section = nullptr;
|
|
Segment::it_sections sections = pt_interp->sections();
|
|
if (!sections.empty()) {
|
|
section = §ions[0];
|
|
}
|
|
pt_interp->virtual_address(va_r_base);
|
|
pt_interp->virtual_size(interp_size_);
|
|
pt_interp->physical_address(va_r_base);
|
|
pt_interp->physical_size(interp_size_);
|
|
uint64_t offset_r_base = 0;
|
|
if (auto res = binary_->virtual_address_to_offset(va_r_base)) {
|
|
offset_r_base = *res;
|
|
} else {
|
|
return make_error_code(lief_errors::build_error);
|
|
}
|
|
|
|
pt_interp->file_offset(offset_r_base);
|
|
if (section != nullptr) {
|
|
section->virtual_address(va_r_base);
|
|
section->size(interp_size_);
|
|
section->offset(offset_r_base);
|
|
section->original_size_ = interp_size_;
|
|
}
|
|
|
|
va_r_base += interp_size_;
|
|
}
|
|
|
|
if (relocate_notes_) {
|
|
Segment* note_segment = binary_->get(Segment::TYPE::NOTE);
|
|
if (note_segment == nullptr) {
|
|
LIEF_ERR("PT_NOTE segment not found");
|
|
return make_error_code(lief_errors::file_format_error);
|
|
}
|
|
note_segment->virtual_address(va_r_base);
|
|
note_segment->virtual_size(raw_notes_.size());
|
|
note_segment->physical_address(va_r_base);
|
|
note_segment->physical_size(raw_notes_.size());
|
|
|
|
uint64_t offset_r_base = 0;
|
|
if (auto res = binary_->virtual_address_to_offset(va_r_base)) {
|
|
offset_r_base = *res;
|
|
} else {
|
|
return make_error_code(lief_errors::build_error);
|
|
}
|
|
|
|
note_segment->file_offset(offset_r_base);
|
|
va_r_base += raw_notes_.size();
|
|
}
|
|
|
|
if (dynamic_size_ > 0) {
|
|
// Update .dynamic / PT_DYNAMIC
|
|
// Update relocations associated with .init_array etc.
|
|
Segment* dynamic_segment = binary_->get(Segment::TYPE::DYNAMIC);
|
|
if (dynamic_segment == nullptr) {
|
|
LIEF_ERR("Dynamic section/segment not found");
|
|
return make_error_code(lief_errors::file_format_error);
|
|
}
|
|
|
|
uint64_t offset_rw_base = 0;
|
|
if (auto res = binary_->virtual_address_to_offset(va_rw_base)) {
|
|
offset_rw_base = *res;
|
|
} else {
|
|
return make_error_code(lief_errors::build_error);
|
|
}
|
|
|
|
dynamic_segment->virtual_address(va_rw_base);
|
|
dynamic_segment->virtual_size(dynamic_size_);
|
|
dynamic_segment->physical_address(va_rw_base);
|
|
dynamic_segment->file_offset(offset_rw_base);
|
|
dynamic_segment->physical_size(dynamic_size_);
|
|
|
|
if (Section* section = binary_->dynamic_section()) {
|
|
section->virtual_address(va_rw_base);
|
|
section->size(dynamic_size_);
|
|
section->offset(offset_rw_base);
|
|
section->original_size_ = dynamic_size_;
|
|
}
|
|
|
|
va_rw_base += dynamic_size_;
|
|
}
|
|
|
|
if (dynsym_size_ > 0) {
|
|
// Update .dynsym / DT_SYMTAB
|
|
DynamicEntry* dt_symtab = binary_->get(DynamicEntry::TAG::SYMTAB);
|
|
|
|
if (dt_symtab == nullptr) {
|
|
LIEF_ERR("DT_SYMTAB not found");
|
|
return make_error_code(lief_errors::file_format_error);
|
|
}
|
|
|
|
uint64_t offset_r_base = 0;
|
|
if (auto res = binary_->virtual_address_to_offset(va_r_base)) {
|
|
offset_r_base = *res;
|
|
} else {
|
|
return make_error_code(lief_errors::build_error);
|
|
}
|
|
|
|
if (Section* section =
|
|
binary_->section_from_virtual_address(dt_symtab->value()))
|
|
{
|
|
section->virtual_address(va_r_base);
|
|
section->size(dynsym_size_);
|
|
section->offset(offset_r_base);
|
|
section->original_size_ = dynsym_size_;
|
|
}
|
|
|
|
dt_symtab->value(va_r_base);
|
|
|
|
va_r_base += dynsym_size_;
|
|
}
|
|
|
|
if (relocate_dynstr_) {
|
|
// Update .dynstr section, DT_SYMTAB, DT_STRSZ
|
|
DynamicEntry* dt_strtab = binary_->get(DynamicEntry::TAG::STRTAB);
|
|
DynamicEntry* dt_strsize = binary_->get(DynamicEntry::TAG::STRSZ);
|
|
|
|
if (dt_strtab == nullptr || dt_strsize == nullptr) {
|
|
LIEF_ERR("DT_STRTAB/DT_STRSZ not found");
|
|
return make_error_code(lief_errors::file_format_error);
|
|
}
|
|
|
|
uint64_t offset_r_base = 0;
|
|
if (auto res = binary_->virtual_address_to_offset(va_r_base)) {
|
|
offset_r_base = *res;
|
|
} else {
|
|
return make_error_code(lief_errors::build_error);
|
|
}
|
|
|
|
if (Section* section =
|
|
binary_->section_from_virtual_address(dt_strtab->value()))
|
|
{
|
|
section->virtual_address(va_r_base);
|
|
section->size(raw_dynstr_.size());
|
|
section->offset(offset_r_base);
|
|
section->original_size_ = raw_dynstr_.size();
|
|
}
|
|
|
|
dt_strtab->value(va_r_base);
|
|
dt_strsize->value(raw_dynstr_.size());
|
|
|
|
va_r_base += raw_dynstr_.size();
|
|
}
|
|
|
|
|
|
if (sver_size_ > 0) {
|
|
DynamicEntry* dt_versym = binary_->get(DynamicEntry::TAG::VERSYM);
|
|
if (dt_versym == nullptr) {
|
|
LIEF_ERR("DT_VERSYM not found");
|
|
return make_error_code(lief_errors::file_format_error);
|
|
}
|
|
|
|
uint64_t offset_r_base = 0;
|
|
if (auto res = binary_->virtual_address_to_offset(va_r_base)) {
|
|
offset_r_base = *res;
|
|
} else {
|
|
return make_error_code(lief_errors::build_error);
|
|
}
|
|
|
|
if (Section* section =
|
|
binary_->section_from_virtual_address(dt_versym->value()))
|
|
{
|
|
section->virtual_address(va_r_base);
|
|
section->size(sver_size_);
|
|
section->offset(offset_r_base);
|
|
section->original_size_ = sver_size_;
|
|
}
|
|
|
|
dt_versym->value(va_r_base);
|
|
|
|
va_r_base += sver_size_;
|
|
}
|
|
|
|
if (sverd_size_ > 0) {
|
|
DynamicEntry* dt_verdef = binary_->get(DynamicEntry::TAG::VERDEF);
|
|
|
|
if (dt_verdef == nullptr) {
|
|
LIEF_ERR("DT_VERDEF not found");
|
|
return make_error_code(lief_errors::file_format_error);
|
|
}
|
|
|
|
uint64_t offset_r_base = 0;
|
|
if (auto res = binary_->virtual_address_to_offset(va_r_base)) {
|
|
offset_r_base = *res;
|
|
} else {
|
|
return make_error_code(lief_errors::build_error);
|
|
}
|
|
|
|
if (Section* section =
|
|
binary_->section_from_virtual_address(dt_verdef->value()))
|
|
{
|
|
section->virtual_address(va_r_base);
|
|
section->size(sverd_size_);
|
|
section->offset(offset_r_base);
|
|
section->original_size_ = sverd_size_;
|
|
}
|
|
|
|
dt_verdef->value(va_r_base);
|
|
|
|
va_r_base += sverd_size_;
|
|
}
|
|
|
|
if (sverr_size_ > 0) {
|
|
DynamicEntry* dt_verreq = binary_->get(DynamicEntry::TAG::VERNEED);
|
|
|
|
if (dt_verreq == nullptr) {
|
|
LIEF_ERR("DT_VERNEED not found");
|
|
return make_error_code(lief_errors::file_format_error);
|
|
}
|
|
|
|
uint64_t offset_r_base = 0;
|
|
if (auto res = binary_->virtual_address_to_offset(va_r_base)) {
|
|
offset_r_base = *res;
|
|
} else {
|
|
return make_error_code(lief_errors::build_error);
|
|
}
|
|
|
|
if (Section* section =
|
|
binary_->section_from_virtual_address(dt_verreq->value()))
|
|
{
|
|
section->virtual_address(va_r_base);
|
|
section->size(sverr_size_);
|
|
section->offset(offset_r_base);
|
|
section->original_size_ = sverr_size_;
|
|
}
|
|
|
|
dt_verreq->value(va_r_base);
|
|
|
|
va_r_base += sverr_size_;
|
|
}
|
|
|
|
if (dynamic_reloc_size_ > 0) {
|
|
// Update:
|
|
// - DT_REL / DT_RELA
|
|
// - DT_RELSZ / DT_RELASZ
|
|
// - .dyn.rel
|
|
|
|
DynamicEntry* dt_rela = binary_->get(DynamicEntry::TAG::RELA);
|
|
|
|
const bool is_rela = dt_rela != nullptr;
|
|
DynamicEntry* dt_reloc =
|
|
is_rela ? dt_rela : binary_->get(DynamicEntry::TAG::REL);
|
|
DynamicEntry* dt_relocsz = is_rela ?
|
|
binary_->get(DynamicEntry::TAG::RELASZ) :
|
|
binary_->get(DynamicEntry::TAG::RELSZ);
|
|
|
|
if (dt_reloc == nullptr || dt_relocsz == nullptr) {
|
|
LIEF_ERR("DT_REL(A)/DT_REL(A)SZ not found");
|
|
return make_error_code(lief_errors::file_format_error);
|
|
}
|
|
|
|
|
|
uint64_t offset_r_base = 0;
|
|
if (auto res = binary_->virtual_address_to_offset(va_r_base)) {
|
|
offset_r_base = *res;
|
|
} else {
|
|
return make_error_code(lief_errors::build_error);
|
|
}
|
|
|
|
if (Section* section =
|
|
binary_->section_from_virtual_address(dt_reloc->value()))
|
|
{
|
|
section->virtual_address(va_r_base);
|
|
section->size(dynamic_reloc_size_);
|
|
section->offset(offset_r_base);
|
|
section->original_size_ = dynamic_reloc_size_;
|
|
}
|
|
|
|
dt_reloc->value(va_r_base);
|
|
dt_relocsz->value(dynamic_reloc_size_);
|
|
|
|
va_r_base += dynamic_reloc_size_;
|
|
}
|
|
|
|
if (pltgot_reloc_size_ > 0) {
|
|
// Update:
|
|
// - DT_JMPREL / DT_PLTRELSZ
|
|
// - .plt.rel
|
|
DynamicEntry* dt_reloc = binary_->get(DynamicEntry::TAG::JMPREL);
|
|
DynamicEntry* dt_relocsz = binary_->get(DynamicEntry::TAG::PLTRELSZ);
|
|
|
|
if (dt_reloc == nullptr || dt_relocsz == nullptr) {
|
|
LIEF_ERR("DT_JMPREL/DT_PLTRELSZ not found");
|
|
return make_error_code(lief_errors::file_format_error);
|
|
}
|
|
|
|
uint64_t offset_r_base = 0;
|
|
if (auto res = binary_->virtual_address_to_offset(va_r_base)) {
|
|
offset_r_base = *res;
|
|
} else {
|
|
return make_error_code(lief_errors::build_error);
|
|
}
|
|
|
|
if (Section* section =
|
|
binary_->section_from_virtual_address(dt_reloc->value()))
|
|
{
|
|
section->virtual_address(va_r_base);
|
|
section->size(pltgot_reloc_size_);
|
|
section->offset(offset_r_base);
|
|
section->original_size_ = pltgot_reloc_size_;
|
|
}
|
|
|
|
|
|
dt_reloc->value(va_r_base);
|
|
dt_relocsz->value(pltgot_reloc_size_);
|
|
|
|
va_r_base += pltgot_reloc_size_;
|
|
}
|
|
|
|
if (relocate_relr_) {
|
|
DynamicEntry* dt_relr = binary_->get(DynamicEntry::TAG::RELR);
|
|
if (dt_relr == nullptr) {
|
|
dt_relr = binary_->get(DynamicEntry::TAG::ANDROID_RELR);
|
|
}
|
|
if (dt_relr == nullptr) {
|
|
LIEF_ERR("DT_RELR/DT_ANDROID_RELR not found");
|
|
return make_error_code(lief_errors::file_format_error);
|
|
}
|
|
|
|
uint64_t offset_r_base = 0;
|
|
if (auto res = binary_->virtual_address_to_offset(va_r_base)) {
|
|
offset_r_base = *res;
|
|
} else {
|
|
return make_error_code(lief_errors::build_error);
|
|
}
|
|
|
|
if (Section* section =
|
|
binary_->section_from_virtual_address(dt_relr->value()))
|
|
{
|
|
section->virtual_address(va_r_base);
|
|
section->size(raw_relr_.size());
|
|
section->offset(offset_r_base);
|
|
section->original_size_ = raw_relr_.size();
|
|
}
|
|
|
|
dt_relr->value(va_r_base);
|
|
va_r_base += raw_relr_.size();
|
|
}
|
|
|
|
if (relocate_android_rela_) {
|
|
DynamicEntry* dt_rel = binary_->get(DynamicEntry::TAG::ANDROID_RELA);
|
|
if (dt_rel == nullptr) {
|
|
dt_rel = binary_->get(DynamicEntry::TAG::ANDROID_REL);
|
|
}
|
|
|
|
if (dt_rel == nullptr) {
|
|
LIEF_ERR("DT_ANDROID_REL[A] not found");
|
|
return make_error_code(lief_errors::file_format_error);
|
|
}
|
|
|
|
uint64_t offset_r_base = 0;
|
|
if (auto res = binary_->virtual_address_to_offset(va_r_base)) {
|
|
offset_r_base = *res;
|
|
} else {
|
|
return make_error_code(lief_errors::build_error);
|
|
}
|
|
|
|
if (Section* section =
|
|
binary_->section_from_virtual_address(dt_rel->value()))
|
|
{
|
|
section->virtual_address(va_r_base);
|
|
section->size(raw_android_rela_.size());
|
|
section->offset(offset_r_base);
|
|
section->original_size_ = raw_android_rela_.size();
|
|
}
|
|
|
|
dt_rel->value(va_r_base);
|
|
va_r_base += raw_android_rela_.size();
|
|
}
|
|
|
|
if (relocate_gnu_hash_) {
|
|
// Update .gnu.hash section / DT_GNU_HASH
|
|
DynamicEntry* dt_gnu_hash = binary_->get(DynamicEntry::TAG::GNU_HASH);
|
|
|
|
if (dt_gnu_hash == nullptr) {
|
|
LIEF_ERR("DT_GNU_HASH not found");
|
|
return make_error_code(lief_errors::file_format_error);
|
|
}
|
|
|
|
|
|
uint64_t offset_r_base = 0;
|
|
if (auto res = binary_->virtual_address_to_offset(va_r_base)) {
|
|
offset_r_base = *res;
|
|
} else {
|
|
return make_error_code(lief_errors::build_error);
|
|
}
|
|
|
|
if (Section* section =
|
|
binary_->section_from_virtual_address(dt_gnu_hash->value()))
|
|
{
|
|
section->virtual_address(va_r_base);
|
|
section->size(raw_gnu_hash_.size());
|
|
section->offset(offset_r_base);
|
|
section->original_size_ = raw_gnu_hash_.size();
|
|
}
|
|
|
|
dt_gnu_hash->value(va_r_base);
|
|
va_r_base += raw_gnu_hash_.size();
|
|
}
|
|
|
|
if (sysv_size_ > 0) {
|
|
// Update .hash section / DT_HASH
|
|
DynamicEntry* dt_hash = binary_->get(DynamicEntry::TAG::HASH);
|
|
|
|
if (dt_hash == nullptr) {
|
|
LIEF_ERR("DT_HASH not found");
|
|
return make_error_code(lief_errors::file_format_error);
|
|
}
|
|
|
|
|
|
uint64_t offset_r_base = 0;
|
|
if (auto res = binary_->virtual_address_to_offset(va_r_base)) {
|
|
offset_r_base = *res;
|
|
} else {
|
|
return make_error_code(lief_errors::build_error);
|
|
}
|
|
|
|
if (Section* section =
|
|
binary_->section_from_virtual_address(dt_hash->value()))
|
|
{
|
|
section->virtual_address(va_r_base);
|
|
section->size(sysv_size_);
|
|
section->offset(offset_r_base);
|
|
section->original_size_ = sysv_size_;
|
|
}
|
|
|
|
dt_hash->value(va_r_base);
|
|
va_r_base += sysv_size_;
|
|
}
|
|
|
|
|
|
// RW-Segment
|
|
// ====================================
|
|
if (init_size_ > 0) { // .init_array
|
|
DynamicEntry* raw_dt_init = binary_->get(DynamicEntry::TAG::INIT_ARRAY);
|
|
if (raw_dt_init == nullptr || !DynamicEntryArray::classof(raw_dt_init)) {
|
|
LIEF_ERR("DT_INIT_ARRAY not found");
|
|
return make_error_code(lief_errors::file_format_error);
|
|
}
|
|
auto* dt_init_array = raw_dt_init->as<DynamicEntryArray>();
|
|
DynamicEntry* dt_init_arraysz =
|
|
binary_->get(DynamicEntry::TAG::INIT_ARRAYSZ);
|
|
|
|
if (dt_init_arraysz == nullptr) {
|
|
LIEF_ERR("DT_INIT_ARRAYSZ not found");
|
|
return make_error_code(lief_errors::file_format_error);
|
|
}
|
|
|
|
|
|
// Update relocation range
|
|
if (binary_->header().file_type() == Header::FILE_TYPE::DYN) {
|
|
LIEF_WARN("Relocating .init_array may not work on Linux");
|
|
const std::vector<uint64_t>& array = dt_init_array->array();
|
|
const size_t sizeof_p = binary_->type() == Header::CLASS::ELF32 ?
|
|
sizeof(uint32_t) :
|
|
sizeof(uint64_t);
|
|
|
|
// Since the values of the .init_array have moved elsewhere,
|
|
// we need to change the relocation associated with the former .init_array
|
|
const uint64_t array_base_address = dt_init_array->value();
|
|
for (size_t i = 0; i < array.size(); ++i) {
|
|
auto it_reloc =
|
|
relocations_addresses_.find(array_base_address + i * sizeof_p);
|
|
if (it_reloc == relocations_addresses_.end()) {
|
|
LIEF_ERR("Missing relocation for .init_array[{:d}]: {:#x}", i,
|
|
array[i]);
|
|
continue;
|
|
}
|
|
Relocation* reloc = it_reloc->second;
|
|
reloc->address(va_rw_base + i * sizeof_p);
|
|
}
|
|
}
|
|
|
|
uint64_t offset_rw_base = 0;
|
|
if (auto res = binary_->virtual_address_to_offset(va_rw_base)) {
|
|
offset_rw_base = *res;
|
|
} else {
|
|
return make_error_code(lief_errors::build_error);
|
|
}
|
|
|
|
if (Section* section = binary_->get(Section::TYPE::INIT_ARRAY)) {
|
|
section->virtual_address(va_rw_base);
|
|
section->size(init_size_);
|
|
section->offset(offset_rw_base);
|
|
section->original_size_ = init_size_;
|
|
}
|
|
|
|
dt_init_array->value(va_rw_base);
|
|
dt_init_arraysz->value(init_size_);
|
|
|
|
va_rw_base += init_size_;
|
|
}
|
|
|
|
if (preinit_size_ > 0) { // .preinit_array
|
|
DynamicEntry* raw_dt_preinit =
|
|
binary_->get(DynamicEntry::TAG::PREINIT_ARRAY);
|
|
if (raw_dt_preinit == nullptr || !DynamicEntryArray::classof(raw_dt_preinit))
|
|
{
|
|
LIEF_ERR("DT_PREINIT_ARRAY not found");
|
|
return make_error_code(lief_errors::file_format_error);
|
|
}
|
|
auto* dt_preinit_array = raw_dt_preinit->as<DynamicEntryArray>();
|
|
DynamicEntry* dt_preinit_arraysz =
|
|
binary_->get(DynamicEntry::TAG::PREINIT_ARRAYSZ);
|
|
|
|
if (dt_preinit_array == nullptr) {
|
|
LIEF_ERR("DT_PREINIT_ARRAYSZ not found");
|
|
return make_error_code(lief_errors::file_format_error);
|
|
}
|
|
|
|
if (binary_->header().file_type() == Header::FILE_TYPE::DYN) {
|
|
const std::vector<uint64_t>& array = dt_preinit_array->array();
|
|
const size_t sizeof_p = binary_->type() == Header::CLASS::ELF32 ?
|
|
sizeof(uint32_t) :
|
|
sizeof(uint64_t);
|
|
LIEF_WARN("Relocating .preinit_array may not work on Linux");
|
|
|
|
const uint64_t array_base_address = dt_preinit_array->value();
|
|
for (size_t i = 0; i < array.size(); ++i) {
|
|
auto it_reloc =
|
|
relocations_addresses_.find(array_base_address + i * sizeof_p);
|
|
if (it_reloc == relocations_addresses_.end()) {
|
|
LIEF_ERR("Missing relocation for .preinit_array[{:d}]: {:#x}", i,
|
|
array[i]);
|
|
continue;
|
|
}
|
|
Relocation* reloc = it_reloc->second;
|
|
reloc->address(va_rw_base + i * sizeof_p);
|
|
}
|
|
}
|
|
|
|
uint64_t offset_rw_base = 0;
|
|
if (auto res = binary_->virtual_address_to_offset(va_rw_base)) {
|
|
offset_rw_base = *res;
|
|
} else {
|
|
return make_error_code(lief_errors::build_error);
|
|
}
|
|
|
|
if (Section* section = binary_->get(Section::TYPE::PREINIT_ARRAY)) {
|
|
section->virtual_address(va_rw_base);
|
|
section->size(preinit_size_);
|
|
section->offset(offset_rw_base);
|
|
section->original_size_ = preinit_size_;
|
|
}
|
|
|
|
dt_preinit_array->value(va_rw_base);
|
|
dt_preinit_arraysz->value(preinit_size_);
|
|
|
|
va_rw_base += preinit_size_;
|
|
}
|
|
|
|
|
|
if (fini_size_ > 0) { // .fini_array
|
|
DynamicEntry* raw_dt_fini = binary_->get(DynamicEntry::TAG::FINI_ARRAY);
|
|
if (raw_dt_fini == nullptr || !DynamicEntryArray::classof(raw_dt_fini)) {
|
|
LIEF_ERR("DT_FINI_ARRAY not found");
|
|
return make_error_code(lief_errors::file_format_error);
|
|
}
|
|
auto* dt_fini_array = raw_dt_fini->as<DynamicEntryArray>();
|
|
DynamicEntry* dt_fini_arraysz =
|
|
binary_->get(DynamicEntry::TAG::FINI_ARRAYSZ);
|
|
|
|
if (dt_fini_arraysz == nullptr) {
|
|
LIEF_ERR("DT_FINI_ARRAYSZ not found");
|
|
return make_error_code(lief_errors::file_format_error);
|
|
}
|
|
|
|
if (binary_->header().file_type() == Header::FILE_TYPE::DYN) {
|
|
const std::vector<uint64_t>& array = dt_fini_array->array();
|
|
const size_t sizeof_p = binary_->type() == Header::CLASS::ELF32 ?
|
|
sizeof(uint32_t) :
|
|
sizeof(uint64_t);
|
|
|
|
LIEF_WARN("Relocating .fini_array may not work on Linux");
|
|
|
|
const uint64_t array_base_address = dt_fini_array->value();
|
|
for (size_t i = 0; i < array.size(); ++i) {
|
|
auto it_reloc =
|
|
relocations_addresses_.find(array_base_address + i * sizeof_p);
|
|
if (it_reloc == relocations_addresses_.end()) {
|
|
LIEF_ERR("Missing relocation for .fini_array[{:d}]: {:#x}", i,
|
|
array[i]);
|
|
continue;
|
|
}
|
|
Relocation* reloc = it_reloc->second;
|
|
reloc->address(va_rw_base + i * sizeof_p);
|
|
}
|
|
}
|
|
|
|
uint64_t offset_rw_base = 0;
|
|
if (auto res = binary_->virtual_address_to_offset(va_rw_base)) {
|
|
offset_rw_base = *res;
|
|
} else {
|
|
return make_error_code(lief_errors::build_error);
|
|
}
|
|
|
|
if (Section* section = binary_->get(Section::TYPE::FINI_ARRAY)) {
|
|
section->virtual_address(va_rw_base);
|
|
section->size(fini_size_);
|
|
section->offset(offset_rw_base);
|
|
section->original_size_ = fini_size_;
|
|
}
|
|
|
|
dt_fini_array->value(va_rw_base);
|
|
dt_fini_arraysz->value(fini_size_);
|
|
va_rw_base += fini_size_;
|
|
}
|
|
|
|
// Check if we need to relocate the .strtab that contains
|
|
// symbol's names associated with debug symbol (not mandatory)
|
|
size_t strtab_idx = 0;
|
|
if (relocate_strtab_) {
|
|
LIEF_DEBUG("Relocating .strtab");
|
|
if (is_strtab_shared_shstrtab()) {
|
|
LIEF_ERR(
|
|
"Strtab inconsistency"
|
|
); // The strtab should be located in the .shstrtab section
|
|
return make_error_code(lief_errors::file_format_error);
|
|
}
|
|
if (strtab_section_ != nullptr) {
|
|
LIEF_DEBUG("Removing the old section: {} {:#x} (size: {:#x})",
|
|
strtab_section_->name(), strtab_section_->file_offset(),
|
|
strtab_section_->size());
|
|
binary_->remove(*strtab_section_, /* clear */ true);
|
|
}
|
|
Section strtab{".strtab", Section::TYPE::STRTAB};
|
|
strtab.content(raw_strtab_);
|
|
strtab.alignment(1);
|
|
Section* new_strtab =
|
|
binary_->add(strtab, /*loaded=*/false,
|
|
/*pos=*/Binary::SEC_INSERT_POS::POST_SECTION);
|
|
|
|
strtab_idx = binary_->sections().size() - 1;
|
|
|
|
if (new_strtab == nullptr) {
|
|
LIEF_ERR("Failed to add .strtab section");
|
|
return make_error_code(lief_errors::build_error);
|
|
}
|
|
|
|
LIEF_DEBUG("New .strtab section: #{:d} {} {:#x} (size: {:x})", strtab_idx,
|
|
new_strtab->name(), new_strtab->file_offset(),
|
|
new_strtab->size());
|
|
|
|
Section* sec_symtab = binary_->get(Section::TYPE::SYMTAB);
|
|
if (sec_symtab != nullptr) {
|
|
LIEF_DEBUG("Linking section {} with new .strtab (idx: #{:d})",
|
|
sec_symtab->name(), strtab_idx);
|
|
sec_symtab->link(strtab_idx);
|
|
}
|
|
set_strtab_section(*new_strtab);
|
|
}
|
|
|
|
if (strtab_section_ != nullptr) {
|
|
strtab_section_->content(raw_strtab_);
|
|
}
|
|
LIEF_DEBUG("strtab_idx: {:d}", strtab_idx);
|
|
// Sections that are not associated with segments (mostly debug information)
|
|
// currently we only handle the symtab symbol table: .symtab
|
|
if (symtab_size_ > 0) {
|
|
LIEF_DEBUG("Relocating .symtab");
|
|
|
|
const auto sections = binary_->sections();
|
|
auto it_sec_symtab =
|
|
std::find_if(sections.begin(), sections.end(), [](const Section& sec) {
|
|
return sec.type() == Section::TYPE::SYMTAB;
|
|
});
|
|
|
|
if (it_sec_symtab != sections.end()) {
|
|
const size_t pos = std::distance(sections.begin(), it_sec_symtab);
|
|
|
|
if (strtab_idx == 0) {
|
|
strtab_idx = it_sec_symtab->link();
|
|
}
|
|
|
|
LIEF_DEBUG("Removing the old section: {} {:#x} (size: {:#x})",
|
|
it_sec_symtab->name(), it_sec_symtab->file_offset(),
|
|
it_sec_symtab->size());
|
|
binary_->remove(*it_sec_symtab, /* clear */ true);
|
|
if (pos < strtab_idx) {
|
|
--strtab_idx;
|
|
}
|
|
}
|
|
|
|
Section symtab{".symtab", Section::TYPE::SYMTAB};
|
|
symtab.content(std::vector<uint8_t>(symtab_size_));
|
|
|
|
const size_t sizeof_sym = binary_->type() == Header::CLASS::ELF32 ?
|
|
sizeof(details::Elf32_Sym) :
|
|
sizeof(details::Elf64_Sym);
|
|
symtab.entry_size(sizeof_sym);
|
|
symtab.alignment(8);
|
|
symtab.link(strtab_idx);
|
|
Section* new_symtab =
|
|
binary_->add(symtab, /*loaded=*/false,
|
|
/*pos=*/Binary::SEC_INSERT_POS::POST_SECTION);
|
|
if (new_symtab == nullptr) {
|
|
LIEF_ERR("Failed to add .symtab section");
|
|
return make_error_code(lief_errors::build_error);
|
|
}
|
|
LIEF_DEBUG("New .symtab section: {} {:#x} (size: {:x})", new_symtab->name(),
|
|
new_symtab->file_offset(), new_symtab->size());
|
|
}
|
|
|
|
// Process note sections
|
|
if (const Segment* segment_note = binary_->get(Segment::TYPE::NOTE)) {
|
|
for (const Note& note : binary_->notes()) {
|
|
auto section_res = Note::note_to_section(note);
|
|
const auto& it_offset = notes_off_map_.find(¬e);
|
|
|
|
if (!section_res) {
|
|
if (binary_->header().file_type() != Header::FILE_TYPE::CORE) {
|
|
LIEF_ERR("Unsupported note type {} ('{}') for section",
|
|
to_string(note.type()), note.name());
|
|
}
|
|
continue;
|
|
}
|
|
|
|
std::string sec_name = *section_res;
|
|
|
|
// If the binary has the note type but does not have
|
|
// the section (likely because the user added the note manually)
|
|
// then, create the section
|
|
if (const Section* nsec = binary_->get_section(*section_res);
|
|
nsec == nullptr)
|
|
{
|
|
if (it_offset == notes_off_map_.end()) {
|
|
LIEF_ERR("Raw data not found for note '{}'", to_string(note.type()));
|
|
continue;
|
|
}
|
|
const size_t note_offset = it_offset->second;
|
|
|
|
Section section{sec_name, Section::TYPE::NOTE};
|
|
section += Section::FLAGS::ALLOC;
|
|
|
|
Section* section_added =
|
|
binary_->add(section, /*loaded=*/false,
|
|
/*pos=*/Binary::SEC_INSERT_POS::POST_SECTION);
|
|
if (section_added == nullptr) {
|
|
LIEF_ERR("Failed to add SHT_NOTE section");
|
|
return make_error_code(lief_errors::build_error);
|
|
}
|
|
section_added->offset(segment_note->file_offset() + note_offset);
|
|
section_added->size(note.size());
|
|
section.virtual_address(segment_note->virtual_address() + note_offset);
|
|
section_added->alignment(4);
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
const std::unordered_map<std::string_view, size_t>& dynstr_map() const {
|
|
return offset_name_map_;
|
|
}
|
|
|
|
const std::unordered_map<const Note*, size_t>& note_off_map() const {
|
|
return notes_off_map_;
|
|
}
|
|
|
|
uint32_t sysv_nchain() const {
|
|
return nchain_;
|
|
}
|
|
|
|
~ExeLayout() override = default;
|
|
ExeLayout() = delete;
|
|
|
|
private:
|
|
std::unordered_map<std::string_view, size_t> offset_name_map_;
|
|
std::unordered_map<const Note*, size_t> notes_off_map_;
|
|
|
|
sym_verdef_info_t verdef_info_;
|
|
|
|
std::vector<uint8_t> raw_notes_;
|
|
bool relocate_notes_ = false;
|
|
|
|
std::vector<uint8_t> raw_dynstr_;
|
|
bool relocate_dynstr_ = false;
|
|
|
|
bool relocate_shstrtab_ = false;
|
|
|
|
bool relocate_strtab_ = false;
|
|
|
|
std::vector<uint8_t> raw_gnu_hash_;
|
|
bool relocate_gnu_hash_ = false;
|
|
|
|
std::vector<uint8_t> raw_relr_;
|
|
bool relocate_relr_ = false;
|
|
|
|
std::vector<uint8_t> raw_android_rela_;
|
|
bool relocate_android_rela_ = false;
|
|
|
|
uint64_t sysv_size_ = 0;
|
|
|
|
uint64_t dynamic_size_ = 0;
|
|
uint64_t dynsym_size_ = 0;
|
|
|
|
uint64_t pltgot_reloc_size_ = 0;
|
|
uint64_t dynamic_reloc_size_ = 0;
|
|
|
|
uint64_t sver_size_ = 0;
|
|
uint64_t sverd_size_ = 0;
|
|
uint64_t sverr_size_ = 0;
|
|
|
|
uint64_t preinit_size_ = 0;
|
|
uint64_t init_size_ = 0;
|
|
uint64_t fini_size_ = 0;
|
|
|
|
uint64_t interp_size_ = 0;
|
|
uint32_t nchain_ = 0;
|
|
uint64_t symtab_size_ = 0;
|
|
|
|
// uint64_t pltgot_reloc_size_ = 0;
|
|
std::unordered_map<uint64_t, Relocation*> relocations_addresses_;
|
|
};
|
|
}
|
|
|
|
|
|
#endif
|