diff options
Diffstat (limited to 'lld')
-rw-r--r-- | lld/include/lld/Core/Reference.h | 1 | ||||
-rw-r--r-- | lld/include/lld/Core/Resolver.h | 1 | ||||
-rw-r--r-- | lld/lib/Core/Resolver.cpp | 12 | ||||
-rw-r--r-- | lld/lib/ReaderWriter/PECOFF/Atoms.h | 8 | ||||
-rw-r--r-- | lld/lib/ReaderWriter/PECOFF/ReaderCOFF.cpp | 52 | ||||
-rw-r--r-- | lld/lib/ReaderWriter/Reader.cpp | 1 | ||||
-rw-r--r-- | lld/test/core/associates.objtxt | 30 | ||||
-rw-r--r-- | lld/test/pecoff/Inputs/associative1.obj.yaml | 53 | ||||
-rw-r--r-- | lld/test/pecoff/Inputs/associative3.obj.yaml | 33 | ||||
-rw-r--r-- | lld/test/pecoff/associative.test | 10 |
10 files changed, 188 insertions, 13 deletions
diff --git a/lld/include/lld/Core/Reference.h b/lld/include/lld/Core/Reference.h index c5580efb39e..89b241399e8 100644 --- a/lld/include/lld/Core/Reference.h +++ b/lld/include/lld/Core/Reference.h @@ -91,6 +91,7 @@ public: 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 diff --git a/lld/include/lld/Core/Resolver.h b/lld/include/lld/Core/Resolver.h index 2cb2966a8d6..dadb231fbb0 100644 --- a/lld/include/lld/Core/Resolver.h +++ b/lld/include/lld/Core/Resolver.h @@ -105,6 +105,7 @@ private: std::vector<const Atom *> _atoms; std::set<const Atom *> _deadStripRoots; llvm::DenseSet<const Atom *> _liveAtoms; + llvm::DenseSet<const Atom *> _deadAtoms; std::unique_ptr<MergedFile> _result; llvm::DenseMap<const Atom *, llvm::DenseSet<const Atom *>> _reverseRef; }; diff --git a/lld/lib/Core/Resolver.cpp b/lld/lib/Core/Resolver.cpp index 3400901242b..ba1f67cc8e7 100644 --- a/lld/lib/Core/Resolver.cpp +++ b/lld/lib/Core/Resolver.cpp @@ -277,6 +277,16 @@ void Resolver::updateReferences() { for (const Atom *atom : _atoms) { if (const DefinedAtom *defAtom = dyn_cast<DefinedAtom>(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<Reference *>(ref)->setTarget(newTarget); } @@ -399,7 +409,7 @@ bool Resolver::checkUndefines() { 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()); } diff --git a/lld/lib/ReaderWriter/PECOFF/Atoms.h b/lld/lib/ReaderWriter/PECOFF/Atoms.h index 16aea4f00eb..4288f7a75bd 100644 --- a/lld/lib/ReaderWriter/PECOFF/Atoms.h +++ b/lld/lib/ReaderWriter/PECOFF/Atoms.h @@ -158,7 +158,6 @@ public: } 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 @@ public: 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<COFFReference>(ref)); + } + private: StringRef _sectionName; Scope _scope; diff --git a/lld/lib/ReaderWriter/PECOFF/ReaderCOFF.cpp b/lld/lib/ReaderWriter/PECOFF/ReaderCOFF.cpp index 397092f67c6..c20782f4407 100644 --- a/lld/lib/ReaderWriter/PECOFF/ReaderCOFF.cpp +++ b/lld/lib/ReaderWriter/PECOFF/ReaderCOFF.cpp @@ -174,6 +174,9 @@ private: // A map to get whether the section allows its contents to be merged or not. std::map<const coff_section *, DefinedAtom::Merge> _merge; + // COMDAT associative sections + std::map<const coff_section *, std::set<const coff_section *>> _association; + // A sorted map to find an atom from a section and an offset within // the section. std::map<const coff_section *, @@ -544,6 +547,7 @@ std::error_code FileCOFF::cacheSectionAttributes() { // section. It feels to me that it's unnecessarily complicated, but this is // how COFF works. for (auto i : _auxSymbol) { + // Read a section from the file const coff_symbol *sym = i.first; if (sym->SectionNumber == llvm::COFF::IMAGE_SYM_ABSOLUTE || sym->SectionNumber == llvm::COFF::IMAGE_SYM_UNDEFINED) @@ -552,19 +556,22 @@ std::error_code FileCOFF::cacheSectionAttributes() { 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<const coff_aux_section_definition *>(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 @@ std::error_code FileCOFF::AtomizeDefinedSymbols( 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<const coff_section *> &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(); } diff --git a/lld/lib/ReaderWriter/Reader.cpp b/lld/lib/ReaderWriter/Reader.cpp index 5bb261dfac1..f7077199c0b 100644 --- a/lld/lib/ReaderWriter/Reader.cpp +++ b/lld/lib/ReaderWriter/Reader.cpp @@ -51,6 +51,7 @@ static const Registry::KindStrings kindStrings[] = { {Reference::kindLayoutAfter, "layout-after"}, {Reference::kindLayoutBefore, "layout-before"}, {Reference::kindGroupChild, "group-child"}, + {Reference::kindAssociate, "associate"}, LLD_KIND_STRING_END}; Registry::Registry() { diff --git a/lld/test/core/associates.objtxt b/lld/test/core/associates.objtxt new file mode 100644 index 00000000000..bf780693ab7 --- /dev/null +++ b/lld/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 diff --git a/lld/test/pecoff/Inputs/associative1.obj.yaml b/lld/test/pecoff/Inputs/associative1.obj.yaml new file mode 100644 index 00000000000..51a7be0b34d --- /dev/null +++ b/lld/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 +... diff --git a/lld/test/pecoff/Inputs/associative3.obj.yaml b/lld/test/pecoff/Inputs/associative3.obj.yaml new file mode 100644 index 00000000000..ffea761a357 --- /dev/null +++ b/lld/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 +... diff --git a/lld/test/pecoff/associative.test b/lld/test/pecoff/associative.test new file mode 100644 index 00000000000..f998befd007 --- /dev/null +++ b/lld/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' |