[llvm] 89f546f - [JITLink][RISCV] Support GOT/PLT relocations

via llvm-commits llvm-commits at lists.llvm.org
Fri Aug 27 20:59:24 PDT 2021


Author: luxufan
Date: 2021-08-28T11:52:21+08:00
New Revision: 89f546f6ba1c21041f1e44657cb9980baf4cd4e6

URL: https://github.com/llvm/llvm-project/commit/89f546f6ba1c21041f1e44657cb9980baf4cd4e6
DIFF: https://github.com/llvm/llvm-project/commit/89f546f6ba1c21041f1e44657cb9980baf4cd4e6.diff

LOG: [JITLink][RISCV] Support GOT/PLT relocations

This patch add the R_RISCV_GOT_HI20 and R_RISCV_CALL_PLT relocation support. And the basic got/plt was implemented. Because of riscv32 and riscv64 has different pointer size, the got entry size and instructions of plt entry is different. This patch is the basic support, the optimization pass at preFixup stage has not been implemented.

Reviewed By: lhames

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

Added: 
    llvm/test/ExecutionEngine/JITLink/RISCV/ELF_riscv32_got_plt_reloc.s
    llvm/test/ExecutionEngine/JITLink/RISCV/ELF_riscv64_got_plt_reloc.s

Modified: 
    llvm/include/llvm/ExecutionEngine/JITLink/riscv.h
    llvm/lib/ExecutionEngine/JITLink/ELF_riscv.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/ExecutionEngine/JITLink/riscv.h b/llvm/include/llvm/ExecutionEngine/JITLink/riscv.h
index a4509f3888a4a..b8d08d88c1c91 100644
--- a/llvm/include/llvm/ExecutionEngine/JITLink/riscv.h
+++ b/llvm/include/llvm/ExecutionEngine/JITLink/riscv.h
@@ -70,7 +70,19 @@ enum EdgeKind_riscv : Edge::Kind {
   ///
   /// Fixup expression:
   ///   Fixup <- (Target - Fixup + Addend)
-  R_RISCV_CALL
+  R_RISCV_CALL,
+
+  /// PC relative GOT offset
+  ///
+  /// Fixup expression:
+  ///   Fixup <- (GOT - Fixup + Addend) >> 12
+  R_RISCV_GOT_HI20,
+
+  /// PC relative call by PLT
+  ///
+  /// Fixup expression:
+  ///   Fixup <- (Target - Fixup + Addend)
+  R_RISCV_CALL_PLT
 
 };
 

diff  --git a/llvm/lib/ExecutionEngine/JITLink/ELF_riscv.cpp b/llvm/lib/ExecutionEngine/JITLink/ELF_riscv.cpp
index d0e65ef1c3ac5..417005aa2620c 100644
--- a/llvm/lib/ExecutionEngine/JITLink/ELF_riscv.cpp
+++ b/llvm/lib/ExecutionEngine/JITLink/ELF_riscv.cpp
@@ -11,17 +11,119 @@
 //===----------------------------------------------------------------------===//
 
 #include "llvm/ExecutionEngine/JITLink/ELF_riscv.h"
+#include "ELFLinkGraphBuilder.h"
+#include "JITLinkGeneric.h"
+#include "PerGraphGOTAndPLTStubsBuilder.h"
+#include "llvm/BinaryFormat/ELF.h"
 #include "llvm/ExecutionEngine/JITLink/JITLink.h"
 #include "llvm/ExecutionEngine/JITLink/riscv.h"
 #include "llvm/Object/ELF.h"
 #include "llvm/Object/ELFObjectFile.h"
 
-#include "ELFLinkGraphBuilder.h"
-#include "JITLinkGeneric.h"
-
 #define DEBUG_TYPE "jitlink"
 using namespace llvm;
