Index: ELF/SyntheticSections.h =================================================================== --- ELF/SyntheticSections.h +++ ELF/SyntheticSections.h @@ -267,7 +267,10 @@ class GotPltSection final : public SyntheticSection { public: GotPltSection(); + void addEntry(Symbol &Sym); + size_t getEntryCount() const; + size_t getSize() const override; void writeTo(uint8_t *Buf) override; bool empty() const override; @@ -360,6 +363,7 @@ void addInt(int32_t Tag, uint64_t Val); void addInSec(int32_t Tag, InputSection *Sec); void addInSecRelative(int32_t Tag, InputSection *Sec); + void addInSecWithOffset(int32_t Tag, InputSection *Sec, uint32_t Offset); void addOutSec(int32_t Tag, OutputSection *Sec); void addSize(int32_t Tag, OutputSection *Sec); void addSym(int32_t Tag, Symbol *Sym); @@ -831,6 +835,30 @@ size_t Size = 0; }; +class PPC64GlinkSection : public SyntheticSection { +public: + PPC64GlinkSection(); + + int32_t getOffsetForDynamicTag() const; + size_t getSize() const override; + void writeTo(uint8_t *Buf) override; + bool empty() const override; + +private: + size_t getEntryCount() const; + enum { + // 13 instructions * 4 bytes per instruction + 8 bytes for offset to first + // got.plt entry = 60 bytes. + GenericResolverStubSize = 60, // 13 * 4 + 8 + // A single branch instruction. (b __glink_PLTResolve) + StubSize = 4, + // The DT_PPC64_GLINK specifed in the V2 abi must point 32 bytes before the + // first glink lazy resolver stub. + DynamicTagOffset = 32 + }; +}; + + InputSection *createInterpSection(); MergeInputSection *createCommentSection(); void decompressSections(); @@ -867,6 +895,7 @@ static StringTableSection *ShStrTab; static StringTableSection *StrTab; static SymbolTableBaseSection *SymTab; + static PPC64GlinkSection *Glink; }; template struct In { Index: ELF/SyntheticSections.cpp =================================================================== --- ELF/SyntheticSections.cpp +++ ELF/SyntheticSections.cpp @@ -913,6 +913,10 @@ !(ElfSym::GlobalOffsetTable && Target->GotBaseSymInGotPlt); } +size_t GotPltSection::getEntryCount() const { + return Entries.size(); +} + // On ARM the IgotPltSection is part of the GotSection, on other Targets it is // part of the .got.plt IgotPltSection::IgotPltSection() @@ -1029,6 +1033,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; }}); } @@ -1190,6 +1200,17 @@ } } + + // This needs to be predicated on an abi version check, since this tag is only + // for the V2 abi. I'm using an endianess check for now, but this isn't truly + // appropriate becuase there is no reason you couldn't use the V2 abi on a BE + // machine. + if (Config->EMachine == EM_PPC64 && ELF64LEKind && + !InX::Glink->empty()) { + addInSecWithOffset(DT_LOPROC + 0, InX::Glink, + InX::Glink->getOffsetForDynamicTag()); + } + addInt(DT_NULL, 0); getParent()->Link = this->Link; @@ -2674,6 +2695,66 @@ return Changed; } +PPC64GlinkSection::PPC64GlinkSection() + : SyntheticSection(SHF_ALLOC | SHF_EXECINSTR, SHT_PROGBITS, + 16, ".glink") { +} + +int32_t PPC64GlinkSection::getOffsetForDynamicTag() const { + // The first lazy resolver stub follows the shared resolver, and the dynamic + // tag points 32 bytes before that lazy resolver stub. + return GenericResolverStubSize - DynamicTagOffset; +} + +size_t PPC64GlinkSection::getEntryCount() const { + // There is one resolver stub for each GotPlt entry. + assert(InX::GotPlt); + return InX::GotPlt->getEntryCount(); +} + +bool PPC64GlinkSection::empty() const { + return getEntryCount() == 0; +} + +void PPC64GlinkSection::writeTo(uint8_t *Buf) { + if (empty()) + return; + + // 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 offset from the instruction after the branch (mflr r11) to the first + // entry in the GotPlt section. + int64_t GotPltOffset = InX::GotPlt->getVA() - (getVA() + 8); + write64(Buf + 52, GotPltOffset); + + // We then emit the stubs that branch to the resolver function. + const uint32_t BranchOp = 0x48000000; + const uint32_t BranchOffsetMask = 0x03FFFFFc; + // The entry written to 'Offset' must branch to the start of + // __glink_PLTResolver, which is a 'b -Offset'. + for (uint32_t EntryIndex = 0; EntryIndex != getEntryCount(); ++EntryIndex) { + int32_t Offset = GenericResolverStubSize + EntryIndex * StubSize; + write32(Buf + Offset, BranchOp | ((-Offset) & BranchOffsetMask)); + } +} + +size_t PPC64GlinkSection::getSize() const { + return empty() ? 0 : (GenericResolverStubSize + (StubSize * getEntryCount())); +} + InputSection *InX::ARMAttributes; BssSection *InX::Bss; BssSection *InX::BssRelRo; @@ -2700,6 +2781,7 @@ StringTableSection *InX::ShStrTab; StringTableSection *InX::StrTab; SymbolTableBaseSection *InX::SymTab; +PPC64GlinkSection *InX::Glink; template GdbIndexSection *elf::createGdbIndex(); template GdbIndexSection *elf::createGdbIndex(); Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -396,6 +396,12 @@ // Add a sentinel to terminate .ARM.exidx. It helps an unwinder // to find the exact address range of the last entry. Add(make()); + + + if (Config->EMachine == EM_PPC64) { + InX::Glink = make(); + Add(InX::Glink); + } } // The main function of the writer. Index: test/ELF/ppc64le-glink.s =================================================================== --- /dev/null +++ test/ELF/ppc64le-glink.s @@ -0,0 +1,76 @@ +// REQUIRES: 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 +// RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %p/Inputs/shared2-ppc64le.s -o %t3.o +// RUN: ld.lld -shared %t3.o -o %t3.so +// RUN: ld.lld -shared %t3.o %t3.so +// RUN: ld.lld -dynamic-linker /lib64/ld64.so.2 %t.o %t2.so %t3.so -o %t +// RUN: llvm-readelf -dynamic-table %t | FileCheck %s +// RUN: llvm-objdump -D %t | FileCheck --check-prefix=DIS %s + + .text + .abiversion 2 + .globl _start + .p2align 4 + .type _start,@function +_start: +.Lfunc_begin0: +.Lfunc_gep0: + addis 2, 12, .TOC.-.Lfunc_gep0@ha + addi 2, 2, .TOC.-.Lfunc_gep0@l +.Lfunc_lep0: + .localentry _start, .Lfunc_lep0-.Lfunc_gep0 + bl foo + nop + bl bar + nop + bl baz + nop + li 0, 1 + sc + .size _start, .-.Lfunc_begin0 + +// First check that the dynamic tag is emitted. +// CHECK: DynamicSection [ +// CHECK-NEXT: Tag Type Name/Value +// CHECK: 0x0000000070000000 PPC64_GLINK 0x100100ac + + +// Check the disassembly for _glink_PLTResolve. We want to verify the address of +// the instruction after the 'bcl' instruction, since we need to check the +// offset from there to the .got.plt section matches the offset stored at the +// end of this stub. +// DIS: Disassembly of section .glink: +// DIS-NEXT: .glink: +// DIS-NEXT: mflr 0 +// DIS-NEXT: bcl 20, 31, .+4 +// DIS-NEXT: 10010098: a6 02 68 7d mflr 11 +// DIS-NEXT: mtlr 0 +// DIS-NEXT: subf 12, 11, 12 +// DIS-NEXT: addi 0, 12, -52 +// DIS-NEXT: rldicl 0, 0, 62, 2 +// DIS-NEXT: ld 12, 44(11) +// DIS-NEXT: add 11, 12, 11 +// DIS-NEXT: ld 12, 0(11) +// DIS-NEXT: ld 11, 8(11) +// DIS-NEXT: mtctr 12 +// DIS-NEXT: bctr + +// Following _glink_PLTResolve is the offset from (_glink + 8) to first entry of +// .got.plt section. +// DIS-NEXT: 68 ff 00 00 +// DIS_NEXT: 00 00 00 00 + +// Check that we have a branch to _glink_PLTResolve for each external function. +// The first branch must be 32 bytes after the address Value from the +// PPC64_GLINK dynamic tag. 0x100100ac + 0x20 = 0x100100cc +// DIS: 100100cc: c4 ff ff 4b b .+67108804 +// DIS-NEXT: b .+67108800 +// DIS-NEXT: b .+67108796 + +// Check that the address of the first entry in the .got.plt section is +// 0x10010098 + 0xff68 = 0x10020000 +// DIS: Disassembly of section .got.plt: +// DIS-NEXT: .got.plt +// DIS-NEXT: 10020000 Index: test/ELF/ppc64le-plt-stub.s =================================================================== --- test/ELF/ppc64le-plt-stub.s +++ test/ELF/ppc64le-plt-stub.s @@ -2,7 +2,7 @@ // 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 -// RUN: ld.lld %t.o %t2.so -o %t +// RUN: ld.lld -dynamic-linker /lib64/ld64.so.2 %t.o %t2.so -o %t // RUN: llvm-objdump -d %t | FileCheck %s // CHECK: Disassembly of section .text: @@ -32,6 +32,6 @@ // CHECK: .plt: // CHECK-NEXT: 18 00 41 f8 std 2, 24(1) // CHECK-NEXT: fe ff 82 3d addis 12, 2, -2 -// CHECK-NEXT: 40 7f 8c e9 ld 12, 32576(12) +// CHECK-NEXT: 30 7f 8c e9 ld 12, 32560(12) // CHECK-NEXT: a6 03 89 7d mtctr 12 // CHECK: 20 04 80 4e bctr