[llvm] 4e668d5 - [RuntimeDyld] Add LoongArch support

via llvm-commits llvm-commits at lists.llvm.org
Thu Nov 7 18:42:33 PST 2024


Author: wanglei
Date: 2024-11-08T10:42:31+08:00
New Revision: 4e668d5b27a339918bee4d994fca31d962519e80

URL: https://github.com/llvm/llvm-project/commit/4e668d5b27a339918bee4d994fca31d962519e80
DIFF: https://github.com/llvm/llvm-project/commit/4e668d5b27a339918bee4d994fca31d962519e80.diff

LOG: [RuntimeDyld] Add LoongArch support

This is necessary for supporting function calls in LLDB expressions for
LoongArch.
This patch is inspired by #99336 and simply extracts the parts related
to RuntimeDyld.

Reviewed By: lhames

Pull Request: https://github.com/llvm/llvm-project/pull/114741

Added: 
    llvm/test/ExecutionEngine/RuntimeDyld/LoongArch/ELF_LoongArch_relocations.s
    llvm/test/ExecutionEngine/RuntimeDyld/LoongArch/lit.local.cfg

Modified: 
    llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp
    llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp
    llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h

Removed: 
    


################################################################################
diff  --git a/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp b/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp
index 5ac5532705dc49..b3798f15a6cc97 100644
--- a/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp
+++ b/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp
@@ -990,6 +990,18 @@ uint8_t *RuntimeDyldImpl::createStubFunction(uint8_t *Addr,
     // and stubs for branches Thumb - ARM and ARM - Thumb.
     writeBytesUnaligned(0xe51ff004, Addr, 4); // ldr pc, [pc, #-4]
     return Addr + 4;
+  } else if (Arch == Triple::loongarch64) {
+    // lu12i.w  $t0, %abs_hi20(addr)
+    // ori      $t0, $t0, %abs_lo12(addr)
+    // lu32i.d  $t0, %abs64_lo20(addr)
+    // lu52i.d  $t0, $t0, %abs64_lo12(addr)
+    // jr       $t0
+    writeBytesUnaligned(0x1400000c, Addr, 4);
+    writeBytesUnaligned(0x0380018c, Addr + 4, 4);
+    writeBytesUnaligned(0x1600000c, Addr + 8, 4);
+    writeBytesUnaligned(0x0300018c, Addr + 12, 4);
+    writeBytesUnaligned(0x4c000180, Addr + 16, 4);
+    return Addr;
   } else if (IsMipsO32ABI || IsMipsN32ABI) {
     // 0:   3c190000        lui     t9,%hi(addr).
     // 4:   27390000        addiu   t9,t9,%lo(addr).

diff  --git a/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp b/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp
index 25b76c7668350b..5f8dc414335646 100644
--- a/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp
+++ b/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp
@@ -645,6 +645,206 @@ void RuntimeDyldELF::resolveARMRelocation(const SectionEntry &Section,
   }
 }
 
