Skip to content

Commit 4e668d5

Browse files
authored
[RuntimeDyld] Add LoongArch support
This is necessary for supporting function calls in LLDB expressions for LoongArch. This patch is inspired by #99336 and simply extracts the parts related to RuntimeDyld. Reviewed By: lhames Pull Request: #114741
1 parent 36d757f commit 4e668d5

File tree

5 files changed

+349
-0
lines changed

5 files changed

+349
-0
lines changed

llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -990,6 +990,18 @@ uint8_t *RuntimeDyldImpl::createStubFunction(uint8_t *Addr,
990990
// and stubs for branches Thumb - ARM and ARM - Thumb.
991991
writeBytesUnaligned(0xe51ff004, Addr, 4); // ldr pc, [pc, #-4]
992992
return Addr + 4;
993+
} else if (Arch == Triple::loongarch64) {
994+
// lu12i.w $t0, %abs_hi20(addr)
995+
// ori $t0, $t0, %abs_lo12(addr)
996+
// lu32i.d $t0, %abs64_lo20(addr)
997+
// lu52i.d $t0, $t0, %abs64_lo12(addr)
998+
// jr $t0
999+
writeBytesUnaligned(0x1400000c, Addr, 4);
1000+
writeBytesUnaligned(0x0380018c, Addr + 4, 4);
1001+
writeBytesUnaligned(0x1600000c, Addr + 8, 4);
1002+
writeBytesUnaligned(0x0300018c, Addr + 12, 4);
1003+
writeBytesUnaligned(0x4c000180, Addr + 16, 4);
1004+
return Addr;
9931005
} else if (IsMipsO32ABI || IsMipsN32ABI) {
9941006
// 0: 3c190000 lui t9,%hi(addr).
9951007
// 4: 27390000 addiu t9,t9,%lo(addr).

llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp

Lines changed: 219 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -645,6 +645,206 @@ void RuntimeDyldELF::resolveARMRelocation(const SectionEntry &Section,
645645
}
646646
}
647647

