summaryrefslogtreecommitdiffstats
path: root/lld
diff options
context:
space:
mode:
Diffstat (limited to 'lld')
-rw-r--r--lld/include/lld/Core/Reference.h1
-rw-r--r--lld/include/lld/Core/Resolver.h1
-rw-r--r--lld/lib/Core/Resolver.cpp12
-rw-r--r--lld/lib/ReaderWriter/PECOFF/Atoms.h8
-rw-r--r--lld/lib/ReaderWriter/PECOFF/ReaderCOFF.cpp52
-rw-r--r--lld/lib/ReaderWriter/Reader.cpp1
-rw-r--r--lld/test/core/associates.objtxt30
-rw-r--r--lld/test/pecoff/Inputs/associative1.obj.yaml53
-rw-r--r--lld/test/pecoff/Inputs/associative3.obj.yaml33
-rw-r--r--lld/test/pecoff/associative.test10
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'
OpenPOWER on IntegriCloud