Skip to content

Commit

Permalink
[LLD] [COFF] Check the aux section definition size for IMAGE_COMDAT_S…
Browse files Browse the repository at this point in the history
…ELECT_SAME_SIZE

Binutils generated sections seem to be padded to a multiple of 16 bytes,
but the aux section definition contains the original, unpadded section
length.

The size check used for IMAGE_COMDAT_SELECT_SAME_SIZE previously
only checked the size of the section itself. When checking the
currently processed object file against the previously chosen
comdat section, we easily have access to the aux section definition
of the currently processed section, but we have to iterate over the
symbols of the previously selected object file to find the section
definition of the previously picked section. (We don't want to
inflate SectionChunk to carry more data, for something that is only
needed in corner cases.) Only do this when the mingw flag is set.

This fixes statically linking clang-built C++ object files against
libstdc++ built with GCC, if the object files contain e.g. typeinfo.

Differential Revision: https://reviews.llvm.org/D86659
  • Loading branch information
mstorsjo committed Aug 27, 2020
1 parent e72403f commit df8f3bf
Show file tree
Hide file tree
Showing 5 changed files with 107 additions and 8 deletions.
33 changes: 28 additions & 5 deletions lld/COFF/InputFiles.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -472,8 +472,23 @@ Symbol *ObjFile::createUndefined(COFFSymbolRef sym) {
return symtab->addUndefined(name, this, sym.isWeakExternal());
}

