Index: ELF/Config.h =================================================================== --- ELF/Config.h +++ ELF/Config.h @@ -75,6 +75,7 @@ llvm::StringRef LtoNewPmPasses; llvm::StringRef OutputFile; llvm::StringRef SoName; + llvm::StringRef SortSection; llvm::StringRef Sysroot; std::string RPath; std::vector VersionDefinitions; Index: ELF/Driver.cpp =================================================================== --- ELF/Driver.cpp +++ ELF/Driver.cpp @@ -461,6 +461,7 @@ Config->LtoNewPmPasses = getString(Args, OPT_lto_newpm_passes); Config->OutputFile = getString(Args, OPT_o); Config->SoName = getString(Args, OPT_soname); + Config->SortSection = getString(Args, OPT_sort_section); Config->Sysroot = getString(Args, OPT_sysroot); Config->Optimize = getInteger(Args, OPT_O, 1); Index: ELF/LinkerScript.h =================================================================== --- ELF/LinkerScript.h +++ ELF/LinkerScript.h @@ -95,7 +95,7 @@ ConstraintKind Constraint = ConstraintKind::NoConstraint; }; -enum SortKind { SortNone, SortByPriority, SortByName, SortByAlignment }; +enum SortKind { SortNone = 1, SortByPriority, SortByName, SortByAlignment }; struct InputSectionDescription : BaseCommand { InputSectionDescription(StringRef FilePattern) @@ -103,8 +103,8 @@ FileRe(compileGlobPatterns({FilePattern})) {} static bool classof(const BaseCommand *C); llvm::Regex FileRe; - SortKind SortOuter = SortNone; - SortKind SortInner = SortNone; + unsigned SortOuter = 0; + unsigned SortInner = 0; llvm::Regex ExcludedFileRe; llvm::Regex SectionRe; }; Index: ELF/LinkerScript.cpp =================================================================== --- ELF/LinkerScript.cpp +++ ELF/LinkerScript.cpp @@ -196,9 +196,11 @@ if (!matchConstraints(V, OutCmd.Constraint)) continue; if (Cmd->SortInner) - std::stable_sort(V.begin(), V.end(), getComparator(Cmd->SortInner)); + std::stable_sort(V.begin(), V.end(), + getComparator((SortKind)Cmd->SortInner)); if (Cmd->SortOuter) - std::stable_sort(V.begin(), V.end(), getComparator(Cmd->SortOuter)); + std::stable_sort(V.begin(), V.end(), + getComparator((SortKind)Cmd->SortOuter)); // Add all input sections corresponding to rule 'Cmd' to // resulting vector. We do not add duplicate input sections. @@ -689,7 +691,7 @@ Regex readFilePatterns(); InputSectionDescription *readInputSectionRules(StringRef FilePattern); unsigned readPhdrType(); - SortKind readSortKind(); + unsigned readSortKind(); SymbolAssignment *readProvideHidden(bool Provide, bool Hidden); SymbolAssignment *readProvideOrAssignment(StringRef Tok, bool MakeAbsolute); void readSort(); @@ -971,16 +973,51 @@ return compileGlobPatterns(V); } -SortKind ScriptParser::readSortKind() { +unsigned ScriptParser::readSortKind() { if (skip("SORT") || skip("SORT_BY_NAME")) return SortByName; if (skip("SORT_BY_ALIGNMENT")) return SortByAlignment; + if (skip("SORT_NONE")) + return SortNone; if (skip("SORT_BY_INIT_PRIORITY")) return SortByPriority; + return 0; +} + +static SortKind getSortKind() { + if (Config->SortSection == "alignment") + return SortByAlignment; + if (Config->SortSection == "name") + return SortByName; + if (!Config->SortSection.empty()) + warning("unknown --sort-section rule ignored: " + Config->SortSection); return SortNone; } +static void applySortKind(InputSectionDescription *Cmd) { + // `SORT_NONE' disables section sorting by ignoring the command line + // section sorting option. + if (Cmd->SortOuter == SortNone) { + Cmd->SortOuter = 0; + return; + } + + if (Cmd->SortOuter != SortNone) { + // If the section sorting command in linker script is nested, the command + // line option will be ignored. + if (Cmd->SortInner != SortNone) + return; + // If the section sorting command in linker script isn't nested, the + // command line option will make the section sorting command to be treated + // as nested sorting command. + Cmd->SortInner = getSortKind(); + return; + } + // If sorting rule not specified, use command line option. + Cmd->SortOuter = getSortKind(); +} + InputSectionDescription * ScriptParser::readInputSectionRules(StringRef FilePattern) { auto *Cmd = new InputSectionDescription(FilePattern); @@ -993,10 +1030,10 @@ } // Read SORT(). - if (SortKind K1 = readSortKind()) { + if (unsigned K1 = readSortKind()) { Cmd->SortOuter = K1; expect("("); - if (SortKind K2 = readSortKind()) { + if (unsigned K2 = readSortKind()) { Cmd->SortInner = K2; expect("("); Cmd->SectionRe = readFilePatterns(); @@ -1005,9 +1042,11 @@ Cmd->SectionRe = readFilePatterns(); } expect(")"); + applySortKind(Cmd); return Cmd; } + applySortKind(Cmd); Cmd->SectionRe = readFilePatterns(); return Cmd; } Index: ELF/Options.td =================================================================== --- ELF/Options.td +++ ELF/Options.td @@ -160,6 +160,8 @@ def soname: J<"soname=">, HelpText<"Set DT_SONAME">; +def sort_section: S<"sort-section">, HelpText<"Specifies sections sorting rule when linkerscript is used">; + def start_lib: F<"start-lib">, HelpText<"Start a grouping of objects that should be treated as if they were together in an archive">; Index: test/ELF/linkerscript/sort-nested.s =================================================================== --- test/ELF/linkerscript/sort-nested.s +++ test/ELF/linkerscript/sort-nested.s @@ -23,6 +23,16 @@ # SORTED_NA: 02000000 00000000 00000000 00000000 # SORTED_NA: 55000000 00000000 +## If the section sorting command in linker script isn't nested, the +## command line option will make the section sorting command to be treated +## as nested sorting command. +# RUN: echo "SECTIONS { .aaa : { *(SORT_BY_ALIGNMENT(.aaa.*)) } }" > %t3.script +# RUN: ld.lld --sort-section name -o %t3 --script %t3.script %t1.o %t2.o +# RUN: llvm-objdump -s %t3 | FileCheck -check-prefix=SORTED_AN %s +# RUN: echo "SECTIONS { .aaa : { *(SORT_BY_NAME(.aaa.*)) } }" > %t4.script +# RUN: ld.lld --sort-section alignment -o %t4 --script %t4.script %t1.o %t2.o +# RUN: llvm-objdump -s %t4 | FileCheck -check-prefix=SORTED_NA %s + .global _start _start: nop Index: test/ELF/linkerscript/sort.s =================================================================== --- test/ELF/linkerscript/sort.s +++ test/ELF/linkerscript/sort.s @@ -66,6 +66,27 @@ # SORTED_ALIGNMENT-NEXT: 0180 44000000 00000000 01000000 00000000 # SORTED_ALIGNMENT-NEXT: 0190 55000000 00000000 +## SORT_NONE itself does not sort anything. +# RUN: echo "SECTIONS { .aaa : { *(SORT_NONE(.aaa.*)) } }" > %t6.script +# RUN: ld.lld -o %t7 --script %t6.script %t2.o %t1.o +# RUN: llvm-objdump -s %t7 | FileCheck -check-prefix=UNSORTED %s + +## Check --sort-section alignment option. +# RUN: echo "SECTIONS { .aaa : { *(.aaa.*) } }" > %t7.script +# RUN: ld.lld --sort-section alignment -o %t8 --script %t7.script %t1.o %t2.o +# RUN: llvm-objdump -s %t8 | FileCheck -check-prefix=SORTED_ALIGNMENT %s + +## Check --sort-section name option. +# RUN: echo "SECTIONS { .aaa : { *(.aaa.*) } }" > %t8.script +# RUN: ld.lld --sort-section name -o %t9 --script %t8.script %t1.o %t2.o +# RUN: llvm-objdump -s %t9 | FileCheck -check-prefix=SORTED_B %s + +## SORT_NONE disables the --sort-section. +# RUN: echo "SECTIONS { .aaa : { *(SORT_NONE(.aaa.*)) } }" > %t9.script +# RUN: ld.lld --sort-section name -o %t10 --script %t9.script %t2.o %t1.o +# RUN: llvm-objdump -s %t10 | FileCheck -check-prefix=UNSORTED %s + + .global _start _start: nop