10b57cec5SDimitry Andric //===- RISCV.cpp ----------------------------------------------------------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric 90b57cec5SDimitry Andric #include "InputFiles.h" 10753f127fSDimitry Andric #include "OutputSections.h" 11480093f4SDimitry Andric #include "Symbols.h" 120b57cec5SDimitry Andric #include "SyntheticSections.h" 130b57cec5SDimitry Andric #include "Target.h" 14bdd1243dSDimitry Andric #include "llvm/Support/ELFAttributes.h" 15bdd1243dSDimitry Andric #include "llvm/Support/LEB128.h" 16bdd1243dSDimitry Andric #include "llvm/Support/RISCVAttributeParser.h" 17bdd1243dSDimitry Andric #include "llvm/Support/RISCVAttributes.h" 18bdd1243dSDimitry Andric #include "llvm/Support/RISCVISAInfo.h" 19753f127fSDimitry Andric #include "llvm/Support/TimeProfiler.h" 200b57cec5SDimitry Andric 210b57cec5SDimitry Andric using namespace llvm; 220b57cec5SDimitry Andric using namespace llvm::object; 230b57cec5SDimitry Andric using namespace llvm::support::endian; 240b57cec5SDimitry Andric using namespace llvm::ELF; 255ffd83dbSDimitry Andric using namespace lld; 265ffd83dbSDimitry Andric using namespace lld::elf; 270b57cec5SDimitry Andric 280b57cec5SDimitry Andric namespace { 290b57cec5SDimitry Andric 300b57cec5SDimitry Andric class RISCV final : public TargetInfo { 310b57cec5SDimitry Andric public: 320b57cec5SDimitry Andric RISCV(); 330b57cec5SDimitry Andric uint32_t calcEFlags() const override; 34fe6060f1SDimitry Andric int64_t getImplicitAddend(const uint8_t *buf, RelType type) const override; 350b57cec5SDimitry Andric void writeGotHeader(uint8_t *buf) const override; 360b57cec5SDimitry Andric void writeGotPlt(uint8_t *buf, const Symbol &s) const override; 37fe6060f1SDimitry Andric void writeIgotPlt(uint8_t *buf, const Symbol &s) const override; 380b57cec5SDimitry Andric void writePltHeader(uint8_t *buf) const override; 39480093f4SDimitry Andric void writePlt(uint8_t *buf, const Symbol &sym, 40480093f4SDimitry Andric uint64_t pltEntryAddr) const override; 410b57cec5SDimitry Andric RelType getDynRel(RelType type) const override; 420b57cec5SDimitry Andric RelExpr getRelExpr(RelType type, const Symbol &s, 430b57cec5SDimitry Andric const uint8_t *loc) const override; 445ffd83dbSDimitry Andric void relocate(uint8_t *loc, const Relocation &rel, 455ffd83dbSDimitry Andric uint64_t val) const override; 461db9f3b2SDimitry Andric void relocateAlloc(InputSectionBase &sec, uint8_t *buf) const override; 47753f127fSDimitry Andric bool relaxOnce(int pass) const override; 4874626c16SDimitry Andric void finalizeRelax(int passes) const override; 490b57cec5SDimitry Andric }; 500b57cec5SDimitry Andric 510b57cec5SDimitry Andric } // end anonymous namespace 520b57cec5SDimitry Andric 5306c3fb27SDimitry Andric // These are internal relocation numbers for GP relaxation. They aren't part 5406c3fb27SDimitry Andric // of the psABI spec. 5506c3fb27SDimitry Andric #define INTERNAL_R_RISCV_GPREL_I 256 5606c3fb27SDimitry Andric #define INTERNAL_R_RISCV_GPREL_S 257 5706c3fb27SDimitry Andric 580b57cec5SDimitry Andric const uint64_t dtpOffset = 0x800; 590b57cec5SDimitry Andric 60*439352acSDimitry Andric namespace { 610b57cec5SDimitry Andric enum Op { 620b57cec5SDimitry Andric ADDI = 0x13, 630b57cec5SDimitry Andric AUIPC = 0x17, 640b57cec5SDimitry Andric JALR = 0x67, 650b57cec5SDimitry Andric LD = 0x3003, 66b3edf446SDimitry Andric LUI = 0x37, 670b57cec5SDimitry Andric LW = 0x2003, 680b57cec5SDimitry Andric SRLI = 0x5013, 690b57cec5SDimitry Andric SUB = 0x40000033, 700b57cec5SDimitry Andric }; 710b57cec5SDimitry Andric 720b57cec5SDimitry Andric enum Reg { 730b57cec5SDimitry Andric X_RA = 1, 7406c3fb27SDimitry Andric X_GP = 3, 75fcaf7f86SDimitry Andric X_TP = 4, 760b57cec5SDimitry Andric X_T0 = 5, 770b57cec5SDimitry Andric X_T1 = 6, 780b57cec5SDimitry Andric X_T2 = 7, 79b3edf446SDimitry Andric X_A0 = 10, 800b57cec5SDimitry Andric X_T3 = 28, 810b57cec5SDimitry Andric }; 82*439352acSDimitry Andric } // namespace 830b57cec5SDimitry Andric 840b57cec5SDimitry Andric static uint32_t hi20(uint32_t val) { return (val + 0x800) >> 12; } 850b57cec5SDimitry Andric static uint32_t lo12(uint32_t val) { return val & 4095; } 860b57cec5SDimitry Andric 870b57cec5SDimitry Andric static uint32_t itype(uint32_t op, uint32_t rd, uint32_t rs1, uint32_t imm) { 880b57cec5SDimitry Andric return op | (rd << 7) | (rs1 << 15) | (imm << 20); 890b57cec5SDimitry Andric } 900b57cec5SDimitry Andric static uint32_t rtype(uint32_t op, uint32_t rd, uint32_t rs1, uint32_t rs2) { 910b57cec5SDimitry Andric return op | (rd << 7) | (rs1 << 15) | (rs2 << 20); 920b57cec5SDimitry Andric } 930b57cec5SDimitry Andric static uint32_t utype(uint32_t op, uint32_t rd, uint32_t imm) { 940b57cec5SDimitry Andric return op | (rd << 7) | (imm << 12); 950b57cec5SDimitry Andric } 960b57cec5SDimitry Andric 97fcaf7f86SDimitry Andric // Extract bits v[begin:end], where range is inclusive, and begin must be < 63. 98fcaf7f86SDimitry Andric static uint32_t extractBits(uint64_t v, uint32_t begin, uint32_t end) { 99fcaf7f86SDimitry Andric return (v & ((1ULL << (begin + 1)) - 1)) >> end; 100fcaf7f86SDimitry Andric } 101fcaf7f86SDimitry Andric 102fcaf7f86SDimitry Andric static uint32_t setLO12_I(uint32_t insn, uint32_t imm) { 103fcaf7f86SDimitry Andric return (insn & 0xfffff) | (imm << 20); 104fcaf7f86SDimitry Andric } 105fcaf7f86SDimitry Andric static uint32_t setLO12_S(uint32_t insn, uint32_t imm) { 106fcaf7f86SDimitry Andric return (insn & 0x1fff07f) | (extractBits(imm, 11, 5) << 25) | 107fcaf7f86SDimitry Andric (extractBits(imm, 4, 0) << 7); 108fcaf7f86SDimitry Andric } 109fcaf7f86SDimitry Andric 1100b57cec5SDimitry Andric RISCV::RISCV() { 1110b57cec5SDimitry Andric copyRel = R_RISCV_COPY; 1120b57cec5SDimitry Andric pltRel = R_RISCV_JUMP_SLOT; 1130b57cec5SDimitry Andric relativeRel = R_RISCV_RELATIVE; 1145ffd83dbSDimitry Andric iRelativeRel = R_RISCV_IRELATIVE; 1150b57cec5SDimitry Andric if (config->is64) { 1160b57cec5SDimitry Andric symbolicRel = R_RISCV_64; 1170b57cec5SDimitry Andric tlsModuleIndexRel = R_RISCV_TLS_DTPMOD64; 1180b57cec5SDimitry Andric tlsOffsetRel = R_RISCV_TLS_DTPREL64; 1190b57cec5SDimitry Andric tlsGotRel = R_RISCV_TLS_TPREL64; 1200b57cec5SDimitry Andric } else { 1210b57cec5SDimitry Andric symbolicRel = R_RISCV_32; 1220b57cec5SDimitry Andric tlsModuleIndexRel = R_RISCV_TLS_DTPMOD32; 1230b57cec5SDimitry Andric tlsOffsetRel = R_RISCV_TLS_DTPREL32; 1240b57cec5SDimitry Andric tlsGotRel = R_RISCV_TLS_TPREL32; 1250b57cec5SDimitry Andric } 1260b57cec5SDimitry Andric gotRel = symbolicRel; 127b3edf446SDimitry Andric tlsDescRel = R_RISCV_TLSDESC; 1280b57cec5SDimitry Andric 1290b57cec5SDimitry Andric // .got[0] = _DYNAMIC 1300b57cec5SDimitry Andric gotHeaderEntriesNum = 1; 1310b57cec5SDimitry Andric 1320b57cec5SDimitry Andric // .got.plt[0] = _dl_runtime_resolve, .got.plt[1] = link_map 1330b57cec5SDimitry Andric gotPltHeaderEntriesNum = 2; 1340b57cec5SDimitry Andric 1350b57cec5SDimitry Andric pltHeaderSize = 32; 136480093f4SDimitry Andric pltEntrySize = 16; 137480093f4SDimitry Andric ipltEntrySize = 16; 1380b57cec5SDimitry Andric } 1390b57cec5SDimitry Andric 1400b57cec5SDimitry Andric static uint32_t getEFlags(InputFile *f) { 1410b57cec5SDimitry Andric if (config->is64) 142e8d8bef9SDimitry Andric return cast<ObjFile<ELF64LE>>(f)->getObj().getHeader().e_flags; 143e8d8bef9SDimitry Andric return cast<ObjFile<ELF32LE>>(f)->getObj().getHeader().e_flags; 1440b57cec5SDimitry Andric } 1450b57cec5SDimitry Andric 1460b57cec5SDimitry Andric uint32_t RISCV::calcEFlags() const { 147a1517e11SDimitry Andric // If there are only binary input files (from -b binary), use a 148a1517e11SDimitry Andric // value of 0 for the ELF header flags. 149bdd1243dSDimitry Andric if (ctx.objectFiles.empty()) 150a1517e11SDimitry Andric return 0; 1510b57cec5SDimitry Andric 152bdd1243dSDimitry Andric uint32_t target = getEFlags(ctx.objectFiles.front()); 1530b57cec5SDimitry Andric 154bdd1243dSDimitry Andric for (InputFile *f : ctx.objectFiles) { 1550b57cec5SDimitry Andric uint32_t eflags = getEFlags(f); 1560b57cec5SDimitry Andric if (eflags & EF_RISCV_RVC) 1570b57cec5SDimitry Andric target |= EF_RISCV_RVC; 1580b57cec5SDimitry Andric 1590b57cec5SDimitry Andric if ((eflags & EF_RISCV_FLOAT_ABI) != (target & EF_RISCV_FLOAT_ABI)) 160bdd1243dSDimitry Andric error( 161bdd1243dSDimitry Andric toString(f) + 162bdd1243dSDimitry Andric ": cannot link object files with different floating-point ABI from " + 163bdd1243dSDimitry Andric toString(ctx.objectFiles[0])); 1640b57cec5SDimitry Andric 1650b57cec5SDimitry Andric if ((eflags & EF_RISCV_RVE) != (target & EF_RISCV_RVE)) 1660b57cec5SDimitry Andric error(toString(f) + 1670b57cec5SDimitry Andric ": cannot link object files with different EF_RISCV_RVE"); 1680b57cec5SDimitry Andric } 1690b57cec5SDimitry Andric 1700b57cec5SDimitry Andric return target; 1710b57cec5SDimitry Andric } 1720b57cec5SDimitry Andric 173fe6060f1SDimitry Andric int64_t RISCV::getImplicitAddend(const uint8_t *buf, RelType type) const { 174fe6060f1SDimitry Andric switch (type) { 175fe6060f1SDimitry Andric default: 176fe6060f1SDimitry Andric internalLinkerError(getErrorLocation(buf), 177fe6060f1SDimitry Andric "cannot read addend for relocation " + toString(type)); 178fe6060f1SDimitry Andric return 0; 179fe6060f1SDimitry Andric case R_RISCV_32: 180fe6060f1SDimitry Andric case R_RISCV_TLS_DTPMOD32: 181fe6060f1SDimitry Andric case R_RISCV_TLS_DTPREL32: 182bdd1243dSDimitry Andric case R_RISCV_TLS_TPREL32: 183fe6060f1SDimitry Andric return SignExtend64<32>(read32le(buf)); 184fe6060f1SDimitry Andric case R_RISCV_64: 185bdd1243dSDimitry Andric case R_RISCV_TLS_DTPMOD64: 186bdd1243dSDimitry Andric case R_RISCV_TLS_DTPREL64: 187bdd1243dSDimitry Andric case R_RISCV_TLS_TPREL64: 188fe6060f1SDimitry Andric return read64le(buf); 189fe6060f1SDimitry Andric case R_RISCV_RELATIVE: 190fe6060f1SDimitry Andric case R_RISCV_IRELATIVE: 191fe6060f1SDimitry Andric return config->is64 ? read64le(buf) : read32le(buf); 192fe6060f1SDimitry Andric case R_RISCV_NONE: 193fe6060f1SDimitry Andric case R_RISCV_JUMP_SLOT: 194fe6060f1SDimitry Andric // These relocations are defined as not having an implicit addend. 195fe6060f1SDimitry Andric return 0; 196b3edf446SDimitry Andric case R_RISCV_TLSDESC: 197b3edf446SDimitry Andric return config->is64 ? read64le(buf + 8) : read32le(buf + 4); 198fe6060f1SDimitry Andric } 199fe6060f1SDimitry Andric } 200fe6060f1SDimitry Andric 2010b57cec5SDimitry Andric void RISCV::writeGotHeader(uint8_t *buf) const { 2020b57cec5SDimitry Andric if (config->is64) 2030b57cec5SDimitry Andric write64le(buf, mainPart->dynamic->getVA()); 2040b57cec5SDimitry Andric else 2050b57cec5SDimitry Andric write32le(buf, mainPart->dynamic->getVA()); 2060b57cec5SDimitry Andric } 2070b57cec5SDimitry Andric 2080b57cec5SDimitry Andric void RISCV::writeGotPlt(uint8_t *buf, const Symbol &s) const { 2090b57cec5SDimitry Andric if (config->is64) 2100b57cec5SDimitry Andric write64le(buf, in.plt->getVA()); 2110b57cec5SDimitry Andric else 2120b57cec5SDimitry Andric write32le(buf, in.plt->getVA()); 2130b57cec5SDimitry Andric } 2140b57cec5SDimitry Andric 215fe6060f1SDimitry Andric void RISCV::writeIgotPlt(uint8_t *buf, const Symbol &s) const { 216fe6060f1SDimitry Andric if (config->writeAddends) { 217fe6060f1SDimitry Andric if (config->is64) 218fe6060f1SDimitry Andric write64le(buf, s.getVA()); 219fe6060f1SDimitry Andric else 220fe6060f1SDimitry Andric write32le(buf, s.getVA()); 221fe6060f1SDimitry Andric } 222fe6060f1SDimitry Andric } 223fe6060f1SDimitry Andric 2240b57cec5SDimitry Andric void RISCV::writePltHeader(uint8_t *buf) const { 2250b57cec5SDimitry Andric // 1: auipc t2, %pcrel_hi(.got.plt) 2260b57cec5SDimitry Andric // sub t1, t1, t3 2270b57cec5SDimitry Andric // l[wd] t3, %pcrel_lo(1b)(t2); t3 = _dl_runtime_resolve 2280b57cec5SDimitry Andric // addi t1, t1, -pltHeaderSize-12; t1 = &.plt[i] - &.plt[0] 2290b57cec5SDimitry Andric // addi t0, t2, %pcrel_lo(1b) 2300b57cec5SDimitry Andric // srli t1, t1, (rv64?1:2); t1 = &.got.plt[i] - &.got.plt[0] 2310b57cec5SDimitry Andric // l[wd] t0, Wordsize(t0); t0 = link_map 2320b57cec5SDimitry Andric // jr t3 2330b57cec5SDimitry Andric uint32_t offset = in.gotPlt->getVA() - in.plt->getVA(); 2340b57cec5SDimitry Andric uint32_t load = config->is64 ? LD : LW; 2350b57cec5SDimitry Andric write32le(buf + 0, utype(AUIPC, X_T2, hi20(offset))); 2360b57cec5SDimitry Andric write32le(buf + 4, rtype(SUB, X_T1, X_T1, X_T3)); 2370b57cec5SDimitry Andric write32le(buf + 8, itype(load, X_T3, X_T2, lo12(offset))); 2380b57cec5SDimitry Andric write32le(buf + 12, itype(ADDI, X_T1, X_T1, -target->pltHeaderSize - 12)); 2390b57cec5SDimitry Andric write32le(buf + 16, itype(ADDI, X_T0, X_T2, lo12(offset))); 2400b57cec5SDimitry Andric write32le(buf + 20, itype(SRLI, X_T1, X_T1, config->is64 ? 1 : 2)); 2410b57cec5SDimitry Andric write32le(buf + 24, itype(load, X_T0, X_T0, config->wordsize)); 2420b57cec5SDimitry Andric write32le(buf + 28, itype(JALR, 0, X_T3, 0)); 2430b57cec5SDimitry Andric } 2440b57cec5SDimitry Andric 245480093f4SDimitry Andric void RISCV::writePlt(uint8_t *buf, const Symbol &sym, 246480093f4SDimitry Andric uint64_t pltEntryAddr) const { 2470b57cec5SDimitry Andric // 1: auipc t3, %pcrel_hi(f@.got.plt) 2480b57cec5SDimitry Andric // l[wd] t3, %pcrel_lo(1b)(t3) 2490b57cec5SDimitry Andric // jalr t1, t3 2500b57cec5SDimitry Andric // nop 251480093f4SDimitry Andric uint32_t offset = sym.getGotPltVA() - pltEntryAddr; 2520b57cec5SDimitry Andric write32le(buf + 0, utype(AUIPC, X_T3, hi20(offset))); 2530b57cec5SDimitry Andric write32le(buf + 4, itype(config->is64 ? LD : LW, X_T3, X_T3, lo12(offset))); 2540b57cec5SDimitry Andric write32le(buf + 8, itype(JALR, X_T1, X_T3, 0)); 2550b57cec5SDimitry Andric write32le(buf + 12, itype(ADDI, 0, 0, 0)); 2560b57cec5SDimitry Andric } 2570b57cec5SDimitry Andric 2580b57cec5SDimitry Andric RelType RISCV::getDynRel(RelType type) const { 2590b57cec5SDimitry Andric return type == target->symbolicRel ? type 2600b57cec5SDimitry Andric : static_cast<RelType>(R_RISCV_NONE); 2610b57cec5SDimitry Andric } 2620b57cec5SDimitry Andric 2630b57cec5SDimitry Andric RelExpr RISCV::getRelExpr(const RelType type, const Symbol &s, 2640b57cec5SDimitry Andric const uint8_t *loc) const { 2650b57cec5SDimitry Andric switch (type) { 266480093f4SDimitry Andric case R_RISCV_NONE: 267480093f4SDimitry Andric return R_NONE; 268480093f4SDimitry Andric case R_RISCV_32: 269480093f4SDimitry Andric case R_RISCV_64: 270480093f4SDimitry Andric case R_RISCV_HI20: 271480093f4SDimitry Andric case R_RISCV_LO12_I: 272480093f4SDimitry Andric case R_RISCV_LO12_S: 273480093f4SDimitry Andric case R_RISCV_RVC_LUI: 274480093f4SDimitry Andric return R_ABS; 2750b57cec5SDimitry Andric case R_RISCV_ADD8: 2760b57cec5SDimitry Andric case R_RISCV_ADD16: 2770b57cec5SDimitry Andric case R_RISCV_ADD32: 2780b57cec5SDimitry Andric case R_RISCV_ADD64: 2790b57cec5SDimitry Andric case R_RISCV_SET6: 2800b57cec5SDimitry Andric case R_RISCV_SET8: 2810b57cec5SDimitry Andric case R_RISCV_SET16: 2820b57cec5SDimitry Andric case R_RISCV_SET32: 2830b57cec5SDimitry Andric case R_RISCV_SUB6: 2840b57cec5SDimitry Andric case R_RISCV_SUB8: 2850b57cec5SDimitry Andric case R_RISCV_SUB16: 2860b57cec5SDimitry Andric case R_RISCV_SUB32: 2870b57cec5SDimitry Andric case R_RISCV_SUB64: 2880b57cec5SDimitry Andric return R_RISCV_ADD; 2890b57cec5SDimitry Andric case R_RISCV_JAL: 2900b57cec5SDimitry Andric case R_RISCV_BRANCH: 2910b57cec5SDimitry Andric case R_RISCV_PCREL_HI20: 2920b57cec5SDimitry Andric case R_RISCV_RVC_BRANCH: 2930b57cec5SDimitry Andric case R_RISCV_RVC_JUMP: 2940b57cec5SDimitry Andric case R_RISCV_32_PCREL: 2950b57cec5SDimitry Andric return R_PC; 2960b57cec5SDimitry Andric case R_RISCV_CALL: 2970b57cec5SDimitry Andric case R_RISCV_CALL_PLT: 29806c3fb27SDimitry Andric case R_RISCV_PLT32: 2990b57cec5SDimitry Andric return R_PLT_PC; 3000b57cec5SDimitry Andric case R_RISCV_GOT_HI20: 301297eecfbSDimitry Andric case R_RISCV_GOT32_PCREL: 3020b57cec5SDimitry Andric return R_GOT_PC; 3030b57cec5SDimitry Andric case R_RISCV_PCREL_LO12_I: 3040b57cec5SDimitry Andric case R_RISCV_PCREL_LO12_S: 3050b57cec5SDimitry Andric return R_RISCV_PC_INDIRECT; 306b3edf446SDimitry Andric case R_RISCV_TLSDESC_HI20: 307b3edf446SDimitry Andric case R_RISCV_TLSDESC_LOAD_LO12: 308b3edf446SDimitry Andric case R_RISCV_TLSDESC_ADD_LO12: 309b3edf446SDimitry Andric return R_TLSDESC_PC; 310b3edf446SDimitry Andric case R_RISCV_TLSDESC_CALL: 311b3edf446SDimitry Andric return R_TLSDESC_CALL; 3120b57cec5SDimitry Andric case R_RISCV_TLS_GD_HI20: 3130b57cec5SDimitry Andric return R_TLSGD_PC; 3140b57cec5SDimitry Andric case R_RISCV_TLS_GOT_HI20: 3150b57cec5SDimitry Andric return R_GOT_PC; 3160b57cec5SDimitry Andric case R_RISCV_TPREL_HI20: 3170b57cec5SDimitry Andric case R_RISCV_TPREL_LO12_I: 3180b57cec5SDimitry Andric case R_RISCV_TPREL_LO12_S: 319e8d8bef9SDimitry Andric return R_TPREL; 32055e4f9d5SDimitry Andric case R_RISCV_ALIGN: 321753f127fSDimitry Andric return R_RELAX_HINT; 322fcaf7f86SDimitry Andric case R_RISCV_TPREL_ADD: 323753f127fSDimitry Andric case R_RISCV_RELAX: 324753f127fSDimitry Andric return config->relax ? R_RELAX_HINT : R_NONE; 3255f757f3fSDimitry Andric case R_RISCV_SET_ULEB128: 3261db9f3b2SDimitry Andric case R_RISCV_SUB_ULEB128: 3275f757f3fSDimitry Andric return R_RISCV_LEB128; 3280b57cec5SDimitry Andric default: 329480093f4SDimitry Andric error(getErrorLocation(loc) + "unknown relocation (" + Twine(type) + 330480093f4SDimitry Andric ") against symbol " + toString(s)); 331480093f4SDimitry Andric return R_NONE; 3320b57cec5SDimitry Andric } 3330b57cec5SDimitry Andric } 3340b57cec5SDimitry Andric 3355ffd83dbSDimitry Andric void RISCV::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const { 3360b57cec5SDimitry Andric const unsigned bits = config->wordsize * 8; 3370b57cec5SDimitry Andric 3385ffd83dbSDimitry Andric switch (rel.type) { 3390b57cec5SDimitry Andric case R_RISCV_32: 3400b57cec5SDimitry Andric write32le(loc, val); 3410b57cec5SDimitry Andric return; 3420b57cec5SDimitry Andric case R_RISCV_64: 3430b57cec5SDimitry Andric write64le(loc, val); 3440b57cec5SDimitry Andric return; 3450b57cec5SDimitry Andric 3460b57cec5SDimitry Andric case R_RISCV_RVC_BRANCH: { 347753f127fSDimitry Andric checkInt(loc, val, 9, rel); 3485ffd83dbSDimitry Andric checkAlignment(loc, val, 2, rel); 3490b57cec5SDimitry Andric uint16_t insn = read16le(loc) & 0xE383; 3500b57cec5SDimitry Andric uint16_t imm8 = extractBits(val, 8, 8) << 12; 3510b57cec5SDimitry Andric uint16_t imm4_3 = extractBits(val, 4, 3) << 10; 3520b57cec5SDimitry Andric uint16_t imm7_6 = extractBits(val, 7, 6) << 5; 3530b57cec5SDimitry Andric uint16_t imm2_1 = extractBits(val, 2, 1) << 3; 3540b57cec5SDimitry Andric uint16_t imm5 = extractBits(val, 5, 5) << 2; 3550b57cec5SDimitry Andric insn |= imm8 | imm4_3 | imm7_6 | imm2_1 | imm5; 3560b57cec5SDimitry Andric 3570b57cec5SDimitry Andric write16le(loc, insn); 3580b57cec5SDimitry Andric return; 3590b57cec5SDimitry Andric } 3600b57cec5SDimitry Andric 3610b57cec5SDimitry Andric case R_RISCV_RVC_JUMP: { 362753f127fSDimitry Andric checkInt(loc, val, 12, rel); 3635ffd83dbSDimitry Andric checkAlignment(loc, val, 2, rel); 3640b57cec5SDimitry Andric uint16_t insn = read16le(loc) & 0xE003; 3650b57cec5SDimitry Andric uint16_t imm11 = extractBits(val, 11, 11) << 12; 3660b57cec5SDimitry Andric uint16_t imm4 = extractBits(val, 4, 4) << 11; 3670b57cec5SDimitry Andric uint16_t imm9_8 = extractBits(val, 9, 8) << 9; 3680b57cec5SDimitry Andric uint16_t imm10 = extractBits(val, 10, 10) << 8; 3690b57cec5SDimitry Andric uint16_t imm6 = extractBits(val, 6, 6) << 7; 3700b57cec5SDimitry Andric uint16_t imm7 = extractBits(val, 7, 7) << 6; 3710b57cec5SDimitry Andric uint16_t imm3_1 = extractBits(val, 3, 1) << 3; 3720b57cec5SDimitry Andric uint16_t imm5 = extractBits(val, 5, 5) << 2; 3730b57cec5SDimitry Andric insn |= imm11 | imm4 | imm9_8 | imm10 | imm6 | imm7 | imm3_1 | imm5; 3740b57cec5SDimitry Andric 3750b57cec5SDimitry Andric write16le(loc, insn); 3760b57cec5SDimitry Andric return; 3770b57cec5SDimitry Andric } 3780b57cec5SDimitry Andric 3790b57cec5SDimitry Andric case R_RISCV_RVC_LUI: { 3800b57cec5SDimitry Andric int64_t imm = SignExtend64(val + 0x800, bits) >> 12; 3815ffd83dbSDimitry Andric checkInt(loc, imm, 6, rel); 3820b57cec5SDimitry Andric if (imm == 0) { // `c.lui rd, 0` is illegal, convert to `c.li rd, 0` 3830b57cec5SDimitry Andric write16le(loc, (read16le(loc) & 0x0F83) | 0x4000); 3840b57cec5SDimitry Andric } else { 3850b57cec5SDimitry Andric uint16_t imm17 = extractBits(val + 0x800, 17, 17) << 12; 3860b57cec5SDimitry Andric uint16_t imm16_12 = extractBits(val + 0x800, 16, 12) << 2; 3870b57cec5SDimitry Andric write16le(loc, (read16le(loc) & 0xEF83) | imm17 | imm16_12); 3880b57cec5SDimitry Andric } 3890b57cec5SDimitry Andric return; 3900b57cec5SDimitry Andric } 3910b57cec5SDimitry Andric 3920b57cec5SDimitry Andric case R_RISCV_JAL: { 393753f127fSDimitry Andric checkInt(loc, val, 21, rel); 3945ffd83dbSDimitry Andric checkAlignment(loc, val, 2, rel); 3950b57cec5SDimitry Andric 3960b57cec5SDimitry Andric uint32_t insn = read32le(loc) & 0xFFF; 3970b57cec5SDimitry Andric uint32_t imm20 = extractBits(val, 20, 20) << 31; 3980b57cec5SDimitry Andric uint32_t imm10_1 = extractBits(val, 10, 1) << 21; 3990b57cec5SDimitry Andric uint32_t imm11 = extractBits(val, 11, 11) << 20; 4000b57cec5SDimitry Andric uint32_t imm19_12 = extractBits(val, 19, 12) << 12; 4010b57cec5SDimitry Andric insn |= imm20 | imm10_1 | imm11 | imm19_12; 4020b57cec5SDimitry Andric 4030b57cec5SDimitry Andric write32le(loc, insn); 4040b57cec5SDimitry Andric return; 4050b57cec5SDimitry Andric } 4060b57cec5SDimitry Andric 4070b57cec5SDimitry Andric case R_RISCV_BRANCH: { 408753f127fSDimitry Andric checkInt(loc, val, 13, rel); 4095ffd83dbSDimitry Andric checkAlignment(loc, val, 2, rel); 4100b57cec5SDimitry Andric 4110b57cec5SDimitry Andric uint32_t insn = read32le(loc) & 0x1FFF07F; 4120b57cec5SDimitry Andric uint32_t imm12 = extractBits(val, 12, 12) << 31; 4130b57cec5SDimitry Andric uint32_t imm10_5 = extractBits(val, 10, 5) << 25; 4140b57cec5SDimitry Andric uint32_t imm4_1 = extractBits(val, 4, 1) << 8; 4150b57cec5SDimitry Andric uint32_t imm11 = extractBits(val, 11, 11) << 7; 4160b57cec5SDimitry Andric insn |= imm12 | imm10_5 | imm4_1 | imm11; 4170b57cec5SDimitry Andric 4180b57cec5SDimitry Andric write32le(loc, insn); 4190b57cec5SDimitry Andric return; 4200b57cec5SDimitry Andric } 4210b57cec5SDimitry Andric 4220b57cec5SDimitry Andric // auipc + jalr pair 4230b57cec5SDimitry Andric case R_RISCV_CALL: 4240b57cec5SDimitry Andric case R_RISCV_CALL_PLT: { 4250b57cec5SDimitry Andric int64_t hi = SignExtend64(val + 0x800, bits) >> 12; 4265ffd83dbSDimitry Andric checkInt(loc, hi, 20, rel); 4270b57cec5SDimitry Andric if (isInt<20>(hi)) { 4285ffd83dbSDimitry Andric relocateNoSym(loc, R_RISCV_PCREL_HI20, val); 4295ffd83dbSDimitry Andric relocateNoSym(loc + 4, R_RISCV_PCREL_LO12_I, val); 4300b57cec5SDimitry Andric } 4310b57cec5SDimitry Andric return; 4320b57cec5SDimitry Andric } 4330b57cec5SDimitry Andric 4340b57cec5SDimitry Andric case R_RISCV_GOT_HI20: 4350b57cec5SDimitry Andric case R_RISCV_PCREL_HI20: 436b3edf446SDimitry Andric case R_RISCV_TLSDESC_HI20: 4370b57cec5SDimitry Andric case R_RISCV_TLS_GD_HI20: 4380b57cec5SDimitry Andric case R_RISCV_TLS_GOT_HI20: 4390b57cec5SDimitry Andric case R_RISCV_TPREL_HI20: 4400b57cec5SDimitry Andric case R_RISCV_HI20: { 4410b57cec5SDimitry Andric uint64_t hi = val + 0x800; 4425ffd83dbSDimitry Andric checkInt(loc, SignExtend64(hi, bits) >> 12, 20, rel); 4430b57cec5SDimitry Andric write32le(loc, (read32le(loc) & 0xFFF) | (hi & 0xFFFFF000)); 4440b57cec5SDimitry Andric return; 4450b57cec5SDimitry Andric } 4460b57cec5SDimitry Andric 4470b57cec5SDimitry Andric case R_RISCV_PCREL_LO12_I: 448b3edf446SDimitry Andric case R_RISCV_TLSDESC_LOAD_LO12: 449b3edf446SDimitry Andric case R_RISCV_TLSDESC_ADD_LO12: 4500b57cec5SDimitry Andric case R_RISCV_TPREL_LO12_I: 4510b57cec5SDimitry Andric case R_RISCV_LO12_I: { 4520b57cec5SDimitry Andric uint64_t hi = (val + 0x800) >> 12; 4530b57cec5SDimitry Andric uint64_t lo = val - (hi << 12); 454fcaf7f86SDimitry Andric write32le(loc, setLO12_I(read32le(loc), lo & 0xfff)); 4550b57cec5SDimitry Andric return; 4560b57cec5SDimitry Andric } 4570b57cec5SDimitry Andric 4580b57cec5SDimitry Andric case R_RISCV_PCREL_LO12_S: 4590b57cec5SDimitry Andric case R_RISCV_TPREL_LO12_S: 4600b57cec5SDimitry Andric case R_RISCV_LO12_S: { 4610b57cec5SDimitry Andric uint64_t hi = (val + 0x800) >> 12; 4620b57cec5SDimitry Andric uint64_t lo = val - (hi << 12); 463fcaf7f86SDimitry Andric write32le(loc, setLO12_S(read32le(loc), lo)); 4640b57cec5SDimitry Andric return; 4650b57cec5SDimitry Andric } 4660b57cec5SDimitry Andric 46706c3fb27SDimitry Andric case INTERNAL_R_RISCV_GPREL_I: 46806c3fb27SDimitry Andric case INTERNAL_R_RISCV_GPREL_S: { 46906c3fb27SDimitry Andric Defined *gp = ElfSym::riscvGlobalPointer; 47006c3fb27SDimitry Andric int64_t displace = SignExtend64(val - gp->getVA(), bits); 47106c3fb27SDimitry Andric checkInt(loc, displace, 12, rel); 47206c3fb27SDimitry Andric uint32_t insn = (read32le(loc) & ~(31 << 15)) | (X_GP << 15); 47306c3fb27SDimitry Andric if (rel.type == INTERNAL_R_RISCV_GPREL_I) 47406c3fb27SDimitry Andric insn = setLO12_I(insn, displace); 47506c3fb27SDimitry Andric else 47606c3fb27SDimitry Andric insn = setLO12_S(insn, displace); 47706c3fb27SDimitry Andric write32le(loc, insn); 47806c3fb27SDimitry Andric return; 47906c3fb27SDimitry Andric } 48006c3fb27SDimitry Andric 4810b57cec5SDimitry Andric case R_RISCV_ADD8: 4820b57cec5SDimitry Andric *loc += val; 4830b57cec5SDimitry Andric return; 4840b57cec5SDimitry Andric case R_RISCV_ADD16: 4850b57cec5SDimitry Andric write16le(loc, read16le(loc) + val); 4860b57cec5SDimitry Andric return; 4870b57cec5SDimitry Andric case R_RISCV_ADD32: 4880b57cec5SDimitry Andric write32le(loc, read32le(loc) + val); 4890b57cec5SDimitry Andric return; 4900b57cec5SDimitry Andric case R_RISCV_ADD64: 4910b57cec5SDimitry Andric write64le(loc, read64le(loc) + val); 4920b57cec5SDimitry Andric return; 4930b57cec5SDimitry Andric case R_RISCV_SUB6: 4940b57cec5SDimitry Andric *loc = (*loc & 0xc0) | (((*loc & 0x3f) - val) & 0x3f); 4950b57cec5SDimitry Andric return; 4960b57cec5SDimitry Andric case R_RISCV_SUB8: 4970b57cec5SDimitry Andric *loc -= val; 4980b57cec5SDimitry Andric return; 4990b57cec5SDimitry Andric case R_RISCV_SUB16: 5000b57cec5SDimitry Andric write16le(loc, read16le(loc) - val); 5010b57cec5SDimitry Andric return; 5020b57cec5SDimitry Andric case R_RISCV_SUB32: 5030b57cec5SDimitry Andric write32le(loc, read32le(loc) - val); 5040b57cec5SDimitry Andric return; 5050b57cec5SDimitry Andric case R_RISCV_SUB64: 5060b57cec5SDimitry Andric write64le(loc, read64le(loc) - val); 5070b57cec5SDimitry Andric return; 5080b57cec5SDimitry Andric case R_RISCV_SET6: 5090b57cec5SDimitry Andric *loc = (*loc & 0xc0) | (val & 0x3f); 5100b57cec5SDimitry Andric return; 5110b57cec5SDimitry Andric case R_RISCV_SET8: 5120b57cec5SDimitry Andric *loc = val; 5130b57cec5SDimitry Andric return; 5140b57cec5SDimitry Andric case R_RISCV_SET16: 5150b57cec5SDimitry Andric write16le(loc, val); 5160b57cec5SDimitry Andric return; 5170b57cec5SDimitry Andric case R_RISCV_SET32: 5180b57cec5SDimitry Andric case R_RISCV_32_PCREL: 51906c3fb27SDimitry Andric case R_RISCV_PLT32: 520297eecfbSDimitry Andric case R_RISCV_GOT32_PCREL: 521297eecfbSDimitry Andric checkInt(loc, val, 32, rel); 5220b57cec5SDimitry Andric write32le(loc, val); 5230b57cec5SDimitry Andric return; 5240b57cec5SDimitry Andric 5250b57cec5SDimitry Andric case R_RISCV_TLS_DTPREL32: 5260b57cec5SDimitry Andric write32le(loc, val - dtpOffset); 5270b57cec5SDimitry Andric break; 5280b57cec5SDimitry Andric case R_RISCV_TLS_DTPREL64: 5290b57cec5SDimitry Andric write64le(loc, val - dtpOffset); 5300b57cec5SDimitry Andric break; 5310b57cec5SDimitry Andric 5320b57cec5SDimitry Andric case R_RISCV_RELAX: 533b3edf446SDimitry Andric return; 534b3edf446SDimitry Andric case R_RISCV_TLSDESC: 535b3edf446SDimitry Andric // The addend is stored in the second word. 536b3edf446SDimitry Andric if (config->is64) 537b3edf446SDimitry Andric write64le(loc + 8, val); 538b3edf446SDimitry Andric else 539b3edf446SDimitry Andric write32le(loc + 4, val); 540b3edf446SDimitry Andric break; 5410b57cec5SDimitry Andric default: 542480093f4SDimitry Andric llvm_unreachable("unknown relocation"); 5430b57cec5SDimitry Andric } 5440b57cec5SDimitry Andric } 5450b57cec5SDimitry Andric 546b3edf446SDimitry Andric static bool relaxable(ArrayRef<Relocation> relocs, size_t i) { 547b3edf446SDimitry Andric return i + 1 != relocs.size() && relocs[i + 1].type == R_RISCV_RELAX; 548b3edf446SDimitry Andric } 549b3edf446SDimitry Andric 550b3edf446SDimitry Andric static void tlsdescToIe(uint8_t *loc, const Relocation &rel, uint64_t val) { 551b3edf446SDimitry Andric switch (rel.type) { 552b3edf446SDimitry Andric case R_RISCV_TLSDESC_HI20: 553b3edf446SDimitry Andric case R_RISCV_TLSDESC_LOAD_LO12: 554b3edf446SDimitry Andric write32le(loc, 0x00000013); // nop 555b3edf446SDimitry Andric break; 556b3edf446SDimitry Andric case R_RISCV_TLSDESC_ADD_LO12: 557b3edf446SDimitry Andric write32le(loc, utype(AUIPC, X_A0, hi20(val))); // auipc a0,<hi20> 558b3edf446SDimitry Andric break; 559b3edf446SDimitry Andric case R_RISCV_TLSDESC_CALL: 560b3edf446SDimitry Andric if (config->is64) 561b3edf446SDimitry Andric write32le(loc, itype(LD, X_A0, X_A0, lo12(val))); // ld a0,<lo12>(a0) 562b3edf446SDimitry Andric else 563b3edf446SDimitry Andric write32le(loc, itype(LW, X_A0, X_A0, lo12(val))); // lw a0,<lo12>(a0) 564b3edf446SDimitry Andric break; 565b3edf446SDimitry Andric default: 566b3edf446SDimitry Andric llvm_unreachable("unsupported relocation for TLSDESC to IE"); 567b3edf446SDimitry Andric } 568b3edf446SDimitry Andric } 569b3edf446SDimitry Andric 570b3edf446SDimitry Andric static void tlsdescToLe(uint8_t *loc, const Relocation &rel, uint64_t val) { 571b3edf446SDimitry Andric switch (rel.type) { 572b3edf446SDimitry Andric case R_RISCV_TLSDESC_HI20: 573b3edf446SDimitry Andric case R_RISCV_TLSDESC_LOAD_LO12: 574b3edf446SDimitry Andric write32le(loc, 0x00000013); // nop 575b3edf446SDimitry Andric return; 576b3edf446SDimitry Andric case R_RISCV_TLSDESC_ADD_LO12: 577b3edf446SDimitry Andric if (isInt<12>(val)) 578b3edf446SDimitry Andric write32le(loc, 0x00000013); // nop 579b3edf446SDimitry Andric else 580b3edf446SDimitry Andric write32le(loc, utype(LUI, X_A0, hi20(val))); // lui a0,<hi20> 581b3edf446SDimitry Andric return; 582b3edf446SDimitry Andric case R_RISCV_TLSDESC_CALL: 583b3edf446SDimitry Andric if (isInt<12>(val)) 584b3edf446SDimitry Andric write32le(loc, itype(ADDI, X_A0, 0, val)); // addi a0,zero,<lo12> 585b3edf446SDimitry Andric else 586b3edf446SDimitry Andric write32le(loc, itype(ADDI, X_A0, X_A0, lo12(val))); // addi a0,a0,<lo12> 587b3edf446SDimitry Andric return; 588b3edf446SDimitry Andric default: 589b3edf446SDimitry Andric llvm_unreachable("unsupported relocation for TLSDESC to LE"); 590b3edf446SDimitry Andric } 591b3edf446SDimitry Andric } 592b3edf446SDimitry Andric 5931db9f3b2SDimitry Andric void RISCV::relocateAlloc(InputSectionBase &sec, uint8_t *buf) const { 5941db9f3b2SDimitry Andric uint64_t secAddr = sec.getOutputSection()->addr; 5951db9f3b2SDimitry Andric if (auto *s = dyn_cast<InputSection>(&sec)) 5961db9f3b2SDimitry Andric secAddr += s->outSecOff; 5971db9f3b2SDimitry Andric else if (auto *ehIn = dyn_cast<EhInputSection>(&sec)) 5981db9f3b2SDimitry Andric secAddr += ehIn->getParent()->outSecOff; 599b3edf446SDimitry Andric uint64_t tlsdescVal = 0; 600b3edf446SDimitry Andric bool tlsdescRelax = false, isToLe = false; 601b3edf446SDimitry Andric const ArrayRef<Relocation> relocs = sec.relocs(); 602b3edf446SDimitry Andric for (size_t i = 0, size = relocs.size(); i != size; ++i) { 603b3edf446SDimitry Andric const Relocation &rel = relocs[i]; 6041db9f3b2SDimitry Andric uint8_t *loc = buf + rel.offset; 605b3edf446SDimitry Andric uint64_t val = 6061db9f3b2SDimitry Andric sec.getRelocTargetVA(sec.file, rel.type, rel.addend, 6071db9f3b2SDimitry Andric secAddr + rel.offset, *rel.sym, rel.expr); 6081db9f3b2SDimitry Andric 6091db9f3b2SDimitry Andric switch (rel.expr) { 6101db9f3b2SDimitry Andric case R_RELAX_HINT: 611b3edf446SDimitry Andric continue; 612b3edf446SDimitry Andric case R_TLSDESC_PC: 613b3edf446SDimitry Andric // For R_RISCV_TLSDESC_HI20, store &got(sym)-PC to be used by the 614b3edf446SDimitry Andric // following two instructions L[DW] and ADDI. 615b3edf446SDimitry Andric if (rel.type == R_RISCV_TLSDESC_HI20) 616b3edf446SDimitry Andric tlsdescVal = val; 617b3edf446SDimitry Andric else 618b3edf446SDimitry Andric val = tlsdescVal; 6191db9f3b2SDimitry Andric break; 620b3edf446SDimitry Andric case R_RELAX_TLS_GD_TO_IE: 621b3edf446SDimitry Andric // Only R_RISCV_TLSDESC_HI20 reaches here. tlsdescVal will be finalized 622b3edf446SDimitry Andric // after we see R_RISCV_TLSDESC_ADD_LO12 in the R_RELAX_TLS_GD_TO_LE case. 623b3edf446SDimitry Andric // The net effect is that tlsdescVal will be smaller than `val` to take 624b3edf446SDimitry Andric // into account of NOP instructions (in the absence of R_RISCV_RELAX) 625b3edf446SDimitry Andric // before AUIPC. 626b3edf446SDimitry Andric tlsdescVal = val + rel.offset; 627b3edf446SDimitry Andric isToLe = false; 628b3edf446SDimitry Andric tlsdescRelax = relaxable(relocs, i); 629b3edf446SDimitry Andric if (!tlsdescRelax) 630b3edf446SDimitry Andric tlsdescToIe(loc, rel, val); 631b3edf446SDimitry Andric continue; 632b3edf446SDimitry Andric case R_RELAX_TLS_GD_TO_LE: 633b3edf446SDimitry Andric // See the comment in handleTlsRelocation. For TLSDESC=>IE, 634b3edf446SDimitry Andric // R_RISCV_TLSDESC_{LOAD_LO12,ADD_LO12,CALL} also reach here. If isToIe is 635b3edf446SDimitry Andric // true, this is actually TLSDESC=>IE optimization. 636b3edf446SDimitry Andric if (rel.type == R_RISCV_TLSDESC_HI20) { 637b3edf446SDimitry Andric tlsdescVal = val; 638b3edf446SDimitry Andric isToLe = true; 639b3edf446SDimitry Andric tlsdescRelax = relaxable(relocs, i); 640b3edf446SDimitry Andric } else { 641b3edf446SDimitry Andric if (!isToLe && rel.type == R_RISCV_TLSDESC_ADD_LO12) 642b3edf446SDimitry Andric tlsdescVal -= rel.offset; 643b3edf446SDimitry Andric val = tlsdescVal; 644b3edf446SDimitry Andric } 645b3edf446SDimitry Andric // When NOP conversion is eligible and relaxation applies, don't write a 646b3edf446SDimitry Andric // NOP in case an unrelated instruction follows the current instruction. 647b3edf446SDimitry Andric if (tlsdescRelax && 648b3edf446SDimitry Andric (rel.type == R_RISCV_TLSDESC_HI20 || 649b3edf446SDimitry Andric rel.type == R_RISCV_TLSDESC_LOAD_LO12 || 650b3edf446SDimitry Andric (rel.type == R_RISCV_TLSDESC_ADD_LO12 && isToLe && !hi20(val)))) 651b3edf446SDimitry Andric continue; 652b3edf446SDimitry Andric if (isToLe) 653b3edf446SDimitry Andric tlsdescToLe(loc, rel, val); 654b3edf446SDimitry Andric else 655b3edf446SDimitry Andric tlsdescToIe(loc, rel, val); 656b3edf446SDimitry Andric continue; 6571db9f3b2SDimitry Andric case R_RISCV_LEB128: 6581db9f3b2SDimitry Andric if (i + 1 < size) { 659b3edf446SDimitry Andric const Relocation &rel1 = relocs[i + 1]; 6601db9f3b2SDimitry Andric if (rel.type == R_RISCV_SET_ULEB128 && 6611db9f3b2SDimitry Andric rel1.type == R_RISCV_SUB_ULEB128 && rel.offset == rel1.offset) { 6621db9f3b2SDimitry Andric auto val = rel.sym->getVA(rel.addend) - rel1.sym->getVA(rel1.addend); 6631db9f3b2SDimitry Andric if (overwriteULEB128(loc, val) >= 0x80) 6641db9f3b2SDimitry Andric errorOrWarn(sec.getLocation(rel.offset) + ": ULEB128 value " + 6651db9f3b2SDimitry Andric Twine(val) + " exceeds available space; references '" + 6661db9f3b2SDimitry Andric lld::toString(*rel.sym) + "'"); 6671db9f3b2SDimitry Andric ++i; 6681db9f3b2SDimitry Andric continue; 6691db9f3b2SDimitry Andric } 6701db9f3b2SDimitry Andric } 6711db9f3b2SDimitry Andric errorOrWarn(sec.getLocation(rel.offset) + 6721db9f3b2SDimitry Andric ": R_RISCV_SET_ULEB128 not paired with R_RISCV_SUB_SET128"); 6731db9f3b2SDimitry Andric return; 6741db9f3b2SDimitry Andric default: 6751db9f3b2SDimitry Andric break; 6761db9f3b2SDimitry Andric } 677b3edf446SDimitry Andric relocate(loc, rel, val); 6781db9f3b2SDimitry Andric } 6791db9f3b2SDimitry Andric } 6801db9f3b2SDimitry Andric 68174626c16SDimitry Andric void elf::initSymbolAnchors() { 682753f127fSDimitry Andric SmallVector<InputSection *, 0> storage; 683753f127fSDimitry Andric for (OutputSection *osec : outputSections) { 684753f127fSDimitry Andric if (!(osec->flags & SHF_EXECINSTR)) 685753f127fSDimitry Andric continue; 686753f127fSDimitry Andric for (InputSection *sec : getInputSections(*osec, storage)) { 68774626c16SDimitry Andric sec->relaxAux = make<RelaxAux>(); 688bdd1243dSDimitry Andric if (sec->relocs().size()) { 689753f127fSDimitry Andric sec->relaxAux->relocDeltas = 690bdd1243dSDimitry Andric std::make_unique<uint32_t[]>(sec->relocs().size()); 691753f127fSDimitry Andric sec->relaxAux->relocTypes = 692bdd1243dSDimitry Andric std::make_unique<RelType[]>(sec->relocs().size()); 693753f127fSDimitry Andric } 694753f127fSDimitry Andric } 695753f127fSDimitry Andric } 696753f127fSDimitry Andric // Store anchors (st_value and st_value+st_size) for symbols relative to text 697753f127fSDimitry Andric // sections. 69806c3fb27SDimitry Andric // 69906c3fb27SDimitry Andric // For a defined symbol foo, we may have `d->file != file` with --wrap=foo. 70006c3fb27SDimitry Andric // We should process foo, as the defining object file's symbol table may not 70106c3fb27SDimitry Andric // contain foo after redirectSymbols changed the foo entry to __wrap_foo. To 70206c3fb27SDimitry Andric // avoid adding a Defined that is undefined in one object file, use 70306c3fb27SDimitry Andric // `!d->scriptDefined` to exclude symbols that are definitely not wrapped. 70406c3fb27SDimitry Andric // 70506c3fb27SDimitry Andric // `relaxAux->anchors` may contain duplicate symbols, but that is fine. 706bdd1243dSDimitry Andric for (InputFile *file : ctx.objectFiles) 707753f127fSDimitry Andric for (Symbol *sym : file->getSymbols()) { 708753f127fSDimitry Andric auto *d = dyn_cast<Defined>(sym); 70906c3fb27SDimitry Andric if (!d || (d->file != file && !d->scriptDefined)) 710753f127fSDimitry Andric continue; 711753f127fSDimitry Andric if (auto *sec = dyn_cast_or_null<InputSection>(d->section)) 712753f127fSDimitry Andric if (sec->flags & SHF_EXECINSTR && sec->relaxAux) { 713753f127fSDimitry Andric // If sec is discarded, relaxAux will be nullptr. 714753f127fSDimitry Andric sec->relaxAux->anchors.push_back({d->value, d, false}); 715753f127fSDimitry Andric sec->relaxAux->anchors.push_back({d->value + d->size, d, true}); 716753f127fSDimitry Andric } 717753f127fSDimitry Andric } 718753f127fSDimitry Andric // Sort anchors by offset so that we can find the closest relocation 719753f127fSDimitry Andric // efficiently. For a zero size symbol, ensure that its start anchor precedes 720753f127fSDimitry Andric // its end anchor. For two symbols with anchors at the same offset, their 721753f127fSDimitry Andric // order does not matter. 722753f127fSDimitry Andric for (OutputSection *osec : outputSections) { 723753f127fSDimitry Andric if (!(osec->flags & SHF_EXECINSTR)) 724753f127fSDimitry Andric continue; 725753f127fSDimitry Andric for (InputSection *sec : getInputSections(*osec, storage)) { 726753f127fSDimitry Andric llvm::sort(sec->relaxAux->anchors, [](auto &a, auto &b) { 727753f127fSDimitry Andric return std::make_pair(a.offset, a.end) < 728753f127fSDimitry Andric std::make_pair(b.offset, b.end); 729753f127fSDimitry Andric }); 730753f127fSDimitry Andric } 731753f127fSDimitry Andric } 732753f127fSDimitry Andric } 733753f127fSDimitry Andric 734753f127fSDimitry Andric // Relax R_RISCV_CALL/R_RISCV_CALL_PLT auipc+jalr to c.j, c.jal, or jal. 735753f127fSDimitry Andric static void relaxCall(const InputSection &sec, size_t i, uint64_t loc, 736753f127fSDimitry Andric Relocation &r, uint32_t &remove) { 7375f757f3fSDimitry Andric const bool rvc = getEFlags(sec.file) & EF_RISCV_RVC; 738753f127fSDimitry Andric const Symbol &sym = *r.sym; 739bdd1243dSDimitry Andric const uint64_t insnPair = read64le(sec.content().data() + r.offset); 740753f127fSDimitry Andric const uint32_t rd = extractBits(insnPair, 32 + 11, 32 + 7); 741753f127fSDimitry Andric const uint64_t dest = 742753f127fSDimitry Andric (r.expr == R_PLT_PC ? sym.getPltVA() : sym.getVA()) + r.addend; 743753f127fSDimitry Andric const int64_t displace = dest - loc; 744753f127fSDimitry Andric 745753f127fSDimitry Andric if (rvc && isInt<12>(displace) && rd == 0) { 746753f127fSDimitry Andric sec.relaxAux->relocTypes[i] = R_RISCV_RVC_JUMP; 747753f127fSDimitry Andric sec.relaxAux->writes.push_back(0xa001); // c.j 748753f127fSDimitry Andric remove = 6; 749753f127fSDimitry Andric } else if (rvc && isInt<12>(displace) && rd == X_RA && 750753f127fSDimitry Andric !config->is64) { // RV32C only 751753f127fSDimitry Andric sec.relaxAux->relocTypes[i] = R_RISCV_RVC_JUMP; 752753f127fSDimitry Andric sec.relaxAux->writes.push_back(0x2001); // c.jal 753753f127fSDimitry Andric remove = 6; 754753f127fSDimitry Andric } else if (isInt<21>(displace)) { 755753f127fSDimitry Andric sec.relaxAux->relocTypes[i] = R_RISCV_JAL; 756753f127fSDimitry Andric sec.relaxAux->writes.push_back(0x6f | rd << 7); // jal 757753f127fSDimitry Andric remove = 4; 758753f127fSDimitry Andric } 759753f127fSDimitry Andric } 760753f127fSDimitry Andric 761fcaf7f86SDimitry Andric // Relax local-exec TLS when hi20 is zero. 762fcaf7f86SDimitry Andric static void relaxTlsLe(const InputSection &sec, size_t i, uint64_t loc, 763fcaf7f86SDimitry Andric Relocation &r, uint32_t &remove) { 764fcaf7f86SDimitry Andric uint64_t val = r.sym->getVA(r.addend); 765fcaf7f86SDimitry Andric if (hi20(val) != 0) 766fcaf7f86SDimitry Andric return; 767bdd1243dSDimitry Andric uint32_t insn = read32le(sec.content().data() + r.offset); 768fcaf7f86SDimitry Andric switch (r.type) { 769fcaf7f86SDimitry Andric case R_RISCV_TPREL_HI20: 770fcaf7f86SDimitry Andric case R_RISCV_TPREL_ADD: 771fcaf7f86SDimitry Andric // Remove lui rd, %tprel_hi(x) and add rd, rd, tp, %tprel_add(x). 772fcaf7f86SDimitry Andric sec.relaxAux->relocTypes[i] = R_RISCV_RELAX; 773fcaf7f86SDimitry Andric remove = 4; 774fcaf7f86SDimitry Andric break; 775fcaf7f86SDimitry Andric case R_RISCV_TPREL_LO12_I: 776fcaf7f86SDimitry Andric // addi rd, rd, %tprel_lo(x) => addi rd, tp, st_value(x) 777fcaf7f86SDimitry Andric sec.relaxAux->relocTypes[i] = R_RISCV_32; 778fcaf7f86SDimitry Andric insn = (insn & ~(31 << 15)) | (X_TP << 15); 779fcaf7f86SDimitry Andric sec.relaxAux->writes.push_back(setLO12_I(insn, val)); 780fcaf7f86SDimitry Andric break; 781fcaf7f86SDimitry Andric case R_RISCV_TPREL_LO12_S: 782fcaf7f86SDimitry Andric // sw rs, %tprel_lo(x)(rd) => sw rs, st_value(x)(rd) 783fcaf7f86SDimitry Andric sec.relaxAux->relocTypes[i] = R_RISCV_32; 784fcaf7f86SDimitry Andric insn = (insn & ~(31 << 15)) | (X_TP << 15); 785fcaf7f86SDimitry Andric sec.relaxAux->writes.push_back(setLO12_S(insn, val)); 786fcaf7f86SDimitry Andric break; 787fcaf7f86SDimitry Andric } 788fcaf7f86SDimitry Andric } 789fcaf7f86SDimitry Andric 79006c3fb27SDimitry Andric static void relaxHi20Lo12(const InputSection &sec, size_t i, uint64_t loc, 79106c3fb27SDimitry Andric Relocation &r, uint32_t &remove) { 79206c3fb27SDimitry Andric const Defined *gp = ElfSym::riscvGlobalPointer; 79306c3fb27SDimitry Andric if (!gp) 79406c3fb27SDimitry Andric return; 79506c3fb27SDimitry Andric 79606c3fb27SDimitry Andric if (!isInt<12>(r.sym->getVA(r.addend) - gp->getVA())) 79706c3fb27SDimitry Andric return; 79806c3fb27SDimitry Andric 79906c3fb27SDimitry Andric switch (r.type) { 80006c3fb27SDimitry Andric case R_RISCV_HI20: 80106c3fb27SDimitry Andric // Remove lui rd, %hi20(x). 80206c3fb27SDimitry Andric sec.relaxAux->relocTypes[i] = R_RISCV_RELAX; 80306c3fb27SDimitry Andric remove = 4; 80406c3fb27SDimitry Andric break; 80506c3fb27SDimitry Andric case R_RISCV_LO12_I: 80606c3fb27SDimitry Andric sec.relaxAux->relocTypes[i] = INTERNAL_R_RISCV_GPREL_I; 80706c3fb27SDimitry Andric break; 80806c3fb27SDimitry Andric case R_RISCV_LO12_S: 80906c3fb27SDimitry Andric sec.relaxAux->relocTypes[i] = INTERNAL_R_RISCV_GPREL_S; 81006c3fb27SDimitry Andric break; 81106c3fb27SDimitry Andric } 81206c3fb27SDimitry Andric } 81306c3fb27SDimitry Andric 814753f127fSDimitry Andric static bool relax(InputSection &sec) { 815753f127fSDimitry Andric const uint64_t secAddr = sec.getVA(); 816b3edf446SDimitry Andric const MutableArrayRef<Relocation> relocs = sec.relocs(); 817753f127fSDimitry Andric auto &aux = *sec.relaxAux; 818753f127fSDimitry Andric bool changed = false; 819bdd1243dSDimitry Andric ArrayRef<SymbolAnchor> sa = ArrayRef(aux.anchors); 82006c3fb27SDimitry Andric uint64_t delta = 0; 821b3edf446SDimitry Andric bool tlsdescRelax = false, toLeShortForm = false; 822753f127fSDimitry Andric 823b3edf446SDimitry Andric std::fill_n(aux.relocTypes.get(), relocs.size(), R_RISCV_NONE); 824753f127fSDimitry Andric aux.writes.clear(); 825b3edf446SDimitry Andric for (auto [i, r] : llvm::enumerate(relocs)) { 826753f127fSDimitry Andric const uint64_t loc = secAddr + r.offset - delta; 827753f127fSDimitry Andric uint32_t &cur = aux.relocDeltas[i], remove = 0; 828753f127fSDimitry Andric switch (r.type) { 829753f127fSDimitry Andric case R_RISCV_ALIGN: { 830753f127fSDimitry Andric const uint64_t nextLoc = loc + r.addend; 831753f127fSDimitry Andric const uint64_t align = PowerOf2Ceil(r.addend + 2); 832753f127fSDimitry Andric // All bytes beyond the alignment boundary should be removed. 833753f127fSDimitry Andric remove = nextLoc - ((loc + align - 1) & -align); 8347a6dacacSDimitry Andric // If we can't satisfy this alignment, we've found a bad input. 8357a6dacacSDimitry Andric if (LLVM_UNLIKELY(static_cast<int32_t>(remove) < 0)) { 8367a6dacacSDimitry Andric errorOrWarn(getErrorLocation((const uint8_t*)loc) + 8377a6dacacSDimitry Andric "insufficient padding bytes for " + lld::toString(r.type) + 8387a6dacacSDimitry Andric ": " + Twine(r.addend) + " bytes available " 8397a6dacacSDimitry Andric "for requested alignment of " + Twine(align) + " bytes"); 8407a6dacacSDimitry Andric remove = 0; 8417a6dacacSDimitry Andric } 842753f127fSDimitry Andric break; 843753f127fSDimitry Andric } 844753f127fSDimitry Andric case R_RISCV_CALL: 845753f127fSDimitry Andric case R_RISCV_CALL_PLT: 846b3edf446SDimitry Andric if (relaxable(relocs, i)) 847753f127fSDimitry Andric relaxCall(sec, i, loc, r, remove); 848753f127fSDimitry Andric break; 849fcaf7f86SDimitry Andric case R_RISCV_TPREL_HI20: 850fcaf7f86SDimitry Andric case R_RISCV_TPREL_ADD: 851fcaf7f86SDimitry Andric case R_RISCV_TPREL_LO12_I: 852fcaf7f86SDimitry Andric case R_RISCV_TPREL_LO12_S: 853b3edf446SDimitry Andric if (relaxable(relocs, i)) 854fcaf7f86SDimitry Andric relaxTlsLe(sec, i, loc, r, remove); 855fcaf7f86SDimitry Andric break; 85606c3fb27SDimitry Andric case R_RISCV_HI20: 85706c3fb27SDimitry Andric case R_RISCV_LO12_I: 85806c3fb27SDimitry Andric case R_RISCV_LO12_S: 859b3edf446SDimitry Andric if (relaxable(relocs, i)) 86006c3fb27SDimitry Andric relaxHi20Lo12(sec, i, loc, r, remove); 86106c3fb27SDimitry Andric break; 862b3edf446SDimitry Andric case R_RISCV_TLSDESC_HI20: 863b3edf446SDimitry Andric // For TLSDESC=>LE, we can use the short form if hi20 is zero. 864b3edf446SDimitry Andric tlsdescRelax = relaxable(relocs, i); 865b3edf446SDimitry Andric toLeShortForm = tlsdescRelax && r.expr == R_RELAX_TLS_GD_TO_LE && 866b3edf446SDimitry Andric !hi20(r.sym->getVA(r.addend)); 867b3edf446SDimitry Andric [[fallthrough]]; 868b3edf446SDimitry Andric case R_RISCV_TLSDESC_LOAD_LO12: 869b3edf446SDimitry Andric // For TLSDESC=>LE/IE, AUIPC and L[DW] are removed if relaxable. 870b3edf446SDimitry Andric if (tlsdescRelax && r.expr != R_TLSDESC_PC) 871b3edf446SDimitry Andric remove = 4; 872b3edf446SDimitry Andric break; 873b3edf446SDimitry Andric case R_RISCV_TLSDESC_ADD_LO12: 874b3edf446SDimitry Andric if (toLeShortForm) 875b3edf446SDimitry Andric remove = 4; 876b3edf446SDimitry Andric break; 877753f127fSDimitry Andric } 878753f127fSDimitry Andric 879753f127fSDimitry Andric // For all anchors whose offsets are <= r.offset, they are preceded by 880753f127fSDimitry Andric // the previous relocation whose `relocDeltas` value equals `delta`. 881753f127fSDimitry Andric // Decrease their st_value and update their st_size. 882753f127fSDimitry Andric for (; sa.size() && sa[0].offset <= r.offset; sa = sa.slice(1)) { 883753f127fSDimitry Andric if (sa[0].end) 884753f127fSDimitry Andric sa[0].d->size = sa[0].offset - delta - sa[0].d->value; 885753f127fSDimitry Andric else 88606c3fb27SDimitry Andric sa[0].d->value = sa[0].offset - delta; 887753f127fSDimitry Andric } 888753f127fSDimitry Andric delta += remove; 889753f127fSDimitry Andric if (delta != cur) { 890753f127fSDimitry Andric cur = delta; 891753f127fSDimitry Andric changed = true; 892753f127fSDimitry Andric } 893753f127fSDimitry Andric } 894753f127fSDimitry Andric 895753f127fSDimitry Andric for (const SymbolAnchor &a : sa) { 896753f127fSDimitry Andric if (a.end) 897753f127fSDimitry Andric a.d->size = a.offset - delta - a.d->value; 898753f127fSDimitry Andric else 89906c3fb27SDimitry Andric a.d->value = a.offset - delta; 900753f127fSDimitry Andric } 901753f127fSDimitry Andric // Inform assignAddresses that the size has changed. 90206c3fb27SDimitry Andric if (!isUInt<32>(delta)) 90306c3fb27SDimitry Andric fatal("section size decrease is too large: " + Twine(delta)); 904753f127fSDimitry Andric sec.bytesDropped = delta; 905753f127fSDimitry Andric return changed; 906753f127fSDimitry Andric } 907753f127fSDimitry Andric 908753f127fSDimitry Andric // When relaxing just R_RISCV_ALIGN, relocDeltas is usually changed only once in 909753f127fSDimitry Andric // the absence of a linker script. For call and load/store R_RISCV_RELAX, code 910753f127fSDimitry Andric // shrinkage may reduce displacement and make more relocations eligible for 911753f127fSDimitry Andric // relaxation. Code shrinkage may increase displacement to a call/load/store 912753f127fSDimitry Andric // target at a higher fixed address, invalidating an earlier relaxation. Any 913753f127fSDimitry Andric // change in section sizes can have cascading effect and require another 914753f127fSDimitry Andric // relaxation pass. 915753f127fSDimitry Andric bool RISCV::relaxOnce(int pass) const { 916753f127fSDimitry Andric llvm::TimeTraceScope timeScope("RISC-V relaxOnce"); 917753f127fSDimitry Andric if (config->relocatable) 918753f127fSDimitry Andric return false; 919753f127fSDimitry Andric 920753f127fSDimitry Andric if (pass == 0) 921753f127fSDimitry Andric initSymbolAnchors(); 922753f127fSDimitry Andric 923753f127fSDimitry Andric SmallVector<InputSection *, 0> storage; 924753f127fSDimitry Andric bool changed = false; 925753f127fSDimitry Andric for (OutputSection *osec : outputSections) { 926753f127fSDimitry Andric if (!(osec->flags & SHF_EXECINSTR)) 927753f127fSDimitry Andric continue; 928753f127fSDimitry Andric for (InputSection *sec : getInputSections(*osec, storage)) 929753f127fSDimitry Andric changed |= relax(*sec); 930753f127fSDimitry Andric } 931753f127fSDimitry Andric return changed; 932753f127fSDimitry Andric } 933753f127fSDimitry Andric 93474626c16SDimitry Andric void RISCV::finalizeRelax(int passes) const { 935753f127fSDimitry Andric llvm::TimeTraceScope timeScope("Finalize RISC-V relaxation"); 936753f127fSDimitry Andric log("relaxation passes: " + Twine(passes)); 937753f127fSDimitry Andric SmallVector<InputSection *, 0> storage; 938753f127fSDimitry Andric for (OutputSection *osec : outputSections) { 939753f127fSDimitry Andric if (!(osec->flags & SHF_EXECINSTR)) 940753f127fSDimitry Andric continue; 941753f127fSDimitry Andric for (InputSection *sec : getInputSections(*osec, storage)) { 94274626c16SDimitry Andric RelaxAux &aux = *sec->relaxAux; 943753f127fSDimitry Andric if (!aux.relocDeltas) 944753f127fSDimitry Andric continue; 945753f127fSDimitry Andric 946bdd1243dSDimitry Andric MutableArrayRef<Relocation> rels = sec->relocs(); 947bdd1243dSDimitry Andric ArrayRef<uint8_t> old = sec->content(); 948bdd1243dSDimitry Andric size_t newSize = old.size() - aux.relocDeltas[rels.size() - 1]; 949753f127fSDimitry Andric size_t writesIdx = 0; 950753f127fSDimitry Andric uint8_t *p = context().bAlloc.Allocate<uint8_t>(newSize); 951753f127fSDimitry Andric uint64_t offset = 0; 952753f127fSDimitry Andric int64_t delta = 0; 953bdd1243dSDimitry Andric sec->content_ = p; 954bdd1243dSDimitry Andric sec->size = newSize; 955753f127fSDimitry Andric sec->bytesDropped = 0; 956753f127fSDimitry Andric 957753f127fSDimitry Andric // Update section content: remove NOPs for R_RISCV_ALIGN and rewrite 958753f127fSDimitry Andric // instructions for relaxed relocations. 959753f127fSDimitry Andric for (size_t i = 0, e = rels.size(); i != e; ++i) { 960753f127fSDimitry Andric uint32_t remove = aux.relocDeltas[i] - delta; 961753f127fSDimitry Andric delta = aux.relocDeltas[i]; 962fcaf7f86SDimitry Andric if (remove == 0 && aux.relocTypes[i] == R_RISCV_NONE) 963753f127fSDimitry Andric continue; 964753f127fSDimitry Andric 965753f127fSDimitry Andric // Copy from last location to the current relocated location. 966753f127fSDimitry Andric const Relocation &r = rels[i]; 967753f127fSDimitry Andric uint64_t size = r.offset - offset; 968753f127fSDimitry Andric memcpy(p, old.data() + offset, size); 969753f127fSDimitry Andric p += size; 970753f127fSDimitry Andric 971753f127fSDimitry Andric // For R_RISCV_ALIGN, we will place `offset` in a location (among NOPs) 9726246ae0bSDimitry Andric // to satisfy the alignment requirement. If both `remove` and r.addend 9736246ae0bSDimitry Andric // are multiples of 4, it is as if we have skipped some NOPs. Otherwise 9746246ae0bSDimitry Andric // we are in the middle of a 4-byte NOP, and we need to rewrite the NOP 9756246ae0bSDimitry Andric // sequence. 976753f127fSDimitry Andric int64_t skip = 0; 977753f127fSDimitry Andric if (r.type == R_RISCV_ALIGN) { 9786246ae0bSDimitry Andric if (remove % 4 || r.addend % 4) { 979753f127fSDimitry Andric skip = r.addend - remove; 980753f127fSDimitry Andric int64_t j = 0; 981753f127fSDimitry Andric for (; j + 4 <= skip; j += 4) 982753f127fSDimitry Andric write32le(p + j, 0x00000013); // nop 983753f127fSDimitry Andric if (j != skip) { 984753f127fSDimitry Andric assert(j + 2 == skip); 985753f127fSDimitry Andric write16le(p + j, 0x0001); // c.nop 986753f127fSDimitry Andric } 987753f127fSDimitry Andric } 988753f127fSDimitry Andric } else if (RelType newType = aux.relocTypes[i]) { 989753f127fSDimitry Andric switch (newType) { 99006c3fb27SDimitry Andric case INTERNAL_R_RISCV_GPREL_I: 99106c3fb27SDimitry Andric case INTERNAL_R_RISCV_GPREL_S: 99206c3fb27SDimitry Andric break; 993fcaf7f86SDimitry Andric case R_RISCV_RELAX: 994fcaf7f86SDimitry Andric // Used by relaxTlsLe to indicate the relocation is ignored. 995fcaf7f86SDimitry Andric break; 996753f127fSDimitry Andric case R_RISCV_RVC_JUMP: 997753f127fSDimitry Andric skip = 2; 998fcaf7f86SDimitry Andric write16le(p, aux.writes[writesIdx++]); 999753f127fSDimitry Andric break; 1000753f127fSDimitry Andric case R_RISCV_JAL: 1001753f127fSDimitry Andric skip = 4; 1002fcaf7f86SDimitry Andric write32le(p, aux.writes[writesIdx++]); 1003fcaf7f86SDimitry Andric break; 1004fcaf7f86SDimitry Andric case R_RISCV_32: 1005fcaf7f86SDimitry Andric // Used by relaxTlsLe to write a uint32_t then suppress the handling 1006fcaf7f86SDimitry Andric // in relocateAlloc. 1007fcaf7f86SDimitry Andric skip = 4; 1008fcaf7f86SDimitry Andric write32le(p, aux.writes[writesIdx++]); 1009fcaf7f86SDimitry Andric aux.relocTypes[i] = R_RISCV_NONE; 1010753f127fSDimitry Andric break; 1011753f127fSDimitry Andric default: 1012753f127fSDimitry Andric llvm_unreachable("unsupported type"); 1013753f127fSDimitry Andric } 1014753f127fSDimitry Andric } 1015753f127fSDimitry Andric 1016753f127fSDimitry Andric p += skip; 1017753f127fSDimitry Andric offset = r.offset + skip + remove; 1018753f127fSDimitry Andric } 1019753f127fSDimitry Andric memcpy(p, old.data() + offset, old.size() - offset); 1020753f127fSDimitry Andric 1021753f127fSDimitry Andric // Subtract the previous relocDeltas value from the relocation offset. 1022753f127fSDimitry Andric // For a pair of R_RISCV_CALL/R_RISCV_RELAX with the same offset, decrease 1023753f127fSDimitry Andric // their r_offset by the same delta. 1024753f127fSDimitry Andric delta = 0; 1025753f127fSDimitry Andric for (size_t i = 0, e = rels.size(); i != e;) { 1026753f127fSDimitry Andric uint64_t cur = rels[i].offset; 1027753f127fSDimitry Andric do { 1028753f127fSDimitry Andric rels[i].offset -= delta; 1029753f127fSDimitry Andric if (aux.relocTypes[i] != R_RISCV_NONE) 1030753f127fSDimitry Andric rels[i].type = aux.relocTypes[i]; 1031753f127fSDimitry Andric } while (++i != e && rels[i].offset == cur); 1032753f127fSDimitry Andric delta = aux.relocDeltas[i - 1]; 1033753f127fSDimitry Andric } 1034753f127fSDimitry Andric } 1035753f127fSDimitry Andric } 1036753f127fSDimitry Andric } 1037753f127fSDimitry Andric 1038bdd1243dSDimitry Andric namespace { 1039bdd1243dSDimitry Andric // Representation of the merged .riscv.attributes input sections. The psABI 1040bdd1243dSDimitry Andric // specifies merge policy for attributes. E.g. if we link an object without an 1041bdd1243dSDimitry Andric // extension with an object with the extension, the output Tag_RISCV_arch shall 1042bdd1243dSDimitry Andric // contain the extension. Some tools like objdump parse .riscv.attributes and 1043bdd1243dSDimitry Andric // disabling some instructions if the first Tag_RISCV_arch does not contain an 1044bdd1243dSDimitry Andric // extension. 1045bdd1243dSDimitry Andric class RISCVAttributesSection final : public SyntheticSection { 1046bdd1243dSDimitry Andric public: 1047bdd1243dSDimitry Andric RISCVAttributesSection() 1048bdd1243dSDimitry Andric : SyntheticSection(0, SHT_RISCV_ATTRIBUTES, 1, ".riscv.attributes") {} 1049bdd1243dSDimitry Andric 1050bdd1243dSDimitry Andric size_t getSize() const override { return size; } 1051bdd1243dSDimitry Andric void writeTo(uint8_t *buf) override; 1052bdd1243dSDimitry Andric 1053bdd1243dSDimitry Andric static constexpr StringRef vendor = "riscv"; 1054bdd1243dSDimitry Andric DenseMap<unsigned, unsigned> intAttr; 1055bdd1243dSDimitry Andric DenseMap<unsigned, StringRef> strAttr; 1056bdd1243dSDimitry Andric size_t size = 0; 1057bdd1243dSDimitry Andric }; 1058bdd1243dSDimitry Andric } // namespace 1059bdd1243dSDimitry Andric 1060bdd1243dSDimitry Andric static void mergeArch(RISCVISAInfo::OrderedExtensionMap &mergedExts, 1061bdd1243dSDimitry Andric unsigned &mergedXlen, const InputSectionBase *sec, 1062bdd1243dSDimitry Andric StringRef s) { 10631ac55f4cSDimitry Andric auto maybeInfo = RISCVISAInfo::parseNormalizedArchString(s); 1064bdd1243dSDimitry Andric if (!maybeInfo) { 1065bdd1243dSDimitry Andric errorOrWarn(toString(sec) + ": " + s + ": " + 1066bdd1243dSDimitry Andric llvm::toString(maybeInfo.takeError())); 1067bdd1243dSDimitry Andric return; 1068bdd1243dSDimitry Andric } 1069bdd1243dSDimitry Andric 1070bdd1243dSDimitry Andric // Merge extensions. 1071bdd1243dSDimitry Andric RISCVISAInfo &info = **maybeInfo; 1072bdd1243dSDimitry Andric if (mergedExts.empty()) { 1073bdd1243dSDimitry Andric mergedExts = info.getExtensions(); 1074bdd1243dSDimitry Andric mergedXlen = info.getXLen(); 1075bdd1243dSDimitry Andric } else { 1076bdd1243dSDimitry Andric for (const auto &ext : info.getExtensions()) { 1077bdd1243dSDimitry Andric if (auto it = mergedExts.find(ext.first); it != mergedExts.end()) { 1078297eecfbSDimitry Andric if (std::tie(it->second.Major, it->second.Minor) >= 1079297eecfbSDimitry Andric std::tie(ext.second.Major, ext.second.Minor)) 1080bdd1243dSDimitry Andric continue; 1081bdd1243dSDimitry Andric } 1082bdd1243dSDimitry Andric mergedExts[ext.first] = ext.second; 1083bdd1243dSDimitry Andric } 1084bdd1243dSDimitry Andric } 1085bdd1243dSDimitry Andric } 1086bdd1243dSDimitry Andric 1087bdd1243dSDimitry Andric static RISCVAttributesSection * 1088bdd1243dSDimitry Andric mergeAttributesSection(const SmallVector<InputSectionBase *, 0> §ions) { 1089bdd1243dSDimitry Andric RISCVISAInfo::OrderedExtensionMap exts; 1090bdd1243dSDimitry Andric const InputSectionBase *firstStackAlign = nullptr; 1091bdd1243dSDimitry Andric unsigned firstStackAlignValue = 0, xlen = 0; 1092bdd1243dSDimitry Andric bool hasArch = false; 1093bdd1243dSDimitry Andric 1094bdd1243dSDimitry Andric in.riscvAttributes = std::make_unique<RISCVAttributesSection>(); 1095bdd1243dSDimitry Andric auto &merged = static_cast<RISCVAttributesSection &>(*in.riscvAttributes); 1096bdd1243dSDimitry Andric 1097bdd1243dSDimitry Andric // Collect all tags values from attributes section. 1098bdd1243dSDimitry Andric const auto &attributesTags = RISCVAttrs::getRISCVAttributeTags(); 1099bdd1243dSDimitry Andric for (const InputSectionBase *sec : sections) { 1100bdd1243dSDimitry Andric RISCVAttributeParser parser; 11015f757f3fSDimitry Andric if (Error e = parser.parse(sec->content(), llvm::endianness::little)) 1102bdd1243dSDimitry Andric warn(toString(sec) + ": " + llvm::toString(std::move(e))); 1103bdd1243dSDimitry Andric for (const auto &tag : attributesTags) { 1104bdd1243dSDimitry Andric switch (RISCVAttrs::AttrType(tag.attr)) { 1105bdd1243dSDimitry Andric // Integer attributes. 1106bdd1243dSDimitry Andric case RISCVAttrs::STACK_ALIGN: 1107bdd1243dSDimitry Andric if (auto i = parser.getAttributeValue(tag.attr)) { 1108bdd1243dSDimitry Andric auto r = merged.intAttr.try_emplace(tag.attr, *i); 1109bdd1243dSDimitry Andric if (r.second) { 1110bdd1243dSDimitry Andric firstStackAlign = sec; 1111bdd1243dSDimitry Andric firstStackAlignValue = *i; 1112bdd1243dSDimitry Andric } else if (r.first->second != *i) { 1113bdd1243dSDimitry Andric errorOrWarn(toString(sec) + " has stack_align=" + Twine(*i) + 1114bdd1243dSDimitry Andric " but " + toString(firstStackAlign) + 1115bdd1243dSDimitry Andric " has stack_align=" + Twine(firstStackAlignValue)); 1116bdd1243dSDimitry Andric } 1117bdd1243dSDimitry Andric } 1118bdd1243dSDimitry Andric continue; 1119bdd1243dSDimitry Andric case RISCVAttrs::UNALIGNED_ACCESS: 1120bdd1243dSDimitry Andric if (auto i = parser.getAttributeValue(tag.attr)) 1121bdd1243dSDimitry Andric merged.intAttr[tag.attr] |= *i; 1122bdd1243dSDimitry Andric continue; 1123bdd1243dSDimitry Andric 1124bdd1243dSDimitry Andric // String attributes. 1125bdd1243dSDimitry Andric case RISCVAttrs::ARCH: 1126bdd1243dSDimitry Andric if (auto s = parser.getAttributeString(tag.attr)) { 1127bdd1243dSDimitry Andric hasArch = true; 1128bdd1243dSDimitry Andric mergeArch(exts, xlen, sec, *s); 1129bdd1243dSDimitry Andric } 1130bdd1243dSDimitry Andric continue; 1131bdd1243dSDimitry Andric 1132bdd1243dSDimitry Andric // Attributes which use the default handling. 1133bdd1243dSDimitry Andric case RISCVAttrs::PRIV_SPEC: 1134bdd1243dSDimitry Andric case RISCVAttrs::PRIV_SPEC_MINOR: 1135bdd1243dSDimitry Andric case RISCVAttrs::PRIV_SPEC_REVISION: 1136bdd1243dSDimitry Andric break; 1137bdd1243dSDimitry Andric } 1138bdd1243dSDimitry Andric 1139bdd1243dSDimitry Andric // Fallback for deprecated priv_spec* and other unknown attributes: retain 1140bdd1243dSDimitry Andric // the attribute if all input sections agree on the value. GNU ld uses 0 1141bdd1243dSDimitry Andric // and empty strings as default values which are not dumped to the output. 1142bdd1243dSDimitry Andric // TODO Adjust after resolution to 1143bdd1243dSDimitry Andric // https://github.com/riscv-non-isa/riscv-elf-psabi-doc/issues/352 1144bdd1243dSDimitry Andric if (tag.attr % 2 == 0) { 1145bdd1243dSDimitry Andric if (auto i = parser.getAttributeValue(tag.attr)) { 1146bdd1243dSDimitry Andric auto r = merged.intAttr.try_emplace(tag.attr, *i); 1147bdd1243dSDimitry Andric if (!r.second && r.first->second != *i) 1148bdd1243dSDimitry Andric r.first->second = 0; 1149bdd1243dSDimitry Andric } 1150bdd1243dSDimitry Andric } else if (auto s = parser.getAttributeString(tag.attr)) { 1151bdd1243dSDimitry Andric auto r = merged.strAttr.try_emplace(tag.attr, *s); 1152bdd1243dSDimitry Andric if (!r.second && r.first->second != *s) 1153bdd1243dSDimitry Andric r.first->second = {}; 1154bdd1243dSDimitry Andric } 1155bdd1243dSDimitry Andric } 1156bdd1243dSDimitry Andric } 1157bdd1243dSDimitry Andric 1158bdd1243dSDimitry Andric if (hasArch) { 1159bdd1243dSDimitry Andric if (auto result = RISCVISAInfo::postProcessAndChecking( 1160bdd1243dSDimitry Andric std::make_unique<RISCVISAInfo>(xlen, exts))) { 1161bdd1243dSDimitry Andric merged.strAttr.try_emplace(RISCVAttrs::ARCH, 1162bdd1243dSDimitry Andric saver().save((*result)->toString())); 1163bdd1243dSDimitry Andric } else { 1164bdd1243dSDimitry Andric errorOrWarn(llvm::toString(result.takeError())); 1165bdd1243dSDimitry Andric } 1166bdd1243dSDimitry Andric } 1167bdd1243dSDimitry Andric 1168bdd1243dSDimitry Andric // The total size of headers: format-version [ <section-length> "vendor-name" 1169bdd1243dSDimitry Andric // [ <file-tag> <size>. 1170bdd1243dSDimitry Andric size_t size = 5 + merged.vendor.size() + 1 + 5; 1171bdd1243dSDimitry Andric for (auto &attr : merged.intAttr) 1172bdd1243dSDimitry Andric if (attr.second != 0) 1173bdd1243dSDimitry Andric size += getULEB128Size(attr.first) + getULEB128Size(attr.second); 1174bdd1243dSDimitry Andric for (auto &attr : merged.strAttr) 1175bdd1243dSDimitry Andric if (!attr.second.empty()) 1176bdd1243dSDimitry Andric size += getULEB128Size(attr.first) + attr.second.size() + 1; 1177bdd1243dSDimitry Andric merged.size = size; 1178bdd1243dSDimitry Andric return &merged; 1179bdd1243dSDimitry Andric } 1180bdd1243dSDimitry Andric 1181bdd1243dSDimitry Andric void RISCVAttributesSection::writeTo(uint8_t *buf) { 1182bdd1243dSDimitry Andric const size_t size = getSize(); 1183bdd1243dSDimitry Andric uint8_t *const end = buf + size; 1184bdd1243dSDimitry Andric *buf = ELFAttrs::Format_Version; 1185bdd1243dSDimitry Andric write32(buf + 1, size - 1); 1186bdd1243dSDimitry Andric buf += 5; 1187bdd1243dSDimitry Andric 1188bdd1243dSDimitry Andric memcpy(buf, vendor.data(), vendor.size()); 1189bdd1243dSDimitry Andric buf += vendor.size() + 1; 1190bdd1243dSDimitry Andric 1191bdd1243dSDimitry Andric *buf = ELFAttrs::File; 1192bdd1243dSDimitry Andric write32(buf + 1, end - buf); 1193bdd1243dSDimitry Andric buf += 5; 1194bdd1243dSDimitry Andric 1195bdd1243dSDimitry Andric for (auto &attr : intAttr) { 1196bdd1243dSDimitry Andric if (attr.second == 0) 1197bdd1243dSDimitry Andric continue; 1198bdd1243dSDimitry Andric buf += encodeULEB128(attr.first, buf); 1199bdd1243dSDimitry Andric buf += encodeULEB128(attr.second, buf); 1200bdd1243dSDimitry Andric } 1201bdd1243dSDimitry Andric for (auto &attr : strAttr) { 1202bdd1243dSDimitry Andric if (attr.second.empty()) 1203bdd1243dSDimitry Andric continue; 1204bdd1243dSDimitry Andric buf += encodeULEB128(attr.first, buf); 1205bdd1243dSDimitry Andric memcpy(buf, attr.second.data(), attr.second.size()); 1206bdd1243dSDimitry Andric buf += attr.second.size() + 1; 1207bdd1243dSDimitry Andric } 1208bdd1243dSDimitry Andric } 1209bdd1243dSDimitry Andric 1210bdd1243dSDimitry Andric void elf::mergeRISCVAttributesSections() { 1211bdd1243dSDimitry Andric // Find the first input SHT_RISCV_ATTRIBUTES; return if not found. 1212bdd1243dSDimitry Andric size_t place = 1213bdd1243dSDimitry Andric llvm::find_if(ctx.inputSections, 1214bdd1243dSDimitry Andric [](auto *s) { return s->type == SHT_RISCV_ATTRIBUTES; }) - 1215bdd1243dSDimitry Andric ctx.inputSections.begin(); 1216bdd1243dSDimitry Andric if (place == ctx.inputSections.size()) 1217bdd1243dSDimitry Andric return; 1218bdd1243dSDimitry Andric 1219bdd1243dSDimitry Andric // Extract all SHT_RISCV_ATTRIBUTES sections into `sections`. 1220bdd1243dSDimitry Andric SmallVector<InputSectionBase *, 0> sections; 1221bdd1243dSDimitry Andric llvm::erase_if(ctx.inputSections, [&](InputSectionBase *s) { 1222bdd1243dSDimitry Andric if (s->type != SHT_RISCV_ATTRIBUTES) 1223bdd1243dSDimitry Andric return false; 1224bdd1243dSDimitry Andric sections.push_back(s); 1225bdd1243dSDimitry Andric return true; 1226bdd1243dSDimitry Andric }); 1227bdd1243dSDimitry Andric 1228bdd1243dSDimitry Andric // Add the merged section. 1229bdd1243dSDimitry Andric ctx.inputSections.insert(ctx.inputSections.begin() + place, 1230bdd1243dSDimitry Andric mergeAttributesSection(sections)); 1231bdd1243dSDimitry Andric } 1232bdd1243dSDimitry Andric 12335ffd83dbSDimitry Andric TargetInfo *elf::getRISCVTargetInfo() { 12340b57cec5SDimitry Andric static RISCV target; 12350b57cec5SDimitry Andric return ⌖ 12360b57cec5SDimitry Andric } 1237