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