Index: ELF/Driver.cpp =================================================================== --- ELF/Driver.cpp +++ ELF/Driver.cpp @@ -1276,7 +1276,7 @@ // Aggregate all input sections into one place. for (InputFile *F : ObjectFiles) for (InputSectionBase *S : F->getSections()) - if (S && S != &InputSection::Discarded) + if (S && !isDiscarded(S)) InputSections.push_back(S); for (BinaryFile *F : BinaryFiles) for (InputSectionBase *S : F->getSections()) Index: ELF/InputFiles.h =================================================================== --- ELF/InputFiles.h +++ ELF/InputFiles.h @@ -178,7 +178,8 @@ ArrayRef getGlobalSymbols(); ObjFile(MemoryBufferRef M, StringRef ArchiveName); - void parse(llvm::DenseSet &ComdatGroups); + void parse(llvm::DenseMap + &ComdatGroups); Symbol &getSymbol(uint32_t SymbolIndex) const { if (SymbolIndex >= this->Symbols.size()) @@ -208,8 +209,8 @@ StringRef SourceFile; private: - void - initializeSections(llvm::DenseSet &ComdatGroups); + void initializeSections(llvm::DenseMap &ComdatGroups); void initializeSymbols(); void initializeJustSymbols(); void initializeDwarf(); @@ -291,7 +292,8 @@ uint64_t OffsetInArchive); static bool classof(const InputFile *F) { return F->kind() == BitcodeKind; } template - void parse(llvm::DenseSet &ComdatGroups); + void parse(llvm::DenseMap + &ComdatGroups); std::unique_ptr Obj; }; Index: ELF/InputFiles.cpp =================================================================== --- ELF/InputFiles.cpp +++ ELF/InputFiles.cpp @@ -279,7 +279,8 @@ } template -void ObjFile::parse(DenseSet &ComdatGroups) { +void ObjFile::parse(llvm::DenseMap &ComdatGroups) { // Read a section table. JustSymbols is usually false. if (this->JustSymbols) initializeJustSymbols(); @@ -396,7 +397,8 @@ template void ObjFile::initializeSections( - DenseSet &ComdatGroups) { + llvm::DenseMap + &ComdatGroups) { const ELFFile &Obj = this->getObj(); ArrayRef ObjSections = CHECK(this->getObj().sections(), this); @@ -406,7 +408,7 @@ CHECK(Obj.getSectionStringTable(ObjSections), this); for (size_t I = 0, E = ObjSections.size(); I < E; I++) { - if (this->Sections[I] == &InputSection::Discarded) + if (isDiscarded(this->Sections[I])) continue; const Elf_Shdr &Sec = ObjSections[I]; @@ -422,7 +424,6 @@ case SHT_GROUP: { // De-duplicate section groups by their signatures. StringRef Signature = getShtGroupSignature(ObjSections, Sec); - bool IsNew = ComdatGroups.insert(CachedHashStringRef(Signature)).second; this->Sections[I] = &InputSection::Discarded; // If it is a new section group, we want to keep group members. @@ -430,7 +431,14 @@ // discarded because they are useless beyond this point. The only // exception is the -r option because in order to produce re-linkable // object files, we want to pass through basically everything. - if (IsNew) { + ArrayRef::Elf_Word> Entries = + getShtGroupEntries(Sec); + + auto It = ComdatGroups.insert({CachedHashStringRef(Signature), nullptr}); + if (It.second /* IsNew */) { + if (Entries.size() == 1) + It.first->second = &this->Sections[Entries[0]]; + if (Config->Relocatable) this->Sections[I] = createInputSection(Sec); continue; @@ -443,6 +451,22 @@ ": invalid section index in group: " + Twine(SecIndex)); this->Sections[SecIndex] = &InputSection::Discarded; } + + // Ideally we could finish here, but unfortunately, have one more + // special case that we want to support. Modern compilers at the moment + // of may/2018 produce technically incorrect ELF when representing the + // debug information for COMDAT groups. We want to support resolving the + // relocations to deduplicated COMDAT sections. We support only the case + // when there is a single COMDAT section in a group because there is no + // clean way to perform correct mapping of the sections to the leader + // sections as COMDATs are designed to work with a group of sections. + // Here we create discarded proxy section that keeps information about the + // leader. + InputSectionBase **SingleLeaderSec = It.first->second; + if (Entries.size() == 1 && SingleLeaderSec) { + InputSection *IS = createDiscardedProxy(*SingleLeaderSec); + this->Sections[Entries[0]] = IS; + } break; } case SHT_SYMTAB: @@ -529,7 +553,7 @@ // Strictly speaking, a relocation section must be included in the // group of the section it relocates. However, LLVM 3.3 and earlier // would fail to do so, so we gracefully handle that case. - if (Target == &InputSection::Discarded) + if (isDiscarded(Target)) return nullptr; if (!Target) @@ -733,7 +757,7 @@ case STB_GLOBAL: case STB_WEAK: case STB_GNU_UNIQUE: - if (Sec == &InputSection::Discarded) + if (isDiscarded(Sec)) return Symtab->addUndefined(Name, Binding, StOther, Type, /*CanOmitFromDynSym=*/false, this); return Symtab->addRegular(Name, StOther, Type, Value, Size, Binding, Sec, @@ -1078,10 +1102,12 @@ } template -void BitcodeFile::parse(DenseSet &ComdatGroups) { +void BitcodeFile::parse(llvm::DenseMap &ComdatGroups) { std::vector KeptComdats; for (StringRef S : Obj->getComdatTable()) - KeptComdats.push_back(ComdatGroups.insert(CachedHashStringRef(S)).second); + KeptComdats.push_back( + ComdatGroups.insert({CachedHashStringRef(S), {}}).second); for (const lto::InputFile::Symbol &ObjSym : Obj->symbols()) Symbols.push_back(createBitcodeSymbol(KeptComdats, ObjSym, *this)); @@ -1236,10 +1262,14 @@ template void ArchiveFile::parse(); template void ArchiveFile::parse(); -template void BitcodeFile::parse(DenseSet &); -template void BitcodeFile::parse(DenseSet &); -template void BitcodeFile::parse(DenseSet &); -template void BitcodeFile::parse(DenseSet &); +template void BitcodeFile::parse( + llvm::DenseMap &); +template void BitcodeFile::parse( + llvm::DenseMap &); +template void BitcodeFile::parse( + llvm::DenseMap &); +template void BitcodeFile::parse( + llvm::DenseMap &); template void LazyObjFile::parse(); template void LazyObjFile::parse(); Index: ELF/InputSection.h =================================================================== --- ELF/InputSection.h +++ ELF/InputSection.h @@ -48,6 +48,8 @@ // Repl pointer of one section points to another section. So, // if you need to get a pointer to this instance, do not use // this but instead this->Repl. + // We also may use this member to keep information about COMDAT leader + // when creating discarded proxy section. See createDiscardedProxy(). SectionBase *Repl; unsigned SectionKind : 3; @@ -336,6 +338,10 @@ // The list of all input sections. extern std::vector InputSections; + +InputSection* createDiscardedProxy(InputSectionBase *Target); +bool isDiscarded(InputSectionBase* IS); + } // namespace elf std::string toString(const elf::InputSectionBase *); Index: ELF/InputSection.cpp =================================================================== --- ELF/InputSection.cpp +++ ELF/InputSection.cpp @@ -285,6 +285,20 @@ .str(); } +InputSection *elf::createDiscardedProxy(InputSectionBase *Target) { + InputSection *IS = + make(nullptr, 0, 0, 0, ArrayRef(), ""); + IS->Repl = Target; + return IS; +} + +bool elf::isDiscarded(InputSectionBase *IS) { + if (IS == &InputSection::Discarded) + return true; + return IS && !IS->File && !IS->Flags && !IS->Type && IS->Data.empty() && + IS->Name.empty(); +} + InputSection InputSection::Discarded(nullptr, 0, 0, 0, ArrayRef(), ""); InputSection::InputSection(InputFile *F, uint64_t Flags, uint32_t Type, @@ -371,7 +385,7 @@ continue; } SectionBase *Section = D->Section; - if (Section == &InputSection::Discarded) { + if (isDiscarded(dyn_cast(Section))) { P->setSymbolAndType(0, 0, false); continue; } Index: ELF/SymbolTable.h =================================================================== --- ELF/SymbolTable.h +++ ELF/SymbolTable.h @@ -109,8 +109,9 @@ // Comdat groups define "link once" sections. If two comdat groups have the // same name, only one of them is linked, and the other is ignored. This set - // is used to uniquify them. - llvm::DenseSet ComdatGroups; + // is used to uniquify them. Value contains a pointer to the single comdat + // leader section if such exist. + llvm::DenseMap ComdatGroups; // Set of .so files to not link the same shared object file more than once. llvm::DenseSet SoNames; Index: ELF/SymbolTable.cpp =================================================================== --- ELF/SymbolTable.cpp +++ ELF/SymbolTable.cpp @@ -130,7 +130,7 @@ LTO->add(*F); for (InputFile *File : LTO->compile()) { - DenseSet DummyGroups; + llvm::DenseMap DummyGroups; auto *Obj = cast>(File); Obj->parse(DummyGroups); for (Symbol *Sym : Obj->getGlobalSymbols()) Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -528,6 +528,8 @@ SectionBase *Sec = D->Section; if (!Sec) return true; + if (isDiscarded(dyn_cast(Sec))) + return false; Sec = Sec->Repl; // Exclude symbols pointing to garbage-collected sections. if (isa(Sec) && !Sec->Live) Index: test/ELF/comdat-debug.s =================================================================== --- test/ELF/comdat-debug.s +++ test/ELF/comdat-debug.s @@ -0,0 +1,22 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o +# RUN: ld.lld %t.o %t.o -o %t +# RUN: llvm-objdump -D %t | FileCheck %s + +## Check that we are able to resolve relocation to discarded COMDAT. +## That violates ELF spec, but unfortunately clang and gcc produce +## technically incorrect ELF and we have to handle this case to +## improve debugging experience. + +# CHECK: Disassembly of section .debug_info: +# CHECK-NEXT: .debug_info: +# CHECK-NEXT: 00 10 +# CHECK-NEXT: 20 00 +# CHECK-NEXT: 00 10 +# CHECK-NEXT: 20 00 + +.section .text.foo,"axG",@progbits,bar,comdat +.Lfoo: + +.section .debug_info,"",@progbits + .long .Lfoo Index: test/ELF/comdat.s =================================================================== --- test/ELF/comdat.s +++ test/ELF/comdat.s @@ -29,9 +29,9 @@ // CHECK: Disassembly of section bar: // CHECK-NEXT: bar: // 0x1000 - 0x1001 - 5 = -6 -// 0 - 0x1006 - 5 = -4107 +// 0x1000 - 0x1006 - 5 = -11 // CHECK-NEXT: 1001: {{.*}} callq -6 -// CHECK-NEXT: 1006: {{.*}} callq -4107 +// CHECK-NEXT: 1006: {{.*}} callq -11 .section .text3,"axG",@progbits,zed,comdat,unique,0