|
| 1 | +//===- RISCV.cpp ----------------------------------------------------------===// |
| 2 | +// |
| 3 | +// The LLVM Linker |
| 4 | +// |
| 5 | +// This file is distributed under the University of Illinois Open Source |
| 6 | +// License. See LICENSE.TXT for details. |
| 7 | +// |
| 8 | +//===----------------------------------------------------------------------===// |
| 9 | + |
| 10 | +#include "InputFiles.h" |
| 11 | +#include "Target.h" |
| 12 | + |
| 13 | +using namespace llvm; |
| 14 | +using namespace llvm::object; |
| 15 | +using namespace llvm::support::endian; |
| 16 | +using namespace llvm::ELF; |
| 17 | +using namespace lld; |
| 18 | +using namespace lld::elf; |
| 19 | + |
| 20 | +namespace { |
| 21 | + |
| 22 | +class RISCV final : public TargetInfo { |
| 23 | +public: |
| 24 | + virtual uint32_t calcEFlags() const override; |
| 25 | + RelExpr getRelExpr(RelType Type, const Symbol &S, |
| 26 | + const uint8_t *Loc) const override; |
| 27 | + void relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const override; |
| 28 | +}; |
| 29 | + |
| 30 | +} // end anonymous namespace |
| 31 | + |
| 32 | +static uint32_t getEFlags(InputFile *F) { |
| 33 | + if (Config->Is64) |
| 34 | + return cast<ObjFile<ELF64LE>>(F)->getObj().getHeader()->e_flags; |
| 35 | + else |
| 36 | + return cast<ObjFile<ELF32LE>>(F)->getObj().getHeader()->e_flags; |
| 37 | +} |
| 38 | + |
| 39 | +uint32_t RISCV::calcEFlags() const { |
| 40 | + assert(!ObjectFiles.empty()); |
| 41 | + |
| 42 | + uint32_t Target = getEFlags(ObjectFiles.front()); |
| 43 | + |
| 44 | + for (InputFile *F : ObjectFiles) { |
| 45 | + uint32_t EFlags = getEFlags(F); |
| 46 | + if (EFlags & EF_RISCV_RVC) |
| 47 | + Target |= EF_RISCV_RVC; |
| 48 | + |
| 49 | + if ((EFlags & EF_RISCV_FLOAT_ABI) != (Target & EF_RISCV_FLOAT_ABI)) |
| 50 | + error(toString(F) + |
| 51 | + ": cannot link object files with different floating-point ABI"); |
| 52 | + |
| 53 | + if ((EFlags & EF_RISCV_RVE) != (Target & EF_RISCV_RVE)) |
| 54 | + error(toString(F) + |
| 55 | + ": cannot link object files with different EF_RISCV_RVE"); |
| 56 | + } |
| 57 | + |
| 58 | + return Target; |
| 59 | +} |
| 60 | + |
| 61 | +RelExpr RISCV::getRelExpr(const RelType Type, const Symbol &S, |
| 62 | + const uint8_t *Loc) const { |
| 63 | + switch (Type) { |
| 64 | + case R_RISCV_JAL: |
| 65 | + case R_RISCV_BRANCH: |
| 66 | + case R_RISCV_CALL: |
| 67 | + case R_RISCV_PCREL_HI20: |
| 68 | + case R_RISCV_RVC_BRANCH: |
| 69 | + case R_RISCV_RVC_JUMP: |
| 70 | + case R_RISCV_32_PCREL: |
| 71 | + return R_PC; |
| 72 | + case R_RISCV_PCREL_LO12_I: |
| 73 | + case R_RISCV_PCREL_LO12_S: |
| 74 | + return R_RISCV_PC_INDIRECT; |
| 75 | + case R_RISCV_RELAX: |
| 76 | + case R_RISCV_ALIGN: |
| 77 | + return R_HINT; |
| 78 | + default: |
| 79 | + return R_ABS; |
| 80 | + } |
| 81 | +} |
| 82 | + |
| 83 | +// Extract bits V[Begin:End], where range is inclusive, and Begin must be < 63. |
| 84 | +static uint32_t extractBits(uint64_t V, uint32_t Begin, uint32_t End) { |
| 85 | + return (V & ((1ULL << (Begin + 1)) - 1)) >> End; |
| 86 | +} |
| 87 | + |
| 88 | +void RISCV::relocateOne(uint8_t *Loc, const RelType Type, |
| 89 | + const uint64_t Val) const { |
| 90 | + switch (Type) { |
| 91 | + case R_RISCV_32: |
| 92 | + write32le(Loc, Val); |
| 93 | + return; |
| 94 | + case R_RISCV_64: |
| 95 | + write64le(Loc, Val); |
| 96 | + return; |
| 97 | + |
| 98 | + case R_RISCV_RVC_BRANCH: { |
| 99 | + checkInt(Loc, static_cast<int64_t>(Val) >> 1, 8, Type); |
| 100 | + checkAlignment(Loc, Val, 2, Type); |
| 101 | + uint16_t Insn = read16le(Loc) & 0xE383; |
| 102 | + uint16_t Imm8 = extractBits(Val, 8, 8) << 12; |
| 103 | + uint16_t Imm4_3 = extractBits(Val, 4, 3) << 10; |
| 104 | + uint16_t Imm7_6 = extractBits(Val, 7, 6) << 5; |
| 105 | + uint16_t Imm2_1 = extractBits(Val, 2, 1) << 3; |
| 106 | + uint16_t Imm5 = extractBits(Val, 5, 5) << 2; |
| 107 | + Insn |= Imm8 | Imm4_3 | Imm7_6 | Imm2_1 | Imm5; |
| 108 | + |
| 109 | + write16le(Loc, Insn); |
| 110 | + return; |
| 111 | + } |
| 112 | + |
| 113 | + case R_RISCV_RVC_JUMP: { |
| 114 | + checkInt(Loc, static_cast<int64_t>(Val) >> 1, 11, Type); |
| 115 | + checkAlignment(Loc, Val, 2, Type); |
| 116 | + uint16_t Insn = read16le(Loc) & 0xE003; |
| 117 | + uint16_t Imm11 = extractBits(Val, 11, 11) << 12; |
| 118 | + uint16_t Imm4 = extractBits(Val, 4, 4) << 11; |
| 119 | + uint16_t Imm9_8 = extractBits(Val, 9, 8) << 9; |
| 120 | + uint16_t Imm10 = extractBits(Val, 10, 10) << 8; |
| 121 | + uint16_t Imm6 = extractBits(Val, 6, 6) << 7; |
| 122 | + uint16_t Imm7 = extractBits(Val, 7, 7) << 6; |
| 123 | + uint16_t Imm3_1 = extractBits(Val, 3, 1) << 3; |
| 124 | + uint16_t Imm5 = extractBits(Val, 5, 5) << 2; |
| 125 | + Insn |= Imm11 | Imm4 | Imm9_8 | Imm10 | Imm6 | Imm7 | Imm3_1 | Imm5; |
| 126 | + |
| 127 | + write16le(Loc, Insn); |
| 128 | + return; |
| 129 | + } |
| 130 | + |
| 131 | + case R_RISCV_RVC_LUI: { |
| 132 | + int32_t Imm = ((Val + 0x800) >> 12); |
| 133 | + checkUInt(Loc, Imm, 6, Type); |
| 134 | + if (Imm == 0) { // `c.lui rd, 0` is illegal, convert to `c.li rd, 0` |
| 135 | + write16le(Loc, (read16le(Loc) & 0x0F83) | 0x4000); |
| 136 | + } else { |
| 137 | + uint16_t Imm17 = extractBits(Val + 0x800, 17, 17) << 12; |
| 138 | + uint16_t Imm16_12 = extractBits(Val + 0x800, 16, 12) << 2; |
| 139 | + write16le(Loc, (read16le(Loc) & 0xEF83) | Imm17 | Imm16_12); |
| 140 | + } |
| 141 | + return; |
| 142 | + } |
| 143 | + |
| 144 | + case R_RISCV_JAL: { |
| 145 | + checkInt(Loc, static_cast<int64_t>(Val) >> 1, 20, Type); |
| 146 | + checkAlignment(Loc, Val, 2, Type); |
| 147 | + |
| 148 | + uint32_t Insn = read32le(Loc) & 0xFFF; |
| 149 | + uint32_t Imm20 = extractBits(Val, 20, 20) << 31; |
| 150 | + uint32_t Imm10_1 = extractBits(Val, 10, 1) << 21; |
| 151 | + uint32_t Imm11 = extractBits(Val, 11, 11) << 20; |
| 152 | + uint32_t Imm19_12 = extractBits(Val, 19, 12) << 12; |
| 153 | + Insn |= Imm20 | Imm10_1 | Imm11 | Imm19_12; |
| 154 | + |
| 155 | + write32le(Loc, Insn); |
| 156 | + return; |
| 157 | + } |
| 158 | + |
| 159 | + case R_RISCV_BRANCH: { |
| 160 | + checkInt(Loc, static_cast<int64_t>(Val) >> 1, 12, Type); |
| 161 | + checkAlignment(Loc, Val, 2, Type); |
| 162 | + |
| 163 | + uint32_t Insn = read32le(Loc) & 0x1FFF07F; |
| 164 | + uint32_t Imm12 = extractBits(Val, 12, 12) << 31; |
| 165 | + uint32_t Imm10_5 = extractBits(Val, 10, 5) << 25; |
| 166 | + uint32_t Imm4_1 = extractBits(Val, 4, 1) << 8; |
| 167 | + uint32_t Imm11 = extractBits(Val, 11, 11) << 7; |
| 168 | + Insn |= Imm12 | Imm10_5 | Imm4_1 | Imm11; |
| 169 | + |
| 170 | + write32le(Loc, Insn); |
| 171 | + return; |
| 172 | + } |
| 173 | + |
| 174 | + // auipc + jalr pair |
| 175 | + case R_RISCV_CALL: { |
| 176 | + checkInt(Loc, Val, 32, Type); |
| 177 | + if (isInt<32>(Val)) { |
| 178 | + relocateOne(Loc, R_RISCV_PCREL_HI20, Val); |
| 179 | + relocateOne(Loc + 4, R_RISCV_PCREL_LO12_I, Val); |
| 180 | + } |
| 181 | + return; |
| 182 | + } |
| 183 | + |
| 184 | + case R_RISCV_PCREL_HI20: |
| 185 | + case R_RISCV_HI20: { |
| 186 | + checkInt(Loc, Val, 32, Type); |
| 187 | + uint32_t Hi = Val + 0x800; |
| 188 | + write32le(Loc, (read32le(Loc) & 0xFFF) | (Hi & 0xFFFFF000)); |
| 189 | + return; |
| 190 | + } |
| 191 | + |
| 192 | + case R_RISCV_PCREL_LO12_I: |
| 193 | + case R_RISCV_LO12_I: { |
| 194 | + checkInt(Loc, Val, 32, Type); |
| 195 | + uint32_t Hi = Val + 0x800; |
| 196 | + uint32_t Lo = Val - (Hi & 0xFFFFF000); |
| 197 | + write32le(Loc, (read32le(Loc) & 0xFFFFF) | ((Lo & 0xFFF) << 20)); |
| 198 | + return; |
| 199 | + } |
| 200 | + |
| 201 | + case R_RISCV_PCREL_LO12_S: |
| 202 | + case R_RISCV_LO12_S: { |
| 203 | + checkInt(Loc, Val, 32, Type); |
| 204 | + uint32_t Hi = Val + 0x800; |
| 205 | + uint32_t Lo = Val - (Hi & 0xFFFFF000); |
| 206 | + uint32_t Imm11_5 = extractBits(Lo, 11, 5) << 25; |
| 207 | + uint32_t Imm4_0 = extractBits(Lo, 4, 0) << 7; |
| 208 | + write32le(Loc, (read32le(Loc) & 0x1FFF07F) | Imm11_5 | Imm4_0); |
| 209 | + return; |
| 210 | + } |
| 211 | + |
| 212 | + case R_RISCV_ADD8: |
| 213 | + *Loc += Val; |
| 214 | + return; |
| 215 | + case R_RISCV_ADD16: |
| 216 | + write16le(Loc, read16le(Loc) + Val); |
| 217 | + return; |
| 218 | + case R_RISCV_ADD32: |
| 219 | + write32le(Loc, read32le(Loc) + Val); |
| 220 | + return; |
| 221 | + case R_RISCV_ADD64: |
| 222 | + write64le(Loc, read64le(Loc) + Val); |
| 223 | + return; |
| 224 | + case R_RISCV_SUB6: |
| 225 | + *Loc = (*Loc & 0xc0) | (((*Loc & 0x3f) - Val) & 0x3f); |
| 226 | + return; |
| 227 | + case R_RISCV_SUB8: |
| 228 | + *Loc -= Val; |
| 229 | + return; |
| 230 | + case R_RISCV_SUB16: |
| 231 | + write16le(Loc, read16le(Loc) - Val); |
| 232 | + return; |
| 233 | + case R_RISCV_SUB32: |
| 234 | + write32le(Loc, read32le(Loc) - Val); |
| 235 | + return; |
| 236 | + case R_RISCV_SUB64: |
| 237 | + write64le(Loc, read64le(Loc) - Val); |
| 238 | + return; |
| 239 | + case R_RISCV_SET6: |
| 240 | + *Loc = (*Loc & 0xc0) | (Val & 0x3f); |
| 241 | + return; |
| 242 | + case R_RISCV_SET8: |
| 243 | + *Loc = Val; |
| 244 | + return; |
| 245 | + case R_RISCV_SET16: |
| 246 | + write16le(Loc, Val); |
| 247 | + return; |
| 248 | + case R_RISCV_SET32: |
| 249 | + case R_RISCV_32_PCREL: |
| 250 | + write32le(Loc, Val); |
| 251 | + return; |
| 252 | + |
| 253 | + case R_RISCV_ALIGN: |
| 254 | + case R_RISCV_RELAX: |
| 255 | + return; // Ignored (for now) |
| 256 | + case R_RISCV_NONE: |
| 257 | + return; // Do nothing |
| 258 | + |
| 259 | + // These are handled by the dynamic linker |
| 260 | + case R_RISCV_RELATIVE: |
| 261 | + case R_RISCV_COPY: |
| 262 | + case R_RISCV_JUMP_SLOT: |
| 263 | + // GP-relative relocations are only produced after relaxation, which |
| 264 | + // we don't support for now |
| 265 | + case R_RISCV_GPREL_I: |
| 266 | + case R_RISCV_GPREL_S: |
| 267 | + default: |
| 268 | + error(getErrorLocation(Loc) + |
| 269 | + "unimplemented relocation: " + toString(Type)); |
| 270 | + return; |
| 271 | + } |
| 272 | +} |
| 273 | + |
| 274 | +TargetInfo *elf::getRISCVTargetInfo() { |
| 275 | + static RISCV Target; |
| 276 | + return &Target; |
| 277 | +} |
0 commit comments