Skip to content

Commit d48d339

Browse files
espindolaMaskRay
authored andcommitted
[lld][ELF] Add --shuffle-sections=seed to shuffle input sections
Summary: This option causes lld to shuffle sections by assigning different priorities in each run. The use case for this is to introduce randomization in benchmarks. The idea is inspired by the paper "Producing Wrong Data Without Doing Anything Obviously Wrong!" (https://www.inf.usi.ch/faculty/hauswirth/publications/asplos09.pdf). Unlike the paper, we shuffle individual sections, not just input files. Doing this in lld is particularly convenient as the --reproduce option makes it easy to collect all the necessary bits for relinking the program being benchmarked. Once that it is done, all that is needed is to add --shuffle-sections=0 to the response file and relink before each run of the benchmark. Differential Revision: https://reviews.llvm.org/D74791
1 parent 03954a1 commit d48d339

File tree

6 files changed

+76
-0
lines changed

6 files changed

+76
-0
lines changed

lld/ELF/Config.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,7 @@ struct Configuration {
182182
bool relocatable;
183183
bool relrPackDynRelocs;
184184
bool saveTemps;
185+
llvm::Optional<uint32_t> shuffleSectionSeed;
185186
bool singleRoRx;
186187
bool shared;
187188
bool isStatic = false;

lld/ELF/Driver.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -956,6 +956,8 @@ static void readConfigs(opt::InputArgList &args) {
956956
config->rpath = getRpath(args);
957957
config->relocatable = args.hasArg(OPT_relocatable);
958958
config->saveTemps = args.hasArg(OPT_save_temps);
959+
if (args.hasArg(OPT_shuffle_sections))
960+
config->shuffleSectionSeed = args::getInteger(args, OPT_shuffle_sections, 0);
959961
config->searchPaths = args::getStrings(args, OPT_library_path);
960962
config->sectionStartMap = getSectionStartMap(args);
961963
config->shared = args.hasArg(OPT_shared);

lld/ELF/Options.td

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -499,6 +499,8 @@ def opt_remarks_format: Separate<["--"], "opt-remarks-format">,
499499
HelpText<"The format used for serializing remarks (default: YAML)">;
500500
defm plugin_opt: Eq<"plugin-opt", "specifies LTO options for compatibility with GNU linkers">;
501501
def save_temps: F<"save-temps">;
502+
def shuffle_sections: J<"shuffle-sections=">, MetaVarName<"<seed>">,
503+
HelpText<"Shuffle input sections using the given seed. If 0, use a random seed">;
502504
def thinlto_cache_dir: J<"thinlto-cache-dir=">,
503505
HelpText<"Path to ThinLTO cached object file directory">;
504506
defm thinlto_cache_policy: Eq<"thinlto-cache-policy", "Pruning policy for the ThinLTO cache">;

lld/ELF/Writer.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1205,6 +1205,27 @@ findOrphanPos(std::vector<BaseCommand *>::iterator b,
12051205
return i;
12061206
}
12071207

1208+
// Adds random priorities to sections not already in the map.
1209+
static void maybeShuffle(DenseMap<const InputSectionBase *, int> &order) {
1210+
if (!config->shuffleSectionSeed)
1211+
return;
1212+
1213+
std::vector<int> priorities(inputSections.size() - order.size());
1214+
// Existing priorities are < 0, so use priorities >= 0 for the missing
1215+
// sections.
1216+
int curPrio = 0;
1217+
for (int &prio : priorities)
1218+
prio = curPrio++;
1219+
uint32_t seed = *config->shuffleSectionSeed;
1220+
std::mt19937 g(seed ? seed : std::random_device()());
1221+
std::shuffle(priorities.begin(), priorities.end(), g);
1222+
int prioIndex = 0;
1223+
for (InputSectionBase *sec : inputSections) {
1224+
if (order.try_emplace(sec, priorities[prioIndex]).second)
1225+
++prioIndex;
1226+
}
1227+
}
1228+
12081229
// Builds section order for handling --symbol-ordering-file.
12091230
static DenseMap<const InputSectionBase *, int> buildSectionOrder() {
12101231
DenseMap<const InputSectionBase *, int> sectionOrder;
@@ -1384,6 +1405,7 @@ static void sortSection(OutputSection *sec,
13841405
template <class ELFT> void Writer<ELFT>::sortInputSections() {
13851406
// Build the order once since it is expensive.
13861407
DenseMap<const InputSectionBase *, int> order = buildSectionOrder();
1408+
maybeShuffle(order);
13871409
for (BaseCommand *base : script->sectionCommands)
13881410
if (auto *sec = dyn_cast<OutputSection>(base))
13891411
sortSection(sec, order);

lld/docs/ld.lld.1

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -456,6 +456,8 @@ were concatenated in the order they appeared on the command line.
456456
Set address of section.
457457
.It Fl -shared , Fl -Bsharable
458458
Build a shared object.
459+
.It Fl -shuffle-sections Ns = Ns Ar seed
460+
Shuffle input sections using the given seed. If 0, use a random seed.
459461
.It Fl -soname Ns = Ns Ar value , Fl h Ar value
460462
Set
461463
.Dv DT_SONAME

lld/test/ELF/shuffle-sections.s

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# REQUIRES: x86
2+
# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t.o
3+
4+
# RUN: ld.lld %t.o -o %t.out
5+
# RUN: llvm-readelf -x .text %t.out | FileCheck %s
6+
# CHECK: Hex dump of section '.text':
7+
# CHECK-NEXT: 01020304
8+
9+
## --shuffle-sections= shuffles input sections.
10+
# RUN: ld.lld --shuffle-sections=1 %t.o -o %t1.out
11+
# RUN: llvm-readelf -x .text %t1.out | FileCheck %s --check-prefix=SHUFFLE1
12+
# SHUFFLE1: Hex dump of section '.text':
13+
# SHUFFLE1-NEXT: 01020403
14+
15+
## Test that --shuffle-sections= can be used with --symbol-ordering-file
16+
# RUN: echo "foo" > %t_order.txt
17+
# RUN: echo "_start " >> %t_order.txt
18+
19+
# RUN: ld.lld --symbol-ordering-file %t_order.txt --shuffle-sections=2 %t.o -o %t2.out
20+
# RUN: llvm-readelf -x .text %t2.out | FileCheck %s --check-prefix=SHUFFLE2
21+
# SHUFFLE2: Hex dump of section '.text':
22+
# SHUFFLE2-NEXT: 02cccccc 010403
23+
24+
# RUN: ld.lld --symbol-ordering-file %t_order.txt --shuffle-sections=3 %t.o -o %t3.out
25+
# RUN: llvm-readelf -x .text %t3.out | FileCheck %s --check-prefix=SHUFFLE3
26+
# SHUFFLE3: Hex dump of section '.text':
27+
# SHUFFLE3-NEXT: 02cccccc 010304
28+
29+
## .text has an alignment of 4.
30+
.global _start
31+
_start:
32+
.byte 1
33+
34+
.section .text.foo,"ax"
35+
.global foo
36+
foo:
37+
.byte 2
38+
39+
.section .text.bar,"ax"
40+
.global bar
41+
bar:
42+
.byte 3
43+
44+
.section .text.zed,"ax"
45+
.global zed
46+
zed:
47+
.byte 4

0 commit comments

Comments
 (0)