@@ -728,6 +728,32 @@ static inline uint32_t extractBits(uint64_t Val, uint32_t Hi, uint32_t Lo) {
728728 return Hi == 63 ? Val >> Lo : (Val & (((1ULL << (Hi + 1 )) - 1 ))) >> Lo;
729729}
730730
731+ // Calculate the adjusted page delta between dest and PC. The code is copied
732+ // from lld and see comments there for more details.
733+ static uint64_t getLoongArchPageDelta (uint64_t dest, uint64_t pc,
734+ uint32_t type) {
735+ uint64_t pcalau12i_pc;
736+ switch (type) {
737+ case ELF::R_LARCH_PCALA64_LO20:
738+ case ELF::R_LARCH_GOT64_PC_LO20:
739+ pcalau12i_pc = pc - 8 ;
740+ break ;
741+ case ELF::R_LARCH_PCALA64_HI12:
742+ case ELF::R_LARCH_GOT64_PC_HI12:
743+ pcalau12i_pc = pc - 12 ;
744+ break ;
745+ default :
746+ pcalau12i_pc = pc;
747+ break ;
748+ }
749+ uint64_t result = (dest & ~0xfffULL ) - (pcalau12i_pc & ~0xfffULL );
750+ if (dest & 0x800 )
751+ result += 0x1000 - 0x1'0000'0000 ;
752+ if (result & 0x8000'0000 )
753+ result += 0x1'0000'0000 ;
754+ return result;
755+ }
756+
731757void RuntimeDyldELF::resolveLoongArch64Relocation (const SectionEntry &Section,
732758 uint64_t Offset,
733759 uint64_t Value, uint32_t Type,
@@ -779,10 +805,7 @@ void RuntimeDyldELF::resolveLoongArch64Relocation(const SectionEntry &Section,
779805 case ELF::R_LARCH_GOT_PC_HI20:
780806 case ELF::R_LARCH_PCALA_HI20: {
781807 uint64_t Target = Value + Addend;
782- uint64_t TargetPage =
783- (Target + (Target & 0x800 )) & ~static_cast <uint64_t >(0xfff );
784- uint64_t PCPage = FinalAddress & ~static_cast <uint64_t >(0xfff );
785- int64_t PageDelta = TargetPage - PCPage;
808+ int64_t PageDelta = getLoongArchPageDelta (Target, FinalAddress, Type);
786809 auto Instr = support::ulittle32_t::ref (TargetPtr);
787810 uint32_t Imm31_12 = extractBits (PageDelta, /* Hi=*/ 31 , /* Lo=*/ 12 ) << 5 ;
788811 Instr = (Instr & 0xfe00001f ) | Imm31_12;
@@ -796,6 +819,24 @@ void RuntimeDyldELF::resolveLoongArch64Relocation(const SectionEntry &Section,
796819 Instr = (Instr & 0xffc003ff ) | Imm11_0;
797820 break ;
798821 }
822+ case ELF::R_LARCH_GOT64_PC_LO20:
823+ case ELF::R_LARCH_PCALA64_LO20: {
824+ uint64_t Target = Value + Addend;
825+ int64_t PageDelta = getLoongArchPageDelta (Target, FinalAddress, Type);
826+ auto Instr = support::ulittle32_t::ref (TargetPtr);
827+ uint32_t Imm51_32 = extractBits (PageDelta, /* Hi=*/ 51 , /* Lo=*/ 32 ) << 5 ;
828+ Instr = (Instr & 0xfe00001f ) | Imm51_32;
829+ break ;
830+ }
831+ case ELF::R_LARCH_GOT64_PC_HI12:
832+ case ELF::R_LARCH_PCALA64_HI12: {
833+ uint64_t Target = Value + Addend;
834+ int64_t PageDelta = getLoongArchPageDelta (Target, FinalAddress, Type);
835+ auto Instr = support::ulittle32_t::ref (TargetPtr);
836+ uint32_t Imm63_52 = extractBits (PageDelta, /* Hi=*/ 63 , /* Lo=*/ 52 ) << 10 ;
837+ Instr = (Instr & 0xffc003ff ) | Imm63_52;
838+ break ;
839+ }
799840 case ELF::R_LARCH_ABS_HI20: {
800841 uint64_t Target = Value + Addend;
801842 auto Instr = support::ulittle32_t::ref (TargetPtr);
@@ -1581,7 +1622,9 @@ RuntimeDyldELF::processRelocationRef(
15811622 if (RelType == ELF::R_LARCH_B26 && MemMgr.allowStubAllocation ()) {
15821623 resolveLoongArch64Branch (SectionID, Value, RelI, Stubs);
15831624 } else if (RelType == ELF::R_LARCH_GOT_PC_HI20 ||
1584- RelType == ELF::R_LARCH_GOT_PC_LO12) {
1625+ RelType == ELF::R_LARCH_GOT_PC_LO12 ||
1626+ RelType == ELF::R_LARCH_GOT64_PC_HI12 ||
1627+ RelType == ELF::R_LARCH_GOT64_PC_LO20) {
15851628 uint64_t GOTOffset = findOrAllocGOTEntry (Value, ELF::R_LARCH_64);
15861629 resolveGOTOffsetRelocation (SectionID, Offset, GOTOffset + Addend,
15871630 RelType);
@@ -2748,7 +2791,9 @@ bool RuntimeDyldELF::relocationNeedsGot(const RelocationRef &R) const {
27482791
27492792 if (Arch == Triple::loongarch64)
27502793 return RelTy == ELF::R_LARCH_GOT_PC_HI20 ||
2751- RelTy == ELF::R_LARCH_GOT_PC_LO12;
2794+ RelTy == ELF::R_LARCH_GOT_PC_LO12 ||
2795+ RelTy == ELF::R_LARCH_GOT64_PC_HI12 ||
2796+ RelTy == ELF::R_LARCH_GOT64_PC_LO20;
27522797
27532798 if (Arch == Triple::x86_64)
27542799 return RelTy == ELF::R_X86_64_GOTPCREL ||
0 commit comments