Index: lld/trunk/include/lld/Core/Reference.h =================================================================== --- lld/trunk/include/lld/Core/Reference.h +++ lld/trunk/include/lld/Core/Reference.h @@ -91,6 +91,8 @@ kindLayoutBefore = 3, // kindGroupChild is treated as a bidirected edge too. kindGroupChild = 4, + // kindAssociate prevents a referenced atom from being dead-stripped. + kindAssociate = 5, }; // A value to be added to the value of a target Index: lld/trunk/lib/ReaderWriter/PECOFF/Atoms.h =================================================================== --- lld/trunk/lib/ReaderWriter/PECOFF/Atoms.h +++ lld/trunk/lib/ReaderWriter/PECOFF/Atoms.h @@ -167,6 +167,13 @@ uint64_t ordinal() const override { return _ordinal; } Alignment alignment() const override { return _alignment; } + void associate(COFFDefinedFileAtom *other) { + auto *r = new COFFReference(other, 0, Reference::kindAssociate, + Reference::KindNamespace::all, + Reference::KindArch::all); + addReference(std::unique_ptr(r)); + } + private: StringRef _sectionName; Scope _scope; Index: lld/trunk/lib/ReaderWriter/PECOFF/ReaderCOFF.cpp =================================================================== --- lld/trunk/lib/ReaderWriter/PECOFF/ReaderCOFF.cpp +++ lld/trunk/lib/ReaderWriter/PECOFF/ReaderCOFF.cpp @@ -172,6 +172,9 @@ // A map to get whether the section allows its contents to be merged or not. std::map _merge; + // COMDAT associative sections + std::map> _association; + // A sorted map to find an atom from a section and an offset within // the section. std::mapSectionNumber == llvm::COFF::IMAGE_SYM_ABSOLUTE || sym->SectionNumber == llvm::COFF::IMAGE_SYM_UNDEFINED) @@ -548,19 +552,22 @@ const coff_section *sec; if (error_code ec = _obj->getSection(sym->SectionNumber, sec)) return ec; + const coff_aux_section_definition *aux = + reinterpret_cast(i.second); - if (_merge.count(sec)) - continue; - if (!(sec->Characteristics & llvm::COFF::IMAGE_SCN_LNK_COMDAT)) - continue; - - _comdatSections.insert(sec); + if (sec->Characteristics & llvm::COFF::IMAGE_SCN_LNK_COMDAT) { + // Read aux symbol data. + _comdatSections.insert(sec); + _merge[sec] = getMerge(aux); + } - if (sym->NumberOfAuxSymbols == 0) - return llvm::object::object_error::parse_failed; - const coff_aux_section_definition *aux = - reinterpret_cast(i.second); - _merge[sec] = getMerge(aux); + // Handle associative sections. + if (aux->Selection == llvm::COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE) { + const coff_section *parent; + if (error_code ec = _obj->getSection(aux->Number, parent)) + return ec; + _association[parent].insert(sec); + } } // The sections that does not have auxiliary symbol are regular sections, in @@ -694,6 +701,28 @@ definedAtoms.push_back(atom); } } + + // A COMDAT section with SELECT_ASSOCIATIVE attribute refer to other + // section. They need to be linked to a binary or dead stripped as a group. + // Here We add a kindAssociate edge between them, so that if a target section + // is linked, the other is also linked. + // + // In a typical use case, parent is a comdat BSS section, and a child is a + // static initializer for the data. + for (auto i : _association) { + const coff_section *parent = i.first; + const std::set &childSections = i.second; + assert(_sectionAtoms[parent].size() > 0); + + COFFDefinedFileAtom *p = _sectionAtoms[parent][0]; + for (const coff_section *sec : childSections) { + if (_sectionAtoms.count(sec)) { + assert(_sectionAtoms[sec].size() > 0); + p->associate(_sectionAtoms[sec][0]); + } + } + } + return error_code(); } Index: lld/trunk/lib/ReaderWriter/Reader.cpp =================================================================== --- lld/trunk/lib/ReaderWriter/Reader.cpp +++ lld/trunk/lib/ReaderWriter/Reader.cpp @@ -52,6 +52,7 @@ {Reference::kindLayoutAfter, "layout-after"}, {Reference::kindLayoutBefore, "layout-before"}, {Reference::kindGroupChild, "group-child"}, + {Reference::kindAssociate, "associate"}, LLD_KIND_STRING_END}; Registry::Registry() { Index: lld/trunk/test/pecoff/Inputs/associative1.obj.yaml =================================================================== --- lld/trunk/test/pecoff/Inputs/associative1.obj.yaml +++ lld/trunk/test/pecoff/Inputs/associative1.obj.yaml @@ -0,0 +1,53 @@ +--- +header: + Machine: IMAGE_FILE_MACHINE_I386 + Characteristics: [] +sections: + - Name: .data + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ] + Alignment: 4 + SectionData: 00000000 + - Name: '.CRT$XCU' + Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] + Alignment: 4 + SectionData: 77777777 +symbols: + - Name: .data + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 4 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 0 + Number: 0 + Selection: IMAGE_COMDAT_SELECT_ANY + - Name: _var + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_EXTERNAL + - Name: '.CRT$XCU' + Value: 0 + SectionNumber: 2 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 4 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 0 + Number: 1 + Selection: IMAGE_COMDAT_SELECT_ASSOCIATIVE + - Name: _init + Value: 0 + SectionNumber: 2 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_EXTERNAL +... Index: lld/trunk/test/pecoff/Inputs/associative3.obj.yaml =================================================================== --- lld/trunk/test/pecoff/Inputs/associative3.obj.yaml +++ lld/trunk/test/pecoff/Inputs/associative3.obj.yaml @@ -0,0 +1,33 @@ +--- +header: + Machine: IMAGE_FILE_MACHINE_I386 + Characteristics: [] +sections: + - Name: .text + Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] + Alignment: 4 + SectionData: 0000000000000000 + Relocations: + - VirtualAddress: 4 + SymbolName: _var + Type: IMAGE_REL_I386_DIR32 +symbols: + - Name: .text + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + - Name: _main + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_EXTERNAL + - Name: _var + Value: 0 + SectionNumber: 0 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_EXTERNAL +... Index: lld/trunk/test/pecoff/associative.test =================================================================== --- lld/trunk/test/pecoff/associative.test +++ lld/trunk/test/pecoff/associative.test @@ -0,0 +1,10 @@ +# RUN: yaml2obj %p/Inputs/associative1.obj.yaml > %t1.obj +# RUN: yaml2obj %p/Inputs/associative1.obj.yaml > %t2.obj +# RUN: yaml2obj %p/Inputs/associative3.obj.yaml > %t3.obj +# +# RUN: lld -flavor link /machine:x86 /subsystem:console /entry:main \ +# RUN: /out:%t.exe -- %t1.obj %t2.obj %t3.obj +# RUN: obj2yaml %t.exe | FileCheck %s + +CHECK: - Name: .CRT +CHECK: SectionData: '77777777'