Index: ELF/Config.h =================================================================== --- ELF/Config.h +++ ELF/Config.h @@ -146,6 +146,8 @@ uint64_t EntryAddr = 0; uint64_t ImageBase; uint64_t MaxPageSize; + uint64_t SdaBase; + uint64_t Sda2Base; uint64_t ZStackSize; unsigned LtoPartitions; unsigned LtoO; Index: ELF/Driver.cpp =================================================================== --- ELF/Driver.cpp +++ ELF/Driver.cpp @@ -700,6 +700,27 @@ return V; } +// Parses -sda-base options. +static std::pair getSdaBases(opt::InputArgList &Args) { + // If argument not given or invalid, use ~0 value; triggering + // midpoint calculation in the first matching small output section. + auto CheckSdaArg = [](opt::Arg *Arg) -> uint64_t { + if (Arg) { + StringRef S = Arg->getValue(); + uint64_t V; + if (S.getAsInteger(0, V)) + error(Arg->getOption().getPrefixedName() + + ": number expected, but got " + S); + else + return V; + } + return ~0; + }; + + return std::make_pair(CheckSdaArg(Args.getLastArg(OPT_sda_base)), + CheckSdaArg(Args.getLastArg(OPT_sda2_base))); +} + // Do actual linking. Note that when this function is called, // all linker scripts have already been parsed. template void LinkerDriver::link(opt::InputArgList &Args) { @@ -716,6 +737,7 @@ Config->Mips64EL = (Config->EMachine == EM_MIPS && Config->EKind == ELF64LEKind); Config->ImageBase = getImageBase(Args); + std::tie(Config->SdaBase, Config->Sda2Base) = getSdaBases(Args); // Default output filename is "a.out" by the Unix tradition. if (Config->OutputFile.empty()) Index: ELF/InputSection.cpp =================================================================== --- ELF/InputSection.cpp +++ ELF/InputSection.cpp @@ -425,6 +425,30 @@ if (Body.isUndefined() && !Body.isLocal() && Body.symbol()->isWeak()) return getAArch64Page(A); return getAArch64Page(Body.getVA(A)) - getAArch64Page(P); + case R_PPC_SDA: { + auto CheckReturn = [](int64_t Val, uint32_t Reg) -> typename ELFT::uint { + if (Val > 32767 || Val < -32768) + error("Small data relocation delta exceeds 16-bit value"); + return (Val & 0xffff) | (Reg << 16); + }; + const DefinedRegular *RelSym = dyn_cast>(&Body); + if (RelSym && RelSym->Section) { + const InputSectionBase *Section = RelSym->Section; + if (Section->OutSec) { + // Relocate relative to _SDA_BASE_ or _SDA2_BASE_ synthetic symbols. + const OutputSectionBase *OutSec = RelSym->Section->OutSec; + if (ElfSym::SdaBase && + (OutSec->getName() == ".sdata" || OutSec->getName() == ".sbss")) + return CheckReturn(Body.getVA(A) - + int64_t(ElfSym::SdaBase->Value), 13); + if (ElfSym::Sda2Base && OutSec->getName() == ".sdata2") + return CheckReturn(Body.getVA(A) - + int64_t(ElfSym::Sda2Base->Value), 2); + } + } + error("Unable to perform small data relocation without designated section"); + return 0; + } } llvm_unreachable("Invalid expression"); } Index: ELF/Options.td =================================================================== --- ELF/Options.td +++ ELF/Options.td @@ -161,6 +161,10 @@ def script: S<"script">, HelpText<"Read linker script">; +def sda_base : J<"sda-base=">, HelpText<"Set the small data base address">; + +def sda2_base : J<"sda2-base=">, HelpText<"Set the second small data base address">; + def section_start: S<"section-start">, MetaVarName<"
">, HelpText<"Set address of section">; Index: ELF/Relocations.h =================================================================== --- ELF/Relocations.h +++ ELF/Relocations.h @@ -48,6 +48,7 @@ R_PPC_OPD, R_PPC_PLT_OPD, R_PPC_TOC, + R_PPC_SDA, R_RELAX_GOT_PC, R_RELAX_GOT_PC_NOPIC, R_RELAX_TLS_GD_TO_IE, Index: ELF/Symbols.h =================================================================== --- ELF/Symbols.h +++ ELF/Symbols.h @@ -380,6 +380,10 @@ // The content for _gp_disp symbol for MIPS target. static SymbolBody *MipsGpDisp; + + // The content for _SDA_BASE_ and _SDA2_BASE_ symbols. + static DefinedSynthetic *SdaBase; + static DefinedSynthetic *Sda2Base; }; template DefinedRegular *ElfSym::EhdrStart; @@ -390,6 +394,8 @@ template DefinedRegular *ElfSym::End; template DefinedRegular *ElfSym::End2; template SymbolBody *ElfSym::MipsGpDisp; +template DefinedSynthetic *ElfSym::SdaBase; +template DefinedSynthetic *ElfSym::Sda2Base; // A real symbol object, SymbolBody, is usually stored within a Symbol. There's // always one Symbol for each symbol name. The resolver updates the SymbolBody Index: ELF/Target.cpp =================================================================== --- ELF/Target.cpp +++ ELF/Target.cpp @@ -972,9 +972,31 @@ case R_PPC_REL32: write32be(Loc, Val); break; - case R_PPC_REL24: - or32be(Loc, Val & 0x3FFFFFC); + case R_PPC_ADDR24: + case R_PPC_REL24: { + uint32_t Inst = read32be(Loc); + Inst &= ~0x3FFFFFC; + Inst |= Val & 0x3FFFFFC; + write32be(Loc, Inst); + break; + } + case R_PPC_ADDR14: + case R_PPC_REL14: { + uint32_t Inst = read32be(Loc); + Inst &= ~0xFFFC; + Inst |= Val & 0xFFFC; + write32be(Loc, Inst); break; + } + case R_PPC_EMB_SDA21: { + // SDA21 relocation entry is offset one byte into instruction + uint8_t *InstLoc = Loc - 1; + uint32_t Inst = read32be(InstLoc); + Inst &= ~0x1FFFFF; + Inst |= Val & 0x1FFFFF; + write32be(InstLoc, Inst); + break; + } default: fatal("unrecognized reloc " + Twine(Type)); } @@ -984,7 +1006,10 @@ switch (Type) { case R_PPC_REL24: case R_PPC_REL32: + case R_PPC_REL14: return R_PC; + case R_PPC_EMB_SDA21: + return R_PPC_SDA; default: return R_ABS; } Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -599,6 +599,19 @@ addOptionalSynthetic("__gnu_local_gp", Out::Got, MipsGPOffset); } + if (Config->EMachine == EM_PPC && !Config->Relocatable) { + // In the event a non-relocatable PPC32 target is being built, reserve + // Small Data base registers. These will be relocated midway through + // the .sdata and .sdata2 sections (if used). This symbol is meant to + // be applied in EABI systems, where r13 and r2 are initialized to these + // linker-generated symbols by the C runtime initialization. + Symbol *Sym; + Sym = Symtab::X->addSynthetic("_SDA_BASE_", nullptr, 0, STV_HIDDEN); + ElfSym::SdaBase = cast>(Sym->body()); + Sym = Symtab::X->addSynthetic("_SDA2_BASE_", nullptr, 0, STV_HIDDEN); + ElfSym::Sda2Base = cast>(Sym->body()); + } + // In the assembly for 32 bit x86 the _GLOBAL_OFFSET_TABLE_ symbol // is magical and is used to produce a R_386_GOTPC relocation. // The R_386_GOTPC relocation value doesn't actually depend on the @@ -1348,6 +1361,36 @@ if (ElfSym::EhdrStart) ElfSym::EhdrStart->Value = Out::ProgramHeaders->Addr; + auto SectionMidpoint = [](OutputSectionBase *Sec) -> + typename ELFT::uint { + return ((Sec->Size / 2) & ~0x3) + Sec->Addr; + }; + + // PPC-EABI systems will need the _SDA_BASE_ and _SDA2_BASE_ symbols + // synthesized for use by C runtime init. The section midpoints are used + // to maximize addressing range. If these values are defined with + // -sda-base/-sda2-base options, those are overridden accordingly. + if (ElfSym::SdaBase) { + if (Config->SdaBase != uint64_t(~0)) + ElfSym::SdaBase->Value = Config->SdaBase; + else { + OutputSectionBase *Sec = findSection(".sdata"); + if (!Sec) + Sec = findSection(".sbss"); + if (Sec) + ElfSym::SdaBase->Value = SectionMidpoint(Sec); + } + } + if (ElfSym::Sda2Base) { + if (Config->Sda2Base != uint64_t(~0)) + ElfSym::Sda2Base->Value = Config->Sda2Base; + else { + OutputSectionBase *Sec = findSection(".sdata2"); + if (Sec) + ElfSym::Sda2Base->Value = SectionMidpoint(Sec); + } + } + auto Set = [](DefinedRegular *S1, DefinedRegular *S2, uintX_t V) { if (S1) S1->Value = V; Index: test/ELF/ppc-relocs.s =================================================================== --- test/ELF/ppc-relocs.s +++ test/ELF/ppc-relocs.s @@ -1,8 +1,18 @@ # RUN: llvm-mc -filetype=obj -triple=powerpc-unknown-freebsd %s -o %t # RUN: ld.lld %t -o %t2 -# RUN: llvm-objdump -d %t2 | FileCheck %s +# RUN: llvm-objdump -disassemble-all %t2 | FileCheck %s # REQUIRES: ppc +.sdata2 +smallstr2: + .long 0xDEADD00D + .long 0xABCDEFAB + +# CHECK: Disassembly of section .sdata2: +# CHECK: smallstr2: +# CHECK: 100d4: de ad d0 0d stfdu 21, -12275(13) +# CHECK: 100d8: ab cd ef ab lha 30, -4181(13) + .section .R_PPC_ADDR16_HA,"ax",@progbits .globl _start _start: @@ -62,3 +72,31 @@ # CHECK: Disassembly of section .R_PPC_ADDR32: # CHECK: .FR_PPC_ADDR32: # CHECK: 1101c: 00 01 10 20 + +.section .R_PPC_EMB_SDA21,"ax",@progbits + lis 13, _SDA_BASE_@ha + ori 13, 13, _SDA_BASE_@l + lis 2, _SDA2_BASE_@ha + ori 2, 2, _SDA2_BASE_@l + lwz 4, smallstr@sdarx(0) + lwz 5, smallstr2@sdarx(0) + +# CHECK: Disassembly of section .R_PPC_EMB_SDA21: +# CHECK: .R_PPC_EMB_SDA21: +# CHECK: 11020: 3d a0 00 01 lis 13, 1 +# CHECK: 11024: 61 ad 20 04 ori 13, 13, 8196 +# CHECK: 11028: 3c 40 00 01 lis 2, 1 +# CHECK: 1102c: 60 42 00 d8 ori 2, 2, 216 +# CHECK: 11030: 80 8d 00 00 lwz 4, 0(13) +# CHECK: 11034: 80 a2 ff fc lwz 5, -4(2) + +.sdata + .long 0xABCDEFAB +smallstr: + .long 0xDEADBEEF + +# CHECK: Disassembly of section .sdata: +# CHECK: .sdata: +# CHECK: 12000: ab cd ef ab lha 30, -4181(13) +# CHECK: smallstr: +# CHECK: 12004: de ad be ef stfdu 21, -16657(13)