291 lines · cpp
1//===--------- ELF_x86.cpp - JIT linker implementation for ELF/x86 --------===//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-exception6//7//===----------------------------------------------------------------------===//8//9// ELF/x86 jit-link implementation.10//11//===----------------------------------------------------------------------===//12 13#include "llvm/ExecutionEngine/JITLink/ELF_x86.h"14#include "DefineExternalSectionStartAndEndSymbols.h"15#include "ELFLinkGraphBuilder.h"16#include "JITLinkGeneric.h"17#include "llvm/BinaryFormat/ELF.h"18#include "llvm/ExecutionEngine/JITLink/x86.h"19#include "llvm/Object/ELFObjectFile.h"20 21#define DEBUG_TYPE "jitlink"22 23using namespace llvm;24using namespace llvm::jitlink;25 26namespace {27constexpr StringRef ELFGOTSymbolName = "_GLOBAL_OFFSET_TABLE_";28 29Error buildTables_ELF_x86(LinkGraph &G) {30 LLVM_DEBUG(dbgs() << "Visiting edges in graph:\n");31 32 x86::GOTTableManager GOT;33 x86::PLTTableManager PLT(GOT);34 visitExistingEdges(G, GOT, PLT);35 return Error::success();36}37} // namespace38 39namespace llvm::jitlink {40 41class ELFJITLinker_x86 : public JITLinker<ELFJITLinker_x86> {42 friend class JITLinker<ELFJITLinker_x86>;43 44public:45 ELFJITLinker_x86(std::unique_ptr<JITLinkContext> Ctx,46 std::unique_ptr<LinkGraph> G, PassConfiguration PassConfig)47 : JITLinker(std::move(Ctx), std::move(G), std::move(PassConfig)) {48 getPassConfig().PostAllocationPasses.push_back(49 [this](LinkGraph &G) { return getOrCreateGOTSymbol(G); });50 }51 52private:53 Symbol *GOTSymbol = nullptr;54 55 Error getOrCreateGOTSymbol(LinkGraph &G) {56 auto DefineExternalGOTSymbolIfPresent =57 createDefineExternalSectionStartAndEndSymbolsPass(58 [&](LinkGraph &LG, Symbol &Sym) -> SectionRangeSymbolDesc {59 if (Sym.getName() != nullptr &&60 *Sym.getName() == ELFGOTSymbolName)61 if (auto *GOTSection = G.findSectionByName(62 x86::GOTTableManager::getSectionName())) {63 GOTSymbol = &Sym;64 return {*GOTSection, true};65 }66 return {};67 });68 69 // Try to attach _GLOBAL_OFFSET_TABLE_ to the GOT if it's defined as an70 // external.71 if (auto Err = DefineExternalGOTSymbolIfPresent(G))72 return Err;73 74 // If we succeeded then we're done.75 if (GOTSymbol)76 return Error::success();77 78 // Otherwise look for a GOT section: If it already has a start symbol we'll79 // record it, otherwise we'll create our own.80 // If there's a GOT section but we didn't find an external GOT symbol...81 if (auto *GOTSection =82 G.findSectionByName(x86::GOTTableManager::getSectionName())) {83 84 // Check for an existing defined symbol.85 for (auto *Sym : GOTSection->symbols())86 if (Sym->getName() != nullptr && *Sym->getName() == ELFGOTSymbolName) {87 GOTSymbol = Sym;88 return Error::success();89 }90 91 // If there's no defined symbol then create one.92 SectionRange SR(*GOTSection);93 94 if (SR.empty()) {95 GOTSymbol =96 &G.addAbsoluteSymbol(ELFGOTSymbolName, orc::ExecutorAddr(), 0,97 Linkage::Strong, Scope::Local, true);98 } else {99 GOTSymbol =100 &G.addDefinedSymbol(*SR.getFirstBlock(), 0, ELFGOTSymbolName, 0,101 Linkage::Strong, Scope::Local, false, true);102 }103 }104 105 return Error::success();106 }107 108 Error applyFixup(LinkGraph &G, Block &B, const Edge &E) const {109 return x86::applyFixup(G, B, E, GOTSymbol);110 }111};112 113class ELFLinkGraphBuilder_x86 : public ELFLinkGraphBuilder<object::ELF32LE> {114private:115 using ELFT = object::ELF32LE;116 117 Expected<x86::EdgeKind_x86> getRelocationKind(const uint32_t Type) {118 switch (Type) {119 case ELF::R_386_32:120 return x86::Pointer32;121 case ELF::R_386_PC32:122 return x86::PCRel32;123 case ELF::R_386_16:124 return x86::Pointer16;125 case ELF::R_386_PC16:126 return x86::PCRel16;127 case ELF::R_386_GOT32:128 return x86::RequestGOTAndTransformToDelta32FromGOT;129 case ELF::R_386_GOT32X:130 // TODO: Add a relaxable edge kind and update relaxation optimization.131 return x86::RequestGOTAndTransformToDelta32FromGOT;132 case ELF::R_386_GOTPC:133 return x86::Delta32;134 case ELF::R_386_GOTOFF:135 return x86::Delta32FromGOT;136 case ELF::R_386_PLT32:137 return x86::BranchPCRel32;138 }139 140 return make_error<JITLinkError>(141 "In " + G->getName() + ": Unsupported x86 relocation type " +142 object::getELFRelocationTypeName(ELF::EM_386, Type));143 }144 145 Error addRelocations() override {146 LLVM_DEBUG(dbgs() << "Adding relocations\n");147 using Base = ELFLinkGraphBuilder<ELFT>;148 using Self = ELFLinkGraphBuilder_x86;149 150 for (const auto &RelSect : Base::Sections) {151 // Validate the section to read relocation entries from.152 if (RelSect.sh_type == ELF::SHT_RELA)153 return make_error<StringError>(154 "No SHT_RELA in valid x86 ELF object files",155 inconvertibleErrorCode());156 157 if (Error Err = Base::forEachRelRelocation(RelSect, this,158 &Self::addSingleRelocation))159 return Err;160 }161 162 return Error::success();163 }164 165 Error addSingleRelocation(const typename ELFT::Rel &Rel,166 const typename ELFT::Shdr &FixupSection,167 Block &BlockToFix) {168 using Base = ELFLinkGraphBuilder<ELFT>;169 170 auto ELFReloc = Rel.getType(false);171 172 // R_386_NONE is a no-op.173 if (LLVM_UNLIKELY(ELFReloc == ELF::R_386_NONE))174 return Error::success();175 176 uint32_t SymbolIndex = Rel.getSymbol(false);177 auto ObjSymbol = Base::Obj.getRelocationSymbol(Rel, Base::SymTabSec);178 if (!ObjSymbol)179 return ObjSymbol.takeError();180 181 Symbol *GraphSymbol = Base::getGraphSymbol(SymbolIndex);182 if (!GraphSymbol)183 return make_error<StringError>(184 formatv("Could not find symbol at given index, did you add it to "185 "JITSymbolTable? index: {0}, shndx: {1} Size of table: {2}",186 SymbolIndex, (*ObjSymbol)->st_shndx,187 Base::GraphSymbols.size()),188 inconvertibleErrorCode());189 190 Expected<x86::EdgeKind_x86> Kind = getRelocationKind(ELFReloc);191 if (!Kind)192 return Kind.takeError();193 194 auto FixupAddress = orc::ExecutorAddr(FixupSection.sh_addr) + Rel.r_offset;195 int64_t Addend = 0;196 197 switch (*Kind) {198 case x86::Pointer32:199 case x86::PCRel32:200 case x86::RequestGOTAndTransformToDelta32FromGOT:201 case x86::Delta32:202 case x86::Delta32FromGOT:203 case x86::BranchPCRel32:204 case x86::BranchPCRel32ToPtrJumpStub:205 case x86::BranchPCRel32ToPtrJumpStubBypassable: {206 const char *FixupContent = BlockToFix.getContent().data() +207 (FixupAddress - BlockToFix.getAddress());208 Addend = *(const support::little32_t *)FixupContent;209 break;210 }211 case x86::Pointer16:212 case x86::PCRel16: {213 const char *FixupContent = BlockToFix.getContent().data() +214 (FixupAddress - BlockToFix.getAddress());215 Addend = *(const support::little16_t *)FixupContent;216 break;217 }218 }219 220 Edge::OffsetT Offset = FixupAddress - BlockToFix.getAddress();221 Edge GE(*Kind, Offset, *GraphSymbol, Addend);222 LLVM_DEBUG({223 dbgs() << " ";224 printEdge(dbgs(), BlockToFix, GE, x86::getEdgeKindName(*Kind));225 dbgs() << "\n";226 });227 228 BlockToFix.addEdge(std::move(GE));229 return Error::success();230 }231 232public:233 ELFLinkGraphBuilder_x86(StringRef FileName, const object::ELFFile<ELFT> &Obj,234 std::shared_ptr<orc::SymbolStringPool> SSP, Triple TT,235 SubtargetFeatures Features)236 : ELFLinkGraphBuilder<ELFT>(Obj, std::move(SSP), std::move(TT),237 std::move(Features), FileName,238 x86::getEdgeKindName) {}239};240 241Expected<std::unique_ptr<LinkGraph>>242createLinkGraphFromELFObject_x86(MemoryBufferRef ObjectBuffer,243 std::shared_ptr<orc::SymbolStringPool> SSP) {244 LLVM_DEBUG({245 dbgs() << "Building jitlink graph for new input "246 << ObjectBuffer.getBufferIdentifier() << "...\n";247 });248 249 auto ELFObj = object::ObjectFile::createELFObjectFile(ObjectBuffer);250 if (!ELFObj)251 return ELFObj.takeError();252 253 auto Features = (*ELFObj)->getFeatures();254 if (!Features)255 return Features.takeError();256 257 assert((*ELFObj)->getArch() == Triple::x86 &&258 "Only x86 (little endian) is supported for now");259 260 auto &ELFObjFile = cast<object::ELFObjectFile<object::ELF32LE>>(**ELFObj);261 262 return ELFLinkGraphBuilder_x86((*ELFObj)->getFileName(),263 ELFObjFile.getELFFile(), std::move(SSP),264 (*ELFObj)->makeTriple(), std::move(*Features))265 .buildGraph();266}267 268void link_ELF_x86(std::unique_ptr<LinkGraph> G,269 std::unique_ptr<JITLinkContext> Ctx) {270 PassConfiguration Config;271 const Triple &TT = G->getTargetTriple();272 if (Ctx->shouldAddDefaultTargetPasses(TT)) {273 if (auto MarkLive = Ctx->getMarkLivePass(TT))274 Config.PrePrunePasses.push_back(std::move(MarkLive));275 else276 Config.PrePrunePasses.push_back(markAllSymbolsLive);277 278 // Add an in-place GOT and PLT build pass.279 Config.PostPrunePasses.push_back(buildTables_ELF_x86);280 281 // Add GOT/Stubs optimizer pass.282 Config.PreFixupPasses.push_back(x86::optimizeGOTAndStubAccesses);283 }284 if (auto Err = Ctx->modifyPassConfig(*G, Config))285 return Ctx->notifyFailed(std::move(Err));286 287 ELFJITLinker_x86::link(std::move(Ctx), std::move(G), std::move(Config));288}289 290} // namespace llvm::jitlink291