Index: ELF/InputFiles.h =================================================================== --- ELF/InputFiles.h +++ ELF/InputFiles.h @@ -29,6 +29,7 @@ class InputFile; class Lazy; class SymbolBody; +class SymbolTable; // The root class of input files. class InputFile { @@ -37,9 +38,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: @@ -75,6 +73,7 @@ static bool classof(const InputFile *F) { return F->kind() == ObjectKind; } ArrayRef getSymbols() { return SymbolBodies; } + virtual void parse(SymbolTable &Symtab) = 0; protected: // List of all symbols referenced or defined by this file. @@ -126,6 +125,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 +139,7 @@ } explicit ObjectFile(MemoryBufferRef M); - void parse() override; + void parse(SymbolTable &Symtab) override; ArrayRef *> getSections() const { return Sections; } @@ -152,7 +156,7 @@ ArrayRef getSymbolTableShndx() const { return SymtabSHNDX; }; private: - void initializeSections(); + void initializeSections(SymbolTable &Symtab); void initializeSymbols(); SymbolBody *createSymbolBody(StringRef StringTable, const Elf_Sym *Sym); @@ -167,7 +171,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 +198,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 @@ -11,6 +11,7 @@ #include "InputSection.h" #include "Error.h" #include "Symbols.h" +#include "SymbolTable.h" #include "llvm/ADT/STLExtras.h" using namespace llvm; @@ -95,19 +96,65 @@ return this->getSymbolsHelper(true); } -template void elf2::ObjectFile::parse() { +template void elf2::ObjectFile::parse(SymbolTable &Symtab) { // Read section and symbol tables. - initializeSections(); + initializeSections(Symtab); 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(SymbolTable &Symtab) { 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 (Symtab.insertComdat(getShtGroupSignature(Sec))) + 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 +182,6 @@ Sections[I] = new (Alloc) InputSection(this, &Sec); break; } - ++I; } } @@ -177,8 +223,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 @@ -329,9 +329,9 @@ Out::DynStrTab->add(File->getSoName()); NumEntries += SharedFiles.size(); - if (Symbol *S = SymTab.getSymbols().lookup(Config->Init)) + if (Symbol *S = SymTab.lookup(Config->Init)) InitSym = dyn_cast>(S->Body); - if (Symbol *S = SymTab.getSymbols().lookup(Config->Fini)) + if (Symbol *S = SymTab.lookup(Config->Fini)) FiniSym = dyn_cast>(S->Body); if (InitSym) ++NumEntries; // DT_INIT @@ -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); @@ -631,6 +652,8 @@ for (const std::pair &P : Table.getSymbols()) { StringRef Name = P.first; Symbol *Sym = P.second; + if (!Sym) + continue; SymbolBody *Body = Sym->Body; if (!includeInSymtab(*Body)) continue; @@ -774,13 +797,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 @@ -11,6 +11,7 @@ #define LLD_ELF_SYMBOL_TABLE_H #include "InputFiles.h" +#include "llvm/ADT/iterator.h" #include "llvm/ADT/MapVector.h" namespace lld { @@ -29,6 +30,18 @@ // to replace the lazy symbol. The logic is implemented in resolve(). class SymbolTable { public: + typedef llvm::MapVector> MapType; + typedef MapType::const_iterator raw_iter; + struct iter : public llvm::iterator_adaptor_base< + iter, raw_iter, + typename std::iterator_traits::iterator_category, + const std::pair> { + iter(raw_iter u) : iter::iterator_adaptor_base(u) {} + const std::pair operator*() const { + const std::pair> &V = *I; + return std::make_pair(V.first, V.second.getPointer()); + } + }; SymbolTable(); void addFile(std::unique_ptr File); @@ -43,10 +56,18 @@ bool shouldUseRela() const; - const llvm::MapVector &getSymbols() const { - return Symtab; + llvm::iterator_range getSymbols() const { + iter Begin = Symtab.begin(); + iter End = Symtab.end(); + return make_range(Begin, End); } + Symbol *lookup(StringRef Key) const { + return Symtab.lookup(Key).getPointer(); + } + + bool insertComdat(StringRef Signature); + const std::vector> &getObjectFiles() const { return ObjectFiles; } @@ -92,7 +113,7 @@ // a bit inefficient. // FIXME: Experiment with passing in a custom hashing or sorting the symbols // once symbol resolution is finished. - llvm::MapVector Symtab; + MapType Symtab; llvm::BumpPtrAllocator Alloc; // The writer needs to infer the machine type from the object files. Index: ELF/SymbolTable.cpp =================================================================== --- ELF/SymbolTable.cpp +++ ELF/SymbolTable.cpp @@ -27,6 +27,14 @@ return K == ELF64LEKind || K == ELF64BEKind; } +bool SymbolTable::insertComdat(StringRef Signature) { + llvm::PointerIntPair &V = Symtab[Signature]; + if (V.getInt()) + return false; + V.setInt(1); + return true; +} + void SymbolTable::addFile(std::unique_ptr File) { if (auto *AF = dyn_cast(File.get())) { File.release(); @@ -45,8 +53,11 @@ S->parseSoName(); if (!IncludedSoNames.insert(S->getSoName()).second) return; + S->parse(); + } else { + cast(File.get())->parse(*this); } - File->parse(); + addELFFile(cast(File.release())); } @@ -247,10 +258,12 @@ Symbol *SymbolTable::insert(SymbolBody *New) { // Find an existing Symbol or create and insert a new one. StringRef Name = New->getName(); - Symbol *&Sym = Symtab[Name]; + PointerIntPair &P = Symtab[Name]; + Symbol *Sym = P.getPointer(); if (!Sym) { Sym = new (Alloc) Symbol(New); New->setBackref(Sym); + P.setPointer(Sym); return Sym; } New->setBackref(Sym); 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()) @@ -440,7 +441,10 @@ std::vector *> CommonSymbols; for (auto &P : Symtab.getSymbols()) { StringRef Name = P.first; - SymbolBody *Body = P.second->Body; + Symbol *Sym = P.second; + if (!Sym) + continue; + SymbolBody *Body = Sym->Body; if (auto *U = dyn_cast>(Body)) { if (!U->isWeak() && !U->canKeepUndefined()) reportUndefined(Symtab, *Body); 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: ]