diff options
| author | Shankar Easwaran <shankarke@gmail.com> | 2014-03-31 03:16:37 +0000 |
|---|---|---|
| committer | Shankar Easwaran <shankarke@gmail.com> | 2014-03-31 03:16:37 +0000 |
| commit | 79cfed55fc923b137a1a41702534b6830c4f5851 (patch) | |
| tree | 2517c558ff2a49c338922de8956ab30559ba881a /lld | |
| parent | 82ec13e3d56dc463a0bbd49d5922e3387119ab27 (diff) | |
| download | bcm5719-llvm-79cfed55fc923b137a1a41702534b6830c4f5851.tar.gz bcm5719-llvm-79cfed55fc923b137a1a41702534b6830c4f5851.zip | |
[core] support .gnu.linkonce sections
.gnu.linkonce sections are similar to section groups. They were supported before
section groups existed and provided a way to resolve COMDAT sections using a
different design. There are few implementations that use .gnu.linkonce sections
to store simple floating point constants which doesnot require complex section
group support but need a way to store only one copy of the floating point
constant. .gnu.linkonce based symbol resolution achieves that.
llvm-svn: 205163
Diffstat (limited to 'lld')
| -rw-r--r-- | lld/include/lld/Core/DefinedAtom.h | 1 | ||||
| -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 | 28 | ||||
| -rw-r--r-- | lld/lib/ReaderWriter/Native/WriterNative.cpp | 3 | ||||
| -rw-r--r-- | lld/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp | 10 | ||||
| -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, 597 insertions, 11 deletions
diff --git a/lld/include/lld/Core/DefinedAtom.h b/lld/include/lld/Core/DefinedAtom.h index de325ada4b8..b911d2323b1 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 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..6ff898726b3 100644 --- a/lld/lib/Core/Resolver.cpp +++ b/lld/lib/Core/Resolver.cpp @@ -184,11 +184,22 @@ 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 +211,7 @@ void Resolver::maybeAddSectionGroup(const DefinedAtom &atom) { _symbolTable.add(*target); } } + return true; } // called on each atom when a file is added @@ -229,8 +241,14 @@ void Resolver::doDefinedAtom(const DefinedAtom &atom) { // add to list of known atoms _atoms.push_back(&atom); - if (atom.contentType() == DefinedAtom::typeGroupComdat) - maybeAddSectionGroup(atom); + if ((atom.contentType() == DefinedAtom::typeGroupComdat) || + (atom.contentType() == DefinedAtom::typeGnuLinkOnce)) { + // 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); diff --git a/lld/lib/ReaderWriter/Native/WriterNative.cpp b/lld/lib/ReaderWriter/Native/WriterNative.cpp index 9735783b0a9..c1173380faa 100644 --- a/lld/lib/ReaderWriter/Native/WriterNative.cpp +++ b/lld/lib/ReaderWriter/Native/WriterNative.cpp @@ -41,7 +41,8 @@ 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->contentType() == DefinedAtom::typeGroupComdat || + defAtom->contentType() == DefinedAtom::typeGnuLinkOnce) { 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..b2295f87d66 100644 --- a/lld/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp +++ b/lld/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp @@ -71,7 +71,9 @@ public: if (!atom->name().empty()) buildDuplicateNameMap(*atom); - if (atom->contentType() == DefinedAtom::typeGroupComdat) { + if (atom->contentType() == DefinedAtom::typeGroupComdat || + atom->contentType() == DefinedAtom::typeGnuLinkOnce) { + for (const lld::Reference *ref : *atom) { if (ref->kindNamespace() != lld::Reference::KindNamespace::all) continue; @@ -229,7 +231,8 @@ private: } if (const lld::DefinedAtom *da = dyn_cast<DefinedAtom>(atom)) { - if (da->contentType() == DefinedAtom::typeGroupComdat) { + if (da->contentType() == DefinedAtom::typeGroupComdat || + da->contentType() == DefinedAtom::typeGnuLinkOnce) { if (_groupMap.count(name)) { _io.setError(Twine("duplicate group name: ") + name); } else { @@ -476,7 +479,8 @@ template <> struct ScalarEnumerationTraits<lld::DefinedAtom::ContentType> { io.enumCase(value, "ro-note", DefinedAtom::typeRONote); io.enumCase(value, "rw-note", DefinedAtom::typeRWNote); io.enumCase(value, "no-alloc", DefinedAtom::typeNoAlloc); - io.enumCase(value, "group-comdat", DefinedAtom::typeGroupComdat); + 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 + |

