diff options
| author | Simon Atanasyan <simon@atanasyan.com> | 2015-07-21 05:54:22 +0000 |
|---|---|---|
| committer | Simon Atanasyan <simon@atanasyan.com> | 2015-07-21 05:54:22 +0000 |
| commit | f9db71eaec623d4e50f0efe6dc327388f70d8de3 (patch) | |
| tree | fa7fe76cad917dd08da98bd31aef9acbea9d78d0 /lld/lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.cpp | |
| parent | 61459cef40cd99fa9fcef7b986eb72b63635e4de (diff) | |
| download | bcm5719-llvm-f9db71eaec623d4e50f0efe6dc327388f70d8de3.tar.gz bcm5719-llvm-f9db71eaec623d4e50f0efe6dc327388f70d8de3.zip | |
[Mips] Handle R_MIPS_JALR relocation to omptimize jalr/jr instructions
llvm-svn: 242759
Diffstat (limited to 'lld/lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.cpp')
| -rw-r--r-- | lld/lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.cpp | 45 |
1 files changed, 35 insertions, 10 deletions
diff --git a/lld/lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.cpp b/lld/lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.cpp index 3e9619f9f19..c0feb735960 100644 --- a/lld/lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.cpp +++ b/lld/lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.cpp @@ -21,7 +21,8 @@ namespace { enum class CrossJumpMode { None, // Not a jump or non-isa-cross jump ToRegular, // cross isa jump to regular symbol - ToMicro // cross isa jump to microMips symbol + ToMicro, // cross isa jump to microMips symbol + ToMicroJalr// cross isa jump to microMips symbol referenced by R_MIPS_JALR }; typedef std::function<std::error_code(int64_t, bool)> OverflowChecker; @@ -178,7 +179,7 @@ static MipsRelocationParams getRelocationParams(uint32_t rType) { case R_MICROMIPS_GOT_OFST: return {4, 0xffff, 0, true, signedCheck<16>}; case R_MIPS_JALR: - return {4, 0x0, 0, false, dummyCheck}; + return {4, 0xffffffff, 0, false, dummyCheck}; case R_MICROMIPS_JALR: return {4, 0x0, 0, true, dummyCheck}; case R_MIPS_JUMP_SLOT: @@ -200,6 +201,10 @@ static MipsRelocationParams getRelocationParams(uint32_t rType) { } } +template <class ELFT> +static uint64_t relocRead(const MipsRelocationParams ¶ms, + const uint8_t *loc); + static int64_t getHi16(int64_t value) { return ((value + 0x8000) >> 16) & 0xffff; } @@ -299,6 +304,22 @@ static ErrorOr<int64_t> relocPc26(uint64_t P, uint64_t S, int64_t A) { return S + A - P; } +template <class ELFT> +static ErrorOr<int64_t> relocJalr(uint64_t P, uint64_t S, bool isCrossJump, + uint8_t *location) { + uint64_t ins = relocRead<ELFT>(getRelocationParams(R_MIPS_JALR), location); + if (isCrossJump) + return ins; + int64_t off = S - P - 4; + if (!llvm::isInt<18>(off)) + return ins; + if (ins == 0x0320f809) // jalr t9 + return 0x04110000 | ((off >> 2) & 0xffff); + if (ins == 0x03200008) // jr t9 + return 0x10000000 | ((off >> 2) & 0xffff); + return ins; +} + static int64_t relocRel32(int64_t A) { // If output relocation format is REL and the input one is RELA, the only // method to transfer the relocation addend from the input relocation @@ -309,7 +330,7 @@ static int64_t relocRel32(int64_t A) { static std::error_code adjustJumpOpCode(uint64_t &ins, uint64_t tgt, CrossJumpMode mode) { - if (mode == CrossJumpMode::None) + if (mode == CrossJumpMode::None || mode == CrossJumpMode::ToMicroJalr) return std::error_code(); bool toMicro = mode == CrossJumpMode::ToMicro; @@ -345,6 +366,8 @@ static CrossJumpMode getCrossJumpMode(const Reference &ref) { return CrossJumpMode::None; bool isTgtMicro = isMicroMipsAtom(ref.target()); switch (ref.kindValue()) { + case R_MIPS_JALR: + return isTgtMicro ? CrossJumpMode::ToMicroJalr : CrossJumpMode::None; case R_MIPS_26: case LLD_R_MIPS_GLOBAL_26: return isTgtMicro ? CrossJumpMode::ToMicro : CrossJumpMode::None; @@ -356,11 +379,12 @@ static CrossJumpMode getCrossJumpMode(const Reference &ref) { } } -static ErrorOr<int64_t> calculateRelocation(Reference::KindValue kind, - Reference::Addend addend, - uint64_t tgtAddr, uint64_t relAddr, - uint64_t gpAddr, bool isGP, - bool isCrossJump, bool isDynamic) { +template <class ELFT> +static ErrorOr<int64_t> +calculateRelocation(Reference::KindValue kind, Reference::Addend addend, + uint64_t tgtAddr, uint64_t relAddr, uint64_t gpAddr, + bool isGP, bool isCrossJump, bool isDynamic, + uint8_t *location) { switch (kind) { case R_MIPS_NONE: return 0; @@ -461,6 +485,7 @@ static ErrorOr<int64_t> calculateRelocation(Reference::KindValue kind, case R_MICROMIPS_LITERAL: return tgtAddr + addend - gpAddr; case R_MIPS_JALR: + return relocJalr<ELFT>(relAddr, tgtAddr, isCrossJump, location); case R_MICROMIPS_JALR: // We do not do JALR optimization now. return 0; @@ -591,8 +616,8 @@ std::error_code RelocationHandler<ELFT>::applyRelocation( if (kind == R_MIPS_NONE) break; auto params = getRelocationParams(kind); - res = calculateRelocation(kind, *res, sym, relAddr, gpAddr, isGpDisp, - isCrossJump, _ctx.isDynamic()); + res = calculateRelocation<ELFT>(kind, *res, sym, relAddr, gpAddr, isGpDisp, + isCrossJump, _ctx.isDynamic(), location); if (auto ec = res.getError()) return ec; // Check result for the last relocation only. |

