425 lines · cpp
1//===----- ELF_systemz.cpp - JIT linker implementation for ELF/systemz ----===//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/systemz jit-link implementation.10//11//===----------------------------------------------------------------------===//12 13#include "llvm/ExecutionEngine/JITLink/DWARFRecordSectionSplitter.h"14#include "llvm/ExecutionEngine/JITLink/systemz.h"15#include "llvm/Object/ELFObjectFile.h"16 17#include "DefineExternalSectionStartAndEndSymbols.h"18#include "EHFrameSupportImpl.h"19#include "ELFLinkGraphBuilder.h"20#include "JITLinkGeneric.h"21 22#define DEBUG_TYPE "jitlink"23 24using namespace llvm;25using namespace llvm::jitlink;26 27namespace {28 29constexpr StringRef ELFGOTSymbolName = "_GLOBAL_OFFSET_TABLE_";30 31Error buildTables_ELF_systemz(LinkGraph &G) {32 LLVM_DEBUG(dbgs() << "Visiting edges in graph:\n");33 systemz::GOTTableManager GOT;34 systemz::PLTTableManager PLT(GOT);35 visitExistingEdges(G, GOT, PLT);36 return Error::success();37}38 39} // namespace40 41namespace llvm {42namespace jitlink {43class ELFJITLinker_systemz : public JITLinker<ELFJITLinker_systemz> {44 friend class JITLinker<ELFJITLinker_systemz>;45 46public:47 ELFJITLinker_systemz(std::unique_ptr<JITLinkContext> Ctx,48 std::unique_ptr<LinkGraph> G,49 PassConfiguration PassConfig)50 : JITLinker(std::move(Ctx), std::move(G), std::move(PassConfig)) {51 if (shouldAddDefaultTargetPasses(getGraph().getTargetTriple()))52 getPassConfig().PostAllocationPasses.push_back(53 [this](LinkGraph &G) { return getOrCreateGOTSymbol(G); });54 }55 56private:57 Symbol *GOTSymbol = nullptr;58 59 Error applyFixup(LinkGraph &G, Block &B, const Edge &E) const {60 return systemz::applyFixup(G, B, E, GOTSymbol);61 }62 63 Error getOrCreateGOTSymbol(LinkGraph &G) {64 auto DefineExternalGOTSymbolIfPresent =65 createDefineExternalSectionStartAndEndSymbolsPass(66 [&](LinkGraph &LG, Symbol &Sym) -> SectionRangeSymbolDesc {67 if (Sym.getName() != nullptr &&68 *Sym.getName() == ELFGOTSymbolName)69 if (auto *GOTSection = G.findSectionByName(70 systemz::GOTTableManager::getSectionName())) {71 GOTSymbol = &Sym;72 return {*GOTSection, true};73 }74 return {};75 });76 77 // Try to attach _GLOBAL_OFFSET_TABLE_ to the GOT if it's defined as an78 // external.79 if (auto Err = DefineExternalGOTSymbolIfPresent(G))80 return Err;81 82 // If we succeeded then we're done.83 if (GOTSymbol)84 return Error::success();85 86 // Otherwise look for a GOT section: If it already has a start symbol we'll87 // record it, otherwise we'll create our own.88 // If there's a GOT section but we didn't find an external GOT symbol...89 if (auto *GOTSection =90 G.findSectionByName(systemz::GOTTableManager::getSectionName())) {91 92 // Check for an existing defined symbol.93 for (auto *Sym : GOTSection->symbols())94 if (Sym->getName() != nullptr && *Sym->getName() == ELFGOTSymbolName) {95 GOTSymbol = Sym;96 return Error::success();97 }98 99 // If there's no defined symbol then create one.100 SectionRange SR(*GOTSection);101 if (SR.empty())102 GOTSymbol =103 &G.addAbsoluteSymbol(ELFGOTSymbolName, orc::ExecutorAddr(), 0,104 Linkage::Strong, Scope::Local, true);105 else106 GOTSymbol =107 &G.addDefinedSymbol(*SR.getFirstBlock(), 0, ELFGOTSymbolName, 0,108 Linkage::Strong, Scope::Local, false, true);109 }110 111 // If we still haven't found a GOT symbol then double check the externals.112 // We may have a GOT-relative reference but no GOT section, in which case113 // we just need to point the GOT symbol at some address in this graph.114 if (!GOTSymbol) {115 for (auto *Sym : G.external_symbols()) {116 if (Sym->getName() != nullptr && *Sym->getName() == ELFGOTSymbolName) {117 auto Blocks = G.blocks();118 if (!Blocks.empty()) {119 G.makeAbsolute(*Sym, (*Blocks.begin())->getAddress());120 GOTSymbol = Sym;121 break;122 }123 }124 }125 }126 127 return Error::success();128 }129};130 131class ELFLinkGraphBuilder_systemz132 : public ELFLinkGraphBuilder<object::ELF64BE> {133private:134 using ELFT = object::ELF64BE;135 using Base = ELFLinkGraphBuilder<ELFT>;136 using Base::G; // Use LinkGraph pointer from base class.137 138 Error addRelocations() override {139 LLVM_DEBUG(dbgs() << "Processing relocations:\n");140 141 using Base = ELFLinkGraphBuilder<ELFT>;142 using Self = ELFLinkGraphBuilder_systemz;143 for (const auto &RelSect : Base::Sections) {144 if (RelSect.sh_type == ELF::SHT_REL)145 // Validate the section to read relocation entries from.146 return make_error<StringError>("No SHT_REL in valid " +147 G->getTargetTriple().getArchName() +148 " ELF object files",149 inconvertibleErrorCode());150 151 if (Error Err = Base::forEachRelaRelocation(RelSect, this,152 &Self::addSingleRelocation))153 return Err;154 }155 156 return Error::success();157 }158 159 Error addSingleRelocation(const typename ELFT::Rela &Rel,160 const typename ELFT::Shdr &FixupSect,161 Block &BlockToFix) {162 using support::big32_t;163 using Base = ELFLinkGraphBuilder<ELFT>;164 auto ELFReloc = Rel.getType(false);165 166 // No reloc.167 if (LLVM_UNLIKELY(ELFReloc == ELF::R_390_NONE))168 return Error::success();169 170 uint32_t SymbolIndex = Rel.getSymbol(false);171 auto ObjSymbol = Base::Obj.getRelocationSymbol(Rel, Base::SymTabSec);172 if (!ObjSymbol)173 return ObjSymbol.takeError();174 175 Symbol *GraphSymbol = Base::getGraphSymbol(SymbolIndex);176 if (!GraphSymbol)177 return make_error<StringError>(178 formatv("Could not find symbol at given index, did you add it to "179 "JITSymbolTable? index: {0}, shndx: {1} Size of table: {2}",180 SymbolIndex, (*ObjSymbol)->st_shndx,181 Base::GraphSymbols.size()),182 inconvertibleErrorCode());183 184 // Validate the relocation kind.185 int64_t Addend = Rel.r_addend;186 Edge::Kind Kind = Edge::Invalid;187 188 switch (ELFReloc) {189 case ELF::R_390_PC64: {190 Kind = systemz::Delta64;191 break;192 }193 case ELF::R_390_PC32: {194 Kind = systemz::Delta32;195 break;196 }197 case ELF::R_390_PC16: {198 Kind = systemz::Delta16;199 break;200 }201 case ELF::R_390_PC32DBL: {202 Kind = systemz::Delta32dbl;203 break;204 }205 case ELF::R_390_PC24DBL: {206 Kind = systemz::Delta24dbl;207 break;208 }209 case ELF::R_390_PC16DBL: {210 Kind = systemz::Delta16dbl;211 break;212 }213 case ELF::R_390_PC12DBL: {214 Kind = systemz::Delta12dbl;215 break;216 }217 case ELF::R_390_64: {218 Kind = systemz::Pointer64;219 break;220 }221 case ELF::R_390_32: {222 Kind = systemz::Pointer32;223 break;224 }225 case ELF::R_390_20: {226 Kind = systemz::Pointer20;227 break;228 }229 case ELF::R_390_16: {230 Kind = systemz::Pointer16;231 break;232 }233 case ELF::R_390_12: {234 Kind = systemz::Pointer12;235 break;236 }237 case ELF::R_390_8: {238 Kind = systemz::Pointer8;239 break;240 }241 // Relocations targeting the PLT associated with the symbol.242 case ELF::R_390_PLT64: {243 Kind = systemz::DeltaPLT64;244 break;245 }246 case ELF::R_390_PLT32: {247 Kind = systemz::DeltaPLT32;248 break;249 }250 case ELF::R_390_PLT32DBL: {251 Kind = systemz::DeltaPLT32dbl;252 break;253 }254 case ELF::R_390_PLT24DBL: {255 Kind = systemz::DeltaPLT24dbl;256 break;257 }258 case ELF::R_390_PLT16DBL: {259 Kind = systemz::DeltaPLT16dbl;260 break;261 }262 case ELF::R_390_PLT12DBL: {263 Kind = systemz::DeltaPLT12dbl;264 break;265 }266 case ELF::R_390_PLTOFF64: {267 Kind = systemz::Delta64PLTFromGOT;268 break;269 }270 case ELF::R_390_PLTOFF32: {271 Kind = systemz::Delta32PLTFromGOT;272 break;273 }274 case ELF::R_390_PLTOFF16: {275 Kind = systemz::Delta16PLTFromGOT;276 break;277 }278 // Relocations targeting the actual symbol (just relative to the GOT).279 case ELF::R_390_GOTOFF64: {280 Kind = systemz::Delta64FromGOT;281 break;282 }283 case ELF::R_390_GOTOFF: {284 Kind = systemz::Delta32FromGOT;285 break;286 }287 case ELF::R_390_GOTOFF16: {288 Kind = systemz::Delta16FromGOT;289 break;290 }291 // Relocations targeting the GOT entry associated with the symbol.292 case ELF::R_390_GOT64:293 case ELF::R_390_GOTPLT64: {294 Kind = systemz::RequestGOTAndTransformToDelta64FromGOT;295 break;296 }297 case ELF::R_390_GOT32:298 case ELF::R_390_GOTPLT32: {299 Kind = systemz::RequestGOTAndTransformToDelta32FromGOT;300 break;301 }302 case ELF::R_390_GOT20:303 case ELF::R_390_GOTPLT20: {304 Kind = systemz::RequestGOTAndTransformToDelta20FromGOT;305 break;306 }307 case ELF::R_390_GOT16:308 case ELF::R_390_GOTPLT16: {309 Kind = systemz::RequestGOTAndTransformToDelta16FromGOT;310 break;311 }312 case ELF::R_390_GOT12:313 case ELF::R_390_GOTPLT12: {314 Kind = systemz::RequestGOTAndTransformToDelta12FromGOT;315 break;316 }317 case ELF::R_390_GOTENT:318 case ELF::R_390_GOTPLTENT: {319 Kind = systemz::RequestGOTAndTransformToDelta32dbl;320 break;321 }322 // R_390_GOTPC and R_390_GOTPCDBL don't create GOT entry, they don't even323 // have symbol.324 case ELF::R_390_GOTPC: {325 Kind = systemz::Delta32GOTBase;326 break;327 }328 case ELF::R_390_GOTPCDBL: {329 Kind = systemz::Delta32dblGOTBase;330 break;331 }332 default:333 return make_error<JITLinkError>(334 "In " + G->getName() + ": Unsupported systemz relocation type " +335 object::getELFRelocationTypeName(ELF::EM_S390, ELFReloc));336 }337 auto FixupAddress = orc::ExecutorAddr(FixupSect.sh_addr) + Rel.r_offset;338 Edge::OffsetT Offset = FixupAddress - BlockToFix.getAddress();339 Edge GE(Kind, Offset, *GraphSymbol, Addend);340 LLVM_DEBUG({341 dbgs() << " ";342 printEdge(dbgs(), BlockToFix, GE, systemz::getEdgeKindName(Kind));343 dbgs() << "\n";344 });345 346 BlockToFix.addEdge(std::move(GE));347 348 return Error::success();349 }350 351public:352 ELFLinkGraphBuilder_systemz(StringRef FileName,353 const object::ELFFile<ELFT> &Obj,354 std::shared_ptr<orc::SymbolStringPool> SSP,355 Triple TT, SubtargetFeatures Features)356 : ELFLinkGraphBuilder<ELFT>(Obj, std::move(SSP), std::move(TT),357 std::move(Features), FileName,358 systemz::getEdgeKindName) {}359};360 361Expected<std::unique_ptr<LinkGraph>> createLinkGraphFromELFObject_systemz(362 MemoryBufferRef ObjectBuffer, std::shared_ptr<orc::SymbolStringPool> SSP) {363 LLVM_DEBUG({364 dbgs() << "Building jitlink graph for new input "365 << ObjectBuffer.getBufferIdentifier() << "...\n";366 });367 368 auto ELFObj = object::ObjectFile::createELFObjectFile(ObjectBuffer);369 if (!ELFObj)370 return ELFObj.takeError();371 372 auto Features = (*ELFObj)->getFeatures();373 if (!Features)374 return Features.takeError();375 376 assert((*ELFObj)->getArch() == Triple::systemz &&377 "Only SystemZ is supported");378 379 auto &ELFObjFile = cast<object::ELFObjectFile<object::ELF64BE>>(**ELFObj);380 return ELFLinkGraphBuilder_systemz(381 (*ELFObj)->getFileName(), ELFObjFile.getELFFile(), std::move(SSP),382 (*ELFObj)->makeTriple(), std::move(*Features))383 .buildGraph();384}385 386void link_ELF_systemz(std::unique_ptr<LinkGraph> G,387 std::unique_ptr<JITLinkContext> Ctx) {388 PassConfiguration Config;389 const Triple &TT = G->getTargetTriple();390 if (Ctx->shouldAddDefaultTargetPasses(TT)) {391 // Add eh-frame passes.392 Config.PrePrunePasses.push_back(DWARFRecordSectionSplitter(".eh_frame"));393 Config.PrePrunePasses.push_back(394 EHFrameEdgeFixer(".eh_frame", G->getPointerSize(), systemz::Pointer32,395 systemz::Pointer64, systemz::Delta32, systemz::Delta64,396 systemz::NegDelta32));397 Config.PrePrunePasses.push_back(EHFrameNullTerminator(".eh_frame"));398 399 // Add a mark-live pass.400 if (auto MarkLive = Ctx->getMarkLivePass(TT))401 Config.PrePrunePasses.push_back(std::move(MarkLive));402 else403 Config.PrePrunePasses.push_back(markAllSymbolsLive);404 405 // Add an in-place GOT/Stubs build pass.406 Config.PostPrunePasses.push_back(buildTables_ELF_systemz);407 408 // Resolve any external section start / end symbols.409 Config.PostAllocationPasses.push_back(410 createDefineExternalSectionStartAndEndSymbolsPass(411 identifyELFSectionStartAndEndSymbols));412 413 // TODO: Add GOT/Stubs optimizer pass.414 // Config.PreFixupPasses.push_back(systemz::optimizeGOTAndStubAccesses);415 }416 417 if (auto Err = Ctx->modifyPassConfig(*G, Config))418 return Ctx->notifyFailed(std::move(Err));419 420 ELFJITLinker_systemz::link(std::move(Ctx), std::move(G), std::move(Config));421}422 423} // namespace jitlink424} // namespace llvm425