void ObjFile::handleComdatSelection(COFFSymbolRef sym, COMDATType &selection,
bool &prevailing, DefinedRegular *leader) {
static const coff_aux_section_definition *findSectionDef(COFFObjectFile *obj,
int32_t section) {
uint32_t numSymbols = obj->getNumberOfSymbols();
for (uint32_t i = 0; i < numSymbols; ++i) {
COFFSymbolRef sym = check(obj->getSymbol(i));
if (sym.getSectionNumber() != section)
continue;
if (const coff_aux_section_definition *def = sym.getSectionDefinition())
return def;
}
return nullptr;
}

void ObjFile::handleComdatSelection(
COFFSymbolRef sym, COMDATType &selection, bool &prevailing,
DefinedRegular *leader,
const llvm::object::coff_aux_section_definition *def) {
if (prevailing)
return;
// There's already an existing comdat for this symbol: `Leader`.
Expand Down Expand Up @@ -540,8 +555,16 @@ void ObjFile::handleComdatSelection(COFFSymbolRef sym, COMDATType &selection,
break;

case IMAGE_COMDAT_SELECT_SAME_SIZE:
if (leaderChunk->getSize() != getSection(sym)->SizeOfRawData)
symtab->reportDuplicate(leader, this);
if (leaderChunk->getSize() != getSection(sym)->SizeOfRawData) {
if (!config->mingw) {
symtab->reportDuplicate(leader, this);
} else {
const coff_aux_section_definition *leaderDef = findSectionDef(
leaderChunk->file->getCOFFObj(), leaderChunk->getSectionNumber());
if (!leaderDef || leaderDef->Length != def->Length)
symtab->reportDuplicate(leader, this);
}
}
break;

case IMAGE_COMDAT_SELECT_EXACT_MATCH: {
Expand Down Expand Up @@ -657,7 +680,7 @@ Optional<Symbol *> ObjFile::createDefined(
COMDATType selection = (COMDATType)def->Selection;

if (leader->isCOMDAT)
handleComdatSelection(sym, selection, prevailing, leader);
handleComdatSelection(sym, selection, prevailing, leader, def);

if (prevailing) {
SectionChunk *c = readSection(sectionNumber, def, getName());
Expand Down
7 changes: 4 additions & 3 deletions lld/COFF/InputFiles.h
Original file line number Diff line number Diff line change
Expand Up @@ -255,9 +255,10 @@ class ObjFile : public InputFile {
// match the existing symbol and its selection. If either old or new
// symbol have selection IMAGE_COMDAT_SELECT_LARGEST, Sym might replace
// the existing leader. In that case, Prevailing is set to true.
void handleComdatSelection(COFFSymbolRef sym,
llvm::COFF::COMDATType &selection,
bool &prevailing, DefinedRegular *leader);
void
handleComdatSelection(COFFSymbolRef sym, llvm::COFF::COMDATType &selection,
bool &prevailing, DefinedRegular *leader,
const llvm::object::coff_aux_section_definition *def);

llvm::Optional<Symbol *>
createDefined(COFFSymbolRef sym,
Expand Down
30 changes: 30 additions & 0 deletions lld/test/COFF/Inputs/comdat-binutils.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
--- !COFF
header:
Machine: IMAGE_FILE_MACHINE_AMD64
Characteristics: [ IMAGE_FILE_RELOCS_STRIPPED, IMAGE_FILE_LINE_NUMS_STRIPPED ]
sections:
- Name: '.rdata$mysymbol'
Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_READ ]
Alignment: 16
SectionData: 2A000000000000000000000000000000
symbols:
- Name: '.rdata$mysymbol'
Value: 0
SectionNumber: 1
SimpleType: IMAGE_SYM_TYPE_NULL
ComplexType: IMAGE_SYM_DTYPE_NULL
StorageClass: IMAGE_SYM_CLASS_STATIC
SectionDefinition:
Length: 1
NumberOfRelocations: 0
NumberOfLinenumbers: 0
CheckSum: 0
Number: 0
Selection: IMAGE_COMDAT_SELECT_SAME_SIZE
- Name: mysymbol
Value: 0
SectionNumber: 1
SimpleType: IMAGE_SYM_TYPE_NULL
ComplexType: IMAGE_SYM_DTYPE_NULL
StorageClass: IMAGE_SYM_CLASS_EXTERNAL
...
30 changes: 30 additions & 0 deletions lld/test/COFF/Inputs/comdat-llvm.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
--- !COFF
header:
Machine: IMAGE_FILE_MACHINE_AMD64
Characteristics: [ ]
sections:
- Name: '.rdata$mysymbol'
Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_READ ]
Alignment: 1
SectionData: 2A
symbols:
- Name: '.rdata$mysymbol'
Value: 0
SectionNumber: 1
SimpleType: IMAGE_SYM_TYPE_NULL
ComplexType: IMAGE_SYM_DTYPE_NULL
StorageClass: IMAGE_SYM_CLASS_STATIC
SectionDefinition:
Length: 1
NumberOfRelocations: 0
NumberOfLinenumbers: 0
CheckSum: 3686517206
Number: 1
Selection: IMAGE_COMDAT_SELECT_SAME_SIZE
- Name: mysymbol
Value: 0
SectionNumber: 1
SimpleType: IMAGE_SYM_TYPE_NULL
ComplexType: IMAGE_SYM_DTYPE_NULL
StorageClass: IMAGE_SYM_CLASS_EXTERNAL
...
15 changes: 15 additions & 0 deletions lld/test/COFF/comdat-gcc-compatibility-size.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# RUN: yaml2obj %p/Inputs/comdat-llvm.yaml > %t.llvm.o
# RUN: yaml2obj %p/Inputs/comdat-binutils.yaml > %t.binutils.o
# RUN: lld-link -lldmingw -noentry -dll %t.llvm.o %t.binutils.o -out:%t.dll
# RUN: lld-link -lldmingw -noentry -dll %t.binutils.o %t.llvm.o -out:%t.dll
# RUN: not lld-link -noentry -dll %t.llvm.o %t.binutils.o -out:%t.dll
# RUN: not lld-link -noentry -dll %t.binutils.o %t.llvm.o -out:%t.dll

# The test object files have been generated by assembling the following
# snippet using binutils and llvm.

# .section .rdata$mysymbol, "dr"
# .linkonce same_size
# .globl mysymbol
#mysymbol:
# .byte 42

0 comments on commit df8f3bf

Please sign in to comment.