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, SortByName, SortByAlignment }; +enum SortKind { SortNone, SortDisabled, SortByName, SortByAlignment }; struct InputSectionDescription : BaseCommand { InputSectionDescription(StringRef FilePattern) Index: ELF/LinkerScript.cpp =================================================================== --- ELF/LinkerScript.cpp +++ ELF/LinkerScript.cpp @@ -967,9 +967,44 @@ return SortByName; if (skip("SORT_BY_ALIGNMENT")) return SortByAlignment; + if (skip("SORT_NONE")) + return SortDisabled; return SortNone; } +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 == SortDisabled) { + Cmd->SortOuter = SortNone; + 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); @@ -994,9 +1029,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