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