Index: lld/trunk/ELF/SyntheticSections.h =================================================================== --- lld/trunk/ELF/SyntheticSections.h +++ lld/trunk/ELF/SyntheticSections.h @@ -32,6 +32,7 @@ virtual void writeTo(uint8_t *Buf) = 0; virtual size_t getSize() const = 0; virtual void finalize() {} + virtual bool empty() const { return false; } uintX_t getVA() const { return this->OutSec ? this->OutSec->Addr + this->OutSecOff : 0; @@ -50,10 +51,11 @@ void writeTo(uint8_t *Buf) override; size_t getSize() const override { return Size; } void finalize() override; + bool empty() const override; + void addEntry(SymbolBody &Sym); bool addDynTlsEntry(SymbolBody &Sym); bool addTlsIndex(); - bool empty() const { return Entries.empty(); } uintX_t getGlobalDynAddr(const SymbolBody &B) const; uintX_t getGlobalDynOffset(const SymbolBody &B) const; @@ -98,6 +100,7 @@ void writeTo(uint8_t *Buf) override; size_t getSize() const override { return Size; } void finalize() override; + bool empty() const override; void addEntry(SymbolBody &Sym, uintX_t Addend, RelExpr Expr); bool addDynTlsEntry(SymbolBody &Sym); bool addTlsIndex(); @@ -194,9 +197,9 @@ public: GotPltSection(); void addEntry(SymbolBody &Sym); - bool empty() const; size_t getSize() const override; void writeTo(uint8_t *Buf) override; + bool empty() const override { return Entries.empty(); } private: std::vector Entries; @@ -315,8 +318,8 @@ unsigned getRelocOffset(); void finalize() override; void writeTo(uint8_t *Buf) override; + bool empty() const override { return Relocs.empty(); } size_t getSize() const override { return Relocs.size() * this->Entsize; } - bool hasRelocs() const { return !Relocs.empty(); } size_t getRelativeRelocCount() const { return NumRelativeRelocs; } private: @@ -421,7 +424,7 @@ void writeTo(uint8_t *Buf) override; size_t getSize() const override; void addEntry(SymbolBody &Sym); - bool empty() const { return Entries.empty(); } + bool empty() const override { return Entries.empty(); } private: std::vector> Entries; @@ -471,6 +474,7 @@ void writeTo(uint8_t *Buf) override; size_t getSize() const override; void addFde(uint32_t Pc, uint32_t FdeVA); + bool empty() const override; private: struct FdeData { @@ -521,6 +525,7 @@ void finalize() override; size_t getSize() const override; void writeTo(uint8_t *Buf) override; + bool empty() const override; }; // The .gnu.version_r section defines the version identifiers used by @@ -547,6 +552,7 @@ void writeTo(uint8_t *Buf) override; size_t getSize() const override; size_t getNeedNum() const { return Needed.size(); } + bool empty() const override; }; // .MIPS.abiflags section. Index: lld/trunk/ELF/SyntheticSections.cpp =================================================================== --- lld/trunk/ELF/SyntheticSections.cpp +++ lld/trunk/ELF/SyntheticSections.cpp @@ -426,6 +426,12 @@ Size = Entries.size() * sizeof(uintX_t); } +template bool GotSection::empty() const { + // If we have a relocation that is relative to GOT (such as GOTOFFREL), + // we need to emit a GOT even if it's empty. + return Entries.empty() && !HasGotOffRel; +} + template void GotSection::writeTo(uint8_t *Buf) { for (const SymbolBody *B : Entries) { uint8_t *Entry = Buf; @@ -614,6 +620,12 @@ Size = EntriesNum * sizeof(uintX_t); } +template bool MipsGotSection::empty() const { + // We add the .got section to the result for dynamic MIPS target because + // its address and properties are mentioned in the .dynamic section. + return Config->Relocatable; +} + template unsigned MipsGotSection::getGp() const { return ElfSym::MipsGp->template getVA(0); } @@ -691,10 +703,6 @@ Entries.push_back(&Sym); } -template bool GotPltSection::empty() const { - return Entries.empty(); -} - template size_t GotPltSection::getSize() const { return (Target->GotPltHeaderEntriesNum + Entries.size()) * Target->GotPltEntrySize; @@ -808,7 +816,7 @@ this->Link = In::DynStrTab->OutSec->SectionIndex; - if (In::RelaDyn->hasRelocs()) { + if (!In::RelaDyn->empty()) { bool IsRela = Config->Rela; add({IsRela ? DT_RELA : DT_REL, In::RelaDyn}); add({IsRela ? DT_RELASZ : DT_RELSZ, In::RelaDyn->getSize()}); @@ -824,7 +832,7 @@ add({IsRela ? DT_RELACOUNT : DT_RELCOUNT, NumRelativeRels}); } } - if (In::RelaPlt->hasRelocs()) { + if (!In::RelaPlt->empty()) { add({DT_JMPREL, In::RelaPlt}); add({DT_PLTRELSZ, In::RelaPlt->getSize()}); add({Config->EMachine == EM_MIPS ? DT_MIPS_PLTGOT : DT_PLTGOT, @@ -1490,6 +1498,10 @@ Fdes.push_back({Pc, FdeVA}); } +template bool EhFrameHeader::empty() const { + return Out::EhFrame->empty(); +} + template VersionDefinitionSection::VersionDefinitionSection() : SyntheticSection(SHF_ALLOC, SHT_GNU_verdef, sizeof(uint32_t), @@ -1573,6 +1585,10 @@ } } +template bool VersionTableSection::empty() const { + return !In::VerDef && In::VerNeed->empty(); +} + template VersionNeedSection::VersionNeedSection() : SyntheticSection(SHF_ALLOC, SHT_GNU_verneed, sizeof(uint32_t), @@ -1654,6 +1670,10 @@ return Size; } +template bool VersionNeedSection::empty() const { + return getNeedNum() == 0; +} + template MipsRldMapSection::MipsRldMapSection() : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS, Index: lld/trunk/ELF/Writer.cpp =================================================================== --- lld/trunk/ELF/Writer.cpp +++ lld/trunk/ELF/Writer.cpp @@ -58,7 +58,6 @@ void sortSections(); void finalizeSections(); void addPredefinedSections(); - bool needsGot(); std::vector createPhdrs(); void assignAddresses(); @@ -242,8 +241,6 @@ In::RelaDyn = make>( Config->Rela ? ".rela.dyn" : ".rel.dyn", Config->ZCombreloc); In::ShStrTab = make>(".shstrtab", false); - In::VerSym = make>(); - In::VerNeed = make>(); Out::ElfHeader = make("", 0, SHF_ALLOC); Out::ElfHeader->Size = sizeof(Elf_Ehdr); @@ -257,17 +254,9 @@ In::Interp = nullptr; } - if (!Symtab::X->getSharedFiles().empty() || Config->Pic) { - In::DynSymTab = make>(*In::DynStrTab); - } - if (Config->EhFrameHdr) In::EhFrameHdr = make>(); - if (Config->GnuHash) - In::GnuHashTab = make>(); - if (Config->SysvHash) - In::HashTab = make>(); if (Config->GdbIndex) In::GdbIndex = make>(); @@ -278,9 +267,6 @@ In::SymTab = make>(*In::StrTab); } - if (!Config->VersionDefinitions.empty()) - In::VerDef = make>(); - // Initialize linker generated sections if (!Config->Relocatable) Symtab::X->Sections.push_back(createCommentSection()); @@ -297,8 +283,9 @@ } // Add MIPS-specific sections. + bool HasDynSymTab = !Symtab::X->getSharedFiles().empty() || Config->Pic; if (Config->EMachine == EM_MIPS) { - if (!Config->Shared && In::DynSymTab) { + if (!Config->Shared && HasDynSymTab) { In::MipsRldMap = make>(); Symtab::X->Sections.push_back(In::MipsRldMap); } @@ -310,14 +297,48 @@ Symtab::X->Sections.push_back(Sec); } + if (HasDynSymTab) { + In::DynSymTab = make>(*In::DynStrTab); + Symtab::X->Sections.push_back(In::DynSymTab); + + In::VerSym = make>(); + Symtab::X->Sections.push_back(In::VerSym); + + if (!Config->VersionDefinitions.empty()) { + In::VerDef = make>(); + Symtab::X->Sections.push_back(In::VerDef); + } + + In::VerNeed = make>(); + Symtab::X->Sections.push_back(In::VerNeed); + + if (Config->GnuHash) { + In::GnuHashTab = make>(); + Symtab::X->Sections.push_back(In::GnuHashTab); + } + + if (Config->SysvHash) { + In::HashTab = make>(); + Symtab::X->Sections.push_back(In::HashTab); + } + + Symtab::X->Sections.push_back(In::Dynamic); + Symtab::X->Sections.push_back(In::DynStrTab); + Symtab::X->Sections.push_back(In::RelaDyn); + } + // Add .got. MIPS' .got is so different from the other archs, // it has its own class. - if (Config->EMachine == EM_MIPS) + if (Config->EMachine == EM_MIPS) { In::MipsGot = make>(); - else + Symtab::X->Sections.push_back(In::MipsGot); + } else { In::Got = make>(); + Symtab::X->Sections.push_back(In::Got); + } In::GotPlt = make>(); + Symtab::X->Sections.push_back(In::GotPlt); } template @@ -870,6 +891,30 @@ } } +// We need to add input synthetic sections early in createSyntheticSections() +// to make them visible from linkescript side. But not all sections are always +// required to be in output. For example we don't need dynamic section content +// sometimes. This function filters out such unused sections from output. +template +static void removeUnusedSyntheticSections(std::vector &V) { + // Input synthetic sections are placed after all regular ones. We iterate over + // them all and exit at first non-synthetic. + for (InputSectionBase *S : llvm::reverse(Symtab::X->Sections)) { + SyntheticSection *SS = dyn_cast>(S); + if (!SS) + return; + if (!SS->empty() || !SS->OutSec) + continue; + + OutputSection *OutSec = cast>(SS->OutSec); + OutSec->Sections.erase( + std::find(OutSec->Sections.begin(), OutSec->Sections.end(), SS)); + // If there is no other sections in output section, remove it from output. + if (OutSec->Sections.empty()) + V.erase(std::find(V.begin(), V.end(), OutSec)); + } +} + // Create output section objects and add them to OutputSections. template void Writer::finalizeSections() { Out::DebugInfo = findSection(".debug_info"); @@ -930,6 +975,7 @@ // So far we have added sections from input object files. // This function adds linker-created Out::* sections. addPredefinedSections(); + removeUnusedSyntheticSections(OutputSections); sortSections(); @@ -956,20 +1002,6 @@ In::VerNeed, In::Dynamic}); } -template bool Writer::needsGot() { - // We add the .got section to the result for dynamic MIPS target because - // its address and properties are mentioned in the .dynamic section. - if (Config->EMachine == EM_MIPS) - return !Config->Relocatable; - - if (!In::Got->empty()) - return true; - - // If we have a relocation that is relative to GOT (such as GOTOFFREL), - // we need to emit a GOT even if it's empty. - return In::Got->HasGotOffRel; -} - // This function add Out::* sections to OutputSections. template void Writer::addPredefinedSections() { auto Add = [&](OutputSectionBase *OS) { @@ -984,41 +1016,12 @@ addInputSec(In::SymTab); addInputSec(In::ShStrTab); addInputSec(In::StrTab); - if (In::DynSymTab) { - addInputSec(In::DynSymTab); - - bool HasVerNeed = In::VerNeed->getNeedNum() != 0; - if (In::VerDef || HasVerNeed) - addInputSec(In::VerSym); - addInputSec(In::VerDef); - if (HasVerNeed) - addInputSec(In::VerNeed); - - addInputSec(In::GnuHashTab); - addInputSec(In::HashTab); - addInputSec(In::Dynamic); - addInputSec(In::DynStrTab); - if (In::RelaDyn->hasRelocs()) - addInputSec(In::RelaDyn); - } // We always need to add rel[a].plt to output if it has entries. // Even during static linking it can contain R_[*]_IRELATIVE relocations. - if (In::RelaPlt->hasRelocs()) + if (!In::RelaPlt->empty()) addInputSec(In::RelaPlt); - // We fill .got and .got.plt sections in scanRelocs(). This is the - // reason we don't add it earlier in createSections(). - if (needsGot()) { - if (Config->EMachine == EM_MIPS) - addInputSec(In::MipsGot); - else - addInputSec(In::Got); - } - - if (!In::GotPlt->empty()) - addInputSec(In::GotPlt); - if (!In::Plt->empty()) addInputSec(In::Plt); if (!Out::EhFrame->empty()) Index: lld/trunk/test/ELF/eh-align-cie.s =================================================================== --- lld/trunk/test/ELF/eh-align-cie.s +++ lld/trunk/test/ELF/eh-align-cie.s @@ -51,7 +51,7 @@ // CHECK-NEXT: EntrySize: // CHECK-NEXT: SectionData ( // CHECK-NEXT: 0000: 1C000000 00000000 017A5052 00017810 -// CHECK-NEXT: 0010: 061B260E 00001B0C 07089001 00000000 -// CHECK-NEXT: 0020: 14000000 24000000 100E0000 00000000 +// CHECK-NEXT: 0010: 061BF60D 00001B0C 07089001 00000000 +// CHECK-NEXT: 0020: 14000000 24000000 E00D0000 00000000 // CHECK-NEXT: 0030: 00000000 00000000 // CHECK-NEXT: ) Index: lld/trunk/test/ELF/eh-frame-hdr-augmentation.s =================================================================== --- lld/trunk/test/ELF/eh-frame-hdr-augmentation.s +++ lld/trunk/test/ELF/eh-frame-hdr-augmentation.s @@ -18,7 +18,7 @@ // CHECK-NEXT: DW_CFA_nop: // CHECK-NEXT: DW_CFA_nop: -// CHECK: 00000020 00000014 00000024 FDE cie=00000024 pc=00000dd8...00000dd8 +// CHECK: 00000020 00000014 00000024 FDE cie=00000024 pc=00000da8...00000da8 // CHECK-NEXT: DW_CFA_nop: // CHECK-NEXT: DW_CFA_nop: // CHECK-NEXT: DW_CFA_nop: Index: lld/trunk/test/ELF/eh-frame-marker.s =================================================================== --- lld/trunk/test/ELF/eh-frame-marker.s +++ lld/trunk/test/ELF/eh-frame-marker.s @@ -8,10 +8,10 @@ // CHECK-NEXT: Flags [ // CHECK-NEXT: SHF_ALLOC // CHECK-NEXT: ] -// CHECK-NEXT: Address: 0x200 +// CHECK-NEXT: Address: 0x229 // CHECK: Name: foo -// CHECK-NEXT: Value: 0x200 +// CHECK-NEXT: Value: 0x229 .section .eh_frame foo: Index: lld/trunk/test/ELF/eh-frame-merge.s =================================================================== --- lld/trunk/test/ELF/eh-frame-merge.s +++ lld/trunk/test/ELF/eh-frame-merge.s @@ -35,10 +35,10 @@ // CHECK-NEXT: SectionData ( // CHECK-NEXT: 0000: 14000000 00000000 017A5200 01781001 | // CHECK-NEXT: 0010: 1B0C0708 90010000 14000000 1C000000 | -// CHECK-NEXT: 0020: 180E0000 01000000 00000000 00000000 | -// CHECK-NEXT: 0030: 14000000 34000000 020E0000 02000000 | +// CHECK-NEXT: 0020: E80D0000 01000000 00000000 00000000 | +// CHECK-NEXT: 0030: 14000000 34000000 D20D0000 02000000 | // CHECK-NEXT: 0040: 00000000 00000000 14000000 4C000000 | -// CHECK-NEXT: 0050: E90D0000 01000000 00000000 00000000 | +// CHECK-NEXT: 0050: B90D0000 01000000 00000000 00000000 | // CHECK-NEXT: ) // CHECK: Name: foo Index: lld/trunk/test/ELF/linkerscript/phdrs.s =================================================================== --- lld/trunk/test/ELF/linkerscript/phdrs.s +++ lld/trunk/test/ELF/linkerscript/phdrs.s @@ -102,7 +102,7 @@ # INT-PHDRS-NEXT: PF_W # INT-PHDRS-NEXT: PF_X # INT-PHDRS-NEXT: ] -# INT-PHDRS-NEXT: Alignment: 4 +# INT-PHDRS-NEXT: Alignment: # INT-PHDRS-NEXT: } # INT-PHDRS-NEXT: ] Index: lld/trunk/test/ELF/synthetic-got.s =================================================================== --- lld/trunk/test/ELF/synthetic-got.s +++ lld/trunk/test/ELF/synthetic-got.s @@ -0,0 +1,32 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o +# RUN: echo "SECTIONS { }" > %t0.script +# RUN: ld.lld -shared %t.o -o %t0.out --script %t0.script +# RUN: llvm-objdump -section-headers %t0.out | FileCheck %s --check-prefix=GOT +# RUN: llvm-objdump -s -section=.got -section=.got.plt %t0.out \ +# RUN: | FileCheck %s --check-prefix=GOTDATA + +# GOT: Sections: +# GOT: 9 .got 00000008 00000000000001b0 DATA +# GOT-NEXT: 10 .got.plt 00000020 00000000000001b8 DATA +# GOTDATA: Contents of section .got: +# GOTDATA-NEXT: 01b0 00000000 00000000 +# GOTDATA-NEXT: Contents of section .got.plt: +# GOTDATA-NEXT: 01b8 e0000000 00000000 00000000 00000000 +# GOTDATA-NEXT: 01c8 00000000 00000000 d6000000 00000000 + +# RUN: echo "SECTIONS { .mygot : { *(.got) *(.got.plt) } }" > %t1.script +# RUN: ld.lld -shared %t.o -o %t1.out --script %t1.script +# RUN: llvm-objdump -section-headers %t1.out | FileCheck %s --check-prefix=MYGOT +# RUN: llvm-objdump -s -section=.mygot %t1.out | FileCheck %s --check-prefix=MYGOTDATA + +# MYGOT: Sections: +# MYGOT: 9 .mygot 00000028 00000000000001b0 DATA +# MYGOT-NOT: .got +# MYGOT-NOT: .got.plt +# MYGOTDATA: 01b0 00000000 00000000 e0000000 00000000 +# MYGOTDATA-NEXT: 01c0 00000000 00000000 00000000 00000000 +# MYGOTDATA-NEXT: 01d0 d6000000 00000000 + +mov bar@gotpcrel(%rip), %rax +call foo@plt