Index: COFF/Writer.cpp =================================================================== --- COFF/Writer.cpp +++ COFF/Writer.cpp @@ -319,16 +319,63 @@ static StringRef getOutputSection(StringRef Name) { StringRef S = Name.split('$').first; + S = S.substr(0, S.find('.', 1)); auto It = Config->Merge.find(S); if (It == Config->Merge.end()) return S; return It->second; } +// Compare sections, taking numerical ordering of sections like +// ".ctors.123" into account, for compatibility with MinGW. +// This does a normal lexical ordering, with two exceptions: +// - Output section names that are followed by a dollar sign are sorted +// after output section names that are followed by a period. This ensures +// the ordering ".ctors", ".ctors.123", ".ctors$zzz". +// - For section names that are followed by a period, order them by the +// numerical value following the period, not by the lexical ordering. +// The ensure that ".ctors.5" gets sorted before ".ctors.123". +static bool orderSections(StringRef A, StringRef B) { + // Initially sort based on what getOutputSections (without the Merge + // remapping) would output. + StringRef SectA = A.split('$').first; + StringRef SectB = B.split('$').first; + SectA = SectA.substr(0, SectA.find('.', 1)); + SectB = SectB.substr(0, SectB.find('.', 1)); + if (SectA != SectB) + return A < B; + // Skip the now known identical output section name, check the suffixes. + A = A.substr(SectA.size()); + B = B.substr(SectB.size()); + // If either of the section names don't have a suffixes, do a normal + // lexical comparison. + if (A.empty() || B.empty()) + return A < B; + bool DollarA = A[0] == '$'; + bool DollarB = B[0] == '$'; + if (DollarA && DollarB) + return A < B; + // If one section has a dollar suffix, sort that after sections that + // don't have it (i.e. have got a period instead). + if (DollarA != DollarB) + return DollarB; + assert(A[0] == '.'); + assert(B[0] == '.'); + // Skip the period in both suffixes. + A = A.substr(1); + B = B.substr(1); + int NumA, NumB; + // If both are parseable as numbers, compare numerically. + if (!A.getAsInteger(10, NumA) && !B.getAsInteger(10, NumB)) + return NumA < NumB; + return A < B; +} + // Create output section objects and add them to OutputSections. void Writer::createSections() { // First, bin chunks by name. - std::map> Map; + std::map, bool (*)(StringRef, StringRef)> Map( + orderSections); for (Chunk *C : Symtab->getChunks()) { auto *SC = dyn_cast(C); if (SC && !SC->isLive()) { Index: test/COFF/ctors_dtors_priority.s =================================================================== --- /dev/null +++ test/COFF/ctors_dtors_priority.s @@ -0,0 +1,34 @@ +# REQUIRES: x86 +# RUN: llvm-mc -triple=x86_64-windows-gnu -filetype=obj -o %t.obj %s +# RUN: lld-link -entry:main %t.obj -out:%t.exe +# RUN: llvm-objdump -s %t.exe | FileCheck %s + +.globl main +main: + nop + +.section .ctors$zzz, "w" + .quad 4 +.section .ctors.5, "w" + .quad 2 +.section .ctors, "w" + .quad 1 +.section .ctors.100, "w" + .quad 3 + +.section .dtors, "w" + .quad 1 +.section .dtors$zzz, "w" + .quad 4 +.section .dtors.100, "w" + .quad 3 +.section .dtors.5, "w" + .quad 2 + +# CHECK: Contents of section .ctors: +# CHECK-NEXT: 140001000 01000000 00000000 02000000 00000000 +# CHECK-NEXT: 140001010 03000000 00000000 04000000 00000000 + +# CHECK: Contents of section .dtors: +# CHECK-NEXT: 140002000 01000000 00000000 02000000 00000000 +# CHECK-NEXT: 140002010 03000000 00000000 04000000 00000000