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 "MCTargetDesc/PPCMCExpr.h"
13#include "llvm/ADT/STLExtras.h"
14#include "llvm/MC/MCELFObjectWriter.h"
15#include "llvm/MC/MCExpr.h"
16#include "llvm/MC/MCValue.h"
17#include "llvm/Support/ErrorHandling.h"
18
19using namespace llvm;
20
21namespace {
22  class PPCELFObjectWriter : public MCELFObjectTargetWriter {
23  public:
24    PPCELFObjectWriter(bool Is64Bit, uint8_t OSABI);
25
26    virtual ~PPCELFObjectWriter();
27  protected:
28    virtual unsigned getRelocTypeInner(const MCValue &Target,
29                                       const MCFixup &Fixup,
30                                       bool IsPCRel) const;
31    unsigned GetRelocType(const MCValue &Target, const MCFixup &Fixup,
32                          bool IsPCRel) const override;
33  };
34}
35
36PPCELFObjectWriter::PPCELFObjectWriter(bool Is64Bit, uint8_t OSABI)
37  : MCELFObjectTargetWriter(Is64Bit, OSABI,
38                            Is64Bit ?  ELF::EM_PPC64 : ELF::EM_PPC,
39                            /*HasRelocationAddend*/ true) {}
40
41PPCELFObjectWriter::~PPCELFObjectWriter() {
42}
43
44static MCSymbolRefExpr::VariantKind getAccessVariant(const MCValue &Target,
45                                                     const MCFixup &Fixup) {
46  const MCExpr *Expr = Fixup.getValue();
47
48  if (Expr->getKind() != MCExpr::Target)
49    return Target.getAccessVariant();
50
51  switch (cast<PPCMCExpr>(Expr)->getKind()) {
52  case PPCMCExpr::VK_PPC_None:
53    return MCSymbolRefExpr::VK_None;
54  case PPCMCExpr::VK_PPC_LO:
55    return MCSymbolRefExpr::VK_PPC_LO;
56  case PPCMCExpr::VK_PPC_HI:
57    return MCSymbolRefExpr::VK_PPC_HI;
58  case PPCMCExpr::VK_PPC_HA:
59    return MCSymbolRefExpr::VK_PPC_HA;
60  case PPCMCExpr::VK_PPC_HIGHERA:
61    return MCSymbolRefExpr::VK_PPC_HIGHERA;
62  case PPCMCExpr::VK_PPC_HIGHER:
63    return MCSymbolRefExpr::VK_PPC_HIGHER;
64  case PPCMCExpr::VK_PPC_HIGHEST:
65    return MCSymbolRefExpr::VK_PPC_HIGHEST;
66  case PPCMCExpr::VK_PPC_HIGHESTA:
67    return MCSymbolRefExpr::VK_PPC_HIGHESTA;
68  }
69  llvm_unreachable("unknown PPCMCExpr kind");
70}
71
72unsigned PPCELFObjectWriter::getRelocTypeInner(const MCValue &Target,
73                                               const MCFixup &Fixup,
74                                               bool IsPCRel) const
75{
76  MCSymbolRefExpr::VariantKind Modifier = getAccessVariant(Target, Fixup);
77
78  // determine the type of the relocation
79  unsigned Type;
80  if (IsPCRel) {
81    switch ((unsigned)Fixup.getKind()) {
82    default:
83      llvm_unreachable("Unimplemented");
84    case PPC::fixup_ppc_br24:
85    case PPC::fixup_ppc_br24abs:
86      Type = ELF::R_PPC_REL24;
87      break;
88    case PPC::fixup_ppc_brcond14:
89    case PPC::fixup_ppc_brcond14abs:
90      Type = ELF::R_PPC_REL14;
91      break;
92    case PPC::fixup_ppc_half16:
93      switch (Modifier) {
94      default: llvm_unreachable("Unsupported Modifier");
95      case MCSymbolRefExpr::VK_None:
96        Type = ELF::R_PPC_REL16;
97        break;
98      case MCSymbolRefExpr::VK_PPC_LO:
99        Type = ELF::R_PPC_REL16_LO;
100        break;
101      case MCSymbolRefExpr::VK_PPC_HI:
102        Type = ELF::R_PPC_REL16_HI;
103        break;
104      case MCSymbolRefExpr::VK_PPC_HA:
105        Type = ELF::R_PPC_REL16_HA;
106        break;
107      }
108      break;
109    case FK_Data_4:
110    case FK_PCRel_4:
111      Type = ELF::R_PPC_REL32;
112      break;
113    case FK_Data_8:
114    case FK_PCRel_8:
115      Type = ELF::R_PPC64_REL64;
116      break;
117    }
118  } else {
119    switch ((unsigned)Fixup.getKind()) {
120      default: llvm_unreachable("invalid fixup kind!");
121    case PPC::fixup_ppc_br24abs:
122      Type = ELF::R_PPC_ADDR24;
123      break;
124    case PPC::fixup_ppc_brcond14abs:
125      Type = ELF::R_PPC_ADDR14; // XXX: or BRNTAKEN?_
126      break;
127    case PPC::fixup_ppc_half16:
128      switch (Modifier) {
129      default: llvm_unreachable("Unsupported Modifier");
130      case MCSymbolRefExpr::VK_None:
131        Type = ELF::R_PPC_ADDR16;
132        break;
133      case MCSymbolRefExpr::VK_PPC_LO:
134        Type = ELF::R_PPC_ADDR16_LO;
135        break;
136      case MCSymbolRefExpr::VK_PPC_HI:
137        Type = ELF::R_PPC_ADDR16_HI;
138        break;
139      case MCSymbolRefExpr::VK_PPC_HA:
140        Type = ELF::R_PPC_ADDR16_HA;
141        break;
142      case MCSymbolRefExpr::VK_PPC_HIGHER:
143        Type = ELF::R_PPC64_ADDR16_HIGHER;
144        break;
145      case MCSymbolRefExpr::VK_PPC_HIGHERA:
146        Type = ELF::R_PPC64_ADDR16_HIGHERA;
147        break;
148      case MCSymbolRefExpr::VK_PPC_HIGHEST:
149        Type = ELF::R_PPC64_ADDR16_HIGHEST;
150        break;
151      case MCSymbolRefExpr::VK_PPC_HIGHESTA:
152        Type = ELF::R_PPC64_ADDR16_HIGHESTA;
153        break;
154      case MCSymbolRefExpr::VK_GOT:
155        Type = ELF::R_PPC_GOT16;
156        break;
157      case MCSymbolRefExpr::VK_PPC_GOT_LO:
158        Type = ELF::R_PPC_GOT16_LO;
159        break;
160      case MCSymbolRefExpr::VK_PPC_GOT_HI:
161        Type = ELF::R_PPC_GOT16_HI;
162        break;
163      case MCSymbolRefExpr::VK_PPC_GOT_HA:
164        Type = ELF::R_PPC_GOT16_HA;
165        break;
166      case MCSymbolRefExpr::VK_PPC_TOC:
167        Type = ELF::R_PPC64_TOC16;
168        break;
169      case MCSymbolRefExpr::VK_PPC_TOC_LO:
170        Type = ELF::R_PPC64_TOC16_LO;
171        break;
172      case MCSymbolRefExpr::VK_PPC_TOC_HI:
173        Type = ELF::R_PPC64_TOC16_HI;
174        break;
175      case MCSymbolRefExpr::VK_PPC_TOC_HA:
176        Type = ELF::R_PPC64_TOC16_HA;
177        break;
178      case MCSymbolRefExpr::VK_PPC_TPREL:
179        Type = ELF::R_PPC_TPREL16;
180        break;
181      case MCSymbolRefExpr::VK_PPC_TPREL_LO:
182        Type = ELF::R_PPC_TPREL16_LO;
183        break;
184      case MCSymbolRefExpr::VK_PPC_TPREL_HI:
185        Type = ELF::R_PPC_TPREL16_HI;
186        break;
187      case MCSymbolRefExpr::VK_PPC_TPREL_HA:
188        Type = ELF::R_PPC_TPREL16_HA;
189        break;
190      case MCSymbolRefExpr::VK_PPC_TPREL_HIGHER:
191        Type = ELF::R_PPC64_TPREL16_HIGHER;
192        break;
193      case MCSymbolRefExpr::VK_PPC_TPREL_HIGHERA:
194        Type = ELF::R_PPC64_TPREL16_HIGHERA;
195        break;
196      case MCSymbolRefExpr::VK_PPC_TPREL_HIGHEST:
197        Type = ELF::R_PPC64_TPREL16_HIGHEST;
198        break;
199      case MCSymbolRefExpr::VK_PPC_TPREL_HIGHESTA:
200        Type = ELF::R_PPC64_TPREL16_HIGHESTA;
201        break;
202      case MCSymbolRefExpr::VK_PPC_DTPREL:
203        Type = ELF::R_PPC64_DTPREL16;
204        break;
205      case MCSymbolRefExpr::VK_PPC_DTPREL_LO:
206        Type = ELF::R_PPC64_DTPREL16_LO;
207        break;
208      case MCSymbolRefExpr::VK_PPC_DTPREL_HI:
209        Type = ELF::R_PPC64_DTPREL16_HI;
210        break;
211      case MCSymbolRefExpr::VK_PPC_DTPREL_HA:
212        Type = ELF::R_PPC64_DTPREL16_HA;
213        break;
214      case MCSymbolRefExpr::VK_PPC_DTPREL_HIGHER:
215        Type = ELF::R_PPC64_DTPREL16_HIGHER;
216        break;
217      case MCSymbolRefExpr::VK_PPC_DTPREL_HIGHERA:
218        Type = ELF::R_PPC64_DTPREL16_HIGHERA;
219        break;
220      case MCSymbolRefExpr::VK_PPC_DTPREL_HIGHEST:
221        Type = ELF::R_PPC64_DTPREL16_HIGHEST;
222        break;
223      case MCSymbolRefExpr::VK_PPC_DTPREL_HIGHESTA:
224        Type = ELF::R_PPC64_DTPREL16_HIGHESTA;
225        break;
226      case MCSymbolRefExpr::VK_PPC_GOT_TLSGD:
227        Type = ELF::R_PPC64_GOT_TLSGD16;
228        break;
229      case MCSymbolRefExpr::VK_PPC_GOT_TLSGD_LO:
230        Type = ELF::R_PPC64_GOT_TLSGD16_LO;
231        break;
232      case MCSymbolRefExpr::VK_PPC_GOT_TLSGD_HI:
233        Type = ELF::R_PPC64_GOT_TLSGD16_HI;
234        break;
235      case MCSymbolRefExpr::VK_PPC_GOT_TLSGD_HA:
236        Type = ELF::R_PPC64_GOT_TLSGD16_HA;
237        break;
238      case MCSymbolRefExpr::VK_PPC_GOT_TLSLD:
239        Type = ELF::R_PPC64_GOT_TLSLD16;
240        break;
241      case MCSymbolRefExpr::VK_PPC_GOT_TLSLD_LO:
242        Type = ELF::R_PPC64_GOT_TLSLD16_LO;
243        break;
244      case MCSymbolRefExpr::VK_PPC_GOT_TLSLD_HI:
245        Type = ELF::R_PPC64_GOT_TLSLD16_HI;
246        break;
247      case MCSymbolRefExpr::VK_PPC_GOT_TLSLD_HA:
248        Type = ELF::R_PPC64_GOT_TLSLD16_HA;
249        break;
250      case MCSymbolRefExpr::VK_PPC_GOT_TPREL:
251        /* We don't have R_PPC64_GOT_TPREL16, but since GOT offsets
252           are always 4-aligned, we can use R_PPC64_GOT_TPREL16_DS.  */
253        Type = ELF::R_PPC64_GOT_TPREL16_DS;
254        break;
255      case MCSymbolRefExpr::VK_PPC_GOT_TPREL_LO:
256        /* We don't have R_PPC64_GOT_TPREL16_LO, but since GOT offsets
257           are always 4-aligned, we can use R_PPC64_GOT_TPREL16_LO_DS.  */
258        Type = ELF::R_PPC64_GOT_TPREL16_LO_DS;
259        break;
260      case MCSymbolRefExpr::VK_PPC_GOT_TPREL_HI:
261        Type = ELF::R_PPC64_GOT_TPREL16_HI;
262        break;
263      case MCSymbolRefExpr::VK_PPC_GOT_DTPREL:
264        /* We don't have R_PPC64_GOT_DTPREL16, but since GOT offsets
265           are always 4-aligned, we can use R_PPC64_GOT_DTPREL16_DS.  */
266        Type = ELF::R_PPC64_GOT_DTPREL16_DS;
267        break;
268      case MCSymbolRefExpr::VK_PPC_GOT_DTPREL_LO:
269        /* We don't have R_PPC64_GOT_DTPREL16_LO, but since GOT offsets
270           are always 4-aligned, we can use R_PPC64_GOT_DTPREL16_LO_DS.  */
271        Type = ELF::R_PPC64_GOT_DTPREL16_LO_DS;
272        break;
273      case MCSymbolRefExpr::VK_PPC_GOT_TPREL_HA:
274        Type = ELF::R_PPC64_GOT_TPREL16_HA;
275        break;
276      case MCSymbolRefExpr::VK_PPC_GOT_DTPREL_HI:
277        Type = ELF::R_PPC64_GOT_DTPREL16_HI;
278        break;
279      case MCSymbolRefExpr::VK_PPC_GOT_DTPREL_HA:
280        Type = ELF::R_PPC64_GOT_DTPREL16_HA;
281        break;
282      }
283      break;
284    case PPC::fixup_ppc_half16ds:
285      switch (Modifier) {
286      default: llvm_unreachable("Unsupported Modifier");
287      case MCSymbolRefExpr::VK_None:
288        Type = ELF::R_PPC64_ADDR16_DS;
289        break;
290      case MCSymbolRefExpr::VK_PPC_LO:
291        Type = ELF::R_PPC64_ADDR16_LO_DS;
292        break;
293      case MCSymbolRefExpr::VK_GOT:
294        Type = ELF::R_PPC64_GOT16_DS;
295	break;
296      case MCSymbolRefExpr::VK_PPC_GOT_LO:
297        Type = ELF::R_PPC64_GOT16_LO_DS;
298        break;
299      case MCSymbolRefExpr::VK_PPC_TOC:
300        Type = ELF::R_PPC64_TOC16_DS;
301	break;
302      case MCSymbolRefExpr::VK_PPC_TOC_LO:
303        Type = ELF::R_PPC64_TOC16_LO_DS;
304        break;
305      case MCSymbolRefExpr::VK_PPC_TPREL:
306        Type = ELF::R_PPC64_TPREL16_DS;
307        break;
308      case MCSymbolRefExpr::VK_PPC_TPREL_LO:
309        Type = ELF::R_PPC64_TPREL16_LO_DS;
310        break;
311      case MCSymbolRefExpr::VK_PPC_DTPREL:
312        Type = ELF::R_PPC64_DTPREL16_DS;
313        break;
314      case MCSymbolRefExpr::VK_PPC_DTPREL_LO:
315        Type = ELF::R_PPC64_DTPREL16_LO_DS;
316        break;
317      case MCSymbolRefExpr::VK_PPC_GOT_TPREL:
318        Type = ELF::R_PPC64_GOT_TPREL16_DS;
319        break;
320      case MCSymbolRefExpr::VK_PPC_GOT_TPREL_LO:
321        Type = ELF::R_PPC64_GOT_TPREL16_LO_DS;
322        break;
323      case MCSymbolRefExpr::VK_PPC_GOT_DTPREL:
324        Type = ELF::R_PPC64_GOT_DTPREL16_DS;
325        break;
326      case MCSymbolRefExpr::VK_PPC_GOT_DTPREL_LO:
327        Type = ELF::R_PPC64_GOT_DTPREL16_LO_DS;
328        break;
329      }
330      break;
331    case PPC::fixup_ppc_nofixup:
332      switch (Modifier) {
333      default: llvm_unreachable("Unsupported Modifier");
334      case MCSymbolRefExpr::VK_PPC_TLSGD:
335        Type = ELF::R_PPC64_TLSGD;
336        break;
337      case MCSymbolRefExpr::VK_PPC_TLSLD:
338        Type = ELF::R_PPC64_TLSLD;
339        break;
340      case MCSymbolRefExpr::VK_PPC_TLS:
341        Type = ELF::R_PPC64_TLS;
342        break;
343      }
344      break;
345    case FK_Data_8:
346      switch (Modifier) {
347      default: llvm_unreachable("Unsupported Modifier");
348      case MCSymbolRefExpr::VK_PPC_TOCBASE:
349        Type = ELF::R_PPC64_TOC;
350        break;
351      case MCSymbolRefExpr::VK_None:
352        Type = ELF::R_PPC64_ADDR64;
353	break;
354      case MCSymbolRefExpr::VK_PPC_DTPMOD:
355        Type = ELF::R_PPC64_DTPMOD64;
356	break;
357      case MCSymbolRefExpr::VK_PPC_TPREL:
358        Type = ELF::R_PPC64_TPREL64;
359	break;
360      case MCSymbolRefExpr::VK_PPC_DTPREL:
361        Type = ELF::R_PPC64_DTPREL64;
362	break;
363      }
364      break;
365    case FK_Data_4:
366      Type = ELF::R_PPC_ADDR32;
367      break;
368    case FK_Data_2:
369      Type = ELF::R_PPC_ADDR16;
370      break;
371    }
372  }
373  return Type;
374}
375
376unsigned PPCELFObjectWriter::GetRelocType(const MCValue &Target,
377                                          const MCFixup &Fixup,
378                                          bool IsPCRel) const {
379  return getRelocTypeInner(Target, Fixup, IsPCRel);
380}
381
382MCObjectWriter *llvm::createPPCELFObjectWriter(raw_ostream &OS,
383                                               bool Is64Bit,
384                                               bool IsLittleEndian,
385                                               uint8_t OSABI) {
386  MCELFObjectTargetWriter *MOTW = new PPCELFObjectWriter(Is64Bit, OSABI);
387  return createELFObjectWriter(MOTW, OS, IsLittleEndian);
388}
389