diff options
-rw-r--r-- | lld/include/lld/Core/DefinedAtom.h | 9 | ||||
-rw-r--r-- | lld/include/lld/Core/Resolver.h | 4 | ||||
-rw-r--r-- | lld/lib/Core/DefinedAtom.cpp | 1 | ||||
-rw-r--r-- | lld/lib/Core/Resolver.cpp | 32 | ||||
-rw-r--r-- | lld/lib/ReaderWriter/Native/WriterNative.cpp | 2 | ||||
-rw-r--r-- | lld/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp | 5 | ||||
-rw-r--r-- | lld/test/core/gnulinkonce-rearrange-resolve.objtxt | 115 | ||||
-rw-r--r-- | lld/test/core/gnulinkonce-remaining-undef.objtxt | 113 | ||||
-rw-r--r-- | lld/test/core/gnulinkonce-resolve.objtxt | 133 | ||||
-rw-r--r-- | lld/test/core/gnulinkonce-simple.objtxt | 112 | ||||
-rw-r--r-- | lld/test/core/sectiongroup-gnulinkonce-error.objtxt | 88 |
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 + |