Implements TLS descriptor relocations in JITLink ELF/AARCH64 backend and support the relevant runtime functions in ELFNixPlatform. Unlike traditional TLS model, TLS descriptor model requires linker to return the "offset" from thread pointer via relocaiton not the actual pointer to thread local variable. There is no public libc api for adding new allocations to TLS block dynamically which thread pointer points to. So, we support this by taking delta from thread base pointer to the actual thread local variable in our allocated section. Reviewed By: lhames Differential Revision: https://reviews.llvm.org/D128601
578 lines
18 KiB
C++
578 lines
18 KiB
C++
//===----- 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::forEachRelocation(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::Branch26;
|
|
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::GOTPage21;
|
|
break;
|
|
}
|
|
case ELFLd64GOTLo12: {
|
|
Kind = aarch64::GOTPageOffset12;
|
|
break;
|
|
}
|
|
case ELFTLSDescAdrPage21: {
|
|
Kind = aarch64::TLSDescPage21;
|
|
break;
|
|
}
|
|
case ELFTLSDescAddLo12: {
|
|
Kind = aarch64::TLSDescPageOffset12;
|
|
break;
|
|
}
|
|
case ELFTLSDescLd64Lo12: {
|
|
Kind = aarch64::TLSDescPageOffset12;
|
|
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(), 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::TLSDescPage21: {
|
|
KindToSet = aarch64::Page21;
|
|
break;
|
|
}
|
|
case aarch64::TLSDescPageOffset12: {
|
|
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(), MemProt::Read);
|
|
return *GOTSection;
|
|
}
|
|
|
|
Symbol &getTLSDescResolver(LinkGraph &G) {
|
|
if (!TLSDescResolver)
|
|
TLSDescResolver =
|
|
&G.addExternalSymbol("__tlsdesc_resolver", 8, Linkage::Strong);
|
|
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
|