1234285Sdim//===-- ARMELFObjectWriter.cpp - ARM ELF Writer ---------------------------===//
2234285Sdim//
3234285Sdim//                     The LLVM Compiler Infrastructure
4234285Sdim//
5234285Sdim// This file is distributed under the University of Illinois Open Source
6234285Sdim// License. See LICENSE.TXT for details.
7234285Sdim//
8234285Sdim//===----------------------------------------------------------------------===//
9234285Sdim
10249423Sdim#include "MCTargetDesc/ARMMCTargetDesc.h"
11234285Sdim#include "MCTargetDesc/ARMFixupKinds.h"
12234285Sdim#include "llvm/ADT/Statistic.h"
13234285Sdim#include "llvm/ADT/StringSwitch.h"
14234285Sdim#include "llvm/MC/MCELFObjectWriter.h"
15234285Sdim#include "llvm/MC/MCExpr.h"
16234285Sdim#include "llvm/MC/MCSectionELF.h"
17234285Sdim#include "llvm/MC/MCValue.h"
18249423Sdim#include "llvm/Support/Debug.h"
19249423Sdim#include "llvm/Support/ErrorHandling.h"
20249423Sdim#include "llvm/Support/raw_ostream.h"
21234285Sdim
22234285Sdimusing namespace llvm;
23234285Sdim
24234285Sdimnamespace {
25234285Sdim  class ARMELFObjectWriter : public MCELFObjectTargetWriter {
26234285Sdim    enum { DefaultEABIVersion = 0x05000000U };
27234285Sdim    unsigned GetRelocTypeInner(const MCValue &Target,
28234285Sdim                               const MCFixup &Fixup,
29234285Sdim                               bool IsPCRel) const;
30234285Sdim
31234285Sdim
32234285Sdim  public:
33234285Sdim    ARMELFObjectWriter(uint8_t OSABI);
34234285Sdim
35288943Sdim    ~ARMELFObjectWriter() override;
36234285Sdim
37276479Sdim    unsigned GetRelocType(const MCValue &Target, const MCFixup &Fixup,
38276479Sdim                          bool IsPCRel) const override;
39276479Sdim
40288943Sdim    bool needsRelocateWithSymbol(const MCSymbol &Sym,
41276479Sdim                                 unsigned Type) const override;
42234285Sdim  };
43234285Sdim}
44234285Sdim
45234285SdimARMELFObjectWriter::ARMELFObjectWriter(uint8_t OSABI)
46234285Sdim  : MCELFObjectTargetWriter(/*Is64Bit*/ false, OSABI,
47234285Sdim                            ELF::EM_ARM,
48234285Sdim                            /*HasRelocationAddend*/ false) {}
49234285Sdim
50234285SdimARMELFObjectWriter::~ARMELFObjectWriter() {}
51234285Sdim
52288943Sdimbool ARMELFObjectWriter::needsRelocateWithSymbol(const MCSymbol &Sym,
53276479Sdim                                                 unsigned Type) const {
54280031Sdim  // FIXME: This is extremely conservative. This really needs to use a
55276479Sdim  // whitelist with a clear explanation for why each realocation needs to
56276479Sdim  // point to the symbol, not to the section.
57276479Sdim  switch (Type) {
58276479Sdim  default:
59276479Sdim    return true;
60234285Sdim
61276479Sdim  case ELF::R_ARM_PREL31:
62276479Sdim  case ELF::R_ARM_ABS32:
63276479Sdim    return false;
64234285Sdim  }
65234285Sdim}
66234285Sdim
67234285Sdim// Need to examine the Fixup when determining whether to
68234285Sdim// emit the relocation as an explicit symbol or as a section relative
69234285Sdim// offset
70234285Sdimunsigned ARMELFObjectWriter::GetRelocType(const MCValue &Target,
71234285Sdim                                          const MCFixup &Fixup,
72276479Sdim                                          bool IsPCRel) const {
73234285Sdim  return GetRelocTypeInner(Target, Fixup, IsPCRel);
74234285Sdim}
75234285Sdim
76234285Sdimunsigned ARMELFObjectWriter::GetRelocTypeInner(const MCValue &Target,
77234285Sdim                                               const MCFixup &Fixup,
78234285Sdim                                               bool IsPCRel) const  {
79276479Sdim  MCSymbolRefExpr::VariantKind Modifier = Target.getAccessVariant();
80234285Sdim
81234285Sdim  unsigned Type = 0;
82234285Sdim  if (IsPCRel) {
83234285Sdim    switch ((unsigned)Fixup.getKind()) {
84288943Sdim    default:
85288943Sdim      report_fatal_error("unsupported relocation on symbol");
86288943Sdim      return ELF::R_ARM_NONE;
87234285Sdim    case FK_Data_4:
88234285Sdim      switch (Modifier) {
89234285Sdim      default: llvm_unreachable("Unsupported Modifier");
90234285Sdim      case MCSymbolRefExpr::VK_None:
91234285Sdim        Type = ELF::R_ARM_REL32;
92234285Sdim        break;
93276479Sdim      case MCSymbolRefExpr::VK_TLSGD:
94234285Sdim        llvm_unreachable("unimplemented");
95276479Sdim      case MCSymbolRefExpr::VK_GOTTPOFF:
96234285Sdim        Type = ELF::R_ARM_TLS_IE32;
97234285Sdim        break;
98296417Sdim      case MCSymbolRefExpr::VK_ARM_GOT_PREL:
99276479Sdim        Type = ELF::R_ARM_GOT_PREL;
100276479Sdim        break;
101234285Sdim      }
102234285Sdim      break;
103239462Sdim    case ARM::fixup_arm_blx:
104234285Sdim    case ARM::fixup_arm_uncondbl:
105234285Sdim      switch (Modifier) {
106276479Sdim      case MCSymbolRefExpr::VK_PLT:
107280031Sdim        Type = ELF::R_ARM_CALL;
108234285Sdim        break;
109276479Sdim      case MCSymbolRefExpr::VK_ARM_TLSCALL:
110276479Sdim        Type = ELF::R_ARM_TLS_CALL;
111276479Sdim        break;
112234285Sdim      default:
113234285Sdim        Type = ELF::R_ARM_CALL;
114234285Sdim        break;
115234285Sdim      }
116234285Sdim      break;
117234285Sdim    case ARM::fixup_arm_condbl:
118234285Sdim    case ARM::fixup_arm_condbranch:
119239462Sdim    case ARM::fixup_arm_uncondbranch:
120234285Sdim      Type = ELF::R_ARM_JUMP24;
121234285Sdim      break;
122243830Sdim    case ARM::fixup_t2_condbranch:
123243830Sdim    case ARM::fixup_t2_uncondbranch:
124243830Sdim      Type = ELF::R_ARM_THM_JUMP24;
125243830Sdim      break;
126234285Sdim    case ARM::fixup_arm_movt_hi16:
127234285Sdim      Type = ELF::R_ARM_MOVT_PREL;
128234285Sdim      break;
129234285Sdim    case ARM::fixup_arm_movw_lo16:
130234285Sdim      Type = ELF::R_ARM_MOVW_PREL_NC;
131234285Sdim      break;
132234285Sdim    case ARM::fixup_t2_movt_hi16:
133234285Sdim      Type = ELF::R_ARM_THM_MOVT_PREL;
134234285Sdim      break;
135234285Sdim    case ARM::fixup_t2_movw_lo16:
136234285Sdim      Type = ELF::R_ARM_THM_MOVW_PREL_NC;
137234285Sdim      break;
138234285Sdim    case ARM::fixup_arm_thumb_bl:
139234285Sdim    case ARM::fixup_arm_thumb_blx:
140276479Sdim      switch (Modifier) {
141276479Sdim      case MCSymbolRefExpr::VK_ARM_TLSCALL:
142276479Sdim        Type = ELF::R_ARM_THM_TLS_CALL;
143276479Sdim        break;
144276479Sdim      default:
145276479Sdim        Type = ELF::R_ARM_THM_CALL;
146276479Sdim        break;
147276479Sdim      }
148234285Sdim      break;
149234285Sdim    }
150234285Sdim  } else {
151234285Sdim    switch ((unsigned)Fixup.getKind()) {
152288943Sdim    default:
153288943Sdim      report_fatal_error("unsupported relocation on symbol");
154288943Sdim      return ELF::R_ARM_NONE;
155280031Sdim    case FK_Data_1:
156280031Sdim      switch (Modifier) {
157280031Sdim      default: llvm_unreachable("unsupported Modifier");
158280031Sdim      case MCSymbolRefExpr::VK_None:
159280031Sdim        Type = ELF::R_ARM_ABS8;
160280031Sdim        break;
161280031Sdim      }
162280031Sdim      break;
163280031Sdim    case FK_Data_2:
164280031Sdim      switch (Modifier) {
165280031Sdim      default: llvm_unreachable("unsupported modifier");
166280031Sdim      case MCSymbolRefExpr::VK_None:
167280031Sdim        Type = ELF::R_ARM_ABS16;
168280031Sdim        break;
169280031Sdim      }
170280031Sdim      break;
171234285Sdim    case FK_Data_4:
172234285Sdim      switch (Modifier) {
173234285Sdim      default: llvm_unreachable("Unsupported Modifier");
174249423Sdim      case MCSymbolRefExpr::VK_ARM_NONE:
175249423Sdim        Type = ELF::R_ARM_NONE;
176249423Sdim        break;
177276479Sdim      case MCSymbolRefExpr::VK_GOT:
178234285Sdim        Type = ELF::R_ARM_GOT_BREL;
179234285Sdim        break;
180276479Sdim      case MCSymbolRefExpr::VK_TLSGD:
181234285Sdim        Type = ELF::R_ARM_TLS_GD32;
182234285Sdim        break;
183276479Sdim      case MCSymbolRefExpr::VK_TPOFF:
184234285Sdim        Type = ELF::R_ARM_TLS_LE32;
185234285Sdim        break;
186276479Sdim      case MCSymbolRefExpr::VK_GOTTPOFF:
187234285Sdim        Type = ELF::R_ARM_TLS_IE32;
188234285Sdim        break;
189234285Sdim      case MCSymbolRefExpr::VK_None:
190234285Sdim        Type = ELF::R_ARM_ABS32;
191234285Sdim        break;
192276479Sdim      case MCSymbolRefExpr::VK_GOTOFF:
193234285Sdim        Type = ELF::R_ARM_GOTOFF32;
194234285Sdim        break;
195296417Sdim      case MCSymbolRefExpr::VK_ARM_GOT_PREL:
196276479Sdim        Type = ELF::R_ARM_GOT_PREL;
197276479Sdim        break;
198234285Sdim      case MCSymbolRefExpr::VK_ARM_TARGET1:
199234285Sdim        Type = ELF::R_ARM_TARGET1;
200234285Sdim        break;
201243830Sdim      case MCSymbolRefExpr::VK_ARM_TARGET2:
202243830Sdim        Type = ELF::R_ARM_TARGET2;
203243830Sdim        break;
204249423Sdim      case MCSymbolRefExpr::VK_ARM_PREL31:
205249423Sdim        Type = ELF::R_ARM_PREL31;
206249423Sdim        break;
207280031Sdim      case MCSymbolRefExpr::VK_ARM_SBREL:
208280031Sdim        Type = ELF::R_ARM_SBREL32;
209280031Sdim        break;
210276479Sdim      case MCSymbolRefExpr::VK_ARM_TLSLDO:
211276479Sdim        Type = ELF::R_ARM_TLS_LDO32;
212276479Sdim        break;
213276479Sdim      case MCSymbolRefExpr::VK_ARM_TLSCALL:
214276479Sdim        Type = ELF::R_ARM_TLS_CALL;
215276479Sdim        break;
216276479Sdim      case MCSymbolRefExpr::VK_ARM_TLSDESC:
217276479Sdim        Type = ELF::R_ARM_TLS_GOTDESC;
218276479Sdim        break;
219276479Sdim      case MCSymbolRefExpr::VK_ARM_TLSDESCSEQ:
220276479Sdim        Type = ELF::R_ARM_TLS_DESCSEQ;
221276479Sdim        break;
222249423Sdim      }
223234285Sdim      break;
224234285Sdim    case ARM::fixup_arm_ldst_pcrel_12:
225234285Sdim    case ARM::fixup_arm_pcrel_10:
226234285Sdim    case ARM::fixup_arm_adr_pcrel_12:
227234285Sdim    case ARM::fixup_arm_thumb_bl:
228234285Sdim    case ARM::fixup_arm_thumb_cb:
229234285Sdim    case ARM::fixup_arm_thumb_cp:
230234285Sdim    case ARM::fixup_arm_thumb_br:
231234285Sdim      llvm_unreachable("Unimplemented");
232239462Sdim    case ARM::fixup_arm_condbranch:
233234285Sdim    case ARM::fixup_arm_uncondbranch:
234234285Sdim      Type = ELF::R_ARM_JUMP24;
235234285Sdim      break;
236234285Sdim    case ARM::fixup_arm_movt_hi16:
237234285Sdim      Type = ELF::R_ARM_MOVT_ABS;
238234285Sdim      break;
239234285Sdim    case ARM::fixup_arm_movw_lo16:
240234285Sdim      Type = ELF::R_ARM_MOVW_ABS_NC;
241234285Sdim      break;
242234285Sdim    case ARM::fixup_t2_movt_hi16:
243234285Sdim      Type = ELF::R_ARM_THM_MOVT_ABS;
244234285Sdim      break;
245234285Sdim    case ARM::fixup_t2_movw_lo16:
246234285Sdim      Type = ELF::R_ARM_THM_MOVW_ABS_NC;
247234285Sdim      break;
248234285Sdim    }
249234285Sdim  }
250234285Sdim
251234285Sdim  return Type;
252234285Sdim}
253234285Sdim
254288943SdimMCObjectWriter *llvm::createARMELFObjectWriter(raw_pwrite_stream &OS,
255276479Sdim                                               uint8_t OSABI,
256276479Sdim                                               bool IsLittleEndian) {
257234285Sdim  MCELFObjectTargetWriter *MOTW = new ARMELFObjectWriter(OSABI);
258276479Sdim  return createELFObjectWriter(MOTW, OS, IsLittleEndian);
259234285Sdim}
260