Path: blob/main/contrib/llvm-project/lld/ELF/Relocations.h
34878 views
//===- Relocations.h -------------------------------------------*- C++ -*-===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#ifndef LLD_ELF_RELOCATIONS_H9#define LLD_ELF_RELOCATIONS_H1011#include "lld/Common/LLVM.h"12#include "llvm/ADT/DenseMap.h"13#include "llvm/ADT/STLExtras.h"14#include "llvm/Object/ELFTypes.h"15#include <vector>1617namespace lld::elf {18class Symbol;19class InputSection;20class InputSectionBase;21class OutputSection;22class SectionBase;2324// Represents a relocation type, such as R_X86_64_PC32 or R_ARM_THM_CALL.25using RelType = uint32_t;26using JumpModType = uint32_t;2728// List of target-independent relocation types. Relocations read29// from files are converted to these types so that the main code30// doesn't have to know about architecture-specific details.31enum RelExpr {32R_ABS,33R_ADDEND,34R_DTPREL,35R_GOT,36R_GOT_OFF,37R_GOT_PC,38R_GOTONLY_PC,39R_GOTPLTONLY_PC,40R_GOTPLT,41R_GOTPLTREL,42R_GOTREL,43R_GOTPLT_GOTREL,44R_GOTPLT_PC,45R_NONE,46R_PC,47R_PLT,48R_PLT_PC,49R_PLT_GOTPLT,50R_PLT_GOTREL,51R_RELAX_HINT,52R_RELAX_GOT_PC,53R_RELAX_GOT_PC_NOPIC,54R_RELAX_TLS_GD_TO_IE,55R_RELAX_TLS_GD_TO_IE_ABS,56R_RELAX_TLS_GD_TO_IE_GOT_OFF,57R_RELAX_TLS_GD_TO_IE_GOTPLT,58R_RELAX_TLS_GD_TO_LE,59R_RELAX_TLS_GD_TO_LE_NEG,60R_RELAX_TLS_IE_TO_LE,61R_RELAX_TLS_LD_TO_LE,62R_RELAX_TLS_LD_TO_LE_ABS,63R_SIZE,64R_TPREL,65R_TPREL_NEG,66R_TLSDESC,67R_TLSDESC_CALL,68R_TLSDESC_PC,69R_TLSDESC_GOTPLT,70R_TLSGD_GOT,71R_TLSGD_GOTPLT,72R_TLSGD_PC,73R_TLSIE_HINT,74R_TLSLD_GOT,75R_TLSLD_GOTPLT,76R_TLSLD_GOT_OFF,77R_TLSLD_HINT,78R_TLSLD_PC,7980// The following is abstract relocation types used for only one target.81//82// Even though RelExpr is intended to be a target-neutral representation83// of a relocation type, there are some relocations whose semantics are84// unique to a target. Such relocation are marked with R_<TARGET_NAME>.85R_AARCH64_GOT_PAGE_PC,86R_AARCH64_GOT_PAGE,87R_AARCH64_PAGE_PC,88R_AARCH64_RELAX_TLS_GD_TO_IE_PAGE_PC,89R_AARCH64_TLSDESC_PAGE,90R_AARCH64_AUTH,91R_ARM_PCA,92R_ARM_SBREL,93R_MIPS_GOTREL,94R_MIPS_GOT_GP,95R_MIPS_GOT_GP_PC,96R_MIPS_GOT_LOCAL_PAGE,97R_MIPS_GOT_OFF,98R_MIPS_GOT_OFF32,99R_MIPS_TLSGD,100R_MIPS_TLSLD,101R_PPC32_PLTREL,102R_PPC64_CALL,103R_PPC64_CALL_PLT,104R_PPC64_RELAX_TOC,105R_PPC64_TOCBASE,106R_PPC64_RELAX_GOT_PC,107R_RISCV_ADD,108R_RISCV_LEB128,109R_RISCV_PC_INDIRECT,110// Same as R_PC but with page-aligned semantics.111R_LOONGARCH_PAGE_PC,112// Same as R_PLT_PC but with page-aligned semantics.113R_LOONGARCH_PLT_PAGE_PC,114// In addition to having page-aligned semantics, LoongArch GOT relocs are115// also reused for TLS, making the semantics differ from other architectures.116R_LOONGARCH_GOT,117R_LOONGARCH_GOT_PAGE_PC,118R_LOONGARCH_TLSGD_PAGE_PC,119R_LOONGARCH_TLSDESC_PAGE_PC,120};121122// Architecture-neutral representation of relocation.123struct Relocation {124RelExpr expr;125RelType type;126uint64_t offset;127int64_t addend;128Symbol *sym;129};130131// Manipulate jump instructions with these modifiers. These are used to relax132// jump instruction opcodes at basic block boundaries and are particularly133// useful when basic block sections are enabled.134struct JumpInstrMod {135uint64_t offset;136JumpModType original;137unsigned size;138};139140// This function writes undefined symbol diagnostics to an internal buffer.141// Call reportUndefinedSymbols() after calling scanRelocations() to emit142// the diagnostics.143template <class ELFT> void scanRelocations();144template <class ELFT> void checkNoCrossRefs();145void reportUndefinedSymbols();146void postScanRelocations();147void addGotEntry(Symbol &sym);148149void hexagonTLSSymbolUpdate(ArrayRef<OutputSection *> outputSections);150bool hexagonNeedsTLSSymbol(ArrayRef<OutputSection *> outputSections);151152class ThunkSection;153class Thunk;154class InputSectionDescription;155156class ThunkCreator {157public:158// Return true if Thunks have been added to OutputSections159bool createThunks(uint32_t pass, ArrayRef<OutputSection *> outputSections);160161private:162void mergeThunks(ArrayRef<OutputSection *> outputSections);163164ThunkSection *getISDThunkSec(OutputSection *os, InputSection *isec,165InputSectionDescription *isd,166const Relocation &rel, uint64_t src);167168ThunkSection *getISThunkSec(InputSection *isec);169170void createInitialThunkSections(ArrayRef<OutputSection *> outputSections);171172std::pair<Thunk *, bool> getThunk(InputSection *isec, Relocation &rel,173uint64_t src);174175ThunkSection *addThunkSection(OutputSection *os, InputSectionDescription *,176uint64_t off);177178bool normalizeExistingThunk(Relocation &rel, uint64_t src);179180// Record all the available Thunks for a (Symbol, addend) pair, where Symbol181// is represented as a (section, offset) pair. There may be multiple182// relocations sharing the same (section, offset + addend) pair. We may revert183// a relocation back to its original non-Thunk target, and restore the184// original addend, so we cannot fold offset + addend. A nested pair is used185// because DenseMapInfo is not specialized for std::tuple.186llvm::DenseMap<std::pair<std::pair<SectionBase *, uint64_t>, int64_t>,187std::vector<Thunk *>>188thunkedSymbolsBySectionAndAddend;189llvm::DenseMap<std::pair<Symbol *, int64_t>, std::vector<Thunk *>>190thunkedSymbols;191192// Find a Thunk from the Thunks symbol definition, we can use this to find193// the Thunk from a relocation to the Thunks symbol definition.194llvm::DenseMap<Symbol *, Thunk *> thunks;195196// Track InputSections that have an inline ThunkSection placed in front197// an inline ThunkSection may have control fall through to the section below198// so we need to make sure that there is only one of them.199// The Mips LA25 Thunk is an example of an inline ThunkSection.200llvm::DenseMap<InputSection *, ThunkSection *> thunkedSections;201202// The number of completed passes of createThunks this permits us203// to do one time initialization on Pass 0 and put a limit on the204// number of times it can be called to prevent infinite loops.205uint32_t pass = 0;206};207208// Decode LEB128 without error checking. Only used by performance critical code209// like RelocsCrel.210inline uint64_t readLEB128(const uint8_t *&p, uint64_t leb) {211uint64_t acc = 0, shift = 0, byte;212do {213byte = *p++;214acc |= (byte - 128 * (byte >= leb)) << shift;215shift += 7;216} while (byte >= 128);217return acc;218}219inline uint64_t readULEB128(const uint8_t *&p) { return readLEB128(p, 128); }220inline int64_t readSLEB128(const uint8_t *&p) { return readLEB128(p, 64); }221222// This class implements a CREL iterator that does not allocate extra memory.223template <bool is64> struct RelocsCrel {224using uint = std::conditional_t<is64, uint64_t, uint32_t>;225struct const_iterator {226using iterator_category = std::forward_iterator_tag;227using value_type = llvm::object::Elf_Crel_Impl<is64>;228using difference_type = ptrdiff_t;229using pointer = value_type *;230using reference = const value_type &;231uint32_t count;232uint8_t flagBits, shift;233const uint8_t *p;234llvm::object::Elf_Crel_Impl<is64> crel{};235const_iterator(size_t hdr, const uint8_t *p)236: count(hdr / 8), flagBits(hdr & 4 ? 3 : 2), shift(hdr % 4), p(p) {237if (count)238step();239}240void step() {241// See object::decodeCrel.242const uint8_t b = *p++;243crel.r_offset += b >> flagBits << shift;244if (b >= 0x80)245crel.r_offset +=246((readULEB128(p) << (7 - flagBits)) - (0x80 >> flagBits)) << shift;247if (b & 1)248crel.r_symidx += readSLEB128(p);249if (b & 2)250crel.r_type += readSLEB128(p);251if (b & 4 && flagBits == 3)252crel.r_addend += static_cast<uint>(readSLEB128(p));253}254llvm::object::Elf_Crel_Impl<is64> operator*() const { return crel; };255const llvm::object::Elf_Crel_Impl<is64> *operator->() const {256return &crel;257}258// For llvm::enumerate.259bool operator==(const const_iterator &r) const { return count == r.count; }260bool operator!=(const const_iterator &r) const { return count != r.count; }261const_iterator &operator++() {262if (--count)263step();264return *this;265}266// For RelocationScanner::scanOne.267void operator+=(size_t n) {268for (; n; --n)269operator++();270}271};272273size_t hdr = 0;274const uint8_t *p = nullptr;275276constexpr RelocsCrel() = default;277RelocsCrel(const uint8_t *p) : hdr(readULEB128(p)) { this->p = p; }278size_t size() const { return hdr / 8; }279const_iterator begin() const { return {hdr, p}; }280const_iterator end() const { return {0, nullptr}; }281};282283template <class RelTy> struct Relocs : ArrayRef<RelTy> {284Relocs() = default;285Relocs(ArrayRef<RelTy> a) : ArrayRef<RelTy>(a) {}286};287288template <bool is64>289struct Relocs<llvm::object::Elf_Crel_Impl<is64>> : RelocsCrel<is64> {290using RelocsCrel<is64>::RelocsCrel;291};292293// Return a int64_t to make sure we get the sign extension out of the way as294// early as possible.295template <class ELFT>296static inline int64_t getAddend(const typename ELFT::Rel &rel) {297return 0;298}299template <class ELFT>300static inline int64_t getAddend(const typename ELFT::Rela &rel) {301return rel.r_addend;302}303template <class ELFT>304static inline int64_t getAddend(const typename ELFT::Crel &rel) {305return rel.r_addend;306}307308template <typename RelTy>309inline Relocs<RelTy> sortRels(Relocs<RelTy> rels,310SmallVector<RelTy, 0> &storage) {311auto cmp = [](const RelTy &a, const RelTy &b) {312return a.r_offset < b.r_offset;313};314if (!llvm::is_sorted(rels, cmp)) {315storage.assign(rels.begin(), rels.end());316llvm::stable_sort(storage, cmp);317rels = Relocs<RelTy>(storage);318}319return rels;320}321322template <bool is64>323inline Relocs<llvm::object::Elf_Crel_Impl<is64>>324sortRels(Relocs<llvm::object::Elf_Crel_Impl<is64>> rels,325SmallVector<llvm::object::Elf_Crel_Impl<is64>, 0> &storage) {326return {};327}328329// Returns true if Expr refers a GOT entry. Note that this function returns330// false for TLS variables even though they need GOT, because TLS variables uses331// GOT differently than the regular variables.332bool needsGot(RelExpr expr);333} // namespace lld::elf334335#endif336337338