Skip to content

Commit 9316c40

Browse files
committedApr 1, 2014
[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 in a binary. .gnu.linkonce based symbol resolution achieves that. Review : http://llvm-reviews.chandlerc.com/D3242 llvm-svn: 205280
1 parent d09ba23 commit 9316c40

11 files changed

+603
-11
lines changed
 

‎lld/include/lld/Core/DefinedAtom.h

+9
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@ class DefinedAtom : public Atom {
147147
typeRWNote, // Identifies readwrite note sections [ELF]
148148
typeNoAlloc, // Identifies non allocatable sections [ELF]
149149
typeGroupComdat, // Identifies a section group [ELF, COFF]
150+
typeGnuLinkOnce, // Identifies a gnu.linkonce section [ELF]
150151
};
151152

152153
// Permission bits for atoms and segments. The order of these values are
@@ -330,6 +331,14 @@ class DefinedAtom : public Atom {
330331
atomContentType == DefinedAtom::typeThreadZeroFill);
331332
}
332333

334+
/// Utility function to check if the atom belongs to a group section
335+
/// that represents section groups or .gnu.linkonce sections.
336+
bool isGroupParent() const {
337+
ContentType atomContentType = contentType();
338+
return (atomContentType == DefinedAtom::typeGroupComdat ||
339+
atomContentType == DefinedAtom::typeGnuLinkOnce);
340+
}
341+
333342
protected:
334343
// DefinedAtom is an abstract base class. Only subclasses can access
335344
// constructor.

