ARMELFObjectWriter.cpp revision bc2198133a1836598b54b943420748e75d5dea94
1//===-- ARMELFObjectWriter.cpp - ARM 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/ARMFixupKinds.h"
11#include "MCTargetDesc/ARMMCTargetDesc.h"
12#include "llvm/Support/Debug.h"
13#include "llvm/Support/ErrorHandling.h"
14#include "llvm/ADT/Statistic.h"
15#include "llvm/ADT/StringSwitch.h"
16#include "llvm/MC/MCELFObjectWriter.h"
17#include "llvm/MC/MCExpr.h"
18#include "llvm/MC/MCSectionELF.h"
19#include "llvm/MC/MCValue.h"
20
21using namespace llvm;
22
23namespace {
24  class ARMELFObjectWriter : public MCELFObjectTargetWriter {
25    enum { DefaultEABIVersion = 0x05000000U };
26    unsigned GetRelocTypeInner(const MCValue &Target,
27                               const MCFixup &Fixup,
28                               bool IsPCRel) const;
29
30
31  public:
32    ARMELFObjectWriter(uint8_t OSABI);
33
34    virtual ~ARMELFObjectWriter();
35
36    virtual unsigned GetRelocType(const MCValue &Target, const MCFixup &Fixup,
37                                  bool IsPCRel, bool IsRelocWithSymbol,
38                                  int64_t Addend) const;
39    virtual unsigned getEFlags() const;
40    virtual const MCSymbol *ExplicitRelSym(const MCAssembler &Asm,
41                                   const MCValue &Target,
42                                   const MCFragment &F,
43                                   const MCFixup &Fixup,
44                                   bool IsPCRel) const;
45  };
46}
47
48ARMELFObjectWriter::ARMELFObjectWriter(uint8_t OSABI)
49  : MCELFObjectTargetWriter(/*Is64Bit*/ false, OSABI,
50                            ELF::EM_ARM,
51                            /*HasRelocationAddend*/ false) {}
52
53ARMELFObjectWriter::~ARMELFObjectWriter() {}
54
55// FIXME: get the real EABI Version from the Triple.
56unsigned ARMELFObjectWriter::getEFlags() const {
57  return ELF::EF_ARM_EABIMASK & DefaultEABIVersion;
58}
59
60// In ARM, _MergedGlobals and other most symbols get emitted directly.
61// I.e. not as an offset to a section symbol.
62// This code is an approximation of what ARM/gcc does.
63
64STATISTIC(PCRelCount, "Total number of PIC Relocations");
65STATISTIC(NonPCRelCount, "Total number of non-PIC relocations");
66
67const MCSymbol *ARMELFObjectWriter::ExplicitRelSym(const MCAssembler &Asm,
68                                                   const MCValue &Target,
69                                                   const MCFragment &F,
70                                                   const MCFixup &Fixup,
71                                                   bool IsPCRel) const {
72  const MCSymbol &Symbol = Target.getSymA()->getSymbol().AliasedSymbol();
73  bool EmitThisSym = false;
74
75  const MCSectionELF &Section =
76    static_cast<const MCSectionELF&>(Symbol.getSection());
77  bool InNormalSection = true;
78  unsigned RelocType = 0;
79  RelocType = GetRelocTypeInner(Target, Fixup, IsPCRel);
80
81  DEBUG(
82      const MCSymbolRefExpr::VariantKind Kind = Target.getSymA()->getKind();
83      MCSymbolRefExpr::VariantKind Kind2;
84      Kind2 = Target.getSymB() ?  Target.getSymB()->getKind() :
85        MCSymbolRefExpr::VK_None;
86      dbgs() << "considering symbol "
87        << Section.getSectionName() << "/"
88        << Symbol.getName() << "/"
89        << " Rel:" << (unsigned)RelocType
90        << " Kind: " << (int)Kind << "/" << (int)Kind2
91        << " Tmp:"
92        << Symbol.isAbsolute() << "/" << Symbol.isDefined() << "/"
93        << Symbol.isVariable() << "/" << Symbol.isTemporary()
94        << " Counts:" << PCRelCount << "/" << NonPCRelCount << "\n");
95
96  if (IsPCRel) { ++PCRelCount;
97    switch (RelocType) {
98    default:
99      // Most relocation types are emitted as explicit symbols
100      InNormalSection =
101        StringSwitch<bool>(Section.getSectionName())
102        .Case(".data.rel.ro.local", false)
103        .Case(".data.rel", false)
104        .Case(".bss", false)
105        .Default(true);
106      EmitThisSym = true;
107      break;
108    case ELF::R_ARM_ABS32:
109      // But things get strange with R_ARM_ABS32
110      // In this case, most things that go in .rodata show up
111      // as section relative relocations
112      InNormalSection =
113        StringSwitch<bool>(Section.getSectionName())
114        .Case(".data.rel.ro.local", false)
115        .Case(".data.rel", false)
116        .Case(".rodata", false)
117        .Case(".bss", false)
118        .Default(true);
119      EmitThisSym = false;
120      break;
121    }
122  } else {
123    NonPCRelCount++;
124    InNormalSection =
125      StringSwitch<bool>(Section.getSectionName())
126      .Case(".data.rel.ro.local", false)
127      .Case(".rodata", false)
128      .Case(".data.rel", false)
129      .Case(".bss", false)
130      .Default(true);
131
132    switch (RelocType) {
133    default: EmitThisSym = true; break;
134    case ELF::R_ARM_ABS32: EmitThisSym = false; break;
135    }
136  }
137
138  if (EmitThisSym)
139    return &Symbol;
140  if (! Symbol.isTemporary() && InNormalSection) {
141    return &Symbol;
142  }
143  return NULL;
144}
145
146// Need to examine the Fixup when determining whether to
147// emit the relocation as an explicit symbol or as a section relative
148// offset
149unsigned ARMELFObjectWriter::GetRelocType(const MCValue &Target,
150                                          const MCFixup &Fixup,
151                                          bool IsPCRel,
152                                          bool IsRelocWithSymbol,
153                                          int64_t Addend) const {
154  return GetRelocTypeInner(Target, Fixup, IsPCRel);
155}
156
157unsigned ARMELFObjectWriter::GetRelocTypeInner(const MCValue &Target,
158                                               const MCFixup &Fixup,
159                                               bool IsPCRel) const  {
160  MCSymbolRefExpr::VariantKind Modifier = Target.isAbsolute() ?
161    MCSymbolRefExpr::VK_None : Target.getSymA()->getKind();
162
163  unsigned Type = 0;
164  if (IsPCRel) {
165    switch ((unsigned)Fixup.getKind()) {
166    default: llvm_unreachable("Unimplemented");
167    case FK_Data_4:
168      switch (Modifier) {
169      default: llvm_unreachable("Unsupported Modifier");
170      case MCSymbolRefExpr::VK_None:
171        Type = ELF::R_ARM_REL32;
172        break;
173      case MCSymbolRefExpr::VK_ARM_TLSGD:
174        llvm_unreachable("unimplemented");
175      case MCSymbolRefExpr::VK_ARM_GOTTPOFF:
176        Type = ELF::R_ARM_TLS_IE32;
177        break;
178      }
179      break;
180    case ARM::fixup_arm_uncondbranch:
181      switch (Modifier) {
182      case MCSymbolRefExpr::VK_ARM_PLT:
183        Type = ELF::R_ARM_PLT32;
184        break;
185      default:
186        Type = ELF::R_ARM_CALL;
187        break;
188      }
189      break;
190    case ARM::fixup_arm_condbranch:
191      Type = ELF::R_ARM_JUMP24;
192      break;
193    case ARM::fixup_arm_movt_hi16:
194    case ARM::fixup_arm_movt_hi16_pcrel:
195      Type = ELF::R_ARM_MOVT_PREL;
196      break;
197    case ARM::fixup_arm_movw_lo16:
198    case ARM::fixup_arm_movw_lo16_pcrel:
199      Type = ELF::R_ARM_MOVW_PREL_NC;
200      break;
201    case ARM::fixup_t2_movt_hi16:
202    case ARM::fixup_t2_movt_hi16_pcrel:
203      Type = ELF::R_ARM_THM_MOVT_PREL;
204      break;
205    case ARM::fixup_t2_movw_lo16:
206    case ARM::fixup_t2_movw_lo16_pcrel:
207      Type = ELF::R_ARM_THM_MOVW_PREL_NC;
208      break;
209    case ARM::fixup_arm_thumb_bl:
210    case ARM::fixup_arm_thumb_blx:
211      Type = ELF::R_ARM_THM_CALL;
212      break;
213    }
214  } else {
215    switch ((unsigned)Fixup.getKind()) {
216    default: llvm_unreachable("invalid fixup kind!");
217    case FK_Data_4:
218      switch (Modifier) {
219      default: llvm_unreachable("Unsupported Modifier");
220      case MCSymbolRefExpr::VK_ARM_GOT:
221        Type = ELF::R_ARM_GOT_BREL;
222        break;
223      case MCSymbolRefExpr::VK_ARM_TLSGD:
224        Type = ELF::R_ARM_TLS_GD32;
225        break;
226      case MCSymbolRefExpr::VK_ARM_TPOFF:
227        Type = ELF::R_ARM_TLS_LE32;
228        break;
229      case MCSymbolRefExpr::VK_ARM_GOTTPOFF:
230        Type = ELF::R_ARM_TLS_IE32;
231        break;
232      case MCSymbolRefExpr::VK_None:
233        Type = ELF::R_ARM_ABS32;
234        break;
235      case MCSymbolRefExpr::VK_ARM_GOTOFF:
236        Type = ELF::R_ARM_GOTOFF32;
237        break;
238      case MCSymbolRefExpr::VK_ARM_TARGET1:
239        Type = ELF::R_ARM_TARGET1;
240        break;
241      }
242      break;
243    case ARM::fixup_arm_ldst_pcrel_12:
244    case ARM::fixup_arm_pcrel_10:
245    case ARM::fixup_arm_adr_pcrel_12:
246    case ARM::fixup_arm_thumb_bl:
247    case ARM::fixup_arm_thumb_cb:
248    case ARM::fixup_arm_thumb_cp:
249    case ARM::fixup_arm_thumb_br:
250      llvm_unreachable("Unimplemented");
251    case ARM::fixup_arm_uncondbranch:
252      Type = ELF::R_ARM_CALL;
253      break;
254    case ARM::fixup_arm_condbranch:
255      Type = ELF::R_ARM_JUMP24;
256      break;
257    case ARM::fixup_arm_movt_hi16:
258      Type = ELF::R_ARM_MOVT_ABS;
259      break;
260    case ARM::fixup_arm_movw_lo16:
261      Type = ELF::R_ARM_MOVW_ABS_NC;
262      break;
263    case ARM::fixup_t2_movt_hi16:
264      Type = ELF::R_ARM_THM_MOVT_ABS;
265      break;
266    case ARM::fixup_t2_movw_lo16:
267      Type = ELF::R_ARM_THM_MOVW_ABS_NC;
268      break;
269    }
270  }
271
272  return Type;
273}
274
275MCObjectWriter *llvm::createARMELFObjectWriter(raw_ostream &OS,
276                                               uint8_t OSABI) {
277  MCELFObjectTargetWriter *MOTW = new ARMELFObjectWriter(OSABI);
278  return createELFObjectWriter(MOTW, OS,  /*IsLittleEndian=*/true);
279}
280