1 //===-- RelocVisitor.h - Visitor for object file relocations -*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // This file provides a wrapper around all the different types of relocations 11 // in different file formats, such that a client can handle them in a unified 12 // manner by only implementing a minimal number of functions. 13 // 14 //===----------------------------------------------------------------------===// 15 16 #ifndef LLVM_OBJECT_RELOCVISITOR_H 17 #define LLVM_OBJECT_RELOCVISITOR_H 18 19 #include "llvm/ADT/StringRef.h" 20 #include "llvm/Object/ObjectFile.h" 21 #include "llvm/Support/Debug.h" 22 #include "llvm/Support/ELF.h" 23 #include "llvm/Support/raw_ostream.h" 24 25 namespace llvm { 26 namespace object { 27 28 struct RelocToApply { 29 // The computed value after applying the relevant relocations. 30 int64_t Value; 31 32 // The width of the value; how many bytes to touch when applying the 33 // relocation. 34 char Width; RelocToApplyRelocToApply35 RelocToApply(const RelocToApply &In) : Value(In.Value), Width(In.Width) {} RelocToApplyRelocToApply36 RelocToApply(int64_t Value, char Width) : Value(Value), Width(Width) {} RelocToApplyRelocToApply37 RelocToApply() : Value(0), Width(0) {} 38 }; 39 40 /// @brief Base class for object file relocation visitors. 41 class RelocVisitor { 42 public: RelocVisitor(StringRef FileFormat)43 explicit RelocVisitor(StringRef FileFormat) 44 : FileFormat(FileFormat), HasError(false) {} 45 46 // TODO: Should handle multiple applied relocations via either passing in the 47 // previously computed value or just count paired relocations as a single 48 // visit. 49 RelocToApply visit(uint32_t RelocType, RelocationRef R, uint64_t SecAddr = 0, 50 uint64_t Value = 0) { 51 if (FileFormat == "ELF64-x86-64") { 52 switch (RelocType) { 53 case llvm::ELF::R_X86_64_NONE: 54 return visitELF_X86_64_NONE(R); 55 case llvm::ELF::R_X86_64_64: 56 return visitELF_X86_64_64(R, Value); 57 case llvm::ELF::R_X86_64_PC32: 58 return visitELF_X86_64_PC32(R, Value, SecAddr); 59 case llvm::ELF::R_X86_64_32: 60 return visitELF_X86_64_32(R, Value); 61 case llvm::ELF::R_X86_64_32S: 62 return visitELF_X86_64_32S(R, Value); 63 default: 64 HasError = true; 65 return RelocToApply(); 66 } 67 } else if (FileFormat == "ELF32-i386") { 68 switch (RelocType) { 69 case llvm::ELF::R_386_NONE: 70 return visitELF_386_NONE(R); 71 case llvm::ELF::R_386_32: 72 return visitELF_386_32(R, Value); 73 case llvm::ELF::R_386_PC32: 74 return visitELF_386_PC32(R, Value, SecAddr); 75 default: 76 HasError = true; 77 return RelocToApply(); 78 } 79 } else if (FileFormat == "ELF64-ppc64") { 80 switch (RelocType) { 81 case llvm::ELF::R_PPC64_ADDR32: 82 return visitELF_PPC64_ADDR32(R, Value); 83 default: 84 HasError = true; 85 return RelocToApply(); 86 } 87 } else if (FileFormat == "ELF32-mips") { 88 switch (RelocType) { 89 case llvm::ELF::R_MIPS_32: 90 return visitELF_MIPS_32(R, Value); 91 default: 92 HasError = true; 93 return RelocToApply(); 94 } 95 } else if (FileFormat == "ELF64-aarch64") { 96 switch (RelocType) { 97 case llvm::ELF::R_AARCH64_ABS32: 98 return visitELF_AARCH64_ABS32(R, Value); 99 case llvm::ELF::R_AARCH64_ABS64: 100 return visitELF_AARCH64_ABS64(R, Value); 101 default: 102 HasError = true; 103 return RelocToApply(); 104 } 105 } 106 HasError = true; 107 return RelocToApply(); 108 } 109 error()110 bool error() { return HasError; } 111 112 private: 113 StringRef FileFormat; 114 bool HasError; 115 116 /// Operations 117 118 /// 386-ELF visitELF_386_NONE(RelocationRef R)119 RelocToApply visitELF_386_NONE(RelocationRef R) { 120 return RelocToApply(0, 0); 121 } 122 123 // Ideally the Addend here will be the addend in the data for 124 // the relocation. It's not actually the case for Rel relocations. visitELF_386_32(RelocationRef R,uint64_t Value)125 RelocToApply visitELF_386_32(RelocationRef R, uint64_t Value) { 126 int64_t Addend; 127 R.getAdditionalInfo(Addend); 128 return RelocToApply(Value + Addend, 4); 129 } 130 visitELF_386_PC32(RelocationRef R,uint64_t Value,uint64_t SecAddr)131 RelocToApply visitELF_386_PC32(RelocationRef R, uint64_t Value, 132 uint64_t SecAddr) { 133 int64_t Addend; 134 R.getAdditionalInfo(Addend); 135 uint64_t Address; 136 R.getAddress(Address); 137 return RelocToApply(Value + Addend - Address, 4); 138 } 139 140 /// X86-64 ELF visitELF_X86_64_NONE(RelocationRef R)141 RelocToApply visitELF_X86_64_NONE(RelocationRef R) { 142 return RelocToApply(0, 0); 143 } visitELF_X86_64_64(RelocationRef R,uint64_t Value)144 RelocToApply visitELF_X86_64_64(RelocationRef R, uint64_t Value) { 145 int64_t Addend; 146 R.getAdditionalInfo(Addend); 147 return RelocToApply(Value + Addend, 8); 148 } visitELF_X86_64_PC32(RelocationRef R,uint64_t Value,uint64_t SecAddr)149 RelocToApply visitELF_X86_64_PC32(RelocationRef R, uint64_t Value, 150 uint64_t SecAddr) { 151 int64_t Addend; 152 R.getAdditionalInfo(Addend); 153 uint64_t Address; 154 R.getAddress(Address); 155 return RelocToApply(Value + Addend - Address, 4); 156 } visitELF_X86_64_32(RelocationRef R,uint64_t Value)157 RelocToApply visitELF_X86_64_32(RelocationRef R, uint64_t Value) { 158 int64_t Addend; 159 R.getAdditionalInfo(Addend); 160 uint32_t Res = (Value + Addend) & 0xFFFFFFFF; 161 return RelocToApply(Res, 4); 162 } visitELF_X86_64_32S(RelocationRef R,uint64_t Value)163 RelocToApply visitELF_X86_64_32S(RelocationRef R, uint64_t Value) { 164 int64_t Addend; 165 R.getAdditionalInfo(Addend); 166 int32_t Res = (Value + Addend) & 0xFFFFFFFF; 167 return RelocToApply(Res, 4); 168 } 169 170 /// PPC64 ELF visitELF_PPC64_ADDR32(RelocationRef R,uint64_t Value)171 RelocToApply visitELF_PPC64_ADDR32(RelocationRef R, uint64_t Value) { 172 int64_t Addend; 173 R.getAdditionalInfo(Addend); 174 uint32_t Res = (Value + Addend) & 0xFFFFFFFF; 175 return RelocToApply(Res, 4); 176 } 177 178 /// MIPS ELF visitELF_MIPS_32(RelocationRef R,uint64_t Value)179 RelocToApply visitELF_MIPS_32(RelocationRef R, uint64_t Value) { 180 int64_t Addend; 181 R.getAdditionalInfo(Addend); 182 uint32_t Res = (Value + Addend) & 0xFFFFFFFF; 183 return RelocToApply(Res, 4); 184 } 185 186 // AArch64 ELF visitELF_AARCH64_ABS32(RelocationRef R,uint64_t Value)187 RelocToApply visitELF_AARCH64_ABS32(RelocationRef R, uint64_t Value) { 188 int64_t Addend; 189 R.getAdditionalInfo(Addend); 190 int64_t Res = Value + Addend; 191 192 // Overflow check allows for both signed and unsigned interpretation. 193 if (Res < INT32_MIN || Res > UINT32_MAX) 194 HasError = true; 195 196 return RelocToApply(static_cast<uint32_t>(Res), 4); 197 } 198 visitELF_AARCH64_ABS64(RelocationRef R,uint64_t Value)199 RelocToApply visitELF_AARCH64_ABS64(RelocationRef R, uint64_t Value) { 200 int64_t Addend; 201 R.getAdditionalInfo(Addend); 202 return RelocToApply(Value + Addend, 8); 203 } 204 205 }; 206 207 } 208 } 209 #endif 210