Skip to content
This repository was archived by the owner on Feb 5, 2019. It is now read-only.

Commit 813b3b9

Browse files
authored
Merge pull request #1 from danc86/riscv
Support RISC-V
2 parents f76ea3c + 0d6ab7d commit 813b3b9

19 files changed

Lines changed: 1013 additions & 1 deletion

ELF/Arch/RISCV.cpp

Lines changed: 277 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,277 @@
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+
}

ELF/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ add_lld_library(lldELF
1717
Arch/MipsArchTree.cpp
1818
Arch/PPC.cpp
1919
Arch/PPC64.cpp
20+
Arch/RISCV.cpp
2021
Arch/SPARCV9.cpp
2122
Arch/X86.cpp
2223
Arch/X86_64.cpp

ELF/Driver.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,9 +125,11 @@ static std::tuple<ELFKind, uint16_t, uint8_t> parseEmulation(StringRef Emul) {
125125
.Case("elf32_x86_64", {ELF32LEKind, EM_X86_64})
126126
.Cases("elf32btsmip", "elf32btsmipn32", {ELF32BEKind, EM_MIPS})
127127
.Cases("elf32ltsmip", "elf32ltsmipn32", {ELF32LEKind, EM_MIPS})
128+
.Case("elf32lriscv", {ELF32LEKind, EM_RISCV})
128129
.Case("elf32ppc", {ELF32BEKind, EM_PPC})
129130
.Case("elf64btsmip", {ELF64BEKind, EM_MIPS})
130131
.Case("elf64ltsmip", {ELF64LEKind, EM_MIPS})
132+
.Case("elf64lriscv", {ELF64LEKind, EM_RISCV})
131133
.Case("elf64ppc", {ELF64BEKind, EM_PPC64})
132134
.Case("elf64lppc", {ELF64LEKind, EM_PPC64})
133135
.Cases("elf_amd64", "elf_x86_64", {ELF64LEKind, EM_X86_64})
@@ -994,7 +996,8 @@ static void setConfigs(opt::InputArgList &Args) {
994996
// ABI defines which one you need to use. The following expression expresses
995997
// that.
996998
Config->IsRela =
997-
(Config->Is64 || IsX32 || Machine == EM_PPC) && Machine != EM_MIPS;
999+
(Config->Is64 || IsX32 || Machine == EM_PPC || Machine == EM_RISCV) &&
1000+
Machine != EM_MIPS;
9981001

9991002
// If the output uses REL relocations we must store the dynamic relocation
10001003
// addends to the output sections. We also store addends for RELA relocations

ELF/InputSection.cpp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -487,6 +487,33 @@ static uint64_t getARMStaticBase(const Symbol &Sym) {
487487
return OS->PtLoad->FirstSec->Addr;
488488
}
489489

490+
// For R_RISCV_PC_INDIRECT (R_RISCV_PCREL_LO12_{I,S}), the symbol actually
491+
// points the corresponding R_RISCV_PCREL_HI20 relocation, and the target VA
492+
// is calculated using PCREL_HI20's symbol.
493+
//
494+
// This function returns the R_RISCV_PCREL_HI20 relocation from
495+
// R_RISCV_PCREL_LO12's symbol and addend.
496+
Relocation *lld::elf::getRISCVPCRelHi20(const Symbol *Sym, uint64_t Addend) {
497+
const Defined *D = cast<Defined>(Sym);
498+
InputSection *IS = cast<InputSection>(D->Section);
499+
500+
if (Addend != 0)
501+
warn("Non-zero addend in R_RISCV_PCREL_LO12 relocation to " +
502+
IS->getObjMsg(D->Value) + " is ignored");
503+
504+
// Relocations are sorted by offset, so we can use std::equal_range to do
505+
// binary search.
506+
auto Range = std::equal_range(IS->Relocations.begin(), IS->Relocations.end(),
507+
D->Value, RelocationOffsetComparator{});
508+
for (auto It = std::get<0>(Range); It != std::get<1>(Range); ++It)
509+
if (isRelExprOneOf<R_PC>(It->Expr))
510+
return &*It;
511+
512+
error("R_RISCV_PCREL_LO12 relocation points to " + IS->getObjMsg(D->Value) +
513+
" without an associated R_RISCV_PCREL_HI20 relocation");
514+
return nullptr;
515+
}
516+
490517
static uint64_t getRelocTargetVA(const InputFile *File, RelType Type, int64_t A,
491518
uint64_t P, const Symbol &Sym, RelExpr Expr) {
492519
switch (Expr) {
@@ -578,6 +605,13 @@ static uint64_t getRelocTargetVA(const InputFile *File, RelType Type, int64_t A,
578605
Dest = getAArch64Page(Sym.getVA(A));
579606
return Dest - getAArch64Page(P);
580607
}
608+
case R_RISCV_PC_INDIRECT: {
609+
const Relocation *HiRel = getRISCVPCRelHi20(&Sym, A);
610+
if (!HiRel)
611+
return 0;
612+
return getRelocTargetVA(File, HiRel->Type, HiRel->Addend, Sym.getVA(),
613+
*HiRel->Sym, HiRel->Expr);
614+
}
581615
case R_PC: {
582616
uint64_t Dest;
583617
if (Sym.isUndefWeak()) {

ELF/InputSection.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,8 @@ class InputSection : public InputSectionBase {
353353

354354
// The list of all input sections.
355355
extern std::vector<InputSectionBase *> InputSections;
356+
357+
Relocation *getRISCVPCRelHi20(const Symbol *Sym, const uint64_t Addend);
356358
} // namespace elf
357359

358360
std::string toString(const elf::InputSectionBase *);

ELF/Relocations.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1047,6 +1047,11 @@ static void scanRelocs(InputSectionBase &Sec, ArrayRef<RelTy> Rels) {
10471047

10481048
for (auto I = Rels.begin(), End = Rels.end(); I != End;)
10491049
scanReloc<ELFT>(Sec, GetOffset, I, End);
1050+
1051+
// Sort relocations by offset to binary search for R_RISCV_PCREL_HI20
1052+
if (Config->EMachine == EM_RISCV)
1053+
std::stable_sort(Sec.Relocations.begin(), Sec.Relocations.end(),
1054+
RelocationOffsetComparator{});
10501055
}
10511056

10521057
template <class ELFT> void elf::scanRelocations(InputSectionBase &S) {

0 commit comments

Comments
 (0)