1 | //===-- MipsMCExpr.cpp - Mips 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 | #include "MipsMCExpr.h" |
10 | #include "llvm/BinaryFormat/ELF.h" |
11 | #include "llvm/MC/MCAsmInfo.h" |
12 | #include "llvm/MC/MCAssembler.h" |
13 | #include "llvm/MC/MCContext.h" |
14 | #include "llvm/MC/MCStreamer.h" |
15 | #include "llvm/MC/MCSymbolELF.h" |
16 | #include "llvm/MC/MCValue.h" |
17 | #include "llvm/Support/Casting.h" |
18 | #include "llvm/Support/ErrorHandling.h" |
19 | #include "llvm/Support/MathExtras.h" |
20 | #include "llvm/Support/raw_ostream.h" |
21 | #include <cstdint> |
22 | |
23 | using namespace llvm; |
24 | |
25 | #define DEBUG_TYPE "mipsmcexpr" |
26 | |
27 | const MipsMCExpr *MipsMCExpr::create(MipsMCExpr::MipsExprKind Kind, |
28 | const MCExpr *Expr, MCContext &Ctx) { |
29 | return new (Ctx) MipsMCExpr(Kind, Expr); |
30 | } |
31 | |
32 | const MipsMCExpr *MipsMCExpr::createGpOff(MipsMCExpr::MipsExprKind Kind, |
33 | const MCExpr *Expr, MCContext &Ctx) { |
34 | return create(Kind, Expr: create(Kind: MEK_NEG, Expr: create(Kind: MEK_GPREL, Expr, Ctx), Ctx), Ctx); |
35 | } |
36 | |
37 | void MipsMCExpr::printImpl(raw_ostream &OS, const MCAsmInfo *MAI) const { |
38 | int64_t AbsVal; |
39 | |
40 | switch (Kind) { |
41 | case MEK_None: |
42 | case MEK_Special: |
43 | llvm_unreachable("MEK_None and MEK_Special are invalid" ); |
44 | break; |
45 | case MEK_DTPREL: |
46 | // MEK_DTPREL is used for marking TLS DIEExpr only |
47 | // and contains a regular sub-expression. |
48 | getSubExpr()->print(OS, MAI, InParens: true); |
49 | return; |
50 | case MEK_CALL_HI16: |
51 | OS << "%call_hi" ; |
52 | break; |
53 | case MEK_CALL_LO16: |
54 | OS << "%call_lo" ; |
55 | break; |
56 | case MEK_DTPREL_HI: |
57 | OS << "%dtprel_hi" ; |
58 | break; |
59 | case MEK_DTPREL_LO: |
60 | OS << "%dtprel_lo" ; |
61 | break; |
62 | case MEK_GOT: |
63 | OS << "%got" ; |
64 | break; |
65 | case MEK_GOTTPREL: |
66 | OS << "%gottprel" ; |
67 | break; |
68 | case MEK_GOT_CALL: |
69 | OS << "%call16" ; |
70 | break; |
71 | case MEK_GOT_DISP: |
72 | OS << "%got_disp" ; |
73 | break; |
74 | case MEK_GOT_HI16: |
75 | OS << "%got_hi" ; |
76 | break; |
77 | case MEK_GOT_LO16: |
78 | OS << "%got_lo" ; |
79 | break; |
80 | case MEK_GOT_PAGE: |
81 | OS << "%got_page" ; |
82 | break; |
83 | case MEK_GOT_OFST: |
84 | OS << "%got_ofst" ; |
85 | break; |
86 | case MEK_GPREL: |
87 | OS << "%gp_rel" ; |
88 | break; |
89 | case MEK_HI: |
90 | OS << "%hi" ; |
91 | break; |
92 | case MEK_HIGHER: |
93 | OS << "%higher" ; |
94 | break; |
95 | case MEK_HIGHEST: |
96 | OS << "%highest" ; |
97 | break; |
98 | case MEK_LO: |
99 | OS << "%lo" ; |
100 | break; |
101 | case MEK_NEG: |
102 | OS << "%neg" ; |
103 | break; |
104 | case MEK_PCREL_HI16: |
105 | OS << "%pcrel_hi" ; |
106 | break; |
107 | case MEK_PCREL_LO16: |
108 | OS << "%pcrel_lo" ; |
109 | break; |
110 | case MEK_TLSGD: |
111 | OS << "%tlsgd" ; |
112 | break; |
113 | case MEK_TLSLDM: |
114 | OS << "%tlsldm" ; |
115 | break; |
116 | case MEK_TPREL_HI: |
117 | OS << "%tprel_hi" ; |
118 | break; |
119 | case MEK_TPREL_LO: |
120 | OS << "%tprel_lo" ; |
121 | break; |
122 | } |
123 | |
124 | OS << '('; |
125 | if (Expr->evaluateAsAbsolute(Res&: AbsVal)) |
126 | OS << AbsVal; |
127 | else |
128 | Expr->print(OS, MAI, InParens: true); |
129 | OS << ')'; |
130 | } |
131 | |
132 | bool MipsMCExpr::evaluateAsRelocatableImpl(MCValue &Res, const MCAssembler *Asm, |
133 | const MCFixup *Fixup) const { |
134 | // Look for the %hi(%neg(%gp_rel(X))) and %lo(%neg(%gp_rel(X))) special cases. |
135 | if (isGpOff()) { |
136 | const MCExpr *SubExpr = |
137 | cast<MipsMCExpr>(Val: cast<MipsMCExpr>(Val: getSubExpr())->getSubExpr()) |
138 | ->getSubExpr(); |
139 | if (!SubExpr->evaluateAsRelocatable(Res, Asm, Fixup)) |
140 | return false; |
141 | |
142 | Res = MCValue::get(SymA: Res.getSymA(), SymB: Res.getSymB(), Val: Res.getConstant(), |
143 | RefKind: MEK_Special); |
144 | return true; |
145 | } |
146 | |
147 | if (!getSubExpr()->evaluateAsRelocatable(Res, Asm, Fixup)) |
148 | return false; |
149 | |
150 | if (Res.getRefKind() != MCSymbolRefExpr::VK_None) |
151 | return false; |
152 | |
153 | // evaluateAsAbsolute() and evaluateAsValue() require that we evaluate the |
154 | // %hi/%lo/etc. here. Fixup is a null pointer when either of these is the |
155 | // caller. |
156 | if (Res.isAbsolute() && Fixup == nullptr) { |
157 | int64_t AbsVal = Res.getConstant(); |
158 | switch (Kind) { |
159 | case MEK_None: |
160 | case MEK_Special: |
161 | llvm_unreachable("MEK_None and MEK_Special are invalid" ); |
162 | case MEK_DTPREL: |
163 | // MEK_DTPREL is used for marking TLS DIEExpr only |
164 | // and contains a regular sub-expression. |
165 | return getSubExpr()->evaluateAsRelocatable(Res, Asm, Fixup); |
166 | case MEK_DTPREL_HI: |
167 | case MEK_DTPREL_LO: |
168 | case MEK_GOT: |
169 | case MEK_GOTTPREL: |
170 | case MEK_GOT_CALL: |
171 | case MEK_GOT_DISP: |
172 | case MEK_GOT_HI16: |
173 | case MEK_GOT_LO16: |
174 | case MEK_GOT_OFST: |
175 | case MEK_GOT_PAGE: |
176 | case MEK_GPREL: |
177 | case MEK_PCREL_HI16: |
178 | case MEK_PCREL_LO16: |
179 | case MEK_TLSGD: |
180 | case MEK_TLSLDM: |
181 | case MEK_TPREL_HI: |
182 | case MEK_TPREL_LO: |
183 | return false; |
184 | case MEK_LO: |
185 | case MEK_CALL_LO16: |
186 | AbsVal = SignExtend64<16>(x: AbsVal); |
187 | break; |
188 | case MEK_CALL_HI16: |
189 | case MEK_HI: |
190 | AbsVal = SignExtend64<16>(x: (AbsVal + 0x8000) >> 16); |
191 | break; |
192 | case MEK_HIGHER: |
193 | AbsVal = SignExtend64<16>(x: (AbsVal + 0x80008000LL) >> 32); |
194 | break; |
195 | case MEK_HIGHEST: |
196 | AbsVal = SignExtend64<16>(x: (AbsVal + 0x800080008000LL) >> 48); |
197 | break; |
198 | case MEK_NEG: |
199 | AbsVal = -AbsVal; |
200 | break; |
201 | } |
202 | Res = MCValue::get(Val: AbsVal); |
203 | return true; |
204 | } |
205 | |
206 | // We want to defer it for relocatable expressions since the constant is |
207 | // applied to the whole symbol value. |
208 | // |
209 | // The value of getKind() that is given to MCValue is only intended to aid |
210 | // debugging when inspecting MCValue objects. It shouldn't be relied upon |
211 | // for decision making. |
212 | Res = |
213 | MCValue::get(SymA: Res.getSymA(), SymB: Res.getSymB(), Val: Res.getConstant(), RefKind: getKind()); |
214 | |
215 | return true; |
216 | } |
217 | |
218 | void MipsMCExpr::visitUsedExpr(MCStreamer &Streamer) const { |
219 | Streamer.visitUsedExpr(Expr: *getSubExpr()); |
220 | } |
221 | |
222 | static void fixELFSymbolsInTLSFixupsImpl(const MCExpr *Expr, MCAssembler &Asm) { |
223 | switch (Expr->getKind()) { |
224 | case MCExpr::Target: |
225 | fixELFSymbolsInTLSFixupsImpl(Expr: cast<MipsMCExpr>(Val: Expr)->getSubExpr(), Asm); |
226 | break; |
227 | case MCExpr::Constant: |
228 | break; |
229 | case MCExpr::Binary: { |
230 | const MCBinaryExpr *BE = cast<MCBinaryExpr>(Val: Expr); |
231 | fixELFSymbolsInTLSFixupsImpl(Expr: BE->getLHS(), Asm); |
232 | fixELFSymbolsInTLSFixupsImpl(Expr: BE->getRHS(), Asm); |
233 | break; |
234 | } |
235 | case MCExpr::SymbolRef: { |
236 | // We're known to be under a TLS fixup, so any symbol should be |
237 | // modified. There should be only one. |
238 | const MCSymbolRefExpr &SymRef = *cast<MCSymbolRefExpr>(Val: Expr); |
239 | cast<MCSymbolELF>(Val: SymRef.getSymbol()).setType(ELF::STT_TLS); |
240 | break; |
241 | } |
242 | case MCExpr::Unary: |
243 | fixELFSymbolsInTLSFixupsImpl(Expr: cast<MCUnaryExpr>(Val: Expr)->getSubExpr(), Asm); |
244 | break; |
245 | } |
246 | } |
247 | |
248 | void MipsMCExpr::fixELFSymbolsInTLSFixups(MCAssembler &Asm) const { |
249 | switch (getKind()) { |
250 | case MEK_None: |
251 | case MEK_Special: |
252 | llvm_unreachable("MEK_None and MEK_Special are invalid" ); |
253 | break; |
254 | case MEK_CALL_HI16: |
255 | case MEK_CALL_LO16: |
256 | case MEK_GOT: |
257 | case MEK_GOT_CALL: |
258 | case MEK_GOT_DISP: |
259 | case MEK_GOT_HI16: |
260 | case MEK_GOT_LO16: |
261 | case MEK_GOT_OFST: |
262 | case MEK_GOT_PAGE: |
263 | case MEK_GPREL: |
264 | case MEK_HI: |
265 | case MEK_HIGHER: |
266 | case MEK_HIGHEST: |
267 | case MEK_LO: |
268 | case MEK_NEG: |
269 | case MEK_PCREL_HI16: |
270 | case MEK_PCREL_LO16: |
271 | // If we do have nested target-specific expressions, they will be in |
272 | // a consecutive chain. |
273 | if (const MipsMCExpr *E = dyn_cast<const MipsMCExpr>(Val: getSubExpr())) |
274 | E->fixELFSymbolsInTLSFixups(Asm); |
275 | break; |
276 | case MEK_DTPREL: |
277 | case MEK_DTPREL_HI: |
278 | case MEK_DTPREL_LO: |
279 | case MEK_TLSLDM: |
280 | case MEK_TLSGD: |
281 | case MEK_GOTTPREL: |
282 | case MEK_TPREL_HI: |
283 | case MEK_TPREL_LO: |
284 | fixELFSymbolsInTLSFixupsImpl(Expr: getSubExpr(), Asm); |
285 | break; |
286 | } |
287 | } |
288 | |
289 | bool MipsMCExpr::isGpOff(MipsExprKind &Kind) const { |
290 | if (getKind() == MEK_HI || getKind() == MEK_LO) { |
291 | if (const MipsMCExpr *S1 = dyn_cast<const MipsMCExpr>(Val: getSubExpr())) { |
292 | if (const MipsMCExpr *S2 = dyn_cast<const MipsMCExpr>(Val: S1->getSubExpr())) { |
293 | if (S1->getKind() == MEK_NEG && S2->getKind() == MEK_GPREL) { |
294 | Kind = getKind(); |
295 | return true; |
296 | } |
297 | } |
298 | } |
299 | } |
300 | return false; |
301 | } |
302 | |