Skip to content

Commit 4283f5e

Browse files
[lld] Add thunks for hexagon
Co-authored-by: Alexey Karyakin <[email protected]>
1 parent c5ab70c commit 4283f5e

File tree

6 files changed

+321
-46
lines changed

6 files changed

+321
-46
lines changed

lld/ELF/Arch/Hexagon.cpp

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include "Symbols.h"
1111
#include "SyntheticSections.h"
1212
#include "Target.h"
13+
#include "Thunks.h"
1314
#include "lld/Common/ErrorHandler.h"
1415
#include "llvm/BinaryFormat/ELF.h"
1516
#include "llvm/Support/Endian.h"
@@ -30,6 +31,10 @@ class Hexagon final : public TargetInfo {
3031
const uint8_t *loc) const override;
3132
RelType getDynRel(RelType type) const override;
3233
int64_t getImplicitAddend(const uint8_t *buf, RelType type) const override;
34+
bool needsThunk(RelExpr expr, RelType type, const InputFile *file,
35+
uint64_t branchAddr, const Symbol &s,
36+
int64_t a) const override;
37+
bool inBranchRange(RelType type, uint64_t src, uint64_t dst) const override;
3338
void relocate(uint8_t *loc, const Relocation &rel,
3439
uint64_t val) const override;
3540
void writePltHeader(uint8_t *buf) const override;
@@ -57,6 +62,8 @@ Hexagon::Hexagon(Ctx &ctx) : TargetInfo(ctx) {
5762
tlsGotRel = R_HEX_TPREL_32;
5863
tlsModuleIndexRel = R_HEX_DTPMOD_32;
5964
tlsOffsetRel = R_HEX_DTPREL_32;
65+
66+
needsThunks = true;
6067
}
6168

