[llvm] 5c98617 - [JITLink] Add public APIs for getting stub creation functions.

Sunho Kim via llvm-commits llvm-commits at lists.llvm.org
Fri Aug 4 17:50:03 PDT 2023


Author: Sunho Kim
Date: 2023-08-05T09:49:30+09:00
New Revision: 5c98617ccc4b4094032ae87856e03f6a402e5def

URL: https://github.com/llvm/llvm-project/commit/5c98617ccc4b4094032ae87856e03f6a402e5def
DIFF: https://github.com/llvm/llvm-project/commit/5c98617ccc4b4094032ae87856e03f6a402e5def.diff

LOG: [JITLink] Add public APIs for getting stub creation functions.

Creating stubs in JITLink require creating architecture-specific edges. In order to allow user to create stubs in cross-architecture manner, this patch exposes these stub creations functions by returning "stub creators" for given triple.

Reviewed By: lhames

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

Added: 
    llvm/unittests/ExecutionEngine/JITLink/StubsTests.cpp

Modified: 
    llvm/include/llvm/ExecutionEngine/JITLink/JITLink.h
    llvm/include/llvm/ExecutionEngine/JITLink/x86_64.h
    llvm/lib/ExecutionEngine/JITLink/JITLink.cpp
    llvm/lib/ExecutionEngine/Orc/ExecutionUtils.cpp
    llvm/unittests/ExecutionEngine/JITLink/CMakeLists.txt

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/ExecutionEngine/JITLink/JITLink.h b/llvm/include/llvm/ExecutionEngine/JITLink/JITLink.h
index 568c9cf87f80e4..4221b884f06b3f 100644
--- a/llvm/include/llvm/ExecutionEngine/JITLink/JITLink.h
+++ b/llvm/include/llvm/ExecutionEngine/JITLink/JITLink.h
@@ -15,6 +15,7 @@
 
 #include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/FunctionExtras.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ExecutionEngine/JITLink/JITLinkMemoryManager.h"
 #include "llvm/ExecutionEngine/JITSymbol.h"
@@ -1851,6 +1852,30 @@ Error makeTargetOutOfRangeError(const LinkGraph &G, const Block &B,
 Error makeAlignmentError(llvm::orc::ExecutorAddr Loc, uint64_t Value, int N,
                          const Edge &E);
 
+/// Creates a new pointer block in the given section and returns an
+/// Anonymous symobl pointing to it.
+///
+/// The pointer block will have the following default values:
+///   alignment: PointerSize
+///   alignment-offset: 0
+///   address: highest allowable
+using AnonymousPointerCreator = unique_function<Expected<Symbol &>(
+    LinkGraph &G, Section &PointerSection, Symbol *InitialTarget,
+    uint64_t InitialAddend)>;
+
+/// Get target-specific AnonymousPointerCreator
+AnonymousPointerCreator getAnonymousPointerCreator(const Triple &TT);
+
+/// Create a jump stub that jumps via the pointer at the given symbol and
+/// an anonymous symbol pointing to it. Return the anonymous symbol.
+///
+/// The stub block will be created by createPointerJumpStubBlock.
+using PointerJumpStubCreator = unique_function<Expected<Symbol &>(
+    LinkGraph &G, Section &StubSection, Symbol &PointerSymbol)>;
+
+/// Get target-specific PointerJumpStubCreator
+PointerJumpStubCreator getPointerJumpStubCreator(const Triple &TT);
+
 /// Base case for edge-visitors where the visitor-list is empty.
 inline void visitEdge(LinkGraph &G, Block *B, Edge &E) {}
 

diff  --git a/llvm/include/llvm/ExecutionEngine/JITLink/x86_64.h b/llvm/include/llvm/ExecutionEngine/JITLink/x86_64.h
index 80af39055f1919..e072ee1575de8f 100644
--- a/llvm/include/llvm/ExecutionEngine/JITLink/x86_64.h
+++ b/llvm/include/llvm/ExecutionEngine/JITLink/x86_64.h
@@ -547,7 +547,7 @@ inline Block &createPointerJumpStubBlock(LinkGraph &G, Section &StubSection,
                                          Symbol &PointerSymbol) {
   auto &B = G.createContentBlock(StubSection, PointerJumpStubContent,
                                  orc::ExecutorAddr(~uint64_t(5)), 1, 0);
-  B.addEdge(Delta32, 2, PointerSymbol, -4);
+  B.addEdge(BranchPCRel32, 2, PointerSymbol, 0);
   return B;
 }
 

diff  --git a/llvm/lib/ExecutionEngine/JITLink/JITLink.cpp b/llvm/lib/ExecutionEngine/JITLink/JITLink.cpp
index 4a2755d3696be1..d86ceb99ded0e6 100644
--- a/llvm/lib/ExecutionEngine/JITLink/JITLink.cpp
+++ b/llvm/lib/ExecutionEngine/JITLink/JITLink.cpp
@@ -13,6 +13,10 @@
 #include "llvm/ExecutionEngine/JITLink/COFF.h"
 #include "llvm/ExecutionEngine/JITLink/ELF.h"
 #include "llvm/ExecutionEngine/JITLink/MachO.h"
+#include "llvm/ExecutionEngine/JITLink/aarch64.h"
+#include "llvm/ExecutionEngine/JITLink/i386.h"
+#include "llvm/ExecutionEngine/JITLink/loongarch.h"
+#include "llvm/ExecutionEngine/JITLink/x86_64.h"
 #include "llvm/Support/Format.h"
 #include "llvm/Support/MemoryBuffer.h"
 #include "llvm/Support/raw_ostream.h"
@@ -417,6 +421,38 @@ Error makeAlignmentError(llvm::orc::ExecutorAddr Loc, uint64_t Value, int N,
                                   " is not aligned to " + Twine(N) + " bytes");
 }
 
