forked from OSchip/llvm-project
[PECOFF] Support COMDAT associative sections.
COFF supports a feature similar to ELF's section groups. This patch implements it. In ELF, section groups are identified by their names, and they are treated somewhat differently from regular symbols. In COFF, the feature is realized in a more straightforward way. A section can have an annotation saying "if Nth section is linked, link this section too." I added a new reference type, kindAssociate. If a target atom is coalesced away, the referring atom is removed by Resolver, so that they are treated as a group. Differential Revision: http://reviews.llvm.org/D4028 llvm-svn: 211106
This commit is contained in:
parent
8d7ab8c617
commit
61d7f97000
|
@ -91,6 +91,7 @@ public:
|
|||
kindLayoutBefore = 3,
|
||||
// kindGroupChild is treated as a bidirected edge too.
|
||||
kindGroupChild = 4,
|
||||
kindAssociate = 5,
|
||||
};
|
||||
|
||||
// A value to be added to the value of a target
|
||||
|
|
|
@ -105,6 +105,7 @@ private:
|
|||
std::vector<const Atom *> _atoms;
|
||||
std::set<const Atom *> _deadStripRoots;
|
||||
llvm::DenseSet<const Atom *> _liveAtoms;
|
||||
llvm::DenseSet<const Atom *> _deadAtoms;
|
||||
std::unique_ptr<MergedFile> _result;
|
||||
llvm::DenseMap<const Atom *, llvm::DenseSet<const Atom *>> _reverseRef;
|
||||
};
|
||||
|
|
|
@ -277,6 +277,16 @@ void Resolver::updateReferences() {
|
|||
for (const Atom *atom : _atoms) {
|
||||
if (const DefinedAtom *defAtom = dyn_cast<DefinedAtom>(atom)) {
|
||||
for (const Reference *ref : *defAtom) {
|
||||
// A reference of type kindAssociate should't be updated.
|
||||
// Instead, an atom having such reference will be removed
|
||||
// if the target atom is coalesced away, so that they will
|
||||
// go away as a group.
|
||||
if (ref->kindNamespace() == lld::Reference::KindNamespace::all &&
|
||||
ref->kindValue() == lld::Reference::kindAssociate) {
|
||||
if (_symbolTable.isCoalescedAway(atom))
|
||||
_deadAtoms.insert(ref->target());
|
||||
continue;
|
||||
}
|
||||
const Atom *newTarget = _symbolTable.replacement(ref->target());
|
||||
const_cast<Reference *>(ref)->setTarget(newTarget);
|
||||
}
|
||||
|
@ -399,7 +409,7 @@ bool Resolver::checkUndefines() {
|
|||
void Resolver::removeCoalescedAwayAtoms() {
|
||||
ScopedTask task(getDefaultDomain(), "removeCoalescedAwayAtoms");
|
||||
_atoms.erase(std::remove_if(_atoms.begin(), _atoms.end(), [&](const Atom *a) {
|
||||
return _symbolTable.isCoalescedAway(a);
|
||||
return _symbolTable.isCoalescedAway(a) || _deadAtoms.count(a);
|
||||
}),
|
||||
_atoms.end());
|
||||
}
|
||||
|
|
|
@ -158,7 +158,6 @@ public:
|
|||
}
|
||||
|
||||
void setAlignment(Alignment val) { _alignment = val; }
|
||||
|
||||
SectionChoice sectionChoice() const override { return sectionCustomRequired; }
|
||||
StringRef customSectionName() const override { return _sectionName; }
|
||||
Scope scope() const override { return _scope; }
|
||||
|
@ -167,6 +166,13 @@ public:
|
|||
uint64_t ordinal() const override { return _ordinal; }
|
||||
Alignment alignment() const override { return _alignment; }
|
||||
|
||||
void addAssociate(const DefinedAtom *other) {
|
||||
auto *ref = new COFFReference(other, 0, lld::Reference::kindAssociate,
|
||||
Reference::KindNamespace::all,
|
||||
Reference::KindArch::all);
|
||||
addReference(std::unique_ptr<COFFReference>(ref));
|
||||
}
|
||||
|
||||
private:
|
||||
StringRef _sectionName;
|
||||
Scope _scope;
|
||||
|
|
|
@ -174,6 +174,9 @@ private:
|
|||
// A map to get whether the section allows its contents to be merged or not.
|
||||
std::map<const coff_section *, DefinedAtom::Merge> _merge;
|
||||
|
||||
// COMDAT associative sections
|
||||
std::map<const coff_section *, std::set<const coff_section *>> _association;
|
||||
|
||||
// A sorted map to find an atom from a section and an offset within
|
||||
// the section.
|
||||
std::map<const coff_section *,
|
||||
|
@ -544,6 +547,7 @@ std::error_code FileCOFF::cacheSectionAttributes() {
|
|||
// section. It feels to me that it's unnecessarily complicated, but this is
|
||||
// how COFF works.
|
||||
for (auto i : _auxSymbol) {
|
||||
// Read a section from the file
|
||||
const coff_symbol *sym = i.first;
|
||||
if (sym->SectionNumber == llvm::COFF::IMAGE_SYM_ABSOLUTE ||
|
||||
sym->SectionNumber == llvm::COFF::IMAGE_SYM_UNDEFINED)
|
||||
|
@ -552,19 +556,22 @@ std::error_code FileCOFF::cacheSectionAttributes() {
|
|||
const coff_section *sec;
|
||||
if (std::error_code ec = _obj->getSection(sym->SectionNumber, sec))
|
||||
return ec;
|
||||
|
||||
if (_merge.count(sec))
|
||||
continue;
|
||||
if (!(sec->Characteristics & llvm::COFF::IMAGE_SCN_LNK_COMDAT))
|
||||
continue;
|
||||
|
||||
_comdatSections.insert(sec);
|
||||
|
||||
if (sym->NumberOfAuxSymbols == 0)
|
||||
return llvm::object::object_error::parse_failed;
|
||||
const coff_aux_section_definition *aux =
|
||||
reinterpret_cast<const coff_aux_section_definition *>(i.second);
|
||||
_merge[sec] = getMerge(aux);
|
||||
|
||||
if (sec->Characteristics & llvm::COFF::IMAGE_SCN_LNK_COMDAT) {
|
||||
// Read aux symbol data.
|
||||
_comdatSections.insert(sec);
|
||||
_merge[sec] = getMerge(aux);
|
||||
}
|
||||
|
||||
// Handle associative sections.
|
||||
if (aux->Selection == llvm::COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE) {
|
||||
const coff_section *parent;
|
||||
if (std::error_code ec = _obj->getSection(aux->Number, parent))
|
||||
return ec;
|
||||
_association[parent].insert(sec);
|
||||
}
|
||||
}
|
||||
|
||||
// The sections that does not have auxiliary symbol are regular sections, in
|
||||
|
@ -699,6 +706,29 @@ std::error_code FileCOFF::AtomizeDefinedSymbols(
|
|||
definedAtoms.push_back(atom);
|
||||
}
|
||||
}
|
||||
|
||||
// A COMDAT section with SELECT_ASSOCIATIVE attribute refer to other
|
||||
// section. If the referred section is linked to a binary, the
|
||||
// referring section needs to be linked too. A typical use case of
|
||||
// this attribute is a static initializer; a parent is a comdat BSS
|
||||
// section, and a child is a static initializer code for the data.
|
||||
//
|
||||
// We add referring section contents to the referred section's
|
||||
// associate list, so that Resolver takes care of them.
|
||||
for (auto i : _association) {
|
||||
const coff_section *parent = i.first;
|
||||
const std::set<const coff_section *> &childSections = i.second;
|
||||
assert(_sectionAtoms[parent].size() > 0);
|
||||
|
||||
COFFDefinedFileAtom *p = _sectionAtoms[parent][0];
|
||||
for (const coff_section *sec : childSections) {
|
||||
if (_sectionAtoms.count(sec)) {
|
||||
assert(_sectionAtoms[sec].size() > 0);
|
||||
p->addAssociate(_sectionAtoms[sec][0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return std::error_code();
|
||||
}
|
||||
|
||||
|
|
|
@ -51,6 +51,7 @@ static const Registry::KindStrings kindStrings[] = {
|
|||
{Reference::kindLayoutAfter, "layout-after"},
|
||||
{Reference::kindLayoutBefore, "layout-before"},
|
||||
{Reference::kindGroupChild, "group-child"},
|
||||
{Reference::kindAssociate, "associate"},
|
||||
LLD_KIND_STRING_END};
|
||||
|
||||
Registry::Registry() {
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
# RUN: lld -core %s | FileCheck %s
|
||||
|
||||
---
|
||||
defined-atoms:
|
||||
- name: f1
|
||||
merge: as-weak
|
||||
scope: global
|
||||
references:
|
||||
- kind: associate
|
||||
target: f2
|
||||
- name: f2
|
||||
---
|
||||
defined-atoms:
|
||||
- name: f1
|
||||
merge: as-weak
|
||||
scope: global
|
||||
references:
|
||||
- kind: associate
|
||||
target: f2
|
||||
- name: f2
|
||||
...
|
||||
|
||||
# CHECK: defined-atoms:
|
||||
# CHECK: - name: f1
|
||||
# CHECK: scope: global
|
||||
# CHECK: references:
|
||||
# CHECK: - kind: associate
|
||||
# CHECK: target: f2
|
||||
# CHECK: - name: f2
|
||||
# CHECK-NOT: - name: f2
|
|
@ -0,0 +1,53 @@
|
|||
---
|
||||
header:
|
||||
Machine: IMAGE_FILE_MACHINE_I386
|
||||
Characteristics: []
|
||||
sections:
|
||||
- Name: .data
|
||||
Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
|
||||
Alignment: 4
|
||||
SectionData: 00000000
|
||||
- Name: '.CRT$XCU'
|
||||
Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
|
||||
Alignment: 4
|
||||
SectionData: 77777777
|
||||
symbols:
|
||||
- Name: .data
|
||||
Value: 0
|
||||
SectionNumber: 1
|
||||
SimpleType: IMAGE_SYM_TYPE_NULL
|
||||
ComplexType: IMAGE_SYM_DTYPE_NULL
|
||||
StorageClass: IMAGE_SYM_CLASS_STATIC
|
||||
SectionDefinition:
|
||||
Length: 4
|
||||
NumberOfRelocations: 0
|
||||
NumberOfLinenumbers: 0
|
||||
CheckSum: 0
|
||||
Number: 0
|
||||
Selection: IMAGE_COMDAT_SELECT_ANY
|
||||
- Name: _var
|
||||
Value: 0
|
||||
SectionNumber: 1
|
||||
SimpleType: IMAGE_SYM_TYPE_NULL
|
||||
ComplexType: IMAGE_SYM_DTYPE_NULL
|
||||
StorageClass: IMAGE_SYM_CLASS_EXTERNAL
|
||||
- Name: '.CRT$XCU'
|
||||
Value: 0
|
||||
SectionNumber: 2
|
||||
SimpleType: IMAGE_SYM_TYPE_NULL
|
||||
ComplexType: IMAGE_SYM_DTYPE_NULL
|
||||
StorageClass: IMAGE_SYM_CLASS_STATIC
|
||||
SectionDefinition:
|
||||
Length: 4
|
||||
NumberOfRelocations: 0
|
||||
NumberOfLinenumbers: 0
|
||||
CheckSum: 0
|
||||
Number: 1
|
||||
Selection: IMAGE_COMDAT_SELECT_ASSOCIATIVE
|
||||
- Name: _init
|
||||
Value: 0
|
||||
SectionNumber: 2
|
||||
SimpleType: IMAGE_SYM_TYPE_NULL
|
||||
ComplexType: IMAGE_SYM_DTYPE_NULL
|
||||
StorageClass: IMAGE_SYM_CLASS_EXTERNAL
|
||||
...
|
|
@ -0,0 +1,33 @@
|
|||
---
|
||||
header:
|
||||
Machine: IMAGE_FILE_MACHINE_I386
|
||||
Characteristics: []
|
||||
sections:
|
||||
- Name: .text
|
||||
Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
|
||||
Alignment: 4
|
||||
SectionData: 0000000000000000
|
||||
Relocations:
|
||||
- VirtualAddress: 4
|
||||
SymbolName: _var
|
||||
Type: IMAGE_REL_I386_DIR32
|
||||
symbols:
|
||||
- Name: .text
|
||||
Value: 0
|
||||
SectionNumber: 1
|
||||
SimpleType: IMAGE_SYM_TYPE_NULL
|
||||
ComplexType: IMAGE_SYM_DTYPE_NULL
|
||||
StorageClass: IMAGE_SYM_CLASS_STATIC
|
||||
- Name: _main
|
||||
Value: 0
|
||||
SectionNumber: 1
|
||||
SimpleType: IMAGE_SYM_TYPE_NULL
|
||||
ComplexType: IMAGE_SYM_DTYPE_NULL
|
||||
StorageClass: IMAGE_SYM_CLASS_EXTERNAL
|
||||
- Name: _var
|
||||
Value: 0
|
||||
SectionNumber: 0
|
||||
SimpleType: IMAGE_SYM_TYPE_NULL
|
||||
ComplexType: IMAGE_SYM_DTYPE_NULL
|
||||
StorageClass: IMAGE_SYM_CLASS_EXTERNAL
|
||||
...
|
|
@ -0,0 +1,10 @@
|
|||
# RUN: yaml2obj %p/Inputs/associative1.obj.yaml > %t1.obj
|
||||
# RUN: yaml2obj %p/Inputs/associative1.obj.yaml > %t2.obj
|
||||
# RUN: yaml2obj %p/Inputs/associative3.obj.yaml > %t3.obj
|
||||
#
|
||||
# RUN: lld -flavor link /machine:x86 /subsystem:console /entry:main \
|
||||
# RUN: /out:%t.exe -- %t1.obj %t2.obj %t3.obj
|
||||
# RUN: obj2yaml %t.exe | FileCheck %s
|
||||
|
||||
CHECK: - Name: .CRT
|
||||
CHECK: SectionData: '77777777'
|
Loading…
Reference in New Issue