Skip to content

Commit

Permalink
[nanoMIPS][LLD] Added linker transformations
Browse files Browse the repository at this point in the history
Added nanoMIPS specific linker relaxations/expansions:
- Transformations are conducted through a driver class
  NanoMipsTransformController. It scans through relocs of executable
  input sections and performs relaxations/expansions if possible or
  necessary
- New nanoMIPS specific options used in transformations added to lld
- New TableGen backend (NanoMipsTransformationPropertyEmitter.cpp) for
  emitting properties of instructions and relocations, transformation
  templates used in linker transformations
  • Loading branch information
AndrijaSyrmia committed Sep 13, 2024
1 parent 0722672 commit b45082c
Show file tree
Hide file tree
Showing 15 changed files with 3,310 additions and 33 deletions.
54 changes: 23 additions & 31 deletions lld/ELF/Arch/NanoMips.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

#include "InputFiles.h"
#include "InputSection.h"
#include "NanoMipsTransformations.h"
#include "OutputSections.h"
#include "Symbols.h"
#include "SyntheticSections.h"
Expand All @@ -16,7 +17,6 @@
#include "lld/Common/ErrorHandler.h"
#include "lld/Common/Memory.h"
#include "llvm/Object/ELF.h"
#include "llvm/Support/Endian.h"

