Skip to content

Commit 4e35ae1

Browse files
[RuntimeDyld][LoongArch] Support large code model (#148584)
Co-authored-by: Weining Lu <[email protected]>
1 parent 04b17bd commit 4e35ae1

File tree

2 files changed

+93
-6
lines changed

2 files changed

+93
-6
lines changed

llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp

Lines changed: 51 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -738,6 +738,32 @@ static inline uint32_t extractBits(uint64_t Val, uint32_t Hi, uint32_t Lo) {
738738
return Hi == 63 ? Val >> Lo : (Val & (((1ULL << (Hi + 1)) - 1))) >> Lo;
739739
}
740740

741+
// Calculate the adjusted page delta between dest and PC. The code is copied
742+
// from lld and see comments there for more details.
743+
static uint64_t getLoongArchPageDelta(uint64_t dest, uint64_t pc,
744+
uint32_t type) {
745+
uint64_t pcalau12i_pc;
746+
switch (type) {
747+
case ELF::R_LARCH_PCALA64_LO20:
748+
case ELF::R_LARCH_GOT64_PC_LO20:
749+
pcalau12i_pc = pc - 8;
750+
break;
751+
case ELF::R_LARCH_PCALA64_HI12:
752+
case ELF::R_LARCH_GOT64_PC_HI12:
753+
pcalau12i_pc = pc - 12;
754+
break;
755+
default:
756+
pcalau12i_pc = pc;
757+
break;
758+
}
759+
uint64_t result = (dest & ~0xfffULL) - (pcalau12i_pc & ~0xfffULL);
760+
if (dest & 0x800)
761+
result += 0x1000 - 0x1'0000'0000;
762+
if (result & 0x8000'0000)
763+
result += 0x1'0000'0000;
764+
return result;
765+
}
766+
741767
void RuntimeDyldELF::resolveLoongArch64Relocation(const SectionEntry &Section,
742768
uint64_t Offset,
743769
uint64_t Value, uint32_t Type,
@@ -789,10 +815,7 @@ void RuntimeDyldELF::resolveLoongArch64Relocation(const SectionEntry &Section,
789815
case ELF::R_LARCH_GOT_PC_HI20:
790816
case ELF::R_LARCH_PCALA_HI20: {
791817
uint64_t Target = Value + Addend;
792-
uint64_t TargetPage =
793-
(Target + (Target & 0x800)) & ~static_cast<uint64_t>(0xfff);
794-
uint64_t PCPage = FinalAddress & ~static_cast<uint64_t>(0xfff);
795-
int64_t PageDelta = TargetPage - PCPage;
818+
int64_t PageDelta = getLoongArchPageDelta(Target, FinalAddress, Type);
796819
auto Instr = support::ulittle32_t::ref(TargetPtr);
797820
uint32_t Imm31_12 = extractBits(PageDelta, /*Hi=*/31, /*Lo=*/12) << 5;
798821
Instr = (Instr & 0xfe00001f) | Imm31_12;
@@ -806,6 +829,24 @@ void RuntimeDyldELF::resolveLoongArch64Relocation(const SectionEntry &Section,
806829
Instr = (Instr & 0xffc003ff) | Imm11_0;
807830
break;
808831
}
832+
case ELF::R_LARCH_GOT64_PC_LO20:
833+
case ELF::R_LARCH_PCALA64_LO20: {
834+
uint64_t Target = Value + Addend;
835+
int64_t PageDelta = getLoongArchPageDelta(Target, FinalAddress, Type);
836+
auto Instr = support::ulittle32_t::ref(TargetPtr);
837+
uint32_t Imm51_32 = extractBits(PageDelta, /*Hi=*/51, /*Lo=*/32) << 5;
838+
Instr = (Instr & 0xfe00001f) | Imm51_32;
839+
break;
840+
}
841+
case ELF::R_LARCH_GOT64_PC_HI12:
842+
case ELF::R_LARCH_PCALA64_HI12: {
843+
uint64_t Target = Value + Addend;
844+
int64_t PageDelta = getLoongArchPageDelta(Target, FinalAddress, Type);
845+
auto Instr = support::ulittle32_t::ref(TargetPtr);
846+
uint32_t Imm63_52 = extractBits(PageDelta, /*Hi=*/63, /*Lo=*/52) << 10;
847+
Instr = (Instr & 0xffc003ff) | Imm63_52;
848+
break;
849+
}
809850
case ELF::R_LARCH_ABS_HI20: {
810851
uint64_t Target = Value + Addend;
811852
auto Instr = support::ulittle32_t::ref(TargetPtr);
@@ -1758,7 +1799,9 @@ RuntimeDyldELF::processRelocationRef(
17581799
MemMgr.allowStubAllocation()) {
17591800
resolveLoongArch64Branch(SectionID, Value, RelI, Stubs);
17601801
} else if (RelType == ELF::R_LARCH_GOT_PC_HI20 ||
1761-
RelType == ELF::R_LARCH_GOT_PC_LO12) {
1802+
RelType == ELF::R_LARCH_GOT_PC_LO12 ||
1803+
RelType == ELF::R_LARCH_GOT64_PC_HI12 ||
1804+
RelType == ELF::R_LARCH_GOT64_PC_LO20) {
17621805
uint64_t GOTOffset = findOrAllocGOTEntry(Value, ELF::R_LARCH_64);
17631806
resolveGOTOffsetRelocation(SectionID, Offset, GOTOffset + Addend,
17641807
RelType);
@@ -2936,7 +2979,9 @@ bool RuntimeDyldELF::relocationNeedsGot(const RelocationRef &R) const {
29362979

29372980
if (Arch == Triple::loongarch64)
29382981
return RelTy == ELF::R_LARCH_GOT_PC_HI20 ||
2939-
RelTy == ELF::R_LARCH_GOT_PC_LO12;
2982+
RelTy == ELF::R_LARCH_GOT_PC_LO12 ||
2983+
RelTy == ELF::R_LARCH_GOT64_PC_HI12 ||
2984+
RelTy == ELF::R_LARCH_GOT64_PC_LO20;
29402985

29412986
if (Arch == Triple::x86_64)
29422987
return RelTy == ELF::R_X86_64_GOTPCREL ||

llvm/test/ExecutionEngine/RuntimeDyld/LoongArch/ELF_LoongArch_relocations.s

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22
# RUN: llvm-mc --triple=loongarch64 --filetype=obj -o %t/reloc.o %s
33
# RUN: llvm-rtdyld --triple=loongarch64 --verify --check=%s %t/reloc.o \
44
# RUN: --map-section reloc.o,.got=0x21f00 \
5+
# RUN: --map-section reloc.o,.sec.large.pc=0x0000000012345000 \
6+
# RUN: --map-section reloc.o,.sec.large.got=0x44433333abcde000 \
7+
# RUN: --map-section reloc.o,.sec.dummy=0x4443333334567111 \
58
# RUN: --dummy-extern abs=0x0123456789abcdef \
69
# RUN: --dummy-extern external_data=0x1234
710

@@ -100,3 +103,42 @@ named_data:
100103
.quad 0x2222222222222222
101104
.quad 0x3333333333333333
102105
.size named_data, .-named_data
106+
107+
.section .sec.large.pc,"ax"
108+
.globl test_large_pc
109+
test_large_pc:
110+
## Code after link should be:
111+
## 1a44444d pcalau12i $t1, 139810
112+
## 02c4440c addi.d $t0, $zero, 273
113+
## 1666666c lu32i.d $t0, 209715
114+
## 0311118c lu52i.d $t0, $t0, 1092
115+
116+
# rtdyld-check: *{4}(test_large_pc) = 0x1a44444d
117+
pcalau12i $t1, %pc_hi20(.sec.dummy)
118+
# rtdyld-check: *{4}(test_large_pc + 4) = 0x02c4440c
119+
addi.d $t0, $zero, %pc_lo12(.sec.dummy)
120+
# rtdyld-check: *{4}(test_large_pc + 8) = 0x1666666c
121+
lu32i.d $t0, %pc64_lo20(.sec.dummy)
122+
# rtdyld-check: *{4}(test_large_pc + 12) = 0x0311118c
123+
lu52i.d $t0, $t0, %pc64_hi12(.sec.dummy)
124+
125+
.section .sec.large.got,"ax"
126+
.globl test_large_got
127+
test_large_got:
128+
## Code after link should be:
129+
## 1aa8688d pcalau12i $t1, 344900
130+
## 02fc000c addi.d $t0, $zero, -256
131+
## 1799996c lu32i.d $t0, -209717
132+
## 032eed8c lu52i.d $t0, $t0, -1093
133+
134+
# rtdyld-check: *{4}(test_large_got) = 0x1aa8688d
135+
pcalau12i $t1, %got_pc_hi20(external_data)
136+
# rtdyld-check: *{4}(test_large_got + 4) = 0x02fc000c
137+
addi.d $t0, $zero, %got_pc_lo12(external_data)
138+
# rtdyld-check: *{4}(test_large_got + 8) = 0x1799996c
139+
lu32i.d $t0, %got64_pc_lo20(external_data)
140+
# rtdyld-check: *{4}(test_large_got + 12) = 0x032eed8c
141+
lu52i.d $t0, $t0, %got64_pc_hi12(external_data)
142+
143+
.section .sec.dummy,"a"
144+
.word 0

0 commit comments

Comments
 (0)