‎lld/include/lld/Core/Resolver.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,8 @@ class Resolver {
6767
private:
6868
typedef std::function<void(StringRef, bool)> UndefCallback;
6969

70-
/// \brief Add section group if it does not exist previously.
71-
void maybeAddSectionGroup(const DefinedAtom &atom);
70+
/// \brief Add section group/.gnu.linkonce if it does not exist previously.
71+
bool maybeAddSectionGroupOrGnuLinkOnce(const DefinedAtom &atom);
7272

7373
/// \brief The main function that iterates over the files to resolve
7474
bool resolveUndefines();

‎lld/lib/Core/DefinedAtom.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ DefinedAtom::ContentPermissions DefinedAtom::permissions(ContentType type) {
7272
return permRW_L;
7373

7474
case typeGroupComdat:
75+
case typeGnuLinkOnce:
7576
case typeUnknown:
7677
case typeTempLTO:
7778
return permUnknown;

‎lld/lib/Core/Resolver.cpp

+26-6
Original file line numberDiff line numberDiff line change
@@ -184,11 +184,24 @@ void Resolver::doUndefinedAtom(const UndefinedAtom &atom) {
184184
}
185185

186186
/// \brief Add the section group and the group-child reference members.
187-
void Resolver::maybeAddSectionGroup(const DefinedAtom &atom) {
187+
bool Resolver::maybeAddSectionGroupOrGnuLinkOnce(const DefinedAtom &atom) {
188188
// First time adding a group ?
189189
bool isFirstTime = _symbolTable.addGroup(atom);
190-
if (!isFirstTime)
191-
return;
190+
191+
if (!isFirstTime) {
192+
// If duplicate symbols are allowed, select the first group.
193+
if (_context.getAllowDuplicates())
194+
return true;
195+
const DefinedAtom *prevGroup =
196+
llvm::dyn_cast<DefinedAtom>(_symbolTable.findGroup(atom.name()));
197+
assert(prevGroup &&
198+
"Internal Error: The group atom could only be a defined atom");
199+
// The atoms should be of the same content type, reject invalid group
200+
// resolution behaviors.
201+
if (atom.contentType() != prevGroup->contentType())
202+
return false;
203+
return true;
204+
}
192205

193206
for (const Reference *r : atom) {
194207
if ((r->kindNamespace() == lld::Reference::KindNamespace::all) &&
@@ -200,6 +213,7 @@ void Resolver::maybeAddSectionGroup(const DefinedAtom &atom) {
200213
_symbolTable.add(*target);
201214
}
202215
}
216+
return true;
203217
}
204218

205219
// called on each atom when a file is added
@@ -229,10 +243,16 @@ void Resolver::doDefinedAtom(const DefinedAtom &atom) {
229243
// add to list of known atoms
230244
_atoms.push_back(&atom);
231245

232-
if (atom.contentType() == DefinedAtom::typeGroupComdat)
233-
maybeAddSectionGroup(atom);
234-
else
246+
if (atom.isGroupParent()) {
247+
// Raise error if there exists a similar gnu linkonce section.
248+
if (!maybeAddSectionGroupOrGnuLinkOnce(atom)) {
249+
llvm::errs() << "SymbolTable: error while merging " << atom.name()
250+
<< "\n";
251+
llvm::report_fatal_error("duplicate symbol error");
252+
}
253+
} else {
235254
_symbolTable.add(atom);
255+
}
236256

237257
if (_context.deadStrip()) {
238258
// add to set of dead-strip-roots, all symbols that

‎lld/lib/ReaderWriter/Native/WriterNative.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ class Writer : public lld::Writer {
4141
// We are trying to process all atoms, but the defined() iterator does not
4242
// return group children. So, when a group parent is found, we need to
4343
// handle each child atom.
44-
if (defAtom->contentType() == DefinedAtom::typeGroupComdat) {
44+
if (defAtom->isGroupParent()) {
4545
for (const Reference *r : *defAtom) {
4646
if (r->kindNamespace() != lld::Reference::KindNamespace::all)
4747
continue;

‎lld/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp

+3-2
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ class RefNameBuilder {
7171
if (!atom->name().empty())
7272
buildDuplicateNameMap(*atom);
7373

74-
if (atom->contentType() == DefinedAtom::typeGroupComdat) {
74+
if (atom->isGroupParent()) {
7575
for (const lld::Reference *ref : *atom) {
7676
if (ref->kindNamespace() != lld::Reference::KindNamespace::all)
7777
continue;
@@ -229,7 +229,7 @@ class RefNameResolver {
229229
}
230230

231231
if (const lld::DefinedAtom *da = dyn_cast<DefinedAtom>(atom)) {
232-
if (da->contentType() == DefinedAtom::typeGroupComdat) {
232+
if (da->isGroupParent()) {
233233
if (_groupMap.count(name)) {
234234
_io.setError(Twine("duplicate group name: ") + name);
235235
} else {
@@ -477,6 +477,7 @@ template <> struct ScalarEnumerationTraits<lld::DefinedAtom::ContentType> {
477477
io.enumCase(value, "rw-note", DefinedAtom::typeRWNote);
478478
io.enumCase(value, "no-alloc", DefinedAtom::typeNoAlloc);
479479
io.enumCase(value, "group-comdat", DefinedAtom::typeGroupComdat);
480+
io.enumCase(value, "gnu-linkonce", DefinedAtom::typeGnuLinkOnce);
480481
}
481482
};
482483

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
# RUN: lld -core %s | FileCheck %s
2+
3+
#
4+
# Test that gnu linkonce sections are parsed and the first section selected for symbol
5+
# resolution
6+
#
7+
8+
---
9+
defined-atoms:
10+
- name: g1
11+
scope: global
12+
type: gnu-linkonce
13+
references:
14+
- kind: group-child
15+
target: f1
16+
- kind: group-child
17+
target: f2
18+
- kind: group-child
19+
target: g1
20+
- kind: group-child
21+
target: d1
22+
- name: f1
23+
scope: global
24+
type: code
25+
references:
26+
- kind: group-parent
27+
target: g1
28+
- name: f2
29+
scope: global
30+
type: code
31+
references:
32+
- kind: group-parent
33+
target: g1
34+
- name: g1
35+
scope: global
36+
type: code
37+
references:
38+
- kind: group-parent
39+
target: g1
40+
- name: d1
41+
scope: global
42+
type: data
43+
references:
44+
- kind: group-parent
45+
target: g1
46+
---
47+
defined-atoms:
48+
- name: g1
49+
scope: global
50+
type: gnu-linkonce
51+
references:
52+
- kind: group-child
53+
target: f1
54+
- kind: group-child
55+
target: f2
56+
- kind: group-child
57+
target: g1
58+
- kind: group-child
59+
target: d1
60+
- name: f1
61+
scope: global
62+
type: code
63+
references:
64+
- kind: group-parent
65+
target: g1
66+
- name: f2
67+
scope: global
68+
type: code
69+
references:
70+
- kind: group-parent
71+
target: g1
72+
- name: g1
73+
scope: global
74+
type: code
75+
references:
76+
- kind: group-parent
77+
target: g1
78+
- name: d1
79+
scope: global
80+
type: data
81+
references:
82+
- kind: group-parent
83+
target: g1
84+
...
85+
86+
# CHECK: defined-atoms:
87+
# CHECK: - name: g1
88+
# CHECK: ref-name: [[PARENT:[a-zA-Z\.0-9_]+]]
89+
# CHECK: type: gnu-linkonce
90+
# CHECK: references:
91+
# CHECK: - kind: group-child
92+
# CHECK: target: f1
93+
# CHECK: - kind: group-child
94+
# CHECK: target: f2
95+
# CHECK: - kind: group-child
96+
# CHECK: target: [[CHILD:[a-zA-Z\.0-9_]+]]
97+
# CHECK: - kind: group-child
98+
# CHECK: target: d1
99+
# CHECK: - name: f1
100+
# CHECK: references:
101+
# CHECK: - kind: group-parent
102+
# CHECK: target: [[PARENT]]
103+
# CHECK: - name: f2
104+
# CHECK: references:
105+
# CHECK: - kind: group-parent
106+
# CHECK: target: [[PARENT]]
107+
# CHECK: - name: g1
108+
# CHECK: ref-name: [[CHILD]]
109+
# CHECK: references:
110+
# CHECK: - kind: group-parent
111+
# CHECK: target: [[PARENT]]
112+
# CHECK: - name: d1
113+
# CHECK: references:
114+
# CHECK: - kind: group-parent
115+
# CHECK: target: [[PARENT]]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
# RUN: lld -core %s | FileCheck %s
2+
3+
#
4+
# Test that gnu linkonce sections are parsed and the first section selected for
5+
# symbol resolution. The second file which has the same gnu linkonce section has
6+
# a unresolved undefined symbol. lets make sure that the symbol is kept around
7+
# in the final link and remains undefined.
8+
#
9+
10+
---
11+
defined-atoms:
12+
- name: f1
13+
scope: global
14+
type: code
15+
references:
16+
- kind: group-parent
17+
target: g1
18+
- name: f2
19+
scope: global
20+
type: code
21+
references:
22+
- kind: group-parent
23+
target: g1
24+
- name: g1
25+
scope: global
26+
type: code
27+
references:
28+
- kind: group-parent
29+
target: g1
30+
- name: d1
31+
scope: global
32+
type: data
33+
references:
34+
- kind: group-parent
35+
target: g1
36+
- name: g1
37+
scope: global
38+
type: gnu-linkonce
39+
references:
40+
- kind: group-child
41+
target: f1
42+
- kind: group-child
43+
target: f2
44+
- kind: group-child
45+
target: g1
46+
- kind: group-child
47+
target: d1
48+
---
49+
defined-atoms:
50+
- name: anotherfunction
51+
scope: global
52+
type: data
53+
references:
54+
- kind: layout-before
55+
target: f3
56+
- name: f1
57+
scope: global
58+
type: code
59+
references:
60+
- kind: group-parent
61+
target: g1
62+
- name: f2
63+
scope: global
64+
type: code
65+
references:
66+
- kind: group-parent
67+
target: g1
68+
- name: f3
69+
scope: global
70+
type: code
71+
references:
72+
- kind: group-parent
73+
target: g1
74+
- name: g1
75+
scope: global
76+
type: code
77+
references:
78+
- kind: group-parent
79+
target: g1
80+
- name: d1
81+
scope: global
82+
type: data
83+
references:
84+
- kind: group-parent
85+
target: g1
86+
- name: g1
87+
scope: global
88+
type: gnu-linkonce
89+
references:
90+
- kind: group-child
91+
target: f1
92+
- kind: group-child
93+
target: f2
94+
- kind: group-child
95+
target: f3
96+
- kind: group-child
97+
target: g1
98+
- kind: group-child
99+
target: d1
100+
undefined-atoms:
101+
- name: f3
102+
can-be-null: never
103+
...
104+
105+
#CHECK: - name: anotherfunction
106+
#CHECK: scope: global
107+
#CHECK: type: data
108+
#CHECK: references:
109+
#CHECK: - kind: layout-before
110+
#CHECK: offset: 0
111+
#CHECK: target: f3
112+
#CHECK: undefined-atoms:
113+
#CHECK: - name: f3

0 commit comments

Comments
 (0)