+AnonymousPointerCreator getAnonymousPointerCreator(const Triple &TT) {
+  switch (TT.getArch()) {
+  case Triple::aarch64:
+    return aarch64::createAnonymousPointer;
+  case Triple::x86_64:
+    return x86_64::createAnonymousPointer;
+  case Triple::x86:
+    return i386::createAnonymousPointer;
+  case Triple::loongarch32:
+  case Triple::loongarch64:
+    return loongarch::createAnonymousPointer;
+  default:
+    return nullptr;
+  }
+}
+
+PointerJumpStubCreator getPointerJumpStubCreator(const Triple &TT) {
+  switch (TT.getArch()) {
+  case Triple::aarch64:
+    return aarch64::createAnonymousPointerJumpStub;
+  case Triple::x86_64:
+    return x86_64::createAnonymousPointerJumpStub;
+  case Triple::x86:
+    return i386::createAnonymousPointerJumpStub;
+  case Triple::loongarch32:
+  case Triple::loongarch64:
+    return loongarch::createAnonymousPointerJumpStub;
+  default:
+    return nullptr;
+  }
+}
+
 Expected<std::unique_ptr<LinkGraph>>
 createLinkGraphFromObject(MemoryBufferRef ObjectBuffer) {
   auto Magic = identify_magic(ObjectBuffer.getBuffer());

diff  --git a/llvm/lib/ExecutionEngine/Orc/ExecutionUtils.cpp b/llvm/lib/ExecutionEngine/Orc/ExecutionUtils.cpp
index fb685e6c37271e..8ed9cadd2abdce 100644
--- a/llvm/lib/ExecutionEngine/Orc/ExecutionUtils.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/ExecutionUtils.cpp
@@ -553,7 +553,7 @@ DLLImportDefinitionGenerator::getTargetEndianness(const Triple &TT) {
 Expected<std::unique_ptr<jitlink::LinkGraph>>
 DLLImportDefinitionGenerator::createStubsGraph(const SymbolMap &Resolved) {
   Triple TT = ES.getTargetTriple();
-  auto PointerSize = getTargetEndianness(TT);
+  auto PointerSize = getTargetPointerSize(TT);
   if (!PointerSize)
     return PointerSize.takeError();
   auto Endianness = getTargetEndianness(TT);

diff  --git a/llvm/unittests/ExecutionEngine/JITLink/CMakeLists.txt b/llvm/unittests/ExecutionEngine/JITLink/CMakeLists.txt
index 5f71cd03b66f99..e535bcf47fc801 100644
--- a/llvm/unittests/ExecutionEngine/JITLink/CMakeLists.txt
+++ b/llvm/unittests/ExecutionEngine/JITLink/CMakeLists.txt
@@ -13,6 +13,7 @@ add_llvm_unittest(JITLinkTests
     JITLinkMocks.cpp
     LinkGraphTests.cpp
     MemoryManagerErrorTests.cpp
+    StubsTests.cpp
   )
 
 target_link_libraries(JITLinkTests PRIVATE LLVMTestingSupport)

diff  --git a/llvm/unittests/ExecutionEngine/JITLink/StubsTests.cpp b/llvm/unittests/ExecutionEngine/JITLink/StubsTests.cpp
new file mode 100644
index 00000000000000..fb932e756c727f
--- /dev/null
+++ b/llvm/unittests/ExecutionEngine/JITLink/StubsTests.cpp
@@ -0,0 +1,179 @@
+//===------ StubsTests.cpp - Unit tests for generic stub generation -------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ExecutionEngine/JITLink/JITLink.h"
+#include "llvm/ExecutionEngine/JITLink/aarch64.h"
+#include "llvm/ExecutionEngine/JITLink/i386.h"
+#include "llvm/ExecutionEngine/JITLink/loongarch.h"
+#include "llvm/ExecutionEngine/JITLink/x86_64.h"
+#include "llvm/ExecutionEngine/Orc/ObjectFileInterface.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/Memory.h"
+
+#include "llvm/Testing/Support/Error.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+using namespace llvm::jitlink;
+
+static std::pair<Symbol &, Symbol &>
+GenerateStub(LinkGraph &G, size_t PointerSize, Edge::Kind PointerEdgeKind) {
+  auto &FuncSymbol = G.addAbsoluteSymbol("Func", orc::ExecutorAddr(0x2000), 0,
+                                         Linkage::Strong, Scope::Default, true);
+
+  // Create a section for pointer symbols.
+  auto &PointersSec =
+      G.createSection("__pointers", orc::MemProt::Read | orc::MemProt::Write);
+
+  // Create a section for jump stubs symbols.
+  auto &StubsSec =
+      G.createSection("__stubs", orc::MemProt::Read | orc::MemProt::Write);
+
+  auto AnonymousPtrCreator = getAnonymousPointerCreator(G.getTargetTriple());
+  EXPECT_TRUE(AnonymousPtrCreator);
+
+  auto PointerSym = AnonymousPtrCreator(G, PointersSec, &FuncSymbol, 0);
+  EXPECT_FALSE(errorToBool(PointerSym.takeError()));
+  EXPECT_EQ(std::distance(PointerSym->getBlock().edges().begin(),
+                          PointerSym->getBlock().edges().end()),
+            1U);
+  auto &DeltaEdge = *PointerSym->getBlock().edges().begin();
+  EXPECT_EQ(DeltaEdge.getKind(), PointerEdgeKind);
+  EXPECT_EQ(&DeltaEdge.getTarget(), &FuncSymbol);
+  EXPECT_EQ(PointerSym->getBlock().getSize(), PointerSize);
+  EXPECT_TRUE(all_of(PointerSym->getBlock().getContent(),
+                     [](char x) { return x == 0; }));
+
+  auto PtrJumpStubCreator = getPointerJumpStubCreator(G.getTargetTriple());
+  EXPECT_TRUE(PtrJumpStubCreator);
+  auto StubSym = PtrJumpStubCreator(G, StubsSec, *PointerSym);
+  EXPECT_FALSE(errorToBool(StubSym.takeError()));
+  return {*PointerSym, *StubSym};
+}
+
+TEST(StubsTest, StubsGeneration_x86_64) {
+  const char PointerJumpStubContent[6] = {
+      static_cast<char>(0xFFu), 0x25, 0x00, 0x00, 0x00, 0x00};
+  LinkGraph G("foo", Triple("x86_64-apple-darwin"), 8, support::little,
+              getGenericEdgeKindName);
+  auto [PointerSym, StubSym] = GenerateStub(G, 8U, x86_64::Pointer64);
+
+  EXPECT_EQ(std::distance(StubSym.getBlock().edges().begin(),
+                          StubSym.getBlock().edges().end()),
+            1U);
+  auto &JumpEdge = *StubSym.getBlock().edges().begin();
+  EXPECT_EQ(JumpEdge.getKind(), x86_64::BranchPCRel32);
+  EXPECT_EQ(&JumpEdge.getTarget(), &PointerSym);
+  EXPECT_EQ(StubSym.getBlock().getContent(),
+            ArrayRef<char>(PointerJumpStubContent));
+}
+
+TEST(StubsTest, StubsGeneration_aarch64) {
+  const char PointerJumpStubContent[12] = {
+      0x10, 0x00, 0x00, (char)0x90u, // ADRP x16, <imm>@page21
+      0x10, 0x02, 0x40, (char)0xf9u, // LDR x16, [x16, <imm>@pageoff12]
+      0x00, 0x02, 0x1f, (char)0xd6u  // BR  x16
+  };
+  LinkGraph G("foo", Triple("aarch64-linux-gnu"), 8, support::little,
+              getGenericEdgeKindName);
+  auto [PointerSym, StubSym] = GenerateStub(G, 8U, aarch64::Pointer64);
+
+  EXPECT_EQ(std::distance(StubSym.getBlock().edges().begin(),
+                          StubSym.getBlock().edges().end()),
+            2U);
+  auto &AdrpHighEdge = *StubSym.getBlock().edges().begin();
+  auto &LdrEdge = *++StubSym.getBlock().edges().begin();
+  EXPECT_EQ(AdrpHighEdge.getKind(), aarch64::Page21);
+  EXPECT_EQ(&AdrpHighEdge.getTarget(), &PointerSym);
+  EXPECT_EQ(LdrEdge.getKind(), aarch64::PageOffset12);
+  EXPECT_EQ(&LdrEdge.getTarget(), &PointerSym);
+  EXPECT_EQ(StubSym.getBlock().getContent(),
+            ArrayRef<char>(PointerJumpStubContent));
+}
+
+TEST(StubsTest, StubsGeneration_i386) {
+  const char PointerJumpStubContent[6] = {
+      static_cast<char>(0xFFu), 0x25, 0x00, 0x00, 0x00, 0x00};
+  LinkGraph G("foo", Triple("i386-unknown-linux-gnu"), 4, support::little,
+              getGenericEdgeKindName);
+  auto [PointerSym, StubSym] = GenerateStub(G, 4U, i386::Pointer32);
+
+  EXPECT_EQ(std::distance(StubSym.getBlock().edges().begin(),
+                          StubSym.getBlock().edges().end()),
+            1U);
+  auto &JumpEdge = *StubSym.getBlock().edges().begin();
+  EXPECT_EQ(JumpEdge.getKind(), i386::Pointer32);
+  EXPECT_EQ(&JumpEdge.getTarget(), &PointerSym);
+  EXPECT_EQ(StubSym.getBlock().getContent(),
+            ArrayRef<char>(PointerJumpStubContent));
+}
+
+TEST(StubsTest, StubsGeneration_loongarch32) {
+  const char PointerJumpStubContent[12] = {
+      0x14,
+      0x00,
+      0x00,
+      0x1a, // pcalau12i $t8, %page20(imm)
+      static_cast<char>(0x94),
+      0x02,
+      static_cast<char>(0x80),
+      0x28, // ld.d $t8, $t8, %pageoff12(imm)
+      static_cast<char>(0x80),
+      0x02,
+      0x00,
+      0x4c // jr $t8
+  };
+  LinkGraph G("foo", Triple("loongarch32"), 4, support::little,
+              getGenericEdgeKindName);
+  auto [PointerSym, StubSym] = GenerateStub(G, 4U, loongarch::Pointer32);
+
+  EXPECT_EQ(std::distance(StubSym.getBlock().edges().begin(),
+                          StubSym.getBlock().edges().end()),
+            2U);
+  auto &PageHighEdge = *StubSym.getBlock().edges().begin();
+  auto &PageLowEdge = *++StubSym.getBlock().edges().begin();
+  EXPECT_EQ(PageHighEdge.getKind(), loongarch::Page20);
+  EXPECT_EQ(&PageHighEdge.getTarget(), &PointerSym);
+  EXPECT_EQ(PageLowEdge.getKind(), loongarch::PageOffset12);
+  EXPECT_EQ(&PageLowEdge.getTarget(), &PointerSym);
+  EXPECT_EQ(StubSym.getBlock().getContent(),
+            ArrayRef<char>(PointerJumpStubContent));
+}
+
+TEST(StubsTest, StubsGeneration_loongarch64) {
+  const char PointerJumpStubContent[12] = {
+      0x14,
+      0x00,
+      0x00,
+      0x1a, // pcalau12i $t8, %page20(imm)
+      static_cast<char>(0x94),
+      0x02,
+      static_cast<char>(0xc0),
+      0x28, // ld.d $t8, $t8, %pageoff12(imm)
+      static_cast<char>(0x80),
+      0x02,
+      0x00,
+      0x4c // jr $t8
+  };
+  LinkGraph G("foo", Triple("loongarch64"), 8, support::little,
+              getGenericEdgeKindName);
+  auto [PointerSym, StubSym] = GenerateStub(G, 8U, loongarch::Pointer64);
+
+  EXPECT_EQ(std::distance(StubSym.getBlock().edges().begin(),
+                          StubSym.getBlock().edges().end()),
+            2U);
+  auto &PageHighEdge = *StubSym.getBlock().edges().begin();
+  auto &PageLowEdge = *++StubSym.getBlock().edges().begin();
+  EXPECT_EQ(PageHighEdge.getKind(), loongarch::Page20);
+  EXPECT_EQ(&PageHighEdge.getTarget(), &PointerSym);
+  EXPECT_EQ(PageLowEdge.getKind(), loongarch::PageOffset12);
+  EXPECT_EQ(&PageLowEdge.getTarget(), &PointerSym);
+  EXPECT_EQ(StubSym.getBlock().getContent(),
+            ArrayRef<char>(PointerJumpStubContent));
+}


        


More information about the llvm-commits mailing list