Index: ELF/SyntheticSections.h =================================================================== --- ELF/SyntheticSections.h +++ 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 isPresent() const { return true; } uintX_t getVA() const { return this->OutSec ? this->OutSec->Addr + this->OutSecOff : 0; @@ -50,6 +51,8 @@ void writeTo(uint8_t *Buf) override; size_t getSize() const override { return Size; } void finalize() override; + bool isPresent() const override; + void addEntry(SymbolBody &Sym); bool addDynTlsEntry(SymbolBody &Sym); bool addTlsIndex(); @@ -98,6 +101,7 @@ void writeTo(uint8_t *Buf) override; size_t getSize() const override { return Size; } void finalize() override; + bool isPresent() const override; void addEntry(SymbolBody &Sym, uintX_t Addend, RelExpr Expr); bool addDynTlsEntry(SymbolBody &Sym); bool addTlsIndex(); @@ -193,9 +197,9 @@ public: GotPltSection(); void addEntry(SymbolBody &Sym); - bool empty() const; size_t getSize() const override; void writeTo(uint8_t *Buf) override; + bool isPresent() const override { return !Entries.empty(); } private: std::vector Entries; @@ -314,8 +318,8 @@ unsigned getRelocOffset(); void finalize() override; void writeTo(uint8_t *Buf) override; + bool isPresent() 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: @@ -470,6 +474,7 @@ void writeTo(uint8_t *Buf) override; size_t getSize() const override; void addFde(uint32_t Pc, uint32_t FdeVA); + bool isPresent() const override { return !Out::EhFrame->empty(); } private: struct FdeData { @@ -520,6 +525,7 @@ void finalize() override; size_t getSize() const override; void writeTo(uint8_t *Buf) override; + bool isPresent() const override; }; // The .gnu.version_r section defines the version identifiers used by @@ -546,6 +552,7 @@ void writeTo(uint8_t *Buf) override; size_t getSize() const override; size_t getNeedNum() const { return Needed.size(); } + bool isPresent() const override; }; // .MIPS.abiflags section. Index: ELF/SyntheticSections.cpp =================================================================== --- ELF/SyntheticSections.cpp +++ ELF/SyntheticSections.cpp @@ -432,6 +432,12 @@ Size = Entries.size() * sizeof(uintX_t); } +template bool GotSection::isPresent() 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 Config->EMachine != EM_MIPS && (!empty() || HasGotOffRel); +} + template void GotSection::writeTo(uint8_t *Buf) { for (const SymbolBody *B : Entries) { uint8_t *Entry = Buf; @@ -620,6 +626,12 @@ Size = EntriesNum * sizeof(uintX_t); } +template bool MipsGotSection::isPresent() 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->EMachine == EM_MIPS && !Config->Relocatable; +} + template static void writeUint(uint8_t *Buf, typename ELFT::uint Val) { typedef typename ELFT::uint uintX_t; @@ -693,10 +705,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; @@ -810,7 +818,7 @@ this->Link = In::DynStrTab->OutSec->SectionIndex; - if (In::RelaDyn->hasRelocs()) { + if (In::RelaDyn->isPresent()) { bool IsRela = Config->Rela; add({IsRela ? DT_RELA : DT_REL, In::RelaDyn}); add({IsRela ? DT_RELASZ : DT_RELSZ, In::RelaDyn->getSize()}); @@ -826,7 +834,7 @@ add({IsRela ? DT_RELACOUNT : DT_RELCOUNT, NumRelativeRels}); } } - if (In::RelaPlt->hasRelocs()) { + if (In::RelaPlt->isPresent()) { add({DT_JMPREL, In::RelaPlt}); add({DT_PLTRELSZ, In::RelaPlt->getSize()}); add({Config->EMachine == EM_MIPS ? DT_MIPS_PLTGOT : DT_PLTGOT, @@ -1575,6 +1583,11 @@ } } +template bool VersionTableSection::isPresent() const { + bool HasVerNeed = In::VerNeed->getNeedNum() != 0; + return In::VerDef || HasVerNeed; +} + template VersionNeedSection::VersionNeedSection() : SyntheticSection(SHF_ALLOC, SHT_GNU_verneed, sizeof(uint32_t), @@ -1656,6 +1669,10 @@ return Size; } +template bool VersionNeedSection::isPresent() const { + return getNeedNum() != 0; +} + template MipsRldMapSection::MipsRldMapSection() : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS, Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -58,7 +58,6 @@ void sortSections(); void finalizeSections(); void addPredefinedSections(); - bool needsGot(); std::vector createPhdrs(); void assignAddresses(); @@ -225,6 +224,11 @@ exitLld(0); } +template static void doAdd(Sec *&Dest, Sec *Targ) { + Dest = Targ; + Symtab::X->Sections.push_back(Targ); +}; + // Initialize Out members. template void Writer::createSyntheticSections() { // Initialize all pointers with NULL. This is needed because @@ -241,32 +245,20 @@ 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); Out::ProgramHeaders = make("", 0, SHF_ALLOC); Out::ProgramHeaders->updateAlignment(sizeof(uintX_t)); - if (needsInterpSection()) { - In::Interp = createInterpSection(); - Symtab::X->Sections.push_back(In::Interp); - } else { + if (needsInterpSection()) + doAdd(In::Interp, createInterpSection()); + else 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>(); @@ -277,30 +269,22 @@ 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()); - if (Config->BuildId != BuildIdKind::None) { - In::BuildId = make>(); - Symtab::X->Sections.push_back(In::BuildId); - } + if (Config->BuildId != BuildIdKind::None) + doAdd(In::BuildId, make>()); InputSection *Common = createCommonSection(); - if (!Common->Data.empty()) { - In::Common = Common; - Symtab::X->Sections.push_back(Common); - } + if (!Common->Data.empty()) + doAdd(In::Common, Common); // Add MIPS-specific sections. + bool HasDynSymTab = !Symtab::X->getSharedFiles().empty() || Config->Pic; if (Config->EMachine == EM_MIPS) { - if (!Config->Shared && In::DynSymTab) { - In::MipsRldMap = make>(); - Symtab::X->Sections.push_back(In::MipsRldMap); - } + if (!Config->Shared && HasDynSymTab) + doAdd(In::MipsRldMap, make>()); if (auto *Sec = MipsAbiFlagsSection::create()) Symtab::X->Sections.push_back(Sec); if (auto *Sec = MipsOptionsSection::create()) @@ -309,14 +293,32 @@ Symtab::X->Sections.push_back(Sec); } + if (HasDynSymTab) { + doAdd(In::DynSymTab, make>(*In::DynStrTab)); + + doAdd(In::VerSym, make>()); + if (!Config->VersionDefinitions.empty()) + doAdd(In::VerDef, make>()); + doAdd(In::VerNeed, make>()); + + if (Config->GnuHash) + doAdd(In::GnuHashTab, make>()); + if (Config->SysvHash) + doAdd(In::HashTab, make>()); + + 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) - In::MipsGot = make>(); + doAdd(In::MipsGot, make>()); else - In::Got = make>(); + doAdd(In::Got, make>()); - In::GotPlt = make>(); + doAdd(In::GotPlt, make>()); } template @@ -718,7 +720,7 @@ void Writer::forEachRelSec( std::function &)> Fn) { for (InputSectionBase *IS : Symtab::X->Sections) { - if (!IS->Live) + if (!IS || !IS->Live) continue; // Scan all relocations. Each relocation goes through a series // of tests to determine if it needs special treatment, such as @@ -867,6 +869,32 @@ } } +// We need to add 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 removeUnusedSynthetics(std::vector &V) { + // Synthetic sections are placed after all regular ones. We iterate over them + // all and exit at first non-synthetic. + for (auto I = Symtab::X->Sections.rbegin(); + I != Symtab::X->Sections.rend(); ++I) { + SyntheticSection *SS = dyn_cast>(*I); + if (!SS) + return; + if (SS->isPresent() || !SS->OutSec) + continue; + + OutputSection *OutSec = cast>(SS->OutSec); + OutSec->Sections.erase( + std::find(OutSec->Sections.begin(), OutSec->Sections.end(), SS), + OutSec->Sections.end()); + // 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"); @@ -927,6 +955,7 @@ // So far we have added sections from input object files. // This function adds linker-created Out::* sections. addPredefinedSections(); + removeUnusedSynthetics(OutputSections); sortSections(); @@ -953,20 +982,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) { @@ -981,41 +996,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->isPresent()) 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: test/ELF/eh-align-cie.s =================================================================== --- test/ELF/eh-align-cie.s +++ 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: test/ELF/eh-frame-hdr-augmentation.s =================================================================== --- test/ELF/eh-frame-hdr-augmentation.s +++ 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: test/ELF/eh-frame-marker.s =================================================================== --- test/ELF/eh-frame-marker.s +++ 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: test/ELF/eh-frame-merge.s =================================================================== --- test/ELF/eh-frame-merge.s +++ 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: test/ELF/linkerscript/phdrs.s =================================================================== --- test/ELF/linkerscript/phdrs.s +++ 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: test/ELF/synthetic-got.s =================================================================== --- test/ELF/synthetic-got.s +++ 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