Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions lld/ELF/Arch/NanoMips.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,9 @@ template <class ELFT> class NanoMips final : public TargetInfo {
bool relaxOnce(int pass) const override {
return this->transformController.relaxOnce(pass);
}

void scatterNops() const override { this->transformController.scatterNops(); }

void relocateAlloc(InputSectionBase &sec, uint8_t *buf) const override;

uint32_t calcEFlags() const override;
Expand Down
2 changes: 2 additions & 0 deletions lld/ELF/Config.h
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,8 @@ struct Config {
bool relrGlibc = false;
bool relrPackDynRelocs = false;
llvm::DenseSet<llvm::StringRef> saveTempsArgs;
uint32_t scatterNopsDensity;
uint32_t scatterNopsSeed;
llvm::SmallVector<std::pair<llvm::GlobPattern, uint32_t>, 0> shuffleSections;
bool singleRoRx;
bool shared;
Expand Down
5 changes: 5 additions & 0 deletions lld/ELF/Driver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1236,6 +1236,11 @@ static void readConfigs(opt::InputArgList &args) {
}

config->searchPaths = args::getStrings(args, OPT_library_path);
config->scatterNopsDensity =
args.hasArg(OPT_relocatable)
? 0
: args::getInteger(args, OPT_scatter_nops_density, 0);
config->scatterNopsSeed = args::getInteger(args, OPT_scatter_nops_seed, 0);
config->sectionStartMap = getSectionStartMap(args);
config->shared = args.hasArg(OPT_shared);
config->singleRoRx = !args.hasFlag(OPT_rosegment, OPT_no_rosegment, true);
Expand Down
75 changes: 59 additions & 16 deletions lld/ELF/NanoMipsTransformations.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "llvm/Object/ELFTypes.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/xxhash.h"

#define DEBUG_TYPE "lld-nanomips"
using namespace lld;
Expand Down Expand Up @@ -362,19 +363,16 @@ void NanoMipsTransform::changeBytes(InputSection *isec, uint64_t location,
}
}

void NanoMipsTransform::updateSectionContent(InputSection *isec,
uint64_t location, int32_t delta,
bool align) {

bool NanoMipsTransform::updateSectionContentInner(InputSection *isec,
uint64_t location,
int32_t delta, bool align) {
// Other than increasing/decreasing byte size of isec, it also
// allocates new section content if delta is 0 and section
// hasn't yet been changed, as those content would be readonly
changeBytes(isec, location, delta);
NanoMipsTransform::changeBytes(isec, location, delta);
if (delta == 0)
return;
return false;

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

for (auto &symAnchor : isec->nanoMipsRelaxAux->anchors) {
Defined *dSym = symAnchor.d;
Expand All @@ -413,6 +411,19 @@ void NanoMipsTransform::updateSectionContent(InputSection *isec,
}
}
}

return true;
}

void NanoMipsTransform::updateSectionContent(InputSection *isec,
uint64_t location, int32_t delta,
bool align) {
bool changed = NanoMipsTransform::updateSectionContentInner(isec, location,
delta, align);
if (changed) {
this->changed = true;
this->changedThisIteration = true;
}
}

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

template <class ELFT>
void NanoMipsTransformController<ELFT>::scatterNops() const {
if (!this->mayRelax())
return;

NanoMipsTransformController<ELFT>::initTransformAuxInfo();

for (OutputSection *osec : outputSections) {
if (!isOutputSecTransformable(osec))
continue;

SmallVector<InputSection *, 0> storage;
for (InputSection *sec : getInputSections(*osec, storage)) {
if (!NanoMipsTransformController<ELFT>::safeToModify(sec) ||
!sec->relocs().size() || !(sec->flags & SHF_EXECINSTR))
continue;

uint64_t hash = llvm::xxHash64(sec->name) + config->scatterNopsSeed;
if ((hash % 100) >= config->scatterNopsDensity)
continue;

const uint32_t nop16 = 0x9008;
const uint32_t nop16Size = 2;
NanoMipsTransform::updateSectionContentInner(sec, 0, 2, false);
writeInsn<ELFT::TargetEndianness>(nop16, sec->content(), 0, nop16Size);
LLVM_DEBUG(llvm::dbgs() << sec->name
<< " updated with a nop in the beginning!\n";);
}
}
}

// relaxOnce is used for both relaxations and expansions
template <class ELFT>
bool NanoMipsTransformController<ELFT>::relaxOnce(int pass) const {
Expand All @@ -1148,18 +1190,18 @@ bool NanoMipsTransformController<ELFT>::relaxOnce(int pass) const {
LLVM_DEBUG(llvm::dbgs() << "Transformation Pass num: " << pass << "\n";);
bool shouldRunAgain = false;
if (this->mayRelax()) {
if (pass == 0) {
if (pass == 0 && config->scatterNopsDensity == 0) {
// Initialization of additional info that are needed for
// relaxations/expansions
initTransformAuxInfo();
NanoMipsTransformController<ELFT>::initTransformAuxInfo();
}
for (OutputSection *osec : outputSections) {
if (!isOutputSecTransformable(osec))
continue;

SmallVector<InputSection *, 0> storage;
for (InputSection *sec : getInputSections(*osec, storage)) {
if (!this->safeToModify(sec))
if (!NanoMipsTransformController<ELFT>::safeToModify(sec))
continue;
if (sec->relocs().size())
this->scanAndTransform(sec);
Expand All @@ -1175,8 +1217,8 @@ bool NanoMipsTransformController<ELFT>::relaxOnce(int pass) const {
}

template <class ELFT>
inline bool lld::elf::NanoMipsTransformController<ELFT>::safeToModify(
InputSection *sec) const {
inline bool
lld::elf::NanoMipsTransformController<ELFT>::safeToModify(InputSection *sec) {
bool modifiable = false;
if (auto *obj = sec->getFile<ELF32LE>()) {
modifiable =
Expand All @@ -1186,14 +1228,15 @@ inline bool lld::elf::NanoMipsTransformController<ELFT>::safeToModify(
}

template <class ELFT>
void NanoMipsTransformController<ELFT>::initTransformAuxInfo() const {
void NanoMipsTransformController<ELFT>::initTransformAuxInfo() {
SmallVector<InputSection *, 0> storage;
for (OutputSection *osec : outputSections) {
if (!isOutputSecTransformable(osec))
continue;

for (InputSection *sec : getInputSections(*osec, storage)) {
if (!this->safeToModify(sec) || sec->relocs().size() == 0)
if (!NanoMipsTransformController<ELFT>::safeToModify(sec) ||
sec->relocs().size() == 0)
continue;
sec->nanoMipsRelaxAux = make<NanoMipsRelaxAux>();
sec->nanoMipsRelaxAux->isAlreadyTransformed = false;
Expand Down
9 changes: 6 additions & 3 deletions lld/ELF/NanoMipsTransformations.h
Original file line number Diff line number Diff line change
Expand Up @@ -352,6 +352,8 @@ class NanoMipsTransform {
getTransformTemplate(const NanoMipsInsProperty *insProperty, uint32_t relNum,
uint64_t valueToRelocate, uint64_t insn,
const InputSection *isec) const = 0;
static bool updateSectionContentInner(InputSection *isec, uint64_t location,
int32_t delta, bool aligned);
virtual void updateSectionContent(InputSection *isec, uint64_t location,
int32_t delta, bool align = false);
bool getChanged() { return changed; }
Expand All @@ -375,7 +377,7 @@ class NanoMipsTransform {
static uint32_t newSkipBcSymCount;

private:
void changeBytes(InputSection *isec, uint64_t location, int32_t count);
static void changeBytes(InputSection *isec, uint64_t location, int32_t count);
};

class NanoMipsTransformExpand : public NanoMipsTransform {
Expand Down Expand Up @@ -450,6 +452,7 @@ template <class ELFT> class NanoMipsTransformController {

void initState();
bool relaxOnce(int pass) const;
void scatterNops() const;

// should be called before change state
bool shouldRunAgain() const { return this->currentState->getChanged(); }
Expand All @@ -467,8 +470,8 @@ template <class ELFT> class NanoMipsTransformController {
NanoMipsTransform::TransformKind getType() const {
return this->currentState->getType();
}
bool safeToModify(InputSection *sec) const;
void initTransformAuxInfo() const;
static bool safeToModify(InputSection *sec);
static void initTransformAuxInfo();
void scanAndTransform(InputSection *sec) const;
void align(InputSection *sec, Relocation &reloc, uint32_t relNum) const;
void changeState(int pass);
Expand Down
14 changes: 14 additions & 0 deletions lld/ELF/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -371,6 +371,20 @@ defm retain_symbols_file:
Eq<"retain-symbols-file", "Retain only the symbols listed in the file">,
MetaVarName<"<file>">;

defm scatter_nops_density: EEq<"scatter-nops-density",
"Approximate percentage of instruction sections that will have nops "
"inserted at their beginnings. If 0, scatter nops doesn't do anything. "
"Doesn't do anything for relocatable outputs (default=0)(nanoMIPS only)">,
Flags<[HelpHidden]>;


defm scatter_nops_seed: EEq<"scatter-nops-seed",
"Use a different seed for the pseudo-random determination of "
"section that will be inserted with a nop. If scatter-nops-density is "
"0 or the requested output is relocatable, than this option doesn't have "
"effect (default=0)(nanoMIPS only)">,
Flags<[HelpHidden]>;

defm script: Eq<"script", "Read linker script">;

defm section_start: Eq<"section-start", "Set address of section">,
Expand Down
4 changes: 4 additions & 0 deletions lld/ELF/Target.h
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,10 @@ class TargetInfo {
// Do a linker relaxation pass and return true if we changed something.
virtual bool relaxOnce(int pass) const { return false; }

// Insert nops randomly on the beginning of every instruction section.
// Currently only implemented on nanoMIPS.
virtual void scatterNops() const {}

virtual void applyJumpInstrMod(uint8_t *loc, JumpModType type,
JumpModType val) const {}

Expand Down
8 changes: 8 additions & 0 deletions lld/ELF/Writer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1657,6 +1657,14 @@ template <class ELFT> void Writer<ELFT>::finalizeAddressDependentContent() {
ThunkCreator tc;
AArch64Err843419Patcher a64p;
ARMErr657417Patcher a32p;

// Put scatter nops here, everything is finished with input sections
// till this point, except some instruction transformations. Putting
// scatter nops may trigger those transformations, so we have to put
// it before these transformations.
if (config->scatterNopsDensity != 0)
target->scatterNops();

script->assignAddresses();
// .ARM.exidx and SHF_LINK_ORDER do not require precise addresses, but they
// do require the relative addresses of OutputSections because linker scripts
Expand Down