diff --git a/lld/COFF/InputFiles.cpp b/lld/COFF/InputFiles.cpp --- a/lld/COFF/InputFiles.cpp +++ b/lld/COFF/InputFiles.cpp @@ -505,7 +505,13 @@ assert(leader->data && "Comdat leader without SectionChunk?"); leaderChunk = leader->getChunk(); - leaderSelection = leaderChunk->selection; + if (leaderChunk->selection == IMAGE_COMDAT_SELECT_LTO) { + // If the leader is only a LTO symbol, we don't know e.g. its final size + // yet, so we can't do the full strict comdat selection checking yet. + selection = leaderSelection; + } else { + leaderSelection = leaderChunk->selection; + } if ((selection == IMAGE_COMDAT_SELECT_ANY && leaderSelection == IMAGE_COMDAT_SELECT_LARGEST) || @@ -550,6 +556,7 @@ break; case IMAGE_COMDAT_SELECT_ANY: + case IMAGE_COMDAT_SELECT_LTO: // Nothing to do. break; @@ -558,8 +565,10 @@ if (!config->mingw) { symtab->reportDuplicate(leader, this); } else { - const coff_aux_section_definition *leaderDef = findSectionDef( - leaderChunk->file->getCOFFObj(), leaderChunk->getSectionNumber()); + const coff_aux_section_definition *leaderDef = nullptr; + if (leaderChunk->file) + leaderDef = findSectionDef(leaderChunk->file->getCOFFObj(), + leaderChunk->getSectionNumber()); if (!leaderDef || leaderDef->Length != def->Length) symtab->reportDuplicate(leader, this); } @@ -1050,9 +1059,12 @@ class FakeSectionChunk { public: FakeSectionChunk(const coff_section *section) : chunk(nullptr, section) { - // FIXME: comdats from LTO files don't know their selection; treat them - // as "any". - chunk.selection = IMAGE_COMDAT_SELECT_ANY; + // Comdats from LTO files can't be fully treated as regular comdats + // yet; we don't e.g. know what size they are going to have, so we can't + // do proper checking against a regular comdat of type + // IMAGE_COMDAT_SELECT_SAME_SIZE. Therefore, while the symbol isn't yet + // LTO compiled, bail out from the nitpicky part of comdat resolution. + chunk.selection = IMAGE_COMDAT_SELECT_LTO; } SectionChunk chunk; diff --git a/lld/test/COFF/lto-comdat-samesize.ll b/lld/test/COFF/lto-comdat-samesize.ll new file mode 100644 --- /dev/null +++ b/lld/test/COFF/lto-comdat-samesize.ll @@ -0,0 +1,36 @@ +; REQUIRES: x86 + +; RUN: split-file %s %t.dir +; RUN: llvm-as %t.dir/other.ll -o %t.other.bc +; RUN: llc -filetype=obj -o %t.main.obj %t.dir/main.ll + +; RUN: lld-link -out:%t.exe -subsystem:console %t.other.bc %t.main.obj + +#--- main.ll +target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-windows-msvc19.14.0" + +$comdatData = comdat samesize + +@comdatData = weak_odr dso_local global i32 42, comdat + +define dso_local void @mainCRTStartup() { +entry: + tail call void @other() + ret void +} + +declare dso_local void @other() + +#--- other.ll +target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-windows-msvc19.14.0" + +$comdatData = comdat samesize + +@comdatData = weak_odr dso_local global i32 42, comdat + +define dso_local void @other() { +entry: + ret void +} diff --git a/llvm/include/llvm/BinaryFormat/COFF.h b/llvm/include/llvm/BinaryFormat/COFF.h --- a/llvm/include/llvm/BinaryFormat/COFF.h +++ b/llvm/include/llvm/BinaryFormat/COFF.h @@ -410,7 +410,9 @@ IMAGE_COMDAT_SELECT_EXACT_MATCH, IMAGE_COMDAT_SELECT_ASSOCIATIVE, IMAGE_COMDAT_SELECT_LARGEST, - IMAGE_COMDAT_SELECT_NEWEST + IMAGE_COMDAT_SELECT_NEWEST, + // Not a real value in files, but usable as dummy value within LLD. + IMAGE_COMDAT_SELECT_LTO = 0xff }; // Auxiliary Symbol Formats