[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