1 //===-- CSKYMCExpr.cpp - CSKY specific MC expression classes -*- C++ -*----===//
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 "CSKYMCExpr.h"
10 #include "CSKYFixupKinds.h"
11 #include "llvm/BinaryFormat/ELF.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/Support/Casting.h"
17 
18 using namespace llvm;
19 
20 #define DEBUG_TYPE "csky-mc-expr"
21 
22 const CSKYMCExpr *CSKYMCExpr::create(const MCExpr *Expr, VariantKind Kind,
23                                      MCContext &Ctx) {
24   return new (Ctx) CSKYMCExpr(Kind, Expr);
25 }
26 
27 StringRef CSKYMCExpr::getVariantKindName(VariantKind Kind) {
28   switch (Kind) {
29   default:
30     llvm_unreachable("Invalid ELF symbol kind");
31   case VK_CSKY_None:
32   case VK_CSKY_ADDR:
33     return "";
34   case VK_CSKY_ADDR_HI16:
35     return "@HI16";
36   case VK_CSKY_ADDR_LO16:
37     return "@LO16";
38   case VK_CSKY_GOT_IMM18_BY4:
39   case VK_CSKY_GOT:
40     return "@GOT";
41   case VK_CSKY_GOTPC:
42     return "@GOTPC";
43   case VK_CSKY_GOTOFF:
44     return "@GOTOFF";
45   case VK_CSKY_PLT_IMM18_BY4:
46   case VK_CSKY_PLT:
47     return "@PLT";
48   case VK_CSKY_TLSLE:
49     return "@TPOFF";
50   case VK_CSKY_TLSIE:
51     return "@GOTTPOFF";
52   case VK_CSKY_TLSGD:
53     return "@TLSGD32";
54   case VK_CSKY_TLSLDO:
55     return "@TLSLDO32";
56   case VK_CSKY_TLSLDM:
57     return "@TLSLDM32";
58   }
59 }
60 
61 void CSKYMCExpr::visitUsedExpr(MCStreamer &Streamer) const {
62   Streamer.visitUsedExpr(*getSubExpr());
63 }
64 
65 void CSKYMCExpr::printImpl(raw_ostream &OS, const MCAsmInfo *MAI) const {
66   Expr->print(OS, MAI);
67   OS << getVariantKindName(getKind());
68 }
69 
70 static void fixELFSymbolsInTLSFixupsImpl(const MCExpr *Expr, MCAssembler &Asm) {
71   switch (Expr->getKind()) {
72   case MCExpr::Target:
73     llvm_unreachable("Can't handle nested target expression");
74     break;
75   case MCExpr::Constant:
76     break;
77 
78   case MCExpr::Binary: {
79     const MCBinaryExpr *BE = cast<MCBinaryExpr>(Expr);
80     fixELFSymbolsInTLSFixupsImpl(BE->getLHS(), Asm);
81     fixELFSymbolsInTLSFixupsImpl(BE->getRHS(), Asm);
82     break;
83   }
84 
85   case MCExpr::SymbolRef: {
86     // We're known to be under a TLS fixup, so any symbol should be
87     // modified. There should be only one.
88     const MCSymbolRefExpr &SymRef = *cast<MCSymbolRefExpr>(Expr);
89     cast<MCSymbolELF>(SymRef.getSymbol()).setType(ELF::STT_TLS);
90     break;
91   }
92 
93   case MCExpr::Unary:
94     fixELFSymbolsInTLSFixupsImpl(cast<MCUnaryExpr>(Expr)->getSubExpr(), Asm);
95     break;
96   }
97 }
98 
99 void CSKYMCExpr::fixELFSymbolsInTLSFixups(MCAssembler &Asm) const {
100   switch (getKind()) {
101   default:
102     return;
103   case VK_CSKY_TLSLE:
104   case VK_CSKY_TLSIE:
105   case VK_CSKY_TLSGD:
106     break;
107   }
108 
109   fixELFSymbolsInTLSFixupsImpl(getSubExpr(), Asm);
110 }
111 
112 bool CSKYMCExpr::evaluateAsRelocatableImpl(MCValue &Res,
113                                            const MCAsmLayout *Layout,
114                                            const MCFixup *Fixup) const {
115   if (!getSubExpr()->evaluateAsRelocatable(Res, Layout, Fixup))
116     return false;
117 
118   // Some custom fixup types are not valid with symbol difference expressions
119   if (Res.getSymA() && Res.getSymB()) {
120     switch (getKind()) {
121     default:
122       return true;
123     case VK_CSKY_GOT:
124     case VK_CSKY_GOT_IMM18_BY4:
125     case VK_CSKY_GOTPC:
126     case VK_CSKY_GOTOFF:
127     case VK_CSKY_PLT:
128     case VK_CSKY_PLT_IMM18_BY4:
129     case VK_CSKY_TLSIE:
130     case VK_CSKY_TLSLE:
131     case VK_CSKY_TLSGD:
132     case VK_CSKY_TLSLDO:
133     case VK_CSKY_TLSLDM:
134       return false;
135     }
136   }
137 
138   return true;
139 }
140