1*5f613dfdSUlrich Weigand //===-- SystemZMCObjectWriter.cpp - SystemZ ELF writer --------------------===//
2*5f613dfdSUlrich Weigand //
3*5f613dfdSUlrich Weigand //                     The LLVM Compiler Infrastructure
4*5f613dfdSUlrich Weigand //
5*5f613dfdSUlrich Weigand // This file is distributed under the University of Illinois Open Source
6*5f613dfdSUlrich Weigand // License. See LICENSE.TXT for details.
7*5f613dfdSUlrich Weigand //
8*5f613dfdSUlrich Weigand //===----------------------------------------------------------------------===//
9*5f613dfdSUlrich Weigand 
10*5f613dfdSUlrich Weigand #include "MCTargetDesc/SystemZMCTargetDesc.h"
11*5f613dfdSUlrich Weigand #include "MCTargetDesc/SystemZMCFixups.h"
12*5f613dfdSUlrich Weigand #include "llvm/MC/MCELFObjectWriter.h"
13*5f613dfdSUlrich Weigand #include "llvm/MC/MCExpr.h"
14*5f613dfdSUlrich Weigand #include "llvm/MC/MCValue.h"
15*5f613dfdSUlrich Weigand 
16*5f613dfdSUlrich Weigand using namespace llvm;
17*5f613dfdSUlrich Weigand 
18*5f613dfdSUlrich Weigand namespace {
19*5f613dfdSUlrich Weigand class SystemZObjectWriter : public MCELFObjectTargetWriter {
20*5f613dfdSUlrich Weigand public:
21*5f613dfdSUlrich Weigand   SystemZObjectWriter(uint8_t OSABI);
22*5f613dfdSUlrich Weigand 
23*5f613dfdSUlrich Weigand   virtual ~SystemZObjectWriter();
24*5f613dfdSUlrich Weigand 
25*5f613dfdSUlrich Weigand protected:
26*5f613dfdSUlrich Weigand   // Override MCELFObjectTargetWriter.
27*5f613dfdSUlrich Weigand   virtual unsigned GetRelocType(const MCValue &Target, const MCFixup &Fixup,
28*5f613dfdSUlrich Weigand                                 bool IsPCRel, bool IsRelocWithSymbol,
29*5f613dfdSUlrich Weigand                                 int64_t Addend) const LLVM_OVERRIDE;
30*5f613dfdSUlrich Weigand   virtual const MCSymbol *ExplicitRelSym(const MCAssembler &Asm,
31*5f613dfdSUlrich Weigand                                          const MCValue &Target,
32*5f613dfdSUlrich Weigand                                          const MCFragment &F,
33*5f613dfdSUlrich Weigand                                          const MCFixup &Fixup,
34*5f613dfdSUlrich Weigand                                          bool IsPCRel) const LLVM_OVERRIDE;
35*5f613dfdSUlrich Weigand };
36*5f613dfdSUlrich Weigand } // end anonymouse namespace
37*5f613dfdSUlrich Weigand 
38*5f613dfdSUlrich Weigand SystemZObjectWriter::SystemZObjectWriter(uint8_t OSABI)
39*5f613dfdSUlrich Weigand   : MCELFObjectTargetWriter(/*Is64Bit=*/true, OSABI, ELF::EM_S390,
40*5f613dfdSUlrich Weigand                             /*HasRelocationAddend=*/ true) {}
41*5f613dfdSUlrich Weigand 
42*5f613dfdSUlrich Weigand SystemZObjectWriter::~SystemZObjectWriter() {
43*5f613dfdSUlrich Weigand }
44*5f613dfdSUlrich Weigand 
45*5f613dfdSUlrich Weigand // Return the relocation type for an absolute value of MCFixupKind Kind.
46*5f613dfdSUlrich Weigand static unsigned getAbsoluteReloc(unsigned Kind) {
47*5f613dfdSUlrich Weigand   switch (Kind) {
48*5f613dfdSUlrich Weigand   case FK_Data_1: return ELF::R_390_8;
49*5f613dfdSUlrich Weigand   case FK_Data_2: return ELF::R_390_16;
50*5f613dfdSUlrich Weigand   case FK_Data_4: return ELF::R_390_32;
51*5f613dfdSUlrich Weigand   case FK_Data_8: return ELF::R_390_64;
52*5f613dfdSUlrich Weigand   }
53*5f613dfdSUlrich Weigand   llvm_unreachable("Unsupported absolute address");
54*5f613dfdSUlrich Weigand }
55*5f613dfdSUlrich Weigand 
56*5f613dfdSUlrich Weigand // Return the relocation type for a PC-relative value of MCFixupKind Kind.
57*5f613dfdSUlrich Weigand static unsigned getPCRelReloc(unsigned Kind) {
58*5f613dfdSUlrich Weigand   switch (Kind) {
59*5f613dfdSUlrich Weigand   case FK_Data_2:                return ELF::R_390_PC16;
60*5f613dfdSUlrich Weigand   case FK_Data_4:                return ELF::R_390_PC32;
61*5f613dfdSUlrich Weigand   case FK_Data_8:                return ELF::R_390_PC64;
62*5f613dfdSUlrich Weigand   case SystemZ::FK_390_PC16DBL:  return ELF::R_390_PC16DBL;
63*5f613dfdSUlrich Weigand   case SystemZ::FK_390_PC32DBL:  return ELF::R_390_PC32DBL;
64*5f613dfdSUlrich Weigand   case SystemZ::FK_390_PLT16DBL: return ELF::R_390_PLT16DBL;
65*5f613dfdSUlrich Weigand   case SystemZ::FK_390_PLT32DBL: return ELF::R_390_PLT32DBL;
66*5f613dfdSUlrich Weigand   }
67*5f613dfdSUlrich Weigand   llvm_unreachable("Unsupported PC-relative address");
68*5f613dfdSUlrich Weigand }
69*5f613dfdSUlrich Weigand 
70*5f613dfdSUlrich Weigand // Return the R_390_TLS_LE* relocation type for MCFixupKind Kind.
71*5f613dfdSUlrich Weigand static unsigned getTLSLEReloc(unsigned Kind) {
72*5f613dfdSUlrich Weigand   switch (Kind) {
73*5f613dfdSUlrich Weigand   case FK_Data_4: return ELF::R_390_TLS_LE32;
74*5f613dfdSUlrich Weigand   case FK_Data_8: return ELF::R_390_TLS_LE64;
75*5f613dfdSUlrich Weigand   }
76*5f613dfdSUlrich Weigand   llvm_unreachable("Unsupported absolute address");
77*5f613dfdSUlrich Weigand }
78*5f613dfdSUlrich Weigand 
79*5f613dfdSUlrich Weigand // Return the PLT relocation counterpart of MCFixupKind Kind.
80*5f613dfdSUlrich Weigand static unsigned getPLTReloc(unsigned Kind) {
81*5f613dfdSUlrich Weigand   switch (Kind) {
82*5f613dfdSUlrich Weigand   case SystemZ::FK_390_PC16DBL: return ELF::R_390_PLT16DBL;
83*5f613dfdSUlrich Weigand   case SystemZ::FK_390_PC32DBL: return ELF::R_390_PLT32DBL;
84*5f613dfdSUlrich Weigand   }
85*5f613dfdSUlrich Weigand   llvm_unreachable("Unsupported absolute address");
86*5f613dfdSUlrich Weigand }
87*5f613dfdSUlrich Weigand 
88*5f613dfdSUlrich Weigand unsigned SystemZObjectWriter::GetRelocType(const MCValue &Target,
89*5f613dfdSUlrich Weigand                                            const MCFixup &Fixup,
90*5f613dfdSUlrich Weigand                                            bool IsPCRel,
91*5f613dfdSUlrich Weigand                                            bool IsRelocWithSymbol,
92*5f613dfdSUlrich Weigand                                            int64_t Addend) const {
93*5f613dfdSUlrich Weigand   MCSymbolRefExpr::VariantKind Modifier = (Target.isAbsolute() ?
94*5f613dfdSUlrich Weigand                                            MCSymbolRefExpr::VK_None :
95*5f613dfdSUlrich Weigand                                            Target.getSymA()->getKind());
96*5f613dfdSUlrich Weigand   unsigned Kind = Fixup.getKind();
97*5f613dfdSUlrich Weigand   switch (Modifier) {
98*5f613dfdSUlrich Weigand   case MCSymbolRefExpr::VK_None:
99*5f613dfdSUlrich Weigand     if (IsPCRel)
100*5f613dfdSUlrich Weigand       return getPCRelReloc(Kind);
101*5f613dfdSUlrich Weigand     return getAbsoluteReloc(Kind);
102*5f613dfdSUlrich Weigand 
103*5f613dfdSUlrich Weigand   case MCSymbolRefExpr::VK_NTPOFF:
104*5f613dfdSUlrich Weigand     assert(!IsPCRel && "NTPOFF shouldn't be PC-relative");
105*5f613dfdSUlrich Weigand     return getTLSLEReloc(Kind);
106*5f613dfdSUlrich Weigand 
107*5f613dfdSUlrich Weigand   case MCSymbolRefExpr::VK_GOT:
108*5f613dfdSUlrich Weigand     if (IsPCRel && Kind == SystemZ::FK_390_PC32DBL)
109*5f613dfdSUlrich Weigand       return ELF::R_390_GOTENT;
110*5f613dfdSUlrich Weigand     llvm_unreachable("Only PC-relative GOT accesses are supported for now");
111*5f613dfdSUlrich Weigand 
112*5f613dfdSUlrich Weigand   case MCSymbolRefExpr::VK_PLT:
113*5f613dfdSUlrich Weigand     assert(IsPCRel && "@PLT shouldt be PC-relative");
114*5f613dfdSUlrich Weigand     return getPLTReloc(Kind);
115*5f613dfdSUlrich Weigand 
116*5f613dfdSUlrich Weigand   default:
117*5f613dfdSUlrich Weigand     llvm_unreachable("Modifier not supported");
118*5f613dfdSUlrich Weigand   }
119*5f613dfdSUlrich Weigand }
120*5f613dfdSUlrich Weigand 
121*5f613dfdSUlrich Weigand const MCSymbol *SystemZObjectWriter::ExplicitRelSym(const MCAssembler &Asm,
122*5f613dfdSUlrich Weigand                                                     const MCValue &Target,
123*5f613dfdSUlrich Weigand                                                     const MCFragment &F,
124*5f613dfdSUlrich Weigand                                                     const MCFixup &Fixup,
125*5f613dfdSUlrich Weigand                                                     bool IsPCRel) const {
126*5f613dfdSUlrich Weigand   // The addend in a PC-relative R_390_* relocation is always applied to
127*5f613dfdSUlrich Weigand   // the PC-relative part of the address.  If some kind of indirection
128*5f613dfdSUlrich Weigand   // is applied to the symbol first, we can't use an addend there too.
129*5f613dfdSUlrich Weigand   if (!Target.isAbsolute() &&
130*5f613dfdSUlrich Weigand       Target.getSymA()->getKind() != MCSymbolRefExpr::VK_None &&
131*5f613dfdSUlrich Weigand       IsPCRel)
132*5f613dfdSUlrich Weigand     return &Target.getSymA()->getSymbol().AliasedSymbol();
133*5f613dfdSUlrich Weigand   return NULL;
134*5f613dfdSUlrich Weigand }
135*5f613dfdSUlrich Weigand 
136*5f613dfdSUlrich Weigand MCObjectWriter *llvm::createSystemZObjectWriter(raw_ostream &OS,
137*5f613dfdSUlrich Weigand                                                 uint8_t OSABI) {
138*5f613dfdSUlrich Weigand   MCELFObjectTargetWriter *MOTW = new SystemZObjectWriter(OSABI);
139*5f613dfdSUlrich Weigand   return createELFObjectWriter(MOTW, OS, /*IsLittleEndian=*/false);
140*5f613dfdSUlrich Weigand }
141