Index: ELF/Arch/X86.cpp =================================================================== --- ELF/Arch/X86.cpp +++ ELF/Arch/X86.cpp @@ -32,8 +32,16 @@ void writeGotPlt(uint8_t *Buf, const Symbol &S) const override; void writeIgotPlt(uint8_t *Buf, const Symbol &S) const override; void writePltHeader(uint8_t *Buf) const override; + virtual void writePltImpl(uint8_t *Buf, uint64_t GotPltEntryAddr, + uint64_t PltEntryAddr, int32_t Index, + unsigned RelOff, unsigned PrefixSize) const; void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, - int32_t Index, unsigned RelOff) const override; + int32_t Index, unsigned RelOff) const override { + return writePltImpl(Buf, GotPltEntryAddr, PltEntryAddr, Index, RelOff, 0); + } + void writeCanonicalPlt(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; RelExpr adjustRelaxExpr(RelType Type, const uint8_t *Data, @@ -57,6 +65,8 @@ GotEntrySize = 4; GotPltEntrySize = 4; PltEntrySize = 16; + if (Config->Pic) + CanonicalPltEntrySize = PltEntrySize + 12; PltHeaderSize = 16; TlsGdRelaxSkip = 2; TrapInstr = 0xcccccccc; // 0xcc = INT3 @@ -158,7 +168,10 @@ void X86::writeGotPlt(uint8_t *Buf, const Symbol &S) const { // Entries in .got.plt initially points back to the corresponding // PLT entries with a fixed offset to skip the first instruction. - write32le(Buf, S.getPltVA() + 6); + if (S.NeedsPltAddr) + write32le(Buf, S.getPltVA() + 6 + 12); + else + write32le(Buf, S.getPltVA() + 6); } void X86::writeIgotPlt(uint8_t *Buf, const Symbol &S) const { @@ -201,9 +214,9 @@ write32le(Buf + 8, GotPlt + 8); } -void X86::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, - uint64_t PltEntryAddr, int32_t Index, - unsigned RelOff) const { +void X86::writePltImpl(uint8_t *Buf, uint64_t GotPltEntryAddr, + uint64_t PltEntryAddr, int32_t Index, unsigned RelOff, + unsigned PrefixSize) const { const uint8_t Inst[] = { 0xff, 0x00, 0, 0, 0, 0, // jmp *foo_in_GOT or jmp *foo@GOT(%ebx) 0x68, 0, 0, 0, 0, // pushl $reloc_offset @@ -223,7 +236,26 @@ } write32le(Buf + 7, RelOff); - write32le(Buf + 12, -Index * PltEntrySize - PltHeaderSize - 16); + write32le(Buf + 12, -InX::Plt->getPltEntryStart(Index) - 16 - PrefixSize); +} + +void X86::writeCanonicalPlt(uint8_t *Buf, uint64_t GotPltEntryAddr, + uint64_t PltEntryAddr, int32_t Index, + unsigned RelOff) const { + unsigned PrefixSize = 0; + if (Config->Pic) { + const uint8_t Inst[] = { + 0xe8, 0x00, 0x00, 0x00, 0x00, // call + 0x5b, // pop %ebx + 0x81, 0xc3, 0x03, 0x00, 0x00, 0x00 // add $_GLOBAL_OFFSET_TABLE_,%ebx + }; + memcpy(Buf, Inst, sizeof(Inst)); + write32le(Buf + 8, + InX::Got->getVA() + InX::Got->getSize() - PltEntryAddr + 8 - 13); + Buf += sizeof(Inst); + PrefixSize = sizeof(Inst); + } + writePltImpl(Buf, GotPltEntryAddr, PltEntryAddr, Index, RelOff, PrefixSize); } int64_t X86::getImplicitAddend(const uint8_t *Buf, RelType Type) const { @@ -404,8 +436,9 @@ RetpolinePic(); void writeGotPlt(uint8_t *Buf, const Symbol &S) 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 writePltImpl(uint8_t *Buf, uint64_t GotPltEntryAddr, + uint64_t PltEntryAddr, int32_t Index, unsigned RelOff, + unsigned PrefixSize) const override; }; class RetpolineNoPic : public X86 { @@ -413,18 +446,23 @@ RetpolineNoPic(); void writeGotPlt(uint8_t *Buf, const Symbol &S) 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 writePltImpl(uint8_t *Buf, uint64_t GotPltEntryAddr, + uint64_t PltEntryAddr, int32_t Index, unsigned RelOff, + unsigned PrefixSize) const override; }; } // namespace RetpolinePic::RetpolinePic() { PltHeaderSize = 48; PltEntrySize = 32; + CanonicalPltEntrySize = PltEntrySize + 12; } void RetpolinePic::writeGotPlt(uint8_t *Buf, const Symbol &S) const { - write32le(Buf, S.getPltVA() + 17); + if (S.NeedsPltAddr) + write32le(Buf, S.getPltVA() + 17 + 12); + else + write32le(Buf, S.getPltVA() + 17); } void RetpolinePic::writePltHeader(uint8_t *Buf) const { @@ -452,9 +490,9 @@ write32le(Buf + 9, GotPlt + 8); } -void RetpolinePic::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, - uint64_t PltEntryAddr, int32_t Index, - unsigned RelOff) const { +void RetpolinePic::writePltImpl(uint8_t *Buf, uint64_t GotPltEntryAddr, + uint64_t PltEntryAddr, int32_t Index, + unsigned RelOff, unsigned PrefixSize) const { const uint8_t Insn[] = { 0x50, // pushl %eax 0x8b, 0x83, 0, 0, 0, 0, // mov foo@GOT(%ebx), %eax @@ -467,10 +505,11 @@ uint32_t Ebx = InX::Got->getVA() + InX::Got->getSize(); write32le(Buf + 3, GotPltEntryAddr - Ebx); - write32le(Buf + 8, -Index * PltEntrySize - PltHeaderSize - 12 + 32); - write32le(Buf + 13, -Index * PltEntrySize - PltHeaderSize - 17 + 18); + unsigned Start = InX::Plt->getPltEntryStart(Index); + write32le(Buf + 8, -Start - 12 + 32 - PrefixSize); + write32le(Buf + 13, -Start - 17 + 18 - PrefixSize); write32le(Buf + 18, RelOff); - write32le(Buf + 23, -Index * PltEntrySize - PltHeaderSize - 27); + write32le(Buf + 23, -Start - 27 - PrefixSize); } RetpolineNoPic::RetpolineNoPic() { @@ -507,9 +546,10 @@ write32le(Buf + 8, GotPlt + 8); } -void RetpolineNoPic::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, - uint64_t PltEntryAddr, int32_t Index, - unsigned RelOff) const { +void RetpolineNoPic::writePltImpl(uint8_t *Buf, uint64_t GotPltEntryAddr, + uint64_t PltEntryAddr, int32_t Index, + unsigned RelOff, unsigned PrefixSize) const { + assert(PrefixSize == 0 && "Wrote a ebx prefix for a non pic output"); const uint8_t Insn[] = { 0x50, // 0: pushl %eax 0xa1, 0, 0, 0, 0, // 1: mov foo_in_GOT, %eax Index: ELF/Driver.cpp =================================================================== --- ELF/Driver.cpp +++ ELF/Driver.cpp @@ -1011,6 +1011,8 @@ // all linker scripts have already been parsed. template void LinkerDriver::link(opt::InputArgList &Args) { Target = getTarget(); + if (Target->CanonicalPltEntrySize == 0) + Target->CanonicalPltEntrySize = Target->PltEntrySize; Config->MaxPageSize = getMaxPageSize(Args); Config->ImageBase = getImageBase(Args); Index: ELF/Relocations.cpp =================================================================== --- ELF/Relocations.cpp +++ ELF/Relocations.cpp @@ -876,6 +876,8 @@ // plt. That is identified by special relocation types (R_X86_64_JUMP_SLOT, // R_386_JMP_SLOT, etc). Sym.NeedsPltAddr = true; + if (Config->EMachine == EM_386) + InX::Got->HasGotOffRel = true; Expr = toPlt(Expr); Sec.Relocations.push_back({Expr, Type, Offset, Addend, &Sym}); return Expr; Index: ELF/Symbols.cpp =================================================================== --- ELF/Symbols.cpp +++ ELF/Symbols.cpp @@ -139,8 +139,7 @@ uint64_t Symbol::getPltVA() const { if (this->IsInIplt) return InX::Iplt->getVA() + PltIndex * Target->PltEntrySize; - return InX::Plt->getVA() + Target->PltHeaderSize + - PltIndex * Target->PltEntrySize; + return InX::Plt->getVA() + InX::Plt->getPltEntryStart(PltIndex); } uint64_t Symbol::getSize() const { Index: ELF/SyntheticSections.h =================================================================== --- ELF/SyntheticSections.h +++ ELF/SyntheticSections.h @@ -24,6 +24,7 @@ #include "EhFrame.h" #include "GdbIndex.h" #include "InputSection.h" +#include "Target.h" #include "llvm/ADT/MapVector.h" #include "llvm/MC/StringTableBuilder.h" #include @@ -508,14 +509,28 @@ PltSection(bool IsIplt); void writeTo(uint8_t *Buf) override; size_t getSize() const override; + void finalizeContents() override; bool empty() const override { return Entries.empty(); } void addSymbols(); - + size_t numEntries() { return Entries.size(); } template void addEntry(Symbol &Sym); + unsigned getPltEntryStart(int32_t Index) { + int32_t NumRegular = numEntries() - NumCanonicalEntries; + if (Index < NumRegular) + return Target->PltHeaderSize + Index * Target->PltEntrySize; + return Target->PltHeaderSize + NumRegular * Target->PltEntrySize + + (Index - NumRegular) * Target->CanonicalPltEntrySize; + } + + // The number of plt entries for NeedsPltAddr symbols. They are called + // canonical because they are used as the address of the symbol. + size_t NumCanonicalEntries; + private: unsigned getPltRelocOff() const; std::vector> Entries; + size_t HeaderSize; bool IsIplt; }; Index: ELF/SyntheticSections.cpp =================================================================== --- ELF/SyntheticSections.cpp +++ ELF/SyntheticSections.cpp @@ -1882,12 +1882,17 @@ unsigned PltOff = getPltRelocOff(); for (auto &I : Entries) { - const Symbol *B = I.first; + const Symbol *S = I.first; unsigned RelOff = I.second + PltOff; - uint64_t Got = B->getGotPltVA(); + uint64_t Got = S->getGotPltVA(); uint64_t Plt = this->getVA() + Off; - Target->writePlt(Buf + Off, Got, Plt, B->PltIndex, RelOff); - Off += Target->PltEntrySize; + if (S->NeedsPltAddr) { + Target->writeCanonicalPlt(Buf + Off, Got, Plt, S->PltIndex, RelOff); + Off += Target->CanonicalPltEntrySize; + } else { + Target->writePlt(Buf + Off, Got, Plt, S->PltIndex, RelOff); + Off += Target->PltEntrySize; + } } } @@ -1903,8 +1908,17 @@ Entries.push_back(std::make_pair(&Sym, RelOff)); } +void PltSection::finalizeContents() { + auto I = llvm::partition(Entries, [](std::pair &P) { + return !P.first->NeedsPltAddr; + }); + NumCanonicalEntries = std::distance(I, Entries.end()); +} + size_t PltSection::getSize() const { - return HeaderSize + Entries.size() * Target->PltEntrySize; + return HeaderSize + + (Entries.size() - NumCanonicalEntries) * Target->PltEntrySize + + NumCanonicalEntries * Target->CanonicalPltEntrySize; } // Some architectures such as additional symbols in the PLT section. For Index: ELF/Target.h =================================================================== --- ELF/Target.h +++ ELF/Target.h @@ -40,6 +40,11 @@ virtual void writePlt(uint8_t *Buf, uint64_t GotEntryAddr, uint64_t PltEntryAddr, int32_t Index, unsigned RelOff) const {} + virtual void writeCanonicalPlt(uint8_t *Buf, uint64_t GotEntryAddr, + uint64_t PltEntryAddr, int32_t Index, + unsigned RelOff) const { + writePlt(Buf, GotEntryAddr, PltEntryAddr, Index, RelOff); + } virtual void addPltHeaderSymbols(InputSection &IS) const {} virtual void addPltSymbols(InputSection &IS, uint64_t Off) const {} @@ -91,6 +96,7 @@ RelType TlsOffsetRel; unsigned GotEntrySize = 0; unsigned GotPltEntrySize = 0; + unsigned CanonicalPltEntrySize = 0; unsigned PltEntrySize; unsigned PltHeaderSize; Index: test/ELF/Inputs/i386-pic-plt.s =================================================================== --- /dev/null +++ test/ELF/Inputs/i386-pic-plt.s @@ -0,0 +1,7 @@ + .global foo + .type foo, @function + .global bar + .type bar, @function +bar: +foo: + nop Index: test/ELF/i386-pic-plt.s =================================================================== --- /dev/null +++ test/ELF/i386-pic-plt.s @@ -0,0 +1,58 @@ +// REQUIRES: x86 +// RUN: llvm-mc -filetype=obj -triple=i386-pc-linux %s -o %t.o +// RUN: llvm-mc -filetype=obj -triple=i386-pc-linux %p/Inputs/i386-pic-plt.s -o %t2.o +// RUN: ld.lld -shared %t2.o -o %t2.so +// RUN: ld.lld %t.o %t2.so -o %t +// RUN: llvm-objdump -d %t | FileCheck %s +// RUN: ld.lld %t.o %t2.so -o %t2 -pie +// RUN: llvm-objdump -d %t2 | FileCheck --check-prefix=PIE %s +// RUN: ld.lld %t.o %t2.so -o %t3 -pie -z retpolineplt +// RUN: llvm-objdump -d %t3 | FileCheck --check-prefix=PICRET %s + + +// CHECK: Disassembly of section .plt: +// CHECK: jmpl *73740 +// CHECK-NEXT: pushl $0 +// CHECK-NEXT: jmp -32 <.plt> +// CHECK-NEXT: jmpl *73744 +// CHECK-NEXT: pushl $8 +// CHECK-NEXT: jmp -48 <.plt> + +// PIE: Disassembly of section .plt: +// PIE: calll 0 +// PIE-NEXT: popl %ebx +// PIE-NEXT: addl $8259, %ebx +// PIE-NEXT: jmpl *-4188(%ebx) +// PIE-NEXT: pushl $0 +// PIE-NEXT: jmp -44 <.plt> +// PIE-NEXT: calll 0 +// PIE-NEXT: %ebx +// PIE-NEXT: addl $8231, %ebx +// PIE-NEXT: jmpl *-4184(%ebx) +// PIE-NEXT: pushl $8 +// PIE-NEXT: jmp -72 <.plt> + +// PICRET: Disassembly of section .plt: +// PICRET: calll 0 +// PICRET-NEXT: popl %ebx +// PICRET-NEXT: addl $8227, %ebx +// PICRET-NEXT: pushl %eax +// PICRET-NEXT: movl -4188(%ebx), %eax +// PICRET-NEXT: calll -40 <.plt+0x20> +// PICRET-NEXT: jmp -59 <.plt+0x12> +// PICRET-NEXT: pushl $0 +// PICRET-NEXT: jmp -87 <.plt> +// PICRET: calll 0 <.plt+0x61> +// PICRET-NEXT: popl %ebx +// PICRET-NEXT: addl $8183, %ebx +// PICRET-NEXT: pushl %eax +// PICRET-NEXT: movl -4184(%ebx), %eax +// PICRET-NEXT: calll -84 <.plt+0x20> +// PICRET-NEXT: jmp -103 <.plt+0x12> +// PICRET-NEXT: pushl $8 +// PICRET-NEXT: jmp -131 <.plt> + +.global _start +_start: + call foo + call bar