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