diff --git a/lld/COFF/InputFiles.h b/lld/COFF/InputFiles.h --- a/lld/COFF/InputFiles.h +++ b/lld/COFF/InputFiles.h @@ -255,9 +255,10 @@ // match the existing symbol and its selection. If either old or new // symbol have selection IMAGE_COMDAT_SELECT_LARGEST, Sym might replace // the existing leader. In that case, Prevailing is set to true. - void handleComdatSelection(COFFSymbolRef sym, - llvm::COFF::COMDATType &selection, - bool &prevailing, DefinedRegular *leader); + void + handleComdatSelection(COFFSymbolRef sym, llvm::COFF::COMDATType &selection, + bool &prevailing, DefinedRegular *leader, + const llvm::object::coff_aux_section_definition *def); llvm::Optional createDefined(COFFSymbolRef sym, diff --git a/lld/COFF/InputFiles.cpp b/lld/COFF/InputFiles.cpp --- a/lld/COFF/InputFiles.cpp +++ b/lld/COFF/InputFiles.cpp @@ -472,8 +472,23 @@ return symtab->addUndefined(name, this, sym.isWeakExternal()); } -void ObjFile::handleComdatSelection(COFFSymbolRef sym, COMDATType &selection, - bool &prevailing, DefinedRegular *leader) { +static const coff_aux_section_definition *findSectionDef(COFFObjectFile *obj, + int32_t section) { + uint32_t numSymbols = obj->getNumberOfSymbols(); + for (uint32_t i = 0; i < numSymbols; ++i) { + COFFSymbolRef sym = check(obj->getSymbol(i)); + if (sym.getSectionNumber() != section) + continue; + if (const coff_aux_section_definition *def = sym.getSectionDefinition()) + return def; + } + return nullptr; +} + +void ObjFile::handleComdatSelection( + COFFSymbolRef sym, COMDATType &selection, bool &prevailing, + DefinedRegular *leader, + const llvm::object::coff_aux_section_definition *def) { if (prevailing) return; // There's already an existing comdat for this symbol: `Leader`. @@ -540,8 +555,16 @@ break; case IMAGE_COMDAT_SELECT_SAME_SIZE: - if (leaderChunk->getSize() != getSection(sym)->SizeOfRawData) - symtab->reportDuplicate(leader, this); + if (leaderChunk->getSize() != getSection(sym)->SizeOfRawData) { + if (!config->mingw) { + symtab->reportDuplicate(leader, this); + } else { + const coff_aux_section_definition *leaderDef = findSectionDef( + leaderChunk->file->getCOFFObj(), leaderChunk->getSectionNumber()); + if (!leaderDef || leaderDef->Length != def->Length) + symtab->reportDuplicate(leader, this); + } + } break; case IMAGE_COMDAT_SELECT_EXACT_MATCH: { @@ -657,7 +680,7 @@ COMDATType selection = (COMDATType)def->Selection; if (leader->isCOMDAT) - handleComdatSelection(sym, selection, prevailing, leader); + handleComdatSelection(sym, selection, prevailing, leader, def); if (prevailing) { SectionChunk *c = readSection(sectionNumber, def, getName()); diff --git a/lld/test/COFF/Inputs/comdat-binutils.yaml b/lld/test/COFF/Inputs/comdat-binutils.yaml new file mode 100644 --- /dev/null +++ b/lld/test/COFF/Inputs/comdat-binutils.yaml @@ -0,0 +1,30 @@ +--- !COFF +header: + Machine: IMAGE_FILE_MACHINE_AMD64 + Characteristics: [ IMAGE_FILE_RELOCS_STRIPPED, IMAGE_FILE_LINE_NUMS_STRIPPED ] +sections: + - Name: '.rdata$mysymbol' + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_READ ] + Alignment: 16 + SectionData: 2A000000000000000000000000000000 +symbols: + - Name: '.rdata$mysymbol' + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 1 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 0 + Number: 0 + Selection: IMAGE_COMDAT_SELECT_SAME_SIZE + - Name: mysymbol + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_EXTERNAL +... diff --git a/lld/test/COFF/Inputs/comdat-llvm.yaml b/lld/test/COFF/Inputs/comdat-llvm.yaml new file mode 100644 --- /dev/null +++ b/lld/test/COFF/Inputs/comdat-llvm.yaml @@ -0,0 +1,30 @@ +--- !COFF +header: + Machine: IMAGE_FILE_MACHINE_AMD64 + Characteristics: [ ] +sections: + - Name: '.rdata$mysymbol' + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_READ ] + Alignment: 1 + SectionData: 2A +symbols: + - Name: '.rdata$mysymbol' + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 1 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 3686517206 + Number: 1 + Selection: IMAGE_COMDAT_SELECT_SAME_SIZE + - Name: mysymbol + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_EXTERNAL +... diff --git a/lld/test/COFF/comdat-gcc-compatibility-size.test b/lld/test/COFF/comdat-gcc-compatibility-size.test new file mode 100644 --- /dev/null +++ b/lld/test/COFF/comdat-gcc-compatibility-size.test @@ -0,0 +1,15 @@ +# RUN: yaml2obj %p/Inputs/comdat-llvm.yaml > %t.llvm.o +# RUN: yaml2obj %p/Inputs/comdat-binutils.yaml > %t.binutils.o +# RUN: lld-link -lldmingw -noentry -dll %t.llvm.o %t.binutils.o -out:%t.dll +# RUN: lld-link -lldmingw -noentry -dll %t.binutils.o %t.llvm.o -out:%t.dll +# RUN: not lld-link -noentry -dll %t.llvm.o %t.binutils.o -out:%t.dll +# RUN: not lld-link -noentry -dll %t.binutils.o %t.llvm.o -out:%t.dll + +# The test object files have been generated by assembling the following +# snippet using binutils and llvm. + +# .section .rdata$mysymbol, "dr" +# .linkonce same_size +# .globl mysymbol +#mysymbol: +# .byte 42