+using namespace llvm::jitlink;
+using namespace llvm::jitlink::riscv;
+
+namespace {
+
+class PerGraphGOTAndPLTStubsBuilder_ELF_riscv
+    : public PerGraphGOTAndPLTStubsBuilder<
+          PerGraphGOTAndPLTStubsBuilder_ELF_riscv> {
+public:
+  static constexpr size_t StubEntrySize = 16;
+  static const uint8_t NullGOTEntryContent[8];
+  static const uint8_t RV64StubContent[StubEntrySize];
+  static const uint8_t RV32StubContent[StubEntrySize];
+
+  using PerGraphGOTAndPLTStubsBuilder<
+      PerGraphGOTAndPLTStubsBuilder_ELF_riscv>::PerGraphGOTAndPLTStubsBuilder;
+
+  bool isRV64() const { return G.getPointerSize() == 8; }
 
+  bool isGOTEdgeToFix(Edge &E) const { return E.getKind() == R_RISCV_GOT_HI20; }
+
+  Symbol &createGOTEntry(Symbol &Target) {
+    Block &GOTBlock = G.createContentBlock(
+        getGOTSection(), getGOTEntryBlockContent(), 0, G.getPointerSize(), 0);
+    GOTBlock.addEdge(isRV64() ? R_RISCV_64 : R_RISCV_32, 0, Target, 0);
+    return G.addAnonymousSymbol(GOTBlock, 0, G.getPointerSize(), false, false);
+  }
+
+  Symbol &createPLTStub(Symbol &Target) {
+    Block &StubContentBlock =
+        G.createContentBlock(getStubsSection(), getStubBlockContent(), 0, 4, 0);
+    auto &GOTEntrySymbol = getGOTEntry(Target);
+    StubContentBlock.addEdge(R_RISCV_CALL, 0, GOTEntrySymbol, 0);
+    return G.addAnonymousSymbol(StubContentBlock, 0, StubEntrySize, true,
+                                false);
+  }
+
+  void fixGOTEdge(Edge &E, Symbol &GOTEntry) {
+    // Replace the relocation pair (R_RISCV_GOT_HI20, R_RISCV_PCREL_LO12)
+    // with (R_RISCV_PCREL_HI20, R_RISCV_PCREL_LO12)
+    // Therefore, here just change the R_RISCV_GOT_HI20 to R_RISCV_PCREL_HI20
+    E.setKind(R_RISCV_PCREL_HI20);
+    E.setTarget(GOTEntry);
+  }
+
+  void fixPLTEdge(Edge &E, Symbol &PLTStubs) {
+    assert(E.getKind() == R_RISCV_CALL_PLT && "Not a R_RISCV_CALL_PLT edge?");
+    E.setKind(R_RISCV_CALL);
+    E.setTarget(PLTStubs);
+  }
+
+  bool isExternalBranchEdge(Edge &E) const {
+    return E.getKind() == R_RISCV_CALL_PLT;
+  }
+
+private:
+  Section &getGOTSection() const {
+    if (!GOTSection)
+      GOTSection = &G.createSection("$__GOT", sys::Memory::MF_READ);
+    return *GOTSection;
+  }
+
+  Section &getStubsSection() const {
+    if (!StubsSection) {
+      auto StubsProt = static_cast<sys::Memory::ProtectionFlags>(
+          sys::Memory::MF_READ | sys::Memory::MF_EXEC);
+      StubsSection = &G.createSection("$__STUBS", StubsProt);
+    }
+    return *StubsSection;
+  }
+
+  ArrayRef<char> getGOTEntryBlockContent() {
+    return {reinterpret_cast<const char *>(NullGOTEntryContent),
+            G.getPointerSize()};
+  }
+
+  ArrayRef<char> getStubBlockContent() {
+    auto StubContent = isRV64() ? RV64StubContent : RV32StubContent;
+    return {reinterpret_cast<const char *>(StubContent), StubEntrySize};
+  }
+
+  mutable Section *GOTSection = nullptr;
+  mutable Section *StubsSection = nullptr;
+};
+
+const uint8_t PerGraphGOTAndPLTStubsBuilder_ELF_riscv::NullGOTEntryContent[8] =
+    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+const uint8_t
+    PerGraphGOTAndPLTStubsBuilder_ELF_riscv::RV64StubContent[StubEntrySize] = {
+        0x17, 0x0e, 0x00, 0x00,  // auipc t3, literal
+        0x03, 0x3e, 0x0e, 0x00,  // ld    t3, literal(t3)
+        0x67, 0x00, 0x0e, 0x00,  // jr    t3
+        0x13, 0x00, 0x00, 0x00}; // nop
+
+const uint8_t
+    PerGraphGOTAndPLTStubsBuilder_ELF_riscv::RV32StubContent[StubEntrySize] = {
+        0x17, 0x0e, 0x00, 0x00,  // auipc t3, literal
+        0x03, 0x2e, 0x0e, 0x00,  // lw    t3, literal(t3)
+        0x67, 0x00, 0x0e, 0x00,  // jr    t3
+        0x13, 0x00, 0x00, 0x00}; // nop
+} // namespace
 namespace llvm {
 namespace jitlink {
 
@@ -78,6 +180,16 @@ class ELFJITLinker_riscv : public JITLinker<ELFJITLinker_riscv> {
     char *FixupPtr = BlockWorkingMem + E.getOffset();
     JITTargetAddress FixupAddress = B.getAddress() + E.getOffset();
     switch (E.getKind()) {
+    case R_RISCV_32: {
+      int64_t Value = E.getTarget().getAddress() + E.getAddend();
+      *(little32_t *)FixupPtr = static_cast<uint32_t>(Value);
+      break;
+    }
+    case R_RISCV_64: {
+      int64_t Value = E.getTarget().getAddress() + E.getAddend();
+      *(little64_t *)FixupPtr = static_cast<uint64_t>(Value);
+      break;
+    }
     case R_RISCV_HI20: {
       int64_t Value = E.getTarget().getAddress() + E.getAddend();
       int32_t Hi = (Value + 0x800) & 0xFFFFF000;
@@ -163,6 +275,10 @@ class ELFLinkGraphBuilder_riscv : public ELFLinkGraphBuilder<ELFT> {
       return EdgeKind_riscv::R_RISCV_PCREL_LO12_I;
     case ELF::R_RISCV_PCREL_LO12_S:
       return EdgeKind_riscv::R_RISCV_PCREL_LO12_S;
+    case ELF::R_RISCV_GOT_HI20:
+      return EdgeKind_riscv::R_RISCV_GOT_HI20;
+    case ELF::R_RISCV_CALL_PLT:
+      return EdgeKind_riscv::R_RISCV_CALL_PLT;
     }
 
     return make_error<JITLinkError>("Unsupported riscv relocation:" +
@@ -304,6 +420,8 @@ void link_ELF_riscv(std::unique_ptr<LinkGraph> G,
       Config.PrePrunePasses.push_back(std::move(MarkLive));
     else
       Config.PrePrunePasses.push_back(markAllSymbolsLive);
+    Config.PostPrunePasses.push_back(
+        PerGraphGOTAndPLTStubsBuilder_ELF_riscv::asPass);
   }
   if (auto Err = Ctx->modifyPassConfig(*G, Config))
     return Ctx->notifyFailed(std::move(Err));

diff  --git a/llvm/test/ExecutionEngine/JITLink/RISCV/ELF_riscv32_got_plt_reloc.s b/llvm/test/ExecutionEngine/JITLink/RISCV/ELF_riscv32_got_plt_reloc.s
new file mode 100644
index 0000000000000..d9c71426cd3d4
--- /dev/null
+++ b/llvm/test/ExecutionEngine/JITLink/RISCV/ELF_riscv32_got_plt_reloc.s
@@ -0,0 +1,43 @@
+# RUN: rm -rf %t && mkdir -p %t
+# RUN: llvm-mc -triple=riscv32 -position-independent -filetype=obj -o %t/elf_riscv32_got_plt_reloc.o %s
+# RUN: llvm-jitlink -noexec -slab-allocate 100Kb -slab-address 0xfff00000 \
+# RUN:      -define-abs external_func=0x1 -define-abs external_data=0x2 \
+# RUN:              -check %s %t/elf_riscv32_got_plt_reloc.o
+
+
+        .text
+        .file   "testcase.c"
+
+# Empty main entry point.
+        .globl  main
+        .p2align  1
+        .type   main, at function
+main:
+        ret
+
+        .size   main, .-main
+# Test R_RISCV_GOT_HI20. The low 12 relocation is R_RISCV_PC_REL_LO12. This test case will
+# check both the offset to the GOT entry and its content.
+# jitlink-check: decode_operand(test_got, 1) = (got_addr(elf_riscv32_got_plt_reloc.o, external_data) - test_got + 0x800)[31:12]
+# jitlink-check: decode_operand(test_got+4, 2)[11:0] = (got_addr(elf_riscv32_got_plt_reloc.o, external_data) - test_got)[11:0]
+# jitlink-check: *{4}(got_addr(elf_riscv32_got_plt_reloc.o, external_data)) = external_data
+        .globl test_got
+        .p2align  1
+        .type  test_got, at function
+test_got:
+        auipc a0, %got_pcrel_hi(external_data)
+        lw    a0, %pcrel_lo(test_got)(a0)
+
+        .size test_got, .-test_got
+
+# Test R_RISCV_CALL_PLT.
+# jitlink-check: decode_operand(test_plt, 1) = (stub_addr(elf_riscv32_got_plt_reloc.o, external_func) - test_plt + 0x800)[31:12]
+# jitlink-check: decode_operand(test_plt+4, 2) = (stub_addr(elf_riscv32_got_plt_reloc.o, external_func) - test_plt)[11:0]
+# jitlink-check: *{4}(got_addr(elf_riscv32_got_plt_reloc.o, external_func)) = external_func
+       .globl   test_plt
+       .p2align  1
+       .type    test_got, at function
+test_plt:
+       call external_func at plt
+
+       .size test_plt, .-test_plt

diff  --git a/llvm/test/ExecutionEngine/JITLink/RISCV/ELF_riscv64_got_plt_reloc.s b/llvm/test/ExecutionEngine/JITLink/RISCV/ELF_riscv64_got_plt_reloc.s
new file mode 100644
index 0000000000000..141ef9f360cbf
--- /dev/null
+++ b/llvm/test/ExecutionEngine/JITLink/RISCV/ELF_riscv64_got_plt_reloc.s
@@ -0,0 +1,44 @@
+# RUN: rm -rf %t && mkdir -p %t
+# RUN: llvm-mc -triple=riscv64 -position-independent -filetype=obj -o %t/elf_riscv64_got_plt_reloc.o %s
+# RUN: llvm-jitlink -noexec -slab-allocate 100Kb -slab-address 0xfff00000 \
+# RUN:      -define-abs external_func=0x1 -define-abs external_data=0x2 \
+# RUN:              -check %s %t/elf_riscv64_got_plt_reloc.o
+
+
+        .text
+        .file   "testcase.c"
+
+# Empty main entry point.
+        .globl  main
+        .p2align  1
+        .type   main, at function
+main:
+        ret
+
+        .size   main, .-main
+# Test R_RISCV_GOT_HI20. The low 12 relocation is R_RISCV_PC_REL_LO12. This test case will
+# check both the offset to the GOT entry and its content.
+# jitlink-check: decode_operand(test_got, 1) = (got_addr(elf_riscv64_got_plt_reloc.o, external_data) - test_got + 0x800)[31:12]
+# jitlink-check: decode_operand(test_got+4, 2)[11:0] = (got_addr(elf_riscv64_got_plt_reloc.o, external_data) - test_got)[11:0]
+# jitlink-check: *{8}(got_addr(elf_riscv64_got_plt_reloc.o, external_data)) = external_data
+        .globl test_got
+        .p2align  1
+        .type  test_got, at function
+test_got:
+        auipc a0, %got_pcrel_hi(external_data)
+        ld    a0, %pcrel_lo(test_got)(a0)
+
+        .size test_got, .-test_got
+
+# Test R_RISCV_CALL_PLT.
+# jitlink-check: decode_operand(test_plt, 1) = (stub_addr(elf_riscv64_got_plt_reloc.o, external_func) - test_plt + 0x800)[31:12]
+# jitlink-check: decode_operand(test_plt+4, 2) = (stub_addr(elf_riscv64_got_plt_reloc.o, external_func) - test_plt)[11:0]
+# jitlink-check: *{8}(got_addr(elf_riscv64_got_plt_reloc.o, external_func)) = external_func
+       .globl   test_plt
+       .p2align  1
+       .type    test_got, at function
+test_plt:
+       call external_func at plt
+
+       .size test_plt, .-test_plt
+


        


More information about the llvm-commits mailing list