xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp (revision 480093f4440d54b30b3025afeac24b48f2ba7a2e)
1 //===-- RISCVMCExpr.cpp - RISCV 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 RISCV architecture (e.g. ":lo12:", ":gottprel_g1:", ...).
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #include "RISCVMCExpr.h"
15 #include "MCTargetDesc/RISCVAsmBackend.h"
16 #include "RISCV.h"
17 #include "RISCVFixupKinds.h"
18 #include "llvm/BinaryFormat/ELF.h"
19 #include "llvm/MC/MCAsmLayout.h"
20 #include "llvm/MC/MCAssembler.h"
21 #include "llvm/MC/MCContext.h"
22 #include "llvm/MC/MCStreamer.h"
23 #include "llvm/MC/MCSymbolELF.h"
24 #include "llvm/MC/MCValue.h"
25 #include "llvm/Support/ErrorHandling.h"
26 
27 using namespace llvm;
28 
29 #define DEBUG_TYPE "riscvmcexpr"
30 
31 const RISCVMCExpr *RISCVMCExpr::create(const MCExpr *Expr, VariantKind Kind,
32                                        MCContext &Ctx) {
33   return new (Ctx) RISCVMCExpr(Expr, Kind);
34 }
35 
36 void RISCVMCExpr::printImpl(raw_ostream &OS, const MCAsmInfo *MAI) const {
37   VariantKind Kind = getKind();
38   bool HasVariant = ((Kind != VK_RISCV_None) && (Kind != VK_RISCV_CALL) &&
39                      (Kind != VK_RISCV_CALL_PLT));
40 
41   if (HasVariant)
42     OS << '%' << getVariantKindName(getKind()) << '(';
43   Expr->print(OS, MAI);
44   if (Kind == VK_RISCV_CALL_PLT)
45     OS << "@plt";
46   if (HasVariant)
47     OS << ')';
48 }
49 
50 const MCFixup *RISCVMCExpr::getPCRelHiFixup() const {
51   MCValue AUIPCLoc;
52   if (!getSubExpr()->evaluateAsRelocatable(AUIPCLoc, nullptr, nullptr))
53     return nullptr;
54 
55   const MCSymbolRefExpr *AUIPCSRE = AUIPCLoc.getSymA();
56   if (!AUIPCSRE)
57     return nullptr;
58 
59   const MCSymbol *AUIPCSymbol = &AUIPCSRE->getSymbol();
60   const auto *DF = dyn_cast_or_null<MCDataFragment>(AUIPCSymbol->getFragment());
61 
62   if (!DF)
63     return nullptr;
64 
65   uint64_t Offset = AUIPCSymbol->getOffset();
66   if (DF->getContents().size() == Offset) {
67     DF = dyn_cast_or_null<MCDataFragment>(DF->getNextNode());
68     if (!DF)
69       return nullptr;
70     Offset = 0;
71   }
72 
73   for (const MCFixup &F : DF->getFixups()) {
74     if (F.getOffset() != Offset)
75       continue;
76 
77     switch ((unsigned)F.getKind()) {
78     default:
79       continue;
80     case RISCV::fixup_riscv_got_hi20:
81     case RISCV::fixup_riscv_tls_got_hi20:
82     case RISCV::fixup_riscv_tls_gd_hi20:
83     case RISCV::fixup_riscv_pcrel_hi20:
84       return &F;
85     }
86   }
87 
88   return nullptr;
89 }
90 
91 bool RISCVMCExpr::evaluatePCRelLo(MCValue &Res, const MCAsmLayout *Layout,
92                                   const MCFixup *Fixup) const {
93   // VK_RISCV_PCREL_LO has to be handled specially.  The MCExpr inside is
94   // actually the location of a auipc instruction with a VK_RISCV_PCREL_HI fixup
95   // pointing to the real target.  We need to generate an MCValue in the form of
96   // (<real target> + <offset from this fixup to the auipc fixup>).  The Fixup
97   // is pcrel relative to the VK_RISCV_PCREL_LO fixup, so we need to add the
98   // offset to the VK_RISCV_PCREL_HI Fixup from VK_RISCV_PCREL_LO to correct.
99 
100   // Don't try to evaluate if the fixup will be forced as a relocation (e.g.
101   // as linker relaxation is enabled). If we evaluated pcrel_lo in this case,
102   // the modified fixup will be converted into a relocation that no longer
103   // points to the pcrel_hi as the linker requires.
104   auto &RAB =
105       static_cast<RISCVAsmBackend &>(Layout->getAssembler().getBackend());
106   if (RAB.willForceRelocations())
107     return false;
108 
109   MCValue AUIPCLoc;
110   if (!getSubExpr()->evaluateAsValue(AUIPCLoc, *Layout))
111     return false;
112 
113   const MCSymbolRefExpr *AUIPCSRE = AUIPCLoc.getSymA();
114   // Don't try to evaluate %pcrel_hi/%pcrel_lo pairs that cross fragment
115   // boundries.
116   if (!AUIPCSRE ||
117       findAssociatedFragment() != AUIPCSRE->findAssociatedFragment())
118     return false;
119 
120   const MCSymbol *AUIPCSymbol = &AUIPCSRE->getSymbol();
121   if (!AUIPCSymbol)
122     return false;
123 
124   const MCFixup *TargetFixup = getPCRelHiFixup();
125   if (!TargetFixup)
126     return false;
127 
128   if ((unsigned)TargetFixup->getKind() != RISCV::fixup_riscv_pcrel_hi20)
129     return false;
130 
131   MCValue Target;
132   if (!TargetFixup->getValue()->evaluateAsValue(Target, *Layout))
133     return false;
134 
135   if (!Target.getSymA() || !Target.getSymA()->getSymbol().isInSection())
136     return false;
137 
138   if (&Target.getSymA()->getSymbol().getSection() !=
139       findAssociatedFragment()->getParent())
140     return false;
141 
142   // We must use TargetFixup rather than AUIPCSymbol here. They will almost
143   // always have the same offset, except for the case when AUIPCSymbol is at
144   // the end of a fragment and the fixup comes from offset 0 in the next
145   // fragment.
146   uint64_t AUIPCOffset = TargetFixup->getOffset();
147 
148   Res = MCValue::get(Target.getSymA(), nullptr,
149                      Target.getConstant() + (Fixup->getOffset() - AUIPCOffset));
150   return true;
151 }
152 
153 bool RISCVMCExpr::evaluateAsRelocatableImpl(MCValue &Res,
154                                             const MCAsmLayout *Layout,
155                                             const MCFixup *Fixup) const {
156   if (Kind == VK_RISCV_PCREL_LO && evaluatePCRelLo(Res, Layout, Fixup))
157     return true;
158 
159   if (!getSubExpr()->evaluateAsRelocatable(Res, Layout, Fixup))
160     return false;
161 
162   // Some custom fixup types are not valid with symbol difference expressions
163   if (Res.getSymA() && Res.getSymB()) {
164     switch (getKind()) {
165     default:
166       return true;
167     case VK_RISCV_LO:
168     case VK_RISCV_HI:
169     case VK_RISCV_PCREL_LO:
170     case VK_RISCV_PCREL_HI:
171     case VK_RISCV_GOT_HI:
172     case VK_RISCV_TPREL_LO:
173     case VK_RISCV_TPREL_HI:
174     case VK_RISCV_TPREL_ADD:
175     case VK_RISCV_TLS_GOT_HI:
176     case VK_RISCV_TLS_GD_HI:
177       return false;
178     }
179   }
180 
181   return true;
182 }
183 
184 void RISCVMCExpr::visitUsedExpr(MCStreamer &Streamer) const {
185   Streamer.visitUsedExpr(*getSubExpr());
186 }
187 
188 RISCVMCExpr::VariantKind RISCVMCExpr::getVariantKindForName(StringRef name) {
189   return StringSwitch<RISCVMCExpr::VariantKind>(name)
190       .Case("lo", VK_RISCV_LO)
191       .Case("hi", VK_RISCV_HI)
192       .Case("pcrel_lo", VK_RISCV_PCREL_LO)
193       .Case("pcrel_hi", VK_RISCV_PCREL_HI)
194       .Case("got_pcrel_hi", VK_RISCV_GOT_HI)
195       .Case("tprel_lo", VK_RISCV_TPREL_LO)
196       .Case("tprel_hi", VK_RISCV_TPREL_HI)
197       .Case("tprel_add", VK_RISCV_TPREL_ADD)
198       .Case("tls_ie_pcrel_hi", VK_RISCV_TLS_GOT_HI)
199       .Case("tls_gd_pcrel_hi", VK_RISCV_TLS_GD_HI)
200       .Default(VK_RISCV_Invalid);
201 }
202 
203 StringRef RISCVMCExpr::getVariantKindName(VariantKind Kind) {
204   switch (Kind) {
205   default:
206     llvm_unreachable("Invalid ELF symbol kind");
207   case VK_RISCV_LO:
208     return "lo";
209   case VK_RISCV_HI:
210     return "hi";
211   case VK_RISCV_PCREL_LO:
212     return "pcrel_lo";
213   case VK_RISCV_PCREL_HI:
214     return "pcrel_hi";
215   case VK_RISCV_GOT_HI:
216     return "got_pcrel_hi";
217   case VK_RISCV_TPREL_LO:
218     return "tprel_lo";
219   case VK_RISCV_TPREL_HI:
220     return "tprel_hi";
221   case VK_RISCV_TPREL_ADD:
222     return "tprel_add";
223   case VK_RISCV_TLS_GOT_HI:
224     return "tls_ie_pcrel_hi";
225   case VK_RISCV_TLS_GD_HI:
226     return "tls_gd_pcrel_hi";
227   }
228 }
229 
230 static void fixELFSymbolsInTLSFixupsImpl(const MCExpr *Expr, MCAssembler &Asm) {
231   switch (Expr->getKind()) {
232   case MCExpr::Target:
233     llvm_unreachable("Can't handle nested target expression");
234     break;
235   case MCExpr::Constant:
236     break;
237 
238   case MCExpr::Binary: {
239     const MCBinaryExpr *BE = cast<MCBinaryExpr>(Expr);
240     fixELFSymbolsInTLSFixupsImpl(BE->getLHS(), Asm);
241     fixELFSymbolsInTLSFixupsImpl(BE->getRHS(), Asm);
242     break;
243   }
244 
245   case MCExpr::SymbolRef: {
246     // We're known to be under a TLS fixup, so any symbol should be
247     // modified. There should be only one.
248     const MCSymbolRefExpr &SymRef = *cast<MCSymbolRefExpr>(Expr);
249     cast<MCSymbolELF>(SymRef.getSymbol()).setType(ELF::STT_TLS);
250     break;
251   }
252 
253   case MCExpr::Unary:
254     fixELFSymbolsInTLSFixupsImpl(cast<MCUnaryExpr>(Expr)->getSubExpr(), Asm);
255     break;
256   }
257 }
258 
259 void RISCVMCExpr::fixELFSymbolsInTLSFixups(MCAssembler &Asm) const {
260   switch (getKind()) {
261   default:
262     return;
263   case VK_RISCV_TPREL_HI:
264   case VK_RISCV_TLS_GOT_HI:
265   case VK_RISCV_TLS_GD_HI:
266     break;
267   }
268 
269   fixELFSymbolsInTLSFixupsImpl(getSubExpr(), Asm);
270 }
271 
272 bool RISCVMCExpr::evaluateAsConstant(int64_t &Res) const {
273   MCValue Value;
274 
275   if (Kind == VK_RISCV_PCREL_HI || Kind == VK_RISCV_PCREL_LO ||
276       Kind == VK_RISCV_GOT_HI || Kind == VK_RISCV_TPREL_HI ||
277       Kind == VK_RISCV_TPREL_LO || Kind == VK_RISCV_TPREL_ADD ||
278       Kind == VK_RISCV_TLS_GOT_HI || Kind == VK_RISCV_TLS_GD_HI ||
279       Kind == VK_RISCV_CALL || Kind == VK_RISCV_CALL_PLT)
280     return false;
281 
282   if (!getSubExpr()->evaluateAsRelocatable(Value, nullptr, nullptr))
283     return false;
284 
285   if (!Value.isAbsolute())
286     return false;
287 
288   Res = evaluateAsInt64(Value.getConstant());
289   return true;
290 }
291 
292 int64_t RISCVMCExpr::evaluateAsInt64(int64_t Value) const {
293   switch (Kind) {
294   default:
295     llvm_unreachable("Invalid kind");
296   case VK_RISCV_LO:
297     return SignExtend64<12>(Value);
298   case VK_RISCV_HI:
299     // Add 1 if bit 11 is 1, to compensate for low 12 bits being negative.
300     return ((Value + 0x800) >> 12) & 0xfffff;
301   }
302 }
303