//===-- CSKYMCExpr.cpp - CSKY specific MC expression classes -*- C++ -*----===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "CSKYMCExpr.h" #include "CSKYFixupKinds.h" #include "llvm/BinaryFormat/ELF.h" #include "llvm/MC/MCAssembler.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCSymbolELF.h" #include "llvm/Support/Casting.h" using namespace llvm; #define DEBUG_TYPE "csky-mc-expr" const CSKYMCExpr *CSKYMCExpr::create(const MCExpr *Expr, VariantKind Kind, MCContext &Ctx) { return new (Ctx) CSKYMCExpr(Kind, Expr); } StringRef CSKYMCExpr::getVariantKindName(VariantKind Kind) { switch (Kind) { default: llvm_unreachable("Invalid ELF symbol kind"); case VK_CSKY_None: case VK_CSKY_ADDR: return ""; case VK_CSKY_ADDR_HI16: return "@HI16"; case VK_CSKY_ADDR_LO16: return "@LO16"; case VK_CSKY_GOT_IMM18_BY4: case VK_CSKY_GOT: return "@GOT"; case VK_CSKY_GOTPC: return "@GOTPC"; case VK_CSKY_GOTOFF: return "@GOTOFF"; case VK_CSKY_PLT_IMM18_BY4: case VK_CSKY_PLT: return "@PLT"; case VK_CSKY_TLSLE: return "@TPOFF"; case VK_CSKY_TLSIE: return "@GOTTPOFF"; case VK_CSKY_TLSGD: return "@TLSGD32"; case VK_CSKY_TLSLDO: return "@TLSLDO32"; case VK_CSKY_TLSLDM: return "@TLSLDM32"; } } void CSKYMCExpr::visitUsedExpr(MCStreamer &Streamer) const { Streamer.visitUsedExpr(*getSubExpr()); } void CSKYMCExpr::printImpl(raw_ostream &OS, const MCAsmInfo *MAI) const { Expr->print(OS, MAI); OS << getVariantKindName(getKind()); } static void fixELFSymbolsInTLSFixupsImpl(const MCExpr *Expr, MCAssembler &Asm) { switch (Expr->getKind()) { case MCExpr::Target: llvm_unreachable("Can't handle nested target expression"); break; case MCExpr::Constant: break; case MCExpr::Binary: { const MCBinaryExpr *BE = cast(Expr); fixELFSymbolsInTLSFixupsImpl(BE->getLHS(), Asm); fixELFSymbolsInTLSFixupsImpl(BE->getRHS(), Asm); break; } case MCExpr::SymbolRef: { // We're known to be under a TLS fixup, so any symbol should be // modified. There should be only one. const MCSymbolRefExpr &SymRef = *cast(Expr); cast(SymRef.getSymbol()).setType(ELF::STT_TLS); break; } case MCExpr::Unary: fixELFSymbolsInTLSFixupsImpl(cast(Expr)->getSubExpr(), Asm); break; } } void CSKYMCExpr::fixELFSymbolsInTLSFixups(MCAssembler &Asm) const { switch (getKind()) { default: return; case VK_CSKY_TLSLE: case VK_CSKY_TLSIE: case VK_CSKY_TLSGD: break; } fixELFSymbolsInTLSFixupsImpl(getSubExpr(), Asm); } bool CSKYMCExpr::evaluateAsRelocatableImpl(MCValue &Res, const MCAssembler *Asm, const MCFixup *Fixup) const { if (!getSubExpr()->evaluateAsRelocatable(Res, Asm, Fixup)) return false; // Some custom fixup types are not valid with symbol difference expressions if (Res.getSymA() && Res.getSymB()) { switch (getKind()) { default: return true; case VK_CSKY_GOT: case VK_CSKY_GOT_IMM18_BY4: case VK_CSKY_GOTPC: case VK_CSKY_GOTOFF: case VK_CSKY_PLT: case VK_CSKY_PLT_IMM18_BY4: case VK_CSKY_TLSIE: case VK_CSKY_TLSLE: case VK_CSKY_TLSGD: case VK_CSKY_TLSLDO: case VK_CSKY_TLSLDM: return false; } } return true; }