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