129fe204bSKshitij Jain //===----- ELF_i386.cpp - JIT linker implementation for ELF/i386 ----===// 229fe204bSKshitij Jain // 329fe204bSKshitij Jain // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 429fe204bSKshitij Jain // See https://llvm.org/LICENSE.txt for license information. 529fe204bSKshitij Jain // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 629fe204bSKshitij Jain // 729fe204bSKshitij Jain //===----------------------------------------------------------------------===// 829fe204bSKshitij Jain // 929fe204bSKshitij Jain // ELF/i386 jit-link implementation. 1029fe204bSKshitij Jain // 1129fe204bSKshitij Jain //===----------------------------------------------------------------------===// 1229fe204bSKshitij Jain 1329fe204bSKshitij Jain #include "llvm/ExecutionEngine/JITLink/ELF_i386.h" 14a3e975d4SKshitij Jain #include "DefineExternalSectionStartAndEndSymbols.h" 1529fe204bSKshitij Jain #include "ELFLinkGraphBuilder.h" 1629fe204bSKshitij Jain #include "JITLinkGeneric.h" 1729fe204bSKshitij Jain #include "llvm/BinaryFormat/ELF.h" 1829fe204bSKshitij Jain #include "llvm/ExecutionEngine/JITLink/i386.h" 1929fe204bSKshitij Jain #include "llvm/Object/ELFObjectFile.h" 2029fe204bSKshitij Jain 2129fe204bSKshitij Jain #define DEBUG_TYPE "jitlink" 2229fe204bSKshitij Jain 2329fe204bSKshitij Jain using namespace llvm; 2429fe204bSKshitij Jain using namespace llvm::jitlink; 2529fe204bSKshitij Jain 261b123d9fSKshitij Jain namespace { 271b123d9fSKshitij Jain constexpr StringRef ELFGOTSymbolName = "_GLOBAL_OFFSET_TABLE_"; 281b123d9fSKshitij Jain 291b123d9fSKshitij Jain Error buildTables_ELF_i386(LinkGraph &G) { 301b123d9fSKshitij Jain LLVM_DEBUG(dbgs() << "Visiting edges in graph:\n"); 311b123d9fSKshitij Jain 321b123d9fSKshitij Jain i386::GOTTableManager GOT; 33cd9fd425SKshitij Jain i386::PLTTableManager PLT(GOT); 34cd9fd425SKshitij Jain visitExistingEdges(G, GOT, PLT); 351b123d9fSKshitij Jain return Error::success(); 361b123d9fSKshitij Jain } 371b123d9fSKshitij Jain } // namespace 381b123d9fSKshitij Jain 392a3b257aSKshitij Jain namespace llvm::jitlink { 4029fe204bSKshitij Jain 4129fe204bSKshitij Jain class ELFJITLinker_i386 : public JITLinker<ELFJITLinker_i386> { 4229fe204bSKshitij Jain friend class JITLinker<ELFJITLinker_i386>; 4329fe204bSKshitij Jain 4429fe204bSKshitij Jain public: 4529fe204bSKshitij Jain ELFJITLinker_i386(std::unique_ptr<JITLinkContext> Ctx, 4629fe204bSKshitij Jain std::unique_ptr<LinkGraph> G, PassConfiguration PassConfig) 471b123d9fSKshitij Jain : JITLinker(std::move(Ctx), std::move(G), std::move(PassConfig)) { 481b123d9fSKshitij Jain getPassConfig().PostAllocationPasses.push_back( 491b123d9fSKshitij Jain [this](LinkGraph &G) { return getOrCreateGOTSymbol(G); }); 501b123d9fSKshitij Jain } 5129fe204bSKshitij Jain 5229fe204bSKshitij Jain private: 531b123d9fSKshitij Jain Symbol *GOTSymbol = nullptr; 541b123d9fSKshitij Jain 551b123d9fSKshitij Jain Error getOrCreateGOTSymbol(LinkGraph &G) { 561b123d9fSKshitij Jain auto DefineExternalGOTSymbolIfPresent = 571b123d9fSKshitij Jain createDefineExternalSectionStartAndEndSymbolsPass( 581b123d9fSKshitij Jain [&](LinkGraph &LG, Symbol &Sym) -> SectionRangeSymbolDesc { 59*2ccf7ed2SJared Wyles if (Sym.getName() != nullptr && 60*2ccf7ed2SJared Wyles *Sym.getName() == ELFGOTSymbolName) 611b123d9fSKshitij Jain if (auto *GOTSection = G.findSectionByName( 621b123d9fSKshitij Jain i386::GOTTableManager::getSectionName())) { 631b123d9fSKshitij Jain GOTSymbol = &Sym; 641b123d9fSKshitij Jain return {*GOTSection, true}; 651b123d9fSKshitij Jain } 661b123d9fSKshitij Jain return {}; 671b123d9fSKshitij Jain }); 681b123d9fSKshitij Jain 691b123d9fSKshitij Jain // Try to attach _GLOBAL_OFFSET_TABLE_ to the GOT if it's defined as an 701b123d9fSKshitij Jain // external. 711b123d9fSKshitij Jain if (auto Err = DefineExternalGOTSymbolIfPresent(G)) 721b123d9fSKshitij Jain return Err; 731b123d9fSKshitij Jain 741b123d9fSKshitij Jain // If we succeeded then we're done. 751b123d9fSKshitij Jain if (GOTSymbol) 761b123d9fSKshitij Jain return Error::success(); 771b123d9fSKshitij Jain 781b123d9fSKshitij Jain // Otherwise look for a GOT section: If it already has a start symbol we'll 791b123d9fSKshitij Jain // record it, otherwise we'll create our own. 801b123d9fSKshitij Jain // If there's a GOT section but we didn't find an external GOT symbol... 811b123d9fSKshitij Jain if (auto *GOTSection = 821b123d9fSKshitij Jain G.findSectionByName(i386::GOTTableManager::getSectionName())) { 831b123d9fSKshitij Jain 841b123d9fSKshitij Jain // Check for an existing defined symbol. 851b123d9fSKshitij Jain for (auto *Sym : GOTSection->symbols()) 86*2ccf7ed2SJared Wyles if (Sym->getName() != nullptr && *Sym->getName() == ELFGOTSymbolName) { 871b123d9fSKshitij Jain GOTSymbol = Sym; 881b123d9fSKshitij Jain return Error::success(); 891b123d9fSKshitij Jain } 901b123d9fSKshitij Jain 911b123d9fSKshitij Jain // If there's no defined symbol then create one. 921b123d9fSKshitij Jain SectionRange SR(*GOTSection); 931b123d9fSKshitij Jain 941b123d9fSKshitij Jain if (SR.empty()) { 951b123d9fSKshitij Jain GOTSymbol = 961b123d9fSKshitij Jain &G.addAbsoluteSymbol(ELFGOTSymbolName, orc::ExecutorAddr(), 0, 971b123d9fSKshitij Jain Linkage::Strong, Scope::Local, true); 981b123d9fSKshitij Jain } else { 991b123d9fSKshitij Jain GOTSymbol = 1001b123d9fSKshitij Jain &G.addDefinedSymbol(*SR.getFirstBlock(), 0, ELFGOTSymbolName, 0, 1011b123d9fSKshitij Jain Linkage::Strong, Scope::Local, false, true); 1021b123d9fSKshitij Jain } 1031b123d9fSKshitij Jain } 1041b123d9fSKshitij Jain 1051b123d9fSKshitij Jain return Error::success(); 1061b123d9fSKshitij Jain } 1071b123d9fSKshitij Jain 10829fe204bSKshitij Jain Error applyFixup(LinkGraph &G, Block &B, const Edge &E) const { 1091b123d9fSKshitij Jain return i386::applyFixup(G, B, E, GOTSymbol); 11029fe204bSKshitij Jain } 11129fe204bSKshitij Jain }; 11229fe204bSKshitij Jain 11329fe204bSKshitij Jain template <typename ELFT> 11429fe204bSKshitij Jain class ELFLinkGraphBuilder_i386 : public ELFLinkGraphBuilder<ELFT> { 11529fe204bSKshitij Jain private: 11629fe204bSKshitij Jain static Expected<i386::EdgeKind_i386> getRelocationKind(const uint32_t Type) { 11729fe204bSKshitij Jain using namespace i386; 11829fe204bSKshitij Jain switch (Type) { 11929fe204bSKshitij Jain case ELF::R_386_NONE: 12029fe204bSKshitij Jain return EdgeKind_i386::None; 1212a3b257aSKshitij Jain case ELF::R_386_32: 1222a3b257aSKshitij Jain return EdgeKind_i386::Pointer32; 1232a3b257aSKshitij Jain case ELF::R_386_PC32: 1242a3b257aSKshitij Jain return EdgeKind_i386::PCRel32; 1252a3b257aSKshitij Jain case ELF::R_386_16: 1262a3b257aSKshitij Jain return EdgeKind_i386::Pointer16; 1272a3b257aSKshitij Jain case ELF::R_386_PC16: 1282a3b257aSKshitij Jain return EdgeKind_i386::PCRel16; 1291b123d9fSKshitij Jain case ELF::R_386_GOT32: 1301b123d9fSKshitij Jain return EdgeKind_i386::RequestGOTAndTransformToDelta32FromGOT; 1312a3b257aSKshitij Jain case ELF::R_386_GOTPC: 1321b123d9fSKshitij Jain return EdgeKind_i386::Delta32; 1331b123d9fSKshitij Jain case ELF::R_386_GOTOFF: 1342a3b257aSKshitij Jain return EdgeKind_i386::Delta32FromGOT; 135cd9fd425SKshitij Jain case ELF::R_386_PLT32: 136cd9fd425SKshitij Jain return EdgeKind_i386::BranchPCRel32; 13729fe204bSKshitij Jain } 13829fe204bSKshitij Jain 13929fe204bSKshitij Jain return make_error<JITLinkError>("Unsupported i386 relocation:" + 14029fe204bSKshitij Jain formatv("{0:d}", Type)); 14129fe204bSKshitij Jain } 14229fe204bSKshitij Jain 14329fe204bSKshitij Jain Error addRelocations() override { 14429fe204bSKshitij Jain LLVM_DEBUG(dbgs() << "Adding relocations\n"); 1452a3b257aSKshitij Jain using Base = ELFLinkGraphBuilder<ELFT>; 1462a3b257aSKshitij Jain using Self = ELFLinkGraphBuilder_i386; 1472a3b257aSKshitij Jain 1482a3b257aSKshitij Jain for (const auto &RelSect : Base::Sections) { 1492a3b257aSKshitij Jain // Validate the section to read relocation entries from. 1502a3b257aSKshitij Jain if (RelSect.sh_type == ELF::SHT_RELA) 1512a3b257aSKshitij Jain return make_error<StringError>( 1522a3b257aSKshitij Jain "No SHT_RELA in valid i386 ELF object files", 1532a3b257aSKshitij Jain inconvertibleErrorCode()); 1542a3b257aSKshitij Jain 1552a3b257aSKshitij Jain if (Error Err = Base::forEachRelRelocation(RelSect, this, 1562a3b257aSKshitij Jain &Self::addSingleRelocation)) 1572a3b257aSKshitij Jain return Err; 1582a3b257aSKshitij Jain } 1592a3b257aSKshitij Jain 1602a3b257aSKshitij Jain return Error::success(); 1612a3b257aSKshitij Jain } 1622a3b257aSKshitij Jain 1632a3b257aSKshitij Jain Error addSingleRelocation(const typename ELFT::Rel &Rel, 1642a3b257aSKshitij Jain const typename ELFT::Shdr &FixupSection, 1652a3b257aSKshitij Jain Block &BlockToFix) { 1662a3b257aSKshitij Jain using Base = ELFLinkGraphBuilder<ELFT>; 1672a3b257aSKshitij Jain 1682a3b257aSKshitij Jain uint32_t SymbolIndex = Rel.getSymbol(false); 1692a3b257aSKshitij Jain auto ObjSymbol = Base::Obj.getRelocationSymbol(Rel, Base::SymTabSec); 1702a3b257aSKshitij Jain if (!ObjSymbol) 1712a3b257aSKshitij Jain return ObjSymbol.takeError(); 1722a3b257aSKshitij Jain 1732a3b257aSKshitij Jain Symbol *GraphSymbol = Base::getGraphSymbol(SymbolIndex); 1742a3b257aSKshitij Jain if (!GraphSymbol) 1752a3b257aSKshitij Jain return make_error<StringError>( 1762a3b257aSKshitij Jain formatv("Could not find symbol at given index, did you add it to " 1772a3b257aSKshitij Jain "JITSymbolTable? index: {0}, shndx: {1} Size of table: {2}", 1782a3b257aSKshitij Jain SymbolIndex, (*ObjSymbol)->st_shndx, 1792a3b257aSKshitij Jain Base::GraphSymbols.size()), 1802a3b257aSKshitij Jain inconvertibleErrorCode()); 1812a3b257aSKshitij Jain 1822a3b257aSKshitij Jain Expected<i386::EdgeKind_i386> Kind = getRelocationKind(Rel.getType(false)); 1832a3b257aSKshitij Jain if (!Kind) 1842a3b257aSKshitij Jain return Kind.takeError(); 1852a3b257aSKshitij Jain 186a3e975d4SKshitij Jain auto FixupAddress = orc::ExecutorAddr(FixupSection.sh_addr) + Rel.r_offset; 1872a3b257aSKshitij Jain int64_t Addend = 0; 1882a3b257aSKshitij Jain 189a3e975d4SKshitij Jain switch (*Kind) { 1905716f836SJameson Nash case i386::EdgeKind_i386::None: 1915716f836SJameson Nash break; 1925716f836SJameson Nash case i386::EdgeKind_i386::Pointer32: 1935716f836SJameson Nash case i386::EdgeKind_i386::PCRel32: 1945716f836SJameson Nash case i386::EdgeKind_i386::RequestGOTAndTransformToDelta32FromGOT: 1955716f836SJameson Nash case i386::EdgeKind_i386::Delta32: 1965716f836SJameson Nash case i386::EdgeKind_i386::Delta32FromGOT: 1975716f836SJameson Nash case i386::EdgeKind_i386::BranchPCRel32: 1985716f836SJameson Nash case i386::EdgeKind_i386::BranchPCRel32ToPtrJumpStub: 1995716f836SJameson Nash case i386::EdgeKind_i386::BranchPCRel32ToPtrJumpStubBypassable: { 200a3e975d4SKshitij Jain const char *FixupContent = BlockToFix.getContent().data() + 201a3e975d4SKshitij Jain (FixupAddress - BlockToFix.getAddress()); 2025716f836SJameson Nash Addend = *(const support::little32_t *)FixupContent; 203a3e975d4SKshitij Jain break; 204a3e975d4SKshitij Jain } 2055716f836SJameson Nash case i386::EdgeKind_i386::Pointer16: 2065716f836SJameson Nash case i386::EdgeKind_i386::PCRel16: { 2075716f836SJameson Nash const char *FixupContent = BlockToFix.getContent().data() + 2085716f836SJameson Nash (FixupAddress - BlockToFix.getAddress()); 2095716f836SJameson Nash Addend = *(const support::little16_t *)FixupContent; 21078e3168cSNAKAMURA Takumi break; 211a3e975d4SKshitij Jain } 2125716f836SJameson Nash } 213a3e975d4SKshitij Jain 2142a3b257aSKshitij Jain Edge::OffsetT Offset = FixupAddress - BlockToFix.getAddress(); 2152a3b257aSKshitij Jain Edge GE(*Kind, Offset, *GraphSymbol, Addend); 2162a3b257aSKshitij Jain LLVM_DEBUG({ 2172a3b257aSKshitij Jain dbgs() << " "; 2182a3b257aSKshitij Jain printEdge(dbgs(), BlockToFix, GE, i386::getEdgeKindName(*Kind)); 2192a3b257aSKshitij Jain dbgs() << "\n"; 2202a3b257aSKshitij Jain }); 2212a3b257aSKshitij Jain 2222a3b257aSKshitij Jain BlockToFix.addEdge(std::move(GE)); 22329fe204bSKshitij Jain return Error::success(); 22429fe204bSKshitij Jain } 22529fe204bSKshitij Jain 22629fe204bSKshitij Jain public: 22729fe204bSKshitij Jain ELFLinkGraphBuilder_i386(StringRef FileName, const object::ELFFile<ELFT> &Obj, 228*2ccf7ed2SJared Wyles std::shared_ptr<orc::SymbolStringPool> SSP, 22952b88457SJob Noorman Triple TT, SubtargetFeatures Features) 230*2ccf7ed2SJared Wyles : ELFLinkGraphBuilder<ELFT>(Obj, std::move(SSP), std::move(TT), 231*2ccf7ed2SJared Wyles std::move(Features), FileName, 232*2ccf7ed2SJared Wyles i386::getEdgeKindName) {} 23329fe204bSKshitij Jain }; 23429fe204bSKshitij Jain 23529fe204bSKshitij Jain Expected<std::unique_ptr<LinkGraph>> 236*2ccf7ed2SJared Wyles createLinkGraphFromELFObject_i386(MemoryBufferRef ObjectBuffer, 237*2ccf7ed2SJared Wyles std::shared_ptr<orc::SymbolStringPool> SSP) { 23829fe204bSKshitij Jain LLVM_DEBUG({ 23929fe204bSKshitij Jain dbgs() << "Building jitlink graph for new input " 24029fe204bSKshitij Jain << ObjectBuffer.getBufferIdentifier() << "...\n"; 24129fe204bSKshitij Jain }); 24229fe204bSKshitij Jain 24329fe204bSKshitij Jain auto ELFObj = object::ObjectFile::createELFObjectFile(ObjectBuffer); 24429fe204bSKshitij Jain if (!ELFObj) 24529fe204bSKshitij Jain return ELFObj.takeError(); 24629fe204bSKshitij Jain 247348d0a6bSJob Noorman auto Features = (*ELFObj)->getFeatures(); 248348d0a6bSJob Noorman if (!Features) 249348d0a6bSJob Noorman return Features.takeError(); 250348d0a6bSJob Noorman 25129fe204bSKshitij Jain assert((*ELFObj)->getArch() == Triple::x86 && 25229fe204bSKshitij Jain "Only i386 (little endian) is supported for now"); 25329fe204bSKshitij Jain 25429fe204bSKshitij Jain auto &ELFObjFile = cast<object::ELFObjectFile<object::ELF32LE>>(**ELFObj); 255*2ccf7ed2SJared Wyles 256348d0a6bSJob Noorman return ELFLinkGraphBuilder_i386<object::ELF32LE>( 257*2ccf7ed2SJared Wyles (*ELFObj)->getFileName(), ELFObjFile.getELFFile(), std::move(SSP), 25852b88457SJob Noorman (*ELFObj)->makeTriple(), std::move(*Features)) 25929fe204bSKshitij Jain .buildGraph(); 26029fe204bSKshitij Jain } 26129fe204bSKshitij Jain 26229fe204bSKshitij Jain void link_ELF_i386(std::unique_ptr<LinkGraph> G, 26329fe204bSKshitij Jain std::unique_ptr<JITLinkContext> Ctx) { 26429fe204bSKshitij Jain PassConfiguration Config; 26529fe204bSKshitij Jain const Triple &TT = G->getTargetTriple(); 26629fe204bSKshitij Jain if (Ctx->shouldAddDefaultTargetPasses(TT)) { 26729fe204bSKshitij Jain if (auto MarkLive = Ctx->getMarkLivePass(TT)) 26829fe204bSKshitij Jain Config.PrePrunePasses.push_back(std::move(MarkLive)); 26929fe204bSKshitij Jain else 27029fe204bSKshitij Jain Config.PrePrunePasses.push_back(markAllSymbolsLive); 2711b123d9fSKshitij Jain 272cd9fd425SKshitij Jain // Add an in-place GOT and PLT build pass. 2731b123d9fSKshitij Jain Config.PostPrunePasses.push_back(buildTables_ELF_i386); 274cd9fd425SKshitij Jain 275cd9fd425SKshitij Jain // Add GOT/Stubs optimizer pass. 276cd9fd425SKshitij Jain Config.PreFixupPasses.push_back(i386::optimizeGOTAndStubAccesses); 27729fe204bSKshitij Jain } 27829fe204bSKshitij Jain if (auto Err = Ctx->modifyPassConfig(*G, Config)) 27929fe204bSKshitij Jain return Ctx->notifyFailed(std::move(Err)); 28029fe204bSKshitij Jain 28129fe204bSKshitij Jain ELFJITLinker_i386::link(std::move(Ctx), std::move(G), std::move(Config)); 28229fe204bSKshitij Jain } 28329fe204bSKshitij Jain 2842a3b257aSKshitij Jain } // namespace llvm::jitlink 285