Skip to content

Commit 79ac99b

Browse files
committedJun 16, 2017
[COFF] Drop unused comdat sections when GC is turned off
Summary: Adds a "Discarded" bool to SectionChunk to indicate if the section was discarded by COMDAT deduplication. The Writer still just checks `isLive()`. Fixes PR33446 Reviewers: ruiu Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D34288 llvm-svn: 305582
1 parent f1b9f3a commit 79ac99b

File tree

6 files changed

+98
-6
lines changed

6 files changed

+98
-6
lines changed
 

‎lld/COFF/Chunks.cpp

+14-4
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,14 @@ SectionChunk::SectionChunk(ObjectFile *F, const coff_section *H)
3737

3838
Align = Header->getAlignment();
3939

40-
// Only COMDAT sections are subject of dead-stripping.
41-
Live = !isCOMDAT();
40+
// Chunks may be discarded during comdat merging.
41+
Discarded = false;
42+
43+
// If linker GC is disabled, every chunk starts out alive. If linker GC is
44+
// enabled, treat non-comdat sections as roots. Generally optimized object
45+
// files will be built with -ffunction-sections or /Gy, so most things worth
46+
// stripping will be in a comdat.
47+
Live = !Config->DoGC || !isCOMDAT();
4248
}
4349

4450
static void add16(uint8_t *P, int16_t V) { write16le(P, read16le(P) + V); }
@@ -226,8 +232,12 @@ bool SectionChunk::isCOMDAT() const {
226232
void SectionChunk::printDiscardedMessage() const {
227233
// Removed by dead-stripping. If it's removed by ICF, ICF already
228234
// printed out the name, so don't repeat that here.
229-
if (Sym && this == Repl)
230-
message("Discarded " + Sym->getName());
235+
if (Sym && this == Repl) {
236+
if (Discarded)
237+
message("Discarded comdat symbol " + Sym->getName());
238+
else if (!Live)
239+
message("Discarded " + Sym->getName());
240+
}
231241
}
232242

233243
StringRef SectionChunk::getDebugName() {

‎lld/COFF/Chunks.h

+14-1
Original file line numberDiff line numberDiff line change
@@ -159,13 +159,23 @@ class SectionChunk : public Chunk {
159159
StringRef getDebugName() override;
160160
void setSymbol(DefinedRegular *S) { if (!Sym) Sym = S; }
161161

162+
// Returns true if the chunk was not dropped by GC or COMDAT deduplication.
163+
bool isLive() { return Live && !Discarded; }
164+
162165
// Used by the garbage collector.
163-
bool isLive() { return !Config->DoGC || Live; }
164166
void markLive() {
167+
assert(Config->DoGC && "should only mark things live from GC");
165168
assert(!isLive() && "Cannot mark an already live section!");
166169
Live = true;
167170
}
168171

172+
// Returns true if this chunk was dropped by COMDAT deduplication.
173+
bool isDiscarded() const { return Discarded; }
174+
175+
// Used by the SymbolTable when discarding unused comdat sections. This is
176+
// redundant when GC is enabled, as all comdat sections will start out dead.
177+
void markDiscarded() { Discarded = true; }
178+
169179
// Allow iteration over the bodies of this chunk's relocated symbols.
170180
llvm::iterator_range<symbol_iterator> symbols() const {
171181
return llvm::make_range(symbol_iterator(File, Relocs.begin()),
@@ -196,6 +206,9 @@ class SectionChunk : public Chunk {
196206
llvm::iterator_range<const coff_relocation *> Relocs;
197207
size_t NumRelocs;
198208

209+
// True if this chunk was discarded because it was a duplicate comdat section.
210+
bool Discarded;
211+
199212
// Used by the garbage collector.
200213
bool Live;
201214

‎lld/COFF/InputFiles.cpp

+5-1
Original file line numberDiff line numberDiff line change
@@ -249,8 +249,12 @@ SymbolBody *ObjectFile::createDefined(COFFSymbolRef Sym, const void *AuxP,
249249
auto *Aux = reinterpret_cast<const coff_aux_section_definition *>(AuxP);
250250
if (Aux->Selection == IMAGE_COMDAT_SELECT_ASSOCIATIVE)
251251
if (auto *ParentSC = cast_or_null<SectionChunk>(
252-
SparseChunks[Aux->getNumber(Sym.isBigObj())]))
252+
SparseChunks[Aux->getNumber(Sym.isBigObj())])) {
253253
ParentSC->addAssociative(SC);
254+
// If we already discarded the parent, discard the child.
255+
if (ParentSC->isDiscarded())
256+
SC->markDiscarded();
257+
}
254258
SC->Checksum = Aux->CheckSum;
255259
}
256260

‎lld/COFF/SymbolTable.cpp

+6
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,12 @@ Symbol *SymbolTable::addRegular(InputFile *F, StringRef N, bool IsCOMDAT,
244244
reportDuplicate(S, F);
245245
} else if (SP == SP_NEW) {
246246
replaceBody<DefinedRegular>(S, F, N, IsCOMDAT, /*IsExternal*/ true, Sym, C);
247+
} else if (SP == SP_EXISTING && IsCOMDAT && C) {
248+
C->markDiscarded();
249+
// Discard associative chunks that we've parsed so far. No need to recurse
250+
// because an associative section cannot have children.
251+
for (SectionChunk *Child : C->children())
252+
Child->markDiscarded();
247253
}
248254
return S;
249255
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# Defines foo and foo_assoc globals. foo is comdat, and foo_assoc is comdat
2+
# associative with it. foo_assoc should be discarded iff foo is discarded,
3+
# either by linker GC or normal comdat merging.
4+
5+
.section .rdata,"dr",associative,foo
6+
.p2align 3
7+
.quad foo
8+
9+
.section .data,"dw",discard,foo
10+
.globl foo # @foo
11+
.p2align 2
12+
foo:
13+
.long 42

‎lld/test/COFF/associative-comdat.s

+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
# RUN: llvm-mc %s -filetype=obj -o %t1.obj
2+
# RUN: llvm-mc %S/Inputs/associative-comdat-2.s -filetype=obj -o %t2.obj
3+
4+
# RUN: lld-link -entry:main %t1.obj %t2.obj -out:%t.gc.exe
5+
# RUN: llvm-readobj -sections %t.gc.exe | FileCheck %s
6+
7+
# RUN: lld-link -entry:main %t1.obj %t2.obj -opt:noref -out:%t.nogc.exe
8+
# RUN: llvm-readobj -sections %t.nogc.exe | FileCheck %s
9+
10+
# CHECK: Sections [
11+
# CHECK: Section {
12+
# CHECK: Number: 1
13+
# CHECK-LABEL: Name: .data (2E 64 61 74 61 00 00 00)
14+
# CHECK-NEXT: VirtualSize: 0x4
15+
# CHECK: Section {
16+
# CHECK-LABEL: Name: .rdata (2E 72 64 61 74 61 00 00)
17+
# This is the critical check to show that only *one* definition of
18+
# foo_assoc was retained. This *must* be 8, not 16.
19+
# CHECK-NEXT: VirtualSize: 0x8
20+
21+
.text
22+
.def main;
23+
.scl 2;
24+
.type 32;
25+
.endef
26+
.globl main # -- Begin function main
27+
.p2align 4, 0x90
28+
main: # @main
29+
# BB#0:
30+
movl foo(%rip), %eax
31+
retq
32+
# -- End function
33+
34+
# Defines foo and foo_assoc globals. foo is comdat, and foo_assoc is comdat
35+
# associative with it. foo_assoc should be discarded iff foo is discarded,
36+
# either by linker GC or normal comdat merging.
37+
38+
.section .rdata,"dr",associative,foo
39+
.p2align 3
40+
.quad foo
41+
42+
.section .data,"dw",discard,foo
43+
.globl foo # @foo
44+
.p2align 2
45+
foo:
46+
.long 42

0 commit comments

Comments
 (0)
Please sign in to comment.