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 @@ -321,14 +321,24 @@ llvm_unreachable("Not a GOT edge?"); } - bool isExternalBranchEdge(Edge &E) { return false; } + bool isExternalBranchEdge(Edge &E) { + return E.getKind() == aarch64::Branch26 && !E.getTarget().isDefined(); + } Symbol &createPLTStub(Symbol &Target) { - assert(false && "unimplemetned"); - return Target; + auto &StubContentBlock = G.createContentBlock( + getStubsSection(), getStubBlockContent(), orc::ExecutorAddr(), 1, 0); + // Re-use GOT entries for stub targets. + auto &GOTEntrySymbol = getGOTEntry(Target); + StubContentBlock.addEdge(aarch64::LDRLiteral19, 0, GOTEntrySymbol, 0); + return G.addAnonymousSymbol(StubContentBlock, 0, 8, true, false); } - void fixPLTEdge(Edge &E, Symbol &Stub) { assert(false && "unimplemetned"); } + void fixPLTEdge(Edge &E, Symbol &Stub) { + assert(E.getKind() == aarch64::Branch26 && "Not a Branch26 edge?"); + assert(E.getAddend() == 0 && "Branch26 edge has non-zero addend?"); + E.setTarget(Stub); + } private: Section &getGOTSection() { @@ -337,17 +347,34 @@ return *GOTSection; } + Section &getStubsSection() { + if (!StubsSection) + StubsSection = + &G.createSection("$__STUBS", MemProt::Read | MemProt::Exec); + return *StubsSection; + } + ArrayRef getGOTEntryBlockContent() { return {reinterpret_cast(NullGOTEntryContent), sizeof(NullGOTEntryContent)}; } + ArrayRef getStubBlockContent() { + return {reinterpret_cast(StubContent), sizeof(StubContent)}; + } + static const uint8_t NullGOTEntryContent[8]; + static const uint8_t StubContent[8]; Section *GOTSection = nullptr; + Section *StubsSection = nullptr; }; const uint8_t PerGraphGOTAndPLTStubsBuilder_ELF_arm64::NullGOTEntryContent[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; +const uint8_t PerGraphGOTAndPLTStubsBuilder_ELF_arm64::StubContent[8] = { + 0x10, 0x00, 0x00, 0x58, // LDR x16, + 0x00, 0x02, 0x1f, 0xd6 // BR x16 +}; Expected> createLinkGraphFromELFObject_aarch64(MemoryBufferRef ObjectBuffer) { 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 @@ -3,6 +3,7 @@ # RUN: -position-independent -filetype=obj -o %t/elf_reloc.o %s # RUN: llvm-jitlink -noexec \ # RUN: -abs external_data=0xdeadbeef \ +# RUN: -abs external_func=0xcafef00d \ # RUN: -check %s %t/elf_reloc.o .text @@ -57,6 +58,24 @@ add x0, x0, :lo12:named_data .size test_add_abs_lo12, .-test_add_abs_lo12 +# Check that calls/jumps to external functions trigger the generation of stubs and GOT +# entries. +# +# jitlink-check: decode_operand(test_external_call, 0) = (stub_addr(elf_reloc.o, external_func) - test_external_call)[27:2] +# jitlink-check: decode_operand(test_external_jump, 0) = (stub_addr(elf_reloc.o, external_func) - test_external_jump)[27:2] +# jitlink-check: *{8}(got_addr(elf_reloc.o, external_func)) = external_func + .globl test_external_call + .p2align 2 +test_external_call: + bl external_func + .size test_external_call, .-test_external_call + + .globl test_external_jump + .p2align 2 +test_external_jump: + b external_func + .size test_external_jump, .-test_external_jump + # Check R_AARCH64_LDST*_ABS_LO12_NC relocation of a local symbol # # The immediate value should be the symbol address right shifted according to its instruction bitwidth. @@ -131,6 +150,15 @@ .xword named_func .size local_func_addr_quad, 8 +# Check R_AARCH64_ABS64 relocation of a function pointer to external symbol +# +# jitlink-check: *{8}external_func_addr_quad = external_func + .globl external_func_addr_quad + .p2align 3 +external_func_addr_quad: + .xword external_func + .size external_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.