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

source code of bolt/include/bolt/Core/Relocation.h