[llvm] 87c4268 - [JITLink][ELF][AArch64] Implement Procedure Linkage Table.

Sunho Kim via llvm-commits llvm-commits at lists.llvm.org
Thu Jun 9 22:45:41 PDT 2022


Author: Sunho Kim
Date: 2022-06-10T14:44:33+09:00
New Revision: 87c4268329072153f178d554e138166d579f18b9

URL: https://github.com/llvm/llvm-project/commit/87c4268329072153f178d554e138166d579f18b9
DIFF: https://github.com/llvm/llvm-project/commit/87c4268329072153f178d554e138166d579f18b9.diff

LOG: [JITLink][ELF][AArch64] Implement Procedure Linkage Table.

Implements Procedure Linkage Table (PLT) for ELF/AARCH64. The aarch64 linux calling convention also uses r16 as the intra-procedure-call scratch register same as MachO/ARM64. We can use the same stub sequence for this reason.

Also, BR regiseter doesn't touch X30 register. External function call by BL instruction (touched by CALL26 relocation) will set X30 to the original PC + 4, which is the intended behavior. External function call by B instruction (touched by JUMP26 relocation) doesn't requite to set X30, so the patch will be correct in this case too.

Reference: https://github.com/ARM-software/abi-aa/blob/main/aapcs64/aapcs64.rst#611general-purpose-registers

Reviewed By: lhames

Differential Revision: https://reviews.llvm.org/D127061

Added: 
    

Modified: 
    llvm/lib/ExecutionEngine/JITLink/ELF_aarch64.cpp
    llvm/test/ExecutionEngine/JITLink/AArch64/ELF_aarch64_relocations.s

Removed: 
    


################################################################################
diff  --git a/llvm/lib/ExecutionEngine/JITLink/ELF_aarch64.cpp b/llvm/lib/ExecutionEngine/JITLink/ELF_aarch64.cpp
index ae9963735c61..0f6f73192e17 100644
--- a/llvm/lib/ExecutionEngine/JITLink/ELF_aarch64.cpp
+++ b/llvm/lib/ExecutionEngine/JITLink/ELF_aarch64.cpp
@@ -321,14 +321,24 @@ class PerGraphGOTAndPLTStubsBuilder_ELF_arm64
       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 @@ class PerGraphGOTAndPLTStubsBuilder_ELF_arm64
     return *GOTSection;
   }
 
+  Section &getStubsSection() {
+    if (!StubsSection)
+      StubsSection =
+          &G.createSection("$__STUBS", MemProt::Read | MemProt::Exec);
+    return *StubsSection;
+  }
+
   ArrayRef<char> getGOTEntryBlockContent() {
     return {reinterpret_cast<const char *>(NullGOTEntryContent),
             sizeof(NullGOTEntryContent)};
   }
 
+  ArrayRef<char> getStubBlockContent() {
+    return {reinterpret_cast<const char *>(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, <literal>
+    0x00, 0x02, 0x1f, 0xd6  // BR  x16
+};
 
 Expected<std::unique_ptr<LinkGraph>>
 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
index 86048783432b..8714f09095c8 100644
--- 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 @@ test_add_abs_lo12:
         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 @@ local_func_addr_quad:
         .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.


        


More information about the llvm-commits mailing list