Skip to content

Commit 6b20e44

Browse files
[lld] Add thunks for hexagon
Co-authored-by: Alexey Karyakin <[email protected]>
1 parent 36d757f commit 6b20e44

File tree

6 files changed

+307
-46
lines changed

6 files changed

+307
-46
lines changed

lld/ELF/Arch/Hexagon.cpp

Lines changed: 36 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 {
@@ -253,6 +260,35 @@ static uint32_t findMaskR16(uint32_t insn) {
253260

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

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

lld/ELF/Relocations.cpp

Lines changed: 41 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2054,18 +2054,46 @@ void ThunkCreator::mergeThunks(ArrayRef<OutputSection *> outputSections) {
20542054
});
20552055
}
20562056

2057-
static int64_t getPCBias(Ctx &ctx, RelType type) {
2058-
if (ctx.arg.emachine != EM_ARM)
2059-
return 0;
2060-
switch (type) {
2061-
case R_ARM_THM_JUMP19:
2062-
case R_ARM_THM_JUMP24:
2063-
case R_ARM_THM_CALL:
2064-
return 4;
2065-
default:
2066-
return 8;
2057+
static const uint32_t HEXAGON_MASK_END_PACKET = 3 << 14;
2058+
static const uint32_t HEXAGON_END_OF_PACKET = 3 << 14;
2059+
static const uint32_t HEXAGON_END_OF_DUPLEX = 0 << 14;
2060+
2061+
// Return the distance between the packet start and the instruction in the
2062+
// relocation.
2063+
static int getHexagonPacketOffset(const InputSection &isec,
2064+
const Relocation &rel) {
2065+
const ArrayRef<uint8_t> SectContents = isec.content();
2066+
2067+
// Search back as many as 3 instructions.
2068+
for (unsigned i = 0;; i++) {
2069+
if (i == 3 || rel.offset < (i + 1) * 4)
2070+
return i * 4;
2071+
uint32_t instWord = 0;
2072+
const ArrayRef<uint8_t> InstWordContents =
2073+
SectContents.drop_front(rel.offset - (i + 1) * 4);
2074+
::memcpy(&instWord, InstWordContents.data(), sizeof(instWord));
2075+
if (((instWord & HEXAGON_MASK_END_PACKET) == HEXAGON_END_OF_PACKET) ||
2076+
((instWord & HEXAGON_MASK_END_PACKET) == HEXAGON_END_OF_DUPLEX))
2077+
return i * 4;
20672078
}
20682079
}
2080+
static int64_t getPCBias(Ctx &ctx, const InputSection &isec,
2081+
const Relocation &rel) {
2082+
if (ctx.arg.emachine == EM_ARM) {
2083+
switch (rel.type) {
2084+
case R_ARM_THM_JUMP19:
2085+
case R_ARM_THM_JUMP24:
2086+
case R_ARM_THM_CALL:
2087+
return 4;
2088+
default:
2089+
return 8;
2090+
}
2091+
}
2092+
if (ctx.arg.emachine == EM_HEXAGON) {
2093+
return -getHexagonPacketOffset(isec, rel);
2094+
}
2095+
return 0;
2096+
}
20692097

20702098
// Find or create a ThunkSection within the InputSectionDescription (ISD) that
20712099
// is in range of Src. An ISD maps to a range of InputSections described by a
@@ -2076,7 +2104,7 @@ ThunkSection *ThunkCreator::getISDThunkSec(OutputSection *os,
20762104
const Relocation &rel,
20772105
uint64_t src) {
20782106
// See the comment in getThunk for -pcBias below.
2079-
const int64_t pcBias = getPCBias(ctx, rel.type);
2107+
const int64_t pcBias = getPCBias(ctx, *isec, rel);
20802108
for (std::pair<ThunkSection *, uint32_t> tp : isd->thunkSections) {
20812109
ThunkSection *ts = tp.first;
20822110
uint64_t tsBase = os->addr + ts->outSecOff - pcBias;
@@ -2237,7 +2265,7 @@ std::pair<Thunk *, bool> ThunkCreator::getThunk(InputSection *isec,
22372265
// out in the relocation addend. We compensate for the PC bias so that
22382266
// an Arm and Thumb relocation to the same destination get the same keyAddend,
22392267
// which is usually 0.
2240-
const int64_t pcBias = getPCBias(ctx, rel.type);
2268+
const int64_t pcBias = getPCBias(ctx, *isec, rel);
22412269
const int64_t keyAddend = rel.addend + pcBias;
22422270

22432271
// We use a ((section, offset), addend) pair to find the thunk position if
@@ -2383,7 +2411,7 @@ bool ThunkCreator::createThunks(uint32_t pass,
23832411
// STT_SECTION + non-zero addend, clear the addend after
23842412
// redirection.
23852413
if (ctx.arg.emachine != EM_MIPS)
2386-
rel.addend = -getPCBias(ctx, rel.type);
2414+
rel.addend = -getPCBias(ctx, *isec, rel);
23872415
}
23882416

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

lld/ELF/Thunks.cpp

Lines changed: 67 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -351,6 +351,21 @@ class AVRThunk : public Thunk {
351351
void addSymbols(ThunkSection &isec) override;
352352
};
353353

354+
// Hexagon CPUs need thunks for <<FIXME TBD>>
355+
// when their destination is out of range [0, 0x_?].
356+
class HexagonThunk : public Thunk {
357+
public:
358+
HexagonThunk(Ctx &ctx, const InputSection &isec, Relocation &rel,
359+
Symbol &dest)
360+
: Thunk(ctx, dest, 0), RelOffset(rel.offset) {
361+
alignment = 4;
362+
}
363+
uint32_t RelOffset;
364+
uint32_t size() override { return ctx.arg.isPic ? 12 : 8; }
365+
void writeTo(uint8_t *buf) override;
366+
void addSymbols(ThunkSection &isec) override;
367+
};
368+
354369
// MIPS LA25 thunk
355370
class MipsThunk final : public Thunk {
356371
public:
@@ -1365,6 +1380,39 @@ bool PPC64LongBranchThunk::isCompatibleWith(const InputSection &isec,
13651380
return rel.type == R_PPC64_REL24 || rel.type == R_PPC64_REL14;
13661381
}
13671382

1383+
// Hexagon Target Thunks
1384+
static uint64_t getHexagonThunkDestVA(Ctx &ctx, const Symbol &s, int64_t a) {
1385+
uint64_t v = s.isInPlt(ctx) ? s.getPltVA(ctx) : s.getVA(ctx, a);
1386+
return SignExtend64<32>(v); // FIXME: sign extend to 64-bit?
1387+
}
1388+
1389+
void HexagonThunk::writeTo(uint8_t *buf) {
1390+
uint64_t s = getHexagonThunkDestVA(ctx, destination, addend);
1391+
uint64_t p = getThunkTargetSym()->getVA(ctx);
1392+
1393+
if (ctx.arg.isPic) {
1394+
write32(ctx, buf + 0, 0x00004000); // { immext(#0)
1395+
ctx.target->relocateNoSym(buf, R_HEX_B32_PCREL_X, s - p);
1396+
write32(ctx, buf + 4, 0x6a49c00e); // r14 = add(pc,##0) }
1397+
ctx.target->relocateNoSym(buf + 4, R_HEX_6_PCREL_X, s - p);
1398+
1399+
write32(ctx, buf + 8, 0x528ec000); // { jumpr r14 }
1400+
} else {
1401+
write32(ctx, buf + 0, 0x00004000); // { immext
1402+
ctx.target->relocateNoSym(buf, R_HEX_B32_PCREL_X, s - p);
1403+
write32(ctx, buf + 4, 0x5800c000); // jump <> }
1404+
ctx.target->relocateNoSym(buf + 4, R_HEX_B22_PCREL_X, s - p);
1405+
}
1406+
}
1407+
void HexagonThunk::addSymbols(ThunkSection &isec) {
1408+
Symbol *enclosing = isec.getEnclosingSymbol(RelOffset);
1409+
StringRef src = enclosing ? enclosing->getName() : isec.name;
1410+
1411+
addSymbol(saver().save("__trampoline_for_" + destination.getName() +
1412+
"_from_" + src),
1413+
STT_FUNC, 0, isec);
1414+
}
1415+
13681416
Thunk::Thunk(Ctx &ctx, Symbol &d, int64_t a)
13691417
: ctx(ctx), destination(d), addend(a), offset(0) {
13701418
destination.thunkAccessed = true;
@@ -1531,6 +1579,21 @@ static Thunk *addThunkAVR(Ctx &ctx, RelType type, Symbol &s, int64_t a) {
15311579
}
15321580
}
15331581

1582+
static Thunk *addThunkHexagon(Ctx &ctx, const InputSection &isec,
1583+
Relocation &rel, Symbol &s) {
1584+
switch (rel.type) {
1585+
case R_HEX_B9_PCREL:
1586+
case R_HEX_B13_PCREL:
1587+
case R_HEX_B15_PCREL:
1588+
case R_HEX_B22_PCREL:
1589+
case R_HEX_PLT_B22_PCREL:
1590+
case R_HEX_GD_PLT_B22_PCREL:
1591+
return make<HexagonThunk>(ctx, isec, rel, s);
1592+
default:
1593+
fatal("unrecognized relocation type " + toString(rel.type));
1594+
}
1595+
}
1596+
15341597
static Thunk *addThunkMips(Ctx &ctx, RelType type, Symbol &s) {
15351598
if ((s.stOther & STO_MIPS_MICROMIPS) && isMipsR6(ctx))
15361599
return make<MicroMipsR6Thunk>(ctx, s);
@@ -1596,8 +1659,11 @@ Thunk *elf::addThunk(Ctx &ctx, const InputSection &isec, Relocation &rel) {
15961659
return addThunkPPC32(ctx, isec, rel, s);
15971660
case EM_PPC64:
15981661
return addThunkPPC64(ctx, rel.type, s, a);
1662+
case EM_HEXAGON:
1663+
return addThunkHexagon(ctx, isec, rel, s);
15991664
default:
1600-
llvm_unreachable("add Thunk only supported for ARM, AVR, Mips and PowerPC");
1665+
llvm_unreachable(
1666+
"add Thunk only supported for ARM, AVR, Hexagon, Mips and PowerPC");
16011667
}
16021668
}
16031669

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

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

lld/test/ELF/hexagon-thunks-packets.s

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
# REQUIRES: hexagon
2+
# RUN: llvm-mc -filetype=obj -triple=hexagon-unknown-linux-musl %s -o %t.o
3+
# RUN: ld.lld %t.o -o %t
4+
# RUN: llvm-objdump -d %t 2>&1 | FileCheck --check-prefix=CHECK-NONPIC %s
5+
# RUN: llvm-mc -filetype=obj --position-independent \
6+
# RUN: -triple=hexagon-unknown-linux-musl %s -o %t.o
7+
# RUN: ld.lld --pie %t.o -o %t
8+
# RUN: llvm-objdump -d %t 2>&1 | FileCheck --check-prefix=CHECK-PIC %s
9+
10+
# Packets with pc-relative relocations are more interesting because
11+
# the offset must be relative to the start of the source, destination
12+
# packets and not necessarily the instruction word containing the jump/call.
13+
14+
# CHECK: Disassembly of section .text:
15+
16+
# CHECK-NONPIC: 000200b4 <__trampoline_for_myfn_a_from_.text.thunk>:
17+
# CHECK-NONPIC: { immext(#0x1000040)
18+
# CHECK-NONPIC: jump 0x1020110 }
19+
20+
# CHECK-PIC: 00010150 <__trampoline_for_myfn_a_from_.text.thunk>:
21+
# CHECK-PIC: { immext(#0x1000040)
22+
# CHECK-PIC: r14 = add(pc,##0x1000060) }
23+
# CHECK-PIC: { jumpr r14 }
24+
25+
# CHECK-NONPIC: 000200bc <myfn_b>:
26+
# CHECK-NONPIC: { jumpr r31 }
27+
# CHECK-PIC: 0001015c <myfn_b>:
28+
# CHECK-PIC: { jumpr r31 }
29+
.globl myfn_b
30+
.type myfn_b, @function
31+
myfn_b:
32+
jumpr r31
33+
.size myfn_b, .-myfn_b
34+
35+
# CHECK-PIC: 00010160 <main>:
36+
.globl main
37+
.type main, @function
38+
main:
39+
{ r0 = #0
40+
call myfn_a }
41+
# CHECK-PIC: { call 0x10150
42+
# CHECK-NONPIC: { call 0x200b4
43+
# CHECK: r0 = #0x0 }
44+
call myfn_a
45+
# CHECK-PIC: call 0x10150
46+
# CHECK-NONPIC: call 0x200b4
47+
call myfn_b
48+
# CHECK-PIC: call 0x1015c
49+
# CHECK-NONPIC: call 0x200bc
50+
51+
{ r2 = add(r0, r1)
52+
if (p0) call #myfn_b
53+
if (!p0) call #myfn_a }
54+
# CHECK-PIC: { if (p0) call 0x1015c
55+
# CHECK-PIC: if (!p0) call 0x10150
56+
# CHECK-NONPIC: { if (p0) call 0x200bc
57+
# CHECK-NONPIC: if (!p0) call 0x200b4
58+
# CHECK: r2 = add(r0,r1) }
59+
60+
{ r2 = add(r0, r1)
61+
if (p0) call #myfn_a
62+
if (!p0) call #myfn_a }
63+
# CHECK-PIC: { if (p0) call 0x10150
64+
# CHECK-PIC: if (!p0) call 0x10150
65+
# CHECK-NONPIC: { if (p0) call 0x200b4
66+
# CHECK-NONPIC: if (!p0) call 0x200b4
67+
# CHECK: r2 = add(r0,r1) }
68+
69+
{ r2 = add(r0, r1)
70+
r1 = r4
71+
r4 = r5
72+
if (r0 == #0) jump:t #myfn_a }
73+
# CHECK-PIC: { if (r0==#0) jump:t 0x10150
74+
# CHECK-NONPIC: { if (r0==#0) jump:t 0x200b4
75+
# CHECK: r2 = add(r0,r1)
76+
# CHECK: r1 = r4; r4 = r5 }
77+
78+
{ r2 = add(r0, r1)
79+
r4 = r5
80+
if (r0 <= #0) jump:t #myfn_a
81+
p1 = cmp.eq(r0, #0); if (p1.new) jump:nt #myfn_a }
82+
# CHECK-NONPIC: { if (r0<=#0) jump:t 0x200b4
83+
# CHECK-NONPIC: p1 = cmp.eq(r0,#0x0); if (p1.new) jump:nt 0x200b4
84+
# CHECK-PIC: { if (r0<=#0) jump:t 0x10150
85+
# CHECK-PIC: p1 = cmp.eq(r0,#0x0); if (p1.new) jump:nt 0x10150
86+
# CHECK: r2 = add(r0,r1)
87+
# CHECK: r4 = r5 }
88+
89+
{r0 = #0; jump #myfn_a}
90+
# CHECK-PIC: { r0 = #0x0 ; jump 0x10150 }
91+
# CHECK-NONPIC: { r0 = #0x0 ; jump 0x200b4 }
92+
{r0 = #0; jump #myfn_b}
93+
# CHECK-PIC: { r0 = #0x0 ; jump 0x1015c }
94+
# CHECK-NONPIC: { r0 = #0x0 ; jump 0x200bc }
95+
jumpr r31
96+
.size main, .-main
97+
98+
.section .text.foo
99+
.skip 0x1000000
100+
101+
.globl myfn_a
102+
.type myfn_a, @function
103+
myfn_a:
104+
{r0 = #0; jump #myfn_b}
105+
jumpr r31
106+
.size myfn_a, .-myfn_a
107+
108+
# CHECK-NONPIC: 01020110 <myfn_a>:
109+
# CHECK-NONPIC: { r0 = #0x0 ; jump 0x1020118 }
110+
# CHECK-NONPIC: { jumpr r31 }
111+
112+
# CHECK-NONPIC: 01020118 <__trampoline_for_myfn_b_from_.text.thunk>:
113+
# CHECK-NONPIC: { immext(#0xfeffff80)
114+
# CHECK-NONPIC: jump 0x200bc }
115+
116+
# CHECK-PIC: 010101b8 <__trampoline_for_myfn_b_from_.text.thunk>:
117+
# CHECK-PIC: { immext(#0xfeffff80)
118+
# CHECK-PIC: r14 = add(pc,##0xfeffffa4) }
119+
# CHECK-PIC: { jumpr r14 }

0 commit comments

Comments
 (0)