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;
23class raw_ostream;
24
25namespace ELF {
26/// Relocation type mask that was accidentally output by bfd 2.30 linker.
27enum { R_X86_64_converted_reloc_bit = 0x80 };
28} // namespace ELF
29
30namespace bolt {
31
32/// Relocation class.
33struct 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 extractValue(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
160private:
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.
168inline bool operator<(const Relocation &A, const Relocation &B) {
169 return A.Offset < B.Offset;
170}
171
172inline bool operator<(const Relocation &A, uint64_t B) { return A.Offset < B; }
173
174inline bool operator<(uint64_t A, const Relocation &B) { return A < B.Offset; }
175
176inline 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

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