123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573 |
- //===----- ELF_aarch64.cpp - JIT linker implementation for ELF/aarch64 ----===//
- //
- // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
- // See https://llvm.org/LICENSE.txt for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- //
- //===----------------------------------------------------------------------===//
- //
- // ELF/aarch64 jit-link implementation.
- //
- //===----------------------------------------------------------------------===//
- #include "llvm/ExecutionEngine/JITLink/ELF_aarch64.h"
- #include "EHFrameSupportImpl.h"
- #include "ELFLinkGraphBuilder.h"
- #include "JITLinkGeneric.h"
- #include "llvm/BinaryFormat/ELF.h"
- #include "llvm/ExecutionEngine/JITLink/DWARFRecordSectionSplitter.h"
- #include "llvm/ExecutionEngine/JITLink/aarch64.h"
- #include "llvm/Object/ELFObjectFile.h"
- #include "llvm/Support/Endian.h"
- #define DEBUG_TYPE "jitlink"
- using namespace llvm;
- using namespace llvm::jitlink;
- namespace {
- class ELFJITLinker_aarch64 : public JITLinker<ELFJITLinker_aarch64> {
- friend class JITLinker<ELFJITLinker_aarch64>;
- public:
- ELFJITLinker_aarch64(std::unique_ptr<JITLinkContext> Ctx,
- std::unique_ptr<LinkGraph> G,
- PassConfiguration PassConfig)
- : JITLinker(std::move(Ctx), std::move(G), std::move(PassConfig)) {}
- private:
- Error applyFixup(LinkGraph &G, Block &B, const Edge &E) const {
- return aarch64::applyFixup(G, B, E);
- }
- };
- template <typename ELFT>
- class ELFLinkGraphBuilder_aarch64 : public ELFLinkGraphBuilder<ELFT> {
- private:
- enum ELFAArch64RelocationKind : Edge::Kind {
- ELFCall26 = Edge::FirstRelocation,
- ELFAdrPage21,
- ELFAddAbs12,
- ELFLdSt8Abs12,
- ELFLdSt16Abs12,
- ELFLdSt32Abs12,
- ELFLdSt64Abs12,
- ELFLdSt128Abs12,
- ELFMovwAbsG0,
- ELFMovwAbsG1,
- ELFMovwAbsG2,
- ELFMovwAbsG3,
- ELFAbs64,
- ELFPrel32,
- ELFPrel64,
- ELFAdrGOTPage21,
- ELFLd64GOTLo12,
- ELFTLSDescAdrPage21,
- ELFTLSDescAddLo12,
- ELFTLSDescLd64Lo12,
- ELFTLSDescCall,
- };
- static Expected<ELFAArch64RelocationKind>
- getRelocationKind(const uint32_t Type) {
- using namespace aarch64;
- switch (Type) {
- case ELF::R_AARCH64_CALL26:
- case ELF::R_AARCH64_JUMP26:
- return ELFCall26;
- case ELF::R_AARCH64_ADR_PREL_PG_HI21:
- return ELFAdrPage21;
- case ELF::R_AARCH64_ADD_ABS_LO12_NC:
- return ELFAddAbs12;
- case ELF::R_AARCH64_LDST8_ABS_LO12_NC:
- return ELFLdSt8Abs12;
- case ELF::R_AARCH64_LDST16_ABS_LO12_NC:
- return ELFLdSt16Abs12;
- case ELF::R_AARCH64_LDST32_ABS_LO12_NC:
- return ELFLdSt32Abs12;
- case ELF::R_AARCH64_LDST64_ABS_LO12_NC:
- return ELFLdSt64Abs12;
- case ELF::R_AARCH64_LDST128_ABS_LO12_NC:
- return ELFLdSt128Abs12;
- case ELF::R_AARCH64_MOVW_UABS_G0_NC:
- return ELFMovwAbsG0;
- case ELF::R_AARCH64_MOVW_UABS_G1_NC:
- return ELFMovwAbsG1;
- case ELF::R_AARCH64_MOVW_UABS_G2_NC:
- return ELFMovwAbsG2;
- case ELF::R_AARCH64_MOVW_UABS_G3:
- return ELFMovwAbsG3;
- case ELF::R_AARCH64_ABS64:
- return ELFAbs64;
- case ELF::R_AARCH64_PREL32:
- return ELFPrel32;
- case ELF::R_AARCH64_PREL64:
- return ELFPrel64;
- case ELF::R_AARCH64_ADR_GOT_PAGE:
- return ELFAdrGOTPage21;
- case ELF::R_AARCH64_LD64_GOT_LO12_NC:
- return ELFLd64GOTLo12;
- case ELF::R_AARCH64_TLSDESC_ADR_PAGE21:
- return ELFTLSDescAdrPage21;
- case ELF::R_AARCH64_TLSDESC_ADD_LO12:
- return ELFTLSDescAddLo12;
- case ELF::R_AARCH64_TLSDESC_LD64_LO12:
- return ELFTLSDescLd64Lo12;
- case ELF::R_AARCH64_TLSDESC_CALL:
- return ELFTLSDescCall;
- }
- return make_error<JITLinkError>(
- "Unsupported aarch64 relocation:" + formatv("{0:d}: ", Type) +
- object::getELFRelocationTypeName(ELF::EM_AARCH64, Type));
- }
- Error addRelocations() override {
- LLVM_DEBUG(dbgs() << "Processing relocations:\n");
- using Base = ELFLinkGraphBuilder<ELFT>;
- using Self = ELFLinkGraphBuilder_aarch64<ELFT>;
- for (const auto &RelSect : Base::Sections)
- if (Error Err = Base::forEachRelaRelocation(RelSect, this,
- &Self::addSingleRelocation))
- return Err;
- return Error::success();
- }
- Error addSingleRelocation(const typename ELFT::Rela &Rel,
- const typename ELFT::Shdr &FixupSect,
- Block &BlockToFix) {
- using support::ulittle32_t;
- using Base = ELFLinkGraphBuilder<ELFT>;
- uint32_t SymbolIndex = Rel.getSymbol(false);
- auto ObjSymbol = Base::Obj.getRelocationSymbol(Rel, Base::SymTabSec);
- if (!ObjSymbol)
- return ObjSymbol.takeError();
- Symbol *GraphSymbol = Base::getGraphSymbol(SymbolIndex);
- if (!GraphSymbol)
- return make_error<StringError>(
- formatv("Could not find symbol at given index, did you add it to "
- "JITSymbolTable? index: {0}, shndx: {1} Size of table: {2}",
- SymbolIndex, (*ObjSymbol)->st_shndx,
- Base::GraphSymbols.size()),
- inconvertibleErrorCode());
- uint32_t Type = Rel.getType(false);
- Expected<ELFAArch64RelocationKind> RelocKind = getRelocationKind(Type);
- if (!RelocKind)
- return RelocKind.takeError();
- int64_t Addend = Rel.r_addend;
- orc::ExecutorAddr FixupAddress =
- orc::ExecutorAddr(FixupSect.sh_addr) + Rel.r_offset;
- Edge::OffsetT Offset = FixupAddress - BlockToFix.getAddress();
- // Get a pointer to the fixup content.
- const void *FixupContent = BlockToFix.getContent().data() +
- (FixupAddress - BlockToFix.getAddress());
- Edge::Kind Kind = Edge::Invalid;
- switch (*RelocKind) {
- case ELFCall26: {
- Kind = aarch64::Branch26PCRel;
- break;
- }
- case ELFAdrPage21: {
- Kind = aarch64::Page21;
- break;
- }
- case ELFAddAbs12: {
- Kind = aarch64::PageOffset12;
- break;
- }
- case ELFLdSt8Abs12: {
- uint32_t Instr = *(const ulittle32_t *)FixupContent;
- if (!aarch64::isLoadStoreImm12(Instr) ||
- aarch64::getPageOffset12Shift(Instr) != 0)
- return make_error<JITLinkError>(
- "R_AARCH64_LDST8_ABS_LO12_NC target is not a "
- "LDRB/STRB (imm12) instruction");
- Kind = aarch64::PageOffset12;
- break;
- }
- case ELFLdSt16Abs12: {
- uint32_t Instr = *(const ulittle32_t *)FixupContent;
- if (!aarch64::isLoadStoreImm12(Instr) ||
- aarch64::getPageOffset12Shift(Instr) != 1)
- return make_error<JITLinkError>(
- "R_AARCH64_LDST16_ABS_LO12_NC target is not a "
- "LDRH/STRH (imm12) instruction");
- Kind = aarch64::PageOffset12;
- break;
- }
- case ELFLdSt32Abs12: {
- uint32_t Instr = *(const ulittle32_t *)FixupContent;
- if (!aarch64::isLoadStoreImm12(Instr) ||
- aarch64::getPageOffset12Shift(Instr) != 2)
- return make_error<JITLinkError>(
- "R_AARCH64_LDST32_ABS_LO12_NC target is not a "
- "LDR/STR (imm12, 32 bit) instruction");
- Kind = aarch64::PageOffset12;
- break;
- }
- case ELFLdSt64Abs12: {
- uint32_t Instr = *(const ulittle32_t *)FixupContent;
- if (!aarch64::isLoadStoreImm12(Instr) ||
- aarch64::getPageOffset12Shift(Instr) != 3)
- return make_error<JITLinkError>(
- "R_AARCH64_LDST64_ABS_LO12_NC target is not a "
- "LDR/STR (imm12, 64 bit) instruction");
- Kind = aarch64::PageOffset12;
- break;
- }
- case ELFLdSt128Abs12: {
- uint32_t Instr = *(const ulittle32_t *)FixupContent;
- if (!aarch64::isLoadStoreImm12(Instr) ||
- aarch64::getPageOffset12Shift(Instr) != 4)
- return make_error<JITLinkError>(
- "R_AARCH64_LDST128_ABS_LO12_NC target is not a "
- "LDR/STR (imm12, 128 bit) instruction");
- Kind = aarch64::PageOffset12;
- break;
- }
- case ELFMovwAbsG0: {
- uint32_t Instr = *(const ulittle32_t *)FixupContent;
- if (!aarch64::isMoveWideImm16(Instr) ||
- aarch64::getMoveWide16Shift(Instr) != 0)
- return make_error<JITLinkError>(
- "R_AARCH64_MOVW_UABS_G0_NC target is not a "
- "MOVK/MOVZ (imm16, LSL #0) instruction");
- Kind = aarch64::MoveWide16;
- break;
- }
- case ELFMovwAbsG1: {
- uint32_t Instr = *(const ulittle32_t *)FixupContent;
- if (!aarch64::isMoveWideImm16(Instr) ||
- aarch64::getMoveWide16Shift(Instr) != 16)
- return make_error<JITLinkError>(
- "R_AARCH64_MOVW_UABS_G1_NC target is not a "
- "MOVK/MOVZ (imm16, LSL #16) instruction");
- Kind = aarch64::MoveWide16;
- break;
- }
- case ELFMovwAbsG2: {
- uint32_t Instr = *(const ulittle32_t *)FixupContent;
- if (!aarch64::isMoveWideImm16(Instr) ||
- aarch64::getMoveWide16Shift(Instr) != 32)
- return make_error<JITLinkError>(
- "R_AARCH64_MOVW_UABS_G2_NC target is not a "
- "MOVK/MOVZ (imm16, LSL #32) instruction");
- Kind = aarch64::MoveWide16;
- break;
- }
- case ELFMovwAbsG3: {
- uint32_t Instr = *(const ulittle32_t *)FixupContent;
- if (!aarch64::isMoveWideImm16(Instr) ||
- aarch64::getMoveWide16Shift(Instr) != 48)
- return make_error<JITLinkError>(
- "R_AARCH64_MOVW_UABS_G3 target is not a "
- "MOVK/MOVZ (imm16, LSL #48) instruction");
- Kind = aarch64::MoveWide16;
- break;
- }
- case ELFAbs64: {
- Kind = aarch64::Pointer64;
- break;
- }
- case ELFPrel32: {
- Kind = aarch64::Delta32;
- break;
- }
- case ELFPrel64: {
- Kind = aarch64::Delta64;
- break;
- }
- case ELFAdrGOTPage21: {
- Kind = aarch64::RequestGOTAndTransformToPage21;
- break;
- }
- case ELFLd64GOTLo12: {
- Kind = aarch64::RequestGOTAndTransformToPageOffset12;
- break;
- }
- case ELFTLSDescAdrPage21: {
- Kind = aarch64::RequestTLSDescEntryAndTransformToPage21;
- break;
- }
- case ELFTLSDescAddLo12:
- case ELFTLSDescLd64Lo12: {
- Kind = aarch64::RequestTLSDescEntryAndTransformToPageOffset12;
- break;
- }
- case ELFTLSDescCall: {
- return Error::success();
- }
- };
- Edge GE(Kind, Offset, *GraphSymbol, Addend);
- LLVM_DEBUG({
- dbgs() << " ";
- printEdge(dbgs(), BlockToFix, GE, aarch64::getEdgeKindName(Kind));
- dbgs() << "\n";
- });
- BlockToFix.addEdge(std::move(GE));
- return Error::success();
- }
- /// Return the string name of the given ELF aarch64 edge kind.
- const char *getELFAArch64RelocationKindName(Edge::Kind R) {
- switch (R) {
- case ELFCall26:
- return "ELFCall26";
- case ELFAdrPage21:
- return "ELFAdrPage21";
- case ELFAddAbs12:
- return "ELFAddAbs12";
- case ELFLdSt8Abs12:
- return "ELFLdSt8Abs12";
- case ELFLdSt16Abs12:
- return "ELFLdSt16Abs12";
- case ELFLdSt32Abs12:
- return "ELFLdSt32Abs12";
- case ELFLdSt64Abs12:
- return "ELFLdSt64Abs12";
- case ELFLdSt128Abs12:
- return "ELFLdSt128Abs12";
- case ELFMovwAbsG0:
- return "ELFMovwAbsG0";
- case ELFMovwAbsG1:
- return "ELFMovwAbsG1";
- case ELFMovwAbsG2:
- return "ELFMovwAbsG2";
- case ELFMovwAbsG3:
- return "ELFMovwAbsG3";
- case ELFAbs64:
- return "ELFAbs64";
- case ELFPrel32:
- return "ELFPrel32";
- case ELFPrel64:
- return "ELFPrel64";
- case ELFAdrGOTPage21:
- return "ELFAdrGOTPage21";
- case ELFLd64GOTLo12:
- return "ELFLd64GOTLo12";
- case ELFTLSDescAdrPage21:
- return "ELFTLSDescAdrPage21";
- case ELFTLSDescAddLo12:
- return "ELFTLSDescAddLo12";
- case ELFTLSDescLd64Lo12:
- return "ELFTLSDescLd64Lo12";
- case ELFTLSDescCall:
- return "ELFTLSDescCall";
- default:
- return getGenericEdgeKindName(static_cast<Edge::Kind>(R));
- }
- }
- public:
- ELFLinkGraphBuilder_aarch64(StringRef FileName,
- const object::ELFFile<ELFT> &Obj, const Triple T)
- : ELFLinkGraphBuilder<ELFT>(Obj, std::move(T), FileName,
- aarch64::getEdgeKindName) {}
- };
- // TLS Info Builder.
- class TLSInfoTableManager_ELF_aarch64
- : public TableManager<TLSInfoTableManager_ELF_aarch64> {
- public:
- static StringRef getSectionName() { return "$__TLSINFO"; }
- static const uint8_t TLSInfoEntryContent[16];
- bool visitEdge(LinkGraph &G, Block *B, Edge &E) { return false; }
- Symbol &createEntry(LinkGraph &G, Symbol &Target) {
- // the TLS Info entry's key value will be written by the fixTLVSectionByName
- // pass, so create mutable content.
- auto &TLSInfoEntry = G.createMutableContentBlock(
- getTLSInfoSection(G), G.allocateContent(getTLSInfoEntryContent()),
- orc::ExecutorAddr(), 8, 0);
- TLSInfoEntry.addEdge(aarch64::Pointer64, 8, Target, 0);
- return G.addAnonymousSymbol(TLSInfoEntry, 0, 16, false, false);
- }
- private:
- Section &getTLSInfoSection(LinkGraph &G) {
- if (!TLSInfoTable)
- TLSInfoTable = &G.createSection(getSectionName(), orc::MemProt::Read);
- return *TLSInfoTable;
- }
- ArrayRef<char> getTLSInfoEntryContent() const {
- return {reinterpret_cast<const char *>(TLSInfoEntryContent),
- sizeof(TLSInfoEntryContent)};
- }
- Section *TLSInfoTable = nullptr;
- };
- const uint8_t TLSInfoTableManager_ELF_aarch64::TLSInfoEntryContent[16] = {
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /*pthread key */
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /*data address*/
- };
- // TLS Descriptor Builder.
- class TLSDescTableManager_ELF_aarch64
- : public TableManager<TLSDescTableManager_ELF_aarch64> {
- public:
- TLSDescTableManager_ELF_aarch64(
- TLSInfoTableManager_ELF_aarch64 &TLSInfoTableManager)
- : TLSInfoTableManager(TLSInfoTableManager) {}
- static StringRef getSectionName() { return "$__TLSDESC"; }
- static const uint8_t TLSDescEntryContent[16];
- bool visitEdge(LinkGraph &G, Block *B, Edge &E) {
- Edge::Kind KindToSet = Edge::Invalid;
- switch (E.getKind()) {
- case aarch64::RequestTLSDescEntryAndTransformToPage21: {
- KindToSet = aarch64::Page21;
- break;
- }
- case aarch64::RequestTLSDescEntryAndTransformToPageOffset12: {
- KindToSet = aarch64::PageOffset12;
- break;
- }
- default:
- return false;
- }
- assert(KindToSet != Edge::Invalid &&
- "Fell through switch, but no new kind to set");
- DEBUG_WITH_TYPE("jitlink", {
- dbgs() << " Fixing " << G.getEdgeKindName(E.getKind()) << " edge at "
- << B->getFixupAddress(E) << " (" << B->getAddress() << " + "
- << formatv("{0:x}", E.getOffset()) << ")\n";
- });
- E.setKind(KindToSet);
- E.setTarget(getEntryForTarget(G, E.getTarget()));
- return true;
- }
- Symbol &createEntry(LinkGraph &G, Symbol &Target) {
- auto &EntryBlock =
- G.createContentBlock(getTLSDescSection(G), getTLSDescBlockContent(),
- orc::ExecutorAddr(), 8, 0);
- EntryBlock.addEdge(aarch64::Pointer64, 0, getTLSDescResolver(G), 0);
- EntryBlock.addEdge(aarch64::Pointer64, 8,
- TLSInfoTableManager.getEntryForTarget(G, Target), 0);
- return G.addAnonymousSymbol(EntryBlock, 0, 8, false, false);
- }
- private:
- Section &getTLSDescSection(LinkGraph &G) {
- if (!GOTSection)
- GOTSection = &G.createSection(getSectionName(), orc::MemProt::Read);
- return *GOTSection;
- }
- Symbol &getTLSDescResolver(LinkGraph &G) {
- if (!TLSDescResolver)
- TLSDescResolver = &G.addExternalSymbol("__tlsdesc_resolver", 8, false);
- return *TLSDescResolver;
- }
- ArrayRef<char> getTLSDescBlockContent() {
- return {reinterpret_cast<const char *>(TLSDescEntryContent),
- sizeof(TLSDescEntryContent)};
- }
- Section *GOTSection = nullptr;
- Symbol *TLSDescResolver = nullptr;
- TLSInfoTableManager_ELF_aarch64 &TLSInfoTableManager;
- };
- const uint8_t TLSDescTableManager_ELF_aarch64::TLSDescEntryContent[16] = {
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, /*resolver function pointer*/
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00 /*pointer to tls info*/
- };
- Error buildTables_ELF_aarch64(LinkGraph &G) {
- LLVM_DEBUG(dbgs() << "Visiting edges in graph:\n");
- aarch64::GOTTableManager GOT;
- aarch64::PLTTableManager PLT(GOT);
- TLSInfoTableManager_ELF_aarch64 TLSInfo;
- TLSDescTableManager_ELF_aarch64 TLSDesc(TLSInfo);
- visitExistingEdges(G, GOT, PLT, TLSDesc, TLSInfo);
- return Error::success();
- }
- } // namespace
- namespace llvm {
- namespace jitlink {
- Expected<std::unique_ptr<LinkGraph>>
- createLinkGraphFromELFObject_aarch64(MemoryBufferRef ObjectBuffer) {
- LLVM_DEBUG({
- dbgs() << "Building jitlink graph for new input "
- << ObjectBuffer.getBufferIdentifier() << "...\n";
- });
- auto ELFObj = object::ObjectFile::createELFObjectFile(ObjectBuffer);
- if (!ELFObj)
- return ELFObj.takeError();
- assert((*ELFObj)->getArch() == Triple::aarch64 &&
- "Only AArch64 (little endian) is supported for now");
- auto &ELFObjFile = cast<object::ELFObjectFile<object::ELF64LE>>(**ELFObj);
- return ELFLinkGraphBuilder_aarch64<object::ELF64LE>((*ELFObj)->getFileName(),
- ELFObjFile.getELFFile(),
- (*ELFObj)->makeTriple())
- .buildGraph();
- }
- void link_ELF_aarch64(std::unique_ptr<LinkGraph> G,
- std::unique_ptr<JITLinkContext> Ctx) {
- PassConfiguration Config;
- const Triple &TT = G->getTargetTriple();
- if (Ctx->shouldAddDefaultTargetPasses(TT)) {
- // Add eh-frame passses.
- Config.PrePrunePasses.push_back(DWARFRecordSectionSplitter(".eh_frame"));
- Config.PrePrunePasses.push_back(EHFrameEdgeFixer(
- ".eh_frame", 8, aarch64::Pointer32, aarch64::Pointer64,
- aarch64::Delta32, aarch64::Delta64, aarch64::NegDelta32));
- // Add a mark-live pass.
- if (auto MarkLive = Ctx->getMarkLivePass(TT))
- Config.PrePrunePasses.push_back(std::move(MarkLive));
- else
- Config.PrePrunePasses.push_back(markAllSymbolsLive);
- // Add an in-place GOT/TLS/Stubs build pass.
- Config.PostPrunePasses.push_back(buildTables_ELF_aarch64);
- }
- if (auto Err = Ctx->modifyPassConfig(*G, Config))
- return Ctx->notifyFailed(std::move(Err));
- ELFJITLinker_aarch64::link(std::move(Ctx), std::move(G), std::move(Config));
- }
- } // namespace jitlink
- } // namespace llvm
|