[llvm] [RuntimeDyld][LoongArch] Support large code model (PR #148584)
via llvm-commits
llvm-commits at lists.llvm.org
Mon Jul 14 01:25:23 PDT 2025
https://github.com/Ami-zhang created https://github.com/llvm/llvm-project/pull/148584
None
>From e8dfcb883d42e413a1a8eed7cf2a4246d0690ecb Mon Sep 17 00:00:00 2001
From: Ami-zhang <zhanglimin at loongson.cn>
Date: Mon, 14 Jul 2025 16:18:04 +0800
Subject: [PATCH] [RuntimeDyld][LoongArch] Support large code model
---
.../RuntimeDyld/RuntimeDyldELF.cpp | 49 +++++++++++++++++--
.../LoongArch/ELF_LoongArch_relocations.s | 42 ++++++++++++++++
2 files changed, 87 insertions(+), 4 deletions(-)
diff --git a/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp b/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp
index cca99591c8c45..5cb5138b61514 100644
--- a/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp
+++ b/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp
@@ -738,6 +738,32 @@ 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;
}
+// Calculate the adjusted page delta between dest and PC. The code is copied
+// from lld and see comments there for more details.
+static uint64_t getLoongArchPageDelta(uint64_t dest, uint64_t pc,
+ uint32_t type) {
+ uint64_t pcalau12i_pc;
+ switch (type) {
+ case ELF::R_LARCH_PCALA64_LO20:
+ case ELF::R_LARCH_GOT64_PC_LO20:
+ pcalau12i_pc = pc - 8;
+ break;
+ case ELF::R_LARCH_PCALA64_HI12:
+ case ELF::R_LARCH_GOT64_PC_HI12:
+ pcalau12i_pc = pc - 12;
+ break;
+ default:
+ pcalau12i_pc = pc;
+ break;
+ }
+ uint64_t result = (dest & ~0xfffULL) - (pcalau12i_pc & ~0xfffULL);
+ if (dest & 0x800)
+ result += 0x1000 - 0x1'0000'0000;
+ if (result & 0x8000'0000)
+ result += 0x1'0000'0000;
+ return result;
+}
+
void RuntimeDyldELF::resolveLoongArch64Relocation(const SectionEntry &Section,
uint64_t Offset,
uint64_t Value, uint32_t Type,
@@ -789,10 +815,7 @@ void RuntimeDyldELF::resolveLoongArch64Relocation(const SectionEntry &Section,
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;
+ int64_t PageDelta = getLoongArchPageDelta(Target, FinalAddress, Type);
auto Instr = support::ulittle32_t::ref(TargetPtr);
uint32_t Imm31_12 = extractBits(PageDelta, /*Hi=*/31, /*Lo=*/12) << 5;
Instr = (Instr & 0xfe00001f) | Imm31_12;
@@ -806,6 +829,24 @@ void RuntimeDyldELF::resolveLoongArch64Relocation(const SectionEntry &Section,
Instr = (Instr & 0xffc003ff) | Imm11_0;
break;
}
+ case ELF::R_LARCH_GOT64_PC_LO20:
+ case ELF::R_LARCH_PCALA64_LO20: {
+ uint64_t Target = Value + Addend;
+ int64_t PageDelta = getLoongArchPageDelta(Target, FinalAddress, Type);
+ auto Instr = support::ulittle32_t::ref(TargetPtr);
+ uint32_t Imm51_32 = extractBits(PageDelta, /*Hi=*/51, /*Lo=*/32) << 5;
+ Instr = (Instr & 0xfe00001f) | Imm51_32;
+ break;
+ }
+ case ELF::R_LARCH_GOT64_PC_HI12:
+ case ELF::R_LARCH_PCALA64_HI12: {
+ uint64_t Target = Value + Addend;
+ int64_t PageDelta = getLoongArchPageDelta(Target, FinalAddress, Type);
+ auto Instr = support::ulittle32_t::ref(TargetPtr);
+ uint32_t Imm63_52 = extractBits(PageDelta, /*Hi=*/63, /*Lo=*/52) << 10;
+ Instr = (Instr & 0xffc003ff) | Imm63_52;
+ break;
+ }
case ELF::R_LARCH_ABS_HI20: {
uint64_t Target = Value + Addend;
auto Instr = support::ulittle32_t::ref(TargetPtr);
diff --git a/llvm/test/ExecutionEngine/RuntimeDyld/LoongArch/ELF_LoongArch_relocations.s b/llvm/test/ExecutionEngine/RuntimeDyld/LoongArch/ELF_LoongArch_relocations.s
index 0fca88b6e9ba2..4d15846ba0703 100644
--- a/llvm/test/ExecutionEngine/RuntimeDyld/LoongArch/ELF_LoongArch_relocations.s
+++ b/llvm/test/ExecutionEngine/RuntimeDyld/LoongArch/ELF_LoongArch_relocations.s
@@ -2,6 +2,9 @@
# 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: --map-section reloc.o,.sec.large.pc=0x0000000012345000 \
+# RUN: --map-section reloc.o,.sec.large.got=0x44433333abcde000 \
+# RUN: --map-section reloc.o,.sec.dummy=0x4443333334567111 \
# RUN: --dummy-extern abs=0x0123456789abcdef \
# RUN: --dummy-extern external_data=0x1234
@@ -100,3 +103,42 @@ named_data:
.quad 0x2222222222222222
.quad 0x3333333333333333
.size named_data, .-named_data
+
+ .section .sec.large.pc,"ax"
+ .globl test_large_pc
+test_large_pc:
+## Code after link should be:
+## 1a44444d pcalau12i $t1, 139810
+## 02c4440c addi.d $t0, 273
+## 1666666c lu32i.d $t0, 209715
+## 0311118c lu52i.d $t0, $t0, 1092
+
+# rtdyld-check: *{4}(test_large_pc) = 0x1a44444d
+ pcalau12i $t1, %pc_hi20(.sec.dummy)
+# rtdyld-check: *{4}(test_large_pc + 4) = 0x02c4440c
+ addi.d $t0, $zero, %pc_lo12(.sec.dummy)
+# rtdyld-check: *{4}(test_large_pc + 8) = 0x1666666c
+ lu32i.d $t0, %pc64_lo20(.sec.dummy)
+# rtdyld-check: *{4}(test_large_pc + 12) = 0x0311118c
+ lu52i.d $t0, $t0, %pc64_hi12(.sec.dummy)
+
+ .section .sec.large.got,"ax"
+ .globl test_large_got
+test_large_got:
+## Code after link should be:
+## 1aa8688d pcalau12i $t1, 344900
+## 02fc000c addi.d $t0, -256
+## 1799998c lu32i.d $t0, -209716
+## 032eed8c lu52i.d $t0, $t0, -1093
+
+# rtdyld-check: *{4}(test_large_got) = 0x1aa8688d
+ pcalau12i $t1, %got_pc_hi20(external_data)
+# rtdyld-check: *{4}(test_large_got + 4) = 0x02fc000c
+ addi.d $t0, $zero, %got_pc_lo12(external_data)
+# rtdyld-check: *{4}(test_large_got + 8) = 0x1799998c
+ lu32i.d $t0, %got64_pc_lo20(external_data)
+# rtdyld-check: *{4}(test_large_got + 12) = 0x032eed8c
+ lu52i.d $t0, $t0, %got64_pc_hi12(external_data)
+
+ .section .sec.dummy,"a"
+ .word 0
More information about the llvm-commits
mailing list