diff --git a/llvm/lib/ExecutionEngine/JITLink/ELF_aarch64.cpp b/llvm/lib/ExecutionEngine/JITLink/ELF_aarch64.cpp --- a/llvm/lib/ExecutionEngine/JITLink/ELF_aarch64.cpp +++ b/llvm/lib/ExecutionEngine/JITLink/ELF_aarch64.cpp @@ -19,6 +19,8 @@ #include "llvm/Support/Endian.h" #include "llvm/Support/MathExtras.h" +#include "PerGraphGOTAndPLTStubsBuilder.h" + #define DEBUG_TYPE "jitlink" using namespace llvm; @@ -55,6 +57,8 @@ ELFLdSt64Abs12, ELFLdSt128Abs12, ELFAbs64, + ELFAdrGOTPage21, + ELFLd64GOTLo12, }; static Expected @@ -79,6 +83,10 @@ return ELFLdSt128Abs12; case ELF::R_AARCH64_ABS64: return ELFAbs64; + case ELF::R_AARCH64_ADR_GOT_PAGE: + return ELFAdrGOTPage21; + case ELF::R_AARCH64_LD64_GOT_LO12_NC: + return ELFLd64GOTLo12; } return make_error("Unsupported aarch64 relocation:" + @@ -206,6 +214,14 @@ Kind = aarch64::Pointer64; break; } + case ELFAdrGOTPage21: { + Kind = aarch64::GOTPage21; + break; + } + case ELFLd64GOTLo12: { + Kind = aarch64::GOTPageOffset12; + break; + } }; Edge GE(Kind, Offset, *GraphSymbol, Addend); @@ -240,6 +256,10 @@ return "ELFLdSt128Abs12"; case ELFAbs64: return "ELFAbs64"; + case ELFAdrGOTPage21: + return "ELFAdrGOTPage21"; + case ELFLd64GOTLo12: + return "ELFLd64GOTLo12"; default: return getGenericEdgeKindName(static_cast(R)); } @@ -252,6 +272,64 @@ aarch64::getEdgeKindName) {} }; +class PerGraphGOTAndPLTStubsBuilder_ELF_arm64 + : public PerGraphGOTAndPLTStubsBuilder< + PerGraphGOTAndPLTStubsBuilder_ELF_arm64> { +public: + using PerGraphGOTAndPLTStubsBuilder< + PerGraphGOTAndPLTStubsBuilder_ELF_arm64>::PerGraphGOTAndPLTStubsBuilder; + + bool isGOTEdgeToFix(Edge &E) const { + return E.getKind() == aarch64::GOTPage21 || + E.getKind() == aarch64::GOTPageOffset12; + } + + Symbol &createGOTEntry(Symbol &Target) { + auto &GOTEntryBlock = G.createContentBlock( + getGOTSection(), getGOTEntryBlockContent(), orc::ExecutorAddr(), 8, 0); + GOTEntryBlock.addEdge(aarch64::Pointer64, 0, Target, 0); + return G.addAnonymousSymbol(GOTEntryBlock, 0, 8, false, false); + } + + void fixGOTEdge(Edge &E, Symbol &GOTEntry) { + if (E.getKind() == aarch64::GOTPage21) { + E.setKind(aarch64::Page21); + E.setTarget(GOTEntry); + } else if (E.getKind() == aarch64::GOTPageOffset12) { + E.setKind(aarch64::PageOffset12); + E.setTarget(GOTEntry); + } else + llvm_unreachable("Not a GOT edge?"); + } + + bool isExternalBranchEdge(Edge &E) { return false; } + + Symbol &createPLTStub(Symbol &Target) { + assert(false && "unimplemetned"); + return Target; + } + + void fixPLTEdge(Edge &E, Symbol &Stub) { assert(false && "unimplemetned"); } + +private: + Section &getGOTSection() { + if (!GOTSection) + GOTSection = &G.createSection("$__GOT", MemProt::Read | MemProt::Exec); + return *GOTSection; + } + + ArrayRef getGOTEntryBlockContent() { + return {reinterpret_cast(NullGOTEntryContent), + sizeof(NullGOTEntryContent)}; + } + + static const uint8_t NullGOTEntryContent[8]; + Section *GOTSection = nullptr; +}; + +const uint8_t PerGraphGOTAndPLTStubsBuilder_ELF_arm64::NullGOTEntryContent[8] = + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + Expected> createLinkGraphFromELFObject_aarch64(MemoryBufferRef ObjectBuffer) { LLVM_DEBUG({ @@ -283,6 +361,10 @@ else Config.PrePrunePasses.push_back(markAllSymbolsLive); } + + Config.PostPrunePasses.push_back( + PerGraphGOTAndPLTStubsBuilder_ELF_arm64::asPass); + if (auto Err = Ctx->modifyPassConfig(*G, Config)) return Ctx->notifyFailed(std::move(Err)); diff --git a/llvm/test/ExecutionEngine/JITLink/AArch64/ELF_aarch64_relocations.s b/llvm/test/ExecutionEngine/JITLink/AArch64/ELF_aarch64_relocations.s --- a/llvm/test/ExecutionEngine/JITLink/AArch64/ELF_aarch64_relocations.s +++ b/llvm/test/ExecutionEngine/JITLink/AArch64/ELF_aarch64_relocations.s @@ -1,7 +1,9 @@ # RUN: rm -rf %t && mkdir -p %t # RUN: llvm-mc -triple=aarch64-unknown-linux-gnu -relax-relocations=false \ # RUN: -position-independent -filetype=obj -o %t/elf_reloc.o %s -# RUN: llvm-jitlink -noexec -check %s %t/elf_reloc.o +# RUN: llvm-jitlink -noexec \ +# RUN: -abs external_data=0xdeadbeef \ +# RUN: -check %s %t/elf_reloc.o .text @@ -123,6 +125,34 @@ .xword named_func .size local_func_addr_quad, 8 +# Check R_AARCH64_ADR_GOT_PAGE / R_AARCH64_LD64_GOT_LO12_NC handling with a +# reference to an external symbol. Validate both the reference to the GOT entry, +# and also the content of the GOT entry. +# +# For the ADRP :got: instruction we have the 21-bit delta to the 4k page +# containing the GOT entry for external_data. +# +# For the LDR :got_lo12: instruction we have the 12-bit offset of the entry +# within the page. +# +# jitlink-check: *{8}(got_addr(elf_reloc.o, external_data)) = external_data +# jitlink-check: decode_operand(test_adr_gotpage_external, 1) = \ +# jitlink-check: (got_addr(elf_reloc.o, external_data)[32:12] - \ +# jitlink-check: test_adr_gotpage_external[32:12]) +# jitlink-check: decode_operand(test_ld64_gotlo12_external, 2) = \ +# jitlink-check: got_addr(elf_reloc.o, external_data)[11:3] + .globl test_adr_gotpage_external + .p2align 2 +test_adr_gotpage_external: + adrp x0, :got:external_data + .size test_adr_gotpage_external, .-test_adr_gotpage_external + + .globl test_ld64_gotlo12_external + .p2align 2 +test_ld64_gotlo12_external: + ldr x0, [x0, :got_lo12:external_data] + .size test_ld64_gotlo12_external, .-test_ld64_gotlo12_external + .globl named_data .p2align 4 .type named_data,@object