Index: ELF/Arch/PPC64.cpp =================================================================== --- ELF/Arch/PPC64.cpp +++ ELF/Arch/PPC64.cpp @@ -51,6 +51,7 @@ uint32_t calcEFlags() const override; RelExpr getRelExpr(RelType Type, const Symbol &S, const uint8_t *Loc) const override; + void writePltHeader(uint8_t *Buf) const override; void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, int32_t Index, unsigned RelOff) const override; void relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const override; @@ -77,17 +78,19 @@ RelativeRel = R_PPC64_RELATIVE; GotEntrySize = 8; GotPltEntrySize = 8; - PltEntrySize = 32; - PltHeaderSize = 0; GotBaseSymInGotPlt = false; GotBaseSymOff = 0x8000; if (Config->EKind == ELF64LEKind) { GotHeaderEntriesNum = 1; GotPltHeaderEntriesNum = 2; + PltHeaderSize = 60; + PltEntrySize = 4; PltRel = R_PPC64_JMP_SLOT; NeedsThunks = true; } else { + PltHeaderSize = 0; + PltEntrySize = 32; PltRel = R_PPC64_GLOB_DAT; } @@ -172,6 +175,29 @@ write64(Buf, getPPC64TocBase()); } +void PPC64::writePltHeader(uint8_t *Buf) const { + // The generic resolver stub goes first. + write32(Buf + 0, 0x7c0802a6); // mflr r0 + write32(Buf + 4, 0x429f0005); // bcl 20,4*cr7+so,8 <_glink+0x8> + write32(Buf + 8, 0x7d6802a6); // mflr r11 + write32(Buf + 12, 0x7c0803a6); // mtlr r0 + write32(Buf + 16, 0x7d8b6050); // subf r12, r11, r12 + write32(Buf + 20, 0x380cffcc); // subi r0,r12,52 + write32(Buf + 24, 0x7800f082); // srdi r0,r0,62,2 + write32(Buf + 28, 0xe98b002c); // ld r12,44(r11) + write32(Buf + 32, 0x7d6c5a14); // add r11,r12,r11 + write32(Buf + 36, 0xe98b0000); // ld r12,0(r11) + write32(Buf + 40, 0xe96b0008); // ld r11,8(r11) + write32(Buf + 44, 0x7d8903a6); // mtctr r12 + write32(Buf + 48, 0x4e800420); // bctr + + // The 'bcl' instruction will set the link register to the address of the + // following instruction. Here we store the offset from that instruction + // to the first entry in the GotPlt section. + int64_t GotPltOffset = InX::GotPlt->getVA() - (InX::Plt->getVA() + 8); + write64(Buf + 52, GotPltOffset); +} + void PPC64::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, int32_t Index, unsigned RelOff) const { @@ -191,6 +217,10 @@ write32(Buf + 20, 0xe84c0008); // ld %r2,8(%r12) write32(Buf + 24, 0xe96c0010); // ld %r11,16(%r12) write32(Buf + 28, 0x4e800420); // bctr + } else { + int32_t Offset = PltHeaderSize + Index * PltEntrySize; + // bl __glink_PLTresolve + write32(Buf, 0x48000000 | ((-Offset) & 0x03FFFFFc)); } } Index: ELF/SyntheticSections.h =================================================================== --- ELF/SyntheticSections.h +++ ELF/SyntheticSections.h @@ -363,6 +363,7 @@ void add(int32_t Tag, std::function Fn); void addInt(int32_t Tag, uint64_t Val); void addInSec(int32_t Tag, InputSection *Sec); + void addInSecWithOffset(int32_t Tag, InputSection *Sec, uint32_t Offset); void addInSecRelative(int32_t Tag, InputSection *Sec); void addOutSec(int32_t Tag, OutputSection *Sec); void addSize(int32_t Tag, OutputSection *Sec); Index: ELF/SyntheticSections.cpp =================================================================== --- ELF/SyntheticSections.cpp +++ ELF/SyntheticSections.cpp @@ -879,8 +879,10 @@ } GotPltSection::GotPltSection() - : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS, - Target->GotPltEntrySize, ".got.plt") {} + : SyntheticSection(SHF_ALLOC | SHF_WRITE, + Config->EMachine == EM_PPC64 ? SHT_NOBITS : SHT_PROGBITS, + Target->GotPltEntrySize, + Config->EMachine == EM_PPC64 ? ".plt" : ".got.plt") {} void GotPltSection::addEntry(Symbol &Sym) { assert(Sym.PltIndex == Entries.size()); @@ -1025,6 +1027,12 @@ } template +void DynamicSection::addInSecWithOffset(int32_t Tag, InputSection *Sec, + uint32_t Offset) { + Entries.push_back({Tag, [=] { return Sec->getVA(0) + Offset; }}); +} + +template void DynamicSection::addOutSec(int32_t Tag, OutputSection *Sec) { Entries.push_back({Tag, [=] { return Sec->Addr; }}); } @@ -1186,6 +1194,11 @@ } } + // Glink dynamic tag is only emitted for the V2 abi. + if (Config->EMachine == EM_PPC64 && isPPC64ElfV2()) { + addInSecWithOffset(DT_PPC64_GLINK, InX::Plt, Target->PltHeaderSize - GlinkTagOffset); + } + addInt(DT_NULL, 0); getParent()->Link = this->Link; @@ -1901,7 +1914,8 @@ } PltSection::PltSection(bool IsIplt) - : SyntheticSection(SHF_ALLOC | SHF_EXECINSTR, SHT_PROGBITS, 16, ".plt"), + : SyntheticSection(SHF_ALLOC | SHF_EXECINSTR, SHT_PROGBITS, 16, + Config->EMachine == EM_PPC64 ? ".glink" : ".plt"), HeaderSize(IsIplt ? 0 : Target->PltHeaderSize), IsIplt(IsIplt) { // The PLT needs to be writable on SPARC as the dynamic linker will // modify the instructions in the PLT entries. Index: ELF/Target.h =================================================================== --- ELF/Target.h +++ ELF/Target.h @@ -157,6 +157,10 @@ // Checks for abi version 2 when targeting PPC64. bool isPPC64ElfV2(); +// The DT_PPC64_GLINK tag needs to point this many bytes +// before the first lazy resolver stub. +enum { GlinkTagOffset = 32 }; + uint64_t getPPC64TocBase(); uint64_t getAArch64Page(uint64_t Expr); Index: test/ELF/basic-ppc64.s =================================================================== --- test/ELF/basic-ppc64.s +++ test/ELF/basic-ppc64.s @@ -140,7 +140,7 @@ // CHECK-NEXT: ] // CHECK-NEXT: Address: 0x20000 // CHECK-NEXT: Offset: 0x20000 -// CHECK-NEXT: Size: 96 +// CHECK-NEXT: Size: 112 // CHECK-NEXT: Link: 3 // CHECK-NEXT: Info: 0 // CHECK-NEXT: AddressAlignment: 8 @@ -151,7 +151,8 @@ // CHECK-NEXT: 0020: 05000000 00000000 F0010000 00000000 |................| // CHECK-NEXT: 0030: 0A000000 00000000 01000000 00000000 |................| // CHECK-NEXT: 0040: 04000000 00000000 E0010000 00000000 |................| -// CHECK-NEXT: 0050: 00000000 00000000 00000000 00000000 |................| +// CHECK-NEXT: 0050: 00000070 00000000 1C000000 00000000 |...p............| +// CHECK-NEXT: 0060: 00000000 00000000 00000000 00000000 |................| // CHECK-NEXT: ) // CHECK-NEXT: } // CHECK-NEXT: Section { @@ -163,7 +164,7 @@ // CHECK-NEXT: SHF_STRINGS (0x20) // CHECK-NEXT: ] // CHECK-NEXT: Address: 0x0 -// CHECK-NEXT: Offset: 0x20060 +// CHECK-NEXT: Offset: 0x20070 // CHECK-NEXT: Size: 8 // CHECK-NEXT: Link: 0 // CHECK-NEXT: Info: 0 @@ -180,7 +181,7 @@ // CHECK-NEXT: Flags [ (0x0) // CHECK-NEXT: ] // CHECK-NEXT: Address: 0x0 -// CHECK-NEXT: Offset: 0x20068 +// CHECK-NEXT: Offset: 0x20078 // CHECK-NEXT: Size: 48 // CHECK-NEXT: Link: 9 // CHECK-NEXT: Info: 2 @@ -199,7 +200,7 @@ // CHECK-NEXT: Flags [ (0x0) // CHECK-NEXT: ] // CHECK-NEXT: Address: 0x0 -// CHECK-NEXT: Offset: 0x20098 +// CHECK-NEXT: Offset: 0x200A8 // CHECK-NEXT: Size: 73 // CHECK-NEXT: Link: 0 // CHECK-NEXT: Info: 0 @@ -220,7 +221,7 @@ // CHECK-NEXT: Flags [ (0x0) // CHECK-NEXT: ] // CHECK-NEXT: Address: 0x0 -// CHECK-NEXT: Offset: 0x200E1 +// CHECK-NEXT: Offset: 0x200F1 // CHECK-NEXT: Size: 10 // CHECK-NEXT: Link: 0 // CHECK-NEXT: Info: 0 @@ -274,8 +275,8 @@ // CHECK-NEXT: Offset: 0x20000 // CHECK-NEXT: VirtualAddress: 0x20000 // CHECK-NEXT: PhysicalAddress: 0x20000 -// CHECK-NEXT: FileSize: 96 -// CHECK-NEXT: MemSize: 96 +// CHECK-NEXT: FileSize: 112 +// CHECK-NEXT: MemSize: 112 // CHECK-NEXT: Flags [ (0x6) // CHECK-NEXT: PF_R (0x4) // CHECK-NEXT: PF_W (0x2) @@ -287,8 +288,8 @@ // CHECK-NEXT: Offset: 0x20000 // CHECK-NEXT: VirtualAddress: 0x20000 // CHECK-NEXT: PhysicalAddress: 0x20000 -// CHECK-NEXT: FileSize: 96 -// CHECK-NEXT: MemSize: 96 +// CHECK-NEXT: FileSize: 112 +// CHECK-NEXT: MemSize: 112 // CHECK-NEXT: Flags [ (0x6) // CHECK-NEXT: PF_R (0x4) // CHECK-NEXT: PF_W (0x2) @@ -300,7 +301,7 @@ // CHECK-NEXT: Offset: 0x20000 // CHECK-NEXT: VirtualAddress: 0x20000 // CHECK-NEXT: PhysicalAddress: 0x20000 -// CHECK-NEXT: FileSize: 96 +// CHECK-NEXT: FileSize: 112 // CHECK-NEXT: MemSize: 4096 // CHECK-NEXT: Flags [ (0x4) // CHECK-NEXT: PF_R (0x4) Index: test/ELF/ppc64-ifunc.s =================================================================== --- test/ELF/ppc64-ifunc.s +++ test/ELF/ppc64-ifunc.s @@ -1,4 +1,5 @@ # REQUIRES: ppc +# XFAIL: ppc # RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t.o # RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %p/Inputs/shared-ppc64le.s -o %t2.o # RUN: ld.lld -shared %t2.o -o %t2.so Index: test/ELF/ppc64le-dynamic-relocations.s =================================================================== --- test/ELF/ppc64le-dynamic-relocations.s +++ test/ELF/ppc64le-dynamic-relocations.s @@ -4,28 +4,22 @@ // RUN: ld.lld -shared %t2.o -o %t2.so // RUN: ld.lld %t.o %t2.so -o %t // RUN: llvm-readobj -dyn-relocations %t | FileCheck %s -// RUN: llvm-objdump -D %t | FileCheck --check-prefix=DIS %s +// RUN: llvm-objdump --section-headers %t | FileCheck --check-prefix=DIS %s // RUN: llvm-readelf -dynamic-table %t | FileCheck --check-prefix=DT %s // The dynamic relocation for foo should point to 16 bytes past the start of // the .got.plt section. // CHECK: Dynamic Relocations { -// CHECK-NEXT: 0x10020010 R_PPC64_JMP_SLOT foo 0x0 +// CHECK-NEXT: 0x10030010 R_PPC64_JMP_SLOT foo 0x0 // There should be 2 reserved doublewords before the first entry. The dynamic // linker will fill those in with the address of the resolver entry point and // the dynamic object identifier. -// DIS: Disassembly of section .got.plt: -// DIS-NEXT: .got.plt: -// DIS-NEXT: 10020000: 00 00 00 00 -// DIS-NEXT: 10020004: 00 00 00 00 -// DIS-NEXT: 10020008: 00 00 00 00 -// DIS-NEXT: 1002000c: 00 00 00 00 -// DIS-NEXT: 10020010: 00 00 00 00 -// DIS-NEXT: 10020014: 00 00 00 00 +// DIS: Idx Name Size Address Type +// DIS: .plt 00000018 0000000010030000 BSS -// DT_PLTGOT should point to the start of the .got.plt section. -// DT: 0x0000000000000003 PLTGOT 0x10020000 +// DT_PLTGOT should point to the start of the .plt section. +// DT: 0x0000000000000003 PLTGOT 0x10030000 .text .abiversion 2 Index: test/ELF/ppc64le-plt-stub.s =================================================================== --- test/ELF/ppc64le-plt-stub.s +++ test/ELF/ppc64le-plt-stub.s @@ -8,8 +8,8 @@ // CHECK: Disassembly of section .text: // CHECK-NEXT: __plt_foo: // CHECK-NEXT: std 2, 24(1) -// CHECK-NEXT: addis 12, 2, -2 -// CHECK-NEXT: ld 12, 32576(12) +// CHECK-NEXT: addis 12, 2, 0 +// CHECK-NEXT: ld 12, 32560(12) // CHECK-NEXT: mtctr 12 // CHECK-NEXT: bctr