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 // This should become a template as the ELFFile is so a lot of this could become 28 // generic 29 class ELFLinkGraphBuilder_x86_64 { 30 31 private: 32 Section *CommonSection = nullptr; 33 Section &getCommonSection() { 34 if (!CommonSection) { 35 auto Prot = static_cast<sys::Memory::ProtectionFlags>( 36 sys::Memory::MF_READ | sys::Memory::MF_WRITE); 37 CommonSection = &G->createSection(CommonSectionName, Prot); 38 } 39 return *CommonSection; 40 } 41 42 std::unique_ptr<LinkGraph> G; 43 // This could be a template 44 const object::ELFFile<object::ELF64LE> &Obj; 45 object::ELFFile<object::ELF64LE>::Elf_Shdr_Range sections; 46 47 bool isRelocatable() { return Obj.getHeader()->e_type == llvm::ELF::ET_REL; } 48 49 support::endianness 50 getEndianness(const object::ELFFile<object::ELF64LE> &Obj) { 51 return Obj.isLE() ? support::little : support::big; 52 } 53 54 // This could also just become part of a template 55 unsigned getPointerSize(const object::ELFFile<object::ELF64LE> &Obj) { 56 return Obj.getHeader()->getFileClass() == ELF::ELFCLASS64 ? 8 : 4; 57 } 58 59 // We don't technically need this right now 60 // But for now going to keep it as it helps me to debug things 61 62 Error createNormalizedSymbols() { 63 LLVM_DEBUG(dbgs() << "Creating normalized symbols...\n"); 64 65 for (auto SecRef : sections) { 66 if (SecRef.sh_type != ELF::SHT_SYMTAB && 67 SecRef.sh_type != ELF::SHT_DYNSYM) 68 continue; 69 70 auto Symbols = Obj.symbols(&SecRef); 71 // TODO: Currently I use this function to test things 72 // I also want to leave it to see if its common between MACH and elf 73 // so for now I just want to continue even if there is an error 74 if (errorToBool(Symbols.takeError())) 75 continue; 76 77 auto StrTabSec = Obj.getSection(SecRef.sh_link); 78 if (!StrTabSec) 79 return StrTabSec.takeError(); 80 auto StringTable = Obj.getStringTable(*StrTabSec); 81 if (!StringTable) 82 return StringTable.takeError(); 83 84 for (auto SymRef : *Symbols) { 85 Optional<StringRef> Name; 86 unsigned char Binding; 87 uint64_t Value; 88 uint64_t Size = 0; 89 90 // FIXME: Read size. 91 (void)Size; 92 93 if (auto NameOrErr = SymRef.getName(*StringTable)) { 94 Name = *NameOrErr; 95 } else { 96 return NameOrErr.takeError(); 97 } 98 Binding = SymRef.getBinding(); 99 Value = SymRef.getValue(); 100 LLVM_DEBUG({ 101 dbgs() << " "; 102 if (!Name) 103 dbgs() << "<anonymous symbol>"; 104 else 105 dbgs() << *Name; 106 dbgs() << ": value = " << formatv("{0:x16}", Value) 107 << ", type = " << formatv("{0:x2}", SymRef.getType()) 108 << ", binding = " << Binding 109 << ", size =" << Size; 110 dbgs() << "\n"; 111 }); 112 } 113 } 114 return Error::success(); 115 } 116 117 Error createNormalizedSections() { 118 LLVM_DEBUG(dbgs() << "Creating normalized sections...\n"); 119 for (auto &SecRef : sections) { 120 auto Name = Obj.getSectionName(&SecRef); 121 if (!Name) 122 return Name.takeError(); 123 sys::Memory::ProtectionFlags Prot; 124 if (SecRef.sh_flags & ELF::SHF_EXECINSTR) { 125 Prot = static_cast<sys::Memory::ProtectionFlags>(sys::Memory::MF_READ | 126 sys::Memory::MF_EXEC); 127 } else { 128 Prot = static_cast<sys::Memory::ProtectionFlags>(sys::Memory::MF_READ | 129 sys::Memory::MF_WRITE); 130 } 131 uint64_t Address = SecRef.sh_addr; 132 uint64_t Size = SecRef.sh_size; 133 uint64_t Flags = SecRef.sh_flags; 134 uint64_t Alignment = SecRef.sh_addralign; 135 const char *Data = nullptr; 136 // TODO: figure out what it is that has 0 size no name and address 137 // 0000-0000 138 if (Size == 0) 139 continue; 140 141 // FIXME: Use flags. 142 (void)Flags; 143 144 LLVM_DEBUG({ 145 dbgs() << " " << *Name << ": " << formatv("{0:x16}", Address) << " -- " 146 << formatv("{0:x16}", Address + Size) << ", align: " << Alignment 147 << " Flags:" << Flags << "\n"; 148 }); 149 150 if (SecRef.sh_type != ELF::SHT_NOBITS) { 151 // .sections() already checks that the data is not beyond the end of 152 // file 153 auto contents = Obj.getSectionContentsAsArray<char>(&SecRef); 154 if (!contents) 155 return contents.takeError(); 156 157 Data = contents->data(); 158 // TODO protection flags. 159 // for now everything is 160 auto §ion = G->createSection(*Name, Prot); 161 // Do this here because we have it, but move it into graphify later 162 G->createContentBlock(section, StringRef(Data, Size), Address, 163 Alignment, 0); 164 } 165 } 166 167 return Error::success(); 168 } 169 170 Error graphifyRegularSymbols() { 171 172 // TODO: ELF supports beyond SHN_LORESERVE, 173 // need to perf test how a vector vs map handles those cases 174 175 std::vector<std::vector<object::ELFFile<object::ELF64LE>::Elf_Shdr_Range *>> 176 SecIndexToSymbols; 177 178 LLVM_DEBUG(dbgs() << "Creating graph symbols...\n"); 179 180 for (auto SecRef : sections) { 181 182 if (SecRef.sh_type != ELF::SHT_SYMTAB && 183 SecRef.sh_type != ELF::SHT_DYNSYM) 184 continue; 185 auto Symbols = Obj.symbols(&SecRef); 186 if (!Symbols) 187 return Symbols.takeError(); 188 189 auto StrTabSec = Obj.getSection(SecRef.sh_link); 190 if (!StrTabSec) 191 return StrTabSec.takeError(); 192 auto StringTable = Obj.getStringTable(*StrTabSec); 193 if (!StringTable) 194 return StringTable.takeError(); 195 auto Name = Obj.getSectionName(&SecRef); 196 if (!Name) 197 return Name.takeError(); 198 auto Section = G->findSectionByName(*Name); 199 if (!Section) 200 return make_error<llvm::StringError>("Could not find a section", 201 llvm::inconvertibleErrorCode()); 202 // we only have one for now 203 auto blocks = Section->blocks(); 204 if (blocks.empty()) 205 return make_error<llvm::StringError>("Section has no block", 206 llvm::inconvertibleErrorCode()); 207 208 for (auto SymRef : *Symbols) { 209 auto Type = SymRef.getType(); 210 if (Type == ELF::STT_NOTYPE || Type == ELF::STT_FILE) 211 continue; 212 // these should do it for now 213 // if(Type != ELF::STT_NOTYPE && 214 // Type != ELF::STT_OBJECT && 215 // Type != ELF::STT_FUNC && 216 // Type != ELF::STT_SECTION && 217 // Type != ELF::STT_COMMON) { 218 // continue; 219 // } 220 std::pair<Linkage, Scope> bindings; 221 auto Name = SymRef.getName(*StringTable); 222 // I am not sure on If this is going to hold as an invariant. Revisit. 223 if (!Name) 224 return Name.takeError(); 225 // TODO: weak and hidden 226 if (SymRef.isExternal()) { 227 bindings = {Linkage::Strong, Scope::Default}; 228 } else { 229 bindings = {Linkage::Strong, Scope::Local}; 230 } 231 232 if (SymRef.isDefined() && 233 (Type == ELF::STT_FUNC || Type == ELF::STT_OBJECT)) { 234 235 auto DefinedSection = Obj.getSection(SymRef.st_shndx); 236 if (!DefinedSection) 237 return DefinedSection.takeError(); 238 auto sectName = Obj.getSectionName(*DefinedSection); 239 if (!sectName) 240 return Name.takeError(); 241 242 auto JitSection = G->findSectionByName(*sectName); 243 if (!JitSection) 244 return make_error<llvm::StringError>( 245 "Could not find a section", llvm::inconvertibleErrorCode()); 246 auto bs = JitSection->blocks(); 247 if (bs.empty()) 248 return make_error<llvm::StringError>( 249 "Section has no block", llvm::inconvertibleErrorCode()); 250 251 auto B = *bs.begin(); 252 LLVM_DEBUG({ dbgs() << " " << *Name << ": "; }); 253 254 G->addDefinedSymbol(*B, SymRef.getValue(), *Name, SymRef.st_size, 255 bindings.first, bindings.second, 256 SymRef.getType() == ELF::STT_FUNC, false); 257 } 258 //TODO: The following has to be implmented. 259 // leaving commented out to save time for future patchs 260 /* 261 G->addAbsoluteSymbol(*Name, SymRef.getValue(), SymRef.st_size, 262 Linkage::Strong, Scope::Default, false); 263 264 if(SymRef.isCommon()) { 265 G->addCommonSymbol(*Name, Scope::Default, getCommonSection(), 0, 0, 266 SymRef.getValue(), false); 267 } 268 269 270 //G->addExternalSymbol(*Name, SymRef.st_size, Linkage::Strong); 271 */ 272 } 273 } 274 return Error::success(); 275 } 276 277 public: 278 ELFLinkGraphBuilder_x86_64(std::string filename, 279 const object::ELFFile<object::ELF64LE> &Obj) 280 : G(std::make_unique<LinkGraph>(filename, getPointerSize(Obj), 281 getEndianness(Obj))), 282 Obj(Obj) {} 283 284 Expected<std::unique_ptr<LinkGraph>> buildGraph() { 285 // Sanity check: we only operate on relocatable objects. 286 if (!isRelocatable()) 287 return make_error<JITLinkError>("Object is not a relocatable ELF"); 288 289 auto Secs = Obj.sections(); 290 291 if (!Secs) { 292 return Secs.takeError(); 293 } 294 sections = *Secs; 295 296 if (auto Err = createNormalizedSections()) 297 return std::move(Err); 298 299 if (auto Err = createNormalizedSymbols()) 300 return std::move(Err); 301 302 if (auto Err = graphifyRegularSymbols()) 303 return std::move(Err); 304 305 return std::move(G); 306 } 307 }; 308 309 class ELFJITLinker_x86_64 : public JITLinker<ELFJITLinker_x86_64> { 310 friend class JITLinker<ELFJITLinker_x86_64>; 311 312 public: 313 ELFJITLinker_x86_64(std::unique_ptr<JITLinkContext> Ctx, 314 PassConfiguration PassConfig) 315 : JITLinker(std::move(Ctx), std::move(PassConfig)) {} 316 317 private: 318 StringRef getEdgeKindName(Edge::Kind R) const override { 319 return getELFX86RelocationKindName(R); 320 } 321 322 Expected<std::unique_ptr<LinkGraph>> 323 buildGraph(MemoryBufferRef ObjBuffer) override { 324 auto ELFObj = object::ObjectFile::createELFObjectFile(ObjBuffer); 325 if (!ELFObj) 326 return ELFObj.takeError(); 327 328 auto &ELFObjFile = cast<object::ELFObjectFile<object::ELF64LE>>(**ELFObj); 329 std::string fileName(ELFObj->get()->getFileName()); 330 return ELFLinkGraphBuilder_x86_64(std::move(fileName), 331 *ELFObjFile.getELFFile()) 332 .buildGraph(); 333 } 334 335 Error applyFixup(Block &B, const Edge &E, char *BlockWorkingMem) const { 336 //TODO: add relocation handling 337 return Error::success(); 338 } 339 }; 340 341 void jitLink_ELF_x86_64(std::unique_ptr<JITLinkContext> Ctx) { 342 PassConfiguration Config; 343 Triple TT("x86_64-linux"); 344 // Construct a JITLinker and run the link function. 345 // Add a mark-live pass. 346 if (auto MarkLive = Ctx->getMarkLivePass(TT)) 347 Config.PrePrunePasses.push_back(std::move(MarkLive)); 348 else 349 Config.PrePrunePasses.push_back(markAllSymbolsLive); 350 351 ELFJITLinker_x86_64::link(std::move(Ctx), std::move(Config)); 352 } 353 354 StringRef getELFX86RelocationKindName(Edge::Kind R) { 355 // case R_AMD64_NONE: 356 // return "None"; 357 // case R_AMD64_PC32: 358 // case R_AMD64_GOT32: 359 // case R_AMD64_PLT32, 360 // R_AMD64_COPY, 361 // R_AMD64_GLOB_DAT, 362 // R_AMD64_JUMP_SLOT, 363 // R_AMD64_RELATIVE, 364 // R_AMD64_GOTPCREL, 365 // R_AMD64_32, 366 // R_AMD64_32S, 367 // R_AMD64_16, 368 // R_AMD64_PC16, 369 // R_AMD64_8, 370 // R_AMD64_PC8, 371 // R_AMD64_PC64, 372 // R_AMD64_GOTOFF64, 373 // R_AMD64_GOTPC32, 374 // R_AMD64_SIZE32, 375 // R_AMD64_SIZE64 376 return getGenericEdgeKindName(static_cast<Edge::Kind>(R)); 377 } 378 } // end namespace jitlink 379 } // end namespace llvm 380