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/Triple.h" 20 #include "llvm/BinaryFormat/ELF.h" 21 #include "llvm/BinaryFormat/MachO.h" 22 #include "llvm/Object/COFF.h" 23 #include "llvm/Object/ELFObjectFile.h" 24 #include "llvm/Object/MachO.h" 25 #include "llvm/Object/ObjectFile.h" 26 #include "llvm/Object/Wasm.h" 27 #include "llvm/Support/Casting.h" 28 #include "llvm/Support/ErrorHandling.h" 29 #include <cstdint> 30 #include <system_error> 31 32 namespace llvm { 33 namespace object { 34 35 /// Base class for object file relocation visitors. 36 class RelocVisitor { 37 public: RelocVisitor(const ObjectFile & Obj)38 explicit RelocVisitor(const ObjectFile &Obj) : ObjToVisit(Obj) {} 39 40 // TODO: Should handle multiple applied relocations via either passing in the 41 // previously computed value or just count paired relocations as a single 42 // visit. 43 uint64_t visit(uint32_t Rel, RelocationRef R, uint64_t Value = 0) { 44 if (isa<ELFObjectFileBase>(ObjToVisit)) 45 return visitELF(Rel, R, Value); 46 if (isa<COFFObjectFile>(ObjToVisit)) 47 return visitCOFF(Rel, R, Value); 48 if (isa<MachOObjectFile>(ObjToVisit)) 49 return visitMachO(Rel, R, Value); 50 if (isa<WasmObjectFile>(ObjToVisit)) 51 return visitWasm(Rel, R, Value); 52 53 HasError = true; 54 return 0; 55 } 56 error()57 bool error() { return HasError; } 58 59 private: 60 const ObjectFile &ObjToVisit; 61 bool HasError = false; 62 visitELF(uint32_t Rel,RelocationRef R,uint64_t Value)63 uint64_t visitELF(uint32_t Rel, RelocationRef R, uint64_t Value) { 64 if (ObjToVisit.getBytesInAddress() == 8) { // 64-bit object file 65 switch (ObjToVisit.getArch()) { 66 case Triple::x86_64: 67 return visitX86_64(Rel, R, Value); 68 case Triple::aarch64: 69 case Triple::aarch64_be: 70 return visitAarch64(Rel, R, Value); 71 case Triple::bpfel: 72 case Triple::bpfeb: 73 return visitBpf(Rel, R, Value); 74 case Triple::mips64el: 75 case Triple::mips64: 76 return visitMips64(Rel, R, Value); 77 case Triple::ppc64le: 78 case Triple::ppc64: 79 return visitPPC64(Rel, R, Value); 80 case Triple::systemz: 81 return visitSystemz(Rel, R, Value); 82 case Triple::sparcv9: 83 return visitSparc64(Rel, R, Value); 84 case Triple::amdgcn: 85 return visitAmdgpu(Rel, R, Value); 86 default: 87 HasError = true; 88 return 0; 89 } 90 } 91 92 // 32-bit object file 93 assert(ObjToVisit.getBytesInAddress() == 4 && 94 "Invalid word size in object file"); 95 96 switch (ObjToVisit.getArch()) { 97 case Triple::x86: 98 return visitX86(Rel, R, Value); 99 case Triple::ppc: 100 return visitPPC32(Rel, R, Value); 101 case Triple::arm: 102 case Triple::armeb: 103 return visitARM(Rel, R, Value); 104 case Triple::lanai: 105 return visitLanai(Rel, R, Value); 106 case Triple::mipsel: 107 case Triple::mips: 108 return visitMips32(Rel, R, Value); 109 case Triple::sparc: 110 return visitSparc32(Rel, R, Value); 111 case Triple::hexagon: 112 return visitHexagon(Rel, R, Value); 113 default: 114 HasError = true; 115 return 0; 116 } 117 } 118 getELFAddend(RelocationRef R)119 int64_t getELFAddend(RelocationRef R) { 120 Expected<int64_t> AddendOrErr = ELFRelocationRef(R).getAddend(); 121 handleAllErrors(AddendOrErr.takeError(), [](const ErrorInfoBase &EI) { 122 report_fatal_error(EI.message()); 123 }); 124 return *AddendOrErr; 125 } 126 visitX86_64(uint32_t Rel,RelocationRef R,uint64_t Value)127 uint64_t visitX86_64(uint32_t Rel, RelocationRef R, uint64_t Value) { 128 switch (Rel) { 129 case ELF::R_X86_64_NONE: 130 return 0; 131 case ELF::R_X86_64_64: 132 case ELF::R_X86_64_DTPOFF32: 133 case ELF::R_X86_64_DTPOFF64: 134 return Value + getELFAddend(R); 135 case ELF::R_X86_64_PC32: 136 return Value + getELFAddend(R) - R.getOffset(); 137 case ELF::R_X86_64_32: 138 case ELF::R_X86_64_32S: 139 return (Value + getELFAddend(R)) & 0xFFFFFFFF; 140 } 141 HasError = true; 142 return 0; 143 } 144 visitAarch64(uint32_t Rel,RelocationRef R,uint64_t Value)145 uint64_t visitAarch64(uint32_t Rel, RelocationRef R, uint64_t Value) { 146 switch (Rel) { 147 case ELF::R_AARCH64_ABS32: { 148 int64_t Res = Value + getELFAddend(R); 149 if (Res < INT32_MIN || Res > UINT32_MAX) 150 HasError = true; 151 return static_cast<uint32_t>(Res); 152 } 153 case ELF::R_AARCH64_ABS64: 154 return Value + getELFAddend(R); 155 } 156 HasError = true; 157 return 0; 158 } 159 visitBpf(uint32_t Rel,RelocationRef R,uint64_t Value)160 uint64_t visitBpf(uint32_t Rel, RelocationRef R, uint64_t Value) { 161 switch (Rel) { 162 case ELF::R_BPF_64_32: 163 return Value & 0xFFFFFFFF; 164 case ELF::R_BPF_64_64: 165 return Value; 166 } 167 HasError = true; 168 return 0; 169 } 170 visitMips64(uint32_t Rel,RelocationRef R,uint64_t Value)171 uint64_t visitMips64(uint32_t Rel, RelocationRef R, uint64_t Value) { 172 switch (Rel) { 173 case ELF::R_MIPS_32: 174 return (Value + getELFAddend(R)) & 0xFFFFFFFF; 175 case ELF::R_MIPS_64: 176 return Value + getELFAddend(R); 177 case ELF::R_MIPS_TLS_DTPREL64: 178 return Value + getELFAddend(R) - 0x8000; 179 } 180 HasError = true; 181 return 0; 182 } 183 visitPPC64(uint32_t Rel,RelocationRef R,uint64_t Value)184 uint64_t visitPPC64(uint32_t Rel, RelocationRef R, uint64_t Value) { 185 switch (Rel) { 186 case ELF::R_PPC64_ADDR32: 187 return (Value + getELFAddend(R)) & 0xFFFFFFFF; 188 case ELF::R_PPC64_ADDR64: 189 return Value + getELFAddend(R); 190 } 191 HasError = true; 192 return 0; 193 } 194 visitSystemz(uint32_t Rel,RelocationRef R,uint64_t Value)195 uint64_t visitSystemz(uint32_t Rel, RelocationRef R, uint64_t Value) { 196 switch (Rel) { 197 case ELF::R_390_32: { 198 int64_t Res = Value + getELFAddend(R); 199 if (Res < INT32_MIN || Res > UINT32_MAX) 200 HasError = true; 201 return static_cast<uint32_t>(Res); 202 } 203 case ELF::R_390_64: 204 return Value + getELFAddend(R); 205 } 206 HasError = true; 207 return 0; 208 } 209 visitSparc64(uint32_t Rel,RelocationRef R,uint64_t Value)210 uint64_t visitSparc64(uint32_t Rel, RelocationRef R, uint64_t Value) { 211 switch (Rel) { 212 case ELF::R_SPARC_32: 213 case ELF::R_SPARC_64: 214 case ELF::R_SPARC_UA32: 215 case ELF::R_SPARC_UA64: 216 return Value + getELFAddend(R); 217 } 218 HasError = true; 219 return 0; 220 } 221 visitAmdgpu(uint32_t Rel,RelocationRef R,uint64_t Value)222 uint64_t visitAmdgpu(uint32_t Rel, RelocationRef R, uint64_t Value) { 223 switch (Rel) { 224 case ELF::R_AMDGPU_ABS32: 225 case ELF::R_AMDGPU_ABS64: 226 return Value + getELFAddend(R); 227 } 228 HasError = true; 229 return 0; 230 } 231 visitX86(uint32_t Rel,RelocationRef R,uint64_t Value)232 uint64_t visitX86(uint32_t Rel, RelocationRef R, uint64_t Value) { 233 switch (Rel) { 234 case ELF::R_386_NONE: 235 return 0; 236 case ELF::R_386_32: 237 return Value; 238 case ELF::R_386_PC32: 239 return Value - R.getOffset(); 240 } 241 HasError = true; 242 return 0; 243 } 244 visitPPC32(uint32_t Rel,RelocationRef R,uint64_t Value)245 uint64_t visitPPC32(uint32_t Rel, RelocationRef R, uint64_t Value) { 246 if (Rel == ELF::R_PPC_ADDR32) 247 return (Value + getELFAddend(R)) & 0xFFFFFFFF; 248 HasError = true; 249 return 0; 250 } 251 visitARM(uint32_t Rel,RelocationRef R,uint64_t Value)252 uint64_t visitARM(uint32_t Rel, RelocationRef R, uint64_t Value) { 253 if (Rel == ELF::R_ARM_ABS32) { 254 if ((int64_t)Value < INT32_MIN || (int64_t)Value > UINT32_MAX) 255 HasError = true; 256 return static_cast<uint32_t>(Value); 257 } 258 HasError = true; 259 return 0; 260 } 261 visitLanai(uint32_t Rel,RelocationRef R,uint64_t Value)262 uint64_t visitLanai(uint32_t Rel, RelocationRef R, uint64_t Value) { 263 if (Rel == ELF::R_LANAI_32) 264 return (Value + getELFAddend(R)) & 0xFFFFFFFF; 265 HasError = true; 266 return 0; 267 } 268 visitMips32(uint32_t Rel,RelocationRef R,uint64_t Value)269 uint64_t visitMips32(uint32_t Rel, RelocationRef R, uint64_t Value) { 270 // FIXME: Take in account implicit addends to get correct results. 271 if (Rel == ELF::R_MIPS_32) 272 return Value & 0xFFFFFFFF; 273 if (Rel == ELF::R_MIPS_TLS_DTPREL32) 274 return Value & 0xFFFFFFFF; 275 HasError = true; 276 return 0; 277 } 278 visitSparc32(uint32_t Rel,RelocationRef R,uint64_t Value)279 uint64_t visitSparc32(uint32_t Rel, RelocationRef R, uint64_t Value) { 280 if (Rel == ELF::R_SPARC_32 || Rel == ELF::R_SPARC_UA32) 281 return Value + getELFAddend(R); 282 HasError = true; 283 return 0; 284 } 285 visitHexagon(uint32_t Rel,RelocationRef R,uint64_t Value)286 uint64_t visitHexagon(uint32_t Rel, RelocationRef R, uint64_t Value) { 287 if (Rel == ELF::R_HEX_32) 288 return Value + getELFAddend(R); 289 HasError = true; 290 return 0; 291 } 292 visitCOFF(uint32_t Rel,RelocationRef R,uint64_t Value)293 uint64_t visitCOFF(uint32_t Rel, RelocationRef R, uint64_t Value) { 294 switch (ObjToVisit.getArch()) { 295 case Triple::x86: 296 switch (Rel) { 297 case COFF::IMAGE_REL_I386_SECREL: 298 case COFF::IMAGE_REL_I386_DIR32: 299 return static_cast<uint32_t>(Value); 300 } 301 break; 302 case Triple::x86_64: 303 switch (Rel) { 304 case COFF::IMAGE_REL_AMD64_SECREL: 305 return static_cast<uint32_t>(Value); 306 case COFF::IMAGE_REL_AMD64_ADDR64: 307 return Value; 308 } 309 break; 310 default: 311 break; 312 } 313 HasError = true; 314 return 0; 315 } 316 visitMachO(uint32_t Rel,RelocationRef R,uint64_t Value)317 uint64_t visitMachO(uint32_t Rel, RelocationRef R, uint64_t Value) { 318 if (ObjToVisit.getArch() == Triple::x86_64 && 319 Rel == MachO::X86_64_RELOC_UNSIGNED) 320 return Value; 321 HasError = true; 322 return 0; 323 } 324 visitWasm(uint32_t Rel,RelocationRef R,uint64_t Value)325 uint64_t visitWasm(uint32_t Rel, RelocationRef R, uint64_t Value) { 326 if (ObjToVisit.getArch() == Triple::wasm32) { 327 switch (Rel) { 328 case wasm::R_WEBASSEMBLY_FUNCTION_INDEX_LEB: 329 case wasm::R_WEBASSEMBLY_TABLE_INDEX_SLEB: 330 case wasm::R_WEBASSEMBLY_TABLE_INDEX_I32: 331 case wasm::R_WEBASSEMBLY_MEMORY_ADDR_LEB: 332 case wasm::R_WEBASSEMBLY_MEMORY_ADDR_SLEB: 333 case wasm::R_WEBASSEMBLY_MEMORY_ADDR_I32: 334 case wasm::R_WEBASSEMBLY_TYPE_INDEX_LEB: 335 case wasm::R_WEBASSEMBLY_GLOBAL_INDEX_LEB: 336 case wasm::R_WEBASSEMBLY_FUNCTION_OFFSET_I32: 337 case wasm::R_WEBASSEMBLY_SECTION_OFFSET_I32: 338 case wasm::R_WEBASSEMBLY_EVENT_INDEX_LEB: 339 // For wasm section, its offset at 0 -- ignoring Value 340 return 0; 341 } 342 } 343 HasError = true; 344 return 0; 345 } 346 }; 347 348 } // end namespace object 349 } // end namespace llvm 350 351 #endif // LLVM_OBJECT_RELOCVISITOR_H 352