Index: lld/trunk/ELF/OutputSections.h =================================================================== --- lld/trunk/ELF/OutputSections.h +++ lld/trunk/ELF/OutputSections.h @@ -117,6 +117,23 @@ }; template +class GotPltSection final : public OutputSectionBase { + typedef OutputSectionBase Base; + typedef typename Base::uintX_t uintX_t; + +public: + GotPltSection(); + void finalize() override; + void writeTo(uint8_t *Buf) override; + void addEntry(SymbolBody *Sym); + bool empty() const; + uintX_t getEntryAddr(const SymbolBody &B) const; + +private: + std::vector Entries; +}; + +template class PltSection final : public OutputSectionBase { typedef OutputSectionBase Base; typedef typename Base::uintX_t uintX_t; @@ -172,7 +189,7 @@ typedef typename llvm::object::ELFFile::uintX_t uintX_t; public: - RelocationSection(bool IsRela); + RelocationSection(StringRef Name, bool IsRela); void addReloc(const DynamicReloc &Reloc) { Relocs.push_back(Reloc); } void finalize() override; void writeTo(uint8_t *Buf) override; @@ -284,6 +301,7 @@ // until Writer is initialized. template struct Out { static DynamicSection *Dynamic; + static GotPltSection *GotPlt; static GotSection *Got; static HashTableSection *HashTab; static InterpSection *Interp; @@ -292,6 +310,7 @@ static uint8_t *OpdBuf; static PltSection *Plt; static RelocationSection *RelaDyn; + static RelocationSection *RelaPlt; static StringTableSection *DynStrTab; static StringTableSection *StrTab; static SymbolTableSection *DynSymTab; @@ -299,6 +318,7 @@ }; template DynamicSection *Out::Dynamic; +template GotPltSection *Out::GotPlt; template GotSection *Out::Got; template HashTableSection *Out::HashTab; template InterpSection *Out::Interp; @@ -307,6 +327,7 @@ template uint8_t *Out::OpdBuf; template PltSection *Out::Plt; template RelocationSection *Out::RelaDyn; +template RelocationSection *Out::RelaPlt; template StringTableSection *Out::DynStrTab; template StringTableSection *Out::StrTab; template SymbolTableSection *Out::DynSymTab; Index: lld/trunk/ELF/OutputSections.cpp =================================================================== --- lld/trunk/ELF/OutputSections.cpp +++ lld/trunk/ELF/OutputSections.cpp @@ -30,6 +30,43 @@ } template +GotPltSection::GotPltSection() + : OutputSectionBase(".got.plt", llvm::ELF::SHT_PROGBITS, + llvm::ELF::SHF_ALLOC | + llvm::ELF::SHF_WRITE) { + this->Header.sh_addralign = this->getAddrSize(); + // .got.plt has 3 reserved entry + Entries.resize(3); +} + +template void GotPltSection::addEntry(SymbolBody *Sym) { + Sym->GotPltIndex = Entries.size(); + Entries.push_back(Sym); +} + +template bool GotPltSection::empty() const { + return Entries.size() == 3; +} + +template +typename GotPltSection::uintX_t +GotPltSection::getEntryAddr(const SymbolBody &B) const { + return this->getVA() + B.GotPltIndex * this->getAddrSize(); +} + +template void GotPltSection::finalize() { + this->Header.sh_size = Entries.size() * this->getAddrSize(); +} + +template void GotPltSection::writeTo(uint8_t *Buf) { + for (const SymbolBody *B : Entries) { + if (B) + Target->writeGotPltEntry(Buf, Out::Plt->getEntryAddr(*B)); + Buf += sizeof(uintX_t); + } +} + +template GotSection::GotSection() : OutputSectionBase(".got", llvm::ELF::SHT_PROGBITS, llvm::ELF::SHF_ALLOC | @@ -69,10 +106,13 @@ template void PltSection::writeTo(uint8_t *Buf) { size_t Off = 0; + // First write PLT[0] entry which is special. + Target->writePltZeroEntry(Buf, Out::GotPlt->getVA(), this->getVA()); + Off += Target->getPltZeroEntrySize(); for (const SymbolBody *E : Entries) { - uint64_t Got = Out::Got->getEntryAddr(*E); + uint64_t Got = Out::GotPlt->getEntryAddr(*E); uint64_t Plt = this->getVA() + Off; - Target->writePltEntry(Buf + Off, Got, Plt); + Target->writePltEntry(Buf + Off, Got, Plt, E->PltIndex); Off += Target->getPltEntrySize(); } } @@ -85,19 +125,20 @@ template typename PltSection::uintX_t PltSection::getEntryAddr(const SymbolBody &B) const { - return this->getVA() + B.PltIndex * Target->getPltEntrySize(); + return this->getVA() + Target->getPltZeroEntrySize() + + B.PltIndex * Target->getPltEntrySize(); } template void PltSection::finalize() { - this->Header.sh_size = Entries.size() * Target->getPltEntrySize(); + this->Header.sh_size = + Target->getPltZeroEntrySize() + Entries.size() * Target->getPltEntrySize(); } template -RelocationSection::RelocationSection(bool IsRela) - : OutputSectionBase(IsRela ? ".rela.dyn" : ".rel.dyn", - IsRela ? llvm::ELF::SHT_RELA - : llvm::ELF::SHT_REL, +RelocationSection::RelocationSection(StringRef Name, bool IsRela) + : OutputSectionBase(Name, IsRela ? llvm::ELF::SHT_RELA + : llvm::ELF::SHT_REL, llvm::ELF::SHF_ALLOC), IsRela(IsRela) { this->Header.sh_entsize = IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel); @@ -135,10 +176,22 @@ } if (Body && Target->relocNeedsGot(Type, *Body)) { - P->r_offset = Out::Got->getEntryAddr(*Body); + // Each symbol that needs plt relocation is placed to Plt and GotPlt, + // otherwise to Got. + // Also symbol can be placed both to Got and Plt + GotPlt, for example + // when we take address of function from DSO and also make a call to it. + // So here depending on what type of relocation is we switch from which + // table to take the offset from. + bool NeedsPlt = Target->relocNeedsPlt(Type, *Body); + if (NeedsPlt) + P->r_offset = Out::GotPlt->getEntryAddr(*Body); + else + P->r_offset = Out::Got->getEntryAddr(*Body); if (CanBePreempted) P->setSymbolAndType(Body->getDynamicSymbolTableIndex(), - Target->getGotReloc(), IsMips64EL); + NeedsPlt ? Target->getPltReloc() + : Target->getGotReloc(), + IsMips64EL); } else { if (IsRela) Addend += static_cast(RI).r_addend; @@ -255,6 +308,12 @@ ++NumEntries; // DT_RELASZ / DT_RELSZ ++NumEntries; // DT_RELAENT / DT_RELENT } + if (Out::RelaPlt->hasRelocs()) { + ++NumEntries; // DT_JMPREL + ++NumEntries; // DT_PLTRELSZ + ++NumEntries; // DT_PLTGOT + ++NumEntries; // DT_PLTREL + } ++NumEntries; // DT_SYMTAB ++NumEntries; // DT_SYMENT ++NumEntries; // DT_STRTAB @@ -323,7 +382,12 @@ WriteVal(IsRela ? DT_RELAENT : DT_RELENT, IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel)); } - + if (Out::RelaPlt->hasRelocs()) { + WritePtr(DT_JMPREL, Out::RelaPlt->getVA()); + WriteVal(DT_PLTRELSZ, Out::RelaPlt->getSize()); + WritePtr(DT_PLTGOT, Out::Got->getVA()); + WriteVal(DT_PLTREL, Out::RelaPlt->isRela() ? DT_RELA : DT_REL); + } WritePtr(DT_SYMTAB, Out::DynSymTab->getVA()); WritePtr(DT_SYMENT, sizeof(Elf_Sym)); WritePtr(DT_STRTAB, Out::DynStrTab->getVA()); @@ -695,6 +759,11 @@ template void OutputSectionBase::writeHeaderTo( ELFFile>::Elf_Shdr *SHdr); +template class GotPltSection; +template class GotPltSection; +template class GotPltSection; +template class GotPltSection; + template class GotSection; template class GotSection; template class GotSection; Index: lld/trunk/ELF/Symbols.h =================================================================== --- lld/trunk/ELF/Symbols.h +++ lld/trunk/ELF/Symbols.h @@ -79,8 +79,10 @@ void setDynamicSymbolTableIndex(unsigned V) { DynamicSymbolTableIndex = V; } uint32_t GotIndex = -1; + uint32_t GotPltIndex = -1; uint32_t PltIndex = -1; bool isInGot() const { return GotIndex != -1U; } + bool isInGotPlt() const { return GotPltIndex != -1U; } bool isInPlt() const { return PltIndex != -1U; } // A SymbolBody has a backreference to a Symbol. Originally they are Index: lld/trunk/ELF/Target.h =================================================================== --- lld/trunk/ELF/Target.h +++ lld/trunk/ELF/Target.h @@ -24,11 +24,16 @@ uint64_t getVAStart() const { return VAStart; } unsigned getPCRelReloc() const { return PCRelReloc; } unsigned getGotReloc() const { return GotReloc; } + unsigned getPltReloc() const { return PltReloc; } unsigned getGotRefReloc() const { return GotRefReloc; } unsigned getRelativeReloc() const { return RelativeReloc; } + unsigned getPltZeroEntrySize() const { return PltZeroEntrySize; } unsigned getPltEntrySize() const { return PltEntrySize; } + virtual void writeGotPltEntry(uint8_t *Buf, uint64_t Plt) const = 0; + virtual void writePltZeroEntry(uint8_t *Buf, uint64_t GotEntryAddr, + uint64_t PltEntryAddr) const = 0; virtual void writePltEntry(uint8_t *Buf, uint64_t GotEntryAddr, - uint64_t PltEntryAddr) const = 0; + uint64_t PltEntryAddr, int32_t Index) const = 0; virtual bool isRelRelative(uint32_t Type) const; virtual bool relocNeedsGot(uint32_t Type, const SymbolBody &S) const = 0; virtual bool relocPointsToGot(uint32_t Type) const; @@ -45,15 +50,21 @@ unsigned PCRelReloc; unsigned GotRefReloc; unsigned GotReloc; + unsigned PltReloc; unsigned RelativeReloc; unsigned PltEntrySize = 8; + unsigned PltZeroEntrySize = 16; + llvm::StringRef DefaultEntry = "_start"; }; class X86TargetInfo final : public TargetInfo { public: X86TargetInfo(); + void writeGotPltEntry(uint8_t *Buf, uint64_t Plt) const override; + void writePltZeroEntry(uint8_t *Buf, uint64_t GotEntryAddr, + uint64_t PltEntryAddr) const override; void writePltEntry(uint8_t *Buf, uint64_t GotEntryAddr, - uint64_t PltEntryAddr) const override; + uint64_t PltEntryAddr, int32_t Index) const override; bool relocNeedsGot(uint32_t Type, const SymbolBody &S) const override; bool relocPointsToGot(uint32_t Type) const override; bool relocNeedsPlt(uint32_t Type, const SymbolBody &S) const override; @@ -65,8 +76,11 @@ class X86_64TargetInfo final : public TargetInfo { public: X86_64TargetInfo(); + void writeGotPltEntry(uint8_t *Buf, uint64_t Plt) const override; + void writePltZeroEntry(uint8_t *Buf, uint64_t GotEntryAddr, + uint64_t PltEntryAddr) const override; void writePltEntry(uint8_t *Buf, uint64_t GotEntryAddr, - uint64_t PltEntryAddr) const override; + uint64_t PltEntryAddr, int32_t Index) const override; bool relocNeedsGot(uint32_t Type, const SymbolBody &S) const override; bool relocNeedsPlt(uint32_t Type, const SymbolBody &S) const override; void relocateOne(uint8_t *Buf, uint8_t *BufEnd, const void *RelP, @@ -78,8 +92,11 @@ class PPC64TargetInfo final : public TargetInfo { public: PPC64TargetInfo(); + void writeGotPltEntry(uint8_t *Buf, uint64_t Plt) const override; + void writePltZeroEntry(uint8_t *Buf, uint64_t GotEntryAddr, + uint64_t PltEntryAddr) const override; void writePltEntry(uint8_t *Buf, uint64_t GotEntryAddr, - uint64_t PltEntryAddr) const override; + uint64_t PltEntryAddr, int32_t Index) const override; bool relocNeedsGot(uint32_t Type, const SymbolBody &S) const override; bool relocNeedsPlt(uint32_t Type, const SymbolBody &S) const override; void relocateOne(uint8_t *Buf, uint8_t *BufEnd, const void *RelP, @@ -91,8 +108,11 @@ class PPCTargetInfo final : public TargetInfo { public: PPCTargetInfo(); + void writeGotPltEntry(uint8_t *Buf, uint64_t Plt) const override; + void writePltZeroEntry(uint8_t *Buf, uint64_t GotEntryAddr, + uint64_t PltEntryAddr) const override; void writePltEntry(uint8_t *Buf, uint64_t GotEntryAddr, - uint64_t PltEntryAddr) const override; + uint64_t PltEntryAddr, int32_t Index) const override; bool relocNeedsGot(uint32_t Type, const SymbolBody &S) const override; bool relocNeedsPlt(uint32_t Type, const SymbolBody &S) const override; void relocateOne(uint8_t *Buf, uint8_t *BufEnd, const void *RelP, @@ -103,8 +123,11 @@ class AArch64TargetInfo final : public TargetInfo { public: AArch64TargetInfo(); + void writeGotPltEntry(uint8_t *Buf, uint64_t Plt) const override; + void writePltZeroEntry(uint8_t *Buf, uint64_t GotEntryAddr, + uint64_t PltEntryAddr) const override; void writePltEntry(uint8_t *Buf, uint64_t GotEntryAddr, - uint64_t PltEntryAddr) const override; + uint64_t PltEntryAddr, int32_t Index) const override; bool relocNeedsGot(uint32_t Type, const SymbolBody &S) const override; bool relocNeedsPlt(uint32_t Type, const SymbolBody &S) const override; void relocateOne(uint8_t *Buf, uint8_t *BufEnd, const void *RelP, @@ -115,8 +138,11 @@ class MipsTargetInfo final : public TargetInfo { public: MipsTargetInfo(); + void writeGotPltEntry(uint8_t *Buf, uint64_t Plt) const override; + void writePltZeroEntry(uint8_t *Buf, uint64_t GotEntryAddr, + uint64_t PltEntryAddr) const override; void writePltEntry(uint8_t *Buf, uint64_t GotEntryAddr, - uint64_t PltEntryAddr) const override; + uint64_t PltEntryAddr, int32_t Index) const override; bool relocNeedsGot(uint32_t Type, const SymbolBody &S) const override; bool relocNeedsPlt(uint32_t Type, const SymbolBody &S) const override; void relocateOne(uint8_t *Buf, uint8_t *BufEnd, const void *RelP, Index: lld/trunk/ELF/Target.cpp =================================================================== --- lld/trunk/ELF/Target.cpp +++ lld/trunk/ELF/Target.cpp @@ -55,16 +55,40 @@ PCRelReloc = R_386_PC32; GotReloc = R_386_GLOB_DAT; GotRefReloc = R_386_GOT32; + PltReloc = R_386_JUMP_SLOT; + PltEntrySize = 16; VAStart = 0x10000; } +void X86TargetInfo::writeGotPltEntry(uint8_t *Buf, uint64_t Plt) const { + // Skip 6 bytes of "jmpq *got(%rip)" + write32le(Buf, Plt + 6); +} + +void X86TargetInfo::writePltZeroEntry(uint8_t *Buf, uint64_t GotEntryAddr, + uint64_t PltEntryAddr) const { + const uint8_t PltData[] = { + 0xff, 0x35, 0x00, 0x00, 0x00, 0x00, // pushq GOT+8(%rip) + 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp *GOT+16(%rip) + 0x00, 0x00, 0x00, 0x00 + }; + memcpy(Buf, PltData, sizeof(PltData)); + write32le(Buf + 2, GotEntryAddr - PltEntryAddr + 2); // GOT+8 + write32le(Buf + 8, GotEntryAddr - PltEntryAddr + 4); // GOT+16 +}; + void X86TargetInfo::writePltEntry(uint8_t *Buf, uint64_t GotEntryAddr, - uint64_t PltEntryAddr) const { - // jmpl *val; nop; nop - const uint8_t Inst[] = {0xff, 0x25, 0, 0, 0, 0, 0x90, 0x90}; + uint64_t PltEntryAddr, int32_t Index) const { + const uint8_t Inst[] = { + 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmpq *got(%rip) + 0x68, 0x00, 0x00, 0x00, 0x00, // pushq + 0xe9, 0x00, 0x00, 0x00, 0x00 // jmpq plt[0] + }; memcpy(Buf, Inst, sizeof(Inst)); - assert(isUInt<32>(GotEntryAddr)); - write32le(Buf + 2, GotEntryAddr); + + write32le(Buf + 2, GotEntryAddr - PltEntryAddr - 6); + write32le(Buf + 7, Index); + write32le(Buf + 12, -Index * PltEntrySize - PltZeroEntrySize - 16); } bool X86TargetInfo::relocNeedsGot(uint32_t Type, const SymbolBody &S) const { @@ -109,7 +133,9 @@ PCRelReloc = R_X86_64_PC32; GotReloc = R_X86_64_GLOB_DAT; GotRefReloc = R_X86_64_PC32; + PltReloc = R_X86_64_JUMP_SLOT; RelativeReloc = R_X86_64_RELATIVE; + PltEntrySize = 16; // On freebsd x86_64 the first page cannot be mmaped. // On linux that is controled by vm.mmap_min_addr. At least on some x86_64 @@ -120,16 +146,35 @@ VAStart = 0x10000; } +void X86_64TargetInfo::writeGotPltEntry(uint8_t *Buf, uint64_t Plt) const { + // Skip 6 bytes of "jmpq *got(%rip)" + write32le(Buf, Plt + 6); +} + +void X86_64TargetInfo::writePltZeroEntry(uint8_t *Buf, uint64_t GotEntryAddr, + uint64_t PltEntryAddr) const { + const uint8_t PltData[] = { + 0xff, 0x35, 0x00, 0x00, 0x00, 0x00, // pushq GOT+8(%rip) + 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp *GOT+16(%rip) + 0x0f, 0x1f, 0x40, 0x00 // nopl 0x0(rax) + }; + memcpy(Buf, PltData, sizeof(PltData)); + write32le(Buf + 2, GotEntryAddr - PltEntryAddr + 2); // GOT+8 + write32le(Buf + 8, GotEntryAddr - PltEntryAddr + 4); // GOT+16 +} + void X86_64TargetInfo::writePltEntry(uint8_t *Buf, uint64_t GotEntryAddr, - uint64_t PltEntryAddr) const { - // jmpq *val(%rip); nop; nop - const uint8_t Inst[] = {0xff, 0x25, 0, 0, 0, 0, 0x90, 0x90}; + uint64_t PltEntryAddr, int32_t Index) const { + const uint8_t Inst[] = { + 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmpq *got(%rip) + 0x68, 0x00, 0x00, 0x00, 0x00, // pushq + 0xe9, 0x00, 0x00, 0x00, 0x00 // jmpq plt[0] + }; memcpy(Buf, Inst, sizeof(Inst)); - uint64_t NextPC = PltEntryAddr + 6; - int64_t Delta = GotEntryAddr - NextPC; - assert(isInt<32>(Delta)); - write32le(Buf + 2, Delta); + write32le(Buf + 2, GotEntryAddr - PltEntryAddr - 6); + write32le(Buf + 7, Index); + write32le(Buf + 12, -Index * PltEntrySize - PltZeroEntrySize - 16); } bool X86_64TargetInfo::relocNeedsGot(uint32_t Type, const SymbolBody &S) const { @@ -241,7 +286,9 @@ GotReloc = R_PPC64_GLOB_DAT; GotRefReloc = R_PPC64_REL64; RelativeReloc = R_PPC64_RELATIVE; + // PltReloc = FIXME PltEntrySize = 32; + PltZeroEntrySize = 0; //FIXME // We need 64K pages (at least under glibc/Linux, the loader won't // set different permissions on a finer granularity than that). @@ -267,8 +314,12 @@ return TocVA + 0x8000; } + +void PPC64TargetInfo::writeGotPltEntry(uint8_t *Buf, uint64_t Plt) const {} +void PPC64TargetInfo::writePltZeroEntry(uint8_t *Buf, uint64_t GotEntryAddr, + uint64_t PltEntryAddr) const {}; void PPC64TargetInfo::writePltEntry(uint8_t *Buf, uint64_t GotEntryAddr, - uint64_t PltEntryAddr) const { + uint64_t PltEntryAddr, int32_t Index) const { uint64_t Off = GotEntryAddr - getPPC64TocBase(); // FIXME: What we should do, in theory, is get the offset of the function @@ -457,11 +508,16 @@ PPCTargetInfo::PPCTargetInfo() { // PCRelReloc = FIXME // GotReloc = FIXME + // PltReloc = FIXME PageSize = 65536; VAStart = 0x10000000; } + +void PPCTargetInfo::writeGotPltEntry(uint8_t *Buf, uint64_t Plt) const {} +void PPCTargetInfo::writePltZeroEntry(uint8_t *Buf, uint64_t GotEntryAddr, + uint64_t PltEntryAddr) const {}; void PPCTargetInfo::writePltEntry(uint8_t *Buf, uint64_t GotEntryAddr, - uint64_t PltEntryAddr) const {} + uint64_t PltEntryAddr, int32_t Index) const {} bool PPCTargetInfo::relocNeedsGot(uint32_t Type, const SymbolBody &S) const { return false; } @@ -475,10 +531,16 @@ AArch64TargetInfo::AArch64TargetInfo() { // PCRelReloc = FIXME // GotReloc = FIXME + // PltReloc = FIXME VAStart = 0x400000; } + +void AArch64TargetInfo::writeGotPltEntry(uint8_t *Buf, uint64_t Plt) const {} +void AArch64TargetInfo::writePltZeroEntry(uint8_t *Buf, uint64_t GotEntryAddr, + uint64_t PltEntryAddr) const {}; void AArch64TargetInfo::writePltEntry(uint8_t *Buf, uint64_t GotEntryAddr, - uint64_t PltEntryAddr) const {} + uint64_t PltEntryAddr, + int32_t Index) const {} bool AArch64TargetInfo::relocNeedsGot(uint32_t Type, const SymbolBody &S) const { return false; @@ -553,12 +615,19 @@ MipsTargetInfo::MipsTargetInfo() { // PCRelReloc = FIXME // GotReloc = FIXME + // PltReloc = FIXME PageSize = 65536; VAStart = 0x400000; } +void MipsTargetInfo::writeGotPltEntry(uint8_t *Buf, uint64_t Plt) const {} + +void MipsTargetInfo::writePltZeroEntry(uint8_t *Buf, uint64_t GotEntryAddr, + uint64_t PltEntryAddr) const {} + void MipsTargetInfo::writePltEntry(uint8_t *Buf, uint64_t GotEntryAddr, - uint64_t PltEntryAddr) const {} + uint64_t PltEntryAddr, int32_t Index) const { +} bool MipsTargetInfo::relocNeedsGot(uint32_t Type, const SymbolBody &S) const { return false; Index: lld/trunk/ELF/Writer.cpp =================================================================== --- lld/trunk/ELF/Writer.cpp +++ lld/trunk/ELF/Writer.cpp @@ -98,6 +98,8 @@ Out::Bss = &Bss; GotSection Got; Out::Got = &Got; + GotPltSection GotPlt; + Out::GotPlt = &GotPlt; PltSection Plt; Out::Plt = &Plt; SymbolTableSection SymTab(*Symtab, *Out::StrTab); @@ -106,8 +108,11 @@ Out::DynSymTab = &DynSymTab; HashTableSection HashTab; Out::HashTab = &HashTab; - RelocationSection RelaDyn(Symtab->shouldUseRela()); + bool IsRela = Symtab->shouldUseRela(); + RelocationSection RelaDyn(IsRela ? ".rela.dyn" : ".rel.dyn", IsRela); Out::RelaDyn = &RelaDyn; + RelocationSection RelaPlt(IsRela ? ".rela.plt" : ".rel.plt", IsRela); + Out::RelaPlt = &RelaPlt; DynamicSection Dynamic(*Symtab); Out::Dynamic = &Dynamic; @@ -187,8 +192,8 @@ if (Body->isInPlt()) continue; Out::Plt->addEntry(Body); - } - if (Target->relocNeedsGot(Type, *Body)) { + Out::GotPlt->addEntry(Body); + } else if (Target->relocNeedsGot(Type, *Body)) { if (Body->isInGot()) continue; Out::Got->addEntry(Body); @@ -200,7 +205,10 @@ continue; if (CBP) Body->setUsedInDynamicReloc(); - Out::RelaDyn->addReloc({C, RI}); + if (Body && Target->relocNeedsPlt(Type, *Body)) + Out::RelaPlt->addReloc({ C, RI }); + else + Out::RelaDyn->addReloc({ C, RI }); } } @@ -447,9 +455,13 @@ OutputSections.push_back(Out::DynStrTab); if (Out::RelaDyn->hasRelocs()) OutputSections.push_back(Out::RelaDyn); + if (Out::RelaPlt->hasRelocs()) + OutputSections.push_back(Out::RelaPlt); } if (!Out::Got->empty()) OutputSections.push_back(Out::Got); + if (!Out::GotPlt->empty()) + OutputSections.push_back(Out::GotPlt); if (!Out::Plt->empty()) OutputSections.push_back(Out::Plt); Index: lld/trunk/test/elf2/plt-i686.s =================================================================== --- lld/trunk/test/elf2/plt-i686.s +++ lld/trunk/test/elf2/plt-i686.s @@ -14,42 +14,63 @@ // CHECK-NEXT: ] // CHECK-NEXT: Address: 0x11010 // CHECK-NEXT: Offset: -// CHECK-NEXT: Size: 16 +// CHECK-NEXT: Size: 48 // CHECK-NEXT: Link: 0 // CHECK-NEXT: Info: 0 // CHECK-NEXT: AddressAlignment: 16 +// CHECK: Name: .got.plt +// CHECK-NEXT: Type: SHT_PROGBITS +// CHECK-NEXT: Flags [ +// CHECK-NEXT: SHF_ALLOC +// CHECK-NEXT: SHF_WRITE +// CHECK-NEXT: ] +// CHECK-NEXT: Address: 0x12058 +// CHECK-NEXT: Offset: 0x2058 +// CHECK-NEXT: Size: 20 +// CHECK-NEXT: Link: 0 +// CHECK-NEXT: Info: 0 +// CHECK-NEXT: AddressAlignment: 4 +// CHECK-NEXT: EntrySize: 0 + // CHECK: Relocations [ -// CHECK-NEXT: Section ({{.*}}) .rel.dyn { -// CHECK-NEXT: 0x12050 R_386_GLOB_DAT bar 0x0 -// CHECK-NEXT: 0x12054 R_386_GLOB_DAT zed 0x0 +// CHECK-NEXT: Section ({{.*}}) .rel.plt { +// CHECK-NEXT: 0x12064 R_386_JUMP_SLOT bar 0x0 +// CHECK-NEXT: 0x12068 R_386_JUMP_SLOT zed 0x0 // CHECK-NEXT: } // CHECK-NEXT: ] // Unfortunately FileCheck can't do math, so we have to check for explicit // values: -// 0x11010 - (0x11000 + 1) - 4 = 11 -// 0x11010 - (0x11005 + 1) - 4 = 2 -// 0x11018 - (0x1100a + 1) - 4 = 9 +// 16 is the size of PLT[0] +// (0x11010 + 16) - (0x11000 + 1) - 4 = 27 +// (0x11010 + 16) - (0x11005 + 1) - 4 = 22 +// (0x11020 + 16) - (0x1100a + 1) - 4 = 33 // DISASM: _start: -// DISASM-NEXT: 11000: e9 0b 00 00 00 jmp 11 -// DISASM-NEXT: 11005: e9 06 00 00 00 jmp 6 -// DISASM-NEXT: 1100a: e9 09 00 00 00 jmp 9 - -// 0x12050 = 73808 -// 0x12054 = 73812 - +// DISASM-NEXT: 11000: e9 1b 00 00 00 jmp 27 +// DISASM-NEXT: 11005: e9 16 00 00 00 jmp 22 +// DISASM-NEXT: 1100a: e9 21 00 00 00 jmp 33 + +// 0x12064 - 0x11020 - 6 = 4158 +// 0x12068 - 0x11030 - 6 = 4146 +// 0x11010 - 0x1102b - 5 = -32 +// 0x11010 - 0x1103b - 5 = -48 // DISASM: Disassembly of section .plt: // DISASM-NEXT: .plt: -// DISASM-NEXT: 11010: ff 25 {{.*}} jmpl *73808 -// DISASM-NEXT: 11016: 90 nop -// DISASM-NEXT: 11017: 90 nop -// DISASM-NEXT: 11018: ff 25 {{.*}} jmpl *73812 -// DISASM-NEXT: 1101e: 90 nop -// DISASM-NEXT: 1101f: 90 nop - +// DISASM-NEXT: 11010: ff 35 4a 10 00 00 pushl 4170 +// DISASM-NEXT: 11016: ff 25 4c 10 00 00 jmpl *4172 +// DISASM-NEXT: 1101c: 00 00 addb %al, (%eax) +// DISASM-NEXT: 1101e: 00 00 addb %al, (%eax) +// DISASM-NEXT: 11020: ff 25 3e 10 00 00 jmpl *4158 +// DISASM-NEXT: 11026: 68 00 00 00 00 pushl $0 +// DISASM-NEXT: 1102b: e9 e0 ff ff ff jmp -32 +// DISASM-NEXT: 11030: ff 25 32 10 00 00 jmpl *4146 +// DISASM-NEXT: 11036: 68 01 00 00 00 pushl $1 +// DISASM-NEXT: 1103b: e9 d0 ff ff ff jmp -48 + + .global _start _start: jmp bar@PLT Index: lld/trunk/test/elf2/plt.s =================================================================== --- lld/trunk/test/elf2/plt.s +++ lld/trunk/test/elf2/plt.s @@ -14,42 +14,49 @@ // CHECK-NEXT: ] // CHECK-NEXT: Address: 0x1020 // CHECK-NEXT: Offset: -// CHECK-NEXT: Size: 24 +// CHECK-NEXT: Size: 64 // CHECK-NEXT: Link: 0 // CHECK-NEXT: Info: 0 // CHECK-NEXT: AddressAlignment: 16 // CHECK: Relocations [ -// CHECK-NEXT: Section ({{.*}}) .rela.dyn { -// CHECK-NEXT: 0x20A0 R_X86_64_GLOB_DAT bar 0x0 -// CHECK-NEXT: 0x20A8 R_X86_64_GLOB_DAT zed 0x0 -// CHECK-NEXT: 0x20B0 R_X86_64_GLOB_DAT _start 0x0 +// CHECK-NEXT: Section ({{.*}}) .rela.plt { +// CHECK-NEXT: 0x20C8 R_X86_64_JUMP_SLOT bar 0x0 +// CHECK-NEXT: 0x20D0 R_X86_64_JUMP_SLOT zed 0x0 +// CHECK-NEXT: 0x20D8 R_X86_64_JUMP_SLOT _start 0x0 // CHECK-NEXT: } // CHECK-NEXT: ] // Unfortunately FileCheck can't do math, so we have to check for explicit // values: -// 0x11020 - (0x11000 + 1) - 4 = 27 -// 0x11020 - (0x11005 + 1) - 4 = 22 -// 0x11028 - (0x1100a + 1) - 4 = 25 +// 0x1030 - (0x1000 + 5) = 43 +// 0x1030 - (0x1005 + 5) = 38 +// 0x1040 - (0x100a + 5) = 49 // DISASM: _start: -// DISASM-NEXT: 1000: e9 {{.*}} jmp 27 -// DISASM-NEXT: 1005: e9 {{.*}} jmp 22 -// DISASM-NEXT: 100a: e9 {{.*}} jmp 25 +// DISASM-NEXT: 1000: e9 {{.*}} jmp 43 +// DISASM-NEXT: 1005: e9 {{.*}} jmp 38 +// DISASM-NEXT: 100a: e9 {{.*}} jmp 49 -// 0x120A0 - 0x11026 = 4218 -// 0x120A8 - 0x1102e = 4218 +// 0x20C8 - 0x1036 = 4242 +// 0x20D0 - 0x1046 = 4234 // DISASM: Disassembly of section .plt: // DISASM-NEXT: .plt: -// DISASM-NEXT: 1020: ff 25 {{.*}} jmpq *4218(%rip) -// DISASM-NEXT: 1026: 90 nop -// DISASM-NEXT: 1027: 90 nop -// DISASM-NEXT: 1028: ff 25 {{.*}} jmpq *4218(%rip) -// DISASM-NEXT: 102e: 90 nop -// DISASM-NEXT: 102f: 90 nop +// DISASM-NEXT: 1020: ff 35 92 10 00 00 pushq 4242(%rip) +// DISASM-NEXT: 1026: ff 25 94 10 00 00 jmpq *4244(%rip) +// DISASM-NEXT: 102c: 0f 1f 40 00 nopl (%rax) +// DISASM-NEXT: 1030: ff 25 92 10 00 00 jmpq *4242(%rip) +// DISASM-NEXT: 1036: 68 00 00 00 00 pushq $0 +// DISASM-NEXT: 103b: e9 e0 ff ff ff jmp -32 +// DISASM-NEXT: 1040: ff 25 8a 10 00 00 jmpq *4234(%rip) +// DISASM-NEXT: 1046: 68 01 00 00 00 pushq $1 +// DISASM-NEXT: 104b: e9 d0 ff ff ff jmp -48 +// DISASM-NEXT: 1050: ff 25 82 10 00 00 jmpq *4226(%rip) +// DISASM-NEXT: 1056: 68 02 00 00 00 pushq $2 +// DISASM-NEXT: 105b: e9 c0 ff ff ff jmp -64 + .global _start _start: Index: lld/trunk/test/elf2/relocation-i686.s =================================================================== --- lld/trunk/test/elf2/relocation-i686.s +++ lld/trunk/test/elf2/relocation-i686.s @@ -47,7 +47,7 @@ // ADDR-NEXT: ] // ADDR-NEXT: Address: 0x11030 // ADDR-NEXT: Offset: 0x1030 -// ADDR-NEXT: Size: 8 +// ADDR-NEXT: Size: 32 // ADDR: Name: .got // ADDR-NEXT: Type: SHT_PROGBITS @@ -55,24 +55,25 @@ // ADDR-NEXT: SHF_ALLOC // ADDR-NEXT: SHF_WRITE // ADDR-NEXT: ] -// ADDR-NEXT: Address: 0x12050 +// ADDR-NEXT: Address: 0x12070 .section .R_386_GOTPC,"ax",@progbits R_386_GOTPC: movl $_GLOBAL_OFFSET_TABLE_, %eax -// 0x12050 - 0x11014 = 4156 +// 0x12070 - 0x11014 = 4188 // CHECK: Disassembly of section .R_386_GOTPC: // CHECK-NEXT: R_386_GOTPC: -// CHECK-NEXT: 11014: {{.*}} movl $4156, %eax +// CHECK-NEXT: 11014: {{.*}} movl $4188, %eax .section .dynamic_reloc, "ax",@progbits call bar -// 0x11030 - (0x11019 + 5) = 18 +// (0x11030 + 16) - (0x11019 + 5) = 34 +// 16 - is a size of PLT[0] // CHECK: Disassembly of section .dynamic_reloc: // CHECK-NEXT: .dynamic_reloc: -// CHECK-NEXT: 11019: e8 12 00 00 00 calll 18 +// CHECK-NEXT: 11019: e8 22 00 00 00 calll 34 .section .R_386_GOT32,"ax",@progbits .global R_386_GOT32 Index: lld/trunk/test/elf2/relocation.s =================================================================== --- lld/trunk/test/elf2/relocation.s +++ lld/trunk/test/elf2/relocation.s @@ -14,23 +14,39 @@ // SEC-NEXT: ] // SEC-NEXT: Address: 0x11020 // SEC-NEXT: Offset: 0x1020 -// SEC-NEXT: Size: 8 +// SEC-NEXT: Size: 32 -// SEC: Name: .got +// SEC: Name: .got // SEC-NEXT: Type: SHT_PROGBITS // SEC-NEXT: Flags [ // SEC-NEXT: SHF_ALLOC // SEC-NEXT: SHF_WRITE // SEC-NEXT: ] -// SEC-NEXT: Address: 0x120A0 +// SEC-NEXT: Address: 0x120E0 // SEC-NEXT: Offset: -// SEC-NEXT: Size: 16 +// SEC-NEXT: Size: 8 // SEC-NEXT: Link: 0 // SEC-NEXT: Info: 0 // SEC-NEXT: AddressAlignment: 8 // SEC-NEXT: EntrySize: 0 // SEC-NEXT: } +// SEC: Name: .got.plt +// SEC-NEXT: Type: SHT_PROGBITS +// SEC-NEXT: Flags [ +// SEC-NEXT: SHF_ALLOC +// SEC-NEXT: SHF_WRITE +// SEC-NEXT: ] +// SEC-NEXT: Address: 0x120E8 +// SEC-NEXT: Offset: 0x20E8 +// SEC-NEXT: Size: 32 +// SEC-NEXT: Link: 0 +// SEC-NEXT: Info: 0 +// SEC-NEXT: AddressAlignment: 8 +// SEC-NEXT: EntrySize: 0 +// SEC-NEXT: } + + .section .text,"ax",@progbits,unique,1 .global _start _start: @@ -75,10 +91,11 @@ .global R_X86_64_PC32 R_X86_64_PC32: call bar -// 0x11020 - (0x11017 + 5) = 4 +// (0x11020 + 16) - (0x11017 + 5) = 20 +// 16 - is a size of PLT[0] // CHECK: Disassembly of section .R_X86_64_PC32: // CHECK-NEXT: R_X86_64_PC32: -// CHECK-NEXT: 11017: e8 04 00 00 00 callq 4 +// CHECK-NEXT: 11017: e8 14 00 00 00 callq 20 .section .R_X86_64_64,"a",@progbits .global R_X86_64_64 @@ -93,7 +110,7 @@ R_X86_64_GOTPCREL: .long zed@gotpcrel -// 0x120A8 - 0x10160 = 8008 -// 8008 = 0x481f0000 in little endian +// 0x120E0 - 0x10160 = 8064 +// 8064 = 0x801f0000 in little endian // CHECK: Contents of section .R_X86_64_GOTPCREL -// CHECK-NEXT: 10160 481f0000 +// CHECK-NEXT: 10160 801f0000