Index: COFF/InputFiles.h =================================================================== --- COFF/InputFiles.h +++ COFF/InputFiles.h @@ -157,6 +157,11 @@ 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); + llvm::Optional createDefined(COFFSymbolRef Sym, std::vector Index: COFF/InputFiles.cpp =================================================================== --- COFF/InputFiles.cpp +++ 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 @@ -254,6 +260,7 @@ std::vector PendingIndexes; PendingIndexes.reserve(NumSymbols); + std::map SymbolSectionIndexes; std::vector ComdatDefs( COFFObj->getNumberOfSections() + 1); @@ -267,6 +274,11 @@ WeakAliases.emplace_back(Symbols[I], TagIndex); } else if (Optional OptSym = createDefined(COFFSym, ComdatDefs)) { Symbols[I] = *OptSym; + if (Config->MinGW) { + StringRef Name; + COFFObj->getSymbolName(COFFSym, Name); + SymbolSectionIndexes[Name] = COFFSym.getSectionNumber(); + } } 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 @@ -284,9 +296,21 @@ 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) { + StringRef Name; + COFFObj->getSymbolName(Sym, Name); + if (Name.consume_front(".xdata$") || Name.consume_front(".pdata$")) { + // For MinGW, treat .xdata$foo as implicitly associative to the symbol + // foo. + auto ParentSym = SymbolSectionIndexes.find(Name); + if (ParentSym != SymbolSectionIndexes.end()) + readAssociativeDefinition(Sym, Def, ParentSym->second); + } + } + } Symbols[I] = createRegular(Sym); } Index: test/COFF/Inputs/associative-comdat-mingw-2.s =================================================================== --- /dev/null +++ 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: test/COFF/associative-comdat-mingw.s =================================================================== --- /dev/null +++ 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",associative,foo +# .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