COFF: Fix ICF correctness bug.

When comparing two COMDAT sections, we need to take section values
and associative sections into account. This patch fixes that bug.
It fixes a crash bug of llvm-tblgen when linked with /opt:lldicf.

One thing I don't understand yet is that this logic seems to be
too strict. MSVC linker is able to create more compact executables
(which of course work correctly). With this ICF algorithm, LLD is
able to make executable smaller, but the outputs are larger than
MSVC's. There must be something I'm missing here.

llvm-svn: 240897
This commit is contained in:
Rui Ueyama 2015-06-28 01:30:54 +00:00
parent 45c4812851
commit 871847e32d
6 changed files with 98 additions and 6 deletions

View File

@ -173,6 +173,13 @@ bool SectionChunk::equals(const SectionChunk *X) const {
if (getContents() != X->getContents())
return false;
// Compare associative sections
if (AssocChildren.size() != X->AssocChildren.size())
return false;
for (size_t I = 0, E = AssocChildren.size(); I != E; ++I)
if (AssocChildren[I]->Ptr != X->AssocChildren[I]->Ptr)
return false;
// Compare relocations
auto Eq = [&](const coff_relocation &R1, const coff_relocation &R2) {
if (R1.Type != R2.Type)
@ -181,11 +188,13 @@ bool SectionChunk::equals(const SectionChunk *X) const {
return false;
SymbolBody *B1 = File->getSymbolBody(R1.SymbolTableIndex);
SymbolBody *B2 = X->File->getSymbolBody(R2.SymbolTableIndex);
if (B1 == B2)
return true;
auto *D1 = dyn_cast<DefinedRegular>(B1);
auto *D2 = dyn_cast<DefinedRegular>(B2);
if (D1 && D2 && D1->getChunk() == D2->getChunk())
return true;
return B1 == B2;
return (D1 && D2 &&
D1->getValue() == D2->getValue() &&
D1->getChunk() == D2->getChunk());
};
return std::equal(Relocs.begin(), Relocs.end(), X->Relocs.begin(), Eq);
}

View File

@ -151,7 +151,7 @@ private:
const coff_section *Header;
StringRef SectionName;
std::vector<Chunk *> AssocChildren;
std::vector<SectionChunk *> AssocChildren;
llvm::iterator_range<const coff_relocation *> Relocs;
size_t NumRelocs;

View File

@ -137,6 +137,7 @@ public:
bool isLive() const { return (*Data)->isLive(); }
void markLive() { (*Data)->markLive(); }
Chunk *getChunk() { return *Data; }
uint64_t getValue() { return Sym.getValue(); }
private:
StringRef Name;

View File

@ -0,0 +1,47 @@
---
header:
Machine: IMAGE_FILE_MACHINE_AMD64
Characteristics: []
sections:
- Name: .text
Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
Alignment: 16
SectionData: 0000000000000000
- Name: .assoc
Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
Alignment: 16
SectionData: 0000000000000000
symbols:
- Name: .text
Value: 0
SectionNumber: 1
SimpleType: IMAGE_SYM_TYPE_NULL
ComplexType: IMAGE_SYM_DTYPE_NULL
StorageClass: IMAGE_SYM_CLASS_STATIC
SectionDefinition:
Length: 8
NumberOfRelocations: 0
NumberOfLinenumbers: 0
CheckSum: 0
Number: 0
Selection: IMAGE_COMDAT_SELECT_ANY
# icf4 is *not* identical with mainCRTStartup because it has an associative section
- Name: icf4
Value: 0
SectionNumber: 1
SimpleType: IMAGE_SYM_TYPE_NULL
ComplexType: IMAGE_SYM_DTYPE_FUNCTION
StorageClass: IMAGE_SYM_CLASS_EXTERNAL
- Name: .assoc
Value: 0
SectionNumber: 2
SimpleType: IMAGE_SYM_TYPE_NULL
ComplexType: IMAGE_SYM_DTYPE_NULL
StorageClass: IMAGE_SYM_CLASS_STATIC
SectionDefinition:
Length: 8
NumberOfRelocations: 0
NumberOfLinenumbers: 0
CheckSum: 0
Number: 1
Selection: IMAGE_COMDAT_SELECT_ASSOCIATIVE

View File

@ -0,0 +1,30 @@
---
header:
Machine: IMAGE_FILE_MACHINE_AMD64
Characteristics: []
sections:
- Name: .text
Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
Alignment: 16
SectionData: 0000000000000000
symbols:
- Name: .text
Value: 0
SectionNumber: 1
SimpleType: IMAGE_SYM_TYPE_NULL
ComplexType: IMAGE_SYM_DTYPE_NULL
StorageClass: IMAGE_SYM_CLASS_STATIC
SectionDefinition:
Length: 8
NumberOfRelocations: 0
NumberOfLinenumbers: 0
CheckSum: 0
Number: 0
Selection: IMAGE_COMDAT_SELECT_ANY
# icf5 is *not* identical with its symbol value is different
- Name: icf5
Value: 5
SectionNumber: 1
SimpleType: IMAGE_SYM_TYPE_NULL
ComplexType: IMAGE_SYM_DTYPE_FUNCTION
StorageClass: IMAGE_SYM_CLASS_EXTERNAL

View File

@ -1,11 +1,16 @@
# RUN: yaml2obj < %p/Inputs/icf1.yaml > %t1.obj
# RUN: yaml2obj < %p/Inputs/icf2.yaml > %t2.obj
# RUN: yaml2obj < %p/Inputs/icf3.yaml > %t3.obj
# RUN: yaml2obj < %p/Inputs/icf4.yaml > %t4.obj
# RUN: yaml2obj < %p/Inputs/icf5.yaml > %t5.obj
#
# RUN: lld -flavor link2 /out:%t.exe %t1.obj %t2.obj %t3.obj \
# RUN: /opt:lldicf /include:icf2 /include:icf3 /verbose >& %t.log
# RUN: lld -flavor link2 /out:%t.exe %t1.obj %t2.obj %t3.obj %t4.obj %t5.obj \
# RUN: /opt:lldicf /include:icf2 /include:icf3 /include:icf4 /include:icf5 \
# RUN: /verbose >& %t.log
# RUN: FileCheck %s < %t.log
CHECK-NOT: Replaced mainCRTStartup
CHECK: Replaced icf2
CHECK-NOT: Replaced icf3
CHECK-NOT: Replaced icf4
CHECK-NOT: Replaced icf5