[llvm] [llvm-jitlink] Support plain AArch32 range extension stubs in jitlink-check's stub_addr() expressions (PR #73268)

Stefan Gränitz via llvm-commits llvm-commits at lists.llvm.org
Thu Nov 23 15:28:53 PST 2023


https://github.com/weliveindetail created https://github.com/llvm/llvm-project/pull/73268

We want to use regular `stub_addr()` expressions in `jitlink-check` lines to test the generation of stubs in AArch32, but we don't want this to require a standardized GOT-based PLT implementation. In terms of performance and binary size it doesn't seem beneficial. And in terms of patching, we should be able to handle range-extension- and interworking-stubs without a lot of extra logic.

This patch adds a separate path for AArch32 stubs in `llvm-jitlink-elf` to allow it. The relocations in our stubs are not pointing to the GOT, but to the external symbol directly. Thus, we have to avoid access to the block of the edge target. Instead we only return the symbol name. This is enough to use `stub_addr()` expressions in tests.

In order to allow decoding of stub target addresses in the future, we mention the stub flavor in the section name.

>From ada456bfe5eb372d38402fdd69234841c1ec0680 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Stefan=20Gr=C3=A4nitz?= <stefan.graenitz at gmail.com>
Date: Thu, 23 Nov 2023 22:46:19 +0100
Subject: [PATCH] [llvm-jitlink] Support plain AArch32 range extension stubs in
 rtdyld-check's stub_addr() expressions

---
 .../llvm/ExecutionEngine/JITLink/aarch32.h    |  6 ++-
 .../JITLink/AArch32/ELF_thumb_stubs.s         | 44 +++++++++++++++++++
 llvm/tools/llvm-jitlink/llvm-jitlink-elf.cpp  | 27 ++++++++++++
 3 files changed, 76 insertions(+), 1 deletion(-)
 create mode 100644 llvm/test/ExecutionEngine/JITLink/AArch32/ELF_thumb_stubs.s

diff --git a/llvm/include/llvm/ExecutionEngine/JITLink/aarch32.h b/llvm/include/llvm/ExecutionEngine/JITLink/aarch32.h
index 94669e0bceb836d..ec28db415c04625 100644
--- a/llvm/include/llvm/ExecutionEngine/JITLink/aarch32.h
+++ b/llvm/include/llvm/ExecutionEngine/JITLink/aarch32.h
@@ -295,7 +295,7 @@ class StubsManager : public TableManager<StubsManager<Flavor>> {
   StubsManager() = default;
 
   /// Name of the object file section that will contain all our stubs.
-  static StringRef getSectionName() { return "__llvm_jitlink_STUBS"; }
+  static StringRef getSectionName();
 
   /// Implements link-graph traversal via visitExistingEdges().
   bool visitEdge(LinkGraph &G, Block *B, Edge &E) {
@@ -345,6 +345,10 @@ class StubsManager : public TableManager<StubsManager<Flavor>> {
 template <>
 Symbol &StubsManager<Thumbv7>::createEntry(LinkGraph &G, Symbol &Target);
 
+template <> inline StringRef StubsManager<Thumbv7>::getSectionName() {
+  return "__llvm_jitlink_aarch32_STUBS_Thumbv7";
+}
+
 } // namespace aarch32
 } // namespace jitlink
 } // namespace llvm
