From 7ad72ebc5e1429c3a337f7b51d01c6f292bdacdc Mon Sep 17 00:00:00 2001 From: Rui Ueyama Date: Tue, 18 Mar 2014 19:37:50 +0000 Subject: [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 --- lld/lib/Core/SymbolTable.cpp | 59 ++++++++++++++++++++------ lld/lib/ReaderWriter/PECOFF/ReaderCOFF.cpp | 4 +- lld/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp | 1 + 3 files changed, 49 insertions(+), 15 deletions(-) (limited to 'lld/lib') diff --git a/lld/lib/Core/SymbolTable.cpp b/lld/lib/Core/SymbolTable.cpp index add6628096e..9bacdad17d9 100644 --- a/lld/lib/Core/SymbolTable.cpp +++ b/lld/lib/Core/SymbolTable.cpp @@ -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(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: diff --git a/lld/lib/ReaderWriter/PECOFF/ReaderCOFF.cpp b/lld/lib/ReaderWriter/PECOFF/ReaderCOFF.cpp index b5f0de049d5..c32ca9762d9 100644 --- a/lld/lib/ReaderWriter/PECOFF/ReaderCOFF.cpp +++ b/lld/lib/ReaderWriter/PECOFF/ReaderCOFF.cpp @@ -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 diff --git a/lld/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp b/lld/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp index fe3cffdafe4..e4c809f11d2 100644 --- a/lld/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp +++ b/lld/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp @@ -340,6 +340,7 @@ template <> struct ScalarEnumerationTraits { 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); } }; -- cgit v1.2.3