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