1//===-- RISCVELFObjectWriter.cpp - RISCV ELF Writer -----------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "MCTargetDesc/RISCVFixupKinds.h"
10#include "MCTargetDesc/RISCVMCExpr.h"
11#include "MCTargetDesc/RISCVMCTargetDesc.h"
12#include "llvm/MC/MCContext.h"
13#include "llvm/MC/MCELFObjectWriter.h"
14#include "llvm/MC/MCFixup.h"
15#include "llvm/MC/MCObjectWriter.h"
16#include "llvm/Support/ErrorHandling.h"
17
18using namespace llvm;
19
20namespace {
21class RISCVELFObjectWriter : public MCELFObjectTargetWriter {
22public:
23  RISCVELFObjectWriter(uint8_t OSABI, bool Is64Bit);
24
25  ~RISCVELFObjectWriter() override;
26
27  // Return true if the given relocation must be with a symbol rather than
28  // section plus offset.
29  bool needsRelocateWithSymbol(const MCSymbol &Sym,
30                               unsigned Type) const override {
31    // TODO: this is very conservative, update once RISC-V psABI requirements
32    //       are clarified.
33    return true;
34  }
35
36protected:
37  unsigned getRelocType(MCContext &Ctx, const MCValue &Target,
38                        const MCFixup &Fixup, bool IsPCRel) const override;
39};
40}
41
42RISCVELFObjectWriter::RISCVELFObjectWriter(uint8_t OSABI, bool Is64Bit)
43    : MCELFObjectTargetWriter(Is64Bit, OSABI, ELF::EM_RISCV,
44                              /*HasRelocationAddend*/ true) {}
45
46RISCVELFObjectWriter::~RISCVELFObjectWriter() {}
47
48unsigned RISCVELFObjectWriter::getRelocType(MCContext &Ctx,
49                                            const MCValue &Target,
50                                            const MCFixup &Fixup,
51                                            bool IsPCRel) const {
52  const MCExpr *Expr = Fixup.getValue();
53  // Determine the type of the relocation
54  unsigned Kind = Fixup.getTargetKind();
55  if (Kind >= FirstLiteralRelocationKind)
56    return Kind - FirstLiteralRelocationKind;
57  if (IsPCRel) {
58    switch (Kind) {
59    default:
60      Ctx.reportError(Fixup.getLoc(), "Unsupported relocation type");
61      return ELF::R_RISCV_NONE;
62    case FK_Data_4:
63    case FK_PCRel_4:
64      return ELF::R_RISCV_32_PCREL;
65    case RISCV::fixup_riscv_pcrel_hi20:
66      return ELF::R_RISCV_PCREL_HI20;
67    case RISCV::fixup_riscv_pcrel_lo12_i:
68      return ELF::R_RISCV_PCREL_LO12_I;
69    case RISCV::fixup_riscv_pcrel_lo12_s:
70      return ELF::R_RISCV_PCREL_LO12_S;
71    case RISCV::fixup_riscv_got_hi20:
72      return ELF::R_RISCV_GOT_HI20;
73    case RISCV::fixup_riscv_tls_got_hi20:
74      return ELF::R_RISCV_TLS_GOT_HI20;
75    case RISCV::fixup_riscv_tls_gd_hi20:
76      return ELF::R_RISCV_TLS_GD_HI20;
77    case RISCV::fixup_riscv_jal:
78      return ELF::R_RISCV_JAL;
79    case RISCV::fixup_riscv_branch:
80      return ELF::R_RISCV_BRANCH;
81    case RISCV::fixup_riscv_rvc_jump:
82      return ELF::R_RISCV_RVC_JUMP;
83    case RISCV::fixup_riscv_rvc_branch:
84      return ELF::R_RISCV_RVC_BRANCH;
85    case RISCV::fixup_riscv_call:
86      return ELF::R_RISCV_CALL;
87    case RISCV::fixup_riscv_call_plt:
88      return ELF::R_RISCV_CALL_PLT;
89    }
90  }
91
92  switch (Kind) {
93  default:
94    Ctx.reportError(Fixup.getLoc(), "Unsupported relocation type");
95    return ELF::R_RISCV_NONE;
96  case FK_Data_1:
97    Ctx.reportError(Fixup.getLoc(), "1-byte data relocations not supported");
98    return ELF::R_RISCV_NONE;
99  case FK_Data_2:
100    Ctx.reportError(Fixup.getLoc(), "2-byte data relocations not supported");
101    return ELF::R_RISCV_NONE;
102  case FK_Data_4:
103    if (Expr->getKind() == MCExpr::Target &&
104        cast<RISCVMCExpr>(Expr)->getKind() == RISCVMCExpr::VK_RISCV_32_PCREL)
105      return ELF::R_RISCV_32_PCREL;
106    return ELF::R_RISCV_32;
107  case FK_Data_8:
108    return ELF::R_RISCV_64;
109  case FK_Data_Add_1:
110    return ELF::R_RISCV_ADD8;
111  case FK_Data_Add_2:
112    return ELF::R_RISCV_ADD16;
113  case FK_Data_Add_4:
114    return ELF::R_RISCV_ADD32;
115  case FK_Data_Add_8:
116    return ELF::R_RISCV_ADD64;
117  case FK_Data_Add_6b:
118    return ELF::R_RISCV_SET6;
119  case FK_Data_Sub_1:
120    return ELF::R_RISCV_SUB8;
121  case FK_Data_Sub_2:
122    return ELF::R_RISCV_SUB16;
123  case FK_Data_Sub_4:
124    return ELF::R_RISCV_SUB32;
125  case FK_Data_Sub_8:
126    return ELF::R_RISCV_SUB64;
127  case FK_Data_Sub_6b:
128    return ELF::R_RISCV_SUB6;
129  case RISCV::fixup_riscv_hi20:
130    return ELF::R_RISCV_HI20;
131  case RISCV::fixup_riscv_lo12_i:
132    return ELF::R_RISCV_LO12_I;
133  case RISCV::fixup_riscv_lo12_s:
134    return ELF::R_RISCV_LO12_S;
135  case RISCV::fixup_riscv_tprel_hi20:
136    return ELF::R_RISCV_TPREL_HI20;
137  case RISCV::fixup_riscv_tprel_lo12_i:
138    return ELF::R_RISCV_TPREL_LO12_I;
139  case RISCV::fixup_riscv_tprel_lo12_s:
140    return ELF::R_RISCV_TPREL_LO12_S;
141  case RISCV::fixup_riscv_tprel_add:
142    return ELF::R_RISCV_TPREL_ADD;
143  case RISCV::fixup_riscv_relax:
144    return ELF::R_RISCV_RELAX;
145  case RISCV::fixup_riscv_align:
146    return ELF::R_RISCV_ALIGN;
147  }
148}
149
150std::unique_ptr<MCObjectTargetWriter>
151llvm::createRISCVELFObjectWriter(uint8_t OSABI, bool Is64Bit) {
152  return std::make_unique<RISCVELFObjectWriter>(OSABI, Is64Bit);
153}
154