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,7 @@ kindLayoutBefore = 3, // kindGroupChild is treated as a bidirected edge too. kindGroupChild = 4, + kindAssociate = 5, }; // A value to be added to the value of a target Index: lld/trunk/include/lld/Core/Resolver.h =================================================================== --- lld/trunk/include/lld/Core/Resolver.h +++ lld/trunk/include/lld/Core/Resolver.h @@ -105,6 +105,7 @@ std::vector _atoms; std::set _deadStripRoots; llvm::DenseSet _liveAtoms; + llvm::DenseSet _deadAtoms; std::unique_ptr _result; llvm::DenseMap> _reverseRef; }; Index: lld/trunk/lib/Core/Resolver.cpp =================================================================== --- lld/trunk/lib/Core/Resolver.cpp +++ lld/trunk/lib/Core/Resolver.cpp @@ -277,6 +277,16 @@ for (const Atom *atom : _atoms) { if (const DefinedAtom *defAtom = dyn_cast(atom)) { for (const Reference *ref : *defAtom) { + // A reference of type kindAssociate should't be updated. + // Instead, an atom having such reference will be removed + // if the target atom is coalesced away, so that they will + // go away as a group. + if (ref->kindNamespace() == lld::Reference::KindNamespace::all && + ref->kindValue() == lld::Reference::kindAssociate) { + if (_symbolTable.isCoalescedAway(atom)) + _deadAtoms.insert(ref->target()); + continue; + } const Atom *newTarget = _symbolTable.replacement(ref->target()); const_cast(ref)->setTarget(newTarget); } @@ -399,7 +409,7 @@ void Resolver::removeCoalescedAwayAtoms() { ScopedTask task(getDefaultDomain(), "removeCoalescedAwayAtoms"); _atoms.erase(std::remove_if(_atoms.begin(), _atoms.end(), [&](const Atom *a) { - return _symbolTable.isCoalescedAway(a); + return _symbolTable.isCoalescedAway(a) || _deadAtoms.count(a); }), _atoms.end()); } Index: lld/trunk/lib/ReaderWriter/PECOFF/Atoms.h =================================================================== --- lld/trunk/lib/ReaderWriter/PECOFF/Atoms.h +++ lld/trunk/lib/ReaderWriter/PECOFF/Atoms.h @@ -158,7 +158,6 @@ } void setAlignment(Alignment val) { _alignment = val; } - SectionChoice sectionChoice() const override { return sectionCustomRequired; } StringRef customSectionName() const override { return _sectionName; } Scope scope() const override { return _scope; } @@ -167,6 +166,13 @@ uint64_t ordinal() const override { return _ordinal; } Alignment alignment() const override { return _alignment; } + void addAssociate(const DefinedAtom *other) { + auto *ref = new COFFReference(other, 0, lld::Reference::kindAssociate, + Reference::KindNamespace::all, + Reference::KindArch::all); + addReference(std::unique_ptr(ref)); + } + 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 @@ -174,6 +174,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) @@ -552,19 +556,22 @@ const coff_section *sec; if (std::error_code ec = _obj->getSection(sym->SectionNumber, sec)) return ec; - - if (_merge.count(sec)) - continue; - if (!(sec->Characteristics & llvm::COFF::IMAGE_SCN_LNK_COMDAT)) - continue; - - _comdatSections.insert(sec); - - 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); + + if (sec->Characteristics & llvm::COFF::IMAGE_SCN_LNK_COMDAT) { + // Read aux symbol data. + _comdatSections.insert(sec); + _merge[sec] = getMerge(aux); + } + + // Handle associative sections. + if (aux->Selection == llvm::COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE) { + const coff_section *parent; + if (std::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 @@ -699,6 +706,29 @@ definedAtoms.push_back(atom); } } + + // A COMDAT section with SELECT_ASSOCIATIVE attribute refer to other + // section. If the referred section is linked to a binary, the + // referring section needs to be linked too. A typical use case of + // this attribute is a static initializer; a parent is a comdat BSS + // section, and a child is a static initializer code for the data. + // + // We add referring section contents to the referred section's + // associate list, so that Resolver takes care of them. + 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->addAssociate(_sectionAtoms[sec][0]); + } + } + } + return std::error_code(); } Index: lld/trunk/lib/ReaderWriter/Reader.cpp =================================================================== --- lld/trunk/lib/ReaderWriter/Reader.cpp +++ lld/trunk/lib/ReaderWriter/Reader.cpp @@ -51,6 +51,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/core/associates.objtxt =================================================================== --- lld/trunk/test/core/associates.objtxt +++ lld/trunk/test/core/associates.objtxt @@ -0,0 +1,30 @@ +# RUN: lld -core %s | FileCheck %s + +--- +defined-atoms: + - name: f1 + merge: as-weak + scope: global + references: + - kind: associate + target: f2 + - name: f2 +--- +defined-atoms: + - name: f1 + merge: as-weak + scope: global + references: + - kind: associate + target: f2 + - name: f2 +... + +# CHECK: defined-atoms: +# CHECK: - name: f1 +# CHECK: scope: global +# CHECK: references: +# CHECK: - kind: associate +# CHECK: target: f2 +# CHECK: - name: f2 +# CHECK-NOT: - name: f2 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'