forked from OSchip/llvm-project
[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
This commit is contained in:
parent
f1b9f3a23f
commit
79ac99b3e8
|
@ -37,8 +37,14 @@ SectionChunk::SectionChunk(ObjectFile *F, const coff_section *H)
|
|||
|
||||
Align = Header->getAlignment();
|
||||
|
||||
// Only COMDAT sections are subject of dead-stripping.
|
||||
Live = !isCOMDAT();
|
||||
// Chunks may be discarded during comdat merging.
|
||||
Discarded = false;
|
||||
|
||||
// If linker GC is disabled, every chunk starts out alive. If linker GC is
|
||||
// enabled, treat non-comdat sections as roots. Generally optimized object
|
||||
// files will be built with -ffunction-sections or /Gy, so most things worth
|
||||
// stripping will be in a comdat.
|
||||
Live = !Config->DoGC || !isCOMDAT();
|
||||
}
|
||||
|
||||
static void add16(uint8_t *P, int16_t V) { write16le(P, read16le(P) + V); }
|
||||
|
@ -226,8 +232,12 @@ bool SectionChunk::isCOMDAT() const {
|
|||
void SectionChunk::printDiscardedMessage() const {
|
||||
// Removed by dead-stripping. If it's removed by ICF, ICF already
|
||||
// printed out the name, so don't repeat that here.
|
||||
if (Sym && this == Repl)
|
||||
message("Discarded " + Sym->getName());
|
||||
if (Sym && this == Repl) {
|
||||
if (Discarded)
|
||||
message("Discarded comdat symbol " + Sym->getName());
|
||||
else if (!Live)
|
||||
message("Discarded " + Sym->getName());
|
||||
}
|
||||
}
|
||||
|
||||
StringRef SectionChunk::getDebugName() {
|
||||
|
|
|
@ -159,13 +159,23 @@ public:
|
|||
StringRef getDebugName() override;
|
||||
void setSymbol(DefinedRegular *S) { if (!Sym) Sym = S; }
|
||||
|
||||
// Returns true if the chunk was not dropped by GC or COMDAT deduplication.
|
||||
bool isLive() { return Live && !Discarded; }
|
||||
|
||||
// Used by the garbage collector.
|
||||
bool isLive() { return !Config->DoGC || Live; }
|
||||
void markLive() {
|
||||
assert(Config->DoGC && "should only mark things live from GC");
|
||||
assert(!isLive() && "Cannot mark an already live section!");
|
||||
Live = true;
|
||||
}
|
||||
|
||||
// Returns true if this chunk was dropped by COMDAT deduplication.
|
||||
bool isDiscarded() const { return Discarded; }
|
||||
|
||||
// Used by the SymbolTable when discarding unused comdat sections. This is
|
||||
// redundant when GC is enabled, as all comdat sections will start out dead.
|
||||
void markDiscarded() { Discarded = true; }
|
||||
|
||||
// Allow iteration over the bodies of this chunk's relocated symbols.
|
||||
llvm::iterator_range<symbol_iterator> symbols() const {
|
||||
return llvm::make_range(symbol_iterator(File, Relocs.begin()),
|
||||
|
@ -196,6 +206,9 @@ private:
|
|||
llvm::iterator_range<const coff_relocation *> Relocs;
|
||||
size_t NumRelocs;
|
||||
|
||||
// True if this chunk was discarded because it was a duplicate comdat section.
|
||||
bool Discarded;
|
||||
|
||||
// Used by the garbage collector.
|
||||
bool Live;
|
||||
|
||||
|
|
|
@ -249,8 +249,12 @@ SymbolBody *ObjectFile::createDefined(COFFSymbolRef Sym, const void *AuxP,
|
|||
auto *Aux = reinterpret_cast<const coff_aux_section_definition *>(AuxP);
|
||||
if (Aux->Selection == IMAGE_COMDAT_SELECT_ASSOCIATIVE)
|
||||
if (auto *ParentSC = cast_or_null<SectionChunk>(
|
||||
SparseChunks[Aux->getNumber(Sym.isBigObj())]))
|
||||
SparseChunks[Aux->getNumber(Sym.isBigObj())])) {
|
||||
ParentSC->addAssociative(SC);
|
||||
// If we already discarded the parent, discard the child.
|
||||
if (ParentSC->isDiscarded())
|
||||
SC->markDiscarded();
|
||||
}
|
||||
SC->Checksum = Aux->CheckSum;
|
||||
}
|
||||
|
||||
|
|
|
@ -244,6 +244,12 @@ Symbol *SymbolTable::addRegular(InputFile *F, StringRef N, bool IsCOMDAT,
|
|||
reportDuplicate(S, F);
|
||||
} else if (SP == SP_NEW) {
|
||||
replaceBody<DefinedRegular>(S, F, N, IsCOMDAT, /*IsExternal*/ true, Sym, C);
|
||||
} else if (SP == SP_EXISTING && IsCOMDAT && C) {
|
||||
C->markDiscarded();
|
||||
// Discard associative chunks that we've parsed so far. No need to recurse
|
||||
// because an associative section cannot have children.
|
||||
for (SectionChunk *Child : C->children())
|
||||
Child->markDiscarded();
|
||||
}
|
||||
return S;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
# Defines foo and foo_assoc globals. foo is comdat, and foo_assoc is comdat
|
||||
# associative with it. foo_assoc should be discarded iff foo is discarded,
|
||||
# either by linker GC or normal comdat merging.
|
||||
|
||||
.section .rdata,"dr",associative,foo
|
||||
.p2align 3
|
||||
.quad foo
|
||||
|
||||
.section .data,"dw",discard,foo
|
||||
.globl foo # @foo
|
||||
.p2align 2
|
||||
foo:
|
||||
.long 42
|
|
@ -0,0 +1,46 @@
|
|||
# RUN: llvm-mc %s -filetype=obj -o %t1.obj
|
||||
# RUN: llvm-mc %S/Inputs/associative-comdat-2.s -filetype=obj -o %t2.obj
|
||||
|
||||
# RUN: lld-link -entry:main %t1.obj %t2.obj -out:%t.gc.exe
|
||||
# RUN: llvm-readobj -sections %t.gc.exe | FileCheck %s
|
||||
|
||||
# RUN: lld-link -entry:main %t1.obj %t2.obj -opt:noref -out:%t.nogc.exe
|
||||
# RUN: llvm-readobj -sections %t.nogc.exe | FileCheck %s
|
||||
|
||||
# CHECK: Sections [
|
||||
# CHECK: Section {
|
||||
# CHECK: Number: 1
|
||||
# CHECK-LABEL: Name: .data (2E 64 61 74 61 00 00 00)
|
||||
# CHECK-NEXT: VirtualSize: 0x4
|
||||
# CHECK: Section {
|
||||
# CHECK-LABEL: Name: .rdata (2E 72 64 61 74 61 00 00)
|
||||
# This is the critical check to show that only *one* definition of
|
||||
# foo_assoc was retained. This *must* be 8, not 16.
|
||||
# CHECK-NEXT: VirtualSize: 0x8
|
||||
|
||||
.text
|
||||
.def main;
|
||||
.scl 2;
|
||||
.type 32;
|
||||
.endef
|
||||
.globl main # -- Begin function main
|
||||
.p2align 4, 0x90
|
||||
main: # @main
|
||||
# BB#0:
|
||||
movl foo(%rip), %eax
|
||||
retq
|
||||
# -- End function
|
||||
|
||||
# Defines foo and foo_assoc globals. foo is comdat, and foo_assoc is comdat
|
||||
# associative with it. foo_assoc should be discarded iff foo is discarded,
|
||||
# either by linker GC or normal comdat merging.
|
||||
|
||||
.section .rdata,"dr",associative,foo
|
||||
.p2align 3
|
||||
.quad foo
|
||||
|
||||
.section .data,"dw",discard,foo
|
||||
.globl foo # @foo
|
||||
.p2align 2
|
||||
foo:
|
||||
.long 42
|
Loading…
Reference in New Issue