diff -Naur a/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.cpp b/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.cpp --- a/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.cpp +++ b/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.cpp 2026-08-19 07:14:05.992360749 +0000 @@ -15,6 +15,7 @@ #include "Targets/RuntimeDyldMachOAArch64.h" #include "Targets/RuntimeDyldMachOARM.h" #include "Targets/RuntimeDyldMachOI386.h" +#include "Targets/RuntimeDyldMachOPPC.h" #include "Targets/RuntimeDyldMachOX86_64.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringRef.h" @@ -349,12 +350,16 @@ JITSymbolResolver &Resolver) { switch (Arch) { default: - llvm_unreachable("Unsupported target for RuntimeDyldMachO."); - break; + // Fail loudly: llvm_unreachable is undefined behaviour in release + // builds, and would send an unsupported architecture into an arbitrary + // case of this switch. + report_fatal_error("Unsupported target for RuntimeDyldMachO."); case Triple::arm: return make_unique(MemMgr, Resolver); case Triple::aarch64: return make_unique(MemMgr, Resolver); + case Triple::ppc: + return make_unique(MemMgr, Resolver); case Triple::x86: return make_unique(MemMgr, Resolver); case Triple::x86_64: diff -Naur a/llvm/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldMachOPPC.h b/llvm/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldMachOPPC.h --- a/llvm/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldMachOPPC.h +++ b/llvm/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldMachOPPC.h 2026-08-19 07:13:52.594041333 +0000 @@ -0,0 +1,524 @@ +//===-- RuntimeDyldMachOPPC.h ---- MachO/PPC specific code. -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// MachO/PPC (32-bit, big-endian, powerpc-apple-darwin) support for MCJIT's +// runtime dynamic linker. +// +// Relocation semantics follow the Mach-O runtime ABI for PowerPC as +// implemented by cctools/ld and mirrored by PPCMachObjectWriter: +// +// * PPC_RELOC_HI16/HA16/LO16/LO14 entries are immediately followed by a +// PPC_RELOC_PAIR entry whose r_address field holds the "other half" of +// the original 32-bit value: the low half for HI16/HA16, the high half +// for LO16/LO14. The r_address of the half relocation itself points at +// the start of the instruction word; the immediate lives in the low 16 +// bits of the big-endian word. +// +// * The *_SECTDIFF forms are scattered and compute "A - B + C". The +// r_value of the SECTDIFF entry is the address of A, the r_value of the +// following PPC_RELOC_PAIR is the address of B, and for the half forms +// the PAIR's r_address again holds the other half of the encoded value. +// +// * PPC_RELOC_BR24/BR14 branch displacements are relative to the address +// of the branch instruction itself (no PC bias). Branches with a +// relocation are redirected through a lis/ori/mtctr/bctr island in the +// section's stub area so that targets anywhere in the address space are +// reachable. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDMACHOPPC_H +#define LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDMACHOPPC_H + +#include "../RuntimeDyldMachO.h" +#include "llvm/Support/MathExtras.h" +#include + +#define DEBUG_TYPE "dyld" + +namespace llvm { + +class RuntimeDyldMachOPPC + : public RuntimeDyldMachOCRTPBase { +public: + typedef uint32_t TargetPtrT; + + RuntimeDyldMachOPPC(RuntimeDyld::MemoryManager &MM, + JITSymbolResolver &Resolver) + : RuntimeDyldMachOCRTPBase(MM, Resolver) {} + + // Branch island: lis r12 / ori r12 / mtctr / bctr. + unsigned getMaxStubSize() override { return 16; } + + unsigned getStubAlignment() override { return 4; } + + Expected + processRelocationRef(unsigned SectionID, relocation_iterator RelI, + const ObjectFile &BaseObjT, + ObjSectionToIDMap &ObjSectionToID, + StubMap &Stubs) override { + const MachOObjectFile &Obj = + static_cast(BaseObjT); + MachO::any_relocation_info RelInfo = + Obj.getRelocation(RelI->getRawDataRefImpl()); + uint32_t RelType = Obj.getAnyRelocationType(RelInfo); + + if (Obj.isRelocationScattered(RelInfo)) { + switch (RelType) { + case MachO::PPC_RELOC_SECTDIFF: + case MachO::PPC_RELOC_LOCAL_SECTDIFF: + case MachO::PPC_RELOC_HI16_SECTDIFF: + case MachO::PPC_RELOC_LO16_SECTDIFF: + case MachO::PPC_RELOC_HA16_SECTDIFF: + case MachO::PPC_RELOC_LO14_SECTDIFF: + return processSECTDIFFRelocation(SectionID, RelI, Obj, ObjSectionToID); + case MachO::PPC_RELOC_VANILLA: + return processScatteredVANILLA(SectionID, RelI, Obj, ObjSectionToID); + case MachO::PPC_RELOC_HI16: + case MachO::PPC_RELOC_LO16: + case MachO::PPC_RELOC_HA16: + case MachO::PPC_RELOC_LO14: + return processScatteredHalf(SectionID, RelI, Obj, ObjSectionToID); + default: + return make_error( + ("Unhandled PPC scattered relocation type: " + Twine(RelType)) + .str()); + } + } + + switch (RelType) { + UNIMPLEMENTED_RELOC(MachO::PPC_RELOC_PAIR); // Consumed with its half. + UNIMPLEMENTED_RELOC(MachO::PPC_RELOC_PB_LA_PTR); + UNIMPLEMENTED_RELOC(MachO::PPC_RELOC_JBSR); + // The SECTDIFF family is always scattered and handled above. + UNIMPLEMENTED_RELOC(MachO::PPC_RELOC_SECTDIFF); + UNIMPLEMENTED_RELOC(MachO::PPC_RELOC_LOCAL_SECTDIFF); + UNIMPLEMENTED_RELOC(MachO::PPC_RELOC_HI16_SECTDIFF); + UNIMPLEMENTED_RELOC(MachO::PPC_RELOC_LO16_SECTDIFF); + UNIMPLEMENTED_RELOC(MachO::PPC_RELOC_HA16_SECTDIFF); + UNIMPLEMENTED_RELOC(MachO::PPC_RELOC_LO14_SECTDIFF); + default: + if (RelType > MachO::PPC_RELOC_LOCAL_SECTDIFF) + return make_error( + ("MachO PPC relocation type " + Twine(RelType) + " is out of range") + .str()); + break; + } + + RelocationEntry RE(getRelocationEntry(SectionID, Obj, RelI)); + bool HasPair = false; + + switch (RelType) { + default: + llvm_unreachable("Unhandled relocation type reached addend decoding"); + case MachO::PPC_RELOC_VANILLA: + RE.Addend = SignExtend64(memcpyAddend(RE), 8 * (1 << RE.Size)); + break; + case MachO::PPC_RELOC_BR24: + RE.Addend = SignExtend64<26>(readInstruction(RE) & 0x03FFFFFCU); + break; + case MachO::PPC_RELOC_BR14: + RE.Addend = SignExtend64<16>(readInstruction(RE) & 0xFFFCU); + break; + case MachO::PPC_RELOC_HI16: + case MachO::PPC_RELOC_LO16: + case MachO::PPC_RELOC_HA16: + case MachO::PPC_RELOC_LO14: { + relocation_iterator PairRelI = RelI; + ++PairRelI; + uint32_t OtherHalf; + if (auto OtherHalfOrErr = getPairOtherHalf(Obj, PairRelI)) + OtherHalf = *OtherHalfOrErr; + else + return OtherHalfOrErr.takeError(); + RE.Addend = + combineHalves(RelType, readInstruction(RE) & 0xFFFFU, OtherHalf); + HasPair = true; + break; + } + } + + RelocationValueRef Value; + if (auto ValueOrErr = getRelocationValueRef(Obj, RelI, RE, ObjSectionToID)) + Value = *ValueOrErr; + else + return ValueOrErr.takeError(); + + // PPCMachObjectWriter subtracts the object-layout address of the fixup + // for all PC-relative relocations, external and internal alike, and PPC + // branch displacements are relative to the branch instruction itself, so + // the effective PC offset is 0. + if (RE.IsPCRel) + makeValueAddendPCRel(Value, RelI, 0); + + if (RelType == MachO::PPC_RELOC_BR24 || RelType == MachO::PPC_RELOC_BR14) + processBranchRelocation(RE, Value, Stubs); + else { + RE.Addend = Value.Offset; + if (Value.SymbolName) + addRelocationForSymbol(RE, Value.SymbolName); + else + addRelocationForSection(RE, Value.SectionID); + } + + if (HasPair) + ++RelI; + return ++RelI; + } + + void resolveRelocation(const RelocationEntry &RE, uint64_t Value) override { + LLVM_DEBUG(dumpRelocationToResolve(RE, Value)); + + const SectionEntry &Section = Sections[RE.SectionID]; + uint8_t *LocalAddress = Section.getAddressWithOffset(RE.Offset); + uint64_t FinalAddress = Section.getLoadAddressWithOffset(RE.Offset); + + switch (RE.RelType) { + default: + report_fatal_error("Unhandled MachO PPC relocation type in " + "resolveRelocation"); + case MachO::PPC_RELOC_VANILLA: { + uint64_t FinalValue = Value + RE.Addend; + if (RE.IsPCRel) + FinalValue -= FinalAddress; + writeBytesUnaligned(FinalValue, LocalAddress, 1 << RE.Size); + break; + } + case MachO::PPC_RELOC_BR24: + case MachO::PPC_RELOC_BR14: { + int64_t Displacement = static_cast(Value + RE.Addend) - + static_cast(FinalAddress); + if (Displacement & 0x3) + report_fatal_error("PPC branch target is not 4-byte aligned"); + uint32_t Mask; + if (RE.RelType == MachO::PPC_RELOC_BR24) { + if (!isInt<26>(Displacement)) + report_fatal_error("PPC_RELOC_BR24 relocation out of range"); + Mask = 0x03FFFFFC; + } else { + if (!isInt<16>(Displacement)) + report_fatal_error("PPC_RELOC_BR14 relocation out of range"); + Mask = 0xFFFC; + } + uint32_t Insn = readBytesUnaligned(LocalAddress, 4); + Insn = (Insn & ~Mask) | (static_cast(Displacement) & Mask); + writeBytesUnaligned(Insn, LocalAddress, 4); + break; + } + case MachO::PPC_RELOC_HI16: + case MachO::PPC_RELOC_LO16: + case MachO::PPC_RELOC_HA16: + case MachO::PPC_RELOC_LO14: + applyHalf(RE.RelType, LocalAddress, Value + RE.Addend); + break; + case MachO::PPC_RELOC_SECTDIFF: + case MachO::PPC_RELOC_LOCAL_SECTDIFF: + case MachO::PPC_RELOC_HI16_SECTDIFF: + case MachO::PPC_RELOC_LO16_SECTDIFF: + case MachO::PPC_RELOC_HA16_SECTDIFF: + case MachO::PPC_RELOC_LO14_SECTDIFF: { + uint64_t SectionABase = Sections[RE.Sections.SectionA].getLoadAddress(); + uint64_t SectionBBase = Sections[RE.Sections.SectionB].getLoadAddress(); + assert((Value == SectionABase || Value == SectionBBase) && + "Unexpected SECTDIFF relocation value."); + uint64_t FinalValue = SectionABase - SectionBBase + RE.Addend; + if (RE.RelType == MachO::PPC_RELOC_SECTDIFF || + RE.RelType == MachO::PPC_RELOC_LOCAL_SECTDIFF) + writeBytesUnaligned(FinalValue, LocalAddress, 1 << RE.Size); + else + applyHalf(RE.RelType, LocalAddress, FinalValue); + break; + } + } + } + + Error finalizeSection(const ObjectFile &Obj, unsigned SectionID, + const SectionRef &Section) { + StringRef Name; + Section.getName(Name); + + // Populate (eagerly bind) non-lazy and lazy symbol pointer sections + // from the indirect symbol table; their entries carry no relocations. + if (Name == "__nl_symbol_ptr" || Name == "__la_symbol_ptr" || + Name == "__pointers") + return populateIndirectSymbolPointersSection(cast(Obj), + Section, SectionID); + return Error::success(); + } + +private: + /// Read the big-endian instruction word a relocation applies to. + uint32_t readInstruction(const RelocationEntry &RE) const { + const SectionEntry &Section = Sections[RE.SectionID]; + return readBytesUnaligned(Section.getAddress() + RE.Offset, 4); + } + + /// Fetch the PPC_RELOC_PAIR entry following a half relocation and return + /// the "other half" of the value from its r_address field. The PAIR may + /// be either plain or scattered; r_address is read the same way for both. + Expected getPairOtherHalf(const MachOObjectFile &Obj, + const relocation_iterator &PairRelI) { + MachO::any_relocation_info PairInfo = + Obj.getRelocation(PairRelI->getRawDataRefImpl()); + if (Obj.getAnyRelocationType(PairInfo) != MachO::PPC_RELOC_PAIR) + return make_error( + "PPC half relocation not followed by PPC_RELOC_PAIR"); + return Obj.getAnyRelocationAddress(PairInfo) & 0xFFFFU; + } + + /// Combine the 16 bits kept in a half relocation's instruction with the + /// other half from its PAIR entry into the original 32-bit value. + static int64_t combineHalves(uint32_t RelType, uint32_t InstHalf, + uint32_t OtherHalf) { + uint32_t FullValue; + switch (RelType) { + default: + llvm_unreachable("Unexpected relocation type in combineHalves"); + case MachO::PPC_RELOC_HI16: + case MachO::PPC_RELOC_HI16_SECTDIFF: + FullValue = (InstHalf << 16) | OtherHalf; + break; + case MachO::PPC_RELOC_HA16: + case MachO::PPC_RELOC_HA16_SECTDIFF: + // InstHalf is ha16(value): the high half adjusted for the sign of the + // low half. Undo the adjustment when reassembling the value. + FullValue = (InstHalf << 16) + SignExtend32<16>(OtherHalf); + break; + case MachO::PPC_RELOC_LO16: + case MachO::PPC_RELOC_LO16_SECTDIFF: + FullValue = (OtherHalf << 16) | InstHalf; + break; + case MachO::PPC_RELOC_LO14: + case MachO::PPC_RELOC_LO14_SECTDIFF: + FullValue = (OtherHalf << 16) | (InstHalf & 0xFFFCU); + break; + } + return SignExtend64<32>(FullValue); + } + + /// Patch the low 16 bits of the big-endian instruction word with the + /// appropriate half of Value. + void applyHalf(uint32_t RelType, uint8_t *LocalAddress, uint64_t Value) { + uint32_t Insn = readBytesUnaligned(LocalAddress, 4); + switch (RelType) { + default: + llvm_unreachable("Unexpected relocation type in applyHalf"); + case MachO::PPC_RELOC_HI16: + case MachO::PPC_RELOC_HI16_SECTDIFF: + Insn = (Insn & 0xFFFF0000U) | ((Value >> 16) & 0xFFFFU); + break; + case MachO::PPC_RELOC_HA16: + case MachO::PPC_RELOC_HA16_SECTDIFF: + Insn = (Insn & 0xFFFF0000U) | + (((Value >> 16) + ((Value & 0x8000U) ? 1 : 0)) & 0xFFFFU); + break; + case MachO::PPC_RELOC_LO16: + case MachO::PPC_RELOC_LO16_SECTDIFF: + Insn = (Insn & 0xFFFF0000U) | (Value & 0xFFFFU); + break; + case MachO::PPC_RELOC_LO14: + case MachO::PPC_RELOC_LO14_SECTDIFF: + if (Value & 0x3) + report_fatal_error("PPC_RELOC_LO14 target is not 4-byte aligned"); + Insn = (Insn & 0xFFFF0003U) | (Value & 0xFFFCU); + break; + } + writeBytesUnaligned(Insn, LocalAddress, 4); + } + + /// Redirect a branch through an island in the section's stub area. The + /// island loads the target address with lis/ori (patched via HI16/LO16 + /// relocations on the island itself) and branches through CTR. r12 and + /// CTR are volatile at call boundaries in the Darwin ABI, and r12 is the + /// register the static linker's branch islands use. + void processBranchRelocation(const RelocationEntry &RE, + const RelocationValueRef &Value, + StubMap &Stubs) { + SectionEntry &Section = Sections[RE.SectionID]; + RuntimeDyldMachO::StubMap::const_iterator I = Stubs.find(Value); + uint8_t *Addr; + if (I != Stubs.end()) { + Addr = Section.getAddressWithOffset(I->second); + } else { + assert(Section.getStubOffset() % 4 == 0 && "Misaligned stub"); + uintptr_t StubOffset = Section.getStubOffset(); + Stubs[Value] = StubOffset; + Addr = Section.getAddressWithOffset(StubOffset); + writeBytesUnaligned(0x3D800000U, Addr, 4); // lis r12, hi16(addr) + writeBytesUnaligned(0x618C0000U, Addr + 4, 4); // ori r12, r12, lo16(addr) + writeBytesUnaligned(0x7D8903A6U, Addr + 8, 4); // mtctr r12 + writeBytesUnaligned(0x4E800420U, Addr + 12, 4); // bctr + + RelocationEntry HiRE(RE.SectionID, StubOffset, MachO::PPC_RELOC_HI16, + Value.Offset, false, 2); + RelocationEntry LoRE(RE.SectionID, StubOffset + 4, MachO::PPC_RELOC_LO16, + Value.Offset, false, 2); + if (Value.SymbolName) { + addRelocationForSymbol(HiRE, Value.SymbolName); + addRelocationForSymbol(LoRE, Value.SymbolName); + } else { + addRelocationForSection(HiRE, Value.SectionID); + addRelocationForSection(LoRE, Value.SectionID); + } + Section.advanceStubOffset(getMaxStubSize()); + } + + // Resolve the branch to the island now; the displacement within the + // section does not change when the section's load address changes. + RelocationEntry TargetRE(RE.SectionID, RE.Offset, RE.RelType, 0, + RE.IsPCRel, RE.Size); + resolveRelocation(TargetRE, + static_cast(reinterpret_cast(Addr))); + } + + /// Process a scattered SECTDIFF relocation pair computing "A - B + C". + Expected + processSECTDIFFRelocation(unsigned SectionID, relocation_iterator RelI, + const MachOObjectFile &Obj, + ObjSectionToIDMap &ObjSectionToID) { + MachO::any_relocation_info RE = + Obj.getRelocation(RelI->getRawDataRefImpl()); + + SectionEntry &Section = Sections[SectionID]; + uint32_t RelocType = Obj.getAnyRelocationType(RE); + bool IsPCRel = Obj.getAnyRelocationPCRel(RE); + unsigned Size = Obj.getAnyRelocationLength(RE); + uint64_t Offset = RelI->getOffset(); + uint8_t *LocalAddress = Section.getAddressWithOffset(Offset); + + ++RelI; + MachO::any_relocation_info RE2 = + Obj.getRelocation(RelI->getRawDataRefImpl()); + if (Obj.getAnyRelocationType(RE2) != MachO::PPC_RELOC_PAIR) + return make_error( + "PPC SECTDIFF relocation not followed by PPC_RELOC_PAIR"); + + // Reassemble the encoded value "A - B + C". The half forms keep 16 + // bits in the instruction and the other 16 bits in the PAIR's + // r_address field. + int64_t EncodedValue; + switch (RelocType) { + default: + llvm_unreachable("Unexpected relocation type in " + "processSECTDIFFRelocation"); + case MachO::PPC_RELOC_SECTDIFF: + case MachO::PPC_RELOC_LOCAL_SECTDIFF: + EncodedValue = SignExtend64(readBytesUnaligned(LocalAddress, 1 << Size), + 8 * (1 << Size)); + break; + case MachO::PPC_RELOC_HI16_SECTDIFF: + case MachO::PPC_RELOC_LO16_SECTDIFF: + case MachO::PPC_RELOC_HA16_SECTDIFF: + case MachO::PPC_RELOC_LO14_SECTDIFF: { + uint32_t InstHalf = readBytesUnaligned(LocalAddress, 4) & 0xFFFFU; + uint32_t OtherHalf = Obj.getAnyRelocationAddress(RE2) & 0xFFFFU; + EncodedValue = combineHalves(RelocType, InstHalf, OtherHalf); + break; + } + } + + uint32_t AddrA = Obj.getScatteredRelocationValue(RE); + section_iterator SAI = getSectionByAddress(Obj, AddrA); + assert(SAI != Obj.section_end() && "Can't find section for address A"); + uint64_t SectionABase = SAI->getAddress(); + uint64_t SectionAOffset = AddrA - SectionABase; + SectionRef SectionA = *SAI; + uint32_t SectionAID = ~0U; + if (auto SectionAIDOrErr = + findOrEmitSection(Obj, SectionA, SectionA.isText(), ObjSectionToID)) + SectionAID = *SectionAIDOrErr; + else + return SectionAIDOrErr.takeError(); + + uint32_t AddrB = Obj.getScatteredRelocationValue(RE2); + section_iterator SBI = getSectionByAddress(Obj, AddrB); + assert(SBI != Obj.section_end() && "Can't find section for address B"); + uint64_t SectionBBase = SBI->getAddress(); + uint64_t SectionBOffset = AddrB - SectionBBase; + SectionRef SectionB = *SBI; + uint32_t SectionBID = ~0U; + if (auto SectionBIDOrErr = + findOrEmitSection(Obj, SectionB, SectionB.isText(), ObjSectionToID)) + SectionBID = *SectionBIDOrErr; + else + return SectionBIDOrErr.takeError(); + + // Compute the addend 'C' from the original expression 'A - B + C'. + int64_t Addend = EncodedValue - (static_cast(AddrA) - + static_cast(AddrB)); + + LLVM_DEBUG(dbgs() << "Found SECTDIFF: AddrA: " << AddrA + << ", AddrB: " << AddrB << ", Addend: " << Addend + << ", SectionA ID: " << SectionAID << ", SectionAOffset: " + << SectionAOffset << ", SectionB ID: " << SectionBID + << ", SectionBOffset: " << SectionBOffset << "\n"); + RelocationEntry R(SectionID, Offset, RelocType, Addend, SectionAID, + SectionAOffset, SectionBID, SectionBOffset, IsPCRel, + Size); + + addRelocationForSection(R, SectionAID); + + return ++RelI; + } + + /// Process a scattered half relocation against "local symbol + offset". + /// PPCMachObjectWriter emits these when a defined symbol is referenced + /// with a non-zero offset that still fits the scattered encoding. + Expected + processScatteredHalf(unsigned SectionID, relocation_iterator RelI, + const MachOObjectFile &Obj, + ObjSectionToIDMap &ObjSectionToID) { + MachO::any_relocation_info RE = + Obj.getRelocation(RelI->getRawDataRefImpl()); + + SectionEntry &Section = Sections[SectionID]; + uint32_t RelocType = Obj.getAnyRelocationType(RE); + bool IsPCRel = Obj.getAnyRelocationPCRel(RE); + unsigned Size = Obj.getAnyRelocationLength(RE); + uint64_t Offset = RelI->getOffset(); + uint32_t InstHalf = + readBytesUnaligned(Section.getAddressWithOffset(Offset), 4) & 0xFFFFU; + + ++RelI; + uint32_t OtherHalf; + if (auto OtherHalfOrErr = getPairOtherHalf(Obj, RelI)) + OtherHalf = *OtherHalfOrErr; + else + return OtherHalfOrErr.takeError(); + + // The encoded value is the object-layout address of the target plus the + // constant offset. + int64_t EncodedValue = combineHalves(RelocType, InstHalf, OtherHalf); + + uint32_t SymbolBaseAddr = Obj.getScatteredRelocationValue(RE); + section_iterator TargetSI = getSectionByAddress(Obj, SymbolBaseAddr); + assert(TargetSI != Obj.section_end() && "Can't find section for symbol"); + uint64_t SectionBaseAddr = TargetSI->getAddress(); + SectionRef TargetSection = *TargetSI; + bool IsCode = TargetSection.isText(); + uint32_t TargetSectionID = ~0U; + if (auto TargetSectionIDOrErr = + findOrEmitSection(Obj, TargetSection, IsCode, ObjSectionToID)) + TargetSectionID = *TargetSectionIDOrErr; + else + return TargetSectionIDOrErr.takeError(); + + RelocationEntry R(SectionID, Offset, RelocType, + EncodedValue - SectionBaseAddr, IsPCRel, Size); + addRelocationForSection(R, TargetSectionID); + + return ++RelI; + } +}; + +} // end namespace llvm + +#undef DEBUG_TYPE + +#endif diff -Naur a/llvm/test/ExecutionEngine/RuntimeDyld/PowerPC/MachO_PPC_relocations.s b/llvm/test/ExecutionEngine/RuntimeDyld/PowerPC/MachO_PPC_relocations.s --- a/llvm/test/ExecutionEngine/RuntimeDyld/PowerPC/MachO_PPC_relocations.s +++ b/llvm/test/ExecutionEngine/RuntimeDyld/PowerPC/MachO_PPC_relocations.s 2026-08-19 07:16:32.322878325 +0000 @@ -0,0 +1,101 @@ +; RUN: rm -rf %t && mkdir -p %t +; RUN: llvm-mc -triple=powerpc-apple-darwin9 -filetype=obj -o %t/ppc_macho.o %s +; RUN: llvm-rtdyld -triple=powerpc-apple-darwin9 -verify -check=%s %t/ppc_macho.o + + .section __TEXT,__text,regular,pure_instructions + .globl _foo + .align 2 +_foo: + blr + +; Absolute high/low halves of a local symbol in another section +; (regular HA16/LO16 relocations, each followed by a PPC_RELOC_PAIR): +; rtdyld-check: *{4}insn1 = 0x3C400000 + (lcpi0 + 0x8000)[31:16] +insn1: + lis r2, ha16(lcpi0) +; rtdyld-check: *{4}insn2 = 0x60430000 + lcpi0[15:0] +insn2: + ori r3, r2, lo16(lcpi0) + +; Same, with a non-zero offset from the symbol (scattered halves): +; rtdyld-check: *{4}insn3 = 0x3C400000 + (lcpi0 + 8 + 0x8000)[31:16] +insn3: + lis r2, ha16(lcpi0 + 8) +; rtdyld-check: *{4}insn4 = 0x60430000 + (lcpi0 + 8)[15:0] +insn4: + ori r3, r2, lo16(lcpi0 + 8) + +; Section-difference high/low halves (HA16_SECTDIFF/LO16_SECTDIFF pairs), +; the pattern picbase-relative (PIC) addressing produces: +; rtdyld-check: *{4}insn5 = 0x3C820000 + (ddata - _foo + 0x8000)[31:16] +insn5: + addis r4, r2, ha16(ddata - _foo) +; rtdyld-check: *{4}insn6 = 0x60850000 + (ddata - _foo)[15:0] +insn6: + ori r5, r4, lo16(ddata - _foo) + +; Non-lazy symbol pointer addressing (regular halves against the pointer, +; plus indirect-symbol population of the __nl_symbol_ptr entry itself): +; rtdyld-check: *{4}insn7 = 0x3CC00000 + (ext_ptr + 0x8000)[31:16] +insn7: + lis r6, ha16(ext_ptr) +; rtdyld-check: *{4}insn8 = 0x80C60000 + ext_ptr[15:0] +insn8: + lwz r6, lo16(ext_ptr)(r6) + +; External call: redirected through a lis/ori/mtctr/bctr island in the +; stub area. Check both the island contents and the branch to it. +; rtdyld-check: *{4}(stub_addr(ppc_macho.o, __text, _baz)) = 0x3D800000 + _baz[31:16] +; rtdyld-check: *{4}(stub_addr(ppc_macho.o, __text, _baz) + 4) = 0x618C0000 + _baz[15:0] +; rtdyld-check: *{4}(stub_addr(ppc_macho.o, __text, _baz) + 8) = 0x7D8903A6 +; rtdyld-check: *{4}(stub_addr(ppc_macho.o, __text, _baz) + 12) = 0x4E800420 +; rtdyld-check: *{4}insn9 = 0x48000001 + (stub_addr(ppc_macho.o, __text, _baz) - insn9)[25:0] +insn9: + bl _baz + +; Call to a symbol defined in this module (also via an island): +; rtdyld-check: *{4}(stub_addr(ppc_macho.o, __text, _foo) + 4) = 0x618C0000 + _foo[15:0] +insn10: + bl _foo + blr + + .section __DATA,__data + .align 2 +lcpi0: + .long 1 + .long 2 + .long 3 + .long 4 +ddata: + .long 0 + +; 32-bit absolute pointers: defined-internal, defined-with-offset +; (scattered VANILLA), and external: +; rtdyld-check: *{4}p0 = _foo +p0: + .long _foo +; rtdyld-check: *{4}sv0 = lcpi0 + 8 +sv0: + .long lcpi0 + 8 +; rtdyld-check: *{4}pe0 = _baz +pe0: + .long _baz + +; 32-bit section difference (LOCAL_SECTDIFF): +; rtdyld-check: *{4}sd0 = insn2 - _foo +sd0: + .long insn2 - _foo + +; Non-lazy symbol pointers get their values from the indirect symbol +; table, not from relocations: +; rtdyld-check: *{4}ext_ptr = _ext + .section __DATA,__nl_symbol_ptr,non_lazy_symbol_pointers + .align 2 +ext_ptr: + .indirect_symbol _ext + .long 0 + + .comm _baz, 4, 2 + .comm _ext, 4, 2 + +.subsections_via_symbols