aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/ExecutionEngine
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/ExecutionEngine')
-rw-r--r--llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp57
1 files changed, 51 insertions, 6 deletions
diff --git a/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp b/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp
index cca9959..ffc7696 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);
@@ -1758,7 +1799,9 @@ RuntimeDyldELF::processRelocationRef(
MemMgr.allowStubAllocation()) {
resolveLoongArch64Branch(SectionID, Value, RelI, Stubs);
} else if (RelType == ELF::R_LARCH_GOT_PC_HI20 ||
- RelType == ELF::R_LARCH_GOT_PC_LO12) {
+ RelType == ELF::R_LARCH_GOT_PC_LO12 ||
+ RelType == ELF::R_LARCH_GOT64_PC_HI12 ||
+ RelType == ELF::R_LARCH_GOT64_PC_LO20) {
uint64_t GOTOffset = findOrAllocGOTEntry(Value, ELF::R_LARCH_64);
resolveGOTOffsetRelocation(SectionID, Offset, GOTOffset + Addend,
RelType);
@@ -2936,7 +2979,9 @@ bool RuntimeDyldELF::relocationNeedsGot(const RelocationRef &R) const {
if (Arch == Triple::loongarch64)
return RelTy == ELF::R_LARCH_GOT_PC_HI20 ||
- RelTy == ELF::R_LARCH_GOT_PC_LO12;
+ RelTy == ELF::R_LARCH_GOT_PC_LO12 ||
+ RelTy == ELF::R_LARCH_GOT64_PC_HI12 ||
+ RelTy == ELF::R_LARCH_GOT64_PC_LO20;
if (Arch == Triple::x86_64)
return RelTy == ELF::R_X86_64_GOTPCREL ||