diff options
Diffstat (limited to 'lld/ELF/Thunks.cpp')
-rw-r--r-- | lld/ELF/Thunks.cpp | 72 |
1 files changed, 71 insertions, 1 deletions
diff --git a/lld/ELF/Thunks.cpp b/lld/ELF/Thunks.cpp index c26ba76..65d0f09 100644 --- a/lld/ELF/Thunks.cpp +++ b/lld/ELF/Thunks.cpp @@ -415,6 +415,22 @@ public: void addSymbols(ThunkSection &isec) override; }; +// Hexagon CPUs need thunks for R_HEX_B{9,1{3,5},22}_PCREL, +// R_HEX_{,GD_}PLT_B22_PCREL when their destination is out of +// range. +class HexagonThunk : public Thunk { +public: + HexagonThunk(Ctx &ctx, const InputSection &isec, Relocation &rel, + Symbol &dest) + : Thunk(ctx, dest, 0), relOffset(rel.offset) { + alignment = 4; + } + uint32_t relOffset; + uint32_t size() override { return ctx.arg.isPic ? 12 : 8; } + void writeTo(uint8_t *buf) override; + void addSymbols(ThunkSection &isec) override; +}; + // MIPS LA25 thunk class MipsThunk final : public Thunk { public: @@ -1519,6 +1535,39 @@ bool PPC64LongBranchThunk::isCompatibleWith(const InputSection &isec, return rel.type == R_PPC64_REL24 || rel.type == R_PPC64_REL14; } +// Hexagon Target Thunks +static uint64_t getHexagonThunkDestVA(Ctx &ctx, const Symbol &s, int64_t a) { + uint64_t v = s.isInPlt(ctx) ? s.getPltVA(ctx) : s.getVA(ctx, a); + return SignExtend64<32>(v); +} + +void HexagonThunk::writeTo(uint8_t *buf) { + uint64_t s = getHexagonThunkDestVA(ctx, destination, addend); + uint64_t p = getThunkTargetSym()->getVA(ctx); + + if (ctx.arg.isPic) { + write32(ctx, buf + 0, 0x00004000); // { immext(#0) + ctx.target->relocateNoSym(buf, R_HEX_B32_PCREL_X, s - p); + write32(ctx, buf + 4, 0x6a49c00e); // r14 = add(pc,##0) } + ctx.target->relocateNoSym(buf + 4, R_HEX_6_PCREL_X, s - p); + + write32(ctx, buf + 8, 0x528ec000); // { jumpr r14 } + } else { + write32(ctx, buf + 0, 0x00004000); // { immext + ctx.target->relocateNoSym(buf, R_HEX_B32_PCREL_X, s - p); + write32(ctx, buf + 4, 0x5800c000); // jump <> } + ctx.target->relocateNoSym(buf + 4, R_HEX_B22_PCREL_X, s - p); + } +} +void HexagonThunk::addSymbols(ThunkSection &isec) { + Symbol *enclosing = isec.getEnclosingSymbol(relOffset); + StringRef src = enclosing ? enclosing->getName() : isec.name; + + addSymbol( + saver().save("__hexagon_thunk_" + destination.getName() + "_from_" + src), + STT_FUNC, 0, isec); +} + Thunk::Thunk(Ctx &ctx, Symbol &d, int64_t a) : ctx(ctx), destination(d), addend(a), offset(0) { destination.thunkAccessed = true; @@ -1692,6 +1741,24 @@ static std::unique_ptr<Thunk> addThunkAVR(Ctx &ctx, RelType type, Symbol &s, } } +static std::unique_ptr<Thunk> addThunkHexagon(Ctx &ctx, + const InputSection &isec, + Relocation &rel, Symbol &s) { + switch (rel.type) { + case R_HEX_B9_PCREL: + case R_HEX_B13_PCREL: + case R_HEX_B15_PCREL: + case R_HEX_B22_PCREL: + case R_HEX_PLT_B22_PCREL: + case R_HEX_GD_PLT_B22_PCREL: + return std::make_unique<HexagonThunk>(ctx, isec, rel, s); + default: + Fatal(ctx) << "unrecognized relocation " << rel.type << " to " << &s + << " for hexagon target"; + llvm_unreachable(""); + } +} + static std::unique_ptr<Thunk> addThunkMips(Ctx &ctx, RelType type, Symbol &s) { if ((s.stOther & STO_MIPS_MICROMIPS) && isMipsR6(ctx)) return std::make_unique<MicroMipsR6Thunk>(ctx, s); @@ -1761,8 +1828,11 @@ std::unique_ptr<Thunk> elf::addThunk(Ctx &ctx, const InputSection &isec, return addThunkPPC32(ctx, isec, rel, s); case EM_PPC64: return addThunkPPC64(ctx, rel.type, s, a); + case EM_HEXAGON: + return addThunkHexagon(ctx, isec, rel, s); default: - llvm_unreachable("add Thunk only supported for ARM, AVR, Mips and PowerPC"); + llvm_unreachable( + "add Thunk only supported for ARM, AVR, Hexagon, Mips and PowerPC"); } } |