6269
uint32_t Hexagon::calcEFlags() const {
@@ -252,6 +259,34 @@ static uint32_t findMaskR16(Ctx &ctx, uint32_t insn) {
252259

253260
static void or32le(uint8_t *p, int32_t v) { write32le(p, read32le(p) | v); }
254261

262+
bool Hexagon::inBranchRange(RelType type, uint64_t src, uint64_t dst) const {
263+
int64_t offset = dst - src;
264+
switch (type) {
265+
case llvm::ELF::R_HEX_B22_PCREL:
266+
case llvm::ELF::R_HEX_PLT_B22_PCREL:
267+
case llvm::ELF::R_HEX_GD_PLT_B22_PCREL:
268+
case llvm::ELF::R_HEX_LD_PLT_B22_PCREL:
269+
return llvm::isInt<22>(offset >> 2);
270+
case llvm::ELF::R_HEX_B15_PCREL:
271+
return llvm::isInt<15>(offset >> 2);
272+
break;
273+
case llvm::ELF::R_HEX_B13_PCREL:
274+
return llvm::isInt<13>(offset >> 2);
275+
break;
276+
case llvm::ELF::R_HEX_B9_PCREL:
277+
return llvm::isInt<9>(offset >> 2);
278+
default:
279+
return true;
280+
}
281+
llvm_unreachable("unsupported relocation");
282+
}
283+
284+
bool Hexagon::needsThunk(RelExpr expr, RelType type, const InputFile *file,
285+
uint64_t branchAddr, const Symbol &s,
286+
int64_t a) const {
287+
return !ctx.target->inBranchRange(type, branchAddr, s.getVA(ctx, a));
288+
}
289+
255290
void Hexagon::relocate(uint8_t *loc, const Relocation &rel,
256291
uint64_t val) const {
257292
switch (rel.type) {

lld/ELF/Relocations.cpp

Lines changed: 40 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2037,17 +2037,44 @@ void ThunkCreator::mergeThunks(ArrayRef<OutputSection *> outputSections) {
20372037
});
20382038
}
20392039

2040-
static int64_t getPCBias(Ctx &ctx, RelType type) {
2041-
if (ctx.arg.emachine != EM_ARM)
2042-
return 0;
2043-
switch (type) {
2044-
case R_ARM_THM_JUMP19:
2045-
case R_ARM_THM_JUMP24:
2046-
case R_ARM_THM_CALL:
2047-
return 4;
2048-
default:
2049-
return 8;
2040+
constexpr uint32_t HEXAGON_MASK_END_PACKET = 3 << 14;
2041+
constexpr uint32_t HEXAGON_END_OF_PACKET = 3 << 14;
2042+
constexpr uint32_t HEXAGON_END_OF_DUPLEX = 0 << 14;
2043+
2044+
// Return the distance between the packet start and the instruction in the
2045+
// relocation.
2046+
static int getHexagonPacketOffset(const InputSection &isec,
2047+
const Relocation &rel) {
2048+
const ArrayRef<uint8_t> SectContents = isec.content();
2049+
2050+
// Search back as many as 3 instructions.
2051+
for (unsigned i = 0;; i++) {
2052+
if (i == 3 || rel.offset < (i + 1) * 4)
2053+
return i * 4;
2054+
uint32_t instWord = 0;
2055+
const ArrayRef<uint8_t> InstWordContents =
2056+
SectContents.drop_front(rel.offset - (i + 1) * 4);
2057+
::memcpy(&instWord, InstWordContents.data(), sizeof(instWord));
2058+
if (((instWord & HEXAGON_MASK_END_PACKET) == HEXAGON_END_OF_PACKET) ||
2059+
((instWord & HEXAGON_MASK_END_PACKET) == HEXAGON_END_OF_DUPLEX))
2060+
return i * 4;
2061+
}
2062+
}
2063+
static int64_t getPCBias(Ctx &ctx, const InputSection &isec,
2064+
const Relocation &rel) {
2065+
if (ctx.arg.emachine == EM_ARM) {
2066+
switch (rel.type) {
2067+
case R_ARM_THM_JUMP19:
2068+
case R_ARM_THM_JUMP24:
2069+
case R_ARM_THM_CALL:
2070+
return 4;
2071+
default:
2072+
return 8;
2073+
}
20502074
}
2075+
if (ctx.arg.emachine == EM_HEXAGON)
2076+
return -getHexagonPacketOffset(isec, rel);
2077+
return 0;
20512078
}
20522079

20532080
// Find or create a ThunkSection within the InputSectionDescription (ISD) that
@@ -2059,7 +2086,7 @@ ThunkSection *ThunkCreator::getISDThunkSec(OutputSection *os,
20592086
const Relocation &rel,
20602087
uint64_t src) {
20612088
// See the comment in getThunk for -pcBias below.
2062-
const int64_t pcBias = getPCBias(ctx, rel.type);
2089+
const int64_t pcBias = getPCBias(ctx, *isec, rel);
20632090
for (std::pair<ThunkSection *, uint32_t> tp : isd->thunkSections) {
20642091
ThunkSection *ts = tp.first;
20652092
uint64_t tsBase = os->addr + ts->outSecOff - pcBias;
@@ -2220,7 +2247,7 @@ std::pair<Thunk *, bool> ThunkCreator::getThunk(InputSection *isec,
22202247
// out in the relocation addend. We compensate for the PC bias so that
22212248
// an Arm and Thumb relocation to the same destination get the same keyAddend,
22222249
// which is usually 0.
2223-
const int64_t pcBias = getPCBias(ctx, rel.type);
2250+
const int64_t pcBias = getPCBias(ctx, *isec, rel);
22242251
const int64_t keyAddend = rel.addend + pcBias;
22252252

22262253
// We use a ((section, offset), addend) pair to find the thunk position if
@@ -2379,7 +2406,7 @@ bool ThunkCreator::createThunks(uint32_t pass,
23792406
// STT_SECTION + non-zero addend, clear the addend after
23802407
// redirection.
23812408
if (ctx.arg.emachine != EM_MIPS)
2382-
rel.addend = -getPCBias(ctx, rel.type);
2409+
rel.addend = -getPCBias(ctx, *isec, rel);
23832410
}
23842411

23852412
for (auto &p : isd->thunkSections)

lld/ELF/Thunks.cpp

Lines changed: 71 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -402,6 +402,22 @@ class AVRThunk : public Thunk {
402402
void addSymbols(ThunkSection &isec) override;
403403
};
404404

405+
// Hexagon CPUs need thunks for R_HEX_B{9,1{3,5},22}_PCREL,
406+
// R_HEX_{,GD_}PLT_B22_PCREL when their destination is out of
407+
// range.
408+
class HexagonThunk : public Thunk {
409+
public:
410+
HexagonThunk(Ctx &ctx, const InputSection &isec, Relocation &rel,
411+
Symbol &dest)
412+
: Thunk(ctx, dest, 0), relOffset(rel.offset) {
413+
alignment = 4;
414+
}
415+
uint32_t relOffset;
416+
uint32_t size() override { return ctx.arg.isPic ? 12 : 8; }
417+
void writeTo(uint8_t *buf) override;
418+
void addSymbols(ThunkSection &isec) override;
419+
};
420+
405421
// MIPS LA25 thunk
406422
class MipsThunk final : public Thunk {
407423
public:
@@ -1475,6 +1491,39 @@ bool PPC64LongBranchThunk::isCompatibleWith(const InputSection &isec,
14751491
return rel.type == R_PPC64_REL24 || rel.type == R_PPC64_REL14;
14761492
}
14771493

1494+
// Hexagon Target Thunks
1495+
static uint64_t getHexagonThunkDestVA(Ctx &ctx, const Symbol &s, int64_t a) {
1496+
uint64_t v = s.isInPlt(ctx) ? s.getPltVA(ctx) : s.getVA(ctx, a);
1497+
return SignExtend64<32>(v); // FIXME: sign extend to 64-bit?
1498+
}
1499+
1500+
void HexagonThunk::writeTo(uint8_t *buf) {
1501+
uint64_t s = getHexagonThunkDestVA(ctx, destination, addend);
1502+
uint64_t p = getThunkTargetSym()->getVA(ctx);
1503+
1504+
if (ctx.arg.isPic) {
1505+
write32(ctx, buf + 0, 0x00004000); // { immext(#0)
1506+
ctx.target->relocateNoSym(buf, R_HEX_B32_PCREL_X, s - p);
1507+
write32(ctx, buf + 4, 0x6a49c00e); // r14 = add(pc,##0) }
1508+
ctx.target->relocateNoSym(buf + 4, R_HEX_6_PCREL_X, s - p);
1509+
1510+
write32(ctx, buf + 8, 0x528ec000); // { jumpr r14 }
1511+
} else {
1512+
write32(ctx, buf + 0, 0x00004000); // { immext
1513+
ctx.target->relocateNoSym(buf, R_HEX_B32_PCREL_X, s - p);
1514+
write32(ctx, buf + 4, 0x5800c000); // jump <> }
1515+
ctx.target->relocateNoSym(buf + 4, R_HEX_B22_PCREL_X, s - p);
1516+
}
1517+
}
1518+
void HexagonThunk::addSymbols(ThunkSection &isec) {
1519+
Symbol *enclosing = isec.getEnclosingSymbol(relOffset);
1520+
StringRef src = enclosing ? enclosing->getName() : isec.name;
1521+
1522+
addSymbol(
1523+
saver().save("__hexagon_thunk_" + destination.getName() + "_from_" + src),
1524+
STT_FUNC, 0, isec);
1525+
}
1526+
14781527
Thunk::Thunk(Ctx &ctx, Symbol &d, int64_t a)
14791528
: ctx(ctx), destination(d), addend(a), offset(0) {
14801529
destination.thunkAccessed = true;
@@ -1644,6 +1693,24 @@ static std::unique_ptr<Thunk> addThunkAVR(Ctx &ctx, RelType type, Symbol &s,
16441693
}
16451694
}
16461695

1696+
static std::unique_ptr<Thunk> addThunkHexagon(Ctx &ctx,
1697+
const InputSection &isec,
1698+
Relocation &rel, Symbol &s) {
1699+
switch (rel.type) {
1700+
case R_HEX_B9_PCREL:
1701+
case R_HEX_B13_PCREL:
1702+
case R_HEX_B15_PCREL:
1703+
case R_HEX_B22_PCREL:
1704+
case R_HEX_PLT_B22_PCREL:
1705+
case R_HEX_GD_PLT_B22_PCREL:
1706+
return std::make_unique<HexagonThunk>(ctx, isec, rel, s);
1707+
default:
1708+
Fatal(ctx) << "unrecognized relocation " << rel.type << " to " << &s
1709+
<< " for hexagon target";
1710+
llvm_unreachable("");
1711+
}
1712+
}
1713+
16471714
static std::unique_ptr<Thunk> addThunkMips(Ctx &ctx, RelType type, Symbol &s) {
16481715
if ((s.stOther & STO_MIPS_MICROMIPS) && isMipsR6(ctx))
16491716
return std::make_unique<MicroMipsR6Thunk>(ctx, s);
@@ -1713,8 +1780,11 @@ std::unique_ptr<Thunk> elf::addThunk(Ctx &ctx, const InputSection &isec,
17131780
return addThunkPPC32(ctx, isec, rel, s);
17141781
case EM_PPC64:
17151782
return addThunkPPC64(ctx, rel.type, s, a);
1783+
case EM_HEXAGON:
1784+
return addThunkHexagon(ctx, isec, rel, s);
17161785
default:
1717-
llvm_unreachable("add Thunk only supported for ARM, AVR, Mips and PowerPC");
1786+
llvm_unreachable(
1787+
"add Thunk only supported for ARM, AVR, Hexagon, Mips and PowerPC");
17181788
}
17191789
}
17201790

lld/test/ELF/hexagon-jump-error.s

Lines changed: 0 additions & 32 deletions
This file was deleted.

0 commit comments

Comments
 (0)