using namespace llvm::object;
using namespace llvm::ELF;
Expand All @@ -35,27 +35,6 @@ namespace {

// Helper functions

template <endianness E> uint32_t readShuffle32(const uint8_t *loc) {
// Similar to microMIPS, little endian instructions are encoded as
// big endian so that the opcode comes first and that the hardware could
// know sooner if it is a 16bit, 32bit or 48bit instruction
uint32_t v = read32(loc);
if (E == support::little)
return (v << 16) | (v >> 16);
return v;
}

template <endianness E> void writeShuffle32(uint8_t *loc, uint64_t val) {
uint16_t *words = (uint16_t *)loc;
if (E == support::little)
std::swap(words[0], words[1]);

write32(loc, val);

if (E == support::little)
std::swap(words[0], words[1]);
}

template <endianness E> void writeImmOf48bitIns(uint8_t *loc, uint64_t val) {
// Different than the shuffle, the 48 bit instruction have
// 32 bit imms at last two 16bit words in order so that
Expand Down Expand Up @@ -104,11 +83,11 @@ uint32_t getNanoMipsMach(uint32_t eflags) {

// used for: R_NANOMIPS_HI20, R_NANOMIPS_PC_HI20 and R_NANOMIPS_GPREL_HI20
template <endianness E> void writeValueHi20(uint8_t *loc, uint64_t val) {
uint32_t instr = readShuffle32<E>(loc);
uint32_t instr = nanoMipsReadShuffle32<E>(loc);
uint32_t data = (val & ~1) | ((val >> 31) & 1);
data = (data & ~0xffc) | ((val >> 19) & 0xffc);
uint32_t masked = (instr & ~0x1ffffd) | (data & 0x1ffffd);
writeShuffle32<E>(loc, masked);
nanoMipsWriteShuffle32<E>(loc, masked);
}

// used for: R_NANOMIPS_PC4_S1 and R_NANOMIPS_GPREL7_S2
Expand All @@ -132,22 +111,22 @@ void writePcRel16(uint8_t *loc, uint64_t val, uint8_t bitsSize) {
// R_NANOMIPS_PC11_S1
template <endianness E>
void writePcRel32(uint8_t *loc, uint64_t val, uint8_t bitsSize) {
uint32_t instr = readShuffle32<E>(loc);
uint32_t instr = nanoMipsReadShuffle32<E>(loc);
val = (val & ~1) | ((val >> bitsSize) & 1);
uint32_t mask = (0xffffffff >> (32 - bitsSize));
uint32_t data = (instr & ~mask) | (val & mask);
writeShuffle32<E>(loc, data);
nanoMipsWriteShuffle32<E>(loc, data);
}

// used for: R_NANOMIPS_LO12, R_NANOMIPS_GPREL19_S2, R_NANOMIPS_GPREL18,
// R_NANOMIPS_GPREL17_S1 and R_NANOMIPS_GPREL_LO12
template <endianness E>
void writeValue32Shifted(uint8_t *loc, uint64_t val, uint8_t bitsSize,
uint8_t shift) {
uint32_t instr = readShuffle32<E>(loc);
uint32_t instr = nanoMipsReadShuffle32<E>(loc);
uint32_t mask = (0xffffffff >> (32 - bitsSize)) << shift;
uint32_t data = (instr & ~mask) | (val & mask);
writeShuffle32<E>(loc, data);
nanoMipsWriteShuffle32<E>(loc, data);
}
// used for checking values of: pcrel relocations and gprel ones also
// R_NANOMIPS_LO12
Expand Down Expand Up @@ -200,18 +179,26 @@ template <class ELFT> class NanoMips final : public TargetInfo {
void relocate(uint8_t *loc, const Relocation &rel,
uint64_t val) const override;

bool relaxOnce(int pass) const override {
return this->transformController.relaxOnce(pass);
}
void relocateAlloc(InputSectionBase &sec, uint8_t *buf) const override;

uint32_t calcEFlags() const override;

private:
NanoMipsTransformController<ELFT> transformController;
};
} // namespace

template <class ELFT> NanoMips<ELFT>::NanoMips() {

assert(config->nanoMipsExpandReg >= 0 && config->nanoMipsExpandReg < 32 &&
"nanoMIPS regs range from 0 to 32");
// TODO: When needed initialize symbolicRel, iRelativeRel, relativeRel, etc.
copyRel = R_NANOMIPS_COPY;
defaultMaxPageSize = 65536;
this->transformController.initState();
}

template <class ELFT>
Expand Down Expand Up @@ -254,6 +241,10 @@ RelExpr NanoMips<ELFT>::getRelExpr(RelType type, const Symbol &s,
case R_NANOMIPS_GPREL_LO12:
case R_NANOMIPS_GPREL7_S2:
return R_NANOMIPS_GPREL;
case R_NANOMIPS_NOTRAMP:
case R_NANOMIPS_NONE:
return R_NONE;

case R_NANOMIPS_ALIGN:
case R_NANOMIPS_MAX:
case R_NANOMIPS_FILL:
Expand All @@ -263,9 +254,10 @@ RelExpr NanoMips<ELFT>::getRelExpr(RelType type, const Symbol &s,
case R_NANOMIPS_FIXED:
case R_NANOMIPS_INSN32:
case R_NANOMIPS_INSN16:
case R_NANOMIPS_NOTRAMP:
case R_NANOMIPS_NONE:
return R_NONE;
// Used to save these relocations in relocation vector as
// R_NONE relocs are discareded from this vector, and
// these relocs are needed for relaxations/transformations
return R_RELAX_HINT;
default:
error(getErrorLocation(loc) + "unknown relocation (" + Twine(type) +
") against symbol " + toString(s) +
Expand Down
5 changes: 5 additions & 0 deletions lld/ELF/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
set(LLVM_TARGET_DEFINITIONS Options.td)
tablegen(LLVM Options.inc -gen-opt-parser-defs)

set(LLVM_TARGET_DEFINITIONS NanoMipsTransformationProperties.td)
tablegen(LLVM NanoMipsTransformationProperties.inc -gen-nanomips-transformation-properties)

add_public_tablegen_target(ELFOptionsTableGen)

if(LLVM_ENABLE_ZLIB)
Expand Down Expand Up @@ -29,6 +33,7 @@ add_lld_library(lldELF
Arch/MipsArchTree.cpp
Arch/MSP430.cpp
Arch/NanoMips.cpp
NanoMipsTransformations.cpp
Arch/PPC.cpp
Arch/PPC64.cpp
Arch/RISCV.cpp
Expand Down
7 changes: 7 additions & 0 deletions lld/ELF/Config.h
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,7 @@ struct Config {
bool emitRelocs;
bool enableNewDtags;
bool executeOnly;
bool expand;
bool exportDynamic;
bool fixCortexA53Errata843419;
bool fixCortexA8;
Expand All @@ -229,6 +230,11 @@ struct Config {
bool mergeArmExidx;
bool mipsN32Abi = false;
bool mmapOutputFile;
bool nanoMipsFixHw110880;
bool nanoMipsFixHw113064;
bool nanoMipsInsn32;
bool nanoMipsRelaxLo12;
bool nanoMipsStrictAddressModes;
bool nmagic;
bool noDynamicLinker = false;
bool noinhibitExec;
Expand Down Expand Up @@ -319,6 +325,7 @@ struct Config {
unsigned ltoPartitions;
unsigned ltoo;
unsigned optimize;
unsigned nanoMipsExpandReg;
StringRef thinLTOJobs;
unsigned timeTraceGranularity;
int32_t splitStackAdjustSize;
Expand Down
11 changes: 11 additions & 0 deletions lld/ELF/Driver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1107,6 +1107,7 @@ static void readConfigs(opt::InputArgList &args) {

config->executeOnly =
args.hasFlag(OPT_execute_only, OPT_no_execute_only, false);
config->expand = args.hasFlag(OPT_expand, OPT_no_expand, true);
config->exportDynamic =
args.hasFlag(OPT_export_dynamic, OPT_no_export_dynamic, false) ||
args.hasArg(OPT_shared);
Expand Down Expand Up @@ -1153,6 +1154,16 @@ static void readConfigs(opt::InputArgList &args) {
args.hasFlag(OPT_merge_exidx_entries, OPT_no_merge_exidx_entries, true);
config->mmapOutputFile =
args.hasFlag(OPT_mmap_output_file, OPT_no_mmap_output_file, true);
config->nanoMipsFixHw110880 =
args.hasFlag(OPT_fix_nmips_hw110880, OPT_no_fix_nmips_hw110880, false);
config->nanoMipsFixHw113064 =
args.hasFlag(OPT_fix_nmips_hw113064, OPT_no_fix_nmips_hw113064, false);
config->nanoMipsInsn32 = args.hasFlag(OPT_insn32, OPT_no_insn32, false);
config->nanoMipsRelaxLo12 =
args.hasFlag(OPT_relax_lo12, OPT_no_relax_lo12, false);
config->nanoMipsStrictAddressModes =
args.hasFlag(OPT_strict_address_modes, OPT_no_strict_address_modes, true);
config->nanoMipsExpandReg = args::getInteger(args, OPT_expand_reg, 1);
config->nmagic = args.hasFlag(OPT_nmagic, OPT_no_nmagic, false);
config->noinhibitExec = args.hasArg(OPT_noinhibit_exec);
config->nostdlib = args.hasArg(OPT_nostdlib);
Expand Down
2 changes: 2 additions & 0 deletions lld/ELF/InputSection.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ template <class ELFT> struct RelsOrRelas {
bool areRelocsRel() const { return rels.size(); }
};

struct NanoMipsRelaxAux;
// This is the base class of all sections that lld handles. Some are sections in
// input files, some are sections in the produced output file and some exist
// just as a convenience for implementing special ways of combining some
Expand Down Expand Up @@ -224,6 +225,7 @@ class InputSectionBase : public SectionBase {
// Auxiliary information for RISC-V linker relaxation. RISC-V does not use
// jumpInstrMod.
RISCVRelaxAux *relaxAux;
NanoMipsRelaxAux *nanoMipsRelaxAux;

// The compressed content size when `compressed` is true.
size_t compressedSize;
Expand Down
Loading

0 comments on commit b45082c

Please sign in to comment.