xref: /freebsd/contrib/llvm-project/lld/ELF/Arch/RISCV.cpp (revision 0b57cec536236d46e3dba9bd041533462f33dbb7)
1*0b57cec5SDimitry Andric //===- RISCV.cpp ----------------------------------------------------------===//
2*0b57cec5SDimitry Andric //
3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*0b57cec5SDimitry Andric //
7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
8*0b57cec5SDimitry Andric 
9*0b57cec5SDimitry Andric #include "InputFiles.h"
10*0b57cec5SDimitry Andric #include "SyntheticSections.h"
11*0b57cec5SDimitry Andric #include "Target.h"
12*0b57cec5SDimitry Andric 
13*0b57cec5SDimitry Andric using namespace llvm;
14*0b57cec5SDimitry Andric using namespace llvm::object;
15*0b57cec5SDimitry Andric using namespace llvm::support::endian;
16*0b57cec5SDimitry Andric using namespace llvm::ELF;
17*0b57cec5SDimitry Andric using namespace lld;
18*0b57cec5SDimitry Andric using namespace lld::elf;
19*0b57cec5SDimitry Andric 
20*0b57cec5SDimitry Andric namespace {
21*0b57cec5SDimitry Andric 
22*0b57cec5SDimitry Andric class RISCV final : public TargetInfo {
23*0b57cec5SDimitry Andric public:
24*0b57cec5SDimitry Andric   RISCV();
25*0b57cec5SDimitry Andric   uint32_t calcEFlags() const override;
26*0b57cec5SDimitry Andric   void writeGotHeader(uint8_t *buf) const override;
27*0b57cec5SDimitry Andric   void writeGotPlt(uint8_t *buf, const Symbol &s) const override;
28*0b57cec5SDimitry Andric   void writePltHeader(uint8_t *buf) const override;
29*0b57cec5SDimitry Andric   void writePlt(uint8_t *buf, uint64_t gotPltEntryAddr, uint64_t pltEntryAddr,
30*0b57cec5SDimitry Andric                 int32_t index, unsigned relOff) const override;
31*0b57cec5SDimitry Andric   RelType getDynRel(RelType type) const override;
32*0b57cec5SDimitry Andric   RelExpr getRelExpr(RelType type, const Symbol &s,
33*0b57cec5SDimitry Andric                      const uint8_t *loc) const override;
34*0b57cec5SDimitry Andric   void relocateOne(uint8_t *loc, RelType type, uint64_t val) const override;
35*0b57cec5SDimitry Andric };
36*0b57cec5SDimitry Andric 
37*0b57cec5SDimitry Andric } // end anonymous namespace
38*0b57cec5SDimitry Andric 
39*0b57cec5SDimitry Andric const uint64_t dtpOffset = 0x800;
40*0b57cec5SDimitry Andric 
41*0b57cec5SDimitry Andric enum Op {
42*0b57cec5SDimitry Andric   ADDI = 0x13,
43*0b57cec5SDimitry Andric   AUIPC = 0x17,
44*0b57cec5SDimitry Andric   JALR = 0x67,
45*0b57cec5SDimitry Andric   LD = 0x3003,
46*0b57cec5SDimitry Andric   LW = 0x2003,
47*0b57cec5SDimitry Andric   SRLI = 0x5013,
48*0b57cec5SDimitry Andric   SUB = 0x40000033,
49*0b57cec5SDimitry Andric };
50*0b57cec5SDimitry Andric 
51*0b57cec5SDimitry Andric enum Reg {
52*0b57cec5SDimitry Andric   X_RA = 1,
53*0b57cec5SDimitry Andric   X_T0 = 5,
54*0b57cec5SDimitry Andric   X_T1 = 6,
55*0b57cec5SDimitry Andric   X_T2 = 7,
56*0b57cec5SDimitry Andric   X_T3 = 28,
57*0b57cec5SDimitry Andric };
58*0b57cec5SDimitry Andric 
59*0b57cec5SDimitry Andric static uint32_t hi20(uint32_t val) { return (val + 0x800) >> 12; }
60*0b57cec5SDimitry Andric static uint32_t lo12(uint32_t val) { return val & 4095; }
61*0b57cec5SDimitry Andric 
62*0b57cec5SDimitry Andric static uint32_t itype(uint32_t op, uint32_t rd, uint32_t rs1, uint32_t imm) {
63*0b57cec5SDimitry Andric   return op | (rd << 7) | (rs1 << 15) | (imm << 20);
64*0b57cec5SDimitry Andric }
65*0b57cec5SDimitry Andric static uint32_t rtype(uint32_t op, uint32_t rd, uint32_t rs1, uint32_t rs2) {
66*0b57cec5SDimitry Andric   return op | (rd << 7) | (rs1 << 15) | (rs2 << 20);
67*0b57cec5SDimitry Andric }
68*0b57cec5SDimitry Andric static uint32_t utype(uint32_t op, uint32_t rd, uint32_t imm) {
69*0b57cec5SDimitry Andric   return op | (rd << 7) | (imm << 12);
70*0b57cec5SDimitry Andric }
71*0b57cec5SDimitry Andric 
72*0b57cec5SDimitry Andric RISCV::RISCV() {
73*0b57cec5SDimitry Andric   copyRel = R_RISCV_COPY;
74*0b57cec5SDimitry Andric   noneRel = R_RISCV_NONE;
75*0b57cec5SDimitry Andric   pltRel = R_RISCV_JUMP_SLOT;
76*0b57cec5SDimitry Andric   relativeRel = R_RISCV_RELATIVE;
77*0b57cec5SDimitry Andric   if (config->is64) {
78*0b57cec5SDimitry Andric     symbolicRel = R_RISCV_64;
79*0b57cec5SDimitry Andric     tlsModuleIndexRel = R_RISCV_TLS_DTPMOD64;
80*0b57cec5SDimitry Andric     tlsOffsetRel = R_RISCV_TLS_DTPREL64;
81*0b57cec5SDimitry Andric     tlsGotRel = R_RISCV_TLS_TPREL64;
82*0b57cec5SDimitry Andric   } else {
83*0b57cec5SDimitry Andric     symbolicRel = R_RISCV_32;
84*0b57cec5SDimitry Andric     tlsModuleIndexRel = R_RISCV_TLS_DTPMOD32;
85*0b57cec5SDimitry Andric     tlsOffsetRel = R_RISCV_TLS_DTPREL32;
86*0b57cec5SDimitry Andric     tlsGotRel = R_RISCV_TLS_TPREL32;
87*0b57cec5SDimitry Andric   }
88*0b57cec5SDimitry Andric   gotRel = symbolicRel;
89*0b57cec5SDimitry Andric 
90*0b57cec5SDimitry Andric   // .got[0] = _DYNAMIC
91*0b57cec5SDimitry Andric   gotBaseSymInGotPlt = false;
92*0b57cec5SDimitry Andric   gotHeaderEntriesNum = 1;
93*0b57cec5SDimitry Andric 
94*0b57cec5SDimitry Andric   // .got.plt[0] = _dl_runtime_resolve, .got.plt[1] = link_map
95*0b57cec5SDimitry Andric   gotPltHeaderEntriesNum = 2;
96*0b57cec5SDimitry Andric 
97*0b57cec5SDimitry Andric   pltEntrySize = 16;
98*0b57cec5SDimitry Andric   pltHeaderSize = 32;
99*0b57cec5SDimitry Andric }
100*0b57cec5SDimitry Andric 
101*0b57cec5SDimitry Andric static uint32_t getEFlags(InputFile *f) {
102*0b57cec5SDimitry Andric   if (config->is64)
103*0b57cec5SDimitry Andric     return cast<ObjFile<ELF64LE>>(f)->getObj().getHeader()->e_flags;
104*0b57cec5SDimitry Andric   return cast<ObjFile<ELF32LE>>(f)->getObj().getHeader()->e_flags;
105*0b57cec5SDimitry Andric }
106*0b57cec5SDimitry Andric 
107*0b57cec5SDimitry Andric uint32_t RISCV::calcEFlags() const {
108*0b57cec5SDimitry Andric   assert(!objectFiles.empty());
109*0b57cec5SDimitry Andric 
110*0b57cec5SDimitry Andric   uint32_t target = getEFlags(objectFiles.front());
111*0b57cec5SDimitry Andric 
112*0b57cec5SDimitry Andric   for (InputFile *f : objectFiles) {
113*0b57cec5SDimitry Andric     uint32_t eflags = getEFlags(f);
114*0b57cec5SDimitry Andric     if (eflags & EF_RISCV_RVC)
115*0b57cec5SDimitry Andric       target |= EF_RISCV_RVC;
116*0b57cec5SDimitry Andric 
117*0b57cec5SDimitry Andric     if ((eflags & EF_RISCV_FLOAT_ABI) != (target & EF_RISCV_FLOAT_ABI))
118*0b57cec5SDimitry Andric       error(toString(f) +
119*0b57cec5SDimitry Andric             ": cannot link object files with different floating-point ABI");
120*0b57cec5SDimitry Andric 
121*0b57cec5SDimitry Andric     if ((eflags & EF_RISCV_RVE) != (target & EF_RISCV_RVE))
122*0b57cec5SDimitry Andric       error(toString(f) +
123*0b57cec5SDimitry Andric             ": cannot link object files with different EF_RISCV_RVE");
124*0b57cec5SDimitry Andric   }
125*0b57cec5SDimitry Andric 
126*0b57cec5SDimitry Andric   return target;
127*0b57cec5SDimitry Andric }
128*0b57cec5SDimitry Andric 
129*0b57cec5SDimitry Andric void RISCV::writeGotHeader(uint8_t *buf) const {
130*0b57cec5SDimitry Andric   if (config->is64)
131*0b57cec5SDimitry Andric     write64le(buf, mainPart->dynamic->getVA());
132*0b57cec5SDimitry Andric   else
133*0b57cec5SDimitry Andric     write32le(buf, mainPart->dynamic->getVA());
134*0b57cec5SDimitry Andric }
135*0b57cec5SDimitry Andric 
136*0b57cec5SDimitry Andric void RISCV::writeGotPlt(uint8_t *buf, const Symbol &s) const {
137*0b57cec5SDimitry Andric   if (config->is64)
138*0b57cec5SDimitry Andric     write64le(buf, in.plt->getVA());
139*0b57cec5SDimitry Andric   else
140*0b57cec5SDimitry Andric     write32le(buf, in.plt->getVA());
141*0b57cec5SDimitry Andric }
142*0b57cec5SDimitry Andric 
143*0b57cec5SDimitry Andric void RISCV::writePltHeader(uint8_t *buf) const {
144*0b57cec5SDimitry Andric   // 1: auipc t2, %pcrel_hi(.got.plt)
145*0b57cec5SDimitry Andric   // sub t1, t1, t3
146*0b57cec5SDimitry Andric   // l[wd] t3, %pcrel_lo(1b)(t2); t3 = _dl_runtime_resolve
147*0b57cec5SDimitry Andric   // addi t1, t1, -pltHeaderSize-12; t1 = &.plt[i] - &.plt[0]
148*0b57cec5SDimitry Andric   // addi t0, t2, %pcrel_lo(1b)
149*0b57cec5SDimitry Andric   // srli t1, t1, (rv64?1:2); t1 = &.got.plt[i] - &.got.plt[0]
150*0b57cec5SDimitry Andric   // l[wd] t0, Wordsize(t0); t0 = link_map
151*0b57cec5SDimitry Andric   // jr t3
152*0b57cec5SDimitry Andric   uint32_t offset = in.gotPlt->getVA() - in.plt->getVA();
153*0b57cec5SDimitry Andric   uint32_t load = config->is64 ? LD : LW;
154*0b57cec5SDimitry Andric   write32le(buf + 0, utype(AUIPC, X_T2, hi20(offset)));
155*0b57cec5SDimitry Andric   write32le(buf + 4, rtype(SUB, X_T1, X_T1, X_T3));
156*0b57cec5SDimitry Andric   write32le(buf + 8, itype(load, X_T3, X_T2, lo12(offset)));
157*0b57cec5SDimitry Andric   write32le(buf + 12, itype(ADDI, X_T1, X_T1, -target->pltHeaderSize - 12));
158*0b57cec5SDimitry Andric   write32le(buf + 16, itype(ADDI, X_T0, X_T2, lo12(offset)));
159*0b57cec5SDimitry Andric   write32le(buf + 20, itype(SRLI, X_T1, X_T1, config->is64 ? 1 : 2));
160*0b57cec5SDimitry Andric   write32le(buf + 24, itype(load, X_T0, X_T0, config->wordsize));
161*0b57cec5SDimitry Andric   write32le(buf + 28, itype(JALR, 0, X_T3, 0));
162*0b57cec5SDimitry Andric }
163*0b57cec5SDimitry Andric 
164*0b57cec5SDimitry Andric void RISCV::writePlt(uint8_t *buf, uint64_t gotPltEntryAddr,
165*0b57cec5SDimitry Andric                      uint64_t pltEntryAddr, int32_t index,
166*0b57cec5SDimitry Andric                      unsigned relOff) const {
167*0b57cec5SDimitry Andric   // 1: auipc t3, %pcrel_hi(f@.got.plt)
168*0b57cec5SDimitry Andric   // l[wd] t3, %pcrel_lo(1b)(t3)
169*0b57cec5SDimitry Andric   // jalr t1, t3
170*0b57cec5SDimitry Andric   // nop
171*0b57cec5SDimitry Andric   uint32_t offset = gotPltEntryAddr - pltEntryAddr;
172*0b57cec5SDimitry Andric   write32le(buf + 0, utype(AUIPC, X_T3, hi20(offset)));
173*0b57cec5SDimitry Andric   write32le(buf + 4, itype(config->is64 ? LD : LW, X_T3, X_T3, lo12(offset)));
174*0b57cec5SDimitry Andric   write32le(buf + 8, itype(JALR, X_T1, X_T3, 0));
175*0b57cec5SDimitry Andric   write32le(buf + 12, itype(ADDI, 0, 0, 0));
176*0b57cec5SDimitry Andric }
177*0b57cec5SDimitry Andric 
178*0b57cec5SDimitry Andric RelType RISCV::getDynRel(RelType type) const {
179*0b57cec5SDimitry Andric   return type == target->symbolicRel ? type
180*0b57cec5SDimitry Andric                                      : static_cast<RelType>(R_RISCV_NONE);
181*0b57cec5SDimitry Andric }
182*0b57cec5SDimitry Andric 
183*0b57cec5SDimitry Andric RelExpr RISCV::getRelExpr(const RelType type, const Symbol &s,
184*0b57cec5SDimitry Andric                           const uint8_t *loc) const {
185*0b57cec5SDimitry Andric   switch (type) {
186*0b57cec5SDimitry Andric   case R_RISCV_ADD8:
187*0b57cec5SDimitry Andric   case R_RISCV_ADD16:
188*0b57cec5SDimitry Andric   case R_RISCV_ADD32:
189*0b57cec5SDimitry Andric   case R_RISCV_ADD64:
190*0b57cec5SDimitry Andric   case R_RISCV_SET6:
191*0b57cec5SDimitry Andric   case R_RISCV_SET8:
192*0b57cec5SDimitry Andric   case R_RISCV_SET16:
193*0b57cec5SDimitry Andric   case R_RISCV_SET32:
194*0b57cec5SDimitry Andric   case R_RISCV_SUB6:
195*0b57cec5SDimitry Andric   case R_RISCV_SUB8:
196*0b57cec5SDimitry Andric   case R_RISCV_SUB16:
197*0b57cec5SDimitry Andric   case R_RISCV_SUB32:
198*0b57cec5SDimitry Andric   case R_RISCV_SUB64:
199*0b57cec5SDimitry Andric     return R_RISCV_ADD;
200*0b57cec5SDimitry Andric   case R_RISCV_JAL:
201*0b57cec5SDimitry Andric   case R_RISCV_BRANCH:
202*0b57cec5SDimitry Andric   case R_RISCV_PCREL_HI20:
203*0b57cec5SDimitry Andric   case R_RISCV_RVC_BRANCH:
204*0b57cec5SDimitry Andric   case R_RISCV_RVC_JUMP:
205*0b57cec5SDimitry Andric   case R_RISCV_32_PCREL:
206*0b57cec5SDimitry Andric     return R_PC;
207*0b57cec5SDimitry Andric   case R_RISCV_CALL:
208*0b57cec5SDimitry Andric   case R_RISCV_CALL_PLT:
209*0b57cec5SDimitry Andric     return R_PLT_PC;
210*0b57cec5SDimitry Andric   case R_RISCV_GOT_HI20:
211*0b57cec5SDimitry Andric     return R_GOT_PC;
212*0b57cec5SDimitry Andric   case R_RISCV_PCREL_LO12_I:
213*0b57cec5SDimitry Andric   case R_RISCV_PCREL_LO12_S:
214*0b57cec5SDimitry Andric     return R_RISCV_PC_INDIRECT;
215*0b57cec5SDimitry Andric   case R_RISCV_TLS_GD_HI20:
216*0b57cec5SDimitry Andric     return R_TLSGD_PC;
217*0b57cec5SDimitry Andric   case R_RISCV_TLS_GOT_HI20:
218*0b57cec5SDimitry Andric     config->hasStaticTlsModel = true;
219*0b57cec5SDimitry Andric     return R_GOT_PC;
220*0b57cec5SDimitry Andric   case R_RISCV_TPREL_HI20:
221*0b57cec5SDimitry Andric   case R_RISCV_TPREL_LO12_I:
222*0b57cec5SDimitry Andric   case R_RISCV_TPREL_LO12_S:
223*0b57cec5SDimitry Andric     return R_TLS;
224*0b57cec5SDimitry Andric   case R_RISCV_RELAX:
225*0b57cec5SDimitry Andric   case R_RISCV_ALIGN:
226*0b57cec5SDimitry Andric   case R_RISCV_TPREL_ADD:
227*0b57cec5SDimitry Andric     return R_HINT;
228*0b57cec5SDimitry Andric   default:
229*0b57cec5SDimitry Andric     return R_ABS;
230*0b57cec5SDimitry Andric   }
231*0b57cec5SDimitry Andric }
232*0b57cec5SDimitry Andric 
233*0b57cec5SDimitry Andric // Extract bits V[Begin:End], where range is inclusive, and Begin must be < 63.
234*0b57cec5SDimitry Andric static uint32_t extractBits(uint64_t v, uint32_t begin, uint32_t end) {
235*0b57cec5SDimitry Andric   return (v & ((1ULL << (begin + 1)) - 1)) >> end;
236*0b57cec5SDimitry Andric }
237*0b57cec5SDimitry Andric 
238*0b57cec5SDimitry Andric void RISCV::relocateOne(uint8_t *loc, const RelType type,
239*0b57cec5SDimitry Andric                         const uint64_t val) const {
240*0b57cec5SDimitry Andric   const unsigned bits = config->wordsize * 8;
241*0b57cec5SDimitry Andric 
242*0b57cec5SDimitry Andric   switch (type) {
243*0b57cec5SDimitry Andric   case R_RISCV_32:
244*0b57cec5SDimitry Andric     write32le(loc, val);
245*0b57cec5SDimitry Andric     return;
246*0b57cec5SDimitry Andric   case R_RISCV_64:
247*0b57cec5SDimitry Andric     write64le(loc, val);
248*0b57cec5SDimitry Andric     return;
249*0b57cec5SDimitry Andric 
250*0b57cec5SDimitry Andric   case R_RISCV_RVC_BRANCH: {
251*0b57cec5SDimitry Andric     checkInt(loc, static_cast<int64_t>(val) >> 1, 8, type);
252*0b57cec5SDimitry Andric     checkAlignment(loc, val, 2, type);
253*0b57cec5SDimitry Andric     uint16_t insn = read16le(loc) & 0xE383;
254*0b57cec5SDimitry Andric     uint16_t imm8 = extractBits(val, 8, 8) << 12;
255*0b57cec5SDimitry Andric     uint16_t imm4_3 = extractBits(val, 4, 3) << 10;
256*0b57cec5SDimitry Andric     uint16_t imm7_6 = extractBits(val, 7, 6) << 5;
257*0b57cec5SDimitry Andric     uint16_t imm2_1 = extractBits(val, 2, 1) << 3;
258*0b57cec5SDimitry Andric     uint16_t imm5 = extractBits(val, 5, 5) << 2;
259*0b57cec5SDimitry Andric     insn |= imm8 | imm4_3 | imm7_6 | imm2_1 | imm5;
260*0b57cec5SDimitry Andric 
261*0b57cec5SDimitry Andric     write16le(loc, insn);
262*0b57cec5SDimitry Andric     return;
263*0b57cec5SDimitry Andric   }
264*0b57cec5SDimitry Andric 
265*0b57cec5SDimitry Andric   case R_RISCV_RVC_JUMP: {
266*0b57cec5SDimitry Andric     checkInt(loc, static_cast<int64_t>(val) >> 1, 11, type);
267*0b57cec5SDimitry Andric     checkAlignment(loc, val, 2, type);
268*0b57cec5SDimitry Andric     uint16_t insn = read16le(loc) & 0xE003;
269*0b57cec5SDimitry Andric     uint16_t imm11 = extractBits(val, 11, 11) << 12;
270*0b57cec5SDimitry Andric     uint16_t imm4 = extractBits(val, 4, 4) << 11;
271*0b57cec5SDimitry Andric     uint16_t imm9_8 = extractBits(val, 9, 8) << 9;
272*0b57cec5SDimitry Andric     uint16_t imm10 = extractBits(val, 10, 10) << 8;
273*0b57cec5SDimitry Andric     uint16_t imm6 = extractBits(val, 6, 6) << 7;
274*0b57cec5SDimitry Andric     uint16_t imm7 = extractBits(val, 7, 7) << 6;
275*0b57cec5SDimitry Andric     uint16_t imm3_1 = extractBits(val, 3, 1) << 3;
276*0b57cec5SDimitry Andric     uint16_t imm5 = extractBits(val, 5, 5) << 2;
277*0b57cec5SDimitry Andric     insn |= imm11 | imm4 | imm9_8 | imm10 | imm6 | imm7 | imm3_1 | imm5;
278*0b57cec5SDimitry Andric 
279*0b57cec5SDimitry Andric     write16le(loc, insn);
280*0b57cec5SDimitry Andric     return;
281*0b57cec5SDimitry Andric   }
282*0b57cec5SDimitry Andric 
283*0b57cec5SDimitry Andric   case R_RISCV_RVC_LUI: {
284*0b57cec5SDimitry Andric     int64_t imm = SignExtend64(val + 0x800, bits) >> 12;
285*0b57cec5SDimitry Andric     checkInt(loc, imm, 6, type);
286*0b57cec5SDimitry Andric     if (imm == 0) { // `c.lui rd, 0` is illegal, convert to `c.li rd, 0`
287*0b57cec5SDimitry Andric       write16le(loc, (read16le(loc) & 0x0F83) | 0x4000);
288*0b57cec5SDimitry Andric     } else {
289*0b57cec5SDimitry Andric       uint16_t imm17 = extractBits(val + 0x800, 17, 17) << 12;
290*0b57cec5SDimitry Andric       uint16_t imm16_12 = extractBits(val + 0x800, 16, 12) << 2;
291*0b57cec5SDimitry Andric       write16le(loc, (read16le(loc) & 0xEF83) | imm17 | imm16_12);
292*0b57cec5SDimitry Andric     }
293*0b57cec5SDimitry Andric     return;
294*0b57cec5SDimitry Andric   }
295*0b57cec5SDimitry Andric 
296*0b57cec5SDimitry Andric   case R_RISCV_JAL: {
297*0b57cec5SDimitry Andric     checkInt(loc, static_cast<int64_t>(val) >> 1, 20, type);
298*0b57cec5SDimitry Andric     checkAlignment(loc, val, 2, type);
299*0b57cec5SDimitry Andric 
300*0b57cec5SDimitry Andric     uint32_t insn = read32le(loc) & 0xFFF;
301*0b57cec5SDimitry Andric     uint32_t imm20 = extractBits(val, 20, 20) << 31;
302*0b57cec5SDimitry Andric     uint32_t imm10_1 = extractBits(val, 10, 1) << 21;
303*0b57cec5SDimitry Andric     uint32_t imm11 = extractBits(val, 11, 11) << 20;
304*0b57cec5SDimitry Andric     uint32_t imm19_12 = extractBits(val, 19, 12) << 12;
305*0b57cec5SDimitry Andric     insn |= imm20 | imm10_1 | imm11 | imm19_12;
306*0b57cec5SDimitry Andric 
307*0b57cec5SDimitry Andric     write32le(loc, insn);
308*0b57cec5SDimitry Andric     return;
309*0b57cec5SDimitry Andric   }
310*0b57cec5SDimitry Andric 
311*0b57cec5SDimitry Andric   case R_RISCV_BRANCH: {
312*0b57cec5SDimitry Andric     checkInt(loc, static_cast<int64_t>(val) >> 1, 12, type);
313*0b57cec5SDimitry Andric     checkAlignment(loc, val, 2, type);
314*0b57cec5SDimitry Andric 
315*0b57cec5SDimitry Andric     uint32_t insn = read32le(loc) & 0x1FFF07F;
316*0b57cec5SDimitry Andric     uint32_t imm12 = extractBits(val, 12, 12) << 31;
317*0b57cec5SDimitry Andric     uint32_t imm10_5 = extractBits(val, 10, 5) << 25;
318*0b57cec5SDimitry Andric     uint32_t imm4_1 = extractBits(val, 4, 1) << 8;
319*0b57cec5SDimitry Andric     uint32_t imm11 = extractBits(val, 11, 11) << 7;
320*0b57cec5SDimitry Andric     insn |= imm12 | imm10_5 | imm4_1 | imm11;
321*0b57cec5SDimitry Andric 
322*0b57cec5SDimitry Andric     write32le(loc, insn);
323*0b57cec5SDimitry Andric     return;
324*0b57cec5SDimitry Andric   }
325*0b57cec5SDimitry Andric 
326*0b57cec5SDimitry Andric   // auipc + jalr pair
327*0b57cec5SDimitry Andric   case R_RISCV_CALL:
328*0b57cec5SDimitry Andric   case R_RISCV_CALL_PLT: {
329*0b57cec5SDimitry Andric     int64_t hi = SignExtend64(val + 0x800, bits) >> 12;
330*0b57cec5SDimitry Andric     checkInt(loc, hi, 20, type);
331*0b57cec5SDimitry Andric     if (isInt<20>(hi)) {
332*0b57cec5SDimitry Andric       relocateOne(loc, R_RISCV_PCREL_HI20, val);
333*0b57cec5SDimitry Andric       relocateOne(loc + 4, R_RISCV_PCREL_LO12_I, val);
334*0b57cec5SDimitry Andric     }
335*0b57cec5SDimitry Andric     return;
336*0b57cec5SDimitry Andric   }
337*0b57cec5SDimitry Andric 
338*0b57cec5SDimitry Andric   case R_RISCV_GOT_HI20:
339*0b57cec5SDimitry Andric   case R_RISCV_PCREL_HI20:
340*0b57cec5SDimitry Andric   case R_RISCV_TLS_GD_HI20:
341*0b57cec5SDimitry Andric   case R_RISCV_TLS_GOT_HI20:
342*0b57cec5SDimitry Andric   case R_RISCV_TPREL_HI20:
343*0b57cec5SDimitry Andric   case R_RISCV_HI20: {
344*0b57cec5SDimitry Andric     uint64_t hi = val + 0x800;
345*0b57cec5SDimitry Andric     checkInt(loc, SignExtend64(hi, bits) >> 12, 20, type);
346*0b57cec5SDimitry Andric     write32le(loc, (read32le(loc) & 0xFFF) | (hi & 0xFFFFF000));
347*0b57cec5SDimitry Andric     return;
348*0b57cec5SDimitry Andric   }
349*0b57cec5SDimitry Andric 
350*0b57cec5SDimitry Andric   case R_RISCV_PCREL_LO12_I:
351*0b57cec5SDimitry Andric   case R_RISCV_TPREL_LO12_I:
352*0b57cec5SDimitry Andric   case R_RISCV_LO12_I: {
353*0b57cec5SDimitry Andric     uint64_t hi = (val + 0x800) >> 12;
354*0b57cec5SDimitry Andric     uint64_t lo = val - (hi << 12);
355*0b57cec5SDimitry Andric     write32le(loc, (read32le(loc) & 0xFFFFF) | ((lo & 0xFFF) << 20));
356*0b57cec5SDimitry Andric     return;
357*0b57cec5SDimitry Andric   }
358*0b57cec5SDimitry Andric 
359*0b57cec5SDimitry Andric   case R_RISCV_PCREL_LO12_S:
360*0b57cec5SDimitry Andric   case R_RISCV_TPREL_LO12_S:
361*0b57cec5SDimitry Andric   case R_RISCV_LO12_S: {
362*0b57cec5SDimitry Andric     uint64_t hi = (val + 0x800) >> 12;
363*0b57cec5SDimitry Andric     uint64_t lo = val - (hi << 12);
364*0b57cec5SDimitry Andric     uint32_t imm11_5 = extractBits(lo, 11, 5) << 25;
365*0b57cec5SDimitry Andric     uint32_t imm4_0 = extractBits(lo, 4, 0) << 7;
366*0b57cec5SDimitry Andric     write32le(loc, (read32le(loc) & 0x1FFF07F) | imm11_5 | imm4_0);
367*0b57cec5SDimitry Andric     return;
368*0b57cec5SDimitry Andric   }
369*0b57cec5SDimitry Andric 
370*0b57cec5SDimitry Andric   case R_RISCV_ADD8:
371*0b57cec5SDimitry Andric     *loc += val;
372*0b57cec5SDimitry Andric     return;
373*0b57cec5SDimitry Andric   case R_RISCV_ADD16:
374*0b57cec5SDimitry Andric     write16le(loc, read16le(loc) + val);
375*0b57cec5SDimitry Andric     return;
376*0b57cec5SDimitry Andric   case R_RISCV_ADD32:
377*0b57cec5SDimitry Andric     write32le(loc, read32le(loc) + val);
378*0b57cec5SDimitry Andric     return;
379*0b57cec5SDimitry Andric   case R_RISCV_ADD64:
380*0b57cec5SDimitry Andric     write64le(loc, read64le(loc) + val);
381*0b57cec5SDimitry Andric     return;
382*0b57cec5SDimitry Andric   case R_RISCV_SUB6:
383*0b57cec5SDimitry Andric     *loc = (*loc & 0xc0) | (((*loc & 0x3f) - val) & 0x3f);
384*0b57cec5SDimitry Andric     return;
385*0b57cec5SDimitry Andric   case R_RISCV_SUB8:
386*0b57cec5SDimitry Andric     *loc -= val;
387*0b57cec5SDimitry Andric     return;
388*0b57cec5SDimitry Andric   case R_RISCV_SUB16:
389*0b57cec5SDimitry Andric     write16le(loc, read16le(loc) - val);
390*0b57cec5SDimitry Andric     return;
391*0b57cec5SDimitry Andric   case R_RISCV_SUB32:
392*0b57cec5SDimitry Andric     write32le(loc, read32le(loc) - val);
393*0b57cec5SDimitry Andric     return;
394*0b57cec5SDimitry Andric   case R_RISCV_SUB64:
395*0b57cec5SDimitry Andric     write64le(loc, read64le(loc) - val);
396*0b57cec5SDimitry Andric     return;
397*0b57cec5SDimitry Andric   case R_RISCV_SET6:
398*0b57cec5SDimitry Andric     *loc = (*loc & 0xc0) | (val & 0x3f);
399*0b57cec5SDimitry Andric     return;
400*0b57cec5SDimitry Andric   case R_RISCV_SET8:
401*0b57cec5SDimitry Andric     *loc = val;
402*0b57cec5SDimitry Andric     return;
403*0b57cec5SDimitry Andric   case R_RISCV_SET16:
404*0b57cec5SDimitry Andric     write16le(loc, val);
405*0b57cec5SDimitry Andric     return;
406*0b57cec5SDimitry Andric   case R_RISCV_SET32:
407*0b57cec5SDimitry Andric   case R_RISCV_32_PCREL:
408*0b57cec5SDimitry Andric     write32le(loc, val);
409*0b57cec5SDimitry Andric     return;
410*0b57cec5SDimitry Andric 
411*0b57cec5SDimitry Andric   case R_RISCV_TLS_DTPREL32:
412*0b57cec5SDimitry Andric     write32le(loc, val - dtpOffset);
413*0b57cec5SDimitry Andric     break;
414*0b57cec5SDimitry Andric   case R_RISCV_TLS_DTPREL64:
415*0b57cec5SDimitry Andric     write64le(loc, val - dtpOffset);
416*0b57cec5SDimitry Andric     break;
417*0b57cec5SDimitry Andric 
418*0b57cec5SDimitry Andric   case R_RISCV_ALIGN:
419*0b57cec5SDimitry Andric   case R_RISCV_RELAX:
420*0b57cec5SDimitry Andric     return; // Ignored (for now)
421*0b57cec5SDimitry Andric   case R_RISCV_NONE:
422*0b57cec5SDimitry Andric     return; // Do nothing
423*0b57cec5SDimitry Andric 
424*0b57cec5SDimitry Andric   // These are handled by the dynamic linker
425*0b57cec5SDimitry Andric   case R_RISCV_RELATIVE:
426*0b57cec5SDimitry Andric   case R_RISCV_COPY:
427*0b57cec5SDimitry Andric   case R_RISCV_JUMP_SLOT:
428*0b57cec5SDimitry Andric   // GP-relative relocations are only produced after relaxation, which
429*0b57cec5SDimitry Andric   // we don't support for now
430*0b57cec5SDimitry Andric   case R_RISCV_GPREL_I:
431*0b57cec5SDimitry Andric   case R_RISCV_GPREL_S:
432*0b57cec5SDimitry Andric   default:
433*0b57cec5SDimitry Andric     error(getErrorLocation(loc) +
434*0b57cec5SDimitry Andric           "unimplemented relocation: " + toString(type));
435*0b57cec5SDimitry Andric     return;
436*0b57cec5SDimitry Andric   }
437*0b57cec5SDimitry Andric }
438*0b57cec5SDimitry Andric 
439*0b57cec5SDimitry Andric TargetInfo *elf::getRISCVTargetInfo() {
440*0b57cec5SDimitry Andric   static RISCV target;
441*0b57cec5SDimitry Andric   return &target;
442*0b57cec5SDimitry Andric }
443