Index: ELF/InputFiles.h =================================================================== --- ELF/InputFiles.h +++ ELF/InputFiles.h @@ -37,9 +37,6 @@ Kind kind() const { return FileKind; } virtual ~InputFile() {} - // Reads a file (constructors don't do that). - virtual void parse() = 0; - StringRef getName() const { return MB.getBufferIdentifier(); } protected: @@ -67,6 +64,8 @@ const ELFKind EKind; }; +typedef llvm::DenseSet ComdatSet; + // .o file. class ObjectFileBase : public ELFFileBase { public: @@ -75,6 +74,7 @@ static bool classof(const InputFile *F) { return F->kind() == ObjectKind; } ArrayRef getSymbols() { return SymbolBodies; } + virtual void parse(ComdatSet &Comdats) = 0; protected: // List of all symbols referenced or defined by this file. @@ -126,6 +126,11 @@ typedef typename llvm::object::ELFFile::Elf_Sym_Range Elf_Sym_Range; typedef typename llvm::object::ELFFile::Elf_Word Elf_Word; + typedef llvm::support::detail::packed_endian_specific_integral< + uint32_t, ELFT::TargetEndianness, 2> GroupEntryType; + StringRef getShtGroupSignature(const Elf_Shdr &Sec); + ArrayRef getShtGroupEntries(const Elf_Shdr &Sec); + public: using ELFData::getEMachine; @@ -135,7 +140,7 @@ } explicit ObjectFile(MemoryBufferRef M); - void parse() override; + void parse(ComdatSet &Comdats) override; ArrayRef *> getSections() const { return Sections; } @@ -152,7 +157,7 @@ ArrayRef getSymbolTableShndx() const { return SymtabSHNDX; }; private: - void initializeSections(); + void initializeSections(ComdatSet &Comdats); void initializeSymbols(); SymbolBody *createSymbolBody(StringRef StringTable, const Elf_Sym *Sym); @@ -167,7 +172,7 @@ public: explicit ArchiveFile(MemoryBufferRef M) : InputFile(ArchiveKind, M) {} static bool classof(const InputFile *F) { return F->kind() == ArchiveKind; } - void parse() override; + void parse(); // Returns a memory buffer for a given symbol. An empty memory buffer // is returned if we have already returned the same memory buffer. @@ -194,6 +199,7 @@ static bool classof(const InputFile *F) { return F->kind() == SharedKind; } StringRef getSoName() const { return SoName; } virtual void parseSoName() = 0; + virtual void parse() = 0; }; template Index: ELF/InputFiles.cpp =================================================================== --- ELF/InputFiles.cpp +++ ELF/InputFiles.cpp @@ -95,19 +95,64 @@ return this->getSymbolsHelper(true); } -template void elf2::ObjectFile::parse() { +template void elf2::ObjectFile::parse(ComdatSet &Comdats) { // Read section and symbol tables. - initializeSections(); + initializeSections(Comdats); initializeSymbols(); } -template void elf2::ObjectFile::initializeSections() { +template +StringRef ObjectFile::getShtGroupSignature(const Elf_Shdr &Sec) { + const ELFFile &Obj = this->ELFObj; + uint32_t SymtabdSectionIndex = Sec.sh_link; + ErrorOr SecOrErr = Obj.getSection(SymtabdSectionIndex); + error(SecOrErr); + const Elf_Shdr *SymtabSec = *SecOrErr; + uint32_t SymIndex = Sec.sh_info; + const Elf_Sym *Sym = Obj.getSymbol(SymtabSec, SymIndex); + ErrorOr StringTableOrErr = Obj.getStringTableForSymtab(*SymtabSec); + error(StringTableOrErr); + ErrorOr SignatureOrErr = Sym->getName(*StringTableOrErr); + error(SignatureOrErr); + return *SignatureOrErr; +} + +template +ArrayRef::GroupEntryType> +ObjectFile::getShtGroupEntries(const Elf_Shdr &Sec) { + const ELFFile &Obj = this->ELFObj; + ErrorOr> EntriesOrErr = + Obj.template getSectionContentsAsArray(&Sec); + error(EntriesOrErr.getError()); + ArrayRef Entries = *EntriesOrErr; + if (Entries.empty() || Entries[0] != GRP_COMDAT) + error("Unsupported SHT_GROUP format"); + return Entries.slice(1); +} + +template +void elf2::ObjectFile::initializeSections(ComdatSet &Comdats) { uint64_t Size = this->ELFObj.getNumSections(); Sections.resize(Size); - unsigned I = 0; + unsigned I = -1; const ELFFile &Obj = this->ELFObj; for (const Elf_Shdr &Sec : Obj.sections()) { + ++I; + if (Sections[I] == &InputSection::Discarded) + continue; + switch (Sec.sh_type) { + case SHT_GROUP: + Sections[I] = &InputSection::Discarded; + if (Comdats.insert(getShtGroupSignature(Sec)).second) + continue; + for (GroupEntryType E : getShtGroupEntries(Sec)) { + uint32_t SecIndex = E; + if (SecIndex >= Size) + error("Invalid section index in group"); + Sections[SecIndex] = &InputSection::Discarded; + } + break; case SHT_SYMTAB: this->Symtab = &Sec; break; @@ -135,7 +180,6 @@ Sections[I] = new (Alloc) InputSection(this, &Sec); break; } - ++I; } } @@ -177,8 +221,12 @@ error("unexpected binding"); case STB_GLOBAL: case STB_WEAK: - case STB_GNU_UNIQUE: - return new (Alloc) DefinedRegular(Name, *Sym, *Sections[SecIndex]); + case STB_GNU_UNIQUE: { + InputSection *Sec = Sections[SecIndex]; + if (Sec == &InputSection::Discarded) + return new (Alloc) Undefined(Name, *Sym); + return new (Alloc) DefinedRegular(Name, *Sym, *Sec); + } } } Index: ELF/InputSection.h =================================================================== --- ELF/InputSection.h +++ ELF/InputSection.h @@ -56,6 +56,8 @@ // Relocation sections that refer to this one. SmallVector RelocSections; + static InputSection Discarded; + private: template void relocate(uint8_t *Buf, @@ -75,6 +77,9 @@ const Elf_Shdr *Header; }; +template +InputSection InputSection::Discarded(nullptr, nullptr); + } // namespace elf2 } // namespace lld Index: ELF/OutputSections.h =================================================================== --- ELF/OutputSections.h +++ ELF/OutputSections.h @@ -46,7 +46,8 @@ template bool shouldKeepInSymtab( - StringRef Name, const typename llvm::object::ELFFile::Elf_Sym &Sym); + const ObjectFile &File, StringRef Name, + const typename llvm::object::ELFFile::Elf_Sym &Sym); // This represents a section in an output file. // Different sub classes represent different types of sections. Some contain Index: ELF/OutputSections.cpp =================================================================== --- ELF/OutputSections.cpp +++ ELF/OutputSections.cpp @@ -475,6 +475,14 @@ Sym, File.getSymbolTable(), File.getSymbolTableShndx()); ArrayRef *> Sections = File.getSections(); InputSection *Section = Sections[SecIndex]; + + // According to the ELF spec reference to a local symbol from outside + // the group are not allowed. Unfortunately .eh_frame breaks that rule + // and must be treated specially. For now we just replace the symbol with + // 0. + if (Section == &InputSection::Discarded) + return 0; + OutputSection *OutSec = Section->getOutputSection(); return OutSec->getVA() + Section->getOutputSectionOff() + Sym->st_value; } @@ -534,11 +542,23 @@ } template -bool lld::elf2::shouldKeepInSymtab(StringRef SymName, +bool lld::elf2::shouldKeepInSymtab(const ObjectFile &File, + StringRef SymName, const typename ELFFile::Elf_Sym &Sym) { if (Sym.getType() == STT_SECTION) return false; + uint32_t SecIndex = Sym.st_shndx; + if (SecIndex != SHN_ABS) { + if (SecIndex == SHN_XINDEX) + SecIndex = File.getObj().getExtendedSymbolTableIndex( + &Sym, File.getSymbolTable(), File.getSymbolTableShndx()); + ArrayRef *> Sections = File.getSections(); + const InputSection *Section = Sections[SecIndex]; + if (Section == &InputSection::Discarded) + return false; + } + if (Config->DiscardNone) return true; @@ -597,8 +617,9 @@ ErrorOr SymNameOrErr = Sym.getName(File.getStringTable()); error(SymNameOrErr); StringRef SymName = *SymNameOrErr; - if (!shouldKeepInSymtab(SymName, Sym)) + if (!shouldKeepInSymtab(File, SymName, Sym)) continue; + auto *ESym = reinterpret_cast(Buf); Buf += sizeof(*ESym); ESym->st_name = StrTabSec.getFileOff(SymName); @@ -774,13 +795,17 @@ template bool includeInSymtab(const SymbolBody &); template bool includeInSymtab(const SymbolBody &); -template bool shouldKeepInSymtab(StringRef, +template bool shouldKeepInSymtab(const ObjectFile &, + StringRef, const ELFFile::Elf_Sym &); -template bool shouldKeepInSymtab(StringRef, +template bool shouldKeepInSymtab(const ObjectFile &, + StringRef, const ELFFile::Elf_Sym &); -template bool shouldKeepInSymtab(StringRef, +template bool shouldKeepInSymtab(const ObjectFile &, + StringRef, const ELFFile::Elf_Sym &); -template bool shouldKeepInSymtab(StringRef, +template bool shouldKeepInSymtab(const ObjectFile &, + StringRef, const ELFFile::Elf_Sym &); } } Index: ELF/SymbolTable.h =================================================================== --- ELF/SymbolTable.h +++ ELF/SymbolTable.h @@ -95,6 +95,8 @@ llvm::MapVector Symtab; llvm::BumpPtrAllocator Alloc; + llvm::DenseSet Comdats; + // The writer needs to infer the machine type from the object files. std::vector> ObjectFiles; Index: ELF/SymbolTable.cpp =================================================================== --- ELF/SymbolTable.cpp +++ ELF/SymbolTable.cpp @@ -45,8 +45,10 @@ S->parseSoName(); if (!IncludedSoNames.insert(S->getSoName()).second) return; + S->parse(); + } else { + cast(File.get())->parse(Comdats); } - File->parse(); addELFFile(cast(File.release())); } Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -295,8 +295,9 @@ ErrorOr SymNameOrErr = Sym.getName(File.getStringTable()); error(SymNameOrErr); StringRef SymName = *SymNameOrErr; - if (shouldKeepInSymtab(SymName, Sym)) - Out::SymTab->addSymbol(SymName, true); + if (!shouldKeepInSymtab(File, SymName, Sym)) + continue; + Out::SymTab->addSymbol(SymName, true); } } } @@ -398,11 +399,11 @@ for (const std::unique_ptr &FileB : Symtab.getObjectFiles()) { auto &File = cast>(*FileB); for (InputSection *C : File.getSections()) { - if (!C) + if (!C || C == &InputSection::Discarded) continue; const Elf_Shdr *H = C->getSectionHdr(); - SectionKey Key{C->getSectionName(), H->sh_type, - H->sh_flags}; + uintX_t OutFlags = H->sh_flags & ~SHF_GROUP; + SectionKey Key{C->getSectionName(), H->sh_type, OutFlags}; OutputSection *&Sec = Map[Key]; if (!Sec) { Sec = new (CAlloc.Allocate()) Index: test/elf2/Inputs/comdat.s =================================================================== --- /dev/null +++ test/elf2/Inputs/comdat.s @@ -0,0 +1,3 @@ + .section .text3,"axG",@progbits,zed,comdat,unique,0 + .global abc +abc: Index: test/elf2/comdat.s =================================================================== --- /dev/null +++ test/elf2/comdat.s @@ -0,0 +1,72 @@ +// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o +// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/comdat.s -o %t2.o +// RUN: ld.lld2 -shared %t.o %t.o %t2.o -o %t +// RUN: llvm-objdump -d %t | FileCheck %s +// RUN: llvm-readobj -s -t %t | FileCheck --check-prefix=READ %s +// REQUIRES: x86 + + .section .text2,"axG",@progbits,foo,comdat,unique,0 +foo: + nop + +// CHECK: Disassembly of section .text2: +// CHECK-NEXT: foo: +// CHECK-NEXT: 2000: {{.*}} nop +// CHECK-NOT: nop + + .section bar, "ax" + call foo + +// CHECK: Disassembly of section bar: +// CHECK-NEXT: bar: +// 0x2000 - 0x2001 - 5 = -6 +// 0 - 0x2006 - 5 = -8203 +// CHECK-NEXT: 2001: {{.*}} callq -6 +// CHECK-NEXT: 2006: {{.*}} callq -8203 + + .section .text3,"axG",@progbits,zed,comdat,unique,0 + + +// READ: Name: .text2 +// READ-NEXT: Type: SHT_PROGBITS +// READ-NEXT: Flags [ +// READ-NEXT: SHF_ALLOC +// READ-NEXT: SHF_EXECINSTR +// READ-NEXT: ] + +// READ: Name: .text3 +// READ-NEXT: Type: SHT_PROGBITS +// READ-NEXT: Flags [ +// READ-NEXT: SHF_ALLOC +// READ-NEXT: SHF_EXECINSTR +// READ-NEXT: ] + +// READ: Symbols [ +// READ-NEXT: Symbol { +// READ-NEXT: Name: (0) +// READ-NEXT: Value: 0x0 +// READ-NEXT: Size: 0 +// READ-NEXT: Binding: Local +// READ-NEXT: Type: None +// READ-NEXT: Other: 0 +// READ-NEXT: Section: Undefined +// READ-NEXT: } +// READ-NEXT: Symbol { +// READ-NEXT: Name: foo +// READ-NEXT: Value +// READ-NEXT: Size: 0 +// READ-NEXT: Binding: Local +// READ-NEXT: Type: None +// READ-NEXT: Other: 0 +// READ-NEXT: Section: .text +// READ-NEXT: } +// READ-NEXT: Symbol { +// READ-NEXT: Name: abc +// READ-NEXT: Value: 0x0 +// READ-NEXT: Size: 0 +// READ-NEXT: Binding: Global +// READ-NEXT: Type: None +// READ-NEXT: Other: 0 +// READ-NEXT: Section: Undefined +// READ-NEXT: } +// READ-NEXT: ]