Index: lld/trunk/ELF/Config.h =================================================================== --- lld/trunk/ELF/Config.h +++ lld/trunk/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: lld/trunk/ELF/Driver.cpp =================================================================== --- lld/trunk/ELF/Driver.cpp +++ lld/trunk/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: lld/trunk/ELF/LinkerScript.h =================================================================== --- lld/trunk/ELF/LinkerScript.h +++ lld/trunk/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" @@ -97,16 +98,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; // Pairs of section regex and files excluded. std::list> SectionsVec; std::vector Sections; Index: lld/trunk/ELF/LinkerScript.cpp =================================================================== --- lld/trunk/ELF/LinkerScript.cpp +++ lld/trunk/ELF/LinkerScript.cpp @@ -131,12 +131,17 @@ } static std::function -getComparator(SortKind K) { - if (K == SortByPriority) - return comparePriority; - if (K == SortByName) +getComparator(SortSectionPolicy K) { + switch (K) { + case SortSectionPolicy::Alignment: + return compareAlignment; + case SortSectionPolicy::Name: return compareName; - return compareAlignment; + case SortSectionPolicy::Priority: + return comparePriority; + default: + llvm_unreachable("unknown sort policy"); + } } static bool checkConstraint(uint64_t Flags, ConstraintKind Kind) { @@ -180,10 +185,10 @@ return; } - if (I->SortInner) + if (I->SortInner != SortSectionPolicy::None) std::stable_sort(I->Sections.begin(), I->Sections.end(), getComparator(I->SortInner)); - if (I->SortOuter) + if (I->SortOuter != SortSectionPolicy::None) std::stable_sort(I->Sections.begin(), I->Sections.end(), getComparator(I->SortOuter)); @@ -704,7 +709,7 @@ void readSectionExcludes(InputSectionDescription *Cmd); InputSectionDescription *readInputSectionRules(StringRef FilePattern); unsigned readPhdrType(); - SortKind readSortKind(); + SortSectionPolicy readSortKind(); SymbolAssignment *readProvideHidden(bool Provide, bool Hidden); SymbolAssignment *readProvideOrAssignment(StringRef Tok, bool MakeAbsolute); void readSort(); @@ -985,14 +990,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; } // Method reads a list of sequence of excluded files and section globs given in @@ -1031,10 +1061,12 @@ expect("("); // 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->SectionsVec.push_back({llvm::Regex(), readFilePatterns()}); @@ -1043,9 +1075,11 @@ Cmd->SectionsVec.push_back({llvm::Regex(), readFilePatterns()}); } expect(")"); + selectSortKind(Cmd); return Cmd; } + selectSortKind(Cmd); readSectionExcludes(Cmd); return Cmd; } Index: lld/trunk/ELF/Options.td =================================================================== --- lld/trunk/ELF/Options.td +++ lld/trunk/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: lld/trunk/test/ELF/linkerscript/sort-nested.s =================================================================== --- lld/trunk/test/ELF/linkerscript/sort-nested.s +++ lld/trunk/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: lld/trunk/test/ELF/linkerscript/sort.s =================================================================== --- lld/trunk/test/ELF/linkerscript/sort.s +++ lld/trunk/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