Index: COFF/Chunks.h =================================================================== --- COFF/Chunks.h +++ COFF/Chunks.h @@ -203,10 +203,13 @@ // Allow iteration over the associated child chunks for this section. ArrayRef children() const { return AssocChildren; } + // The section ID this chunk belongs to in its Obj. + uint32_t getSectionNumber() const; + // 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. Index: COFF/Chunks.cpp =================================================================== --- COFF/Chunks.cpp +++ COFF/Chunks.cpp @@ -585,6 +585,13 @@ Other->Live = false; } +uint32_t SectionChunk::getSectionNumber() const { + DataRefImpl R; + R.p = reinterpret_cast(Header); + SectionRef S(R, File->getCOFFObj()); + return S.getIndex() + 1; +} + CommonChunk::CommonChunk(const COFFSymbolRef S) : Sym(S) { // Common symbols are aligned on natural boundaries up to 32 bytes. // This is what MSVC link.exe does. 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); @@ -732,13 +733,32 @@ StringRef Name = getOutputSectionName(Pair.first.first); uint32_t OutChars = Pair.first.second; + log("Processing section " + Pair.first.first + " -> " + Name); + // In link.exe, there is a special case for the I386 target where .CRT // 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(). + // + // As per C++ spec, 3.6.2/2.3, + // "Variables with ordered initialization defined within a single + // translation unit shall be initialized in the order of their definitions + // in the translation unit" + // + // It is therefore critical to sort the chunks containing the function + // pointers in the order that they are listed in the object file (top to + // bottom), 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 +1597,37 @@ errs() << "warning: don't know how to handle .pdata.\n"; } +void Writer::sortSectionChunks(std::vector &Chunks) { + 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->getSectionNumber() < SB->getSectionNumber(); + } + } + // 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(Chunks, SectionChunkOrder); + + if (Config->Verbose) { + for (auto &C : Chunks) { + auto SC = dyn_cast(C); + log(" " + SC->File->MB.getBufferIdentifier().str() + + ", SectionID: " + Twine(SC->getSectionNumber())); + } + } +} + OutputSection *Writer::findSection(StringRef Name) { for (OutputSection *Sec : OutputSections) if (Sec->Name == Name) Index: test/COFF/Inputs/crt-dyn-initializer-order_1.yaml =================================================================== --- test/COFF/Inputs/crt-dyn-initializer-order_1.yaml +++ test/COFF/Inputs/crt-dyn-initializer-order_1.yaml @@ -0,0 +1,15 @@ +--- !COFF +header: + Machine: IMAGE_FILE_MACHINE_AMD64 + Characteristics: [ ] +sections: + - Name: '.CRT$XCU' + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ] + Alignment: 1 + SectionData: 55 + - Name: '.CRT$XCU' + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ] + Alignment: 1 + SectionData: 70 +symbols: +... Index: test/COFF/Inputs/crt-dyn-initializer-order_2.yaml =================================================================== --- test/COFF/Inputs/crt-dyn-initializer-order_2.yaml +++ test/COFF/Inputs/crt-dyn-initializer-order_2.yaml @@ -0,0 +1,19 @@ +--- !COFF +header: + Machine: IMAGE_FILE_MACHINE_AMD64 + Characteristics: [ ] +sections: + - Name: '.CRT$XCU' + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ] + Alignment: 1 + SectionData: 10 + - Name: '.CRT$XCU' + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ] + Alignment: 1 + SectionData: 11 + - Name: '.CRT$XCU' + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ] + Alignment: 1 + SectionData: 12 +symbols: +... 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,91 @@ +# // 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: yaml2obj %S/Inputs/crt-dyn-initializer-order_1.yaml > %t1.obj +# RUN: yaml2obj %S/Inputs/crt-dyn-initializer-order_2.yaml > %t2.obj + +# RUN: lld-link /out:%t.dll /entry:__ImageBase /dll %t.obj %t1.obj %t2.obj +# RUN: llvm-readobj -sections -section-data %t.dll | FileCheck %s +# RUN: lld-link /out:%t.dll /entry:__ImageBase /dll %t.obj %t2.obj %t1.obj +# RUN: llvm-readobj -sections -section-data %t.dll | FileCheck %s + +# RUN: lld-link /out:%t.dll /entry:__ImageBase /dll %t1.obj %t2.obj %t.obj +# RUN: llvm-readobj -sections -section-data %t.dll | FileCheck %s +# RUN: lld-link /out:%t.dll /entry:__ImageBase /dll %t1.obj %t.obj %t2.obj +# RUN: llvm-readobj -sections -section-data %t.dll | FileCheck %s + +# RUN: lld-link /out:%t.dll /entry:__ImageBase /dll %t2.obj %t1.obj %t.obj +# RUN: llvm-readobj -sections -section-data %t.dll | FileCheck %s +# RUN: lld-link /out:%t.dll /entry:__ImageBase /dll %t2.obj %t.obj %t1.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 55701011 1205 +# 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 +...