1 //===---- ELF_x86_64.cpp -JIT linker implementation for ELF/x86-64 ----===// 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 // ELF/x86-64 jit-link implementation. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #include "llvm/ExecutionEngine/JITLink/ELF_x86_64.h" 14 #include "JITLinkGeneric.h" 15 #include "llvm/ExecutionEngine/JITLink/JITLink.h" 16 #include "llvm/Object/ELFObjectFile.h" 17 18 #define DEBUG_TYPE "jitlink" 19 20 using namespace llvm; 21 using namespace llvm::jitlink; 22 23 static const char *CommonSectionName = "__common"; 24 25 namespace llvm { 26 namespace jitlink { 27 28 // This should become a template as the ELFFile is so a lot of this could become 29 // generic 30 class ELFLinkGraphBuilder_x86_64 { 31 32 private: 33 Section *CommonSection = nullptr; 34 // TODO hack to get this working 35 // Find a better way 36 using SymbolTable = object::ELFFile<object::ELF64LE>::Elf_Shdr; 37 // For now we just assume 38 std::map<int32_t, Symbol *> JITSymbolTable; 39 40 Section &getCommonSection() { 41 if (!CommonSection) { 42 auto Prot = static_cast<sys::Memory::ProtectionFlags>( 43 sys::Memory::MF_READ | sys::Memory::MF_WRITE); 44 CommonSection = &G->createSection(CommonSectionName, Prot); 45 } 46 return *CommonSection; 47 } 48 49 static Expected<ELF_x86_64_Edges::ELFX86RelocationKind> 50 getRelocationKind(const uint32_t Type) { 51 switch (Type) { 52 case ELF::R_X86_64_PC32: 53 return ELF_x86_64_Edges::ELFX86RelocationKind::PCRel32; 54 } 55 return make_error<JITLinkError>("Unsupported x86-64 relocation:" + 56 formatv("{0:d}", Type)); 57 } 58 59 std::unique_ptr<LinkGraph> G; 60 // This could be a template 61 const object::ELFFile<object::ELF64LE> &Obj; 62 object::ELFFile<object::ELF64LE>::Elf_Shdr_Range sections; 63 SymbolTable SymTab; 64 65 bool isRelocatable() { return Obj.getHeader()->e_type == llvm::ELF::ET_REL; } 66 67 support::endianness 68 getEndianness(const object::ELFFile<object::ELF64LE> &Obj) { 69 return Obj.isLE() ? support::little : support::big; 70 } 71 72 // This could also just become part of a template 73 unsigned getPointerSize(const object::ELFFile<object::ELF64LE> &Obj) { 74 return Obj.getHeader()->getFileClass() == ELF::ELFCLASS64 ? 8 : 4; 75 } 76 77 // We don't technically need this right now 78 // But for now going to keep it as it helps me to debug things 79 80 Error createNormalizedSymbols() { 81 LLVM_DEBUG(dbgs() << "Creating normalized symbols...\n"); 82 83 for (auto SecRef : sections) { 84 if (SecRef.sh_type != ELF::SHT_SYMTAB && 85 SecRef.sh_type != ELF::SHT_DYNSYM) 86 continue; 87 88 auto Symbols = Obj.symbols(&SecRef); 89 // TODO: Currently I use this function to test things 90 // I also want to leave it to see if its common between MACH and elf 91 // so for now I just want to continue even if there is an error 92 if (errorToBool(Symbols.takeError())) 93 continue; 94 95 auto StrTabSec = Obj.getSection(SecRef.sh_link); 96 if (!StrTabSec) 97 return StrTabSec.takeError(); 98 auto StringTable = Obj.getStringTable(*StrTabSec); 99 if (!StringTable) 100 return StringTable.takeError(); 101 102 for (auto SymRef : *Symbols) { 103 Optional<StringRef> Name; 104 uint64_t Size = 0; 105 106 // FIXME: Read size. 107 (void)Size; 108 109 if (auto NameOrErr = SymRef.getName(*StringTable)) 110 Name = *NameOrErr; 111 else 112 return NameOrErr.takeError(); 113 114 LLVM_DEBUG({ 115 dbgs() << " "; 116 if (!Name) 117 dbgs() << "<anonymous symbol>"; 118 else 119 dbgs() << *Name; 120 dbgs() << ": value = " << formatv("{0:x16}", SymRef.getValue()) 121 << ", type = " << formatv("{0:x2}", SymRef.getType()) 122 << ", binding = " << SymRef.getBinding() 123 << ", size =" << Size; 124 dbgs() << "\n"; 125 }); 126 } 127 } 128 return Error::success(); 129 } 130 131 Error createNormalizedSections() { 132 LLVM_DEBUG(dbgs() << "Creating normalized sections...\n"); 133 for (auto &SecRef : sections) { 134 auto Name = Obj.getSectionName(&SecRef); 135 if (!Name) 136 return Name.takeError(); 137 sys::Memory::ProtectionFlags Prot; 138 if (SecRef.sh_flags & ELF::SHF_EXECINSTR) { 139 Prot = static_cast<sys::Memory::ProtectionFlags>(sys::Memory::MF_READ | 140 sys::Memory::MF_EXEC); 141 } else { 142 Prot = static_cast<sys::Memory::ProtectionFlags>(sys::Memory::MF_READ | 143 sys::Memory::MF_WRITE); 144 } 145 uint64_t Address = SecRef.sh_addr; 146 uint64_t Size = SecRef.sh_size; 147 uint64_t Flags = SecRef.sh_flags; 148 uint64_t Alignment = SecRef.sh_addralign; 149 const char *Data = nullptr; 150 // TODO: figure out what it is that has 0 size no name and address 151 // 0000-0000 152 if (Size == 0) 153 continue; 154 155 // FIXME: Use flags. 156 (void)Flags; 157 158 LLVM_DEBUG({ 159 dbgs() << " " << *Name << ": " << formatv("{0:x16}", Address) << " -- " 160 << formatv("{0:x16}", Address + Size) << ", align: " << Alignment 161 << " Flags:" << Flags << "\n"; 162 }); 163 164 if (SecRef.sh_type != ELF::SHT_NOBITS) { 165 // .sections() already checks that the data is not beyond the end of 166 // file 167 auto contents = Obj.getSectionContentsAsArray<char>(&SecRef); 168 if (!contents) 169 return contents.takeError(); 170 171 Data = contents->data(); 172 // TODO protection flags. 173 // for now everything is 174 auto §ion = G->createSection(*Name, Prot); 175 // Do this here because we have it, but move it into graphify later 176 G->createContentBlock(section, StringRef(Data, Size), Address, 177 Alignment, 0); 178 if (SecRef.sh_type == ELF::SHT_SYMTAB) 179 // TODO: Dynamic? 180 SymTab = SecRef; 181 } 182 } 183 184 return Error::success(); 185 } 186 187 Error addRelocations() { 188 LLVM_DEBUG(dbgs() << "Adding relocations\n"); 189 // TODO a partern is forming of iterate some sections but only give me 190 // ones I am interested, i should abstract that concept some where 191 for (auto &SecRef : sections) { 192 if (SecRef.sh_type != ELF::SHT_RELA && SecRef.sh_type != ELF::SHT_REL) 193 continue; 194 // TODO can the elf obj file do this for me? 195 if (SecRef.sh_type == ELF::SHT_REL) 196 return make_error<llvm::StringError>("Shouldn't have REL in x64", 197 llvm::inconvertibleErrorCode()); 198 199 auto RelSectName = Obj.getSectionName(&SecRef); 200 if (!RelSectName) 201 return RelSectName.takeError(); 202 // Deal with .eh_frame later 203 if (*RelSectName == StringRef(".rela.eh_frame")) 204 continue; 205 206 auto UpdateSection = Obj.getSection(SecRef.sh_info); 207 if (!UpdateSection) 208 return UpdateSection.takeError(); 209 210 auto UpdateSectionName = Obj.getSectionName(*UpdateSection); 211 if (!UpdateSectionName) 212 return UpdateSectionName.takeError(); 213 214 auto JITSection = G->findSectionByName(*UpdateSectionName); 215 if (!JITSection) 216 return make_error<llvm::StringError>( 217 "Refencing a a section that wasn't added to graph" + 218 *UpdateSectionName, 219 llvm::inconvertibleErrorCode()); 220 221 auto Relocations = Obj.relas(&SecRef); 222 if (!Relocations) 223 return Relocations.takeError(); 224 225 for (const auto &Rela : *Relocations) { 226 auto Type = Rela.getType(false); 227 228 LLVM_DEBUG({ 229 dbgs() << "Relocation Type: " << Type << "\n" 230 << "Name: " << Obj.getRelocationTypeName(Type) << "\n"; 231 }); 232 233 auto Symbol = Obj.getRelocationSymbol(&Rela, &SymTab); 234 if (!Symbol) 235 return Symbol.takeError(); 236 237 auto BlockToFix = *(JITSection->blocks().begin()); 238 auto TargetSymbol = JITSymbolTable[(*Symbol)->st_shndx]; 239 uint64_t Addend = Rela.r_addend; 240 JITTargetAddress FixupAddress = 241 (*UpdateSection)->sh_addr + Rela.r_offset; 242 243 LLVM_DEBUG({ 244 dbgs() << "Processing relocation at " 245 << format("0x%016" PRIx64, FixupAddress) << "\n"; 246 }); 247 auto Kind = getRelocationKind(Type); 248 if (!Kind) 249 return Kind.takeError(); 250 251 LLVM_DEBUG({ 252 Edge GE(*Kind, FixupAddress - BlockToFix->getAddress(), *TargetSymbol, 253 Addend); 254 // TODO a mapping of KIND => type then call getRelocationTypeName4 255 printEdge(dbgs(), *BlockToFix, GE, StringRef("")); 256 dbgs() << "\n"; 257 }); 258 BlockToFix->addEdge(*Kind, FixupAddress - BlockToFix->getAddress(), 259 *TargetSymbol, Addend); 260 } 261 } 262 return Error::success(); 263 } 264 265 Error graphifyRegularSymbols() { 266 267 // TODO: ELF supports beyond SHN_LORESERVE, 268 // need to perf test how a vector vs map handles those cases 269 270 std::vector<std::vector<object::ELFFile<object::ELF64LE>::Elf_Shdr_Range *>> 271 SecIndexToSymbols; 272 273 LLVM_DEBUG(dbgs() << "Creating graph symbols...\n"); 274 275 for (auto SecRef : sections) { 276 277 if (SecRef.sh_type != ELF::SHT_SYMTAB && 278 SecRef.sh_type != ELF::SHT_DYNSYM) 279 continue; 280 auto Symbols = Obj.symbols(&SecRef); 281 if (!Symbols) 282 return Symbols.takeError(); 283 284 auto StrTabSec = Obj.getSection(SecRef.sh_link); 285 if (!StrTabSec) 286 return StrTabSec.takeError(); 287 auto StringTable = Obj.getStringTable(*StrTabSec); 288 if (!StringTable) 289 return StringTable.takeError(); 290 auto Name = Obj.getSectionName(&SecRef); 291 if (!Name) 292 return Name.takeError(); 293 auto Section = G->findSectionByName(*Name); 294 if (!Section) 295 return make_error<llvm::StringError>("Could not find a section", 296 llvm::inconvertibleErrorCode()); 297 // we only have one for now 298 auto blocks = Section->blocks(); 299 if (blocks.empty()) 300 return make_error<llvm::StringError>("Section has no block", 301 llvm::inconvertibleErrorCode()); 302 303 for (auto SymRef : *Symbols) { 304 auto Type = SymRef.getType(); 305 if (Type == ELF::STT_NOTYPE || Type == ELF::STT_FILE) 306 continue; 307 // these should do it for now 308 // if(Type != ELF::STT_NOTYPE && 309 // Type != ELF::STT_OBJECT && 310 // Type != ELF::STT_FUNC && 311 // Type != ELF::STT_SECTION && 312 // Type != ELF::STT_COMMON) { 313 // continue; 314 // } 315 std::pair<Linkage, Scope> bindings; 316 auto Name = SymRef.getName(*StringTable); 317 // I am not sure on If this is going to hold as an invariant. Revisit. 318 if (!Name) 319 return Name.takeError(); 320 // TODO: weak and hidden 321 if (SymRef.isExternal()) 322 bindings = {Linkage::Strong, Scope::Default}; 323 else 324 bindings = {Linkage::Strong, Scope::Local}; 325 326 if (SymRef.isDefined() && 327 (Type == ELF::STT_FUNC || Type == ELF::STT_OBJECT)) { 328 329 auto DefinedSection = Obj.getSection(SymRef.st_shndx); 330 if (!DefinedSection) 331 return DefinedSection.takeError(); 332 auto sectName = Obj.getSectionName(*DefinedSection); 333 if (!sectName) 334 return Name.takeError(); 335 336 auto JitSection = G->findSectionByName(*sectName); 337 if (!JitSection) 338 return make_error<llvm::StringError>( 339 "Could not find a section", llvm::inconvertibleErrorCode()); 340 auto bs = JitSection->blocks(); 341 if (bs.empty()) 342 return make_error<llvm::StringError>( 343 "Section has no block", llvm::inconvertibleErrorCode()); 344 345 auto B = *bs.begin(); 346 LLVM_DEBUG({ dbgs() << " " << *Name << ": "; }); 347 348 auto &S = G->addDefinedSymbol( 349 *B, SymRef.getValue(), *Name, SymRef.st_size, bindings.first, 350 bindings.second, SymRef.getType() == ELF::STT_FUNC, false); 351 JITSymbolTable[SymRef.st_shndx] = &S; 352 } 353 //TODO: The following has to be implmented. 354 // leaving commented out to save time for future patchs 355 /* 356 G->addAbsoluteSymbol(*Name, SymRef.getValue(), SymRef.st_size, 357 Linkage::Strong, Scope::Default, false); 358 359 if(SymRef.isCommon()) { 360 G->addCommonSymbol(*Name, Scope::Default, getCommonSection(), 0, 0, 361 SymRef.getValue(), false); 362 } 363 364 365 //G->addExternalSymbol(*Name, SymRef.st_size, Linkage::Strong); 366 */ 367 } 368 } 369 return Error::success(); 370 } 371 372 public: 373 ELFLinkGraphBuilder_x86_64(std::string filename, 374 const object::ELFFile<object::ELF64LE> &Obj) 375 : G(std::make_unique<LinkGraph>(filename, getPointerSize(Obj), 376 getEndianness(Obj))), 377 Obj(Obj) {} 378 379 Expected<std::unique_ptr<LinkGraph>> buildGraph() { 380 // Sanity check: we only operate on relocatable objects. 381 if (!isRelocatable()) 382 return make_error<JITLinkError>("Object is not a relocatable ELF"); 383 384 auto Secs = Obj.sections(); 385 386 if (!Secs) { 387 return Secs.takeError(); 388 } 389 sections = *Secs; 390 391 if (auto Err = createNormalizedSections()) 392 return std::move(Err); 393 394 if (auto Err = createNormalizedSymbols()) 395 return std::move(Err); 396 397 if (auto Err = graphifyRegularSymbols()) 398 return std::move(Err); 399 400 if (auto Err = addRelocations()) 401 return std::move(Err); 402 403 return std::move(G); 404 } 405 }; 406 407 class ELFJITLinker_x86_64 : public JITLinker<ELFJITLinker_x86_64> { 408 friend class JITLinker<ELFJITLinker_x86_64>; 409 410 public: 411 ELFJITLinker_x86_64(std::unique_ptr<JITLinkContext> Ctx, 412 PassConfiguration PassConfig) 413 : JITLinker(std::move(Ctx), std::move(PassConfig)) {} 414 415 private: 416 StringRef getEdgeKindName(Edge::Kind R) const override { return StringRef(); } 417 418 Expected<std::unique_ptr<LinkGraph>> 419 buildGraph(MemoryBufferRef ObjBuffer) override { 420 auto ELFObj = object::ObjectFile::createELFObjectFile(ObjBuffer); 421 if (!ELFObj) 422 return ELFObj.takeError(); 423 424 auto &ELFObjFile = cast<object::ELFObjectFile<object::ELF64LE>>(**ELFObj); 425 std::string fileName(ELFObj->get()->getFileName()); 426 return ELFLinkGraphBuilder_x86_64(std::move(fileName), 427 *ELFObjFile.getELFFile()) 428 .buildGraph(); 429 } 430 431 Error applyFixup(Block &B, const Edge &E, char *BlockWorkingMem) const { 432 using namespace ELF_x86_64_Edges; 433 char *FixupPtr = BlockWorkingMem + E.getOffset(); 434 JITTargetAddress FixupAddress = B.getAddress() + E.getOffset(); 435 switch (E.getKind()) { 436 437 case ELFX86RelocationKind::PCRel32: 438 int64_t Value = E.getTarget().getAddress() + E.getAddend() - FixupAddress; 439 // verify 440 *(support::little32_t *)FixupPtr = Value; 441 break; 442 } 443 return Error::success(); 444 } 445 }; 446 447 void jitLink_ELF_x86_64(std::unique_ptr<JITLinkContext> Ctx) { 448 PassConfiguration Config; 449 Triple TT("x86_64-linux"); 450 // Construct a JITLinker and run the link function. 451 // Add a mark-live pass. 452 if (auto MarkLive = Ctx->getMarkLivePass(TT)) 453 Config.PrePrunePasses.push_back(std::move(MarkLive)); 454 else 455 Config.PrePrunePasses.push_back(markAllSymbolsLive); 456 457 if (auto Err = Ctx->modifyPassConfig(TT, Config)) 458 return Ctx->notifyFailed(std::move(Err)); 459 460 ELFJITLinker_x86_64::link(std::move(Ctx), std::move(Config)); 461 } 462 } // end namespace jitlink 463 } // end namespace llvm 464