diff options
Diffstat (limited to 'lld/COFF/InputFiles.cpp')
-rw-r--r-- | lld/COFF/InputFiles.cpp | 201 |
1 files changed, 103 insertions, 98 deletions
diff --git a/lld/COFF/InputFiles.cpp b/lld/COFF/InputFiles.cpp index ba46184a62f..1ebb5da1b71 100644 --- a/lld/COFF/InputFiles.cpp +++ b/lld/COFF/InputFiles.cpp @@ -384,6 +384,107 @@ Symbol *ObjFile::createUndefined(COFFSymbolRef Sym) { return Symtab->addUndefined(Name, this, Sym.isWeakExternal()); } +void ObjFile::handleComdatSelection(COFFSymbolRef Sym, COMDATType &Selection, + bool &Prevailing, DefinedRegular *Leader) { + if (Prevailing) + return; + // There's already an existing comdat for this symbol: `Leader`. + // Use the comdats's selection field to determine if the new + // symbol in `Sym` should be discarded, produce a duplicate symbol + // error, etc. + + SectionChunk *LeaderChunk = nullptr; + COMDATType LeaderSelection = IMAGE_COMDAT_SELECT_ANY; + + if (Leader->Data) { + LeaderChunk = Leader->getChunk(); + LeaderSelection = LeaderChunk->Selection; + } else { + // FIXME: comdats from LTO files don't know their selection; treat them + // as "any". + Selection = LeaderSelection; + } + + if ((Selection == IMAGE_COMDAT_SELECT_ANY && + LeaderSelection == IMAGE_COMDAT_SELECT_LARGEST) || + (Selection == IMAGE_COMDAT_SELECT_LARGEST && + LeaderSelection == IMAGE_COMDAT_SELECT_ANY)) { + // cl.exe picks "any" for vftables when building with /GR- and + // "largest" when building with /GR. To be able to link object files + // compiled with each flag, "any" and "largest" are merged as "largest". + LeaderSelection = Selection = IMAGE_COMDAT_SELECT_LARGEST; + } + + // Other than that, comdat selections must match. This is a bit more + // strict than link.exe which allows merging "any" and "largest" if "any" + // is the first symbol the linker sees, and it allows merging "largest" + // with everything (!) if "largest" is the first symbol the linker sees. + // Making this symmetric independent of which selection is seen first + // seems better though. + // (This behavior matches ModuleLinker::getComdatResult().) + if (Selection != LeaderSelection) { + log(("conflicting comdat type for " + toString(*Leader) + ": " + + Twine((int)LeaderSelection) + " in " + toString(Leader->getFile()) + + " and " + Twine((int)Selection) + " in " + toString(this)) + .str()); + Symtab->reportDuplicate(Leader, this); + return; + } + + switch (Selection) { + case IMAGE_COMDAT_SELECT_NODUPLICATES: + Symtab->reportDuplicate(Leader, this); + break; + + case IMAGE_COMDAT_SELECT_ANY: + // Nothing to do. + break; + + case IMAGE_COMDAT_SELECT_SAME_SIZE: + if (LeaderChunk->getSize() != getSection(Sym)->SizeOfRawData) + Symtab->reportDuplicate(Leader, this); + break; + + case IMAGE_COMDAT_SELECT_EXACT_MATCH: { + SectionChunk NewChunk(this, getSection(Sym)); + // link.exe only compares section contents here and doesn't complain + // if the two comdat sections have e.g. different alignment. + // Match that. + if (LeaderChunk->getContents() != NewChunk.getContents()) + Symtab->reportDuplicate(Leader, this); + break; + } + + case IMAGE_COMDAT_SELECT_ASSOCIATIVE: + // createDefined() is never called for IMAGE_COMDAT_SELECT_ASSOCIATIVE. + // (This means lld-link doesn't produce duplicate symbol errors for + // associative comdats while link.exe does, but associate comdats + // are never extern in practice.) + llvm_unreachable("createDefined not called for associative comdats"); + + case IMAGE_COMDAT_SELECT_LARGEST: + if (LeaderChunk->getSize() < getSection(Sym)->SizeOfRawData) { + // Replace the existing comdat symbol with the new one. + StringRef Name; + COFFObj->getSymbolName(Sym, Name); + // FIXME: This is incorrect: With /opt:noref, the previous sections + // make it into the final executable as well. Correct handling would + // be to undo reading of the whole old section that's being replaced, + // or doing one pass that determines what the final largest comdat + // is for all IMAGE_COMDAT_SELECT_LARGEST comdats and then reading + // only the largest one. + replaceSymbol<DefinedRegular>(Leader, this, Name, /*IsCOMDAT*/ true, + /*IsExternal*/ true, Sym.getGeneric(), + nullptr); + Prevailing = true; + } + break; + + case IMAGE_COMDAT_SELECT_NEWEST: + llvm_unreachable("should have been rejected earlier"); + } +} + Optional<Symbol *> ObjFile::createDefined( COFFSymbolRef Sym, std::vector<const coff_aux_section_definition *> &ComdatDefs, @@ -463,104 +564,8 @@ Optional<Symbol *> ObjFile::createDefined( } COMDATType Selection = (COMDATType)Def->Selection; - if (!Prevailing && Leader->isCOMDAT()) { - // There's already an existing comdat for this symbol: `Leader`. - // Use the comdats's selection field to determine if the new - // symbol in `Sym` should be discarded, produce a duplicate symbol - // error, etc. - - SectionChunk *LeaderChunk = nullptr; - COMDATType LeaderSelection = IMAGE_COMDAT_SELECT_ANY; - - if (Leader->Data) { - LeaderChunk = Leader->getChunk(); - LeaderSelection = LeaderChunk->Selection; - } else { - // FIXME: comdats from LTO files don't know their selection; treat them - // as "any". - Selection = LeaderSelection; - } - - if ((Selection == IMAGE_COMDAT_SELECT_ANY && - LeaderSelection == IMAGE_COMDAT_SELECT_LARGEST) || - (Selection == IMAGE_COMDAT_SELECT_LARGEST && - LeaderSelection == IMAGE_COMDAT_SELECT_ANY)) { - // cl.exe picks "any" for vftables when building with /GR- and - // "largest" when building with /GR. To be able to link object files - // compiled with each flag, "any" and "largest" are merged as "largest". - LeaderSelection = Selection = IMAGE_COMDAT_SELECT_LARGEST; - } - - // Other than that, comdat selections must match. This is a bit more - // strict than link.exe which allows merging "any" and "largest" if "any" - // is the first symbol the linker sees, and it allows merging "largest" - // with everything (!) if "largest" is the first symbol the linker sees. - // Making this symmetric independent of which selection is seen first - // seems better though. - // (This behavior matches ModuleLinker::getComdatResult().) - if (Selection != LeaderSelection) { - std::string Msg = ("conflicting comdat type for " + toString(*Leader) + - ": " + Twine((int)LeaderSelection) + " in " + - toString(Leader->getFile()) + " and " + - Twine((int)Selection) + " in " + toString(this)) - .str(); - if (Config->ForceMultiple) - warn(Msg); - else - error(Msg); - } - - switch (Selection) { - case IMAGE_COMDAT_SELECT_NODUPLICATES: - Symtab->reportDuplicate(Leader, this); - break; - - case IMAGE_COMDAT_SELECT_ANY: - // Nothing to do. - break; - - case IMAGE_COMDAT_SELECT_SAME_SIZE: - if (LeaderChunk->getSize() != getSection(SectionNumber)->SizeOfRawData) - Symtab->reportDuplicate(Leader, this); - break; - - case IMAGE_COMDAT_SELECT_EXACT_MATCH: { - SectionChunk NewChunk(this, getSection(SectionNumber)); - // link.exe only compares section contents here and doesn't complain - // if the two comdat sections have e.g. different alignment. - // Match that. - if (LeaderChunk->getContents() != NewChunk.getContents()) - Symtab->reportDuplicate(Leader, this); - break; - } - - case IMAGE_COMDAT_SELECT_ASSOCIATIVE: - // createDefined() is never called for IMAGE_COMDAT_SELECT_ASSOCIATIVE. - // (This means lld-link doesn't produce duplicate symbol errors for - // associative comdats while link.exe does, but associate comdats - // are never extern in practice.) - llvm_unreachable("createDefined not called for associative comdats"); - - case IMAGE_COMDAT_SELECT_LARGEST: - if (LeaderChunk->getSize() < getSection(SectionNumber)->SizeOfRawData) { - // Replace the existing comdat symbol with the new one. - // FIXME: This is incorrect: With /opt:noref, the previous sections - // make it into the final executable as well. Correct handling would - // be to undo reading of the whole old section that's being replaced, - // or doing one pass that determines what the final largest comdat - // is for all IMAGE_COMDAT_SELECT_LARGEST comdats and then reading - // only the largest one. - replaceSymbol<DefinedRegular>( - Leader, this, GetName(), /*IsCOMDAT*/ true, - /*IsExternal*/ true, Sym.getGeneric(), nullptr); - Prevailing = true; - } - break; - - case IMAGE_COMDAT_SELECT_NEWEST: - llvm_unreachable("should have been rejected earlier"); - } - } + if (Leader->isCOMDAT()) + handleComdatSelection(Sym, Selection, Prevailing, Leader); if (Prevailing) { SectionChunk *C = readSection(SectionNumber, Def, GetName()); |