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/ADT/Triple.h"
18 
19 namespace llvm {
20 class MCStreamer;
21 class MCSymbol;
22 class raw_ostream;
23 
24 namespace ELF {
25 /// Relocation type mask that was accidentally output by bfd 2.30 linker.
26 enum { R_X86_64_converted_reloc_bit = 0x80 };
27 } // namespace ELF
28 
29 namespace bolt {
30 
31 /// Relocation class.
32 struct Relocation {
33   static Triple::ArchType Arch; /// set by BinaryContext ctor.
34 
35   /// The offset of this relocation in the object it is contained in.
36   uint64_t Offset;
37 
38   /// The symbol this relocation is referring to.
39   MCSymbol *Symbol;
40 
41   /// Relocation type.
42   uint64_t Type;
43 
44   /// The offset from the \p Symbol base used to compute the final
45   /// value of this relocation.
46   uint64_t Addend;
47 
48   /// The computed relocation value extracted from the binary file.
49   /// Used to validate relocation correctness.
50   uint64_t Value;
51 
52   /// Return size in bytes of the given relocation \p Type.
53   static size_t getSizeForType(uint64_t Type);
54 
55   /// Return size of this relocation.
getSizeRelocation56   size_t getSize() const { return getSizeForType(Type); }
57 
58   /// Skip relocations that we don't want to handle in BOLT
59   static bool skipRelocationType(uint64_t Type);
60 
61   /// Handle special cases when relocation should not be processed by BOLT
62   static bool skipRelocationProcess(uint64_t Type, uint64_t Contents);
63 
64   // Adjust value depending on relocation type (make it PC relative or not)
65   static uint64_t adjustValue(uint64_t Type, uint64_t Value,
66                               uint64_t PC);
67 
68   /// Extract current relocated value from binary contents. This is used for
69   /// RISC architectures where values are encoded in specific bits depending
70   /// on the relocation value. For X86, we limit to sign extending the value
71   /// if necessary.
72   static uint64_t extractValue(uint64_t Type, uint64_t Contents, uint64_t PC);
73 
74   /// Return true if relocation type is PC-relative. Return false otherwise.
75   static bool isPCRelative(uint64_t Type);
76 
77   /// Check if \p Type is a supported relocation type.
78   static bool isSupported(uint64_t Type);
79 
80   /// Return true if relocation type implies the creation of a GOT entry
81   static bool isGOT(uint64_t Type);
82 
83   /// Special relocation type that allows the linker to modify the instruction.
84   static bool isX86GOTPCRELX(uint64_t Type);
85 
86   /// Return true if relocation type is NONE
87   static bool isNone(uint64_t Type);
88 
89   /// Return true if relocation type is RELATIVE
90   static bool isRelative(uint64_t Type);
91 
92   /// Return true if relocation type is IRELATIVE
93   static bool isIRelative(uint64_t Type);
94 
95   /// Return true if relocation type is for thread local storage.
96   static bool isTLS(uint64_t Type);
97 
98   /// Return code for a NONE relocation
99   static uint64_t getNone();
100 
101   /// Return code for a PC-relative 4-byte relocation
102   static uint64_t getPC32();
103 
104   /// Return code for a PC-relative 8-byte relocation
105   static uint64_t getPC64();
106 
107   /// Return true if this relocation is PC-relative. Return false otherwise.
isPCRelativeRelocation108   bool isPCRelative() const { return isPCRelative(Type); }
109 
110   /// Return true if this relocation is R_*_RELATIVE type. Return false
111   /// otherwise.
isRelativeRelocation112   bool isRelative() const { return isRelative(Type); }
113 
114   /// Emit relocation at a current \p Streamer' position. The caller is
115   /// responsible for setting the position correctly.
116   size_t emit(MCStreamer *Streamer) const;
117 
118   /// Print a relocation to \p OS.
119   void print(raw_ostream &OS) const;
120 };
121 
122 /// Relocation ordering by offset.
123 inline bool operator<(const Relocation &A, const Relocation &B) {
124   return A.Offset < B.Offset;
125 }
126 
127 inline bool operator<(const Relocation &A, uint64_t B) { return A.Offset < B; }
128 
129 inline bool operator<(uint64_t A, const Relocation &B) { return A < B.Offset; }
130 
131 inline raw_ostream &operator<<(raw_ostream &OS, const Relocation &Rel) {
132   Rel.print(OS);
133   return OS;
134 }
135 
136 } // namespace bolt
137 } // namespace llvm
138 
139 #endif
140