Path: blob/main/contrib/llvm-project/llvm/lib/ExecutionEngine/JITLink/ELF_aarch64.cpp
35271 views
//===----- ELF_aarch64.cpp - JIT linker implementation for ELF/aarch64 ----===//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/aarch64 jit-link implementation.9//10//===----------------------------------------------------------------------===//1112#include "llvm/ExecutionEngine/JITLink/ELF_aarch64.h"13#include "llvm/BinaryFormat/ELF.h"14#include "llvm/ExecutionEngine/JITLink/DWARFRecordSectionSplitter.h"15#include "llvm/ExecutionEngine/JITLink/aarch64.h"16#include "llvm/Object/ELFObjectFile.h"17#include "llvm/Support/Endian.h"1819#include "DefineExternalSectionStartAndEndSymbols.h"20#include "EHFrameSupportImpl.h"21#include "ELFLinkGraphBuilder.h"22#include "JITLinkGeneric.h"2324#define DEBUG_TYPE "jitlink"2526using namespace llvm;27using namespace llvm::jitlink;2829namespace {3031class ELFJITLinker_aarch64 : public JITLinker<ELFJITLinker_aarch64> {32friend class JITLinker<ELFJITLinker_aarch64>;3334public:35ELFJITLinker_aarch64(std::unique_ptr<JITLinkContext> Ctx,36std::unique_ptr<LinkGraph> G,37PassConfiguration PassConfig)38: JITLinker(std::move(Ctx), std::move(G), std::move(PassConfig)) {}3940private:41Error applyFixup(LinkGraph &G, Block &B, const Edge &E) const {42return aarch64::applyFixup(G, B, E);43}44};4546template <typename ELFT>47class ELFLinkGraphBuilder_aarch64 : public ELFLinkGraphBuilder<ELFT> {48private:49enum ELFAArch64RelocationKind : Edge::Kind {50ELFCall26 = Edge::FirstRelocation,51ELFLdrLo19,52ELFAdrLo21,53ELFAdrPage21,54ELFAddAbs12,55ELFLdSt8Abs12,56ELFLdSt16Abs12,57ELFLdSt32Abs12,58ELFLdSt64Abs12,59ELFLdSt128Abs12,60ELFMovwAbsG0,61ELFMovwAbsG1,62ELFMovwAbsG2,63ELFMovwAbsG3,64ELFTstBr14,65ELFCondBr19,66ELFAbs32,67ELFAbs64,68ELFPrel32,69ELFPrel64,70ELFAdrGOTPage21,71ELFLd64GOTLo12,72ELFTLSDescAdrPage21,73ELFTLSDescAddLo12,74ELFTLSDescLd64Lo12,75ELFTLSDescCall,76};7778static Expected<ELFAArch64RelocationKind>79getRelocationKind(const uint32_t Type) {80using namespace aarch64;81switch (Type) {82case ELF::R_AARCH64_CALL26:83case ELF::R_AARCH64_JUMP26:84return ELFCall26;85case ELF::R_AARCH64_LD_PREL_LO19:86return ELFLdrLo19;87case ELF::R_AARCH64_ADR_PREL_LO21:88return ELFAdrLo21;89case ELF::R_AARCH64_ADR_PREL_PG_HI21:90return ELFAdrPage21;91case ELF::R_AARCH64_ADD_ABS_LO12_NC:92return ELFAddAbs12;93case ELF::R_AARCH64_LDST8_ABS_LO12_NC:94return ELFLdSt8Abs12;95case ELF::R_AARCH64_LDST16_ABS_LO12_NC:96return ELFLdSt16Abs12;97case ELF::R_AARCH64_LDST32_ABS_LO12_NC:98return ELFLdSt32Abs12;99case ELF::R_AARCH64_LDST64_ABS_LO12_NC:100return ELFLdSt64Abs12;101case ELF::R_AARCH64_LDST128_ABS_LO12_NC:102return ELFLdSt128Abs12;103case ELF::R_AARCH64_MOVW_UABS_G0_NC:104return ELFMovwAbsG0;105case ELF::R_AARCH64_MOVW_UABS_G1_NC:106return ELFMovwAbsG1;107case ELF::R_AARCH64_MOVW_UABS_G2_NC:108return ELFMovwAbsG2;109case ELF::R_AARCH64_MOVW_UABS_G3:110return ELFMovwAbsG3;111case ELF::R_AARCH64_TSTBR14:112return ELFTstBr14;113case ELF::R_AARCH64_CONDBR19:114return ELFCondBr19;115case ELF::R_AARCH64_ABS32:116return ELFAbs32;117case ELF::R_AARCH64_ABS64:118return ELFAbs64;119case ELF::R_AARCH64_PREL32:120return ELFPrel32;121case ELF::R_AARCH64_PREL64:122return ELFPrel64;123case ELF::R_AARCH64_ADR_GOT_PAGE:124return ELFAdrGOTPage21;125case ELF::R_AARCH64_LD64_GOT_LO12_NC:126return ELFLd64GOTLo12;127case ELF::R_AARCH64_TLSDESC_ADR_PAGE21:128return ELFTLSDescAdrPage21;129case ELF::R_AARCH64_TLSDESC_ADD_LO12:130return ELFTLSDescAddLo12;131case ELF::R_AARCH64_TLSDESC_LD64_LO12:132return ELFTLSDescLd64Lo12;133case ELF::R_AARCH64_TLSDESC_CALL:134return ELFTLSDescCall;135}136137return make_error<JITLinkError>(138"Unsupported aarch64 relocation:" + formatv("{0:d}: ", Type) +139object::getELFRelocationTypeName(ELF::EM_AARCH64, Type));140}141142Error addRelocations() override {143LLVM_DEBUG(dbgs() << "Processing relocations:\n");144145using Base = ELFLinkGraphBuilder<ELFT>;146using Self = ELFLinkGraphBuilder_aarch64<ELFT>;147for (const auto &RelSect : Base::Sections)148if (Error Err = Base::forEachRelaRelocation(RelSect, this,149&Self::addSingleRelocation))150return Err;151152return Error::success();153}154155Error addSingleRelocation(const typename ELFT::Rela &Rel,156const typename ELFT::Shdr &FixupSect,157Block &BlockToFix) {158using support::ulittle32_t;159using Base = ELFLinkGraphBuilder<ELFT>;160161uint32_t SymbolIndex = Rel.getSymbol(false);162auto ObjSymbol = Base::Obj.getRelocationSymbol(Rel, Base::SymTabSec);163if (!ObjSymbol)164return ObjSymbol.takeError();165166Symbol *GraphSymbol = Base::getGraphSymbol(SymbolIndex);167if (!GraphSymbol)168return make_error<StringError>(169formatv("Could not find symbol at given index, did you add it to "170"JITSymbolTable? index: {0}, shndx: {1} Size of table: {2}",171SymbolIndex, (*ObjSymbol)->st_shndx,172Base::GraphSymbols.size()),173inconvertibleErrorCode());174175uint32_t Type = Rel.getType(false);176Expected<ELFAArch64RelocationKind> RelocKind = getRelocationKind(Type);177if (!RelocKind)178return RelocKind.takeError();179180int64_t Addend = Rel.r_addend;181orc::ExecutorAddr FixupAddress =182orc::ExecutorAddr(FixupSect.sh_addr) + Rel.r_offset;183Edge::OffsetT Offset = FixupAddress - BlockToFix.getAddress();184185// Get a pointer to the fixup content.186const void *FixupContent = BlockToFix.getContent().data() +187(FixupAddress - BlockToFix.getAddress());188189Edge::Kind Kind = Edge::Invalid;190191switch (*RelocKind) {192case ELFCall26: {193Kind = aarch64::Branch26PCRel;194break;195}196case ELFLdrLo19: {197uint32_t Instr = *(const ulittle32_t *)FixupContent;198if (!aarch64::isLDRLiteral(Instr))199return make_error<JITLinkError>(200"R_AARCH64_LDR_PREL_LO19 target is not an LDR Literal instruction");201202Kind = aarch64::LDRLiteral19;203break;204}205case ELFAdrLo21: {206uint32_t Instr = *(const ulittle32_t *)FixupContent;207if (!aarch64::isADR(Instr))208return make_error<JITLinkError>(209"R_AARCH64_ADR_PREL_LO21 target is not an ADR instruction");210211Kind = aarch64::ADRLiteral21;212break;213}214case ELFAdrPage21: {215Kind = aarch64::Page21;216break;217}218case ELFAddAbs12: {219Kind = aarch64::PageOffset12;220break;221}222case ELFLdSt8Abs12: {223uint32_t Instr = *(const ulittle32_t *)FixupContent;224if (!aarch64::isLoadStoreImm12(Instr) ||225aarch64::getPageOffset12Shift(Instr) != 0)226return make_error<JITLinkError>(227"R_AARCH64_LDST8_ABS_LO12_NC target is not a "228"LDRB/STRB (imm12) instruction");229230Kind = aarch64::PageOffset12;231break;232}233case ELFLdSt16Abs12: {234uint32_t Instr = *(const ulittle32_t *)FixupContent;235if (!aarch64::isLoadStoreImm12(Instr) ||236aarch64::getPageOffset12Shift(Instr) != 1)237return make_error<JITLinkError>(238"R_AARCH64_LDST16_ABS_LO12_NC target is not a "239"LDRH/STRH (imm12) instruction");240241Kind = aarch64::PageOffset12;242break;243}244case ELFLdSt32Abs12: {245uint32_t Instr = *(const ulittle32_t *)FixupContent;246if (!aarch64::isLoadStoreImm12(Instr) ||247aarch64::getPageOffset12Shift(Instr) != 2)248return make_error<JITLinkError>(249"R_AARCH64_LDST32_ABS_LO12_NC target is not a "250"LDR/STR (imm12, 32 bit) instruction");251252Kind = aarch64::PageOffset12;253break;254}255case ELFLdSt64Abs12: {256uint32_t Instr = *(const ulittle32_t *)FixupContent;257if (!aarch64::isLoadStoreImm12(Instr) ||258aarch64::getPageOffset12Shift(Instr) != 3)259return make_error<JITLinkError>(260"R_AARCH64_LDST64_ABS_LO12_NC target is not a "261"LDR/STR (imm12, 64 bit) instruction");262263Kind = aarch64::PageOffset12;264break;265}266case ELFLdSt128Abs12: {267uint32_t Instr = *(const ulittle32_t *)FixupContent;268if (!aarch64::isLoadStoreImm12(Instr) ||269aarch64::getPageOffset12Shift(Instr) != 4)270return make_error<JITLinkError>(271"R_AARCH64_LDST128_ABS_LO12_NC target is not a "272"LDR/STR (imm12, 128 bit) instruction");273274Kind = aarch64::PageOffset12;275break;276}277case ELFMovwAbsG0: {278uint32_t Instr = *(const ulittle32_t *)FixupContent;279if (!aarch64::isMoveWideImm16(Instr) ||280aarch64::getMoveWide16Shift(Instr) != 0)281return make_error<JITLinkError>(282"R_AARCH64_MOVW_UABS_G0_NC target is not a "283"MOVK/MOVZ (imm16, LSL #0) instruction");284285Kind = aarch64::MoveWide16;286break;287}288case ELFMovwAbsG1: {289uint32_t Instr = *(const ulittle32_t *)FixupContent;290if (!aarch64::isMoveWideImm16(Instr) ||291aarch64::getMoveWide16Shift(Instr) != 16)292return make_error<JITLinkError>(293"R_AARCH64_MOVW_UABS_G1_NC target is not a "294"MOVK/MOVZ (imm16, LSL #16) instruction");295296Kind = aarch64::MoveWide16;297break;298}299case ELFMovwAbsG2: {300uint32_t Instr = *(const ulittle32_t *)FixupContent;301if (!aarch64::isMoveWideImm16(Instr) ||302aarch64::getMoveWide16Shift(Instr) != 32)303return make_error<JITLinkError>(304"R_AARCH64_MOVW_UABS_G2_NC target is not a "305"MOVK/MOVZ (imm16, LSL #32) instruction");306307Kind = aarch64::MoveWide16;308break;309}310case ELFMovwAbsG3: {311uint32_t Instr = *(const ulittle32_t *)FixupContent;312if (!aarch64::isMoveWideImm16(Instr) ||313aarch64::getMoveWide16Shift(Instr) != 48)314return make_error<JITLinkError>(315"R_AARCH64_MOVW_UABS_G3 target is not a "316"MOVK/MOVZ (imm16, LSL #48) instruction");317318Kind = aarch64::MoveWide16;319break;320}321case ELFTstBr14: {322uint32_t Instr = *(const ulittle32_t *)FixupContent;323if (!aarch64::isTestAndBranchImm14(Instr))324return make_error<JITLinkError>("R_AARCH64_TSTBR14 target is not a "325"test and branch instruction");326327Kind = aarch64::TestAndBranch14PCRel;328break;329}330case ELFCondBr19: {331uint32_t Instr = *(const ulittle32_t *)FixupContent;332if (!aarch64::isCondBranchImm19(Instr) &&333!aarch64::isCompAndBranchImm19(Instr))334return make_error<JITLinkError>("R_AARCH64_CONDBR19 target is not a "335"conditional branch instruction");336337Kind = aarch64::CondBranch19PCRel;338break;339}340case ELFAbs32: {341Kind = aarch64::Pointer32;342break;343}344case ELFAbs64: {345Kind = aarch64::Pointer64;346break;347}348case ELFPrel32: {349Kind = aarch64::Delta32;350break;351}352case ELFPrel64: {353Kind = aarch64::Delta64;354break;355}356case ELFAdrGOTPage21: {357Kind = aarch64::RequestGOTAndTransformToPage21;358break;359}360case ELFLd64GOTLo12: {361Kind = aarch64::RequestGOTAndTransformToPageOffset12;362break;363}364case ELFTLSDescAdrPage21: {365Kind = aarch64::RequestTLSDescEntryAndTransformToPage21;366break;367}368case ELFTLSDescAddLo12:369case ELFTLSDescLd64Lo12: {370Kind = aarch64::RequestTLSDescEntryAndTransformToPageOffset12;371break;372}373case ELFTLSDescCall: {374return Error::success();375}376};377378Edge GE(Kind, Offset, *GraphSymbol, Addend);379LLVM_DEBUG({380dbgs() << " ";381printEdge(dbgs(), BlockToFix, GE, aarch64::getEdgeKindName(Kind));382dbgs() << "\n";383});384385BlockToFix.addEdge(std::move(GE));386387return Error::success();388}389390/// Return the string name of the given ELF aarch64 edge kind.391const char *getELFAArch64RelocationKindName(Edge::Kind R) {392switch (R) {393case ELFCall26:394return "ELFCall26";395case ELFAdrPage21:396return "ELFAdrPage21";397case ELFAddAbs12:398return "ELFAddAbs12";399case ELFLdSt8Abs12:400return "ELFLdSt8Abs12";401case ELFLdSt16Abs12:402return "ELFLdSt16Abs12";403case ELFLdSt32Abs12:404return "ELFLdSt32Abs12";405case ELFLdSt64Abs12:406return "ELFLdSt64Abs12";407case ELFLdSt128Abs12:408return "ELFLdSt128Abs12";409case ELFMovwAbsG0:410return "ELFMovwAbsG0";411case ELFMovwAbsG1:412return "ELFMovwAbsG1";413case ELFMovwAbsG2:414return "ELFMovwAbsG2";415case ELFMovwAbsG3:416return "ELFMovwAbsG3";417case ELFAbs32:418return "ELFAbs32";419case ELFAbs64:420return "ELFAbs64";421case ELFPrel32:422return "ELFPrel32";423case ELFPrel64:424return "ELFPrel64";425case ELFAdrGOTPage21:426return "ELFAdrGOTPage21";427case ELFLd64GOTLo12:428return "ELFLd64GOTLo12";429case ELFTLSDescAdrPage21:430return "ELFTLSDescAdrPage21";431case ELFTLSDescAddLo12:432return "ELFTLSDescAddLo12";433case ELFTLSDescLd64Lo12:434return "ELFTLSDescLd64Lo12";435case ELFTLSDescCall:436return "ELFTLSDescCall";437default:438return getGenericEdgeKindName(static_cast<Edge::Kind>(R));439}440}441442public:443ELFLinkGraphBuilder_aarch64(StringRef FileName,444const object::ELFFile<ELFT> &Obj, Triple TT,445SubtargetFeatures Features)446: ELFLinkGraphBuilder<ELFT>(Obj, std::move(TT), std::move(Features),447FileName, aarch64::getEdgeKindName) {}448};449450// TLS Info Builder.451class TLSInfoTableManager_ELF_aarch64452: public TableManager<TLSInfoTableManager_ELF_aarch64> {453public:454static StringRef getSectionName() { return "$__TLSINFO"; }455456static const uint8_t TLSInfoEntryContent[16];457458bool visitEdge(LinkGraph &G, Block *B, Edge &E) { return false; }459460Symbol &createEntry(LinkGraph &G, Symbol &Target) {461// the TLS Info entry's key value will be written by the fixTLVSectionByName462// pass, so create mutable content.463auto &TLSInfoEntry = G.createMutableContentBlock(464getTLSInfoSection(G), G.allocateContent(getTLSInfoEntryContent()),465orc::ExecutorAddr(), 8, 0);466TLSInfoEntry.addEdge(aarch64::Pointer64, 8, Target, 0);467return G.addAnonymousSymbol(TLSInfoEntry, 0, 16, false, false);468}469470private:471Section &getTLSInfoSection(LinkGraph &G) {472if (!TLSInfoTable)473TLSInfoTable = &G.createSection(getSectionName(), orc::MemProt::Read);474return *TLSInfoTable;475}476477ArrayRef<char> getTLSInfoEntryContent() const {478return {reinterpret_cast<const char *>(TLSInfoEntryContent),479sizeof(TLSInfoEntryContent)};480}481482Section *TLSInfoTable = nullptr;483};484485const uint8_t TLSInfoTableManager_ELF_aarch64::TLSInfoEntryContent[16] = {4860x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /*pthread key */4870x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /*data address*/488};489490// TLS Descriptor Builder.491class TLSDescTableManager_ELF_aarch64492: public TableManager<TLSDescTableManager_ELF_aarch64> {493public:494TLSDescTableManager_ELF_aarch64(495TLSInfoTableManager_ELF_aarch64 &TLSInfoTableManager)496: TLSInfoTableManager(TLSInfoTableManager) {}497498static StringRef getSectionName() { return "$__TLSDESC"; }499500static const uint8_t TLSDescEntryContent[16];501502bool visitEdge(LinkGraph &G, Block *B, Edge &E) {503Edge::Kind KindToSet = Edge::Invalid;504switch (E.getKind()) {505case aarch64::RequestTLSDescEntryAndTransformToPage21: {506KindToSet = aarch64::Page21;507break;508}509case aarch64::RequestTLSDescEntryAndTransformToPageOffset12: {510KindToSet = aarch64::PageOffset12;511break;512}513default:514return false;515}516assert(KindToSet != Edge::Invalid &&517"Fell through switch, but no new kind to set");518DEBUG_WITH_TYPE("jitlink", {519dbgs() << " Fixing " << G.getEdgeKindName(E.getKind()) << " edge at "520<< B->getFixupAddress(E) << " (" << B->getAddress() << " + "521<< formatv("{0:x}", E.getOffset()) << ")\n";522});523E.setKind(KindToSet);524E.setTarget(getEntryForTarget(G, E.getTarget()));525return true;526}527528Symbol &createEntry(LinkGraph &G, Symbol &Target) {529auto &EntryBlock =530G.createContentBlock(getTLSDescSection(G), getTLSDescBlockContent(),531orc::ExecutorAddr(), 8, 0);532EntryBlock.addEdge(aarch64::Pointer64, 0, getTLSDescResolver(G), 0);533EntryBlock.addEdge(aarch64::Pointer64, 8,534TLSInfoTableManager.getEntryForTarget(G, Target), 0);535return G.addAnonymousSymbol(EntryBlock, 0, 8, false, false);536}537538private:539Section &getTLSDescSection(LinkGraph &G) {540if (!GOTSection)541GOTSection = &G.createSection(getSectionName(), orc::MemProt::Read);542return *GOTSection;543}544545Symbol &getTLSDescResolver(LinkGraph &G) {546if (!TLSDescResolver)547TLSDescResolver = &G.addExternalSymbol("__tlsdesc_resolver", 8, false);548return *TLSDescResolver;549}550551ArrayRef<char> getTLSDescBlockContent() {552return {reinterpret_cast<const char *>(TLSDescEntryContent),553sizeof(TLSDescEntryContent)};554}555556Section *GOTSection = nullptr;557Symbol *TLSDescResolver = nullptr;558TLSInfoTableManager_ELF_aarch64 &TLSInfoTableManager;559};560561const uint8_t TLSDescTableManager_ELF_aarch64::TLSDescEntryContent[16] = {5620x00, 0x00, 0x00, 0x00,5630x00, 0x00, 0x00, 0x00, /*resolver function pointer*/5640x00, 0x00, 0x00, 0x00,5650x00, 0x00, 0x00, 0x00 /*pointer to tls info*/566};567568Error buildTables_ELF_aarch64(LinkGraph &G) {569LLVM_DEBUG(dbgs() << "Visiting edges in graph:\n");570571aarch64::GOTTableManager GOT;572aarch64::PLTTableManager PLT(GOT);573TLSInfoTableManager_ELF_aarch64 TLSInfo;574TLSDescTableManager_ELF_aarch64 TLSDesc(TLSInfo);575visitExistingEdges(G, GOT, PLT, TLSDesc, TLSInfo);576return Error::success();577}578579} // namespace580581namespace llvm {582namespace jitlink {583584Expected<std::unique_ptr<LinkGraph>>585createLinkGraphFromELFObject_aarch64(MemoryBufferRef ObjectBuffer) {586LLVM_DEBUG({587dbgs() << "Building jitlink graph for new input "588<< ObjectBuffer.getBufferIdentifier() << "...\n";589});590591auto ELFObj = object::ObjectFile::createELFObjectFile(ObjectBuffer);592if (!ELFObj)593return ELFObj.takeError();594595auto Features = (*ELFObj)->getFeatures();596if (!Features)597return Features.takeError();598599assert((*ELFObj)->getArch() == Triple::aarch64 &&600"Only AArch64 (little endian) is supported for now");601602auto &ELFObjFile = cast<object::ELFObjectFile<object::ELF64LE>>(**ELFObj);603return ELFLinkGraphBuilder_aarch64<object::ELF64LE>(604(*ELFObj)->getFileName(), ELFObjFile.getELFFile(),605(*ELFObj)->makeTriple(), std::move(*Features))606.buildGraph();607}608609void link_ELF_aarch64(std::unique_ptr<LinkGraph> G,610std::unique_ptr<JITLinkContext> Ctx) {611PassConfiguration Config;612const Triple &TT = G->getTargetTriple();613if (Ctx->shouldAddDefaultTargetPasses(TT)) {614// Add eh-frame passes.615Config.PrePrunePasses.push_back(DWARFRecordSectionSplitter(".eh_frame"));616Config.PrePrunePasses.push_back(EHFrameEdgeFixer(617".eh_frame", 8, aarch64::Pointer32, aarch64::Pointer64,618aarch64::Delta32, aarch64::Delta64, aarch64::NegDelta32));619Config.PrePrunePasses.push_back(EHFrameNullTerminator(".eh_frame"));620621// Add a mark-live pass.622if (auto MarkLive = Ctx->getMarkLivePass(TT))623Config.PrePrunePasses.push_back(std::move(MarkLive));624else625Config.PrePrunePasses.push_back(markAllSymbolsLive);626627// Resolve any external section start / end symbols.628Config.PostAllocationPasses.push_back(629createDefineExternalSectionStartAndEndSymbolsPass(630identifyELFSectionStartAndEndSymbols));631632// Add an in-place GOT/TLS/Stubs build pass.633Config.PostPrunePasses.push_back(buildTables_ELF_aarch64);634}635636if (auto Err = Ctx->modifyPassConfig(*G, Config))637return Ctx->notifyFailed(std::move(Err));638639ELFJITLinker_aarch64::link(std::move(Ctx), std::move(G), std::move(Config));640}641642} // namespace jitlink643} // namespace llvm644645646