[llvm] 95dcb8b - [llvm-jitlink] Support plain AArch32 stubs in jitlink-check's stub_addr() expressions (#73268)

via llvm-commits llvm-commits at lists.llvm.org
Fri Nov 24 12:41:05 PST 2023


Author: Stefan Gränitz
Date: 2023-11-24T21:41:00+01:00
New Revision: 95dcb8b49dd3bb0fcb9f020fe931632a0ddf4994

URL: https://github.com/llvm/llvm-project/commit/95dcb8b49dd3bb0fcb9f020fe931632a0ddf4994
DIFF: https://github.com/llvm/llvm-project/commit/95dcb8b49dd3bb0fcb9f020fe931632a0ddf4994.diff

LOG: [llvm-jitlink] Support plain AArch32 stubs in jitlink-check's stub_addr() expressions (#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 branch targets, we should be able to handle range-extension- and interworking-stubs without a lot of extra logic.

In order to allow such AArch32 stubs we add a separate path for `stub_addr()` expressions in `llvm-jitlink-elf`. 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, which is enough to use `stub_addr()` expressions in tests.

The name of the AArch32 stubs section differs from the conventional `$__STUBS` on purpose. It allows to add a regular PLT/GOT implementation as an orthogonal feature in the future. In order to also allow decoding of stub target addresses in the future, we mention the stub flavor in the section name as well.

Added: 
    llvm/test/ExecutionEngine/JITLink/AArch32/ELF_thumb_stubs.s

Modified: 
    llvm/include/llvm/ExecutionEngine/JITLink/aarch32.h
    llvm/tools/llvm-jitlink/llvm-jitlink-elf.cpp

Removed: 
    


################################################################################
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..bd95c375279246a
--- /dev/null
+++ b/llvm/test/ExecutionEngine/JITLink/AArch32/ELF_thumb_stubs.s
@@ -0,0 +1,45 @@
+# 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
+# branch-range extension stubs. These stubs don't follow the default PLT model
+# where the branch-target address is loaded from a GOT entry. Instead, they
+# hard-code it in the immediate field.
+#
+# 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 4b7b3f9be701785..a02468758b33f68 100644
--- a/llvm/tools/llvm-jitlink/llvm-jitlink-elf.cpp
+++ b/llvm/tools/llvm-jitlink/llvm-jitlink-elf.cpp
@@ -24,6 +24,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(); });
@@ -68,6 +72,15 @@ static Expected<Symbol &> getELFStubTarget(LinkGraph &G, Block &B) {
   return getELFGOTTarget(G, GOTSym.getBlock());
 }
 
+static Expected<std::string> getELFAArch32StubTargetName(LinkGraph &G,
+                                                         Block &B) {
+  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) {
@@ -102,6 +115,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;
@@ -142,6 +156,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()))
+          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