aboutsummaryrefslogtreecommitdiff
path: root/lld/ELF/Thunks.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lld/ELF/Thunks.cpp')
-rw-r--r--lld/ELF/Thunks.cpp72
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");
}
}