10b57cec5SDimitry Andric //===-- AArch64MCExpr.cpp - AArch64 specific MC expression classes --------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This file contains the implementation of the assembly expression modifiers
100b57cec5SDimitry Andric // accepted by the AArch64 architecture (e.g. ":lo12:", ":gottprel_g1:", ...).
110b57cec5SDimitry Andric //
120b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
130b57cec5SDimitry Andric
140b57cec5SDimitry Andric #include "AArch64MCExpr.h"
150b57cec5SDimitry Andric #include "llvm/BinaryFormat/ELF.h"
160b57cec5SDimitry Andric #include "llvm/MC/MCContext.h"
170b57cec5SDimitry Andric #include "llvm/MC/MCStreamer.h"
180b57cec5SDimitry Andric #include "llvm/MC/MCSymbolELF.h"
190b57cec5SDimitry Andric #include "llvm/MC/MCValue.h"
2081ad6265SDimitry Andric #include "llvm/Support/Casting.h"
210b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h"
220b57cec5SDimitry Andric
230b57cec5SDimitry Andric using namespace llvm;
240b57cec5SDimitry Andric
250b57cec5SDimitry Andric #define DEBUG_TYPE "aarch64symbolrefexpr"
260b57cec5SDimitry Andric
create(const MCExpr * Expr,VariantKind Kind,MCContext & Ctx)270b57cec5SDimitry Andric const AArch64MCExpr *AArch64MCExpr::create(const MCExpr *Expr, VariantKind Kind,
280b57cec5SDimitry Andric MCContext &Ctx) {
290b57cec5SDimitry Andric return new (Ctx) AArch64MCExpr(Expr, Kind);
300b57cec5SDimitry Andric }
310b57cec5SDimitry Andric
getVariantKindName() const320b57cec5SDimitry Andric StringRef AArch64MCExpr::getVariantKindName() const {
330b57cec5SDimitry Andric switch (static_cast<uint32_t>(getKind())) {
340b57cec5SDimitry Andric case VK_CALL: return "";
350b57cec5SDimitry Andric case VK_LO12: return ":lo12:";
360b57cec5SDimitry Andric case VK_ABS_G3: return ":abs_g3:";
370b57cec5SDimitry Andric case VK_ABS_G2: return ":abs_g2:";
380b57cec5SDimitry Andric case VK_ABS_G2_S: return ":abs_g2_s:";
390b57cec5SDimitry Andric case VK_ABS_G2_NC: return ":abs_g2_nc:";
400b57cec5SDimitry Andric case VK_ABS_G1: return ":abs_g1:";
410b57cec5SDimitry Andric case VK_ABS_G1_S: return ":abs_g1_s:";
420b57cec5SDimitry Andric case VK_ABS_G1_NC: return ":abs_g1_nc:";
430b57cec5SDimitry Andric case VK_ABS_G0: return ":abs_g0:";
440b57cec5SDimitry Andric case VK_ABS_G0_S: return ":abs_g0_s:";
450b57cec5SDimitry Andric case VK_ABS_G0_NC: return ":abs_g0_nc:";
468bcb0991SDimitry Andric case VK_PREL_G3: return ":prel_g3:";
478bcb0991SDimitry Andric case VK_PREL_G2: return ":prel_g2:";
488bcb0991SDimitry Andric case VK_PREL_G2_NC: return ":prel_g2_nc:";
498bcb0991SDimitry Andric case VK_PREL_G1: return ":prel_g1:";
508bcb0991SDimitry Andric case VK_PREL_G1_NC: return ":prel_g1_nc:";
518bcb0991SDimitry Andric case VK_PREL_G0: return ":prel_g0:";
528bcb0991SDimitry Andric case VK_PREL_G0_NC: return ":prel_g0_nc:";
530b57cec5SDimitry Andric case VK_DTPREL_G2: return ":dtprel_g2:";
540b57cec5SDimitry Andric case VK_DTPREL_G1: return ":dtprel_g1:";
550b57cec5SDimitry Andric case VK_DTPREL_G1_NC: return ":dtprel_g1_nc:";
560b57cec5SDimitry Andric case VK_DTPREL_G0: return ":dtprel_g0:";
570b57cec5SDimitry Andric case VK_DTPREL_G0_NC: return ":dtprel_g0_nc:";
580b57cec5SDimitry Andric case VK_DTPREL_HI12: return ":dtprel_hi12:";
590b57cec5SDimitry Andric case VK_DTPREL_LO12: return ":dtprel_lo12:";
600b57cec5SDimitry Andric case VK_DTPREL_LO12_NC: return ":dtprel_lo12_nc:";
610b57cec5SDimitry Andric case VK_TPREL_G2: return ":tprel_g2:";
620b57cec5SDimitry Andric case VK_TPREL_G1: return ":tprel_g1:";
630b57cec5SDimitry Andric case VK_TPREL_G1_NC: return ":tprel_g1_nc:";
640b57cec5SDimitry Andric case VK_TPREL_G0: return ":tprel_g0:";
650b57cec5SDimitry Andric case VK_TPREL_G0_NC: return ":tprel_g0_nc:";
660b57cec5SDimitry Andric case VK_TPREL_HI12: return ":tprel_hi12:";
670b57cec5SDimitry Andric case VK_TPREL_LO12: return ":tprel_lo12:";
680b57cec5SDimitry Andric case VK_TPREL_LO12_NC: return ":tprel_lo12_nc:";
690b57cec5SDimitry Andric case VK_TLSDESC_LO12: return ":tlsdesc_lo12:";
700b57cec5SDimitry Andric case VK_ABS_PAGE: return "";
710b57cec5SDimitry Andric case VK_ABS_PAGE_NC: return ":pg_hi21_nc:";
720b57cec5SDimitry Andric case VK_GOT: return ":got:";
730b57cec5SDimitry Andric case VK_GOT_PAGE: return ":got:";
74e8d8bef9SDimitry Andric case VK_GOT_PAGE_LO15: return ":gotpage_lo15:";
750b57cec5SDimitry Andric case VK_GOT_LO12: return ":got_lo12:";
760b57cec5SDimitry Andric case VK_GOTTPREL: return ":gottprel:";
770b57cec5SDimitry Andric case VK_GOTTPREL_PAGE: return ":gottprel:";
780b57cec5SDimitry Andric case VK_GOTTPREL_LO12_NC: return ":gottprel_lo12:";
790b57cec5SDimitry Andric case VK_GOTTPREL_G1: return ":gottprel_g1:";
800b57cec5SDimitry Andric case VK_GOTTPREL_G0_NC: return ":gottprel_g0_nc:";
810b57cec5SDimitry Andric case VK_TLSDESC: return "";
820b57cec5SDimitry Andric case VK_TLSDESC_PAGE: return ":tlsdesc:";
830b57cec5SDimitry Andric case VK_SECREL_LO12: return ":secrel_lo12:";
840b57cec5SDimitry Andric case VK_SECREL_HI12: return ":secrel_hi12:";
850b57cec5SDimitry Andric default:
860b57cec5SDimitry Andric llvm_unreachable("Invalid ELF symbol kind");
870b57cec5SDimitry Andric }
880b57cec5SDimitry Andric }
890b57cec5SDimitry Andric
printImpl(raw_ostream & OS,const MCAsmInfo * MAI) const900b57cec5SDimitry Andric void AArch64MCExpr::printImpl(raw_ostream &OS, const MCAsmInfo *MAI) const {
910b57cec5SDimitry Andric OS << getVariantKindName();
920b57cec5SDimitry Andric Expr->print(OS, MAI);
930b57cec5SDimitry Andric }
940b57cec5SDimitry Andric
visitUsedExpr(MCStreamer & Streamer) const950b57cec5SDimitry Andric void AArch64MCExpr::visitUsedExpr(MCStreamer &Streamer) const {
960b57cec5SDimitry Andric Streamer.visitUsedExpr(*getSubExpr());
970b57cec5SDimitry Andric }
980b57cec5SDimitry Andric
findAssociatedFragment() const990b57cec5SDimitry Andric MCFragment *AArch64MCExpr::findAssociatedFragment() const {
1000b57cec5SDimitry Andric llvm_unreachable("FIXME: what goes here?");
1010b57cec5SDimitry Andric }
1020b57cec5SDimitry Andric
evaluateAsRelocatableImpl(MCValue & Res,const MCAssembler * Asm,const MCFixup * Fixup) const1030b57cec5SDimitry Andric bool AArch64MCExpr::evaluateAsRelocatableImpl(MCValue &Res,
104*0fca6ea1SDimitry Andric const MCAssembler *Asm,
1050b57cec5SDimitry Andric const MCFixup *Fixup) const {
106*0fca6ea1SDimitry Andric if (!getSubExpr()->evaluateAsRelocatable(Res, Asm, Fixup))
1070b57cec5SDimitry Andric return false;
1080b57cec5SDimitry Andric
1090b57cec5SDimitry Andric Res =
1100b57cec5SDimitry Andric MCValue::get(Res.getSymA(), Res.getSymB(), Res.getConstant(), getKind());
1110b57cec5SDimitry Andric
1120b57cec5SDimitry Andric return true;
1130b57cec5SDimitry Andric }
1140b57cec5SDimitry Andric
fixELFSymbolsInTLSFixupsImpl(const MCExpr * Expr,MCAssembler & Asm)1150b57cec5SDimitry Andric static void fixELFSymbolsInTLSFixupsImpl(const MCExpr *Expr, MCAssembler &Asm) {
1160b57cec5SDimitry Andric switch (Expr->getKind()) {
1170b57cec5SDimitry Andric case MCExpr::Target:
1180b57cec5SDimitry Andric llvm_unreachable("Can't handle nested target expression");
1190b57cec5SDimitry Andric break;
1200b57cec5SDimitry Andric case MCExpr::Constant:
1210b57cec5SDimitry Andric break;
1220b57cec5SDimitry Andric
1230b57cec5SDimitry Andric case MCExpr::Binary: {
1240b57cec5SDimitry Andric const MCBinaryExpr *BE = cast<MCBinaryExpr>(Expr);
1250b57cec5SDimitry Andric fixELFSymbolsInTLSFixupsImpl(BE->getLHS(), Asm);
1260b57cec5SDimitry Andric fixELFSymbolsInTLSFixupsImpl(BE->getRHS(), Asm);
1270b57cec5SDimitry Andric break;
1280b57cec5SDimitry Andric }
1290b57cec5SDimitry Andric
1300b57cec5SDimitry Andric case MCExpr::SymbolRef: {
1310b57cec5SDimitry Andric // We're known to be under a TLS fixup, so any symbol should be
1320b57cec5SDimitry Andric // modified. There should be only one.
1330b57cec5SDimitry Andric const MCSymbolRefExpr &SymRef = *cast<MCSymbolRefExpr>(Expr);
1340b57cec5SDimitry Andric cast<MCSymbolELF>(SymRef.getSymbol()).setType(ELF::STT_TLS);
1350b57cec5SDimitry Andric break;
1360b57cec5SDimitry Andric }
1370b57cec5SDimitry Andric
1380b57cec5SDimitry Andric case MCExpr::Unary:
1390b57cec5SDimitry Andric fixELFSymbolsInTLSFixupsImpl(cast<MCUnaryExpr>(Expr)->getSubExpr(), Asm);
1400b57cec5SDimitry Andric break;
1410b57cec5SDimitry Andric }
1420b57cec5SDimitry Andric }
1430b57cec5SDimitry Andric
fixELFSymbolsInTLSFixups(MCAssembler & Asm) const1440b57cec5SDimitry Andric void AArch64MCExpr::fixELFSymbolsInTLSFixups(MCAssembler &Asm) const {
1450b57cec5SDimitry Andric switch (getSymbolLoc(Kind)) {
1460b57cec5SDimitry Andric default:
1470b57cec5SDimitry Andric return;
1480b57cec5SDimitry Andric case VK_DTPREL:
1490b57cec5SDimitry Andric case VK_GOTTPREL:
1500b57cec5SDimitry Andric case VK_TPREL:
1510b57cec5SDimitry Andric case VK_TLSDESC:
1520b57cec5SDimitry Andric break;
1530b57cec5SDimitry Andric }
1540b57cec5SDimitry Andric
1550b57cec5SDimitry Andric fixELFSymbolsInTLSFixupsImpl(getSubExpr(), Asm);
1560b57cec5SDimitry Andric }
1575f757f3fSDimitry Andric
create(const MCExpr * Expr,uint16_t Discriminator,AArch64PACKey::ID Key,bool HasAddressDiversity,MCContext & Ctx)1585f757f3fSDimitry Andric const AArch64AuthMCExpr *AArch64AuthMCExpr::create(const MCExpr *Expr,
1595f757f3fSDimitry Andric uint16_t Discriminator,
1605f757f3fSDimitry Andric AArch64PACKey::ID Key,
1615f757f3fSDimitry Andric bool HasAddressDiversity,
1625f757f3fSDimitry Andric MCContext &Ctx) {
1635f757f3fSDimitry Andric return new (Ctx)
1645f757f3fSDimitry Andric AArch64AuthMCExpr(Expr, Discriminator, Key, HasAddressDiversity);
1655f757f3fSDimitry Andric }
1665f757f3fSDimitry Andric
printImpl(raw_ostream & OS,const MCAsmInfo * MAI) const1675f757f3fSDimitry Andric void AArch64AuthMCExpr::printImpl(raw_ostream &OS, const MCAsmInfo *MAI) const {
1685f757f3fSDimitry Andric bool WrapSubExprInParens = !isa<MCSymbolRefExpr>(getSubExpr());
1695f757f3fSDimitry Andric if (WrapSubExprInParens)
1705f757f3fSDimitry Andric OS << '(';
1715f757f3fSDimitry Andric getSubExpr()->print(OS, MAI);
1725f757f3fSDimitry Andric if (WrapSubExprInParens)
1735f757f3fSDimitry Andric OS << ')';
1745f757f3fSDimitry Andric
1755f757f3fSDimitry Andric OS << "@AUTH(" << AArch64PACKeyIDToString(Key) << ',' << Discriminator;
1765f757f3fSDimitry Andric if (hasAddressDiversity())
1775f757f3fSDimitry Andric OS << ",addr";
1785f757f3fSDimitry Andric OS << ')';
1795f757f3fSDimitry Andric }
1805f757f3fSDimitry Andric
visitUsedExpr(MCStreamer & Streamer) const1815f757f3fSDimitry Andric void AArch64AuthMCExpr::visitUsedExpr(MCStreamer &Streamer) const {
1825f757f3fSDimitry Andric Streamer.visitUsedExpr(*getSubExpr());
1835f757f3fSDimitry Andric }
1845f757f3fSDimitry Andric
findAssociatedFragment() const1855f757f3fSDimitry Andric MCFragment *AArch64AuthMCExpr::findAssociatedFragment() const {
1865f757f3fSDimitry Andric llvm_unreachable("FIXME: what goes here?");
1875f757f3fSDimitry Andric }
1885f757f3fSDimitry Andric
evaluateAsRelocatableImpl(MCValue & Res,const MCAssembler * Asm,const MCFixup * Fixup) const1895f757f3fSDimitry Andric bool AArch64AuthMCExpr::evaluateAsRelocatableImpl(MCValue &Res,
190*0fca6ea1SDimitry Andric const MCAssembler *Asm,
1915f757f3fSDimitry Andric const MCFixup *Fixup) const {
192*0fca6ea1SDimitry Andric if (!getSubExpr()->evaluateAsRelocatable(Res, Asm, Fixup))
1935f757f3fSDimitry Andric return false;
1945f757f3fSDimitry Andric
1955f757f3fSDimitry Andric if (Res.getSymB())
1965f757f3fSDimitry Andric report_fatal_error("Auth relocation can't reference two symbols");
1975f757f3fSDimitry Andric
1985f757f3fSDimitry Andric Res = MCValue::get(Res.getSymA(), nullptr, Res.getConstant(), getKind());
1995f757f3fSDimitry Andric return true;
2005f757f3fSDimitry Andric }
201