diff --git a/lld/ELF/Config.h b/lld/ELF/Config.h --- a/lld/ELF/Config.h +++ b/lld/ELF/Config.h @@ -182,6 +182,7 @@ bool relocatable; bool relrPackDynRelocs; bool saveTemps; + llvm::Optional shuffleSectionSeed; bool singleRoRx; bool shared; bool isStatic = false; diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -956,6 +956,8 @@ config->rpath = getRpath(args); config->relocatable = args.hasArg(OPT_relocatable); config->saveTemps = args.hasArg(OPT_save_temps); + if (args.hasArg(OPT_shuffle_sections)) + config->shuffleSectionSeed = args::getInteger(args, OPT_shuffle_sections, 0); config->searchPaths = args::getStrings(args, OPT_library_path); config->sectionStartMap = getSectionStartMap(args); config->shared = args.hasArg(OPT_shared); diff --git a/lld/ELF/Options.td b/lld/ELF/Options.td --- a/lld/ELF/Options.td +++ b/lld/ELF/Options.td @@ -499,6 +499,8 @@ HelpText<"The format used for serializing remarks (default: YAML)">; defm plugin_opt: Eq<"plugin-opt", "specifies LTO options for compatibility with GNU linkers">; def save_temps: F<"save-temps">; +def shuffle_sections: J<"shuffle-sections=">, MetaVarName<"">, + HelpText<"Shuffle input sections using the given seed. If 0, use a random seed">; def thinlto_cache_dir: J<"thinlto-cache-dir=">, HelpText<"Path to ThinLTO cached object file directory">; defm thinlto_cache_policy: Eq<"thinlto-cache-policy", "Pruning policy for the ThinLTO cache">; diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp --- a/lld/ELF/Writer.cpp +++ b/lld/ELF/Writer.cpp @@ -1205,6 +1205,27 @@ return i; } +// Adds random priorities to sections not already in the map. +static void maybeShuffle(DenseMap &order) { + if (!config->shuffleSectionSeed) + return; + + std::vector priorities(inputSections.size() - order.size()); + // Existing priorities are < 0, so use priorities >= 0 for the missing + // sections. + int curPrio = 0; + for (int &prio : priorities) + prio = curPrio++; + uint32_t seed = *config->shuffleSectionSeed; + std::mt19937 g(seed ? seed : std::random_device()()); + std::shuffle(priorities.begin(), priorities.end(), g); + int prioIndex = 0; + for (InputSectionBase *sec : inputSections) { + if (order.try_emplace(sec, priorities[prioIndex]).second) + ++prioIndex; + } +} + // Builds section order for handling --symbol-ordering-file. static DenseMap buildSectionOrder() { DenseMap sectionOrder; @@ -1384,6 +1405,7 @@ template void Writer::sortInputSections() { // Build the order once since it is expensive. DenseMap order = buildSectionOrder(); + maybeShuffle(order); for (BaseCommand *base : script->sectionCommands) if (auto *sec = dyn_cast(base)) sortSection(sec, order); diff --git a/lld/docs/ld.lld.1 b/lld/docs/ld.lld.1 --- a/lld/docs/ld.lld.1 +++ b/lld/docs/ld.lld.1 @@ -456,6 +456,8 @@ Set address of section. .It Fl -shared , Fl -Bsharable Build a shared object. +.It Fl -shuffle-sections Ns = Ns Ar seed +Shuffle input sections using the given seed. If 0, use a random seed. .It Fl -soname Ns = Ns Ar value , Fl h Ar value Set .Dv DT_SONAME diff --git a/lld/test/ELF/shuffle-sections.s b/lld/test/ELF/shuffle-sections.s new file mode 100644 --- /dev/null +++ b/lld/test/ELF/shuffle-sections.s @@ -0,0 +1,47 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t.o + +# RUN: ld.lld %t.o -o %t.out +# RUN: llvm-readelf -x .text %t.out | FileCheck %s +# CHECK: Hex dump of section '.text': +# CHECK-NEXT: 01020304 + +## --shuffle-sections= shuffles input sections. +# RUN: ld.lld --shuffle-sections=1 %t.o -o %t1.out +# RUN: llvm-readelf -x .text %t1.out | FileCheck %s --check-prefix=SHUFFLE1 +# SHUFFLE1: Hex dump of section '.text': +# SHUFFLE1-NEXT: 01020403 + +## Test that --shuffle-sections= can be used with --symbol-ordering-file +# RUN: echo "foo" > %t_order.txt +# RUN: echo "_start " >> %t_order.txt + +# RUN: ld.lld --symbol-ordering-file %t_order.txt --shuffle-sections=2 %t.o -o %t2.out +# RUN: llvm-readelf -x .text %t2.out | FileCheck %s --check-prefix=SHUFFLE2 +# SHUFFLE2: Hex dump of section '.text': +# SHUFFLE2-NEXT: 02cccccc 010403 + +# RUN: ld.lld --symbol-ordering-file %t_order.txt --shuffle-sections=3 %t.o -o %t3.out +# RUN: llvm-readelf -x .text %t3.out | FileCheck %s --check-prefix=SHUFFLE3 +# SHUFFLE3: Hex dump of section '.text': +# SHUFFLE3-NEXT: 02cccccc 010304 + +## .text has an alignment of 4. +.global _start +_start: + .byte 1 + +.section .text.foo,"ax" +.global foo +foo: + .byte 2 + +.section .text.bar,"ax" +.global bar +bar: + .byte 3 + +.section .text.zed,"ax" +.global zed +zed: + .byte 4