Index: COFF/Chunks.h =================================================================== --- COFF/Chunks.h +++ COFF/Chunks.h @@ -150,7 +150,8 @@ Symbol *operator*() const { return File->getSymbol(I->SymbolTableIndex); } }; - SectionChunk(ObjFile *File, const coff_section *Header); + SectionChunk(ObjFile *File, const coff_section *Header, + uint32_t SectionNumber); static bool classof(const Chunk *C) { return C->kind() == SectionKind; } void readRelocTargets() override; void resetRelocTargets() override; @@ -206,7 +207,7 @@ // A pointer pointing to a replacement for this chunk. // Initially it points to "this" object. If this chunk is merged // with other chunk by ICF, it points to another chunk, - // and this chunk is considrered as dead. + // and this chunk is considered as dead. SectionChunk *Repl; // The CRC of the contents as described in the COFF spec 4.5.5. @@ -215,6 +216,9 @@ const coff_section *Header; + // The section index this chunk belongs to in its Obj. + uint32_t SectionNumber; + // The file that this chunk was created from. ObjFile *File; Index: COFF/Chunks.cpp =================================================================== --- COFF/Chunks.cpp +++ COFF/Chunks.cpp @@ -29,8 +29,8 @@ namespace lld { namespace coff { -SectionChunk::SectionChunk(ObjFile *F, const coff_section *H) - : Chunk(SectionKind), Repl(this), Header(H), File(F), +SectionChunk::SectionChunk(ObjFile *F, const coff_section *H, uint32_t N) + : Chunk(SectionKind), Repl(this), Header(H), SectionNumber(N), File(F), Relocs(File->getCOFFObj()->getRelocations(Header)) { // Initialize SectionName. File->getCOFFObj()->getSectionName(Header, SectionName); Index: COFF/InputFiles.cpp =================================================================== --- COFF/InputFiles.cpp +++ COFF/InputFiles.cpp @@ -182,7 +182,7 @@ if (Sec->Characteristics & llvm::COFF::IMAGE_SCN_LNK_REMOVE) return nullptr; - auto *C = make(this, Sec); + auto *C = make(this, Sec, SectionNumber); if (Def) C->Checksum = Def->CheckSum; Index: COFF/Writer.cpp =================================================================== --- COFF/Writer.cpp +++ COFF/Writer.cpp @@ -192,6 +192,7 @@ void writeSections(); void writeBuildId(); void sortExceptionTable(); + void sortSectionChunks(std::vector &Chunks); llvm::Optional createSymbol(Defined *D); size_t addEntryToStringTable(StringRef Str); @@ -736,9 +737,21 @@ // sections are treated as if they have output characteristics DATA | R if // their characteristics are DATA | R | W. This implements the same special // case for all architectures. - if (Name == ".CRT") + if (Name == ".CRT") { OutChars = DATA | R; + // The CRT section contains, among other things, the array of function + // pointers that initialize every global variable that is not trivially + // constructed. The CRT calls them one after the other prior to invoking + // main(). + // + // It is therefore critical to sort the chunks containing the function + // pointers in the order that they are listed in the object file, + // otherwise global objects might not be initialized in the correct + // order. + sortSectionChunks(Pair.second); + } + OutputSection *Sec = CreateSection(Name, OutChars); std::vector &Chunks = Pair.second; for (Chunk *C : Chunks) @@ -1577,6 +1590,31 @@ errs() << "warning: don't know how to handle .pdata.\n"; } +void Writer::sortSectionChunks(std::vector &Chunks) { + if (Chunks.size() > 1) { + auto SectionChunkOrder = [](const Chunk *A, const Chunk *B) { + auto SA = dyn_cast(A); + auto SB = dyn_cast(B); + if (SA && SB) { + StringRef SAObj = SA->File->MB.getBufferIdentifier(); + StringRef SBObj = SB->File->MB.getBufferIdentifier(); + switch (SAObj.compare(SBObj)) { + case -1: + return true; + case 1: + return false; + case 0: + return SA->SectionNumber < SB->SectionNumber; + } + } + // Normally, there should not be any non-section chunks in the .CRT + // sections, but if that happens move them at the end of the section. + return SA != nullptr; + }; + sort(parallel::par, Chunks.begin(), Chunks.end(), SectionChunkOrder); + } +} + OutputSection *Writer::findSection(StringRef Name) { for (OutputSection *Sec : OutputSections) if (Sec->Name == Name) Index: test/COFF/crt-dyn-initializer-order.test =================================================================== --- test/COFF/crt-dyn-initializer-order.test +++ test/COFF/crt-dyn-initializer-order.test @@ -0,0 +1,77 @@ + +# // a.cpp +# #include +# #include +# +# template struct TemplatedObject { +# static std::vector *> Instances; +# TemplatedObject() { Instances.push_back(this); } +# }; +# +# using Object = TemplatedObject<0>; +# template <> std::vector Object::Instances{}; +# Object idle{}; +# +# int main() { +# if (Object::Instances.size() == 0) +# std::cout << "It's broken" << std::endl; +# else +# std::cout << "It works!" << std::endl; +# return 0; +# } +# // using `clang-cl /c a.cpp | lld-link a.obj` works +# // using `cl /c a.cpp | lld-link a.obj` fails without lld/COFF/Writer.cpp/Writer::sortSectionChunks() + +# RUN: yaml2obj %s > %t.obj +# RUN: lld-link /out:%t.dll /entry:__ImageBase /dll %t.obj +# RUN: llvm-readobj -sections -section-data %t.dll | FileCheck %s + +# CHECK: Name: .CRT +# CHECK: Characteristics [ +# CHECK-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA +# CHECK-NEXT: IMAGE_SCN_MEM_READ +# CHECK-NEXT: ] +# CHECK-NEXT: SectionData ( +# CHECK-NEXT: 01020304 05 +# CHECK-NEXT: ) + +--- !COFF +header: + Machine: IMAGE_FILE_MACHINE_AMD64 + Characteristics: [ ] +sections: + - Name: '.CRT$XCA' + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ] + Alignment: 1 + SectionData: 01 + - Name: '.CRT$XCU' + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ] + Alignment: 1 + SectionData: 02 + - Name: '.CRT$XCU' + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_LNK_COMDAT ] + Alignment: 1 + SectionData: 03 + - Name: '.CRT$XCU' + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ] + Alignment: 1 + SectionData: 04 + - Name: '.CRT$XCZ' + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ] + Alignment: 1 + SectionData: 05 +symbols: + - Name: '.CRT$XCU' + Value: 0 + SectionNumber: 3 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 1 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 1 + Number: 2 + Selection: IMAGE_COMDAT_SELECT_ASSOCIATIVE +...