Index: ELF/Config.h =================================================================== --- ELF/Config.h +++ ELF/Config.h @@ -42,6 +42,9 @@ // For --unresolved-symbols. enum class UnresolvedPolicy { NoUndef, ReportError, Warn, Ignore }; +// For --sort-section and linkerscript sorting rules. +enum class SortSectionPolicy { None, IgnoreConfig, Alignment, Name, Priority }; + struct SymbolVersion { llvm::StringRef Name; bool IsExternCpp; @@ -124,6 +127,7 @@ bool ZOrigin; bool ZRelro; DiscardPolicy Discard; + SortSectionPolicy SortSection; StripPolicy Strip = StripPolicy::None; UnresolvedPolicy UnresolvedSymbols; BuildIdKind BuildId = BuildIdKind::None; Index: ELF/Driver.cpp =================================================================== --- ELF/Driver.cpp +++ ELF/Driver.cpp @@ -407,6 +407,17 @@ return Ret; } +static SortSectionPolicy getSortKind(opt::InputArgList &Args) { + StringRef S = getString(Args, OPT_sort_section); + if (S == "alignment") + return SortSectionPolicy::Alignment; + if (S == "name") + return SortSectionPolicy::Name; + if (!S.empty()) + error("unknown --sort-section rule: " + S); + return SortSectionPolicy::None; +} + // Initializes Config members by the command line options. void LinkerDriver::readConfigs(opt::InputArgList &Args) { for (auto *Arg : Args.filtered(OPT_L)) @@ -530,6 +541,8 @@ for (auto *Arg : Args.filtered(OPT_undefined)) Config->Undefined.push_back(Arg->getValue()); + Config->SortSection = getSortKind(Args); + Config->UnresolvedSymbols = getUnresolvedSymbolOption(Args); if (auto *Arg = Args.getLastArg(OPT_dynamic_list)) Index: ELF/LinkerScript.h =================================================================== --- ELF/LinkerScript.h +++ ELF/LinkerScript.h @@ -10,6 +10,7 @@ #ifndef LLD_ELF_LINKER_SCRIPT_H #define LLD_ELF_LINKER_SCRIPT_H +#include "Config.h" #include "Strings.h" #include "Writer.h" #include "lld/Core/LLVM.h" @@ -95,16 +96,14 @@ ConstraintKind Constraint = ConstraintKind::NoConstraint; }; -enum SortKind { SortNone, SortByPriority, SortByName, SortByAlignment }; - struct InputSectionDescription : BaseCommand { InputSectionDescription(StringRef FilePattern) : BaseCommand(InputSectionKind), FileRe(compileGlobPatterns({FilePattern})) {} static bool classof(const BaseCommand *C); llvm::Regex FileRe; - SortKind SortOuter = SortNone; - SortKind SortInner = SortNone; + SortSectionPolicy SortOuter = SortSectionPolicy::None; + SortSectionPolicy SortInner = SortSectionPolicy::None; llvm::Regex ExcludedFileRe; llvm::Regex SectionRe; }; Index: ELF/LinkerScript.cpp =================================================================== --- ELF/LinkerScript.cpp +++ ELF/LinkerScript.cpp @@ -126,10 +126,10 @@ } static std::function -getComparator(SortKind K) { - if (K == SortByPriority) +getComparator(SortSectionPolicy K) { + if (K == SortSectionPolicy::Priority) return comparePriority; - if (K == SortByName) + if (K == SortSectionPolicy::Name) return compareName; return compareAlignment; } @@ -195,9 +195,9 @@ std::vector *> V = getInputSections(Cmd); if (!matchConstraints(V, OutCmd.Constraint)) continue; - if (Cmd->SortInner) + if (Cmd->SortInner != SortSectionPolicy::None) std::stable_sort(V.begin(), V.end(), getComparator(Cmd->SortInner)); - if (Cmd->SortOuter) + if (Cmd->SortOuter != SortSectionPolicy::None) std::stable_sort(V.begin(), V.end(), getComparator(Cmd->SortOuter)); // Add all input sections corresponding to rule 'Cmd' to @@ -689,7 +689,7 @@ Regex readFilePatterns(); InputSectionDescription *readInputSectionRules(StringRef FilePattern); unsigned readPhdrType(); - SortKind readSortKind(); + SortSectionPolicy readSortKind(); SymbolAssignment *readProvideHidden(bool Provide, bool Hidden); SymbolAssignment *readProvideOrAssignment(StringRef Tok, bool MakeAbsolute); void readSort(); @@ -971,14 +971,39 @@ return compileGlobPatterns(V); } -SortKind ScriptParser::readSortKind() { +SortSectionPolicy ScriptParser::readSortKind() { if (skip("SORT") || skip("SORT_BY_NAME")) - return SortByName; + return SortSectionPolicy::Name; if (skip("SORT_BY_ALIGNMENT")) - return SortByAlignment; + return SortSectionPolicy::Alignment; if (skip("SORT_BY_INIT_PRIORITY")) - return SortByPriority; - return SortNone; + return SortSectionPolicy::Priority; + // `SORT_NONE' disables section sorting by ignoring the command line + // section sorting option. + if (skip("SORT_NONE")) + return SortSectionPolicy::IgnoreConfig; + return SortSectionPolicy::None; +} + +static void selectSortKind(InputSectionDescription *Cmd) { + if (Cmd->SortOuter == SortSectionPolicy::IgnoreConfig) { + Cmd->SortOuter = SortSectionPolicy::None; + return; + } + + if (Cmd->SortOuter != SortSectionPolicy::None) { + // If the section sorting command in linker script is nested, the command + // line option will be ignored. + if (Cmd->SortInner != SortSectionPolicy::None) + 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 = Config->SortSection; + return; + } + // If sorting rule not specified, use command line option. + Cmd->SortOuter = Config->SortSection; } InputSectionDescription * @@ -993,10 +1018,12 @@ } // Read SORT(). - if (SortKind K1 = readSortKind()) { + SortSectionPolicy K1 = readSortKind(); + if (K1 != SortSectionPolicy::None) { Cmd->SortOuter = K1; expect("("); - if (SortKind K2 = readSortKind()) { + SortSectionPolicy K2 = readSortKind(); + if (K2 != SortSectionPolicy::None) { Cmd->SortInner = K2; expect("("); Cmd->SectionRe = readFilePatterns(); @@ -1005,9 +1032,11 @@ Cmd->SectionRe = readFilePatterns(); } expect(")"); + selectSortKind(Cmd); return Cmd; } + selectSortKind(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