xref: /llvm-project/llvm/lib/ExecutionEngine/JITLink/ELF_i386.cpp (revision 2ccf7ed277df28651b94bbee9fccefdf22fb074f)
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