@@ -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+
741767void 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 ||
0 commit comments