1 | //===- bolt/Core/Relocation.h - Object file relocations ---------*- 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 | // This file contains the declaration of Relocation class, which represents a |
10 | // relocation in an object or a binary file. |
11 | // |
12 | //===----------------------------------------------------------------------===// |
13 | |
14 | #ifndef BOLT_CORE_RELOCATION_H |
15 | #define BOLT_CORE_RELOCATION_H |
16 | |
17 | #include "llvm/MC/MCExpr.h" |
18 | #include "llvm/MC/MCStreamer.h" |
19 | #include "llvm/TargetParser/Triple.h" |
20 | |
21 | namespace llvm { |
22 | class MCSymbol; |
23 | class raw_ostream; |
24 | |
25 | namespace ELF { |
26 | /// Relocation type mask that was accidentally output by bfd 2.30 linker. |
27 | enum { R_X86_64_converted_reloc_bit = 0x80 }; |
28 | } // namespace ELF |
29 | |
30 | namespace bolt { |
31 | |
32 | /// Relocation class. |
33 | struct Relocation { |
34 | static Triple::ArchType Arch; /// set by BinaryContext ctor. |
35 | |
36 | /// The offset of this relocation in the object it is contained in. |
37 | uint64_t Offset; |
38 | |
39 | /// The symbol this relocation is referring to. |
40 | MCSymbol *Symbol; |
41 | |
42 | /// Relocation type. |
43 | uint64_t Type; |
44 | |
45 | /// The offset from the \p Symbol base used to compute the final |
46 | /// value of this relocation. |
47 | uint64_t Addend; |
48 | |
49 | /// The computed relocation value extracted from the binary file. |
50 | /// Used to validate relocation correctness. |
51 | uint64_t Value; |
52 | |
53 | /// Return size in bytes of the given relocation \p Type. |
54 | static size_t getSizeForType(uint64_t Type); |
55 | |
56 | /// Return size of this relocation. |
57 | size_t getSize() const { return getSizeForType(Type); } |
58 | |
59 | /// Skip relocations that we don't want to handle in BOLT |
60 | static bool skipRelocationType(uint64_t Type); |
61 | |
62 | /// Handle special cases when relocation should not be processed by BOLT or |
63 | /// change relocation \p Type to proper one before continuing if \p Contents |
64 | /// and \P Type mismatch occurred. |
65 | static bool skipRelocationProcess(uint64_t &Type, uint64_t Contents); |
66 | |
67 | // Adjust value depending on relocation type (make it PC relative or not) |
68 | static uint64_t encodeValue(uint64_t Type, uint64_t Value, uint64_t PC); |
69 | |
70 | /// Extract current relocated value from binary contents. This is used for |
71 | /// RISC architectures where values are encoded in specific bits depending |
72 | /// on the relocation value. For X86, we limit to sign extending the value |
73 | /// if necessary. |
74 | static uint64_t (uint64_t Type, uint64_t Contents, uint64_t PC); |
75 | |
76 | /// Return true if relocation type is PC-relative. Return false otherwise. |
77 | static bool isPCRelative(uint64_t Type); |
78 | |
79 | /// Check if \p Type is a supported relocation type. |
80 | static bool isSupported(uint64_t Type); |
81 | |
82 | /// Return true if relocation type implies the creation of a GOT entry |
83 | static bool isGOT(uint64_t Type); |
84 | |
85 | /// Special relocation type that allows the linker to modify the instruction. |
86 | static bool isX86GOTPCRELX(uint64_t Type); |
87 | static bool isX86GOTPC64(uint64_t Type); |
88 | |
89 | /// Return true if relocation type is NONE |
90 | static bool isNone(uint64_t Type); |
91 | |
92 | /// Return true if relocation type is RELATIVE |
93 | static bool isRelative(uint64_t Type); |
94 | |
95 | /// Return true if relocation type is IRELATIVE |
96 | static bool isIRelative(uint64_t Type); |
97 | |
98 | /// Return true if relocation type is for thread local storage. |
99 | static bool isTLS(uint64_t Type); |
100 | |
101 | /// Return true of relocation type is for referencing a specific instruction |
102 | /// (as opposed to a function, basic block, etc). |
103 | static bool isInstructionReference(uint64_t Type); |
104 | |
105 | /// Return code for a NONE relocation |
106 | static uint64_t getNone(); |
107 | |
108 | /// Return code for a PC-relative 4-byte relocation |
109 | static uint64_t getPC32(); |
110 | |
111 | /// Return code for a PC-relative 8-byte relocation |
112 | static uint64_t getPC64(); |
113 | |
114 | /// Return code for a ABS 8-byte relocation |
115 | static uint64_t getAbs64(); |
116 | |
117 | /// Return code for a RELATIVE relocation |
118 | static uint64_t getRelative(); |
119 | |
120 | /// Return true if this relocation is PC-relative. Return false otherwise. |
121 | bool isPCRelative() const { return isPCRelative(Type); } |
122 | |
123 | /// Return true if this relocation is R_*_RELATIVE type. Return false |
124 | /// otherwise. |
125 | bool isRelative() const { return isRelative(Type); } |
126 | |
127 | /// Return true if this relocation is R_*_IRELATIVE type. Return false |
128 | /// otherwise. |
129 | bool isIRelative() const { return isIRelative(Type); } |
130 | |
131 | /// Emit relocation at a current \p Streamer' position. The caller is |
132 | /// responsible for setting the position correctly. |
133 | size_t emit(MCStreamer *Streamer) const; |
134 | |
135 | /// Emit a group of composed relocations. All relocations must have the same |
136 | /// offset. If std::distance(Begin, End) == 1, this is equivalent to |
137 | /// Begin->emit(Streamer). |
138 | template <typename RelocIt> |
139 | static size_t emit(RelocIt Begin, RelocIt End, MCStreamer *Streamer) { |
140 | if (Begin == End) |
141 | return 0; |
142 | |
143 | const MCExpr *Value = nullptr; |
144 | |
145 | for (auto RI = Begin; RI != End; ++RI) { |
146 | assert(RI->Offset == Begin->Offset && |
147 | "emitting composed relocations with different offsets" ); |
148 | Value = RI->createExpr(Streamer, Value); |
149 | } |
150 | |
151 | assert(Value && "failed to create relocation value" ); |
152 | auto Size = std::prev(End)->getSize(); |
153 | Streamer->emitValue(Value, Size); |
154 | return Size; |
155 | } |
156 | |
157 | /// Print a relocation to \p OS. |
158 | void print(raw_ostream &OS) const; |
159 | |
160 | private: |
161 | const MCExpr *createExpr(MCStreamer *Streamer) const; |
162 | const MCExpr *createExpr(MCStreamer *Streamer, |
163 | const MCExpr *RetainedValue) const; |
164 | static MCBinaryExpr::Opcode getComposeOpcodeFor(uint64_t Type); |
165 | }; |
166 | |
167 | /// Relocation ordering by offset. |
168 | inline bool operator<(const Relocation &A, const Relocation &B) { |
169 | return A.Offset < B.Offset; |
170 | } |
171 | |
172 | inline bool operator<(const Relocation &A, uint64_t B) { return A.Offset < B; } |
173 | |
174 | inline bool operator<(uint64_t A, const Relocation &B) { return A < B.Offset; } |
175 | |
176 | inline raw_ostream &operator<<(raw_ostream &OS, const Relocation &Rel) { |
177 | Rel.print(OS); |
178 | return OS; |
179 | } |
180 | |
181 | } // namespace bolt |
182 | } // namespace llvm |
183 | |
184 | #endif |
185 | |