Skip to content

Commit 5163e27

Browse files
committed
[LLD] Scatter nops
Enable pseudo-randomly adding nops to beginning of instruction sections. Percentage of sections that are affected can be set. This is used in nanoMIPS primarily to try analyzing instruction cache influence on execution time, as well as normalize the results.
1 parent e279b3d commit 5163e27

File tree

8 files changed

+101
-19
lines changed

8 files changed

+101
-19
lines changed

lld/ELF/Arch/NanoMips.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,9 @@ template <class ELFT> class NanoMips final : public TargetInfo {
178178
bool relaxOnce(int pass) const override {
179179
return this->transformController.relaxOnce(pass);
180180
}
181+
182+
void scatterNops() const override { this->transformController.scatterNops(); }
183+
181184
void relocateAlloc(InputSectionBase &sec, uint8_t *buf) const override;
182185

183186
uint32_t calcEFlags() const override;

lld/ELF/Config.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,8 @@ struct Config {
256256
bool relrGlibc = false;
257257
bool relrPackDynRelocs = false;
258258
llvm::DenseSet<llvm::StringRef> saveTempsArgs;
259+
uint32_t scatterNopsDensity;
260+
uint32_t scatterNopsSeed;
259261
llvm::SmallVector<std::pair<llvm::GlobPattern, uint32_t>, 0> shuffleSections;
260262
bool singleRoRx;
261263
bool shared;

lld/ELF/Driver.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1236,6 +1236,11 @@ static void readConfigs(opt::InputArgList &args) {
12361236
}
12371237

12381238
config->searchPaths = args::getStrings(args, OPT_library_path);
1239+
config->scatterNopsDensity =
1240+
args.hasArg(OPT_relocatable)
1241+
? 0
1242+
: args::getInteger(args, OPT_scatter_nops_density, 0);
1243+
config->scatterNopsSeed = args::getInteger(args, OPT_scatter_nops_seed, 0);
12391244
config->sectionStartMap = getSectionStartMap(args);
12401245
config->shared = args.hasArg(OPT_shared);
12411246
config->singleRoRx = !args.hasFlag(OPT_rosegment, OPT_no_rosegment, true);

lld/ELF/NanoMipsTransformations.cpp

Lines changed: 59 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "llvm/Object/ELFTypes.h"
2222
#include "llvm/Support/ErrorHandling.h"
2323
#include "llvm/Support/raw_ostream.h"
24+
#include "llvm/Support/xxhash.h"
2425

2526
#define DEBUG_TYPE "lld-nanomips"
2627
using namespace lld;
@@ -362,19 +363,16 @@ void NanoMipsTransform::changeBytes(InputSection *isec, uint64_t location,
362363
}
363364
}
364365

365-
void NanoMipsTransform::updateSectionContent(InputSection *isec,
366-
uint64_t location, int32_t delta,
367-
bool align) {
368-
366+
bool NanoMipsTransform::updateSectionContentInner(InputSection *isec,
367+
uint64_t location,
368+
int32_t delta, bool align) {
369369
// Other than increasing/decreasing byte size of isec, it also
370370
// allocates new section content if delta is 0 and section
371371
// hasn't yet been changed, as those content would be readonly
372-
changeBytes(isec, location, delta);
372+
NanoMipsTransform::changeBytes(isec, location, delta);
373373
if (delta == 0)
374-
return;
374+
return false;
375375

376-
this->changed = true;
377-
this->changedThisIteration = true;
378376
LLVM_DEBUG(llvm::dbgs() << "Changed size of input section "
379377
<< (isec->file ? isec->file->getName() : "nofile")
380378
<< "(" << isec->name << ") by " << delta
@@ -395,7 +393,7 @@ void NanoMipsTransform::updateSectionContent(InputSection *isec,
395393
// TODO: Check whether sections without a corresponding file
396394
// may have symbols that should be changed during transformations
397395
if (!isec->file)
398-
return;
396+
return true;
399397

400398
for (auto &symAnchor : isec->nanoMipsRelaxAux->anchors) {
401399
Defined *dSym = symAnchor.d;
@@ -413,6 +411,19 @@ void NanoMipsTransform::updateSectionContent(InputSection *isec,
413411
}
414412
}
415413
}
414+
415+
return true;
416+
}
417+
418+
void NanoMipsTransform::updateSectionContent(InputSection *isec,
419+
uint64_t location, int32_t delta,
420+
bool align) {
421+
bool changed = NanoMipsTransform::updateSectionContentInner(isec, location,
422+
delta, align);
423+
if (changed) {
424+
this->changed = true;
425+
this->changedThisIteration = true;
426+
}
416427
}
417428

418429
SmallVector<NewInsnToWrite, 3> NanoMipsTransform::getTransformInsns(
@@ -1140,6 +1151,37 @@ void NanoMipsTransformController<ELFT>::changeState(int pass) {
11401151
LLVM_DEBUG(llvm::dbgs() << "Changed transform state to None\n";);
11411152
}
11421153

1154+
template <class ELFT>
1155+
void NanoMipsTransformController<ELFT>::scatterNops() const {
1156+
if (!this->mayRelax())
1157+
return;
1158+
1159+
NanoMipsTransformController<ELFT>::initTransformAuxInfo();
1160+
1161+
for (OutputSection *osec : outputSections) {
1162+
if (!isOutputSecTransformable(osec))
1163+
continue;
1164+
1165+
SmallVector<InputSection *, 0> storage;
1166+
for (InputSection *sec : getInputSections(*osec, storage)) {
1167+
if (!NanoMipsTransformController<ELFT>::safeToModify(sec) ||
1168+
!sec->relocs().size() || !(sec->flags & SHF_EXECINSTR))
1169+
continue;
1170+
1171+
uint64_t hash = llvm::xxHash64(sec->name) + config->scatterNopsSeed;
1172+
if ((hash % 100) >= config->scatterNopsDensity)
1173+
continue;
1174+
1175+
const uint32_t nop16 = 0x9008;
1176+
const uint32_t nop16Size = 2;
1177+
NanoMipsTransform::updateSectionContentInner(sec, 0, 2, false);
1178+
writeInsn<ELFT::TargetEndianness>(nop16, sec->content(), 0, nop16Size);
1179+
LLVM_DEBUG(llvm::dbgs() << sec->name
1180+
<< " updated with a nop in the beginning!\n";);
1181+
}
1182+
}
1183+
}
1184+
11431185
// relaxOnce is used for both relaxations and expansions
11441186
template <class ELFT>
11451187
bool NanoMipsTransformController<ELFT>::relaxOnce(int pass) const {
@@ -1148,18 +1190,18 @@ bool NanoMipsTransformController<ELFT>::relaxOnce(int pass) const {
11481190
LLVM_DEBUG(llvm::dbgs() << "Transformation Pass num: " << pass << "\n";);
11491191
bool shouldRunAgain = false;
11501192
if (this->mayRelax()) {
1151-
if (pass == 0) {
1193+
if (pass == 0 && config->scatterNopsDensity == 0) {
11521194
// Initialization of additional info that are needed for
11531195
// relaxations/expansions
1154-
initTransformAuxInfo();
1196+
NanoMipsTransformController<ELFT>::initTransformAuxInfo();
11551197
}
11561198
for (OutputSection *osec : outputSections) {
11571199
if (!isOutputSecTransformable(osec))
11581200
continue;
11591201

11601202
SmallVector<InputSection *, 0> storage;
11611203
for (InputSection *sec : getInputSections(*osec, storage)) {
1162-
if (!this->safeToModify(sec))
1204+
if (!NanoMipsTransformController<ELFT>::safeToModify(sec))
11631205
continue;
11641206
if (sec->relocs().size())
11651207
this->scanAndTransform(sec);
@@ -1175,8 +1217,8 @@ bool NanoMipsTransformController<ELFT>::relaxOnce(int pass) const {
11751217
}
11761218

11771219
template <class ELFT>
1178-
inline bool lld::elf::NanoMipsTransformController<ELFT>::safeToModify(
1179-
InputSection *sec) const {
1220+
inline bool
1221+
lld::elf::NanoMipsTransformController<ELFT>::safeToModify(InputSection *sec) {
11801222
bool modifiable = false;
11811223
if (auto *obj = sec->getFile<ELF32LE>()) {
11821224
modifiable =
@@ -1186,14 +1228,15 @@ inline bool lld::elf::NanoMipsTransformController<ELFT>::safeToModify(
11861228
}
11871229

11881230
template <class ELFT>
1189-
void NanoMipsTransformController<ELFT>::initTransformAuxInfo() const {
1231+
void NanoMipsTransformController<ELFT>::initTransformAuxInfo() {
11901232
SmallVector<InputSection *, 0> storage;
11911233
for (OutputSection *osec : outputSections) {
11921234
if (!isOutputSecTransformable(osec))
11931235
continue;
11941236

11951237
for (InputSection *sec : getInputSections(*osec, storage)) {
1196-
if (!this->safeToModify(sec) || sec->relocs().size() == 0)
1238+
if (!NanoMipsTransformController<ELFT>::safeToModify(sec) ||
1239+
sec->relocs().size() == 0)
11971240
continue;
11981241
sec->nanoMipsRelaxAux = make<NanoMipsRelaxAux>();
11991242
sec->nanoMipsRelaxAux->isAlreadyTransformed = false;

lld/ELF/NanoMipsTransformations.h

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -352,6 +352,8 @@ class NanoMipsTransform {
352352
getTransformTemplate(const NanoMipsInsProperty *insProperty, uint32_t relNum,
353353
uint64_t valueToRelocate, uint64_t insn,
354354
const InputSection *isec) const = 0;
355+
static bool updateSectionContentInner(InputSection *isec, uint64_t location,
356+
int32_t delta, bool aligned);
355357
virtual void updateSectionContent(InputSection *isec, uint64_t location,
356358
int32_t delta, bool align = false);
357359
bool getChanged() { return changed; }
@@ -375,7 +377,7 @@ class NanoMipsTransform {
375377
static uint32_t newSkipBcSymCount;
376378

377379
private:
378-
void changeBytes(InputSection *isec, uint64_t location, int32_t count);
380+
static void changeBytes(InputSection *isec, uint64_t location, int32_t count);
379381
};
380382

381383
class NanoMipsTransformExpand : public NanoMipsTransform {
@@ -450,6 +452,7 @@ template <class ELFT> class NanoMipsTransformController {
450452

451453
void initState();
452454
bool relaxOnce(int pass) const;
455+
void scatterNops() const;
453456

454457
// should be called before change state
455458
bool shouldRunAgain() const { return this->currentState->getChanged(); }
@@ -467,8 +470,8 @@ template <class ELFT> class NanoMipsTransformController {
467470
NanoMipsTransform::TransformKind getType() const {
468471
return this->currentState->getType();
469472
}
470-
bool safeToModify(InputSection *sec) const;
471-
void initTransformAuxInfo() const;
473+
static bool safeToModify(InputSection *sec);
474+
static void initTransformAuxInfo();
472475
void scanAndTransform(InputSection *sec) const;
473476
void align(InputSection *sec, Relocation &reloc, uint32_t relNum) const;
474477
void changeState(int pass);

lld/ELF/Options.td

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,20 @@ defm retain_symbols_file:
371371
Eq<"retain-symbols-file", "Retain only the symbols listed in the file">,
372372
MetaVarName<"<file>">;
373373

374+
defm scatter_nops_density: EEq<"scatter-nops-density",
375+
"Approximate percentage of instruction sections that will have nops "
376+
"inserted at their beginnings. If 0, scatter nops doesn't do anything. "
377+
"Doesn't do anything for relocatable outputs (default=0)(nanoMIPS only)">,
378+
Flags<[HelpHidden]>;
379+
380+
381+
defm scatter_nops_seed: EEq<"scatter-nops-seed",
382+
"Use a different seed for the pseudo-random determination of "
383+
"section that will be inserted with a nop. If scatter-nops-density is "
384+
"0 or the requested output is relocatable, than this option doesn't have "
385+
"effect (default=0)(nanoMIPS only)">,
386+
Flags<[HelpHidden]>;
387+
374388
defm script: Eq<"script", "Read linker script">;
375389

376390
defm section_start: Eq<"section-start", "Set address of section">,

lld/ELF/Target.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,10 @@ class TargetInfo {
9494
// Do a linker relaxation pass and return true if we changed something.
9595
virtual bool relaxOnce(int pass) const { return false; }
9696

97+
// Insert nops randomly on the beginning of every instruction section.
98+
// Currently only implemented on nanoMIPS.
99+
virtual void scatterNops() const {}
100+
97101
virtual void applyJumpInstrMod(uint8_t *loc, JumpModType type,
98102
JumpModType val) const {}
99103

lld/ELF/Writer.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1657,6 +1657,14 @@ template <class ELFT> void Writer<ELFT>::finalizeAddressDependentContent() {
16571657
ThunkCreator tc;
16581658
AArch64Err843419Patcher a64p;
16591659
ARMErr657417Patcher a32p;
1660+
1661+
// Put scatter nops here, everything is finished with input sections
1662+
// till this point, except some instruction transformations. Putting
1663+
// scatter nops may trigger those transformations, so we have to put
1664+
// it before these transformations.
1665+
if (config->scatterNopsDensity != 0)
1666+
target->scatterNops();
1667+
16601668
script->assignAddresses();
16611669
// .ARM.exidx and SHF_LINK_ORDER do not require precise addresses, but they
16621670
// do require the relative addresses of OutputSections because linker scripts

0 commit comments

Comments
 (0)