Index: lld/trunk/ELF/SyntheticSections.h =================================================================== --- lld/trunk/ELF/SyntheticSections.h +++ lld/trunk/ELF/SyntheticSections.h @@ -588,6 +588,16 @@ void writeTo(uint8_t *Buf) override; }; +class SymtabShndxSection final : public SyntheticSection { +public: + SymtabShndxSection(); + + void writeTo(uint8_t *Buf) override; + size_t getSize() const override; + bool empty() const override; + void finalizeContents() override; +}; + // Outputs GNU Hash section. For detailed explanation see: // https://blogs.oracle.com/ali/entry/gnu_hash_elf_sections class GnuHashTableSection final : public SyntheticSection { @@ -992,6 +1002,7 @@ static StringTableSection *ShStrTab; static StringTableSection *StrTab; static SymbolTableBaseSection *SymTab; + static SymtabShndxSection* SymTabShndx; }; template struct In { Index: lld/trunk/ELF/SyntheticSections.cpp =================================================================== --- lld/trunk/ELF/SyntheticSections.cpp +++ lld/trunk/ELF/SyntheticSections.cpp @@ -1935,6 +1935,23 @@ this->Entsize = sizeof(Elf_Sym); } +static BssSection *getCommonSec(Symbol *Sym) { + if (!Config->DefineCommon) + if (auto *D = dyn_cast(Sym)) + return dyn_cast_or_null(D->Section); + return nullptr; +} + +static uint32_t getSymSectionIndex(Symbol *Sym) { + if (getCommonSec(Sym)) + return SHN_COMMON; + if (!isa(Sym) || Sym->NeedsPltAddr) + return SHN_UNDEF; + if (const OutputSection *OS = Sym->getOutputSection()) + return OS->SectionIndex >= SHN_LORESERVE ? SHN_XINDEX : OS->SectionIndex; + return SHN_ABS; +} + // Write the internal symbol table contents to the output symbol table. template void SymbolTableSection::writeTo(uint8_t *Buf) { // The first entry is a null entry as per the ELF spec. @@ -1956,22 +1973,7 @@ } ESym->st_name = Ent.StrTabOffset; - - // Set a section index. - BssSection *CommonSec = nullptr; - if (!Config->DefineCommon) - if (auto *D = dyn_cast(Sym)) - CommonSec = dyn_cast_or_null(D->Section); - if (CommonSec) - ESym->st_shndx = SHN_COMMON; - else if (Sym->NeedsPltAddr) - ESym->st_shndx = SHN_UNDEF; - else if (const OutputSection *OutSec = Sym->getOutputSection()) - ESym->st_shndx = OutSec->SectionIndex; - else if (isa(Sym)) - ESym->st_shndx = SHN_ABS; - else - ESym->st_shndx = SHN_UNDEF; + ESym->st_shndx = getSymSectionIndex(Ent.Sym); // Copy symbol size if it is a defined symbol. st_size is not significant // for undefined symbols, so whether copying it or not is up to us if that's @@ -1986,7 +1988,7 @@ // st_value is usually an address of a symbol, but that has a // special meaining for uninstantiated common symbols (this can // occur if -r is given). - if (CommonSec) + if (BssSection *CommonSec = getCommonSec(Ent.Sym)) ESym->st_value = CommonSec->Alignment; else ESym->st_value = Sym->getVA(); @@ -2026,6 +2028,44 @@ } } +SymtabShndxSection::SymtabShndxSection() + : SyntheticSection(0, SHT_SYMTAB_SHNDX, 4, ".symtab_shndxr") { + this->Entsize = 4; +} + +void SymtabShndxSection::writeTo(uint8_t *Buf) { + // We write an array of 32 bit values, where each value has 1:1 association + // with an entry in .symtab. If the corresponding entry contains SHN_XINDEX, + // we need to write actual index, otherwise, we must write SHN_UNDEF(0). + Buf += 4; // Ignore .symtab[0] entry. + for (const SymbolTableEntry &Entry : InX::SymTab->getSymbols()) { + if (getSymSectionIndex(Entry.Sym) == SHN_XINDEX) + write32(Buf, Entry.Sym->getOutputSection()->SectionIndex); + Buf += 4; + } +} + +bool SymtabShndxSection::empty() const { + // SHT_SYMTAB can hold symbols with section indices values up to + // SHN_LORESERVE. If we need more, we want to use extension SHT_SYMTAB_SHNDX + // section. Problem is that we reveal the final section indices a bit too + // late, and we do not know them here. For simplicity, we just always create + // a .symtab_shndxr section when the amount of output sections is huge. + size_t Size = 0; + for (BaseCommand *Base : Script->SectionCommands) + if (isa(Base)) + ++Size; + return Size < SHN_LORESERVE; +} + +void SymtabShndxSection::finalizeContents() { + getParent()->Link = InX::SymTab->getParent()->SectionIndex; +} + +size_t SymtabShndxSection::getSize() const { + return InX::SymTab->getNumSymbols() * 4; +} + // .hash and .gnu.hash sections contain on-disk hash tables that map // symbol names to their dynamic symbol table indices. Their purpose // is to help the dynamic linker resolve symbols quickly. If ELF files @@ -3025,6 +3065,7 @@ StringTableSection *InX::ShStrTab; StringTableSection *InX::StrTab; SymbolTableBaseSection *InX::SymTab; +SymtabShndxSection *InX::SymTabShndx; template GdbIndexSection *GdbIndexSection::create(); template GdbIndexSection *GdbIndexSection::create(); Index: lld/trunk/ELF/Writer.cpp =================================================================== --- lld/trunk/ELF/Writer.cpp +++ lld/trunk/ELF/Writer.cpp @@ -287,6 +287,7 @@ if (Config->Strip != StripPolicy::All) { InX::StrTab = make(".strtab", false); InX::SymTab = make>(*InX::StrTab); + InX::SymTabShndx = make(); } if (Config->BuildId != BuildIdKind::None) { @@ -409,6 +410,8 @@ if (InX::SymTab) Add(InX::SymTab); + if (InX::SymTabShndx) + Add(InX::SymTabShndx); Add(InX::ShStrTab); if (InX::StrTab) Add(InX::StrTab); @@ -1639,12 +1642,13 @@ // Dynamic section must be the last one in this list and dynamic // symbol table section (DynSymTab) must be the first one. applySynthetic( - {InX::DynSymTab, InX::Bss, InX::BssRelRo, InX::GnuHashTab, - InX::HashTab, InX::SymTab, InX::ShStrTab, InX::StrTab, - In::VerDef, InX::DynStrTab, InX::Got, InX::MipsGot, - InX::IgotPlt, InX::GotPlt, InX::RelaDyn, InX::RelrDyn, - InX::RelaIplt, InX::RelaPlt, InX::Plt, InX::Iplt, - InX::EhFrameHdr, In::VerSym, In::VerNeed, InX::Dynamic}, + {InX::DynSymTab, InX::Bss, InX::BssRelRo, InX::GnuHashTab, + InX::HashTab, InX::SymTab, InX::SymTabShndx, InX::ShStrTab, + InX::StrTab, In::VerDef, InX::DynStrTab, InX::Got, + InX::MipsGot, InX::IgotPlt, InX::GotPlt, InX::RelaDyn, + InX::RelrDyn, InX::RelaIplt, InX::RelaPlt, InX::Plt, + InX::Iplt, InX::EhFrameHdr, In::VerSym, In::VerNeed, + InX::Dynamic}, [](SyntheticSection *SS) { SS->finalizeContents(); }); if (!Script->HasSectionsCommand && !Config->Relocatable) Index: lld/trunk/test/ELF/linkerscript/orphan-report.s =================================================================== --- lld/trunk/test/ELF/linkerscript/orphan-report.s +++ lld/trunk/test/ELF/linkerscript/orphan-report.s @@ -36,6 +36,7 @@ # REPORT-NEXT: :(.plt) is being placed in '.plt' # REPORT-NEXT: :(.eh_frame) is being placed in '.eh_frame' # REPORT-NEXT: :(.symtab) is being placed in '.symtab' +# REPORT-NEXT: :(.symtab_shndxr) is being placed in '.symtab_shndxr' # REPORT-NEXT: :(.shstrtab) is being placed in '.shstrtab' # REPORT-NEXT: :(.strtab) is being placed in '.strtab' Index: lld/trunk/test/ELF/relocatable-many-sections.s =================================================================== --- lld/trunk/test/ELF/relocatable-many-sections.s +++ lld/trunk/test/ELF/relocatable-many-sections.s @@ -1,20 +1,32 @@ # REQUIRES: x86 # RUN: llvm-mc -filetype=obj -triple x86_64-pc-linux-gnu %s -o %t.o # RUN: ld.lld -r %t.o -o %t -# RUN: llvm-readobj -file-headers %t | FileCheck %s -## Check we are able to emit a valid ELF header when +## Check we are able to link against relocatable file produced. +# RUN: ld.lld %t -o %t.out + +## Check we emit a valid ELF header when ## sections amount is greater than SHN_LORESERVE. -# CHECK: ElfHeader { -# CHECK: SectionHeaderCount: 0 (65541) -# CHECK-NEXT: StringTableSectionIndex: 65535 (65539) - -## Check that 65539 is really the index of .shstrtab section. -# RUN: llvm-objdump -section-headers -section=.shstrtab %t \ -# RUN: | FileCheck %s --check-prefix=SHSTRTAB -# SHSTRTAB: Sections: -# SHSTRTAB-NEXT: Idx Name -# SHSTRTAB-NEXT: 65539 .shstrtab +# RUN: llvm-readobj -file-headers %t | FileCheck %s --check-prefix=HDR +# HDR: ElfHeader { +# HDR: SectionHeaderCount: 0 (65543) +# HDR-NEXT: StringTableSectionIndex: 65535 (65541) + +## Check that: +## 1) 65541 is the index of .shstrtab section. +## 2) .symtab_shndxr is linked with .symtab. +## 3) .symtab_shndxr entry size and alignment == 4. +## 4) .symtab_shndxr has size equal to +## (sizeof(.symtab) / entsize(.symtab)) * entsize(.symtab_shndxr) = 0x4 * 0x180048 / 0x18 == 0x04000c +# RUN: llvm-readelf -sections -symbols %t | FileCheck %s +## [Nr] Name Type Address Off Size ES Flg Lk Inf Al +# CHECK: [65538] .bar +# CHECK-NEXT: [65539] .symtab SYMTAB 0000000000000000 000040 180078 18 65542 65539 8 +# CHECK-NEXT: [65540] .symtab_shndxr SYMTAB SECTION INDICES 0000000000000000 1800b8 040014 04 65539 0 4 +# CHECK-NEXT: [65541] .shstrtab STRTAB 0000000000000000 1c00cc 0f0035 00 0 0 1 +# CHECK-NEXT: [65542] .strtab STRTAB 0000000000000000 2b0101 00000c 00 +# 5) Check we are able to represent symbol foo with section (.bar) index > 0xFF00 (SHN_LORESERVE). +# CHECK: GLOBAL DEFAULT 65538 foo .macro gen_sections4 x .section a\x @@ -88,5 +100,10 @@ gen_sections16384 c gen_sections16384 d +.section .bar +.global foo +foo: + +.section .text, "ax" .global _start _start: