Index: lld/trunk/COFF/InputFiles.h =================================================================== --- lld/trunk/COFF/InputFiles.h +++ lld/trunk/COFF/InputFiles.h @@ -13,6 +13,7 @@ #include "Config.h" #include "lld/Common/LLVM.h" #include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/DenseMap.h" #include "llvm/ADT/DenseSet.h" #include "llvm/LTO/LTO.h" #include "llvm/Object/Archive.h" @@ -157,10 +158,24 @@ COFFSymbolRef COFFSym, const llvm::object::coff_aux_section_definition *Def); + void readAssociativeDefinition( + COFFSymbolRef COFFSym, + const llvm::object::coff_aux_section_definition *Def, + uint32_t ParentSection); + + void recordPrevailingSymbolForMingw( + COFFSymbolRef COFFSym, + llvm::DenseMap &PrevailingSectionMap); + + void maybeAssociateSEHForMingw( + COFFSymbolRef Sym, const llvm::object::coff_aux_section_definition *Def, + const llvm::DenseMap &PrevailingSectionMap); + llvm::Optional createDefined(COFFSymbolRef Sym, std::vector - &ComdatDefs); + &ComdatDefs, + bool &PrevailingComdat); Symbol *createRegular(COFFSymbolRef Sym); Symbol *createUndefined(COFFSymbolRef Sym); Index: lld/trunk/COFF/InputFiles.cpp =================================================================== --- lld/trunk/COFF/InputFiles.cpp +++ lld/trunk/COFF/InputFiles.cpp @@ -205,7 +205,13 @@ void ObjFile::readAssociativeDefinition( COFFSymbolRef Sym, const coff_aux_section_definition *Def) { - SectionChunk *Parent = SparseChunks[Def->getNumber(Sym.isBigObj())]; + readAssociativeDefinition(Sym, Def, Def->getNumber(Sym.isBigObj())); +} + +void ObjFile::readAssociativeDefinition(COFFSymbolRef Sym, + const coff_aux_section_definition *Def, + uint32_t ParentSection) { + SectionChunk *Parent = SparseChunks[ParentSection]; // If the parent is pending, it probably means that its section definition // appears after us in the symbol table. Leave the associated section as @@ -225,6 +231,35 @@ } } +void ObjFile::recordPrevailingSymbolForMingw( + COFFSymbolRef Sym, DenseMap &PrevailingSectionMap) { + // For comdat symbols in executable sections, where this is the copy + // of the section chunk we actually include instead of discarding it, + // add the symbol to a map to allow using it for implicitly + // associating .[px]data$ sections to it. + int32_t SectionNumber = Sym.getSectionNumber(); + SectionChunk *SC = SparseChunks[SectionNumber]; + if (SC && SC->getOutputCharacteristics() & IMAGE_SCN_MEM_EXECUTE) { + StringRef Name; + COFFObj->getSymbolName(Sym, Name); + PrevailingSectionMap[Name] = SectionNumber; + } +} + +void ObjFile::maybeAssociateSEHForMingw( + COFFSymbolRef Sym, const coff_aux_section_definition *Def, + const DenseMap &PrevailingSectionMap) { + StringRef Name; + COFFObj->getSymbolName(Sym, Name); + if (Name.consume_front(".pdata$") || Name.consume_front(".xdata$")) { + // For MinGW, treat .[px]data$ as implicitly associative to + // the symbol . + auto ParentSym = PrevailingSectionMap.find(Name); + if (ParentSym != PrevailingSectionMap.end()) + readAssociativeDefinition(Sym, Def, ParentSym->second); + } +} + Symbol *ObjFile::createRegular(COFFSymbolRef Sym) { SectionChunk *SC = SparseChunks[Sym.getSectionNumber()]; if (Sym.isExternal()) { @@ -248,19 +283,24 @@ std::vector PendingIndexes; PendingIndexes.reserve(NumSymbols); + DenseMap PrevailingSectionMap; std::vector ComdatDefs( COFFObj->getNumberOfSections() + 1); for (uint32_t I = 0; I < NumSymbols; ++I) { COFFSymbolRef COFFSym = check(COFFObj->getSymbol(I)); + bool PrevailingComdat; if (COFFSym.isUndefined()) { Symbols[I] = createUndefined(COFFSym); } else if (COFFSym.isWeakExternal()) { Symbols[I] = createUndefined(COFFSym); uint32_t TagIndex = COFFSym.getAux()->TagIndex; WeakAliases.emplace_back(Symbols[I], TagIndex); - } else if (Optional OptSym = createDefined(COFFSym, ComdatDefs)) { + } else if (Optional OptSym = + createDefined(COFFSym, ComdatDefs, PrevailingComdat)) { Symbols[I] = *OptSym; + if (Config->MinGW && PrevailingComdat) + recordPrevailingSymbolForMingw(COFFSym, PrevailingSectionMap); } else { // createDefined() returns None if a symbol belongs to a section that // was pending at the point when the symbol was read. This can happen in @@ -278,9 +318,12 @@ for (uint32_t I : PendingIndexes) { COFFSymbolRef Sym = check(COFFObj->getSymbol(I)); - if (auto *Def = Sym.getSectionDefinition()) + if (auto *Def = Sym.getSectionDefinition()) { if (Def->Selection == IMAGE_COMDAT_SELECT_ASSOCIATIVE) readAssociativeDefinition(Sym, Def); + else if (Config->MinGW) + maybeAssociateSEHForMingw(Sym, Def, PrevailingSectionMap); + } if (SparseChunks[Sym.getSectionNumber()] == PendingComdat) { StringRef Name; COFFObj->getSymbolName(Sym, Name); @@ -306,7 +349,9 @@ Optional ObjFile::createDefined( COFFSymbolRef Sym, - std::vector &ComdatDefs) { + std::vector &ComdatDefs, + bool &Prevailing) { + Prevailing = false; auto GetName = [&]() { StringRef S; COFFObj->getSymbolName(Sym, S); @@ -352,7 +397,6 @@ if (const coff_aux_section_definition *Def = ComdatDefs[SectionNumber]) { ComdatDefs[SectionNumber] = nullptr; Symbol *Leader; - bool Prevailing; if (Sym.isExternal()) { std::tie(Leader, Prevailing) = Symtab->addComdat(this, GetName(), Sym.getGeneric()); Index: lld/trunk/test/COFF/Inputs/associative-comdat-mingw-2.s =================================================================== --- lld/trunk/test/COFF/Inputs/associative-comdat-mingw-2.s +++ lld/trunk/test/COFF/Inputs/associative-comdat-mingw-2.s @@ -0,0 +1,34 @@ + .section .xdata$foo,"dr" + .linkonce discard + .p2align 3 + .long 42 + + .section .xdata$bar,"dr" + .linkonce discard + .p2align 3 + .long 43 + + .section .xdata$baz,"dr" + .linkonce discard + .p2align 3 + .long 44 + + .def foo; + .scl 2; + .type 32; + .endef + .section .text$foo,"xr",discard,foo + .globl foo + .p2align 4 +foo: + ret + + .def bar; + .scl 2; + .type 32; + .endef + .section .text$bar,"xr",discard,bar + .globl bar + .p2align 4 +bar: + ret Index: lld/trunk/test/COFF/associative-comdat-mingw.s =================================================================== --- lld/trunk/test/COFF/associative-comdat-mingw.s +++ lld/trunk/test/COFF/associative-comdat-mingw.s @@ -0,0 +1,73 @@ +# REQUIRES: x86 + +# RUN: llvm-mc -triple=x86_64-windows-gnu %s -filetype=obj -o %t1.obj +# RUN: llvm-mc -triple=x86_64-windows-gnu %S/Inputs/associative-comdat-mingw-2.s -filetype=obj -o %t2.obj + +# RUN: lld-link -lldmingw -entry:main %t1.obj %t2.obj -out:%t.gc.exe -verbose +# RUN: llvm-readobj -sections %t.gc.exe | FileCheck %s + +# CHECK: Sections [ +# CHECK: Section { +# CHECK: Number: 2 +# CHECK-LABEL: Name: .rdata (2E 72 64 61 74 61 00 00) +# This is the critical check to show that only *one* definition of +# .xdata$foo was retained. This *must* be 4. +# Make sure that no other .xdata sections get included, which would +# increase the size here. +# CHECK-NEXT: VirtualSize: 0x4 + + .text + .def main; + .scl 2; + .type 32; + .endef + .globl main + .p2align 4, 0x90 +main: + call foo + retq + +# Defines .text$foo (which has a leader symbol and is referenced like +# normally), and .xdata$foo (which lacks a leader symbol, which normally +# would be declared associative to the symbol foo). +# .xdata$foo should be implicitly treated as associative to foo and brought +# in, while .xdata$bar, implicitly associative to bar, not included, and +# .xdata$baz not included since there's no symbol baz. + +# GNU binutils ld doesn't do this at all, but always includes all .xdata/.pdata +# comdat sections, even if --gc-sections is used. + + .section .xdata$foo,"dr" + .linkonce discard + .p2align 3 + .long 42 + + .section .xdata$bar,"dr" + .linkonce discard + .p2align 3 + .long 43 + + .section .xdata$baz,"dr" + .linkonce discard + .p2align 3 + .long 44 + + .def foo; + .scl 2; + .type 32; + .endef + .section .text$foo,"xr",discard,foo + .globl foo + .p2align 4 +foo: + ret + + .def bar; + .scl 2; + .type 32; + .endef + .section .text$bar,"xr",discard,bar + .globl bar + .p2align 4 +bar: + ret