PPCELFObjectWriter.cpp revision 57ac1f458a754f30cf500410b438fb260f9b8fe5
1//===-- PPCELFObjectWriter.cpp - PPC 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/PPCMCTargetDesc.h"
11#include "MCTargetDesc/PPCFixupKinds.h"
12#include "llvm/MC/MCELFObjectWriter.h"
13#include "llvm/MC/MCExpr.h"
14#include "llvm/MC/MCValue.h"
15#include "llvm/Support/ErrorHandling.h"
16
17using namespace llvm;
18
19namespace {
20  class PPCELFObjectWriter : public MCELFObjectTargetWriter {
21  public:
22    PPCELFObjectWriter(bool Is64Bit, uint8_t OSABI);
23
24    virtual ~PPCELFObjectWriter();
25  protected:
26    virtual unsigned getRelocTypeInner(const MCValue &Target,
27                                       const MCFixup &Fixup,
28                                       bool IsPCRel) const;
29    virtual unsigned GetRelocType(const MCValue &Target, const MCFixup &Fixup,
30                                  bool IsPCRel, bool IsRelocWithSymbol,
31                                  int64_t Addend) const;
32    virtual const MCSymbol *undefinedExplicitRelSym(const MCValue &Target,
33                                                    const MCFixup &Fixup,
34                                                    bool IsPCRel) const;
35    virtual void adjustFixupOffset(const MCFixup &Fixup, uint64_t &RelocOffset);
36  };
37}
38
39PPCELFObjectWriter::PPCELFObjectWriter(bool Is64Bit, uint8_t OSABI)
40  : MCELFObjectTargetWriter(Is64Bit, OSABI,
41                            Is64Bit ?  ELF::EM_PPC64 : ELF::EM_PPC,
42                            /*HasRelocationAddend*/ true) {}
43
44PPCELFObjectWriter::~PPCELFObjectWriter() {
45}
46
47unsigned PPCELFObjectWriter::getRelocTypeInner(const MCValue &Target,
48                                               const MCFixup &Fixup,
49                                               bool IsPCRel) const
50{
51  MCSymbolRefExpr::VariantKind Modifier = Target.isAbsolute() ?
52    MCSymbolRefExpr::VK_None : Target.getSymA()->getKind();
53
54  // determine the type of the relocation
55  unsigned Type;
56  if (IsPCRel) {
57    switch ((unsigned)Fixup.getKind()) {
58    default:
59      llvm_unreachable("Unimplemented");
60    case PPC::fixup_ppc_br24:
61      Type = ELF::R_PPC_REL24;
62      break;
63    case FK_PCRel_4:
64      Type = ELF::R_PPC_REL32;
65      break;
66    }
67  } else {
68    switch ((unsigned)Fixup.getKind()) {
69      default: llvm_unreachable("invalid fixup kind!");
70    case PPC::fixup_ppc_br24:
71      Type = ELF::R_PPC_ADDR24;
72      break;
73    case PPC::fixup_ppc_brcond14:
74      Type = ELF::R_PPC_ADDR14; // XXX: or BRNTAKEN?_
75      break;
76    case PPC::fixup_ppc_ha16:
77      switch (Modifier) {
78      default: llvm_unreachable("Unsupported Modifier");
79      case MCSymbolRefExpr::VK_PPC_TPREL16_HA:
80        Type = ELF::R_PPC_TPREL16_HA;
81        break;
82      case MCSymbolRefExpr::VK_None:
83        Type = ELF::R_PPC_ADDR16_HA;
84	break;
85      case MCSymbolRefExpr::VK_PPC_TOC16_HA:
86        Type = ELF::R_PPC64_TOC16_HA;
87        break;
88      case MCSymbolRefExpr::VK_PPC_GOT_TLSGD16_HA:
89        Type = ELF::R_PPC64_GOT_TLSGD16_HA;
90        break;
91      }
92      break;
93    case PPC::fixup_ppc_lo16:
94      switch (Modifier) {
95      default: llvm_unreachable("Unsupported Modifier");
96      case MCSymbolRefExpr::VK_PPC_TPREL16_LO:
97        Type = ELF::R_PPC_TPREL16_LO;
98        break;
99      case MCSymbolRefExpr::VK_None:
100        Type = ELF::R_PPC_ADDR16_LO;
101	break;
102      case MCSymbolRefExpr::VK_PPC_TOC16_LO:
103        Type = ELF::R_PPC64_TOC16_LO;
104        break;
105      case MCSymbolRefExpr::VK_PPC_GOT_TLSGD16_LO:
106        Type = ELF::R_PPC64_GOT_TLSGD16_LO;
107        break;
108      }
109      break;
110    case PPC::fixup_ppc_lo14:
111      Type = ELF::R_PPC_ADDR14;
112      break;
113    case PPC::fixup_ppc_toc:
114      Type = ELF::R_PPC64_TOC;
115      break;
116    case PPC::fixup_ppc_toc16:
117      Type = ELF::R_PPC64_TOC16;
118      break;
119    case PPC::fixup_ppc_toc16_ds:
120      switch (Modifier) {
121      default: llvm_unreachable("Unsupported Modifier");
122      case MCSymbolRefExpr::VK_PPC_TOC_ENTRY:
123        Type = ELF::R_PPC64_TOC16_DS;
124	break;
125      case MCSymbolRefExpr::VK_PPC_TOC16_LO:
126        Type = ELF::R_PPC64_TOC16_LO_DS;
127        break;
128      case MCSymbolRefExpr::VK_PPC_GOT_TPREL16_DS:
129        Type = ELF::R_PPC64_GOT_TPREL16_DS;
130        break;
131      }
132      break;
133    case PPC::fixup_ppc_tlsreg:
134      Type = ELF::R_PPC64_TLS;
135      break;
136    case PPC::fixup_ppc_tlsgd:
137      Type = ELF::R_PPC64_TLSGD;
138      break;
139    case FK_Data_8:
140      switch (Modifier) {
141      default: llvm_unreachable("Unsupported Modifier");
142      case MCSymbolRefExpr::VK_PPC_TOC:
143        Type = ELF::R_PPC64_TOC;
144        break;
145      case MCSymbolRefExpr::VK_None:
146        Type = ELF::R_PPC64_ADDR64;
147	break;
148      }
149      break;
150    case FK_Data_4:
151      Type = ELF::R_PPC_ADDR32;
152      break;
153    case FK_Data_2:
154      Type = ELF::R_PPC_ADDR16;
155      break;
156    }
157  }
158  return Type;
159}
160
161unsigned PPCELFObjectWriter::GetRelocType(const MCValue &Target,
162                                          const MCFixup &Fixup,
163                                          bool IsPCRel,
164                                          bool IsRelocWithSymbol,
165                                          int64_t Addend) const {
166  return getRelocTypeInner(Target, Fixup, IsPCRel);
167}
168
169const MCSymbol *PPCELFObjectWriter::undefinedExplicitRelSym(const MCValue &Target,
170                                                            const MCFixup &Fixup,
171                                                            bool IsPCRel) const {
172  assert(Target.getSymA() && "SymA cannot be 0");
173  const MCSymbol &Symbol = Target.getSymA()->getSymbol().AliasedSymbol();
174
175  unsigned RelocType = getRelocTypeInner(Target, Fixup, IsPCRel);
176
177  // The .odp creation emits a relocation against the symbol ".TOC." which
178  // create a R_PPC64_TOC relocation. However the relocation symbol name
179  // in final object creation should be NULL, since the symbol does not
180  // really exist, it is just the reference to TOC base for the current
181  // object file.
182  bool EmitThisSym = RelocType != ELF::R_PPC64_TOC;
183
184  if (EmitThisSym && !Symbol.isTemporary())
185    return &Symbol;
186  return NULL;
187}
188
189void PPCELFObjectWriter::
190adjustFixupOffset(const MCFixup &Fixup, uint64_t &RelocOffset) {
191  switch ((unsigned)Fixup.getKind()) {
192    case PPC::fixup_ppc_ha16:
193    case PPC::fixup_ppc_lo16:
194    case PPC::fixup_ppc_toc16:
195    case PPC::fixup_ppc_toc16_ds:
196      RelocOffset += 2;
197      break;
198    default:
199      break;
200  }
201}
202
203MCObjectWriter *llvm::createPPCELFObjectWriter(raw_ostream &OS,
204                                               bool Is64Bit,
205                                               uint8_t OSABI) {
206  MCELFObjectTargetWriter *MOTW = new PPCELFObjectWriter(Is64Bit, OSABI);
207  return createELFObjectWriter(MOTW, OS,  /*IsLittleEndian=*/false);
208}
209