Path: blob/main/contrib/llvm-project/llvm/lib/ExecutionEngine/JITLink/ELF_x86.cpp
213799 views
//===--------- ELF_x86.cpp - JIT linker implementation for ELF/x86 --------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// ELF/x86 jit-link implementation.9//10//===----------------------------------------------------------------------===//1112#include "llvm/ExecutionEngine/JITLink/ELF_x86.h"13#include "DefineExternalSectionStartAndEndSymbols.h"14#include "ELFLinkGraphBuilder.h"15#include "JITLinkGeneric.h"16#include "llvm/BinaryFormat/ELF.h"17#include "llvm/ExecutionEngine/JITLink/x86.h"18#include "llvm/Object/ELFObjectFile.h"1920#define DEBUG_TYPE "jitlink"2122using namespace llvm;23using namespace llvm::jitlink;2425namespace {26constexpr StringRef ELFGOTSymbolName = "_GLOBAL_OFFSET_TABLE_";2728Error buildTables_ELF_x86(LinkGraph &G) {29LLVM_DEBUG(dbgs() << "Visiting edges in graph:\n");3031x86::GOTTableManager GOT;32x86::PLTTableManager PLT(GOT);33visitExistingEdges(G, GOT, PLT);34return Error::success();35}36} // namespace3738namespace llvm::jitlink {3940class ELFJITLinker_x86 : public JITLinker<ELFJITLinker_x86> {41friend class JITLinker<ELFJITLinker_x86>;4243public:44ELFJITLinker_x86(std::unique_ptr<JITLinkContext> Ctx,45std::unique_ptr<LinkGraph> G, PassConfiguration PassConfig)46: JITLinker(std::move(Ctx), std::move(G), std::move(PassConfig)) {47getPassConfig().PostAllocationPasses.push_back(48[this](LinkGraph &G) { return getOrCreateGOTSymbol(G); });49}5051private:52Symbol *GOTSymbol = nullptr;5354Error getOrCreateGOTSymbol(LinkGraph &G) {55auto DefineExternalGOTSymbolIfPresent =56createDefineExternalSectionStartAndEndSymbolsPass(57[&](LinkGraph &LG, Symbol &Sym) -> SectionRangeSymbolDesc {58if (Sym.getName() != nullptr &&59*Sym.getName() == ELFGOTSymbolName)60if (auto *GOTSection = G.findSectionByName(61x86::GOTTableManager::getSectionName())) {62GOTSymbol = &Sym;63return {*GOTSection, true};64}65return {};66});6768// Try to attach _GLOBAL_OFFSET_TABLE_ to the GOT if it's defined as an69// external.70if (auto Err = DefineExternalGOTSymbolIfPresent(G))71return Err;7273// If we succeeded then we're done.74if (GOTSymbol)75return Error::success();7677// Otherwise look for a GOT section: If it already has a start symbol we'll78// record it, otherwise we'll create our own.79// If there's a GOT section but we didn't find an external GOT symbol...80if (auto *GOTSection =81G.findSectionByName(x86::GOTTableManager::getSectionName())) {8283// Check for an existing defined symbol.84for (auto *Sym : GOTSection->symbols())85if (Sym->getName() != nullptr && *Sym->getName() == ELFGOTSymbolName) {86GOTSymbol = Sym;87return Error::success();88}8990// If there's no defined symbol then create one.91SectionRange SR(*GOTSection);9293if (SR.empty()) {94GOTSymbol =95&G.addAbsoluteSymbol(ELFGOTSymbolName, orc::ExecutorAddr(), 0,96Linkage::Strong, Scope::Local, true);97} else {98GOTSymbol =99&G.addDefinedSymbol(*SR.getFirstBlock(), 0, ELFGOTSymbolName, 0,100Linkage::Strong, Scope::Local, false, true);101}102}103104return Error::success();105}106107Error applyFixup(LinkGraph &G, Block &B, const Edge &E) const {108return x86::applyFixup(G, B, E, GOTSymbol);109}110};111112class ELFLinkGraphBuilder_x86 : public ELFLinkGraphBuilder<object::ELF32LE> {113private:114using ELFT = object::ELF32LE;115116Expected<x86::EdgeKind_x86> getRelocationKind(const uint32_t Type) {117switch (Type) {118case ELF::R_386_32:119return x86::Pointer32;120case ELF::R_386_PC32:121return x86::PCRel32;122case ELF::R_386_16:123return x86::Pointer16;124case ELF::R_386_PC16:125return x86::PCRel16;126case ELF::R_386_GOT32:127return x86::RequestGOTAndTransformToDelta32FromGOT;128case ELF::R_386_GOT32X:129// TODO: Add a relaxable edge kind and update relaxation optimization.130return x86::RequestGOTAndTransformToDelta32FromGOT;131case ELF::R_386_GOTPC:132return x86::Delta32;133case ELF::R_386_GOTOFF:134return x86::Delta32FromGOT;135case ELF::R_386_PLT32:136return x86::BranchPCRel32;137}138139return make_error<JITLinkError>(140"In " + G->getName() + ": Unsupported x86 relocation type " +141object::getELFRelocationTypeName(ELF::EM_386, Type));142}143144Error addRelocations() override {145LLVM_DEBUG(dbgs() << "Adding relocations\n");146using Base = ELFLinkGraphBuilder<ELFT>;147using Self = ELFLinkGraphBuilder_x86;148149for (const auto &RelSect : Base::Sections) {150// Validate the section to read relocation entries from.151if (RelSect.sh_type == ELF::SHT_RELA)152return make_error<StringError>(153"No SHT_RELA in valid x86 ELF object files",154inconvertibleErrorCode());155156if (Error Err = Base::forEachRelRelocation(RelSect, this,157&Self::addSingleRelocation))158return Err;159}160161return Error::success();162}163164Error addSingleRelocation(const typename ELFT::Rel &Rel,165const typename ELFT::Shdr &FixupSection,166Block &BlockToFix) {167using Base = ELFLinkGraphBuilder<ELFT>;168169auto ELFReloc = Rel.getType(false);170171// R_386_NONE is a no-op.172if (LLVM_UNLIKELY(ELFReloc == ELF::R_386_NONE))173return Error::success();174175uint32_t SymbolIndex = Rel.getSymbol(false);176auto ObjSymbol = Base::Obj.getRelocationSymbol(Rel, Base::SymTabSec);177if (!ObjSymbol)178return ObjSymbol.takeError();179180Symbol *GraphSymbol = Base::getGraphSymbol(SymbolIndex);181if (!GraphSymbol)182return make_error<StringError>(183formatv("Could not find symbol at given index, did you add it to "184"JITSymbolTable? index: {0}, shndx: {1} Size of table: {2}",185SymbolIndex, (*ObjSymbol)->st_shndx,186Base::GraphSymbols.size()),187inconvertibleErrorCode());188189Expected<x86::EdgeKind_x86> Kind = getRelocationKind(ELFReloc);190if (!Kind)191return Kind.takeError();192193auto FixupAddress = orc::ExecutorAddr(FixupSection.sh_addr) + Rel.r_offset;194int64_t Addend = 0;195196switch (*Kind) {197case x86::Pointer32:198case x86::PCRel32:199case x86::RequestGOTAndTransformToDelta32FromGOT:200case x86::Delta32:201case x86::Delta32FromGOT:202case x86::BranchPCRel32:203case x86::BranchPCRel32ToPtrJumpStub:204case x86::BranchPCRel32ToPtrJumpStubBypassable: {205const char *FixupContent = BlockToFix.getContent().data() +206(FixupAddress - BlockToFix.getAddress());207Addend = *(const support::little32_t *)FixupContent;208break;209}210case x86::Pointer16:211case x86::PCRel16: {212const char *FixupContent = BlockToFix.getContent().data() +213(FixupAddress - BlockToFix.getAddress());214Addend = *(const support::little16_t *)FixupContent;215break;216}217}218219Edge::OffsetT Offset = FixupAddress - BlockToFix.getAddress();220Edge GE(*Kind, Offset, *GraphSymbol, Addend);221LLVM_DEBUG({222dbgs() << " ";223printEdge(dbgs(), BlockToFix, GE, x86::getEdgeKindName(*Kind));224dbgs() << "\n";225});226227BlockToFix.addEdge(std::move(GE));228return Error::success();229}230231public:232ELFLinkGraphBuilder_x86(StringRef FileName, const object::ELFFile<ELFT> &Obj,233std::shared_ptr<orc::SymbolStringPool> SSP, Triple TT,234SubtargetFeatures Features)235: ELFLinkGraphBuilder<ELFT>(Obj, std::move(SSP), std::move(TT),236std::move(Features), FileName,237x86::getEdgeKindName) {}238};239240Expected<std::unique_ptr<LinkGraph>>241createLinkGraphFromELFObject_x86(MemoryBufferRef ObjectBuffer,242std::shared_ptr<orc::SymbolStringPool> SSP) {243LLVM_DEBUG({244dbgs() << "Building jitlink graph for new input "245<< ObjectBuffer.getBufferIdentifier() << "...\n";246});247248auto ELFObj = object::ObjectFile::createELFObjectFile(ObjectBuffer);249if (!ELFObj)250return ELFObj.takeError();251252auto Features = (*ELFObj)->getFeatures();253if (!Features)254return Features.takeError();255256assert((*ELFObj)->getArch() == Triple::x86 &&257"Only x86 (little endian) is supported for now");258259auto &ELFObjFile = cast<object::ELFObjectFile<object::ELF32LE>>(**ELFObj);260261return ELFLinkGraphBuilder_x86((*ELFObj)->getFileName(),262ELFObjFile.getELFFile(), std::move(SSP),263(*ELFObj)->makeTriple(), std::move(*Features))264.buildGraph();265}266267void link_ELF_x86(std::unique_ptr<LinkGraph> G,268std::unique_ptr<JITLinkContext> Ctx) {269PassConfiguration Config;270const Triple &TT = G->getTargetTriple();271if (Ctx->shouldAddDefaultTargetPasses(TT)) {272if (auto MarkLive = Ctx->getMarkLivePass(TT))273Config.PrePrunePasses.push_back(std::move(MarkLive));274else275Config.PrePrunePasses.push_back(markAllSymbolsLive);276277// Add an in-place GOT and PLT build pass.278Config.PostPrunePasses.push_back(buildTables_ELF_x86);279280// Add GOT/Stubs optimizer pass.281Config.PreFixupPasses.push_back(x86::optimizeGOTAndStubAccesses);282}283if (auto Err = Ctx->modifyPassConfig(*G, Config))284return Ctx->notifyFailed(std::move(Err));285286ELFJITLinker_x86::link(std::move(Ctx), std::move(G), std::move(Config));287}288289} // namespace llvm::jitlink290291292