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
20bdd1243dSDimitry Andric namespace lld::macho {
21fe6060f1SDimitry Andric LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE();
22fe6060f1SDimitry Andric
23fe6060f1SDimitry Andric class Symbol;
24fe6060f1SDimitry Andric class InputSection;
25fe6060f1SDimitry Andric
26fe6060f1SDimitry Andric enum class RelocAttrBits {
27fe6060f1SDimitry Andric _0 = 0, // invalid
28fe6060f1SDimitry Andric PCREL = 1 << 0, // Value is PC-relative offset
29fe6060f1SDimitry Andric ABSOLUTE = 1 << 1, // Value is an absolute address or fixed offset
30fe6060f1SDimitry Andric BYTE4 = 1 << 2, // 4 byte datum
31fe6060f1SDimitry Andric BYTE8 = 1 << 3, // 8 byte datum
32fe6060f1SDimitry Andric EXTERN = 1 << 4, // Can have an external symbol
33fe6060f1SDimitry Andric LOCAL = 1 << 5, // Can have a local symbol
34fe6060f1SDimitry Andric ADDEND = 1 << 6, // *_ADDEND paired prefix reloc
35fe6060f1SDimitry Andric SUBTRAHEND = 1 << 7, // *_SUBTRACTOR paired prefix reloc
36fe6060f1SDimitry Andric BRANCH = 1 << 8, // Value is branch target
37fe6060f1SDimitry Andric GOT = 1 << 9, // References a symbol in the Global Offset Table
38fe6060f1SDimitry Andric TLV = 1 << 10, // References a thread-local symbol
39fe6060f1SDimitry Andric LOAD = 1 << 11, // Relaxable indirect load
40fe6060f1SDimitry Andric POINTER = 1 << 12, // Non-relaxable indirect load (pointer is taken)
41fe6060f1SDimitry Andric UNSIGNED = 1 << 13, // *_UNSIGNED relocs
42fe6060f1SDimitry Andric LLVM_MARK_AS_BITMASK_ENUM(/*LargestValue*/ (1 << 14) - 1),
43fe6060f1SDimitry Andric };
44fe6060f1SDimitry Andric // Note: SUBTRACTOR always pairs with UNSIGNED (a delta between two symbols).
45fe6060f1SDimitry Andric
46fe6060f1SDimitry Andric struct RelocAttrs {
47fe6060f1SDimitry Andric llvm::StringRef name;
48fe6060f1SDimitry Andric RelocAttrBits bits;
hasAttrRelocAttrs49fe6060f1SDimitry Andric bool hasAttr(RelocAttrBits b) const { return (bits & b) == b; }
50fe6060f1SDimitry Andric };
51fe6060f1SDimitry Andric
52fe6060f1SDimitry Andric struct Reloc {
53fe6060f1SDimitry Andric uint8_t type = llvm::MachO::GENERIC_RELOC_INVALID;
54fe6060f1SDimitry Andric bool pcrel = false;
55fe6060f1SDimitry Andric uint8_t length = 0;
56fe6060f1SDimitry Andric // The offset from the start of the subsection that this relocation belongs
57fe6060f1SDimitry Andric // to.
58349cc55cSDimitry Andric uint32_t offset = 0;
59fe6060f1SDimitry Andric // Adding this offset to the address of the referent symbol or subsection
60fe6060f1SDimitry Andric // gives the destination that this relocation refers to.
61fe6060f1SDimitry Andric int64_t addend = 0;
62fe6060f1SDimitry Andric llvm::PointerUnion<Symbol *, InputSection *> referent = nullptr;
6381ad6265SDimitry Andric
6481ad6265SDimitry Andric Reloc() = default;
6581ad6265SDimitry Andric
RelocReloc6681ad6265SDimitry Andric Reloc(uint8_t type, bool pcrel, uint8_t length, uint32_t offset,
6781ad6265SDimitry Andric int64_t addend, llvm::PointerUnion<Symbol *, InputSection *> referent)
6881ad6265SDimitry Andric : type(type), pcrel(pcrel), length(length), offset(offset),
6981ad6265SDimitry Andric addend(addend), referent(referent) {}
70*06c3fb27SDimitry Andric
71*06c3fb27SDimitry Andric InputSection *getReferentInputSection() const;
7281ad6265SDimitry Andric };
7381ad6265SDimitry Andric
74fe6060f1SDimitry Andric bool validateSymbolRelocation(const Symbol *, const InputSection *,
75fe6060f1SDimitry Andric const Reloc &);
76fe6060f1SDimitry Andric
77fe6060f1SDimitry Andric /*
78fe6060f1SDimitry Andric * v: The value the relocation is attempting to encode
79fe6060f1SDimitry Andric * bits: The number of bits actually available to encode this relocation
80fe6060f1SDimitry Andric */
8181ad6265SDimitry Andric void reportRangeError(void *loc, const Reloc &, const llvm::Twine &v,
8281ad6265SDimitry Andric uint8_t bits, int64_t min, uint64_t max);
83fe6060f1SDimitry Andric
84fe6060f1SDimitry Andric struct SymbolDiagnostic {
85fe6060f1SDimitry Andric const Symbol *symbol;
86fe6060f1SDimitry Andric llvm::StringRef reason;
87fe6060f1SDimitry Andric };
88fe6060f1SDimitry Andric
8981ad6265SDimitry Andric void reportRangeError(void *loc, SymbolDiagnostic, const llvm::Twine &v,
9081ad6265SDimitry Andric uint8_t bits, int64_t min, uint64_t max);
91fe6060f1SDimitry Andric
92fe6060f1SDimitry Andric template <typename Diagnostic>
checkInt(void * loc,Diagnostic d,int64_t v,int bits)9381ad6265SDimitry Andric inline void checkInt(void *loc, Diagnostic d, int64_t v, int bits) {
94fe6060f1SDimitry Andric if (v != llvm::SignExtend64(v, bits))
9581ad6265SDimitry Andric reportRangeError(loc, d, llvm::Twine(v), bits, llvm::minIntN(bits),
96fe6060f1SDimitry Andric llvm::maxIntN(bits));
97fe6060f1SDimitry Andric }
98fe6060f1SDimitry Andric
99fe6060f1SDimitry Andric template <typename Diagnostic>
checkUInt(void * loc,Diagnostic d,uint64_t v,int bits)10081ad6265SDimitry Andric inline void checkUInt(void *loc, Diagnostic d, uint64_t v, int bits) {
101fe6060f1SDimitry Andric if ((v >> bits) != 0)
10281ad6265SDimitry Andric reportRangeError(loc, d, llvm::Twine(v), bits, 0, llvm::maxUIntN(bits));
103fe6060f1SDimitry Andric }
104fe6060f1SDimitry Andric
writeAddress(uint8_t * loc,uint64_t addr,uint8_t length)105fe6060f1SDimitry Andric inline void writeAddress(uint8_t *loc, uint64_t addr, uint8_t length) {
106fe6060f1SDimitry Andric switch (length) {
107fe6060f1SDimitry Andric case 2:
108fe6060f1SDimitry Andric llvm::support::endian::write32le(loc, addr);
109fe6060f1SDimitry Andric break;
110fe6060f1SDimitry Andric case 3:
111fe6060f1SDimitry Andric llvm::support::endian::write64le(loc, addr);
112fe6060f1SDimitry Andric break;
113fe6060f1SDimitry Andric default:
114fe6060f1SDimitry Andric llvm_unreachable("invalid r_length");
115fe6060f1SDimitry Andric }
116fe6060f1SDimitry Andric }
117fe6060f1SDimitry Andric
118bdd1243dSDimitry Andric InputSection *offsetToInputSection(uint64_t *);
119bdd1243dSDimitry Andric
120fe6060f1SDimitry Andric extern const RelocAttrs invalidRelocAttrs;
121fe6060f1SDimitry Andric
122bdd1243dSDimitry Andric } // namespace lld::Macho
123fe6060f1SDimitry Andric
124fe6060f1SDimitry Andric #endif
125