+bool RuntimeDyldELF::resolveLoongArch64ShortBranch(
+    unsigned SectionID, relocation_iterator RelI,
+    const RelocationValueRef &Value) {
+  uint64_t Address;
+  if (Value.SymbolName) {
+    auto Loc = GlobalSymbolTable.find(Value.SymbolName);
+    // Don't create direct branch for external symbols.
+    if (Loc == GlobalSymbolTable.end())
+      return false;
+    const auto &SymInfo = Loc->second;
+    Address =
+        uint64_t(Sections[SymInfo.getSectionID()].getLoadAddressWithOffset(
+            SymInfo.getOffset()));
+  } else {
+    Address = uint64_t(Sections[Value.SectionID].getLoadAddress());
+  }
+  uint64_t Offset = RelI->getOffset();
+  uint64_t SourceAddress = Sections[SectionID].getLoadAddressWithOffset(Offset);
+  if (!isInt<28>(Address + Value.Addend - SourceAddress))
+    return false;
+  resolveRelocation(Sections[SectionID], Offset, Address, RelI->getType(),
+                    Value.Addend);
+  return true;
+}
+
+void RuntimeDyldELF::resolveLoongArch64Branch(unsigned SectionID,
+                                              const RelocationValueRef &Value,
+                                              relocation_iterator RelI,
+                                              StubMap &Stubs) {
+  LLVM_DEBUG(dbgs() << "\t\tThis is an LoongArch64 branch relocation.\n");
+
+  if (resolveLoongArch64ShortBranch(SectionID, RelI, Value))
+    return;
+
+  SectionEntry &Section = Sections[SectionID];
+  uint64_t Offset = RelI->getOffset();
+  unsigned RelType = RelI->getType();
+  // Look for an existing stub.
+  StubMap::const_iterator i = Stubs.find(Value);
+  if (i != Stubs.end()) {
+    resolveRelocation(Section, Offset,
+                      (uint64_t)Section.getAddressWithOffset(i->second),
+                      RelType, 0);
+    LLVM_DEBUG(dbgs() << " Stub function found\n");
+    return;
+  }
+  // Create a new stub function.
+  LLVM_DEBUG(dbgs() << " Create a new stub function\n");
+  Stubs[Value] = Section.getStubOffset();
+  uint8_t *StubTargetAddr =
+      createStubFunction(Section.getAddressWithOffset(Section.getStubOffset()));
+  RelocationEntry LU12I_W(SectionID, StubTargetAddr - Section.getAddress(),
+                          ELF::R_LARCH_ABS_HI20, Value.Addend);
+  RelocationEntry ORI(SectionID, StubTargetAddr - Section.getAddress() + 4,
+                      ELF::R_LARCH_ABS_LO12, Value.Addend);
+  RelocationEntry LU32I_D(SectionID, StubTargetAddr - Section.getAddress() + 8,
+                          ELF::R_LARCH_ABS64_LO20, Value.Addend);
+  RelocationEntry LU52I_D(SectionID, StubTargetAddr - Section.getAddress() + 12,
+                          ELF::R_LARCH_ABS64_HI12, Value.Addend);
+  if (Value.SymbolName) {
+    addRelocationForSymbol(LU12I_W, Value.SymbolName);
+    addRelocationForSymbol(ORI, Value.SymbolName);
+    addRelocationForSymbol(LU32I_D, Value.SymbolName);
+    addRelocationForSymbol(LU52I_D, Value.SymbolName);
+  } else {
+    addRelocationForSection(LU12I_W, Value.SectionID);
+    addRelocationForSection(ORI, Value.SectionID);
+    addRelocationForSection(LU32I_D, Value.SectionID);
+
+    addRelocationForSection(LU52I_D, Value.SectionID);
+  }
+  resolveRelocation(Section, Offset,
+                    reinterpret_cast<uint64_t>(
+                        Section.getAddressWithOffset(Section.getStubOffset())),
+                    RelType, 0);
+  Section.advanceStubOffset(getMaxStubSize());
+}
+
+// Returns extract bits Val[Hi:Lo].
+static inline uint32_t extractBits(uint64_t Val, uint32_t Hi, uint32_t Lo) {
+  return Hi == 63 ? Val >> Lo : (Val & (((1ULL << (Hi + 1)) - 1))) >> Lo;
+}
+
+void RuntimeDyldELF::resolveLoongArch64Relocation(const SectionEntry &Section,
+                                                  uint64_t Offset,
+                                                  uint64_t Value, uint32_t Type,
+                                                  int64_t Addend) {
+  auto *TargetPtr = Section.getAddressWithOffset(Offset);
+  uint64_t FinalAddress = Section.getLoadAddressWithOffset(Offset);
+
+  LLVM_DEBUG(dbgs() << "resolveLoongArch64Relocation, LocalAddress: 0x"
+                    << format("%llx", Section.getAddressWithOffset(Offset))
+                    << " FinalAddress: 0x" << format("%llx", FinalAddress)
+                    << " Value: 0x" << format("%llx", Value) << " Type: 0x"
+                    << format("%x", Type) << " Addend: 0x"
+                    << format("%llx", Addend) << "\n");
+
+  switch (Type) {
+  default:
+    report_fatal_error("Relocation type not implemented yet!");
+    break;
+  case ELF::R_LARCH_32:
+    support::ulittle32_t::ref{TargetPtr} =
+        static_cast<uint32_t>(Value + Addend);
+    break;
+  case ELF::R_LARCH_64:
+    support::ulittle64_t::ref{TargetPtr} = Value + Addend;
+    break;
+  case ELF::R_LARCH_32_PCREL:
+    support::ulittle32_t::ref{TargetPtr} =
+        static_cast<uint32_t>(Value + Addend - FinalAddress);
+    break;
+  case ELF::R_LARCH_B26: {
+    uint64_t B26 = (Value + Addend - FinalAddress) >> 2;
+    auto Instr = support::ulittle32_t::ref(TargetPtr);
+    uint32_t Imm15_0 = extractBits(B26, /*Hi=*/15, /*Lo=*/0) << 10;
+    uint32_t Imm25_16 = extractBits(B26, /*Hi=*/25, /*Lo=*/16);
+    Instr = (Instr & 0xfc000000) | Imm15_0 | Imm25_16;
+    break;
+  }
+  case ELF::R_LARCH_CALL36: {
+    uint64_t Call36 = (Value + Addend - FinalAddress) >> 2;
+    auto Pcaddu18i = support::ulittle32_t::ref(TargetPtr);
+    uint32_t Imm35_16 =
+        extractBits((Call36 + (1UL << 15)), /*Hi=*/35, /*Lo=*/16) << 5;
+    Pcaddu18i = (Pcaddu18i & 0xfe00001f) | Imm35_16;
+    auto Jirl = support::ulittle32_t::ref(TargetPtr + 4);
+    uint32_t Imm15_0 = extractBits(Call36, /*Hi=*/15, /*Lo=*/0) << 10;
+    Jirl = (Jirl & 0xfc0003ff) | Imm15_0;
+    break;
+  }
+  case ELF::R_LARCH_GOT_PC_HI20:
+  case ELF::R_LARCH_PCALA_HI20: {
+    uint64_t Target = Value + Addend;
+    uint64_t TargetPage =
+        (Target + (Target & 0x800)) & ~static_cast<uint64_t>(0xfff);
+    uint64_t PCPage = FinalAddress & ~static_cast<uint64_t>(0xfff);
+    int64_t PageDelta = TargetPage - PCPage;
+    auto Instr = support::ulittle32_t::ref(TargetPtr);
+    uint32_t Imm31_12 = extractBits(PageDelta, /*Hi=*/31, /*Lo=*/12) << 5;
+    Instr = (Instr & 0xfe00001f) | Imm31_12;
+    break;
+  }
+  case ELF::R_LARCH_GOT_PC_LO12:
+  case ELF::R_LARCH_PCALA_LO12: {
+    uint64_t TargetOffset = (Value + Addend) & 0xfff;
+    auto Instr = support::ulittle32_t::ref(TargetPtr);
+    uint32_t Imm11_0 = TargetOffset << 10;
+    Instr = (Instr & 0xffc003ff) | Imm11_0;
+    break;
+  }
+  case ELF::R_LARCH_ABS_HI20: {
+    uint64_t Target = Value + Addend;
+    auto Instr = support::ulittle32_t::ref(TargetPtr);
+    uint32_t Imm31_12 = extractBits(Target, /*Hi=*/31, /*Lo=*/12) << 5;
+    Instr = (Instr & 0xfe00001f) | Imm31_12;
+    break;
+  }
+  case ELF::R_LARCH_ABS_LO12: {
+    uint64_t Target = Value + Addend;
+    auto Instr = support::ulittle32_t::ref(TargetPtr);
+    uint32_t Imm11_0 = extractBits(Target, /*Hi=*/11, /*Lo=*/0) << 10;
+    Instr = (Instr & 0xffc003ff) | Imm11_0;
+    break;
+  }
+  case ELF::R_LARCH_ABS64_LO20: {
+    uint64_t Target = Value + Addend;
+    auto Instr = support::ulittle32_t::ref(TargetPtr);
+    uint32_t Imm51_32 = extractBits(Target, /*Hi=*/51, /*Lo=*/32) << 5;
+    Instr = (Instr & 0xfe00001f) | Imm51_32;
+    break;
+  }
+  case ELF::R_LARCH_ABS64_HI12: {
+    uint64_t Target = Value + Addend;
+    auto Instr = support::ulittle32_t::ref(TargetPtr);
+    uint32_t Imm63_52 = extractBits(Target, /*Hi=*/63, /*Lo=*/52) << 10;
+    Instr = (Instr & 0xffc003ff) | Imm63_52;
+    break;
+  }
+  case ELF::R_LARCH_ADD32:
+    support::ulittle32_t::ref{TargetPtr} =
+        (support::ulittle32_t::ref{TargetPtr} +
+         static_cast<uint32_t>(Value + Addend));
+    break;
+  case ELF::R_LARCH_SUB32:
+    support::ulittle32_t::ref{TargetPtr} =
+        (support::ulittle32_t::ref{TargetPtr} -
+         static_cast<uint32_t>(Value + Addend));
+    break;
+  case ELF::R_LARCH_ADD64:
+    support::ulittle64_t::ref{TargetPtr} =
+        (support::ulittle64_t::ref{TargetPtr} + Value + Addend);
+    break;
+  case ELF::R_LARCH_SUB64:
+    support::ulittle64_t::ref{TargetPtr} =
+        (support::ulittle64_t::ref{TargetPtr} - Value - Addend);
+    break;
+  }
+}
+
 void RuntimeDyldELF::setMipsABI(const ObjectFile &Obj) {
   if (Arch == Triple::UnknownArch ||
       Triple::getArchTypePrefix(Arch) != "mips") {
@@ -1190,6 +1390,9 @@ void RuntimeDyldELF::resolveRelocation(const SectionEntry &Section,
     resolveARMRelocation(Section, Offset, (uint32_t)(Value & 0xffffffffL), Type,
                          (uint32_t)(Addend & 0xffffffffL));
     break;
+  case Triple::loongarch64:
+    resolveLoongArch64Relocation(Section, Offset, Value, Type, Addend);
+    break;
   case Triple::ppc: // Fall through.
   case Triple::ppcle:
     resolvePPC32Relocation(Section, Offset, Value, Type, Addend);
@@ -1515,6 +1718,17 @@ RuntimeDyldELF::processRelocationRef(
       }
       processSimpleRelocation(SectionID, Offset, RelType, Value);
     }
+  } else if (Arch == Triple::loongarch64) {
+    if (RelType == ELF::R_LARCH_B26 && MemMgr.allowStubAllocation()) {
+      resolveLoongArch64Branch(SectionID, Value, RelI, Stubs);
+    } else if (RelType == ELF::R_LARCH_GOT_PC_HI20 ||
+               RelType == ELF::R_LARCH_GOT_PC_LO12) {
+      uint64_t GOTOffset = findOrAllocGOTEntry(Value, ELF::R_LARCH_64);
+      resolveGOTOffsetRelocation(SectionID, Offset, GOTOffset + Addend,
+                                 RelType);
+    } else {
+      processSimpleRelocation(SectionID, Offset, RelType, Value);
+    }
   } else if (IsMipsO32ABI) {
     uint8_t *Placeholder = reinterpret_cast<uint8_t *>(
         computePlaceholderAddress(SectionID, Offset));
@@ -2371,6 +2585,7 @@ size_t RuntimeDyldELF::getGOTEntrySize() {
   case Triple::x86_64:
   case Triple::aarch64:
   case Triple::aarch64_be:
+  case Triple::loongarch64:
   case Triple::ppc64:
   case Triple::ppc64le:
   case Triple::systemz:
@@ -2683,6 +2898,10 @@ bool RuntimeDyldELF::relocationNeedsGot(const RelocationRef &R) const {
     return RelTy == ELF::R_AARCH64_ADR_GOT_PAGE ||
            RelTy == ELF::R_AARCH64_LD64_GOT_LO12_NC;
 
+  if (Arch == Triple::loongarch64)
+    return RelTy == ELF::R_LARCH_GOT_PC_HI20 ||
+           RelTy == ELF::R_LARCH_GOT_PC_LO12;
+
   if (Arch == Triple::x86_64)
     return RelTy == ELF::R_X86_64_GOTPCREL ||
            RelTy == ELF::R_X86_64_GOTPCRELX ||

diff  --git a/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h b/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h
index 97517884654bc5..deb623b1a4bef2 100644
--- a/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h
+++ b/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h
@@ -46,6 +46,18 @@ class RuntimeDyldELF : public RuntimeDyldImpl {
   void resolveARMRelocation(const SectionEntry &Section, uint64_t Offset,
                             uint32_t Value, uint32_t Type, int32_t Addend);
 
+  void resolveLoongArch64Relocation(const SectionEntry &Section,
+                                    uint64_t Offset, uint64_t Value,
+                                    uint32_t Type, int64_t Addend);
+
+  bool resolveLoongArch64ShortBranch(unsigned SectionID,
+                                     relocation_iterator RelI,
+                                     const RelocationValueRef &Value);
+
+  void resolveLoongArch64Branch(unsigned SectionID,
+                                const RelocationValueRef &Value,
+                                relocation_iterator RelI, StubMap &Stubs);
+
   void resolvePPC32Relocation(const SectionEntry &Section, uint64_t Offset,
                               uint64_t Value, uint32_t Type, int64_t Addend);
 
@@ -71,6 +83,8 @@ class RuntimeDyldELF : public RuntimeDyldImpl {
       return 16;
     else if (IsMipsN64ABI)
       return 32;
+    if (Arch == Triple::loongarch64)
+      return 20; // lu12i.w; ori; lu32i.d; lu52i.d; jr
     else if (Arch == Triple::ppc64 || Arch == Triple::ppc64le)
       return 44;
     else if (Arch == Triple::x86_64)

diff  --git a/llvm/test/ExecutionEngine/RuntimeDyld/LoongArch/ELF_LoongArch_relocations.s b/llvm/test/ExecutionEngine/RuntimeDyld/LoongArch/ELF_LoongArch_relocations.s
new file mode 100644
index 00000000000000..0fca88b6e9ba29
--- /dev/null
+++ b/llvm/test/ExecutionEngine/RuntimeDyld/LoongArch/ELF_LoongArch_relocations.s
@@ -0,0 +1,102 @@
+# RUN: rm -rf %t && mkdir -p %t
+# RUN: llvm-mc --triple=loongarch64 --filetype=obj -o %t/reloc.o %s
+# RUN: llvm-rtdyld --triple=loongarch64 --verify --check=%s %t/reloc.o \
+# RUN:     --map-section reloc.o,.got=0x21f00 \
+# RUN:     --dummy-extern abs=0x0123456789abcdef \
+# RUN:     --dummy-extern external_data=0x1234
+
+    .text
+    .globl main
+    .p2align 2
+    .type   main, at function
+main:
+## Check R_LARCH_ABS_HI20
+# rtdyld-check: *{4}(main) = 0x1513578c
+    lu12i.w $t0, %abs_hi20(abs)
+## Check R_LARCH_ABS_LO12
+# rtdyld-check: *{4}(main + 4) = 0x03b7bd8c
+    ori $t0, $t0, %abs_lo12(abs)
+## Check R_LARCH_ABS64_LO20
+# rtdyld-check: *{4}(main + 8) = 0x1668acec
+    lu32i.d $t0, %abs64_lo20(abs)
+## Check R_LARCH_ABS64_HI12
+# rtdyld-check: *{4}(main + 12) = 0x0300498c
+    lu52i.d $t0, $t0, %abs64_hi12(abs)
+		ret
+	  .size main, .-main
+
+    .globl local_func
+    .p2align 2
+    .type local_func, at function
+local_func:
+    ret
+    .size local_func, .-local_func
+
+    .globl local_func_call26
+    .p2align 2
+local_func_call26:
+## Check R_LARCH_B26
+# rtdyld-check: decode_operand(local_func_call26, 0)[27:0] = \
+# rtdyld-check:   (local_func - local_func_call26)[27:0]
+    bl local_func
+    .size local_func_call26, .-local_func_call26
+
+    .globl local_func_call36
+    .p2align 2
+local_func_call36:
+## Check R_LARCH_CALL36
+# rtdyld-check: decode_operand(local_func_call36, 1)[19:0] = \
+# rtdyld-check:   ((local_func - local_func_call36) + \
+# rtdyld-check:    (((local_func - local_func_call36)[17:17]) << 17))[37:18]
+# rtdyld-check: decode_operand(local_func_call36 + 4, 2)[17:0] = \
+# rtdyld-check:   (local_func - local_func_call36)[17:0]
+    pcaddu18i $ra, %call36(local_func)
+    jirl $ra, $ra, 0
+    .size local_func_call36, .-local_func_call36
+
+    .globl test_pc_hi20
+    .p2align 2
+test_pc_hi20:
+## Check R_LARCH_PCALA_HI20
+# rtdyld-check: decode_operand(test_pc_hi20, 1)[19:0] = \
+# rtdyld-check:   (named_data - test_pc_hi20)[31:12] + \
+# rtdyld-check:      named_data[11:11]
+    pcalau12i $a0, %pc_hi20(named_data)
+    .size test_pc_hi20, .-test_pc_hi20
+
+    .globl test_pc_lo12
+    .p2align 2
+test_pc_lo12:
+## Check R_LARCH_PCALA_LO12
+# rtdyld-check: decode_operand(test_pc_lo12, 2)[11:0] = \
+# rtdyld-check:   (named_data)[11:0]
+    addi.d $a0, $a0, %pc_lo12(named_data)
+    .size test_pc_lo12, .-test_pc_lo12
+
+    .globl test_got_pc_hi20
+    .p2align 2
+test_got_pc_hi20:
+## Check R_LARCH_GOT_PC_HI20
+# rtdyld-check: decode_operand(test_got_pc_hi20, 1)[19:0] = \
+# rtdyld-check:   (section_addr(reloc.o, .got)[31:12] - \
+# rtdyld-check:    test_got_pc_hi20[31:12] + \
+# rtdyld-check:    section_addr(reloc.o, .got)[11:11])
+    pcalau12i $a0, %got_pc_hi20(external_data)
+    .size test_got_pc_hi20, .-test_got_pc_hi20
+
+    .globl test_got_pc_lo12
+    .p2align 2
+test_got_pc_lo12:
+## Check R_LARCH_GOT_PC_LO12
+# rtdyld-check: decode_operand(test_got_pc_lo12, 2)[11:0] = \
+# rtdyld-check:   (section_addr(reloc.o, .got)[11:0])
+    ld.d $a0, $a0, %got_pc_lo12(external_data)
+    .size test_gotoffset12_external, .-test_gotoffset12_external
+
+    .globl named_data
+    .p2align 4
+    .type named_data, at object
+named_data:
+    .quad 0x2222222222222222
+    .quad 0x3333333333333333
+    .size named_data, .-named_data

diff  --git a/llvm/test/ExecutionEngine/RuntimeDyld/LoongArch/lit.local.cfg b/llvm/test/ExecutionEngine/RuntimeDyld/LoongArch/lit.local.cfg
new file mode 100644
index 00000000000000..cc24278acbb414
--- /dev/null
+++ b/llvm/test/ExecutionEngine/RuntimeDyld/LoongArch/lit.local.cfg
@@ -0,0 +1,2 @@
+if not "LoongArch" in config.root.targets:
+    config.unsupported = True


        


More information about the llvm-commits mailing list