diff --git a/llvm/test/ExecutionEngine/JITLink/AArch32/ELF_thumb_stubs.s b/llvm/test/ExecutionEngine/JITLink/AArch32/ELF_thumb_stubs.s
new file mode 100644
index 000000000000000..d1bb39f949efa87
--- /dev/null
+++ b/llvm/test/ExecutionEngine/JITLink/AArch32/ELF_thumb_stubs.s
@@ -0,0 +1,44 @@
+# RUN: rm -rf %t && mkdir -p %t
+# RUN: llvm-mc -triple=thumbv7-linux-gnueabi -arm-add-build-attributes \
+# RUN:         -filetype=obj -filetype=obj -o %t/elf_stubs.o %s
+# RUN: llvm-jitlink -noexec -slab-address 0x76ff0000 \
+# RUN:              -slab-allocate 10Kb -slab-page-size 4096 \
+# RUN:              -abs external_func=0x76bbe880 \
+# RUN:              -check %s %t/elf_stubs.o
+
+	.text
+	.syntax unified
+
+# Check that calls/jumps to external functions trigger the generation of stubs
+# and GOT entries. The GOT entry contains the absolute address of the external
+# function. The stub loads it and branches there.
+#
+# jitlink-check: decode_operand(test_external_call, 2) = stub_addr(elf_stubs.o, external_func) - next_pc(test_external_call)
+# jitlink-check: decode_operand(test_external_jump, 0) = stub_addr(elf_stubs.o, external_func) - next_pc(test_external_jump)
+	.globl  test_external_call
+	.type	test_external_call,%function
+	.p2align	1
+	.code	16
+	.thumb_func
+test_external_call:
+	bl	external_func
+	.size test_external_call, .-test_external_call
+
+	.globl  test_external_jump
+	.type	test_external_call,%function
+	.p2align	1
+	.code	16
+	.thumb_func
+test_external_jump:
+	b	external_func
+	.size test_external_jump, .-test_external_jump
+
+# Empty main function for jitlink to be happy
+	.globl	main
+	.type	main,%function
+	.p2align	1
+	.code	16
+	.thumb_func
+main:
+	bx	lr
+	.size	main,	.-main
diff --git a/llvm/tools/llvm-jitlink/llvm-jitlink-elf.cpp b/llvm/tools/llvm-jitlink/llvm-jitlink-elf.cpp
index 7881660d1a73851..9ed73a8c45a9a9c 100644
--- a/llvm/tools/llvm-jitlink/llvm-jitlink-elf.cpp
+++ b/llvm/tools/llvm-jitlink/llvm-jitlink-elf.cpp
@@ -12,6 +12,7 @@
 
 #include "llvm-jitlink.h"
 
+#include "llvm/ExecutionEngine/Orc/Core.h"
 #include "llvm/Support/Error.h"
 #include "llvm/Support/Path.h"
 
@@ -24,6 +25,10 @@ static bool isELFGOTSection(Section &S) { return S.getName() == "$__GOT"; }
 
 static bool isELFStubsSection(Section &S) { return S.getName() == "$__STUBS"; }
 
+static bool isELFAArch32StubsSection(Section &S) {
+  return S.getName().starts_with("__llvm_jitlink_aarch32_STUBS_");
+}
+
 static Expected<Edge &> getFirstRelocationEdge(LinkGraph &G, Block &B) {
   auto EItr =
       llvm::find_if(B.edges(), [](Edge &E) { return E.isRelocation(); });
@@ -64,6 +69,15 @@ static Expected<Symbol &> getELFStubTarget(LinkGraph &G, Block &B) {
   return getELFGOTTarget(G, GOTSym.getBlock());
 }
 
+static Expected<std::string>
+getELFAArch32StubTargetName(LinkGraph &G, Block &B, orc::ExecutionSession &ES) {
+  auto E = getFirstRelocationEdge(G, B);
+  if (!E)
+    return E.takeError();
+  Symbol &StubTarget = E->getTarget();
+  return StubTarget.getName().str();
+}
+
 namespace llvm {
 
 Error registerELFGraphInfo(Session &S, LinkGraph &G) {
@@ -98,6 +112,7 @@ Error registerELFGraphInfo(Session &S, LinkGraph &G) {
 
     bool isGOTSection = isELFGOTSection(Sec);
     bool isStubsSection = isELFStubsSection(Sec);
+    bool isAArch32StubsSection = isELFAArch32StubsSection(Sec);
 
     bool SectionContainsContent = false;
     bool SectionContainsZeroFill = false;
@@ -138,6 +153,18 @@ Error registerELFGraphInfo(Session &S, LinkGraph &G) {
         else
           return TS.takeError();
         SectionContainsContent = true;
+      } else if (isAArch32StubsSection) {
+        if (Sym->isSymbolZeroFill())
+          return make_error<StringError>("zero-fill atom in Stub section",
+                                         inconvertibleErrorCode());
+
+        if (auto Name = getELFAArch32StubTargetName(G, Sym->getBlock(), S.ES))
+          FileInfo.StubInfos[*Name] = {Sym->getSymbolContent(),
+                                       Sym->getAddress().getValue(),
+                                       Sym->getTargetFlags()};
+        else
+          return Name.takeError();
+        SectionContainsContent = true;
       }
 
       if (Sym->hasName()) {



More information about the llvm-commits mailing list