1fe6060f1SDimitry Andric //===- Relocations.h --------------------------------------------*- C++ -*-===// 2fe6060f1SDimitry Andric // 3fe6060f1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4fe6060f1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5fe6060f1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6fe6060f1SDimitry Andric // 7fe6060f1SDimitry Andric //===----------------------------------------------------------------------===// 8fe6060f1SDimitry Andric 9fe6060f1SDimitry Andric #ifndef LLD_MACHO_RELOCATIONS_H 10fe6060f1SDimitry Andric #define LLD_MACHO_RELOCATIONS_H 11fe6060f1SDimitry Andric 12fe6060f1SDimitry Andric #include "llvm/ADT/BitmaskEnum.h" 13fe6060f1SDimitry Andric #include "llvm/ADT/PointerUnion.h" 14fe6060f1SDimitry Andric #include "llvm/BinaryFormat/MachO.h" 15fe6060f1SDimitry Andric #include "llvm/Support/Endian.h" 16fe6060f1SDimitry Andric 17fe6060f1SDimitry Andric #include <cstddef> 18fe6060f1SDimitry Andric #include <cstdint> 19fe6060f1SDimitry Andric 20fe6060f1SDimitry Andric namespace lld { 21fe6060f1SDimitry Andric namespace macho { 22fe6060f1SDimitry Andric LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE(); 23fe6060f1SDimitry Andric 24fe6060f1SDimitry Andric class Symbol; 25fe6060f1SDimitry Andric class InputSection; 26fe6060f1SDimitry Andric 27fe6060f1SDimitry Andric enum class RelocAttrBits { 28fe6060f1SDimitry Andric _0 = 0, // invalid 29fe6060f1SDimitry Andric PCREL = 1 << 0, // Value is PC-relative offset 30fe6060f1SDimitry Andric ABSOLUTE = 1 << 1, // Value is an absolute address or fixed offset 31fe6060f1SDimitry Andric BYTE4 = 1 << 2, // 4 byte datum 32fe6060f1SDimitry Andric BYTE8 = 1 << 3, // 8 byte datum 33fe6060f1SDimitry Andric EXTERN = 1 << 4, // Can have an external symbol 34fe6060f1SDimitry Andric LOCAL = 1 << 5, // Can have a local symbol 35fe6060f1SDimitry Andric ADDEND = 1 << 6, // *_ADDEND paired prefix reloc 36fe6060f1SDimitry Andric SUBTRAHEND = 1 << 7, // *_SUBTRACTOR paired prefix reloc 37fe6060f1SDimitry Andric BRANCH = 1 << 8, // Value is branch target 38fe6060f1SDimitry Andric GOT = 1 << 9, // References a symbol in the Global Offset Table 39fe6060f1SDimitry Andric TLV = 1 << 10, // References a thread-local symbol 40fe6060f1SDimitry Andric LOAD = 1 << 11, // Relaxable indirect load 41fe6060f1SDimitry Andric POINTER = 1 << 12, // Non-relaxable indirect load (pointer is taken) 42fe6060f1SDimitry Andric UNSIGNED = 1 << 13, // *_UNSIGNED relocs 43fe6060f1SDimitry Andric LLVM_MARK_AS_BITMASK_ENUM(/*LargestValue*/ (1 << 14) - 1), 44fe6060f1SDimitry Andric }; 45fe6060f1SDimitry Andric // Note: SUBTRACTOR always pairs with UNSIGNED (a delta between two symbols). 46fe6060f1SDimitry Andric 47fe6060f1SDimitry Andric struct RelocAttrs { 48fe6060f1SDimitry Andric llvm::StringRef name; 49fe6060f1SDimitry Andric RelocAttrBits bits; 50fe6060f1SDimitry Andric bool hasAttr(RelocAttrBits b) const { return (bits & b) == b; } 51fe6060f1SDimitry Andric }; 52fe6060f1SDimitry Andric 53fe6060f1SDimitry Andric struct Reloc { 54fe6060f1SDimitry Andric uint8_t type = llvm::MachO::GENERIC_RELOC_INVALID; 55fe6060f1SDimitry Andric bool pcrel = false; 56fe6060f1SDimitry Andric uint8_t length = 0; 57fe6060f1SDimitry Andric // The offset from the start of the subsection that this relocation belongs 58fe6060f1SDimitry Andric // to. 59*349cc55cSDimitry Andric uint32_t offset = 0; 60fe6060f1SDimitry Andric // Adding this offset to the address of the referent symbol or subsection 61fe6060f1SDimitry Andric // gives the destination that this relocation refers to. 62fe6060f1SDimitry Andric int64_t addend = 0; 63fe6060f1SDimitry Andric llvm::PointerUnion<Symbol *, InputSection *> referent = nullptr; 64fe6060f1SDimitry Andric }; 65fe6060f1SDimitry Andric 66fe6060f1SDimitry Andric bool validateSymbolRelocation(const Symbol *, const InputSection *, 67fe6060f1SDimitry Andric const Reloc &); 68fe6060f1SDimitry Andric 69fe6060f1SDimitry Andric /* 70fe6060f1SDimitry Andric * v: The value the relocation is attempting to encode 71fe6060f1SDimitry Andric * bits: The number of bits actually available to encode this relocation 72fe6060f1SDimitry Andric */ 73fe6060f1SDimitry Andric void reportRangeError(const Reloc &, const llvm::Twine &v, uint8_t bits, 74fe6060f1SDimitry Andric int64_t min, uint64_t max); 75fe6060f1SDimitry Andric 76fe6060f1SDimitry Andric struct SymbolDiagnostic { 77fe6060f1SDimitry Andric const Symbol *symbol; 78fe6060f1SDimitry Andric llvm::StringRef reason; 79fe6060f1SDimitry Andric }; 80fe6060f1SDimitry Andric 81fe6060f1SDimitry Andric void reportRangeError(SymbolDiagnostic, const llvm::Twine &v, uint8_t bits, 82fe6060f1SDimitry Andric int64_t min, uint64_t max); 83fe6060f1SDimitry Andric 84fe6060f1SDimitry Andric template <typename Diagnostic> 85fe6060f1SDimitry Andric inline void checkInt(Diagnostic d, int64_t v, int bits) { 86fe6060f1SDimitry Andric if (v != llvm::SignExtend64(v, bits)) 87fe6060f1SDimitry Andric reportRangeError(d, llvm::Twine(v), bits, llvm::minIntN(bits), 88fe6060f1SDimitry Andric llvm::maxIntN(bits)); 89fe6060f1SDimitry Andric } 90fe6060f1SDimitry Andric 91fe6060f1SDimitry Andric template <typename Diagnostic> 92fe6060f1SDimitry Andric inline void checkUInt(Diagnostic d, uint64_t v, int bits) { 93fe6060f1SDimitry Andric if ((v >> bits) != 0) 94fe6060f1SDimitry Andric reportRangeError(d, llvm::Twine(v), bits, 0, llvm::maxUIntN(bits)); 95fe6060f1SDimitry Andric } 96fe6060f1SDimitry Andric 97fe6060f1SDimitry Andric inline void writeAddress(uint8_t *loc, uint64_t addr, uint8_t length) { 98fe6060f1SDimitry Andric switch (length) { 99fe6060f1SDimitry Andric case 2: 100fe6060f1SDimitry Andric llvm::support::endian::write32le(loc, addr); 101fe6060f1SDimitry Andric break; 102fe6060f1SDimitry Andric case 3: 103fe6060f1SDimitry Andric llvm::support::endian::write64le(loc, addr); 104fe6060f1SDimitry Andric break; 105fe6060f1SDimitry Andric default: 106fe6060f1SDimitry Andric llvm_unreachable("invalid r_length"); 107fe6060f1SDimitry Andric } 108fe6060f1SDimitry Andric } 109fe6060f1SDimitry Andric 110fe6060f1SDimitry Andric extern const RelocAttrs invalidRelocAttrs; 111fe6060f1SDimitry Andric 112fe6060f1SDimitry Andric } // namespace macho 113fe6060f1SDimitry Andric } // namespace lld 114fe6060f1SDimitry Andric 115fe6060f1SDimitry Andric #endif 116