Path: blob/main/contrib/llvm-project/llvm/lib/ExecutionEngine/JITLink/ELF_aarch32.cpp
35271 views
//===----- ELF_aarch32.cpp - JIT linker implementation for arm/thumb ------===//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/aarch32 jit-link implementation.9//10//===----------------------------------------------------------------------===//1112#include "llvm/ExecutionEngine/JITLink/ELF_aarch32.h"1314#include "llvm/BinaryFormat/ELF.h"15#include "llvm/ExecutionEngine/JITLink/JITLink.h"16#include "llvm/ExecutionEngine/JITLink/aarch32.h"17#include "llvm/Object/ELF.h"18#include "llvm/Object/ELFObjectFile.h"19#include "llvm/Support/ErrorHandling.h"20#include "llvm/TargetParser/ARMTargetParser.h"2122#include "ELFLinkGraphBuilder.h"23#include "JITLinkGeneric.h"2425#define DEBUG_TYPE "jitlink"2627using namespace llvm::object;2829namespace llvm {30namespace jitlink {3132/// Translate from ELF relocation type to JITLink-internal edge kind.33Expected<aarch32::EdgeKind_aarch32>34getJITLinkEdgeKind(uint32_t ELFType, const aarch32::ArmConfig &ArmCfg) {35switch (ELFType) {36case ELF::R_ARM_ABS32:37return aarch32::Data_Pointer32;38case ELF::R_ARM_GOT_PREL:39return aarch32::Data_RequestGOTAndTransformToDelta32;40case ELF::R_ARM_REL32:41return aarch32::Data_Delta32;42case ELF::R_ARM_CALL:43return aarch32::Arm_Call;44case ELF::R_ARM_JUMP24:45return aarch32::Arm_Jump24;46case ELF::R_ARM_MOVW_ABS_NC:47return aarch32::Arm_MovwAbsNC;48case ELF::R_ARM_MOVT_ABS:49return aarch32::Arm_MovtAbs;50case ELF::R_ARM_NONE:51return aarch32::None;52case ELF::R_ARM_PREL31:53return aarch32::Data_PRel31;54case ELF::R_ARM_TARGET1:55return (ArmCfg.Target1Rel) ? aarch32::Data_Delta3256: aarch32::Data_Pointer32;57case ELF::R_ARM_THM_CALL:58return aarch32::Thumb_Call;59case ELF::R_ARM_THM_JUMP24:60return aarch32::Thumb_Jump24;61case ELF::R_ARM_THM_MOVW_ABS_NC:62return aarch32::Thumb_MovwAbsNC;63case ELF::R_ARM_THM_MOVT_ABS:64return aarch32::Thumb_MovtAbs;65case ELF::R_ARM_THM_MOVW_PREL_NC:66return aarch32::Thumb_MovwPrelNC;67case ELF::R_ARM_THM_MOVT_PREL:68return aarch32::Thumb_MovtPrel;69}7071return make_error<JITLinkError>(72"Unsupported aarch32 relocation " + formatv("{0:d}: ", ELFType) +73object::getELFRelocationTypeName(ELF::EM_ARM, ELFType));74}7576/// Translate from JITLink-internal edge kind back to ELF relocation type.77Expected<uint32_t> getELFRelocationType(Edge::Kind Kind) {78switch (static_cast<aarch32::EdgeKind_aarch32>(Kind)) {79case aarch32::Data_Delta32:80return ELF::R_ARM_REL32;81case aarch32::Data_Pointer32:82return ELF::R_ARM_ABS32;83case aarch32::Data_PRel31:84return ELF::R_ARM_PREL31;85case aarch32::Data_RequestGOTAndTransformToDelta32:86return ELF::R_ARM_GOT_PREL;87case aarch32::Arm_Call:88return ELF::R_ARM_CALL;89case aarch32::Arm_Jump24:90return ELF::R_ARM_JUMP24;91case aarch32::Arm_MovwAbsNC:92return ELF::R_ARM_MOVW_ABS_NC;93case aarch32::Arm_MovtAbs:94return ELF::R_ARM_MOVT_ABS;95case aarch32::Thumb_Call:96return ELF::R_ARM_THM_CALL;97case aarch32::Thumb_Jump24:98return ELF::R_ARM_THM_JUMP24;99case aarch32::Thumb_MovwAbsNC:100return ELF::R_ARM_THM_MOVW_ABS_NC;101case aarch32::Thumb_MovtAbs:102return ELF::R_ARM_THM_MOVT_ABS;103case aarch32::Thumb_MovwPrelNC:104return ELF::R_ARM_THM_MOVW_PREL_NC;105case aarch32::Thumb_MovtPrel:106return ELF::R_ARM_THM_MOVT_PREL;107case aarch32::None:108return ELF::R_ARM_NONE;109}110111return make_error<JITLinkError>(formatv("Invalid aarch32 edge {0:d}: ",112Kind));113}114115/// Get a human-readable name for the given ELF AArch32 edge kind.116const char *getELFAArch32EdgeKindName(Edge::Kind R) {117// No ELF-specific edge kinds yet118return aarch32::getEdgeKindName(R);119}120121class ELFJITLinker_aarch32 : public JITLinker<ELFJITLinker_aarch32> {122friend class JITLinker<ELFJITLinker_aarch32>;123124public:125ELFJITLinker_aarch32(std::unique_ptr<JITLinkContext> Ctx,126std::unique_ptr<LinkGraph> G, PassConfiguration PassCfg,127aarch32::ArmConfig ArmCfg)128: JITLinker(std::move(Ctx), std::move(G), std::move(PassCfg)),129ArmCfg(std::move(ArmCfg)) {}130131private:132aarch32::ArmConfig ArmCfg;133134Error applyFixup(LinkGraph &G, Block &B, const Edge &E) const {135return aarch32::applyFixup(G, B, E, ArmCfg);136}137};138139template <llvm::endianness DataEndianness>140class ELFLinkGraphBuilder_aarch32141: public ELFLinkGraphBuilder<ELFType<DataEndianness, false>> {142private:143using ELFT = ELFType<DataEndianness, false>;144using Base = ELFLinkGraphBuilder<ELFT>;145146Error addRelocations() override {147LLVM_DEBUG(dbgs() << "Processing relocations:\n");148using Self = ELFLinkGraphBuilder_aarch32<DataEndianness>;149for (const auto &RelSect : Base::Sections) {150if (Error Err = Base::forEachRelRelocation(RelSect, this,151&Self::addSingleRelRelocation))152return Err;153}154return Error::success();155}156157Error addSingleRelRelocation(const typename ELFT::Rel &Rel,158const typename ELFT::Shdr &FixupSect,159Block &BlockToFix) {160uint32_t SymbolIndex = Rel.getSymbol(false);161auto ObjSymbol = Base::Obj.getRelocationSymbol(Rel, Base::SymTabSec);162if (!ObjSymbol)163return ObjSymbol.takeError();164165Symbol *GraphSymbol = Base::getGraphSymbol(SymbolIndex);166if (!GraphSymbol)167return make_error<StringError>(168formatv("Could not find symbol at given index, did you add it to "169"JITSymbolTable? index: {0}, shndx: {1} Size of table: {2}",170SymbolIndex, (*ObjSymbol)->st_shndx,171Base::GraphSymbols.size()),172inconvertibleErrorCode());173174uint32_t Type = Rel.getType(false);175Expected<aarch32::EdgeKind_aarch32> Kind = getJITLinkEdgeKind(Type, ArmCfg);176if (!Kind)177return Kind.takeError();178179auto FixupAddress = orc::ExecutorAddr(FixupSect.sh_addr) + Rel.r_offset;180Edge::OffsetT Offset = FixupAddress - BlockToFix.getAddress();181182Expected<int64_t> Addend =183aarch32::readAddend(*Base::G, BlockToFix, Offset, *Kind, ArmCfg);184if (!Addend)185return Addend.takeError();186187Edge E(*Kind, Offset, *GraphSymbol, *Addend);188LLVM_DEBUG({189dbgs() << " ";190printEdge(dbgs(), BlockToFix, E, getELFAArch32EdgeKindName(*Kind));191dbgs() << "\n";192});193194BlockToFix.addEdge(std::move(E));195return Error::success();196}197198aarch32::ArmConfig ArmCfg;199200protected:201TargetFlagsType makeTargetFlags(const typename ELFT::Sym &Sym) override {202// Only emit target flag for callable symbols203if (Sym.getType() != ELF::STT_FUNC)204return TargetFlagsType{};205if (Sym.getValue() & 0x01)206return aarch32::ThumbSymbol;207return TargetFlagsType{};208}209210orc::ExecutorAddrDiff getRawOffset(const typename ELFT::Sym &Sym,211TargetFlagsType Flags) override {212assert((makeTargetFlags(Sym) & Flags) == Flags);213static constexpr uint64_t ThumbBit = 0x01;214if (Sym.getType() == ELF::STT_FUNC)215return Sym.getValue() & ~ThumbBit;216return Sym.getValue();217}218219public:220ELFLinkGraphBuilder_aarch32(StringRef FileName,221const llvm::object::ELFFile<ELFT> &Obj, Triple TT,222SubtargetFeatures Features,223aarch32::ArmConfig ArmCfg)224: ELFLinkGraphBuilder<ELFT>(Obj, std::move(TT), std::move(Features),225FileName, getELFAArch32EdgeKindName),226ArmCfg(std::move(ArmCfg)) {}227};228229template <typename StubsManagerType>230Error buildTables_ELF_aarch32(LinkGraph &G) {231LLVM_DEBUG(dbgs() << "Visiting edges in graph:\n");232233StubsManagerType StubsManager;234visitExistingEdges(G, StubsManager);235aarch32::GOTBuilder GOT;236visitExistingEdges(G, GOT);237238return Error::success();239}240241Expected<std::unique_ptr<LinkGraph>>242createLinkGraphFromELFObject_aarch32(MemoryBufferRef ObjectBuffer) {243LLVM_DEBUG({244dbgs() << "Building jitlink graph for new input "245<< ObjectBuffer.getBufferIdentifier() << "...\n";246});247248auto ELFObj = ObjectFile::createELFObjectFile(ObjectBuffer);249if (!ELFObj)250return ELFObj.takeError();251252auto Features = (*ELFObj)->getFeatures();253if (!Features)254return Features.takeError();255256// Find out what exact AArch32 instruction set and features we target.257auto TT = (*ELFObj)->makeTriple();258ARM::ArchKind AK = ARM::parseArch(TT.getArchName());259if (AK == ARM::ArchKind::INVALID)260return make_error<JITLinkError>(261"Failed to build ELF link graph: Invalid ARM ArchKind");262263// Resolve our internal configuration for the target. If at some point the264// CPUArch alone becomes too unprecise, we can find more details in the265// Tag_CPU_arch_profile.266auto Arch = static_cast<ARMBuildAttrs::CPUArch>(ARM::getArchAttr(AK));267aarch32::ArmConfig ArmCfg = aarch32::getArmConfigForCPUArch(Arch);268269// Populate the link-graph.270switch (TT.getArch()) {271case Triple::arm:272case Triple::thumb: {273auto &ELFFile = cast<ELFObjectFile<ELF32LE>>(**ELFObj).getELFFile();274return ELFLinkGraphBuilder_aarch32<llvm::endianness::little>(275(*ELFObj)->getFileName(), ELFFile, TT, std::move(*Features),276ArmCfg)277.buildGraph();278}279case Triple::armeb:280case Triple::thumbeb: {281auto &ELFFile = cast<ELFObjectFile<ELF32BE>>(**ELFObj).getELFFile();282return ELFLinkGraphBuilder_aarch32<llvm::endianness::big>(283(*ELFObj)->getFileName(), ELFFile, TT, std::move(*Features),284ArmCfg)285.buildGraph();286}287default:288return make_error<JITLinkError>(289"Failed to build ELF/aarch32 link graph: Invalid target triple " +290TT.getTriple());291}292}293294void link_ELF_aarch32(std::unique_ptr<LinkGraph> G,295std::unique_ptr<JITLinkContext> Ctx) {296const Triple &TT = G->getTargetTriple();297298using namespace ARMBuildAttrs;299ARM::ArchKind AK = ARM::parseArch(TT.getArchName());300auto CPU = static_cast<CPUArch>(ARM::getArchAttr(AK));301aarch32::ArmConfig ArmCfg = aarch32::getArmConfigForCPUArch(CPU);302303PassConfiguration PassCfg;304if (Ctx->shouldAddDefaultTargetPasses(TT)) {305// Add a mark-live pass.306if (auto MarkLive = Ctx->getMarkLivePass(TT))307PassCfg.PrePrunePasses.push_back(std::move(MarkLive));308else309PassCfg.PrePrunePasses.push_back(markAllSymbolsLive);310311switch (ArmCfg.Stubs) {312case aarch32::StubsFlavor::pre_v7:313PassCfg.PostPrunePasses.push_back(314buildTables_ELF_aarch32<aarch32::StubsManager_prev7>);315break;316case aarch32::StubsFlavor::v7:317PassCfg.PostPrunePasses.push_back(318buildTables_ELF_aarch32<aarch32::StubsManager_v7>);319break;320case aarch32::StubsFlavor::Undefined:321llvm_unreachable("Check before building graph");322}323}324325if (auto Err = Ctx->modifyPassConfig(*G, PassCfg))326return Ctx->notifyFailed(std::move(Err));327328ELFJITLinker_aarch32::link(std::move(Ctx), std::move(G), std::move(PassCfg),329std::move(ArmCfg));330}331332} // namespace jitlink333} // namespace llvm334335336