1 | //===-- RISCVELFObjectWriter.cpp - RISC-V 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/RISCVMCAsmInfo.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/MC/MCValue.h" |
17 | #include "llvm/Support/ErrorHandling.h" |
18 | |
19 | using namespace llvm; |
20 | |
21 | namespace { |
22 | class RISCVELFObjectWriter : public MCELFObjectTargetWriter { |
23 | public: |
24 | RISCVELFObjectWriter(uint8_t OSABI, bool Is64Bit); |
25 | |
26 | ~RISCVELFObjectWriter() override; |
27 | |
28 | // Return true if the given relocation must be with a symbol rather than |
29 | // section plus offset. |
30 | bool needsRelocateWithSymbol(const MCValue &, unsigned Type) const override { |
31 | // TODO: this is very conservative, update once RISC-V psABI requirements |
32 | // are clarified. |
33 | return true; |
34 | } |
35 | |
36 | protected: |
37 | unsigned getRelocType(const MCFixup &, const MCValue &, |
38 | bool IsPCRel) const override; |
39 | }; |
40 | } |
41 | |
42 | RISCVELFObjectWriter::RISCVELFObjectWriter(uint8_t OSABI, bool Is64Bit) |
43 | : MCELFObjectTargetWriter(Is64Bit, OSABI, ELF::EM_RISCV, |
44 | /*HasRelocationAddend*/ true) {} |
45 | |
46 | RISCVELFObjectWriter::~RISCVELFObjectWriter() = default; |
47 | |
48 | unsigned RISCVELFObjectWriter::getRelocType(const MCFixup &Fixup, |
49 | const MCValue &Target, |
50 | bool IsPCRel) const { |
51 | unsigned Kind = Fixup.getTargetKind(); |
52 | auto Spec = Target.getSpecifier(); |
53 | switch (Spec) { |
54 | case ELF::R_RISCV_TPREL_HI20: |
55 | case ELF::R_RISCV_TLS_GOT_HI20: |
56 | case ELF::R_RISCV_TLS_GD_HI20: |
57 | case ELF::R_RISCV_TLSDESC_HI20: |
58 | if (auto *SA = Target.getAddSym()) |
59 | cast<MCSymbolELF>(Val: SA)->setType(ELF::STT_TLS); |
60 | break; |
61 | case ELF::R_RISCV_PLT32: |
62 | case ELF::R_RISCV_GOT32_PCREL: |
63 | if (Kind == FK_Data_4) |
64 | break; |
65 | reportError(L: Fixup.getLoc(), Msg: "%" + RISCV::getSpecifierName(Kind: Spec) + |
66 | " can only be used in a .word directive" ); |
67 | return ELF::R_RISCV_NONE; |
68 | default: |
69 | break; |
70 | } |
71 | |
72 | // Extract the relocation type from the fixup kind, after applying STT_TLS as |
73 | // needed. |
74 | if (mc::isRelocation(FixupKind: Fixup.getKind())) |
75 | return Kind; |
76 | |
77 | if (IsPCRel) { |
78 | switch (Kind) { |
79 | default: |
80 | reportError(L: Fixup.getLoc(), Msg: "unsupported relocation type" ); |
81 | return ELF::R_RISCV_NONE; |
82 | case FK_Data_4: |
83 | return ELF::R_RISCV_32_PCREL; |
84 | case RISCV::fixup_riscv_pcrel_hi20: |
85 | return ELF::R_RISCV_PCREL_HI20; |
86 | case RISCV::fixup_riscv_pcrel_lo12_i: |
87 | return ELF::R_RISCV_PCREL_LO12_I; |
88 | case RISCV::fixup_riscv_pcrel_lo12_s: |
89 | return ELF::R_RISCV_PCREL_LO12_S; |
90 | case RISCV::fixup_riscv_jal: |
91 | return ELF::R_RISCV_JAL; |
92 | case RISCV::fixup_riscv_branch: |
93 | return ELF::R_RISCV_BRANCH; |
94 | case RISCV::fixup_riscv_rvc_jump: |
95 | return ELF::R_RISCV_RVC_JUMP; |
96 | case RISCV::fixup_riscv_rvc_branch: |
97 | return ELF::R_RISCV_RVC_BRANCH; |
98 | case RISCV::fixup_riscv_call: |
99 | return ELF::R_RISCV_CALL_PLT; |
100 | case RISCV::fixup_riscv_call_plt: |
101 | return ELF::R_RISCV_CALL_PLT; |
102 | case RISCV::fixup_riscv_qc_e_branch: |
103 | return ELF::R_RISCV_QC_E_BRANCH; |
104 | case RISCV::fixup_riscv_qc_e_call_plt: |
105 | return ELF::R_RISCV_QC_E_CALL_PLT; |
106 | case RISCV::fixup_riscv_nds_branch_10: |
107 | return ELF::R_RISCV_NDS_BRANCH_10; |
108 | } |
109 | } |
110 | |
111 | switch (Kind) { |
112 | default: |
113 | reportError(L: Fixup.getLoc(), Msg: "unsupported relocation type" ); |
114 | return ELF::R_RISCV_NONE; |
115 | |
116 | case FK_Data_1: |
117 | reportError(L: Fixup.getLoc(), Msg: "1-byte data relocations not supported" ); |
118 | return ELF::R_RISCV_NONE; |
119 | case FK_Data_2: |
120 | reportError(L: Fixup.getLoc(), Msg: "2-byte data relocations not supported" ); |
121 | return ELF::R_RISCV_NONE; |
122 | case FK_Data_4: |
123 | switch (Spec) { |
124 | case ELF::R_RISCV_32_PCREL: |
125 | case ELF::R_RISCV_GOT32_PCREL: |
126 | case ELF::R_RISCV_PLT32: |
127 | return Spec; |
128 | } |
129 | return ELF::R_RISCV_32; |
130 | case FK_Data_8: |
131 | return ELF::R_RISCV_64; |
132 | case RISCV::fixup_riscv_hi20: |
133 | return ELF::R_RISCV_HI20; |
134 | case RISCV::fixup_riscv_lo12_i: |
135 | return ELF::R_RISCV_LO12_I; |
136 | case RISCV::fixup_riscv_lo12_s: |
137 | return ELF::R_RISCV_LO12_S; |
138 | case RISCV::fixup_riscv_qc_e_32: |
139 | return ELF::R_RISCV_QC_E_32; |
140 | case RISCV::fixup_riscv_qc_abs20_u: |
141 | return ELF::R_RISCV_QC_ABS20_U; |
142 | } |
143 | } |
144 | |
145 | std::unique_ptr<MCObjectTargetWriter> |
146 | llvm::createRISCVELFObjectWriter(uint8_t OSABI, bool Is64Bit) { |
147 | return std::make_unique<RISCVELFObjectWriter>(args&: OSABI, args&: Is64Bit); |
148 | } |
149 | |