1 | //===-- RISCVMCExpr.cpp - RISC-V specific MC expression classes -----------===// |
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 | // This file contains the implementation of the assembly expression modifiers |
10 | // accepted by the RISC-V architecture (e.g. ":lo12:", ":gottprel_g1:", ...). |
11 | // |
12 | //===----------------------------------------------------------------------===// |
13 | |
14 | #include "RISCVMCExpr.h" |
15 | #include "MCTargetDesc/RISCVAsmBackend.h" |
16 | #include "RISCVFixupKinds.h" |
17 | #include "llvm/BinaryFormat/ELF.h" |
18 | #include "llvm/MC/MCAssembler.h" |
19 | #include "llvm/MC/MCContext.h" |
20 | #include "llvm/MC/MCStreamer.h" |
21 | #include "llvm/MC/MCSymbolELF.h" |
22 | #include "llvm/MC/MCValue.h" |
23 | #include "llvm/Support/Casting.h" |
24 | #include "llvm/Support/ErrorHandling.h" |
25 | |
26 | using namespace llvm; |
27 | |
28 | #define DEBUG_TYPE "riscvmcexpr" |
29 | |
30 | const RISCVMCExpr *RISCVMCExpr::create(const MCExpr *Expr, VariantKind Kind, |
31 | MCContext &Ctx) { |
32 | return new (Ctx) RISCVMCExpr(Expr, Kind); |
33 | } |
34 | |
35 | void RISCVMCExpr::printImpl(raw_ostream &OS, const MCAsmInfo *MAI) const { |
36 | VariantKind Kind = getKind(); |
37 | bool HasVariant = ((Kind != VK_RISCV_None) && (Kind != VK_RISCV_CALL) && |
38 | (Kind != VK_RISCV_CALL_PLT)); |
39 | |
40 | if (HasVariant) |
41 | OS << '%' << getVariantKindName(Kind: getKind()) << '('; |
42 | Expr->print(OS, MAI); |
43 | if (HasVariant) |
44 | OS << ')'; |
45 | } |
46 | |
47 | const MCFixup *RISCVMCExpr::getPCRelHiFixup(const MCFragment **DFOut) const { |
48 | MCValue AUIPCLoc; |
49 | if (!getSubExpr()->evaluateAsRelocatable(Res&: AUIPCLoc, Asm: nullptr, Fixup: nullptr)) |
50 | return nullptr; |
51 | |
52 | const MCSymbolRefExpr *AUIPCSRE = AUIPCLoc.getSymA(); |
53 | if (!AUIPCSRE) |
54 | return nullptr; |
55 | |
56 | const MCSymbol *AUIPCSymbol = &AUIPCSRE->getSymbol(); |
57 | const auto *DF = dyn_cast_or_null<MCDataFragment>(Val: AUIPCSymbol->getFragment()); |
58 | |
59 | if (!DF) |
60 | return nullptr; |
61 | |
62 | uint64_t Offset = AUIPCSymbol->getOffset(); |
63 | if (DF->getContents().size() == Offset) { |
64 | DF = dyn_cast_or_null<MCDataFragment>(Val: DF->getNext()); |
65 | if (!DF) |
66 | return nullptr; |
67 | Offset = 0; |
68 | } |
69 | |
70 | for (const MCFixup &F : DF->getFixups()) { |
71 | if (F.getOffset() != Offset) |
72 | continue; |
73 | |
74 | switch ((unsigned)F.getKind()) { |
75 | default: |
76 | continue; |
77 | case RISCV::fixup_riscv_got_hi20: |
78 | case RISCV::fixup_riscv_tls_got_hi20: |
79 | case RISCV::fixup_riscv_tls_gd_hi20: |
80 | case RISCV::fixup_riscv_pcrel_hi20: |
81 | case RISCV::fixup_riscv_tlsdesc_hi20: |
82 | if (DFOut) |
83 | *DFOut = DF; |
84 | return &F; |
85 | } |
86 | } |
87 | |
88 | return nullptr; |
89 | } |
90 | |
91 | bool RISCVMCExpr::evaluateAsRelocatableImpl(MCValue &Res, |
92 | const MCAssembler *Asm, |
93 | const MCFixup *Fixup) const { |
94 | // Explicitly drop the layout and assembler to prevent any symbolic folding in |
95 | // the expression handling. This is required to preserve symbolic difference |
96 | // expressions to emit the paired relocations. |
97 | if (!getSubExpr()->evaluateAsRelocatable(Res, Asm: nullptr, Fixup: nullptr)) |
98 | return false; |
99 | |
100 | Res = |
101 | MCValue::get(SymA: Res.getSymA(), SymB: Res.getSymB(), Val: Res.getConstant(), RefKind: getKind()); |
102 | // Custom fixup types are not valid with symbol difference expressions. |
103 | return Res.getSymB() ? getKind() == VK_RISCV_None : true; |
104 | } |
105 | |
106 | void RISCVMCExpr::visitUsedExpr(MCStreamer &Streamer) const { |
107 | Streamer.visitUsedExpr(Expr: *getSubExpr()); |
108 | } |
109 | |
110 | RISCVMCExpr::VariantKind RISCVMCExpr::getVariantKindForName(StringRef name) { |
111 | return StringSwitch<RISCVMCExpr::VariantKind>(name) |
112 | .Case(S: "lo" , Value: VK_RISCV_LO) |
113 | .Case(S: "hi" , Value: VK_RISCV_HI) |
114 | .Case(S: "pcrel_lo" , Value: VK_RISCV_PCREL_LO) |
115 | .Case(S: "pcrel_hi" , Value: VK_RISCV_PCREL_HI) |
116 | .Case(S: "got_pcrel_hi" , Value: VK_RISCV_GOT_HI) |
117 | .Case(S: "tprel_lo" , Value: VK_RISCV_TPREL_LO) |
118 | .Case(S: "tprel_hi" , Value: VK_RISCV_TPREL_HI) |
119 | .Case(S: "tprel_add" , Value: VK_RISCV_TPREL_ADD) |
120 | .Case(S: "tls_ie_pcrel_hi" , Value: VK_RISCV_TLS_GOT_HI) |
121 | .Case(S: "tls_gd_pcrel_hi" , Value: VK_RISCV_TLS_GD_HI) |
122 | .Case(S: "tlsdesc_hi" , Value: VK_RISCV_TLSDESC_HI) |
123 | .Case(S: "tlsdesc_load_lo" , Value: VK_RISCV_TLSDESC_LOAD_LO) |
124 | .Case(S: "tlsdesc_add_lo" , Value: VK_RISCV_TLSDESC_ADD_LO) |
125 | .Case(S: "tlsdesc_call" , Value: VK_RISCV_TLSDESC_CALL) |
126 | .Default(Value: VK_RISCV_Invalid); |
127 | } |
128 | |
129 | StringRef RISCVMCExpr::getVariantKindName(VariantKind Kind) { |
130 | switch (Kind) { |
131 | case VK_RISCV_Invalid: |
132 | case VK_RISCV_None: |
133 | llvm_unreachable("Invalid ELF symbol kind" ); |
134 | case VK_RISCV_LO: |
135 | return "lo" ; |
136 | case VK_RISCV_HI: |
137 | return "hi" ; |
138 | case VK_RISCV_PCREL_LO: |
139 | return "pcrel_lo" ; |
140 | case VK_RISCV_PCREL_HI: |
141 | return "pcrel_hi" ; |
142 | case VK_RISCV_GOT_HI: |
143 | return "got_pcrel_hi" ; |
144 | case VK_RISCV_TPREL_LO: |
145 | return "tprel_lo" ; |
146 | case VK_RISCV_TPREL_HI: |
147 | return "tprel_hi" ; |
148 | case VK_RISCV_TPREL_ADD: |
149 | return "tprel_add" ; |
150 | case VK_RISCV_TLS_GOT_HI: |
151 | return "tls_ie_pcrel_hi" ; |
152 | case VK_RISCV_TLSDESC_HI: |
153 | return "tlsdesc_hi" ; |
154 | case VK_RISCV_TLSDESC_LOAD_LO: |
155 | return "tlsdesc_load_lo" ; |
156 | case VK_RISCV_TLSDESC_ADD_LO: |
157 | return "tlsdesc_add_lo" ; |
158 | case VK_RISCV_TLSDESC_CALL: |
159 | return "tlsdesc_call" ; |
160 | case VK_RISCV_TLS_GD_HI: |
161 | return "tls_gd_pcrel_hi" ; |
162 | case VK_RISCV_CALL: |
163 | return "call" ; |
164 | case VK_RISCV_CALL_PLT: |
165 | return "call_plt" ; |
166 | case VK_RISCV_32_PCREL: |
167 | return "32_pcrel" ; |
168 | } |
169 | llvm_unreachable("Invalid ELF symbol kind" ); |
170 | } |
171 | |
172 | static void fixELFSymbolsInTLSFixupsImpl(const MCExpr *Expr, MCAssembler &Asm) { |
173 | switch (Expr->getKind()) { |
174 | case MCExpr::Target: |
175 | llvm_unreachable("Can't handle nested target expression" ); |
176 | break; |
177 | case MCExpr::Constant: |
178 | break; |
179 | |
180 | case MCExpr::Binary: { |
181 | const MCBinaryExpr *BE = cast<MCBinaryExpr>(Val: Expr); |
182 | fixELFSymbolsInTLSFixupsImpl(Expr: BE->getLHS(), Asm); |
183 | fixELFSymbolsInTLSFixupsImpl(Expr: BE->getRHS(), Asm); |
184 | break; |
185 | } |
186 | |
187 | case MCExpr::SymbolRef: { |
188 | // We're known to be under a TLS fixup, so any symbol should be |
189 | // modified. There should be only one. |
190 | const MCSymbolRefExpr &SymRef = *cast<MCSymbolRefExpr>(Val: Expr); |
191 | cast<MCSymbolELF>(Val: SymRef.getSymbol()).setType(ELF::STT_TLS); |
192 | break; |
193 | } |
194 | |
195 | case MCExpr::Unary: |
196 | fixELFSymbolsInTLSFixupsImpl(Expr: cast<MCUnaryExpr>(Val: Expr)->getSubExpr(), Asm); |
197 | break; |
198 | } |
199 | } |
200 | |
201 | void RISCVMCExpr::fixELFSymbolsInTLSFixups(MCAssembler &Asm) const { |
202 | switch (getKind()) { |
203 | default: |
204 | return; |
205 | case VK_RISCV_TPREL_HI: |
206 | case VK_RISCV_TLS_GOT_HI: |
207 | case VK_RISCV_TLS_GD_HI: |
208 | case VK_RISCV_TLSDESC_HI: |
209 | break; |
210 | } |
211 | |
212 | fixELFSymbolsInTLSFixupsImpl(Expr: getSubExpr(), Asm); |
213 | } |
214 | |
215 | bool RISCVMCExpr::evaluateAsConstant(int64_t &Res) const { |
216 | MCValue Value; |
217 | |
218 | if (Kind == VK_RISCV_PCREL_HI || Kind == VK_RISCV_PCREL_LO || |
219 | Kind == VK_RISCV_GOT_HI || Kind == VK_RISCV_TPREL_HI || |
220 | Kind == VK_RISCV_TPREL_LO || Kind == VK_RISCV_TPREL_ADD || |
221 | Kind == VK_RISCV_TLS_GOT_HI || Kind == VK_RISCV_TLS_GD_HI || |
222 | Kind == VK_RISCV_TLSDESC_HI || Kind == VK_RISCV_TLSDESC_LOAD_LO || |
223 | Kind == VK_RISCV_TLSDESC_ADD_LO || Kind == VK_RISCV_TLSDESC_CALL || |
224 | Kind == VK_RISCV_CALL || Kind == VK_RISCV_CALL_PLT) |
225 | return false; |
226 | |
227 | if (!getSubExpr()->evaluateAsRelocatable(Res&: Value, Asm: nullptr, Fixup: nullptr)) |
228 | return false; |
229 | |
230 | if (!Value.isAbsolute()) |
231 | return false; |
232 | |
233 | Res = evaluateAsInt64(Value: Value.getConstant()); |
234 | return true; |
235 | } |
236 | |
237 | int64_t RISCVMCExpr::evaluateAsInt64(int64_t Value) const { |
238 | switch (Kind) { |
239 | default: |
240 | llvm_unreachable("Invalid kind" ); |
241 | case VK_RISCV_LO: |
242 | return SignExtend64<12>(x: Value); |
243 | case VK_RISCV_HI: |
244 | // Add 1 if bit 11 is 1, to compensate for low 12 bits being negative. |
245 | return ((Value + 0x800) >> 12) & 0xfffff; |
246 | } |
247 | } |
248 | |