[PECOFF] Support yet another new type of weak symbol.
COMDAT_SELECT_LARGEST is a COMDAT type that make linker to choose the largest definition from among all of the definition of a symbol. If the size is the same, the choice is arbitrary. Differential Revision: http://llvm-reviews.chandlerc.com/D3011 llvm-svn: 204172
This commit is contained in:
parent
4e39f717ff
commit
7ad72ebc5e
|
@ -99,6 +99,7 @@ public:
|
|||
mergeAsWeakAndAddressUsed, // Is C++ definition inline definition whose
|
||||
// address was taken.
|
||||
mergeSameNameAndSize, // Another atom with different size is error
|
||||
mergeByLargestSection, // Choose an atom whose section is the largest.
|
||||
mergeByContent, // Merge with other constants with same content.
|
||||
};
|
||||
|
||||
|
|
|
@ -102,13 +102,14 @@ enum MergeResolution {
|
|||
MCR_Error
|
||||
};
|
||||
|
||||
static MergeResolution mergeCases[][5] = {
|
||||
// no tentative weak weakAddress sameNameAndSize
|
||||
{MCR_Error, MCR_First, MCR_First, MCR_First, MCR_SameSize}, // no
|
||||
{MCR_Second, MCR_Largest, MCR_Second, MCR_Second, MCR_SameSize}, // tentative
|
||||
{MCR_Second, MCR_First, MCR_First, MCR_Second, MCR_SameSize}, // weak
|
||||
{MCR_Second, MCR_First, MCR_First, MCR_First, MCR_SameSize}, // weakAddress
|
||||
{MCR_SameSize, MCR_SameSize, MCR_SameSize, MCR_SameSize, MCR_SameSize}, // sameSize
|
||||
static MergeResolution mergeCases[][6] = {
|
||||
// no tentative weak weakAddress sameNameAndSize largest
|
||||
{MCR_Error, MCR_First, MCR_First, MCR_First, MCR_SameSize, MCR_Largest}, // no
|
||||
{MCR_Second, MCR_Largest, MCR_Second, MCR_Second, MCR_SameSize, MCR_Largest}, // tentative
|
||||
{MCR_Second, MCR_First, MCR_First, MCR_Second, MCR_SameSize, MCR_Largest}, // weak
|
||||
{MCR_Second, MCR_First, MCR_First, MCR_First, MCR_SameSize, MCR_Largest}, // weakAddress
|
||||
{MCR_SameSize, MCR_SameSize, MCR_SameSize, MCR_SameSize, MCR_SameSize, MCR_SameSize}, // sameSize
|
||||
{MCR_Largest, MCR_Largest, MCR_Largest, MCR_Largest, MCR_SameSize, MCR_Largest}, // largest
|
||||
};
|
||||
|
||||
static MergeResolution mergeSelect(DefinedAtom::Merge first,
|
||||
|
@ -118,6 +119,33 @@ static MergeResolution mergeSelect(DefinedAtom::Merge first,
|
|||
return mergeCases[first][second];
|
||||
}
|
||||
|
||||
static uint64_t getSizeFollowReferences(const DefinedAtom *atom, uint32_t kind) {
|
||||
uint64_t size = 0;
|
||||
redo:
|
||||
while (atom) {
|
||||
for (const Reference *r : *atom) {
|
||||
if (r->kindNamespace() == Reference::KindNamespace::all &&
|
||||
r->kindArch() == Reference::KindArch::all &&
|
||||
r->kindValue() == kind) {
|
||||
atom = cast<DefinedAtom>(r->target());
|
||||
size += atom->size();
|
||||
goto redo;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
// Returns the size of the section containing the given atom. Atoms in the same
|
||||
// section are connected by layout-before and layout-after edges, so this
|
||||
// function traverses them to get the total size of atoms in the same section.
|
||||
static uint64_t sectionSize(const DefinedAtom *atom) {
|
||||
return atom->size()
|
||||
+ getSizeFollowReferences(atom, lld::Reference::kindLayoutBefore)
|
||||
+ getSizeFollowReferences(atom, lld::Reference::kindLayoutAfter);
|
||||
}
|
||||
|
||||
void SymbolTable::addByName(const Atom &newAtom) {
|
||||
StringRef name = newAtom.name();
|
||||
assert(!name.empty());
|
||||
|
@ -148,19 +176,22 @@ void SymbolTable::addByName(const Atom &newAtom) {
|
|||
case MCR_Second:
|
||||
useNew = true;
|
||||
break;
|
||||
case MCR_Largest:
|
||||
useNew = true;
|
||||
case MCR_Largest: {
|
||||
uint64_t existingSize = sectionSize((DefinedAtom*)existing);
|
||||
uint64_t newSize = sectionSize((DefinedAtom*)&newAtom);
|
||||
useNew = (newSize >= existingSize);
|
||||
break;
|
||||
}
|
||||
case MCR_SameSize: {
|
||||
uint64_t sa = ((DefinedAtom*)existing)->size();
|
||||
uint64_t sb = ((DefinedAtom*)&newAtom)->size();
|
||||
if (sa == sb) {
|
||||
uint64_t existingSize = sectionSize((DefinedAtom*)existing);
|
||||
uint64_t newSize = sectionSize((DefinedAtom*)&newAtom);
|
||||
if (existingSize == newSize) {
|
||||
useNew = true;
|
||||
break;
|
||||
}
|
||||
llvm::errs() << "Size mismatch: "
|
||||
<< existing->name() << " (" << sa << ") "
|
||||
<< newAtom.name() << " (" << sb << ")\n";
|
||||
<< existing->name() << " (" << existingSize << ") "
|
||||
<< newAtom.name() << " (" << newSize << ")\n";
|
||||
// fallthrough
|
||||
}
|
||||
case MCR_Error:
|
||||
|
|
|
@ -250,11 +250,13 @@ DefinedAtom::Merge getMerge(const coff_aux_section_definition *auxsym) {
|
|||
case llvm::COFF::IMAGE_COMDAT_SELECT_ANY:
|
||||
return DefinedAtom::mergeAsWeakAndAddressUsed;
|
||||
case llvm::COFF::IMAGE_COMDAT_SELECT_EXACT_MATCH:
|
||||
// TODO: This mapping is wrong. Fix it.
|
||||
return DefinedAtom::mergeByContent;
|
||||
case llvm::COFF::IMAGE_COMDAT_SELECT_SAME_SIZE:
|
||||
return DefinedAtom::mergeSameNameAndSize;
|
||||
case llvm::COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE:
|
||||
case llvm::COFF::IMAGE_COMDAT_SELECT_LARGEST:
|
||||
return DefinedAtom::mergeByLargestSection;
|
||||
case llvm::COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE:
|
||||
case llvm::COFF::IMAGE_COMDAT_SELECT_NEWEST:
|
||||
// FIXME: These attributes has more complicated semantics than the regular
|
||||
// weak symbol. These are mapped to mergeAsWeakAndAddressUsed for now
|
||||
|
|
|
@ -340,6 +340,7 @@ template <> struct ScalarEnumerationTraits<lld::DefinedAtom::Merge> {
|
|||
io.enumCase(value, "by-content", lld::DefinedAtom::mergeByContent);
|
||||
io.enumCase(value, "same-name-and-size",
|
||||
lld::DefinedAtom::mergeSameNameAndSize);
|
||||
io.enumCase(value, "largest", lld::DefinedAtom::mergeByLargestSection);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
---
|
||||
header:
|
||||
Machine: IMAGE_FILE_MACHINE_I386
|
||||
Characteristics: [ ]
|
||||
sections:
|
||||
- Name: .text
|
||||
Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
|
||||
Alignment: 16
|
||||
SectionData: 00112233
|
||||
symbols:
|
||||
- Name: .text
|
||||
Value: 0
|
||||
SectionNumber: 1
|
||||
SimpleType: IMAGE_SYM_TYPE_NULL
|
||||
ComplexType: IMAGE_SYM_DTYPE_NULL
|
||||
StorageClass: IMAGE_SYM_CLASS_STATIC
|
||||
NumberOfAuxSymbols: 1
|
||||
AuxiliaryData: 0700000000000000C979F796000006000000
|
||||
- Name: "_foo"
|
||||
Value: 0
|
||||
SectionNumber: 1
|
||||
SimpleType: IMAGE_SYM_TYPE_NULL
|
||||
ComplexType: IMAGE_SYM_DTYPE_FUNCTION
|
||||
StorageClass: IMAGE_SYM_CLASS_EXTERNAL
|
||||
...
|
|
@ -0,0 +1,25 @@
|
|||
---
|
||||
header:
|
||||
Machine: IMAGE_FILE_MACHINE_I386
|
||||
Characteristics: [ ]
|
||||
sections:
|
||||
- Name: .text
|
||||
Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
|
||||
Alignment: 16
|
||||
SectionData: 0011223344556677
|
||||
symbols:
|
||||
- Name: .text
|
||||
Value: 0
|
||||
SectionNumber: 1
|
||||
SimpleType: IMAGE_SYM_TYPE_NULL
|
||||
ComplexType: IMAGE_SYM_DTYPE_NULL
|
||||
StorageClass: IMAGE_SYM_CLASS_STATIC
|
||||
NumberOfAuxSymbols: 1
|
||||
AuxiliaryData: 0700000000000000C979F796000006000000
|
||||
- Name: "_foo"
|
||||
Value: 6
|
||||
SectionNumber: 1
|
||||
SimpleType: IMAGE_SYM_TYPE_NULL
|
||||
ComplexType: IMAGE_SYM_DTYPE_FUNCTION
|
||||
StorageClass: IMAGE_SYM_CLASS_EXTERNAL
|
||||
...
|
|
@ -0,0 +1,24 @@
|
|||
# RUN: yaml2obj %p/Inputs/merge-largest1.obj.yaml > %t1.obj
|
||||
# RUN: yaml2obj %p/Inputs/merge-largest2.obj.yaml > %t2.obj
|
||||
#
|
||||
# RUN: lld -flavor link /out:%t.exe /subsystem:console /opt:noref /force \
|
||||
# RUN: -- %t1.obj %t2.obj 2>&1 > %t.log
|
||||
#
|
||||
# FileCheck complains if the input files is empty, so add a dummy line.
|
||||
# RUN: echo foo >> %t.log
|
||||
# RUN: FileCheck -check-prefix=STDERR %s < %t.log
|
||||
#
|
||||
# RUN: llvm-readobj -sections %t.exe | FileCheck -check-prefix=READOBJ %s
|
||||
|
||||
STDERR-NOT: duplicate symbol error
|
||||
|
||||
READOBJ: Format: COFF-i386
|
||||
READOBJ-NEXT: Arch: i386
|
||||
READOBJ-NEXT: AddressSize: 32bit
|
||||
READOBJ-NEXT: Sections [
|
||||
READOBJ-NEXT: Section {
|
||||
READOBJ-NEXT: Number: 1
|
||||
READOBJ-NEXT: Name: .text (2E 74 65 78 74 00 00 00)
|
||||
READOBJ-NEXT: VirtualSize: 0x8
|
||||
READOBJ-NEXT: VirtualAddress: 0x1000
|
||||
READOBJ-NEXT: RawDataSize: 8
|
Loading…
Reference in New Issue