1 | //===-- AArch64MCExpr.cpp - AArch64 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 AArch64 architecture (e.g. ":lo12:", ":gottprel_g1:", ...). |
11 | // |
12 | //===----------------------------------------------------------------------===// |
13 | |
14 | #include "AArch64MCExpr.h" |
15 | #include "llvm/BinaryFormat/ELF.h" |
16 | #include "llvm/MC/MCContext.h" |
17 | #include "llvm/MC/MCStreamer.h" |
18 | #include "llvm/MC/MCSymbolELF.h" |
19 | #include "llvm/MC/MCValue.h" |
20 | #include "llvm/Support/Casting.h" |
21 | #include "llvm/Support/ErrorHandling.h" |
22 | |
23 | using namespace llvm; |
24 | |
25 | #define DEBUG_TYPE "aarch64symbolrefexpr" |
26 | |
27 | const AArch64MCExpr *AArch64MCExpr::create(const MCExpr *Expr, VariantKind Kind, |
28 | MCContext &Ctx) { |
29 | return new (Ctx) AArch64MCExpr(Expr, Kind); |
30 | } |
31 | |
32 | StringRef AArch64MCExpr::getVariantKindName() const { |
33 | switch (static_cast<uint32_t>(getKind())) { |
34 | case VK_CALL: return "" ; |
35 | case VK_LO12: return ":lo12:" ; |
36 | case VK_ABS_G3: return ":abs_g3:" ; |
37 | case VK_ABS_G2: return ":abs_g2:" ; |
38 | case VK_ABS_G2_S: return ":abs_g2_s:" ; |
39 | case VK_ABS_G2_NC: return ":abs_g2_nc:" ; |
40 | case VK_ABS_G1: return ":abs_g1:" ; |
41 | case VK_ABS_G1_S: return ":abs_g1_s:" ; |
42 | case VK_ABS_G1_NC: return ":abs_g1_nc:" ; |
43 | case VK_ABS_G0: return ":abs_g0:" ; |
44 | case VK_ABS_G0_S: return ":abs_g0_s:" ; |
45 | case VK_ABS_G0_NC: return ":abs_g0_nc:" ; |
46 | case VK_PREL_G3: return ":prel_g3:" ; |
47 | case VK_PREL_G2: return ":prel_g2:" ; |
48 | case VK_PREL_G2_NC: return ":prel_g2_nc:" ; |
49 | case VK_PREL_G1: return ":prel_g1:" ; |
50 | case VK_PREL_G1_NC: return ":prel_g1_nc:" ; |
51 | case VK_PREL_G0: return ":prel_g0:" ; |
52 | case VK_PREL_G0_NC: return ":prel_g0_nc:" ; |
53 | case VK_DTPREL_G2: return ":dtprel_g2:" ; |
54 | case VK_DTPREL_G1: return ":dtprel_g1:" ; |
55 | case VK_DTPREL_G1_NC: return ":dtprel_g1_nc:" ; |
56 | case VK_DTPREL_G0: return ":dtprel_g0:" ; |
57 | case VK_DTPREL_G0_NC: return ":dtprel_g0_nc:" ; |
58 | case VK_DTPREL_HI12: return ":dtprel_hi12:" ; |
59 | case VK_DTPREL_LO12: return ":dtprel_lo12:" ; |
60 | case VK_DTPREL_LO12_NC: return ":dtprel_lo12_nc:" ; |
61 | case VK_TPREL_G2: return ":tprel_g2:" ; |
62 | case VK_TPREL_G1: return ":tprel_g1:" ; |
63 | case VK_TPREL_G1_NC: return ":tprel_g1_nc:" ; |
64 | case VK_TPREL_G0: return ":tprel_g0:" ; |
65 | case VK_TPREL_G0_NC: return ":tprel_g0_nc:" ; |
66 | case VK_TPREL_HI12: return ":tprel_hi12:" ; |
67 | case VK_TPREL_LO12: return ":tprel_lo12:" ; |
68 | case VK_TPREL_LO12_NC: return ":tprel_lo12_nc:" ; |
69 | case VK_TLSDESC_LO12: return ":tlsdesc_lo12:" ; |
70 | case VK_ABS_PAGE: return "" ; |
71 | case VK_ABS_PAGE_NC: return ":pg_hi21_nc:" ; |
72 | case VK_GOT: return ":got:" ; |
73 | case VK_GOT_PAGE: return ":got:" ; |
74 | case VK_GOT_PAGE_LO15: return ":gotpage_lo15:" ; |
75 | case VK_GOT_LO12: return ":got_lo12:" ; |
76 | case VK_GOTTPREL: return ":gottprel:" ; |
77 | case VK_GOTTPREL_PAGE: return ":gottprel:" ; |
78 | case VK_GOTTPREL_LO12_NC: return ":gottprel_lo12:" ; |
79 | case VK_GOTTPREL_G1: return ":gottprel_g1:" ; |
80 | case VK_GOTTPREL_G0_NC: return ":gottprel_g0_nc:" ; |
81 | case VK_TLSDESC: return "" ; |
82 | case VK_TLSDESC_PAGE: return ":tlsdesc:" ; |
83 | case VK_SECREL_LO12: return ":secrel_lo12:" ; |
84 | case VK_SECREL_HI12: return ":secrel_hi12:" ; |
85 | default: |
86 | llvm_unreachable("Invalid ELF symbol kind" ); |
87 | } |
88 | } |
89 | |
90 | void AArch64MCExpr::printImpl(raw_ostream &OS, const MCAsmInfo *MAI) const { |
91 | OS << getVariantKindName(); |
92 | Expr->print(OS, MAI); |
93 | } |
94 | |
95 | void AArch64MCExpr::visitUsedExpr(MCStreamer &Streamer) const { |
96 | Streamer.visitUsedExpr(Expr: *getSubExpr()); |
97 | } |
98 | |
99 | MCFragment *AArch64MCExpr::findAssociatedFragment() const { |
100 | llvm_unreachable("FIXME: what goes here?" ); |
101 | } |
102 | |
103 | bool AArch64MCExpr::evaluateAsRelocatableImpl(MCValue &Res, |
104 | const MCAssembler *Asm, |
105 | const MCFixup *Fixup) const { |
106 | if (!getSubExpr()->evaluateAsRelocatable(Res, Asm, Fixup)) |
107 | return false; |
108 | |
109 | Res = |
110 | MCValue::get(SymA: Res.getSymA(), SymB: Res.getSymB(), Val: Res.getConstant(), RefKind: getKind()); |
111 | |
112 | return true; |
113 | } |
114 | |
115 | static void fixELFSymbolsInTLSFixupsImpl(const MCExpr *Expr, MCAssembler &Asm) { |
116 | switch (Expr->getKind()) { |
117 | case MCExpr::Target: |
118 | llvm_unreachable("Can't handle nested target expression" ); |
119 | break; |
120 | case MCExpr::Constant: |
121 | break; |
122 | |
123 | case MCExpr::Binary: { |
124 | const MCBinaryExpr *BE = cast<MCBinaryExpr>(Val: Expr); |
125 | fixELFSymbolsInTLSFixupsImpl(Expr: BE->getLHS(), Asm); |
126 | fixELFSymbolsInTLSFixupsImpl(Expr: BE->getRHS(), Asm); |
127 | break; |
128 | } |
129 | |
130 | case MCExpr::SymbolRef: { |
131 | // We're known to be under a TLS fixup, so any symbol should be |
132 | // modified. There should be only one. |
133 | const MCSymbolRefExpr &SymRef = *cast<MCSymbolRefExpr>(Val: Expr); |
134 | cast<MCSymbolELF>(Val: SymRef.getSymbol()).setType(ELF::STT_TLS); |
135 | break; |
136 | } |
137 | |
138 | case MCExpr::Unary: |
139 | fixELFSymbolsInTLSFixupsImpl(Expr: cast<MCUnaryExpr>(Val: Expr)->getSubExpr(), Asm); |
140 | break; |
141 | } |
142 | } |
143 | |
144 | void AArch64MCExpr::fixELFSymbolsInTLSFixups(MCAssembler &Asm) const { |
145 | switch (getSymbolLoc(Kind)) { |
146 | default: |
147 | return; |
148 | case VK_DTPREL: |
149 | case VK_GOTTPREL: |
150 | case VK_TPREL: |
151 | case VK_TLSDESC: |
152 | break; |
153 | } |
154 | |
155 | fixELFSymbolsInTLSFixupsImpl(Expr: getSubExpr(), Asm); |
156 | } |
157 | |
158 | const AArch64AuthMCExpr *AArch64AuthMCExpr::create(const MCExpr *Expr, |
159 | uint16_t Discriminator, |
160 | AArch64PACKey::ID Key, |
161 | bool HasAddressDiversity, |
162 | MCContext &Ctx) { |
163 | return new (Ctx) |
164 | AArch64AuthMCExpr(Expr, Discriminator, Key, HasAddressDiversity); |
165 | } |
166 | |
167 | void AArch64AuthMCExpr::printImpl(raw_ostream &OS, const MCAsmInfo *MAI) const { |
168 | bool WrapSubExprInParens = !isa<MCSymbolRefExpr>(Val: getSubExpr()); |
169 | if (WrapSubExprInParens) |
170 | OS << '('; |
171 | getSubExpr()->print(OS, MAI); |
172 | if (WrapSubExprInParens) |
173 | OS << ')'; |
174 | |
175 | OS << "@AUTH(" << AArch64PACKeyIDToString(KeyID: Key) << ',' << Discriminator; |
176 | if (hasAddressDiversity()) |
177 | OS << ",addr" ; |
178 | OS << ')'; |
179 | } |
180 | |
181 | void AArch64AuthMCExpr::visitUsedExpr(MCStreamer &Streamer) const { |
182 | Streamer.visitUsedExpr(Expr: *getSubExpr()); |
183 | } |
184 | |
185 | MCFragment *AArch64AuthMCExpr::findAssociatedFragment() const { |
186 | llvm_unreachable("FIXME: what goes here?" ); |
187 | } |
188 | |
189 | bool AArch64AuthMCExpr::evaluateAsRelocatableImpl(MCValue &Res, |
190 | const MCAssembler *Asm, |
191 | const MCFixup *Fixup) const { |
192 | if (!getSubExpr()->evaluateAsRelocatable(Res, Asm, Fixup)) |
193 | return false; |
194 | |
195 | if (Res.getSymB()) |
196 | report_fatal_error(reason: "Auth relocation can't reference two symbols" ); |
197 | |
198 | Res = MCValue::get(SymA: Res.getSymA(), SymB: nullptr, Val: Res.getConstant(), RefKind: getKind()); |
199 | return true; |
200 | } |
201 | |