xref: /llvm-project/bolt/include/bolt/Core/Relocation.h (revision 1a2f83366b86433bb86f3b60fa19b3f096313a21)
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.
getSizeRelocation57   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.
isPCRelativeRelocation121   bool isPCRelative() const { return isPCRelative(Type); }
122 
123   /// Return true if this relocation is R_*_RELATIVE type. Return false
124   /// otherwise.
isRelativeRelocation125   bool isRelative() const { return isRelative(Type); }
126 
127   /// Return true if this relocation is R_*_IRELATIVE type. Return false
128   /// otherwise.
isIRelativeRelocation129   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>
emitRelocation139   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