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 ⌖ 442*0b57cec5SDimitry Andric } 443