648+
bool RuntimeDyldELF::resolveLoongArch64ShortBranch(
649+
unsigned SectionID, relocation_iterator RelI,
650+
const RelocationValueRef &Value) {
651+
uint64_t Address;
652+
if (Value.SymbolName) {
653+
auto Loc = GlobalSymbolTable.find(Value.SymbolName);
654+
// Don't create direct branch for external symbols.
655+
if (Loc == GlobalSymbolTable.end())
656+
return false;
657+
const auto &SymInfo = Loc->second;
658+
Address =
659+
uint64_t(Sections[SymInfo.getSectionID()].getLoadAddressWithOffset(
660+
SymInfo.getOffset()));
661+
} else {
662+
Address = uint64_t(Sections[Value.SectionID].getLoadAddress());
663+
}
664+
uint64_t Offset = RelI->getOffset();
665+
uint64_t SourceAddress = Sections[SectionID].getLoadAddressWithOffset(Offset);
666+
if (!isInt<28>(Address + Value.Addend - SourceAddress))
667+
return false;
668+
resolveRelocation(Sections[SectionID], Offset, Address, RelI->getType(),
669+
Value.Addend);
670+
return true;
671+
}
672+
673+
void RuntimeDyldELF::resolveLoongArch64Branch(unsigned SectionID,
674+
const RelocationValueRef &Value,
675+
relocation_iterator RelI,
676+
StubMap &Stubs) {
677+
LLVM_DEBUG(dbgs() << "\t\tThis is an LoongArch64 branch relocation.\n");
678+
679+
if (resolveLoongArch64ShortBranch(SectionID, RelI, Value))
680+
return;
681+
682+
SectionEntry &Section = Sections[SectionID];
683+
uint64_t Offset = RelI->getOffset();
684+
unsigned RelType = RelI->getType();
685+
// Look for an existing stub.
686+
StubMap::const_iterator i = Stubs.find(Value);
687+
if (i != Stubs.end()) {
688+
resolveRelocation(Section, Offset,
689+
(uint64_t)Section.getAddressWithOffset(i->second),
690+
RelType, 0);
691+
LLVM_DEBUG(dbgs() << " Stub function found\n");
692+
return;
693+
}
694+
// Create a new stub function.
695+
LLVM_DEBUG(dbgs() << " Create a new stub function\n");
696+
Stubs[Value] = Section.getStubOffset();
697+
uint8_t *StubTargetAddr =
698+
createStubFunction(Section.getAddressWithOffset(Section.getStubOffset()));
699+
RelocationEntry LU12I_W(SectionID, StubTargetAddr - Section.getAddress(),
700+
ELF::R_LARCH_ABS_HI20, Value.Addend);
701+
RelocationEntry ORI(SectionID, StubTargetAddr - Section.getAddress() + 4,
702+
ELF::R_LARCH_ABS_LO12, Value.Addend);
703+
RelocationEntry LU32I_D(SectionID, StubTargetAddr - Section.getAddress() + 8,
704+
ELF::R_LARCH_ABS64_LO20, Value.Addend);
705+
RelocationEntry LU52I_D(SectionID, StubTargetAddr - Section.getAddress() + 12,
706+
ELF::R_LARCH_ABS64_HI12, Value.Addend);
707+
if (Value.SymbolName) {
708+
addRelocationForSymbol(LU12I_W, Value.SymbolName);
709+
addRelocationForSymbol(ORI, Value.SymbolName);
710+
addRelocationForSymbol(LU32I_D, Value.SymbolName);
711+
addRelocationForSymbol(LU52I_D, Value.SymbolName);
712+
} else {
713+
addRelocationForSection(LU12I_W, Value.SectionID);
714+
addRelocationForSection(ORI, Value.SectionID);
715+
addRelocationForSection(LU32I_D, Value.SectionID);
716+
717+
addRelocationForSection(LU52I_D, Value.SectionID);
718+
}
719+
resolveRelocation(Section, Offset,
720+
reinterpret_cast<uint64_t>(
721+
Section.getAddressWithOffset(Section.getStubOffset())),
722+
RelType, 0);
723+
Section.advanceStubOffset(getMaxStubSize());
724+
}
725+
726+
// Returns extract bits Val[Hi:Lo].
727+
static inline uint32_t extractBits(uint64_t Val, uint32_t Hi, uint32_t Lo) {
728+
return Hi == 63 ? Val >> Lo : (Val & (((1ULL << (Hi + 1)) - 1))) >> Lo;
729+
}
730+
731+
void RuntimeDyldELF::resolveLoongArch64Relocation(const SectionEntry &Section,
732+
uint64_t Offset,
733+
uint64_t Value, uint32_t Type,
734+
int64_t Addend) {
735+
auto *TargetPtr = Section.getAddressWithOffset(Offset);
736+
uint64_t FinalAddress = Section.getLoadAddressWithOffset(Offset);
737+
738+
LLVM_DEBUG(dbgs() << "resolveLoongArch64Relocation, LocalAddress: 0x"
739+
<< format("%llx", Section.getAddressWithOffset(Offset))
740+
<< " FinalAddress: 0x" << format("%llx", FinalAddress)
741+
<< " Value: 0x" << format("%llx", Value) << " Type: 0x"
742+
<< format("%x", Type) << " Addend: 0x"
743+
<< format("%llx", Addend) << "\n");
744+
745+
switch (Type) {
746+
default:
747+
report_fatal_error("Relocation type not implemented yet!");
748+
break;
749+
case ELF::R_LARCH_32:
750+
support::ulittle32_t::ref{TargetPtr} =
751+
static_cast<uint32_t>(Value + Addend);
752+
break;
753+
case ELF::R_LARCH_64:
754+
support::ulittle64_t::ref{TargetPtr} = Value + Addend;
755+
break;
756+
case ELF::R_LARCH_32_PCREL:
757+
support::ulittle32_t::ref{TargetPtr} =
758+
static_cast<uint32_t>(Value + Addend - FinalAddress);
759+
break;
760+
case ELF::R_LARCH_B26: {
761+
uint64_t B26 = (Value + Addend - FinalAddress) >> 2;
762+
auto Instr = support::ulittle32_t::ref(TargetPtr);
763+
uint32_t Imm15_0 = extractBits(B26, /*Hi=*/15, /*Lo=*/0) << 10;
764+
uint32_t Imm25_16 = extractBits(B26, /*Hi=*/25, /*Lo=*/16);
765+
Instr = (Instr & 0xfc000000) | Imm15_0 | Imm25_16;
766+
break;
767+
}
768+
case ELF::R_LARCH_CALL36: {
769+
uint64_t Call36 = (Value + Addend - FinalAddress) >> 2;
770+
auto Pcaddu18i = support::ulittle32_t::ref(TargetPtr);
771+
uint32_t Imm35_16 =
772+
extractBits((Call36 + (1UL << 15)), /*Hi=*/35, /*Lo=*/16) << 5;
773+
Pcaddu18i = (Pcaddu18i & 0xfe00001f) | Imm35_16;
774+
auto Jirl = support::ulittle32_t::ref(TargetPtr + 4);
775+
uint32_t Imm15_0 = extractBits(Call36, /*Hi=*/15, /*Lo=*/0) << 10;
776+
Jirl = (Jirl & 0xfc0003ff) | Imm15_0;
777+
break;
778+
}
779+
case ELF::R_LARCH_GOT_PC_HI20:
780+
case ELF::R_LARCH_PCALA_HI20: {
781+
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;
786+
auto Instr = support::ulittle32_t::ref(TargetPtr);
787+
uint32_t Imm31_12 = extractBits(PageDelta, /*Hi=*/31, /*Lo=*/12) << 5;
788+
Instr = (Instr & 0xfe00001f) | Imm31_12;
789+
break;
790+
}
791+
case ELF::R_LARCH_GOT_PC_LO12:
792+
case ELF::R_LARCH_PCALA_LO12: {
793+
uint64_t TargetOffset = (Value + Addend) & 0xfff;
794+
auto Instr = support::ulittle32_t::ref(TargetPtr);
795+
uint32_t Imm11_0 = TargetOffset << 10;
796+
Instr = (Instr & 0xffc003ff) | Imm11_0;
797+
break;
798+
}
799+
case ELF::R_LARCH_ABS_HI20: {
800+
uint64_t Target = Value + Addend;
801+
auto Instr = support::ulittle32_t::ref(TargetPtr);
802+
uint32_t Imm31_12 = extractBits(Target, /*Hi=*/31, /*Lo=*/12) << 5;
803+
Instr = (Instr & 0xfe00001f) | Imm31_12;
804+
break;
805+
}
806+
case ELF::R_LARCH_ABS_LO12: {
807+
uint64_t Target = Value + Addend;
808+
auto Instr = support::ulittle32_t::ref(TargetPtr);
809+
uint32_t Imm11_0 = extractBits(Target, /*Hi=*/11, /*Lo=*/0) << 10;
810+
Instr = (Instr & 0xffc003ff) | Imm11_0;
811+
break;
812+
}
813+
case ELF::R_LARCH_ABS64_LO20: {
814+
uint64_t Target = Value + Addend;
815+
auto Instr = support::ulittle32_t::ref(TargetPtr);
816+
uint32_t Imm51_32 = extractBits(Target, /*Hi=*/51, /*Lo=*/32) << 5;
817+
Instr = (Instr & 0xfe00001f) | Imm51_32;
818+
break;
819+
}
820+
case ELF::R_LARCH_ABS64_HI12: {
821+
uint64_t Target = Value + Addend;
822+
auto Instr = support::ulittle32_t::ref(TargetPtr);
823+
uint32_t Imm63_52 = extractBits(Target, /*Hi=*/63, /*Lo=*/52) << 10;
824+
Instr = (Instr & 0xffc003ff) | Imm63_52;
825+
break;
826+
}
827+
case ELF::R_LARCH_ADD32:
828+
support::ulittle32_t::ref{TargetPtr} =
829+
(support::ulittle32_t::ref{TargetPtr} +
830+
static_cast<uint32_t>(Value + Addend));
831+
break;
832+
case ELF::R_LARCH_SUB32:
833+
support::ulittle32_t::ref{TargetPtr} =
834+
(support::ulittle32_t::ref{TargetPtr} -
835+
static_cast<uint32_t>(Value + Addend));
836+
break;
837+
case ELF::R_LARCH_ADD64:
838+
support::ulittle64_t::ref{TargetPtr} =
839+
(support::ulittle64_t::ref{TargetPtr} + Value + Addend);
840+
break;
841+
case ELF::R_LARCH_SUB64:
842+
support::ulittle64_t::ref{TargetPtr} =
843+
(support::ulittle64_t::ref{TargetPtr} - Value - Addend);
844+
break;
845+
}
846+
}
847+
648848
void RuntimeDyldELF::setMipsABI(const ObjectFile &Obj) {
649849
if (Arch == Triple::UnknownArch ||
650850
Triple::getArchTypePrefix(Arch) != "mips") {
@@ -1190,6 +1390,9 @@ void RuntimeDyldELF::resolveRelocation(const SectionEntry &Section,
11901390
resolveARMRelocation(Section, Offset, (uint32_t)(Value & 0xffffffffL), Type,
11911391
(uint32_t)(Addend & 0xffffffffL));
11921392
break;
1393+
case Triple::loongarch64:
1394+
resolveLoongArch64Relocation(Section, Offset, Value, Type, Addend);
1395+
break;
11931396
case Triple::ppc: // Fall through.
11941397
case Triple::ppcle:
11951398
resolvePPC32Relocation(Section, Offset, Value, Type, Addend);
@@ -1515,6 +1718,17 @@ RuntimeDyldELF::processRelocationRef(
15151718
}
15161719
processSimpleRelocation(SectionID, Offset, RelType, Value);
15171720
}
1721+
} else if (Arch == Triple::loongarch64) {
1722+
if (RelType == ELF::R_LARCH_B26 && MemMgr.allowStubAllocation()) {
1723+
resolveLoongArch64Branch(SectionID, Value, RelI, Stubs);
1724+
} else if (RelType == ELF::R_LARCH_GOT_PC_HI20 ||
1725+
RelType == ELF::R_LARCH_GOT_PC_LO12) {
1726+
uint64_t GOTOffset = findOrAllocGOTEntry(Value, ELF::R_LARCH_64);
1727+
resolveGOTOffsetRelocation(SectionID, Offset, GOTOffset + Addend,
1728+
RelType);
1729+
} else {
1730+
processSimpleRelocation(SectionID, Offset, RelType, Value);
1731+
}
15181732
} else if (IsMipsO32ABI) {
15191733
uint8_t *Placeholder = reinterpret_cast<uint8_t *>(
15201734
computePlaceholderAddress(SectionID, Offset));
@@ -2371,6 +2585,7 @@ size_t RuntimeDyldELF::getGOTEntrySize() {
23712585
case Triple::x86_64:
23722586
case Triple::aarch64:
23732587
case Triple::aarch64_be:
2588+
case Triple::loongarch64:
23742589
case Triple::ppc64:
23752590
case Triple::ppc64le:
23762591
case Triple::systemz:
@@ -2683,6 +2898,10 @@ bool RuntimeDyldELF::relocationNeedsGot(const RelocationRef &R) const {
26832898
return RelTy == ELF::R_AARCH64_ADR_GOT_PAGE ||
26842899
RelTy == ELF::R_AARCH64_LD64_GOT_LO12_NC;
26852900

2901+
if (Arch == Triple::loongarch64)
2902+
return RelTy == ELF::R_LARCH_GOT_PC_HI20 ||
2903+
RelTy == ELF::R_LARCH_GOT_PC_LO12;
2904+
26862905
if (Arch == Triple::x86_64)
26872906
return RelTy == ELF::R_X86_64_GOTPCREL ||
26882907
RelTy == ELF::R_X86_64_GOTPCRELX ||

llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,18 @@ class RuntimeDyldELF : public RuntimeDyldImpl {
4646
void resolveARMRelocation(const SectionEntry &Section, uint64_t Offset,
4747
uint32_t Value, uint32_t Type, int32_t Addend);
4848

49+
void resolveLoongArch64Relocation(const SectionEntry &Section,
50+
uint64_t Offset, uint64_t Value,
51+
uint32_t Type, int64_t Addend);
52+
53+
bool resolveLoongArch64ShortBranch(unsigned SectionID,
54+
relocation_iterator RelI,
55+
const RelocationValueRef &Value);
56+
57+
void resolveLoongArch64Branch(unsigned SectionID,
58+
const RelocationValueRef &Value,
59+
relocation_iterator RelI, StubMap &Stubs);
60+
4961
void resolvePPC32Relocation(const SectionEntry &Section, uint64_t Offset,
5062
uint64_t Value, uint32_t Type, int64_t Addend);
5163

@@ -71,6 +83,8 @@ class RuntimeDyldELF : public RuntimeDyldImpl {
7183
return 16;
7284
else if (IsMipsN64ABI)
7385
return 32;
86+
if (Arch == Triple::loongarch64)
87+
return 20; // lu12i.w; ori; lu32i.d; lu52i.d; jr
7488
else if (Arch == Triple::ppc64 || Arch == Triple::ppc64le)
7589
return 44;
7690
else if (Arch == Triple::x86_64)

0 commit comments

Comments
 (0)