summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lld/include/lld/Core/DefinedAtom.h9
-rw-r--r--lld/include/lld/Core/Resolver.h4
-rw-r--r--lld/lib/Core/DefinedAtom.cpp1
-rw-r--r--lld/lib/Core/Resolver.cpp32
-rw-r--r--lld/lib/ReaderWriter/Native/WriterNative.cpp2
-rw-r--r--lld/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp5
-rw-r--r--lld/test/core/gnulinkonce-rearrange-resolve.objtxt115
-rw-r--r--lld/test/core/gnulinkonce-remaining-undef.objtxt113
-rw-r--r--lld/test/core/gnulinkonce-resolve.objtxt133
-rw-r--r--lld/test/core/gnulinkonce-simple.objtxt112
-rw-r--r--lld/test/core/sectiongroup-gnulinkonce-error.objtxt88
11 files changed, 603 insertions, 11 deletions
diff --git a/lld/include/lld/Core/DefinedAtom.h b/lld/include/lld/Core/DefinedAtom.h
index de325ada4b8..3e340eb4504 100644
--- a/lld/include/lld/Core/DefinedAtom.h
+++ b/lld/include/lld/Core/DefinedAtom.h
@@ -147,6 +147,7 @@ public:
typeRWNote, // Identifies readwrite note sections [ELF]
typeNoAlloc, // Identifies non allocatable sections [ELF]
typeGroupComdat, // Identifies a section group [ELF, COFF]
+ typeGnuLinkOnce, // Identifies a gnu.linkonce section [ELF]
};
// Permission bits for atoms and segments. The order of these values are
@@ -330,6 +331,14 @@ public:
atomContentType == DefinedAtom::typeThreadZeroFill);
}
+ /// Utility function to check if the atom belongs to a group section
+ /// that represents section groups or .gnu.linkonce sections.
+ bool isGroupParent() const {
+ ContentType atomContentType = contentType();
+ return (atomContentType == DefinedAtom::typeGroupComdat ||
+ atomContentType == DefinedAtom::typeGnuLinkOnce);
+ }
+
protected:
// DefinedAtom is an abstract base class. Only subclasses can access
// constructor.
diff --git a/lld/include/lld/Core/Resolver.h b/lld/include/lld/Core/Resolver.h
index 006ed6e0e79..b6d8185b3cd 100644
--- a/lld/include/lld/Core/Resolver.h
+++ b/lld/include/lld/Core/Resolver.h
@@ -67,8 +67,8 @@ public:
private:
typedef std::function<void(StringRef, bool)> UndefCallback;
- /// \brief Add section group if it does not exist previously.
- void maybeAddSectionGroup(const DefinedAtom &atom);
+ /// \brief Add section group/.gnu.linkonce if it does not exist previously.
+ bool maybeAddSectionGroupOrGnuLinkOnce(const DefinedAtom &atom);
/// \brief The main function that iterates over the files to resolve
bool resolveUndefines();
diff --git a/lld/lib/Core/DefinedAtom.cpp b/lld/lib/Core/DefinedAtom.cpp
index 8362aadb21c..806bd6f4521 100644
--- a/lld/lib/Core/DefinedAtom.cpp
+++ b/lld/lib/Core/DefinedAtom.cpp
@@ -72,6 +72,7 @@ DefinedAtom::ContentPermissions DefinedAtom::permissions(ContentType type) {
return permRW_L;
case typeGroupComdat:
+ case typeGnuLinkOnce:
case typeUnknown:
case typeTempLTO:
return permUnknown;
diff --git a/lld/lib/Core/Resolver.cpp b/lld/lib/Core/Resolver.cpp
index 9555fef22ba..f8bcfbc8b6e 100644
--- a/lld/lib/Core/Resolver.cpp
+++ b/lld/lib/Core/Resolver.cpp
@@ -184,11 +184,24 @@ void Resolver::doUndefinedAtom(const UndefinedAtom &atom) {
}
/// \brief Add the section group and the group-child reference members.
-void Resolver::maybeAddSectionGroup(const DefinedAtom &atom) {
+bool Resolver::maybeAddSectionGroupOrGnuLinkOnce(const DefinedAtom &atom) {
// First time adding a group ?
bool isFirstTime = _symbolTable.addGroup(atom);
- if (!isFirstTime)
- return;
+
+ if (!isFirstTime) {
+ // If duplicate symbols are allowed, select the first group.
+ if (_context.getAllowDuplicates())
+ return true;
+ const DefinedAtom *prevGroup =
+ llvm::dyn_cast<DefinedAtom>(_symbolTable.findGroup(atom.name()));
+ assert(prevGroup &&
+ "Internal Error: The group atom could only be a defined atom");
+ // The atoms should be of the same content type, reject invalid group
+ // resolution behaviors.
+ if (atom.contentType() != prevGroup->contentType())
+ return false;
+ return true;
+ }
for (const Reference *r : atom) {
if ((r->kindNamespace() == lld::Reference::KindNamespace::all) &&
@@ -200,6 +213,7 @@ void Resolver::maybeAddSectionGroup(const DefinedAtom &atom) {
_symbolTable.add(*target);
}
}
+ return true;
}
// called on each atom when a file is added
@@ -229,10 +243,16 @@ void Resolver::doDefinedAtom(const DefinedAtom &atom) {
// add to list of known atoms
_atoms.push_back(&atom);
- if (atom.contentType() == DefinedAtom::typeGroupComdat)
- maybeAddSectionGroup(atom);
- else
+ if (atom.isGroupParent()) {
+ // Raise error if there exists a similar gnu linkonce section.
+ if (!maybeAddSectionGroupOrGnuLinkOnce(atom)) {
+ llvm::errs() << "SymbolTable: error while merging " << atom.name()
+ << "\n";
+ llvm::report_fatal_error("duplicate symbol error");
+ }
+ } else {
_symbolTable.add(atom);
+ }
if (_context.deadStrip()) {
// add to set of dead-strip-roots, all symbols that
diff --git a/lld/lib/ReaderWriter/Native/WriterNative.cpp b/lld/lib/ReaderWriter/Native/WriterNative.cpp
index 9735783b0a9..c8c49ad4003 100644
--- a/lld/lib/ReaderWriter/Native/WriterNative.cpp
+++ b/lld/lib/ReaderWriter/Native/WriterNative.cpp
@@ -41,7 +41,7 @@ public:
// We are trying to process all atoms, but the defined() iterator does not
// return group children. So, when a group parent is found, we need to
// handle each child atom.
- if (defAtom->contentType() == DefinedAtom::typeGroupComdat) {
+ if (defAtom->isGroupParent()) {
for (const Reference *r : *defAtom) {
if (r->kindNamespace() != lld::Reference::KindNamespace::all)
continue;
diff --git a/lld/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp b/lld/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp
index 49de7f551cf..9056b409d76 100644
--- a/lld/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp
+++ b/lld/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp
@@ -71,7 +71,7 @@ public:
if (!atom->name().empty())
buildDuplicateNameMap(*atom);
- if (atom->contentType() == DefinedAtom::typeGroupComdat) {
+ if (atom->isGroupParent()) {
for (const lld::Reference *ref : *atom) {
if (ref->kindNamespace() != lld::Reference::KindNamespace::all)
continue;
@@ -229,7 +229,7 @@ private:
}
if (const lld::DefinedAtom *da = dyn_cast<DefinedAtom>(atom)) {
- if (da->contentType() == DefinedAtom::typeGroupComdat) {
+ if (da->isGroupParent()) {
if (_groupMap.count(name)) {
_io.setError(Twine("duplicate group name: ") + name);
} else {
@@ -477,6 +477,7 @@ template <> struct ScalarEnumerationTraits<lld::DefinedAtom::ContentType> {
io.enumCase(value, "rw-note", DefinedAtom::typeRWNote);
io.enumCase(value, "no-alloc", DefinedAtom::typeNoAlloc);
io.enumCase(value, "group-comdat", DefinedAtom::typeGroupComdat);
+ io.enumCase(value, "gnu-linkonce", DefinedAtom::typeGnuLinkOnce);
}
};
diff --git a/lld/test/core/gnulinkonce-rearrange-resolve.objtxt b/lld/test/core/gnulinkonce-rearrange-resolve.objtxt
new file mode 100644
index 00000000000..dbcc95591a9
--- /dev/null
+++ b/lld/test/core/gnulinkonce-rearrange-resolve.objtxt
@@ -0,0 +1,115 @@
+# RUN: lld -core %s | FileCheck %s
+
+#
+# Test that gnu linkonce sections are parsed and the first section selected for symbol
+# resolution
+#
+
+---
+defined-atoms:
+ - name: g1
+ scope: global
+ type: gnu-linkonce
+ references:
+ - kind: group-child
+ target: f1
+ - kind: group-child
+ target: f2
+ - kind: group-child
+ target: g1
+ - kind: group-child
+ target: d1
+ - name: f1
+ scope: global
+ type: code
+ references:
+ - kind: group-parent
+ target: g1
+ - name: f2
+ scope: global
+ type: code
+ references:
+ - kind: group-parent
+ target: g1
+ - name: g1
+ scope: global
+ type: code
+ references:
+ - kind: group-parent
+ target: g1
+ - name: d1
+ scope: global
+ type: data
+ references:
+ - kind: group-parent
+ target: g1
+---
+defined-atoms:
+ - name: g1
+ scope: global
+ type: gnu-linkonce
+ references:
+ - kind: group-child
+ target: f1
+ - kind: group-child
+ target: f2
+ - kind: group-child
+ target: g1
+ - kind: group-child
+ target: d1
+ - name: f1
+ scope: global
+ type: code
+ references:
+ - kind: group-parent
+ target: g1
+ - name: f2
+ scope: global
+ type: code
+ references:
+ - kind: group-parent
+ target: g1
+ - name: g1
+ scope: global
+ type: code
+ references:
+ - kind: group-parent
+ target: g1
+ - name: d1
+ scope: global
+ type: data
+ references:
+ - kind: group-parent
+ target: g1
+...
+
+# CHECK: defined-atoms:
+# CHECK: - name: g1
+# CHECK: ref-name: [[PARENT:[a-zA-Z\.0-9_]+]]
+# CHECK: type: gnu-linkonce
+# CHECK: references:
+# CHECK: - kind: group-child
+# CHECK: target: f1
+# CHECK: - kind: group-child
+# CHECK: target: f2
+# CHECK: - kind: group-child
+# CHECK: target: [[CHILD:[a-zA-Z\.0-9_]+]]
+# CHECK: - kind: group-child
+# CHECK: target: d1
+# CHECK: - name: f1
+# CHECK: references:
+# CHECK: - kind: group-parent
+# CHECK: target: [[PARENT]]
+# CHECK: - name: f2
+# CHECK: references:
+# CHECK: - kind: group-parent
+# CHECK: target: [[PARENT]]
+# CHECK: - name: g1
+# CHECK: ref-name: [[CHILD]]
+# CHECK: references:
+# CHECK: - kind: group-parent
+# CHECK: target: [[PARENT]]
+# CHECK: - name: d1
+# CHECK: references:
+# CHECK: - kind: group-parent
+# CHECK: target: [[PARENT]]
diff --git a/lld/test/core/gnulinkonce-remaining-undef.objtxt b/lld/test/core/gnulinkonce-remaining-undef.objtxt
new file mode 100644
index 00000000000..ee5f681ac02
--- /dev/null
+++ b/lld/test/core/gnulinkonce-remaining-undef.objtxt
@@ -0,0 +1,113 @@
+# RUN: lld -core %s | FileCheck %s
+
+#
+# Test that gnu linkonce sections are parsed and the first section selected for
+# symbol resolution. The second file which has the same gnu linkonce section has
+# a unresolved undefined symbol. lets make sure that the symbol is kept around
+# in the final link and remains undefined.
+#
+
+---
+defined-atoms:
+ - name: f1
+ scope: global
+ type: code
+ references:
+ - kind: group-parent
+ target: g1
+ - name: f2
+ scope: global
+ type: code
+ references:
+ - kind: group-parent
+ target: g1
+ - name: g1
+ scope: global
+ type: code
+ references:
+ - kind: group-parent
+ target: g1
+ - name: d1
+ scope: global
+ type: data
+ references:
+ - kind: group-parent
+ target: g1
+ - name: g1
+ scope: global
+ type: gnu-linkonce
+ references:
+ - kind: group-child
+ target: f1
+ - kind: group-child
+ target: f2
+ - kind: group-child
+ target: g1
+ - kind: group-child
+ target: d1
+---
+defined-atoms:
+ - name: anotherfunction
+ scope: global
+ type: data
+ references:
+ - kind: layout-before
+ target: f3
+ - name: f1
+ scope: global
+ type: code
+ references:
+ - kind: group-parent
+ target: g1
+ - name: f2
+ scope: global
+ type: code
+ references:
+ - kind: group-parent
+ target: g1
+ - name: f3
+ scope: global
+ type: code
+ references:
+ - kind: group-parent
+ target: g1
+ - name: g1
+ scope: global
+ type: code
+ references:
+ - kind: group-parent
+ target: g1
+ - name: d1
+ scope: global
+ type: data
+ references:
+ - kind: group-parent
+ target: g1
+ - name: g1
+ scope: global
+ type: gnu-linkonce
+ references:
+ - kind: group-child
+ target: f1
+ - kind: group-child
+ target: f2
+ - kind: group-child
+ target: f3
+ - kind: group-child
+ target: g1
+ - kind: group-child
+ target: d1
+undefined-atoms:
+ - name: f3
+ can-be-null: never
+...
+
+#CHECK: - name: anotherfunction
+#CHECK: scope: global
+#CHECK: type: data
+#CHECK: references:
+#CHECK: - kind: layout-before
+#CHECK: offset: 0
+#CHECK: target: f3
+#CHECK: undefined-atoms:
+#CHECK: - name: f3
diff --git a/lld/test/core/gnulinkonce-resolve.objtxt b/lld/test/core/gnulinkonce-resolve.objtxt
new file mode 100644
index 00000000000..ff099a5ba9d
--- /dev/null
+++ b/lld/test/core/gnulinkonce-resolve.objtxt
@@ -0,0 +1,133 @@
+# RUN: lld -core %s | FileCheck %s
+
+#
+# Test that gnu linkonce sections are parsed and the first section selected for symbol
+# resolution
+#
+
+---
+defined-atoms:
+ - name: f1
+ scope: global
+ type: code
+ references:
+ - kind: group-parent
+ target: g1
+ - name: f2
+ scope: global
+ type: code
+ references:
+ - kind: group-parent
+ target: g1
+ - name: g1
+ scope: global
+ type: code
+ references:
+ - kind: group-parent
+ target: g1
+ - name: d1
+ scope: global
+ type: data
+ references:
+ - kind: group-parent
+ target: g1
+ - name: g1
+ scope: global
+ type: gnu-linkonce
+ references:
+ - kind: group-child
+ target: f1
+ - kind: group-child
+ target: f2
+ - kind: group-child
+ target: g1
+ - kind: group-child
+ target: d1
+---
+defined-atoms:
+ - name: f1
+ scope: global
+ type: code
+ references:
+ - kind: group-parent
+ target: g1
+ - name: f2
+ scope: global
+ type: code
+ references:
+ - kind: group-parent
+ target: g1
+ - name: g1
+ scope: global
+ type: code
+ references:
+ - kind: group-parent
+ target: g1
+ - name: d1
+ scope: global
+ type: data
+ references:
+ - kind: group-parent
+ target: g1
+ - name: g1
+ scope: global
+ type: gnu-linkonce
+ references:
+ - kind: group-child
+ target: f1
+ - kind: group-child
+ target: f2
+ - kind: group-child
+ target: g1
+ - kind: group-child
+ target: d1
+...
+
+#CHECK: defined-atoms:
+#CHECK: - name: g1
+#CHECK: ref-name: [[PARENT:[a-zA-Z\.0-9_]+]]
+#CHECK: scope: global
+#CHECK: type: gnu-linkonce
+#CHECK: references:
+#CHECK: - kind: group-child
+#CHECK: offset: 0
+#CHECK: target: [[GCHILDONE:[a-zA-Z\.0-9_]+]]
+#CHECK: - kind: group-child
+#CHECK: offset: 0
+#CHECK: target: [[GCHILDTWO:[a-zA-Z\.0-9_]+]]
+#CHECK: - kind: group-child
+#CHECK: offset: 0
+#CHECK: target: [[GCHILDTHREE:[a-zA-Z\.0-9_]+]]
+#CHECK: - kind: group-child
+#CHECK: offset: 0
+#CHECK: target: [[GCHILDFOUR:[a-zA-Z\.0-9_]+]]
+#CHECK: - name: f1
+#CHECK: ref-name: [[GCHILDONE]]
+#CHECK: scope: global
+#CHECK: references:
+#CHECK: - kind: group-parent
+#CHECK: offset: 0
+#CHECK: target: [[PARENT]]
+#CHECK: - name: f2
+#CHECK: ref-name: [[GCHILDTWO]]
+#CHECK: scope: global
+#CHECK: references:
+#CHECK: - kind: group-parent
+#CHECK: offset: 0
+#CHECK: target: [[PARENT]]
+#CHECK: - name: g1
+#CHECK: ref-name: [[GCHILDTHREE]]
+#CHECK: scope: global
+#CHECK: references:
+#CHECK: - kind: group-parent
+#CHECK: offset: 0
+#CHECK: target: [[PARENT]]
+#CHECK: - name: d1
+#CHECK: ref-name: [[GCHILDFOUR]]
+#CHECK: scope: global
+#CHECK: type: data
+#CHECK: references:
+#CHECK: - kind: group-parent
+#CHECK: offset: 0
+#CHECK: target: [[PARENT]]
+#CHECK: ...
diff --git a/lld/test/core/gnulinkonce-simple.objtxt b/lld/test/core/gnulinkonce-simple.objtxt
new file mode 100644
index 00000000000..1a96b62669b
--- /dev/null
+++ b/lld/test/core/gnulinkonce-simple.objtxt
@@ -0,0 +1,112 @@
+# RUN: lld -core %s | FileCheck %s
+
+#
+# Test that gnu linkonce sections are parsed properly when there is a reference to a
+# atom from outside the gnu linkonce section.
+#
+
+---
+defined-atoms:
+ - name: f1
+ scope: global
+ type: code
+ references:
+ - kind: group-parent
+ target: g1
+ - name: f2
+ scope: global
+ type: code
+ references:
+ - kind: group-parent
+ target: g1
+ - name: g1
+ scope: global
+ type: code
+ references:
+ - kind: group-parent
+ target: g1
+ - name: d1
+ scope: global
+ type: data
+ references:
+ - kind: group-parent
+ target: g1
+ - name: g1
+ scope: global
+ type: gnu-linkonce
+ references:
+ - kind: group-child
+ target: f1
+ - kind: group-child
+ target: f2
+ - kind: group-child
+ target: d1
+ - kind: group-child
+ target: g1
+ - name: anotherfunction
+ scope: global
+ type: data
+ references:
+ - kind: layout-before
+ target: f1
+
+undefined-atoms:
+ - name: f1
+ can-be-null: never
+...
+
+#CHECK: defined-atoms:
+#CHECK: - name: g1
+#CHECK: ref-name: [[PARENT:[a-zA-Z\.0-9_]+]]
+#CHECK: scope: global
+#CHECK: type: gnu-linkonce
+#CHECK: references:
+#CHECK: - kind: group-child
+#CHECK: offset: 0
+#CHECK: target: [[GCHILDONE:[a-zA-Z\.0-9_]+]]
+#CHECK: - kind: group-child
+#CHECK: offset: 0
+#CHECK: target: [[GCHILDTWO:[a-zA-Z\.0-9_]+]]
+#CHECK: - kind: group-child
+#CHECK: offset: 0
+#CHECK: target: [[GCHILDTHREE:[a-zA-Z\.0-9_]+]]
+#CHECK: - kind: group-child
+#CHECK: offset: 0
+#CHECK: target: [[GCHILDFOUR:[a-zA-Z\.0-9_]+]]
+#CHECK: - name: f1
+#CHECK: ref-name: [[GCHILDONE]]
+#CHECK: scope: global
+#CHECK: references:
+#CHECK: - kind: group-parent
+#CHECK: offset: 0
+#CHECK: target: [[PARENT]]
+#CHECK: - name: f2
+#CHECK: ref-name: [[GCHILDTWO]]
+#CHECK: scope: global
+#CHECK: references:
+#CHECK: - kind: group-parent
+#CHECK: offset: 0
+#CHECK: target: [[PARENT]]
+#CHECK: - name: d1
+#CHECK: ref-name: [[GCHILDTHREE]]
+#CHECK: scope: global
+#CHECK: type: data
+#CHECK: references:
+#CHECK: - kind: group-parent
+#CHECK: offset: 0
+#CHECK: target: [[PARENT]]
+#CHECK: - name: g1
+#CHECK: ref-name: [[GCHILDFOUR]]
+#CHECK: scope: global
+#CHECK: references:
+#CHECK: - kind: group-parent
+#CHECK: offset: 0
+#CHECK: target: [[PARENT]]
+#CHECK: - name: anotherfunction
+#CHECK: scope: global
+#CHECK: type: data
+#CHECK: references:
+#CHECK: - kind: layout-before
+#CHECK: offset: 0
+#CHECK: target: [[GCHILDONE]]
+#CHECK: ...
diff --git a/lld/test/core/sectiongroup-gnulinkonce-error.objtxt b/lld/test/core/sectiongroup-gnulinkonce-error.objtxt
new file mode 100644
index 00000000000..e54cdfe0571
--- /dev/null
+++ b/lld/test/core/sectiongroup-gnulinkonce-error.objtxt
@@ -0,0 +1,88 @@
+# RUN: not lld -core %s 2>&1 | FileCheck %s
+
+#
+# Test that section groups/gnu linkonce sections are parsed and a merge error
+# is displayed at the time of symbol resolution.
+#
+
+---
+defined-atoms:
+ - name: f1
+ scope: global
+ type: code
+ references:
+ - kind: group-parent
+ target: g1
+ - name: f2
+ scope: global
+ type: code
+ references:
+ - kind: group-parent
+ target: g1
+ - name: g1
+ scope: global
+ type: code
+ references:
+ - kind: group-parent
+ target: g1
+ - name: d1
+ scope: global
+ type: data
+ references:
+ - kind: group-parent
+ target: g1
+ - name: g1
+ scope: global
+ type: group-comdat
+ references:
+ - kind: group-child
+ target: f1
+ - kind: group-child
+ target: f2
+ - kind: group-child
+ target: g1
+ - kind: group-child
+ target: d1
+---
+defined-atoms:
+ - name: f1
+ scope: global
+ type: code
+ references:
+ - kind: group-parent
+ target: g1
+ - name: f2
+ scope: global
+ type: code
+ references:
+ - kind: group-parent
+ target: g1
+ - name: g1
+ scope: global
+ type: code
+ references:
+ - kind: group-parent
+ target: g1
+ - name: d1
+ scope: global
+ type: data
+ references:
+ - kind: group-parent
+ target: g1
+ - name: g1
+ scope: global
+ type: gnu-linkonce
+ references:
+ - kind: group-child
+ target: f1
+ - kind: group-child
+ target: f2
+ - kind: group-child
+ target: g1
+ - kind: group-child
+ target: d1
+...
+
+#CHECK: SymbolTable: error while merging g1
+#CHECK: LLVM ERROR: duplicate symbol error
+
OpenPOWER on IntegriCloud