1ece8a530Spatrick //===- RISCV.cpp ----------------------------------------------------------===//
2ece8a530Spatrick //
3ece8a530Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4ece8a530Spatrick // See https://llvm.org/LICENSE.txt for license information.
5ece8a530Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6ece8a530Spatrick //
7ece8a530Spatrick //===----------------------------------------------------------------------===//
8ece8a530Spatrick
9ece8a530Spatrick #include "InputFiles.h"
1005edf1c1Srobert #include "OutputSections.h"
11ece8a530Spatrick #include "Symbols.h"
12ece8a530Spatrick #include "SyntheticSections.h"
13ece8a530Spatrick #include "Target.h"
1405edf1c1Srobert #include "llvm/Support/ELFAttributes.h"
1505edf1c1Srobert #include "llvm/Support/LEB128.h"
1605edf1c1Srobert #include "llvm/Support/RISCVAttributeParser.h"
1705edf1c1Srobert #include "llvm/Support/RISCVAttributes.h"
1805edf1c1Srobert #include "llvm/Support/RISCVISAInfo.h"
1905edf1c1Srobert #include "llvm/Support/TimeProfiler.h"
20ece8a530Spatrick
21ece8a530Spatrick using namespace llvm;
22ece8a530Spatrick using namespace llvm::object;
23ece8a530Spatrick using namespace llvm::support::endian;
24ece8a530Spatrick using namespace llvm::ELF;
25bb684c34Spatrick using namespace lld;
26bb684c34Spatrick using namespace lld::elf;
27ece8a530Spatrick
28ece8a530Spatrick namespace {
29ece8a530Spatrick
30ece8a530Spatrick class RISCV final : public TargetInfo {
31ece8a530Spatrick public:
32ece8a530Spatrick RISCV();
33ece8a530Spatrick uint32_t calcEFlags() const override;
341cf9926bSpatrick int64_t getImplicitAddend(const uint8_t *buf, RelType type) const override;
35ece8a530Spatrick void writeGotHeader(uint8_t *buf) const override;
36ece8a530Spatrick void writeGotPlt(uint8_t *buf, const Symbol &s) const override;
371cf9926bSpatrick void writeIgotPlt(uint8_t *buf, const Symbol &s) const override;
38ece8a530Spatrick void writePltHeader(uint8_t *buf) const override;
39ece8a530Spatrick void writePlt(uint8_t *buf, const Symbol &sym,
40ece8a530Spatrick uint64_t pltEntryAddr) const override;
41ece8a530Spatrick RelType getDynRel(RelType type) const override;
42ece8a530Spatrick RelExpr getRelExpr(RelType type, const Symbol &s,
43ece8a530Spatrick const uint8_t *loc) const override;
44bb684c34Spatrick void relocate(uint8_t *loc, const Relocation &rel,
45bb684c34Spatrick uint64_t val) const override;
4605edf1c1Srobert bool relaxOnce(int pass) const override;
47ece8a530Spatrick };
48ece8a530Spatrick
49ece8a530Spatrick } // end anonymous namespace
50ece8a530Spatrick
51ece8a530Spatrick const uint64_t dtpOffset = 0x800;
52ece8a530Spatrick
53ece8a530Spatrick enum Op {
54ece8a530Spatrick ADDI = 0x13,
55ece8a530Spatrick AUIPC = 0x17,
56ece8a530Spatrick JALR = 0x67,
57ece8a530Spatrick LD = 0x3003,
58ece8a530Spatrick LW = 0x2003,
59ece8a530Spatrick SRLI = 0x5013,
60ece8a530Spatrick SUB = 0x40000033,
61ece8a530Spatrick };
62ece8a530Spatrick
63ece8a530Spatrick enum Reg {
64ece8a530Spatrick X_RA = 1,
6505edf1c1Srobert X_TP = 4,
66ece8a530Spatrick X_T0 = 5,
67ece8a530Spatrick X_T1 = 6,
68ece8a530Spatrick X_T2 = 7,
69ece8a530Spatrick X_T3 = 28,
70ece8a530Spatrick };
71ece8a530Spatrick
hi20(uint32_t val)72ece8a530Spatrick static uint32_t hi20(uint32_t val) { return (val + 0x800) >> 12; }
lo12(uint32_t val)73ece8a530Spatrick static uint32_t lo12(uint32_t val) { return val & 4095; }
74ece8a530Spatrick
itype(uint32_t op,uint32_t rd,uint32_t rs1,uint32_t imm)75ece8a530Spatrick static uint32_t itype(uint32_t op, uint32_t rd, uint32_t rs1, uint32_t imm) {
76ece8a530Spatrick return op | (rd << 7) | (rs1 << 15) | (imm << 20);
77ece8a530Spatrick }
rtype(uint32_t op,uint32_t rd,uint32_t rs1,uint32_t rs2)78ece8a530Spatrick static uint32_t rtype(uint32_t op, uint32_t rd, uint32_t rs1, uint32_t rs2) {
79ece8a530Spatrick return op | (rd << 7) | (rs1 << 15) | (rs2 << 20);
80ece8a530Spatrick }
utype(uint32_t op,uint32_t rd,uint32_t imm)81ece8a530Spatrick static uint32_t utype(uint32_t op, uint32_t rd, uint32_t imm) {
82ece8a530Spatrick return op | (rd << 7) | (imm << 12);
83ece8a530Spatrick }
84ece8a530Spatrick
8505edf1c1Srobert // Extract bits v[begin:end], where range is inclusive, and begin must be < 63.
extractBits(uint64_t v,uint32_t begin,uint32_t end)8605edf1c1Srobert static uint32_t extractBits(uint64_t v, uint32_t begin, uint32_t end) {
8705edf1c1Srobert return (v & ((1ULL << (begin + 1)) - 1)) >> end;
8805edf1c1Srobert }
8905edf1c1Srobert
setLO12_I(uint32_t insn,uint32_t imm)9005edf1c1Srobert static uint32_t setLO12_I(uint32_t insn, uint32_t imm) {
9105edf1c1Srobert return (insn & 0xfffff) | (imm << 20);
9205edf1c1Srobert }
setLO12_S(uint32_t insn,uint32_t imm)9305edf1c1Srobert static uint32_t setLO12_S(uint32_t insn, uint32_t imm) {
9405edf1c1Srobert return (insn & 0x1fff07f) | (extractBits(imm, 11, 5) << 25) |
9505edf1c1Srobert (extractBits(imm, 4, 0) << 7);
9605edf1c1Srobert }
9705edf1c1Srobert
RISCV()98ece8a530Spatrick RISCV::RISCV() {
99ece8a530Spatrick copyRel = R_RISCV_COPY;
100ece8a530Spatrick pltRel = R_RISCV_JUMP_SLOT;
101ece8a530Spatrick relativeRel = R_RISCV_RELATIVE;
102bb684c34Spatrick iRelativeRel = R_RISCV_IRELATIVE;
103ece8a530Spatrick if (config->is64) {
104ece8a530Spatrick symbolicRel = R_RISCV_64;
105ece8a530Spatrick tlsModuleIndexRel = R_RISCV_TLS_DTPMOD64;
106ece8a530Spatrick tlsOffsetRel = R_RISCV_TLS_DTPREL64;
107ece8a530Spatrick tlsGotRel = R_RISCV_TLS_TPREL64;
108ece8a530Spatrick } else {
109ece8a530Spatrick symbolicRel = R_RISCV_32;
110ece8a530Spatrick tlsModuleIndexRel = R_RISCV_TLS_DTPMOD32;
111ece8a530Spatrick tlsOffsetRel = R_RISCV_TLS_DTPREL32;
112ece8a530Spatrick tlsGotRel = R_RISCV_TLS_TPREL32;
113ece8a530Spatrick }
114ece8a530Spatrick gotRel = symbolicRel;
115ece8a530Spatrick
116ece8a530Spatrick // .got[0] = _DYNAMIC
117ece8a530Spatrick gotHeaderEntriesNum = 1;
118ece8a530Spatrick
119ece8a530Spatrick // .got.plt[0] = _dl_runtime_resolve, .got.plt[1] = link_map
120ece8a530Spatrick gotPltHeaderEntriesNum = 2;
121ece8a530Spatrick
122ece8a530Spatrick pltHeaderSize = 32;
123ece8a530Spatrick pltEntrySize = 16;
124ece8a530Spatrick ipltEntrySize = 16;
125ece8a530Spatrick }
126ece8a530Spatrick
getEFlags(InputFile * f)127ece8a530Spatrick static uint32_t getEFlags(InputFile *f) {
128ece8a530Spatrick if (config->is64)
1291cf9926bSpatrick return cast<ObjFile<ELF64LE>>(f)->getObj().getHeader().e_flags;
1301cf9926bSpatrick return cast<ObjFile<ELF32LE>>(f)->getObj().getHeader().e_flags;
131ece8a530Spatrick }
132ece8a530Spatrick
calcEFlags() const133ece8a530Spatrick uint32_t RISCV::calcEFlags() const {
134ece8a530Spatrick // If there are only binary input files (from -b binary), use a
135ece8a530Spatrick // value of 0 for the ELF header flags.
13605edf1c1Srobert if (ctx.objectFiles.empty())
137ece8a530Spatrick return 0;
138ece8a530Spatrick
13905edf1c1Srobert uint32_t target = getEFlags(ctx.objectFiles.front());
140ece8a530Spatrick
14105edf1c1Srobert for (InputFile *f : ctx.objectFiles) {
142ece8a530Spatrick uint32_t eflags = getEFlags(f);
143ece8a530Spatrick if (eflags & EF_RISCV_RVC)
144ece8a530Spatrick target |= EF_RISCV_RVC;
145ece8a530Spatrick
146ece8a530Spatrick if ((eflags & EF_RISCV_FLOAT_ABI) != (target & EF_RISCV_FLOAT_ABI))
1477474b486Sjca warn(
14805edf1c1Srobert toString(f) +
14905edf1c1Srobert ": cannot link object files with different floating-point ABI from " +
15005edf1c1Srobert toString(ctx.objectFiles[0]));
151ece8a530Spatrick
152ece8a530Spatrick if ((eflags & EF_RISCV_RVE) != (target & EF_RISCV_RVE))
153ece8a530Spatrick error(toString(f) +
154ece8a530Spatrick ": cannot link object files with different EF_RISCV_RVE");
155ece8a530Spatrick }
156ece8a530Spatrick
157ece8a530Spatrick return target;
158ece8a530Spatrick }
159ece8a530Spatrick
getImplicitAddend(const uint8_t * buf,RelType type) const1601cf9926bSpatrick int64_t RISCV::getImplicitAddend(const uint8_t *buf, RelType type) const {
1611cf9926bSpatrick switch (type) {
1621cf9926bSpatrick default:
1631cf9926bSpatrick internalLinkerError(getErrorLocation(buf),
1641cf9926bSpatrick "cannot read addend for relocation " + toString(type));
1651cf9926bSpatrick return 0;
1661cf9926bSpatrick case R_RISCV_32:
1671cf9926bSpatrick case R_RISCV_TLS_DTPMOD32:
1681cf9926bSpatrick case R_RISCV_TLS_DTPREL32:
16905edf1c1Srobert case R_RISCV_TLS_TPREL32:
1701cf9926bSpatrick return SignExtend64<32>(read32le(buf));
1711cf9926bSpatrick case R_RISCV_64:
17205edf1c1Srobert case R_RISCV_TLS_DTPMOD64:
17305edf1c1Srobert case R_RISCV_TLS_DTPREL64:
17405edf1c1Srobert case R_RISCV_TLS_TPREL64:
1751cf9926bSpatrick return read64le(buf);
1761cf9926bSpatrick case R_RISCV_RELATIVE:
1771cf9926bSpatrick case R_RISCV_IRELATIVE:
1781cf9926bSpatrick return config->is64 ? read64le(buf) : read32le(buf);
1791cf9926bSpatrick case R_RISCV_NONE:
1801cf9926bSpatrick case R_RISCV_JUMP_SLOT:
1811cf9926bSpatrick // These relocations are defined as not having an implicit addend.
1821cf9926bSpatrick return 0;
1831cf9926bSpatrick }
1841cf9926bSpatrick }
1851cf9926bSpatrick
writeGotHeader(uint8_t * buf) const186ece8a530Spatrick void RISCV::writeGotHeader(uint8_t *buf) const {
187ece8a530Spatrick if (config->is64)
188ece8a530Spatrick write64le(buf, mainPart->dynamic->getVA());
189ece8a530Spatrick else
190ece8a530Spatrick write32le(buf, mainPart->dynamic->getVA());
191ece8a530Spatrick }
192ece8a530Spatrick
writeGotPlt(uint8_t * buf,const Symbol & s) const193ece8a530Spatrick void RISCV::writeGotPlt(uint8_t *buf, const Symbol &s) const {
194ece8a530Spatrick if (config->is64)
195ece8a530Spatrick write64le(buf, in.plt->getVA());
196ece8a530Spatrick else
197ece8a530Spatrick write32le(buf, in.plt->getVA());
198ece8a530Spatrick }
199ece8a530Spatrick
writeIgotPlt(uint8_t * buf,const Symbol & s) const2001cf9926bSpatrick void RISCV::writeIgotPlt(uint8_t *buf, const Symbol &s) const {
2011cf9926bSpatrick if (config->writeAddends) {
2021cf9926bSpatrick if (config->is64)
2031cf9926bSpatrick write64le(buf, s.getVA());
2041cf9926bSpatrick else
2051cf9926bSpatrick write32le(buf, s.getVA());
2061cf9926bSpatrick }
2071cf9926bSpatrick }
2081cf9926bSpatrick
writePltHeader(uint8_t * buf) const209ece8a530Spatrick void RISCV::writePltHeader(uint8_t *buf) const {
210ece8a530Spatrick // 1: auipc t2, %pcrel_hi(.got.plt)
211ece8a530Spatrick // sub t1, t1, t3
212ece8a530Spatrick // l[wd] t3, %pcrel_lo(1b)(t2); t3 = _dl_runtime_resolve
213ece8a530Spatrick // addi t1, t1, -pltHeaderSize-12; t1 = &.plt[i] - &.plt[0]
214ece8a530Spatrick // addi t0, t2, %pcrel_lo(1b)
215ece8a530Spatrick // srli t1, t1, (rv64?1:2); t1 = &.got.plt[i] - &.got.plt[0]
216ece8a530Spatrick // l[wd] t0, Wordsize(t0); t0 = link_map
217ece8a530Spatrick // jr t3
218ece8a530Spatrick uint32_t offset = in.gotPlt->getVA() - in.plt->getVA();
219ece8a530Spatrick uint32_t load = config->is64 ? LD : LW;
220ece8a530Spatrick write32le(buf + 0, utype(AUIPC, X_T2, hi20(offset)));
221ece8a530Spatrick write32le(buf + 4, rtype(SUB, X_T1, X_T1, X_T3));
222ece8a530Spatrick write32le(buf + 8, itype(load, X_T3, X_T2, lo12(offset)));
223ece8a530Spatrick write32le(buf + 12, itype(ADDI, X_T1, X_T1, -target->pltHeaderSize - 12));
224ece8a530Spatrick write32le(buf + 16, itype(ADDI, X_T0, X_T2, lo12(offset)));
225ece8a530Spatrick write32le(buf + 20, itype(SRLI, X_T1, X_T1, config->is64 ? 1 : 2));
226ece8a530Spatrick write32le(buf + 24, itype(load, X_T0, X_T0, config->wordsize));
227ece8a530Spatrick write32le(buf + 28, itype(JALR, 0, X_T3, 0));
228ece8a530Spatrick }
229ece8a530Spatrick
writePlt(uint8_t * buf,const Symbol & sym,uint64_t pltEntryAddr) const230ece8a530Spatrick void RISCV::writePlt(uint8_t *buf, const Symbol &sym,
231ece8a530Spatrick uint64_t pltEntryAddr) const {
232ece8a530Spatrick // 1: auipc t3, %pcrel_hi(f@.got.plt)
233ece8a530Spatrick // l[wd] t3, %pcrel_lo(1b)(t3)
234ece8a530Spatrick // jalr t1, t3
235ece8a530Spatrick // nop
236ece8a530Spatrick uint32_t offset = sym.getGotPltVA() - pltEntryAddr;
237ece8a530Spatrick write32le(buf + 0, utype(AUIPC, X_T3, hi20(offset)));
238ece8a530Spatrick write32le(buf + 4, itype(config->is64 ? LD : LW, X_T3, X_T3, lo12(offset)));
239ece8a530Spatrick write32le(buf + 8, itype(JALR, X_T1, X_T3, 0));
240ece8a530Spatrick write32le(buf + 12, itype(ADDI, 0, 0, 0));
241ece8a530Spatrick }
242ece8a530Spatrick
getDynRel(RelType type) const243ece8a530Spatrick RelType RISCV::getDynRel(RelType type) const {
244ece8a530Spatrick return type == target->symbolicRel ? type
245ece8a530Spatrick : static_cast<RelType>(R_RISCV_NONE);
246ece8a530Spatrick }
247ece8a530Spatrick
getRelExpr(const RelType type,const Symbol & s,const uint8_t * loc) const248ece8a530Spatrick RelExpr RISCV::getRelExpr(const RelType type, const Symbol &s,
249ece8a530Spatrick const uint8_t *loc) const {
250ece8a530Spatrick switch (type) {
251ece8a530Spatrick case R_RISCV_NONE:
252ece8a530Spatrick return R_NONE;
253ece8a530Spatrick case R_RISCV_32:
254ece8a530Spatrick case R_RISCV_64:
255ece8a530Spatrick case R_RISCV_HI20:
256ece8a530Spatrick case R_RISCV_LO12_I:
257ece8a530Spatrick case R_RISCV_LO12_S:
258ece8a530Spatrick case R_RISCV_RVC_LUI:
259ece8a530Spatrick return R_ABS;
260ece8a530Spatrick case R_RISCV_ADD8:
261ece8a530Spatrick case R_RISCV_ADD16:
262ece8a530Spatrick case R_RISCV_ADD32:
263ece8a530Spatrick case R_RISCV_ADD64:
264ece8a530Spatrick case R_RISCV_SET6:
265ece8a530Spatrick case R_RISCV_SET8:
266ece8a530Spatrick case R_RISCV_SET16:
267ece8a530Spatrick case R_RISCV_SET32:
268ece8a530Spatrick case R_RISCV_SUB6:
269ece8a530Spatrick case R_RISCV_SUB8:
270ece8a530Spatrick case R_RISCV_SUB16:
271ece8a530Spatrick case R_RISCV_SUB32:
272ece8a530Spatrick case R_RISCV_SUB64:
273ece8a530Spatrick return R_RISCV_ADD;
274ece8a530Spatrick case R_RISCV_JAL:
275ece8a530Spatrick case R_RISCV_BRANCH:
276ece8a530Spatrick case R_RISCV_PCREL_HI20:
277ece8a530Spatrick case R_RISCV_RVC_BRANCH:
278ece8a530Spatrick case R_RISCV_RVC_JUMP:
279ece8a530Spatrick case R_RISCV_32_PCREL:
280ece8a530Spatrick return R_PC;
281ece8a530Spatrick case R_RISCV_CALL:
282ece8a530Spatrick case R_RISCV_CALL_PLT:
283ece8a530Spatrick return R_PLT_PC;
284ece8a530Spatrick case R_RISCV_GOT_HI20:
285ece8a530Spatrick return R_GOT_PC;
286ece8a530Spatrick case R_RISCV_PCREL_LO12_I:
287ece8a530Spatrick case R_RISCV_PCREL_LO12_S:
288ece8a530Spatrick return R_RISCV_PC_INDIRECT;
289ece8a530Spatrick case R_RISCV_TLS_GD_HI20:
290ece8a530Spatrick return R_TLSGD_PC;
291ece8a530Spatrick case R_RISCV_TLS_GOT_HI20:
292ece8a530Spatrick return R_GOT_PC;
293ece8a530Spatrick case R_RISCV_TPREL_HI20:
294ece8a530Spatrick case R_RISCV_TPREL_LO12_I:
295ece8a530Spatrick case R_RISCV_TPREL_LO12_S:
2961cf9926bSpatrick return R_TPREL;
297ece8a530Spatrick case R_RISCV_ALIGN:
29805edf1c1Srobert return R_RELAX_HINT;
29905edf1c1Srobert case R_RISCV_TPREL_ADD:
30005edf1c1Srobert case R_RISCV_RELAX:
30105edf1c1Srobert return config->relax ? R_RELAX_HINT : R_NONE;
302ece8a530Spatrick default:
303ece8a530Spatrick error(getErrorLocation(loc) + "unknown relocation (" + Twine(type) +
304ece8a530Spatrick ") against symbol " + toString(s));
305ece8a530Spatrick return R_NONE;
306ece8a530Spatrick }
307ece8a530Spatrick }
308ece8a530Spatrick
relocate(uint8_t * loc,const Relocation & rel,uint64_t val) const309bb684c34Spatrick void RISCV::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const {
310ece8a530Spatrick const unsigned bits = config->wordsize * 8;
311ece8a530Spatrick
312bb684c34Spatrick switch (rel.type) {
313ece8a530Spatrick case R_RISCV_32:
314ece8a530Spatrick write32le(loc, val);
315ece8a530Spatrick return;
316ece8a530Spatrick case R_RISCV_64:
317ece8a530Spatrick write64le(loc, val);
318ece8a530Spatrick return;
319ece8a530Spatrick
320ece8a530Spatrick case R_RISCV_RVC_BRANCH: {
32105edf1c1Srobert checkInt(loc, val, 9, rel);
322bb684c34Spatrick checkAlignment(loc, val, 2, rel);
323ece8a530Spatrick uint16_t insn = read16le(loc) & 0xE383;
324ece8a530Spatrick uint16_t imm8 = extractBits(val, 8, 8) << 12;
325ece8a530Spatrick uint16_t imm4_3 = extractBits(val, 4, 3) << 10;
326ece8a530Spatrick uint16_t imm7_6 = extractBits(val, 7, 6) << 5;
327ece8a530Spatrick uint16_t imm2_1 = extractBits(val, 2, 1) << 3;
328ece8a530Spatrick uint16_t imm5 = extractBits(val, 5, 5) << 2;
329ece8a530Spatrick insn |= imm8 | imm4_3 | imm7_6 | imm2_1 | imm5;
330ece8a530Spatrick
331ece8a530Spatrick write16le(loc, insn);
332ece8a530Spatrick return;
333ece8a530Spatrick }
334ece8a530Spatrick
335ece8a530Spatrick case R_RISCV_RVC_JUMP: {
33605edf1c1Srobert checkInt(loc, val, 12, rel);
337bb684c34Spatrick checkAlignment(loc, val, 2, rel);
338ece8a530Spatrick uint16_t insn = read16le(loc) & 0xE003;
339ece8a530Spatrick uint16_t imm11 = extractBits(val, 11, 11) << 12;
340ece8a530Spatrick uint16_t imm4 = extractBits(val, 4, 4) << 11;
341ece8a530Spatrick uint16_t imm9_8 = extractBits(val, 9, 8) << 9;
342ece8a530Spatrick uint16_t imm10 = extractBits(val, 10, 10) << 8;
343ece8a530Spatrick uint16_t imm6 = extractBits(val, 6, 6) << 7;
344ece8a530Spatrick uint16_t imm7 = extractBits(val, 7, 7) << 6;
345ece8a530Spatrick uint16_t imm3_1 = extractBits(val, 3, 1) << 3;
346ece8a530Spatrick uint16_t imm5 = extractBits(val, 5, 5) << 2;
347ece8a530Spatrick insn |= imm11 | imm4 | imm9_8 | imm10 | imm6 | imm7 | imm3_1 | imm5;
348ece8a530Spatrick
349ece8a530Spatrick write16le(loc, insn);
350ece8a530Spatrick return;
351ece8a530Spatrick }
352ece8a530Spatrick
353ece8a530Spatrick case R_RISCV_RVC_LUI: {
354ece8a530Spatrick int64_t imm = SignExtend64(val + 0x800, bits) >> 12;
355bb684c34Spatrick checkInt(loc, imm, 6, rel);
356ece8a530Spatrick if (imm == 0) { // `c.lui rd, 0` is illegal, convert to `c.li rd, 0`
357ece8a530Spatrick write16le(loc, (read16le(loc) & 0x0F83) | 0x4000);
358ece8a530Spatrick } else {
359ece8a530Spatrick uint16_t imm17 = extractBits(val + 0x800, 17, 17) << 12;
360ece8a530Spatrick uint16_t imm16_12 = extractBits(val + 0x800, 16, 12) << 2;
361ece8a530Spatrick write16le(loc, (read16le(loc) & 0xEF83) | imm17 | imm16_12);
362ece8a530Spatrick }
363ece8a530Spatrick return;
364ece8a530Spatrick }
365ece8a530Spatrick
366ece8a530Spatrick case R_RISCV_JAL: {
36705edf1c1Srobert checkInt(loc, val, 21, rel);
368bb684c34Spatrick checkAlignment(loc, val, 2, rel);
369ece8a530Spatrick
370ece8a530Spatrick uint32_t insn = read32le(loc) & 0xFFF;
371ece8a530Spatrick uint32_t imm20 = extractBits(val, 20, 20) << 31;
372ece8a530Spatrick uint32_t imm10_1 = extractBits(val, 10, 1) << 21;
373ece8a530Spatrick uint32_t imm11 = extractBits(val, 11, 11) << 20;
374ece8a530Spatrick uint32_t imm19_12 = extractBits(val, 19, 12) << 12;
375ece8a530Spatrick insn |= imm20 | imm10_1 | imm11 | imm19_12;
376ece8a530Spatrick
377ece8a530Spatrick write32le(loc, insn);
378ece8a530Spatrick return;
379ece8a530Spatrick }
380ece8a530Spatrick
381ece8a530Spatrick case R_RISCV_BRANCH: {
38205edf1c1Srobert checkInt(loc, val, 13, rel);
383bb684c34Spatrick checkAlignment(loc, val, 2, rel);
384ece8a530Spatrick
385ece8a530Spatrick uint32_t insn = read32le(loc) & 0x1FFF07F;
386ece8a530Spatrick uint32_t imm12 = extractBits(val, 12, 12) << 31;
387ece8a530Spatrick uint32_t imm10_5 = extractBits(val, 10, 5) << 25;
388ece8a530Spatrick uint32_t imm4_1 = extractBits(val, 4, 1) << 8;
389ece8a530Spatrick uint32_t imm11 = extractBits(val, 11, 11) << 7;
390ece8a530Spatrick insn |= imm12 | imm10_5 | imm4_1 | imm11;
391ece8a530Spatrick
392ece8a530Spatrick write32le(loc, insn);
393ece8a530Spatrick return;
394ece8a530Spatrick }
395ece8a530Spatrick
396ece8a530Spatrick // auipc + jalr pair
397ece8a530Spatrick case R_RISCV_CALL:
398ece8a530Spatrick case R_RISCV_CALL_PLT: {
399ece8a530Spatrick int64_t hi = SignExtend64(val + 0x800, bits) >> 12;
400bb684c34Spatrick checkInt(loc, hi, 20, rel);
401ece8a530Spatrick if (isInt<20>(hi)) {
402bb684c34Spatrick relocateNoSym(loc, R_RISCV_PCREL_HI20, val);
403bb684c34Spatrick relocateNoSym(loc + 4, R_RISCV_PCREL_LO12_I, val);
404ece8a530Spatrick }
405ece8a530Spatrick return;
406ece8a530Spatrick }
407ece8a530Spatrick
408ece8a530Spatrick case R_RISCV_GOT_HI20:
409ece8a530Spatrick case R_RISCV_PCREL_HI20:
410ece8a530Spatrick case R_RISCV_TLS_GD_HI20:
411ece8a530Spatrick case R_RISCV_TLS_GOT_HI20:
412ece8a530Spatrick case R_RISCV_TPREL_HI20:
413ece8a530Spatrick case R_RISCV_HI20: {
414ece8a530Spatrick uint64_t hi = val + 0x800;
415bb684c34Spatrick checkInt(loc, SignExtend64(hi, bits) >> 12, 20, rel);
416ece8a530Spatrick write32le(loc, (read32le(loc) & 0xFFF) | (hi & 0xFFFFF000));
417ece8a530Spatrick return;
418ece8a530Spatrick }
419ece8a530Spatrick
420ece8a530Spatrick case R_RISCV_PCREL_LO12_I:
421ece8a530Spatrick case R_RISCV_TPREL_LO12_I:
422ece8a530Spatrick case R_RISCV_LO12_I: {
423ece8a530Spatrick uint64_t hi = (val + 0x800) >> 12;
424ece8a530Spatrick uint64_t lo = val - (hi << 12);
42505edf1c1Srobert write32le(loc, setLO12_I(read32le(loc), lo & 0xfff));
426ece8a530Spatrick return;
427ece8a530Spatrick }
428ece8a530Spatrick
429ece8a530Spatrick case R_RISCV_PCREL_LO12_S:
430ece8a530Spatrick case R_RISCV_TPREL_LO12_S:
431ece8a530Spatrick case R_RISCV_LO12_S: {
432ece8a530Spatrick uint64_t hi = (val + 0x800) >> 12;
433ece8a530Spatrick uint64_t lo = val - (hi << 12);
43405edf1c1Srobert write32le(loc, setLO12_S(read32le(loc), lo));
435ece8a530Spatrick return;
436ece8a530Spatrick }
437ece8a530Spatrick
438ece8a530Spatrick case R_RISCV_ADD8:
439ece8a530Spatrick *loc += val;
440ece8a530Spatrick return;
441ece8a530Spatrick case R_RISCV_ADD16:
442ece8a530Spatrick write16le(loc, read16le(loc) + val);
443ece8a530Spatrick return;
444ece8a530Spatrick case R_RISCV_ADD32:
445ece8a530Spatrick write32le(loc, read32le(loc) + val);
446ece8a530Spatrick return;
447ece8a530Spatrick case R_RISCV_ADD64:
448ece8a530Spatrick write64le(loc, read64le(loc) + val);
449ece8a530Spatrick return;
450ece8a530Spatrick case R_RISCV_SUB6:
451ece8a530Spatrick *loc = (*loc & 0xc0) | (((*loc & 0x3f) - val) & 0x3f);
452ece8a530Spatrick return;
453ece8a530Spatrick case R_RISCV_SUB8:
454ece8a530Spatrick *loc -= val;
455ece8a530Spatrick return;
456ece8a530Spatrick case R_RISCV_SUB16:
457ece8a530Spatrick write16le(loc, read16le(loc) - val);
458ece8a530Spatrick return;
459ece8a530Spatrick case R_RISCV_SUB32:
460ece8a530Spatrick write32le(loc, read32le(loc) - val);
461ece8a530Spatrick return;
462ece8a530Spatrick case R_RISCV_SUB64:
463ece8a530Spatrick write64le(loc, read64le(loc) - val);
464ece8a530Spatrick return;
465ece8a530Spatrick case R_RISCV_SET6:
466ece8a530Spatrick *loc = (*loc & 0xc0) | (val & 0x3f);
467ece8a530Spatrick return;
468ece8a530Spatrick case R_RISCV_SET8:
469ece8a530Spatrick *loc = val;
470ece8a530Spatrick return;
471ece8a530Spatrick case R_RISCV_SET16:
472ece8a530Spatrick write16le(loc, val);
473ece8a530Spatrick return;
474ece8a530Spatrick case R_RISCV_SET32:
475ece8a530Spatrick case R_RISCV_32_PCREL:
476ece8a530Spatrick write32le(loc, val);
477ece8a530Spatrick return;
478ece8a530Spatrick
479ece8a530Spatrick case R_RISCV_TLS_DTPREL32:
480ece8a530Spatrick write32le(loc, val - dtpOffset);
481ece8a530Spatrick break;
482ece8a530Spatrick case R_RISCV_TLS_DTPREL64:
483ece8a530Spatrick write64le(loc, val - dtpOffset);
484ece8a530Spatrick break;
485ece8a530Spatrick
486ece8a530Spatrick case R_RISCV_RELAX:
487ece8a530Spatrick return; // Ignored (for now)
488ece8a530Spatrick
489ece8a530Spatrick default:
490ece8a530Spatrick llvm_unreachable("unknown relocation");
491ece8a530Spatrick }
492ece8a530Spatrick }
493ece8a530Spatrick
49405edf1c1Srobert namespace {
49505edf1c1Srobert struct SymbolAnchor {
49605edf1c1Srobert uint64_t offset;
49705edf1c1Srobert Defined *d;
49805edf1c1Srobert bool end; // true for the anchor of st_value+st_size
49905edf1c1Srobert };
50005edf1c1Srobert } // namespace
50105edf1c1Srobert
50205edf1c1Srobert struct elf::RISCVRelaxAux {
50305edf1c1Srobert // This records symbol start and end offsets which will be adjusted according
50405edf1c1Srobert // to the nearest relocDeltas element.
50505edf1c1Srobert SmallVector<SymbolAnchor, 0> anchors;
50605edf1c1Srobert // For relocations[i], the actual offset is r_offset - (i ? relocDeltas[i-1] :
50705edf1c1Srobert // 0).
50805edf1c1Srobert std::unique_ptr<uint32_t[]> relocDeltas;
50905edf1c1Srobert // For relocations[i], the actual type is relocTypes[i].
51005edf1c1Srobert std::unique_ptr<RelType[]> relocTypes;
51105edf1c1Srobert SmallVector<uint32_t, 0> writes;
51205edf1c1Srobert };
51305edf1c1Srobert
initSymbolAnchors()51405edf1c1Srobert static void initSymbolAnchors() {
51505edf1c1Srobert SmallVector<InputSection *, 0> storage;
51605edf1c1Srobert for (OutputSection *osec : outputSections) {
51705edf1c1Srobert if (!(osec->flags & SHF_EXECINSTR))
51805edf1c1Srobert continue;
51905edf1c1Srobert for (InputSection *sec : getInputSections(*osec, storage)) {
52005edf1c1Srobert sec->relaxAux = make<RISCVRelaxAux>();
52105edf1c1Srobert if (sec->relocs().size()) {
52205edf1c1Srobert sec->relaxAux->relocDeltas =
52305edf1c1Srobert std::make_unique<uint32_t[]>(sec->relocs().size());
52405edf1c1Srobert sec->relaxAux->relocTypes =
52505edf1c1Srobert std::make_unique<RelType[]>(sec->relocs().size());
52605edf1c1Srobert }
52705edf1c1Srobert }
52805edf1c1Srobert }
52905edf1c1Srobert // Store anchors (st_value and st_value+st_size) for symbols relative to text
53005edf1c1Srobert // sections.
53105edf1c1Srobert for (InputFile *file : ctx.objectFiles)
53205edf1c1Srobert for (Symbol *sym : file->getSymbols()) {
53305edf1c1Srobert auto *d = dyn_cast<Defined>(sym);
53405edf1c1Srobert if (!d || d->file != file)
53505edf1c1Srobert continue;
53605edf1c1Srobert if (auto *sec = dyn_cast_or_null<InputSection>(d->section))
53705edf1c1Srobert if (sec->flags & SHF_EXECINSTR && sec->relaxAux) {
53805edf1c1Srobert // If sec is discarded, relaxAux will be nullptr.
53905edf1c1Srobert sec->relaxAux->anchors.push_back({d->value, d, false});
54005edf1c1Srobert sec->relaxAux->anchors.push_back({d->value + d->size, d, true});
54105edf1c1Srobert }
54205edf1c1Srobert }
54305edf1c1Srobert // Sort anchors by offset so that we can find the closest relocation
54405edf1c1Srobert // efficiently. For a zero size symbol, ensure that its start anchor precedes
54505edf1c1Srobert // its end anchor. For two symbols with anchors at the same offset, their
54605edf1c1Srobert // order does not matter.
54705edf1c1Srobert for (OutputSection *osec : outputSections) {
54805edf1c1Srobert if (!(osec->flags & SHF_EXECINSTR))
54905edf1c1Srobert continue;
55005edf1c1Srobert for (InputSection *sec : getInputSections(*osec, storage)) {
55105edf1c1Srobert llvm::sort(sec->relaxAux->anchors, [](auto &a, auto &b) {
55205edf1c1Srobert return std::make_pair(a.offset, a.end) <
55305edf1c1Srobert std::make_pair(b.offset, b.end);
55405edf1c1Srobert });
55505edf1c1Srobert }
55605edf1c1Srobert }
55705edf1c1Srobert }
55805edf1c1Srobert
55905edf1c1Srobert // Relax R_RISCV_CALL/R_RISCV_CALL_PLT auipc+jalr to c.j, c.jal, or jal.
relaxCall(const InputSection & sec,size_t i,uint64_t loc,Relocation & r,uint32_t & remove)56005edf1c1Srobert static void relaxCall(const InputSection &sec, size_t i, uint64_t loc,
56105edf1c1Srobert Relocation &r, uint32_t &remove) {
56205edf1c1Srobert const bool rvc = config->eflags & EF_RISCV_RVC;
56305edf1c1Srobert const Symbol &sym = *r.sym;
56405edf1c1Srobert const uint64_t insnPair = read64le(sec.content().data() + r.offset);
56505edf1c1Srobert const uint32_t rd = extractBits(insnPair, 32 + 11, 32 + 7);
56605edf1c1Srobert const uint64_t dest =
56705edf1c1Srobert (r.expr == R_PLT_PC ? sym.getPltVA() : sym.getVA()) + r.addend;
56805edf1c1Srobert const int64_t displace = dest - loc;
56905edf1c1Srobert
57005edf1c1Srobert if (rvc && isInt<12>(displace) && rd == 0) {
57105edf1c1Srobert sec.relaxAux->relocTypes[i] = R_RISCV_RVC_JUMP;
57205edf1c1Srobert sec.relaxAux->writes.push_back(0xa001); // c.j
57305edf1c1Srobert remove = 6;
57405edf1c1Srobert } else if (rvc && isInt<12>(displace) && rd == X_RA &&
57505edf1c1Srobert !config->is64) { // RV32C only
57605edf1c1Srobert sec.relaxAux->relocTypes[i] = R_RISCV_RVC_JUMP;
57705edf1c1Srobert sec.relaxAux->writes.push_back(0x2001); // c.jal
57805edf1c1Srobert remove = 6;
57905edf1c1Srobert } else if (isInt<21>(displace)) {
58005edf1c1Srobert sec.relaxAux->relocTypes[i] = R_RISCV_JAL;
58105edf1c1Srobert sec.relaxAux->writes.push_back(0x6f | rd << 7); // jal
58205edf1c1Srobert remove = 4;
58305edf1c1Srobert }
58405edf1c1Srobert }
58505edf1c1Srobert
58605edf1c1Srobert // Relax local-exec TLS when hi20 is zero.
relaxTlsLe(const InputSection & sec,size_t i,uint64_t loc,Relocation & r,uint32_t & remove)58705edf1c1Srobert static void relaxTlsLe(const InputSection &sec, size_t i, uint64_t loc,
58805edf1c1Srobert Relocation &r, uint32_t &remove) {
58905edf1c1Srobert uint64_t val = r.sym->getVA(r.addend);
59005edf1c1Srobert if (hi20(val) != 0)
59105edf1c1Srobert return;
59205edf1c1Srobert uint32_t insn = read32le(sec.content().data() + r.offset);
59305edf1c1Srobert switch (r.type) {
59405edf1c1Srobert case R_RISCV_TPREL_HI20:
59505edf1c1Srobert case R_RISCV_TPREL_ADD:
59605edf1c1Srobert // Remove lui rd, %tprel_hi(x) and add rd, rd, tp, %tprel_add(x).
59705edf1c1Srobert sec.relaxAux->relocTypes[i] = R_RISCV_RELAX;
59805edf1c1Srobert remove = 4;
59905edf1c1Srobert break;
60005edf1c1Srobert case R_RISCV_TPREL_LO12_I:
60105edf1c1Srobert // addi rd, rd, %tprel_lo(x) => addi rd, tp, st_value(x)
60205edf1c1Srobert sec.relaxAux->relocTypes[i] = R_RISCV_32;
60305edf1c1Srobert insn = (insn & ~(31 << 15)) | (X_TP << 15);
60405edf1c1Srobert sec.relaxAux->writes.push_back(setLO12_I(insn, val));
60505edf1c1Srobert break;
60605edf1c1Srobert case R_RISCV_TPREL_LO12_S:
60705edf1c1Srobert // sw rs, %tprel_lo(x)(rd) => sw rs, st_value(x)(rd)
60805edf1c1Srobert sec.relaxAux->relocTypes[i] = R_RISCV_32;
60905edf1c1Srobert insn = (insn & ~(31 << 15)) | (X_TP << 15);
61005edf1c1Srobert sec.relaxAux->writes.push_back(setLO12_S(insn, val));
61105edf1c1Srobert break;
61205edf1c1Srobert }
61305edf1c1Srobert }
61405edf1c1Srobert
relax(InputSection & sec)61505edf1c1Srobert static bool relax(InputSection &sec) {
61605edf1c1Srobert const uint64_t secAddr = sec.getVA();
61705edf1c1Srobert auto &aux = *sec.relaxAux;
61805edf1c1Srobert bool changed = false;
61905edf1c1Srobert
62005edf1c1Srobert // Get st_value delta for symbols relative to this section from the previous
62105edf1c1Srobert // iteration.
62205edf1c1Srobert DenseMap<const Defined *, uint64_t> valueDelta;
62305edf1c1Srobert ArrayRef<SymbolAnchor> sa = ArrayRef(aux.anchors);
624*6add50f8Sjca uint64_t delta = 0;
62505edf1c1Srobert for (auto [i, r] : llvm::enumerate(sec.relocs())) {
62605edf1c1Srobert for (; sa.size() && sa[0].offset <= r.offset; sa = sa.slice(1))
62705edf1c1Srobert if (!sa[0].end)
62805edf1c1Srobert valueDelta[sa[0].d] = delta;
62905edf1c1Srobert delta = aux.relocDeltas[i];
63005edf1c1Srobert }
63105edf1c1Srobert for (const SymbolAnchor &sa : sa)
63205edf1c1Srobert if (!sa.end)
63305edf1c1Srobert valueDelta[sa.d] = delta;
63405edf1c1Srobert sa = ArrayRef(aux.anchors);
63505edf1c1Srobert delta = 0;
63605edf1c1Srobert
63705edf1c1Srobert std::fill_n(aux.relocTypes.get(), sec.relocs().size(), R_RISCV_NONE);
63805edf1c1Srobert aux.writes.clear();
63905edf1c1Srobert for (auto [i, r] : llvm::enumerate(sec.relocs())) {
64005edf1c1Srobert const uint64_t loc = secAddr + r.offset - delta;
64105edf1c1Srobert uint32_t &cur = aux.relocDeltas[i], remove = 0;
64205edf1c1Srobert switch (r.type) {
64305edf1c1Srobert case R_RISCV_ALIGN: {
64405edf1c1Srobert const uint64_t nextLoc = loc + r.addend;
64505edf1c1Srobert const uint64_t align = PowerOf2Ceil(r.addend + 2);
64605edf1c1Srobert // All bytes beyond the alignment boundary should be removed.
64705edf1c1Srobert remove = nextLoc - ((loc + align - 1) & -align);
64805edf1c1Srobert assert(static_cast<int32_t>(remove) >= 0 &&
64905edf1c1Srobert "R_RISCV_ALIGN needs expanding the content");
65005edf1c1Srobert break;
65105edf1c1Srobert }
65205edf1c1Srobert case R_RISCV_CALL:
65305edf1c1Srobert case R_RISCV_CALL_PLT:
65405edf1c1Srobert if (i + 1 != sec.relocs().size() &&
65505edf1c1Srobert sec.relocs()[i + 1].type == R_RISCV_RELAX)
65605edf1c1Srobert relaxCall(sec, i, loc, r, remove);
65705edf1c1Srobert break;
65805edf1c1Srobert case R_RISCV_TPREL_HI20:
65905edf1c1Srobert case R_RISCV_TPREL_ADD:
66005edf1c1Srobert case R_RISCV_TPREL_LO12_I:
66105edf1c1Srobert case R_RISCV_TPREL_LO12_S:
66205edf1c1Srobert if (i + 1 != sec.relocs().size() &&
66305edf1c1Srobert sec.relocs()[i + 1].type == R_RISCV_RELAX)
66405edf1c1Srobert relaxTlsLe(sec, i, loc, r, remove);
66505edf1c1Srobert break;
66605edf1c1Srobert }
66705edf1c1Srobert
66805edf1c1Srobert // For all anchors whose offsets are <= r.offset, they are preceded by
66905edf1c1Srobert // the previous relocation whose `relocDeltas` value equals `delta`.
67005edf1c1Srobert // Decrease their st_value and update their st_size.
67105edf1c1Srobert for (; sa.size() && sa[0].offset <= r.offset; sa = sa.slice(1)) {
67205edf1c1Srobert if (sa[0].end)
67305edf1c1Srobert sa[0].d->size = sa[0].offset - delta - sa[0].d->value;
67405edf1c1Srobert else
67505edf1c1Srobert sa[0].d->value -= delta - valueDelta.find(sa[0].d)->second;
67605edf1c1Srobert }
67705edf1c1Srobert delta += remove;
67805edf1c1Srobert if (delta != cur) {
67905edf1c1Srobert cur = delta;
68005edf1c1Srobert changed = true;
68105edf1c1Srobert }
68205edf1c1Srobert }
68305edf1c1Srobert
68405edf1c1Srobert for (const SymbolAnchor &a : sa) {
68505edf1c1Srobert if (a.end)
68605edf1c1Srobert a.d->size = a.offset - delta - a.d->value;
68705edf1c1Srobert else
68805edf1c1Srobert a.d->value -= delta - valueDelta.find(a.d)->second;
68905edf1c1Srobert }
69005edf1c1Srobert // Inform assignAddresses that the size has changed.
691*6add50f8Sjca if (!isUInt<32>(delta))
692*6add50f8Sjca fatal("section size decrease is too large: " + Twine(delta));
69305edf1c1Srobert sec.bytesDropped = delta;
69405edf1c1Srobert return changed;
69505edf1c1Srobert }
69605edf1c1Srobert
69705edf1c1Srobert // When relaxing just R_RISCV_ALIGN, relocDeltas is usually changed only once in
69805edf1c1Srobert // the absence of a linker script. For call and load/store R_RISCV_RELAX, code
69905edf1c1Srobert // shrinkage may reduce displacement and make more relocations eligible for
70005edf1c1Srobert // relaxation. Code shrinkage may increase displacement to a call/load/store
70105edf1c1Srobert // target at a higher fixed address, invalidating an earlier relaxation. Any
70205edf1c1Srobert // change in section sizes can have cascading effect and require another
70305edf1c1Srobert // relaxation pass.
relaxOnce(int pass) const70405edf1c1Srobert bool RISCV::relaxOnce(int pass) const {
70505edf1c1Srobert llvm::TimeTraceScope timeScope("RISC-V relaxOnce");
70605edf1c1Srobert if (config->relocatable)
70705edf1c1Srobert return false;
70805edf1c1Srobert
70905edf1c1Srobert if (pass == 0)
71005edf1c1Srobert initSymbolAnchors();
71105edf1c1Srobert
71205edf1c1Srobert SmallVector<InputSection *, 0> storage;
71305edf1c1Srobert bool changed = false;
71405edf1c1Srobert for (OutputSection *osec : outputSections) {
71505edf1c1Srobert if (!(osec->flags & SHF_EXECINSTR))
71605edf1c1Srobert continue;
71705edf1c1Srobert for (InputSection *sec : getInputSections(*osec, storage))
71805edf1c1Srobert changed |= relax(*sec);
71905edf1c1Srobert }
72005edf1c1Srobert return changed;
72105edf1c1Srobert }
72205edf1c1Srobert
riscvFinalizeRelax(int passes)72305edf1c1Srobert void elf::riscvFinalizeRelax(int passes) {
72405edf1c1Srobert llvm::TimeTraceScope timeScope("Finalize RISC-V relaxation");
72505edf1c1Srobert log("relaxation passes: " + Twine(passes));
72605edf1c1Srobert SmallVector<InputSection *, 0> storage;
72705edf1c1Srobert for (OutputSection *osec : outputSections) {
72805edf1c1Srobert if (!(osec->flags & SHF_EXECINSTR))
72905edf1c1Srobert continue;
73005edf1c1Srobert for (InputSection *sec : getInputSections(*osec, storage)) {
73105edf1c1Srobert RISCVRelaxAux &aux = *sec->relaxAux;
73205edf1c1Srobert if (!aux.relocDeltas)
73305edf1c1Srobert continue;
73405edf1c1Srobert
73505edf1c1Srobert MutableArrayRef<Relocation> rels = sec->relocs();
73605edf1c1Srobert ArrayRef<uint8_t> old = sec->content();
73705edf1c1Srobert size_t newSize = old.size() - aux.relocDeltas[rels.size() - 1];
73805edf1c1Srobert size_t writesIdx = 0;
73905edf1c1Srobert uint8_t *p = context().bAlloc.Allocate<uint8_t>(newSize);
74005edf1c1Srobert uint64_t offset = 0;
74105edf1c1Srobert int64_t delta = 0;
74205edf1c1Srobert sec->content_ = p;
74305edf1c1Srobert sec->size = newSize;
74405edf1c1Srobert sec->bytesDropped = 0;
74505edf1c1Srobert
74605edf1c1Srobert // Update section content: remove NOPs for R_RISCV_ALIGN and rewrite
74705edf1c1Srobert // instructions for relaxed relocations.
74805edf1c1Srobert for (size_t i = 0, e = rels.size(); i != e; ++i) {
74905edf1c1Srobert uint32_t remove = aux.relocDeltas[i] - delta;
75005edf1c1Srobert delta = aux.relocDeltas[i];
75105edf1c1Srobert if (remove == 0 && aux.relocTypes[i] == R_RISCV_NONE)
75205edf1c1Srobert continue;
75305edf1c1Srobert
75405edf1c1Srobert // Copy from last location to the current relocated location.
75505edf1c1Srobert const Relocation &r = rels[i];
75605edf1c1Srobert uint64_t size = r.offset - offset;
75705edf1c1Srobert memcpy(p, old.data() + offset, size);
75805edf1c1Srobert p += size;
75905edf1c1Srobert
76005edf1c1Srobert // For R_RISCV_ALIGN, we will place `offset` in a location (among NOPs)
76105edf1c1Srobert // to satisfy the alignment requirement. If both `remove` and r.addend
76205edf1c1Srobert // are multiples of 4, it is as if we have skipped some NOPs. Otherwise
76305edf1c1Srobert // we are in the middle of a 4-byte NOP, and we need to rewrite the NOP
76405edf1c1Srobert // sequence.
76505edf1c1Srobert int64_t skip = 0;
76605edf1c1Srobert if (r.type == R_RISCV_ALIGN) {
76705edf1c1Srobert if (remove % 4 || r.addend % 4) {
76805edf1c1Srobert skip = r.addend - remove;
76905edf1c1Srobert int64_t j = 0;
77005edf1c1Srobert for (; j + 4 <= skip; j += 4)
77105edf1c1Srobert write32le(p + j, 0x00000013); // nop
77205edf1c1Srobert if (j != skip) {
77305edf1c1Srobert assert(j + 2 == skip);
77405edf1c1Srobert write16le(p + j, 0x0001); // c.nop
77505edf1c1Srobert }
77605edf1c1Srobert }
77705edf1c1Srobert } else if (RelType newType = aux.relocTypes[i]) {
77805edf1c1Srobert switch (newType) {
77905edf1c1Srobert case R_RISCV_RELAX:
78005edf1c1Srobert // Used by relaxTlsLe to indicate the relocation is ignored.
78105edf1c1Srobert break;
78205edf1c1Srobert case R_RISCV_RVC_JUMP:
78305edf1c1Srobert skip = 2;
78405edf1c1Srobert write16le(p, aux.writes[writesIdx++]);
78505edf1c1Srobert break;
78605edf1c1Srobert case R_RISCV_JAL:
78705edf1c1Srobert skip = 4;
78805edf1c1Srobert write32le(p, aux.writes[writesIdx++]);
78905edf1c1Srobert break;
79005edf1c1Srobert case R_RISCV_32:
79105edf1c1Srobert // Used by relaxTlsLe to write a uint32_t then suppress the handling
79205edf1c1Srobert // in relocateAlloc.
79305edf1c1Srobert skip = 4;
79405edf1c1Srobert write32le(p, aux.writes[writesIdx++]);
79505edf1c1Srobert aux.relocTypes[i] = R_RISCV_NONE;
79605edf1c1Srobert break;
79705edf1c1Srobert default:
79805edf1c1Srobert llvm_unreachable("unsupported type");
79905edf1c1Srobert }
80005edf1c1Srobert }
80105edf1c1Srobert
80205edf1c1Srobert p += skip;
80305edf1c1Srobert offset = r.offset + skip + remove;
80405edf1c1Srobert }
80505edf1c1Srobert memcpy(p, old.data() + offset, old.size() - offset);
80605edf1c1Srobert
80705edf1c1Srobert // Subtract the previous relocDeltas value from the relocation offset.
80805edf1c1Srobert // For a pair of R_RISCV_CALL/R_RISCV_RELAX with the same offset, decrease
80905edf1c1Srobert // their r_offset by the same delta.
81005edf1c1Srobert delta = 0;
81105edf1c1Srobert for (size_t i = 0, e = rels.size(); i != e;) {
81205edf1c1Srobert uint64_t cur = rels[i].offset;
81305edf1c1Srobert do {
81405edf1c1Srobert rels[i].offset -= delta;
81505edf1c1Srobert if (aux.relocTypes[i] != R_RISCV_NONE)
81605edf1c1Srobert rels[i].type = aux.relocTypes[i];
81705edf1c1Srobert } while (++i != e && rels[i].offset == cur);
81805edf1c1Srobert delta = aux.relocDeltas[i - 1];
81905edf1c1Srobert }
82005edf1c1Srobert }
82105edf1c1Srobert }
82205edf1c1Srobert }
82305edf1c1Srobert
82405edf1c1Srobert namespace {
82505edf1c1Srobert // Representation of the merged .riscv.attributes input sections. The psABI
82605edf1c1Srobert // specifies merge policy for attributes. E.g. if we link an object without an
82705edf1c1Srobert // extension with an object with the extension, the output Tag_RISCV_arch shall
82805edf1c1Srobert // contain the extension. Some tools like objdump parse .riscv.attributes and
82905edf1c1Srobert // disabling some instructions if the first Tag_RISCV_arch does not contain an
83005edf1c1Srobert // extension.
83105edf1c1Srobert class RISCVAttributesSection final : public SyntheticSection {
83205edf1c1Srobert public:
RISCVAttributesSection()83305edf1c1Srobert RISCVAttributesSection()
83405edf1c1Srobert : SyntheticSection(0, SHT_RISCV_ATTRIBUTES, 1, ".riscv.attributes") {}
83505edf1c1Srobert
getSize() const83605edf1c1Srobert size_t getSize() const override { return size; }
83705edf1c1Srobert void writeTo(uint8_t *buf) override;
83805edf1c1Srobert
83905edf1c1Srobert static constexpr StringRef vendor = "riscv";
84005edf1c1Srobert DenseMap<unsigned, unsigned> intAttr;
84105edf1c1Srobert DenseMap<unsigned, StringRef> strAttr;
84205edf1c1Srobert size_t size = 0;
84305edf1c1Srobert };
84405edf1c1Srobert } // namespace
84505edf1c1Srobert
mergeArch(RISCVISAInfo::OrderedExtensionMap & mergedExts,unsigned & mergedXlen,const InputSectionBase * sec,StringRef s)84605edf1c1Srobert static void mergeArch(RISCVISAInfo::OrderedExtensionMap &mergedExts,
84705edf1c1Srobert unsigned &mergedXlen, const InputSectionBase *sec,
84805edf1c1Srobert StringRef s) {
84905edf1c1Srobert auto maybeInfo = RISCVISAInfo::parseNormalizedArchString(s);
85005edf1c1Srobert if (!maybeInfo) {
85105edf1c1Srobert errorOrWarn(toString(sec) + ": " + s + ": " +
85205edf1c1Srobert llvm::toString(maybeInfo.takeError()));
85305edf1c1Srobert return;
85405edf1c1Srobert }
85505edf1c1Srobert
85605edf1c1Srobert // Merge extensions.
85705edf1c1Srobert RISCVISAInfo &info = **maybeInfo;
85805edf1c1Srobert if (mergedExts.empty()) {
85905edf1c1Srobert mergedExts = info.getExtensions();
86005edf1c1Srobert mergedXlen = info.getXLen();
86105edf1c1Srobert } else {
86205edf1c1Srobert for (const auto &ext : info.getExtensions()) {
86305edf1c1Srobert if (auto it = mergedExts.find(ext.first); it != mergedExts.end()) {
86405edf1c1Srobert if (std::tie(it->second.MajorVersion, it->second.MinorVersion) >=
86505edf1c1Srobert std::tie(ext.second.MajorVersion, ext.second.MinorVersion))
86605edf1c1Srobert continue;
86705edf1c1Srobert }
86805edf1c1Srobert mergedExts[ext.first] = ext.second;
86905edf1c1Srobert }
87005edf1c1Srobert }
87105edf1c1Srobert }
87205edf1c1Srobert
87305edf1c1Srobert static RISCVAttributesSection *
mergeAttributesSection(const SmallVector<InputSectionBase *,0> & sections)87405edf1c1Srobert mergeAttributesSection(const SmallVector<InputSectionBase *, 0> §ions) {
87505edf1c1Srobert RISCVISAInfo::OrderedExtensionMap exts;
87605edf1c1Srobert const InputSectionBase *firstStackAlign = nullptr;
87705edf1c1Srobert unsigned firstStackAlignValue = 0, xlen = 0;
87805edf1c1Srobert bool hasArch = false;
87905edf1c1Srobert
88005edf1c1Srobert in.riscvAttributes = std::make_unique<RISCVAttributesSection>();
88105edf1c1Srobert auto &merged = static_cast<RISCVAttributesSection &>(*in.riscvAttributes);
88205edf1c1Srobert
88305edf1c1Srobert // Collect all tags values from attributes section.
88405edf1c1Srobert const auto &attributesTags = RISCVAttrs::getRISCVAttributeTags();
88505edf1c1Srobert for (const InputSectionBase *sec : sections) {
88605edf1c1Srobert RISCVAttributeParser parser;
88705edf1c1Srobert if (Error e = parser.parse(sec->content(), support::little))
88805edf1c1Srobert warn(toString(sec) + ": " + llvm::toString(std::move(e)));
88905edf1c1Srobert for (const auto &tag : attributesTags) {
89005edf1c1Srobert switch (RISCVAttrs::AttrType(tag.attr)) {
89105edf1c1Srobert // Integer attributes.
89205edf1c1Srobert case RISCVAttrs::STACK_ALIGN:
89305edf1c1Srobert if (auto i = parser.getAttributeValue(tag.attr)) {
89405edf1c1Srobert auto r = merged.intAttr.try_emplace(tag.attr, *i);
89505edf1c1Srobert if (r.second) {
89605edf1c1Srobert firstStackAlign = sec;
89705edf1c1Srobert firstStackAlignValue = *i;
89805edf1c1Srobert } else if (r.first->second != *i) {
89905edf1c1Srobert errorOrWarn(toString(sec) + " has stack_align=" + Twine(*i) +
90005edf1c1Srobert " but " + toString(firstStackAlign) +
90105edf1c1Srobert " has stack_align=" + Twine(firstStackAlignValue));
90205edf1c1Srobert }
90305edf1c1Srobert }
90405edf1c1Srobert continue;
90505edf1c1Srobert case RISCVAttrs::UNALIGNED_ACCESS:
90605edf1c1Srobert if (auto i = parser.getAttributeValue(tag.attr))
90705edf1c1Srobert merged.intAttr[tag.attr] |= *i;
90805edf1c1Srobert continue;
90905edf1c1Srobert
91005edf1c1Srobert // String attributes.
91105edf1c1Srobert case RISCVAttrs::ARCH:
91205edf1c1Srobert if (auto s = parser.getAttributeString(tag.attr)) {
91305edf1c1Srobert hasArch = true;
91405edf1c1Srobert mergeArch(exts, xlen, sec, *s);
91505edf1c1Srobert }
91605edf1c1Srobert continue;
91705edf1c1Srobert
91805edf1c1Srobert // Attributes which use the default handling.
91905edf1c1Srobert case RISCVAttrs::PRIV_SPEC:
92005edf1c1Srobert case RISCVAttrs::PRIV_SPEC_MINOR:
92105edf1c1Srobert case RISCVAttrs::PRIV_SPEC_REVISION:
92205edf1c1Srobert break;
92305edf1c1Srobert }
92405edf1c1Srobert
92505edf1c1Srobert // Fallback for deprecated priv_spec* and other unknown attributes: retain
92605edf1c1Srobert // the attribute if all input sections agree on the value. GNU ld uses 0
92705edf1c1Srobert // and empty strings as default values which are not dumped to the output.
92805edf1c1Srobert // TODO Adjust after resolution to
92905edf1c1Srobert // https://github.com/riscv-non-isa/riscv-elf-psabi-doc/issues/352
93005edf1c1Srobert if (tag.attr % 2 == 0) {
93105edf1c1Srobert if (auto i = parser.getAttributeValue(tag.attr)) {
93205edf1c1Srobert auto r = merged.intAttr.try_emplace(tag.attr, *i);
93305edf1c1Srobert if (!r.second && r.first->second != *i)
93405edf1c1Srobert r.first->second = 0;
93505edf1c1Srobert }
93605edf1c1Srobert } else if (auto s = parser.getAttributeString(tag.attr)) {
93705edf1c1Srobert auto r = merged.strAttr.try_emplace(tag.attr, *s);
93805edf1c1Srobert if (!r.second && r.first->second != *s)
93905edf1c1Srobert r.first->second = {};
94005edf1c1Srobert }
94105edf1c1Srobert }
94205edf1c1Srobert }
94305edf1c1Srobert
94405edf1c1Srobert if (hasArch) {
94505edf1c1Srobert if (auto result = RISCVISAInfo::postProcessAndChecking(
94605edf1c1Srobert std::make_unique<RISCVISAInfo>(xlen, exts))) {
94705edf1c1Srobert merged.strAttr.try_emplace(RISCVAttrs::ARCH,
94805edf1c1Srobert saver().save((*result)->toString()));
94905edf1c1Srobert } else {
95005edf1c1Srobert errorOrWarn(llvm::toString(result.takeError()));
95105edf1c1Srobert }
95205edf1c1Srobert }
95305edf1c1Srobert
95405edf1c1Srobert // The total size of headers: format-version [ <section-length> "vendor-name"
95505edf1c1Srobert // [ <file-tag> <size>.
95605edf1c1Srobert size_t size = 5 + merged.vendor.size() + 1 + 5;
95705edf1c1Srobert for (auto &attr : merged.intAttr)
95805edf1c1Srobert if (attr.second != 0)
95905edf1c1Srobert size += getULEB128Size(attr.first) + getULEB128Size(attr.second);
96005edf1c1Srobert for (auto &attr : merged.strAttr)
96105edf1c1Srobert if (!attr.second.empty())
96205edf1c1Srobert size += getULEB128Size(attr.first) + attr.second.size() + 1;
96305edf1c1Srobert merged.size = size;
96405edf1c1Srobert return &merged;
96505edf1c1Srobert }
96605edf1c1Srobert
writeTo(uint8_t * buf)96705edf1c1Srobert void RISCVAttributesSection::writeTo(uint8_t *buf) {
96805edf1c1Srobert const size_t size = getSize();
96905edf1c1Srobert uint8_t *const end = buf + size;
97005edf1c1Srobert *buf = ELFAttrs::Format_Version;
97105edf1c1Srobert write32(buf + 1, size - 1);
97205edf1c1Srobert buf += 5;
97305edf1c1Srobert
97405edf1c1Srobert memcpy(buf, vendor.data(), vendor.size());
97505edf1c1Srobert buf += vendor.size() + 1;
97605edf1c1Srobert
97705edf1c1Srobert *buf = ELFAttrs::File;
97805edf1c1Srobert write32(buf + 1, end - buf);
97905edf1c1Srobert buf += 5;
98005edf1c1Srobert
98105edf1c1Srobert for (auto &attr : intAttr) {
98205edf1c1Srobert if (attr.second == 0)
98305edf1c1Srobert continue;
98405edf1c1Srobert buf += encodeULEB128(attr.first, buf);
98505edf1c1Srobert buf += encodeULEB128(attr.second, buf);
98605edf1c1Srobert }
98705edf1c1Srobert for (auto &attr : strAttr) {
98805edf1c1Srobert if (attr.second.empty())
98905edf1c1Srobert continue;
99005edf1c1Srobert buf += encodeULEB128(attr.first, buf);
99105edf1c1Srobert memcpy(buf, attr.second.data(), attr.second.size());
99205edf1c1Srobert buf += attr.second.size() + 1;
99305edf1c1Srobert }
99405edf1c1Srobert }
99505edf1c1Srobert
mergeRISCVAttributesSections()99605edf1c1Srobert void elf::mergeRISCVAttributesSections() {
99705edf1c1Srobert // Find the first input SHT_RISCV_ATTRIBUTES; return if not found.
99805edf1c1Srobert size_t place =
99905edf1c1Srobert llvm::find_if(ctx.inputSections,
100005edf1c1Srobert [](auto *s) { return s->type == SHT_RISCV_ATTRIBUTES; }) -
100105edf1c1Srobert ctx.inputSections.begin();
100205edf1c1Srobert if (place == ctx.inputSections.size())
100305edf1c1Srobert return;
100405edf1c1Srobert
100505edf1c1Srobert // Extract all SHT_RISCV_ATTRIBUTES sections into `sections`.
100605edf1c1Srobert SmallVector<InputSectionBase *, 0> sections;
100705edf1c1Srobert llvm::erase_if(ctx.inputSections, [&](InputSectionBase *s) {
100805edf1c1Srobert if (s->type != SHT_RISCV_ATTRIBUTES)
100905edf1c1Srobert return false;
101005edf1c1Srobert sections.push_back(s);
101105edf1c1Srobert return true;
101205edf1c1Srobert });
101305edf1c1Srobert
101405edf1c1Srobert // Add the merged section.
101505edf1c1Srobert ctx.inputSections.insert(ctx.inputSections.begin() + place,
101605edf1c1Srobert mergeAttributesSection(sections));
101705edf1c1Srobert }
101805edf1c1Srobert
getRISCVTargetInfo()1019bb684c34Spatrick TargetInfo *elf::getRISCVTargetInfo() {
1020ece8a530Spatrick static RISCV target;
1021ece8a530Spatrick return ⌖
1022ece8a530Spatrick }
1023