1//===-- ARMELFObjectWriter.cpp - ARM ELF Writer ---------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "MCTargetDesc/ARMFixupKinds.h"
10#include "MCTargetDesc/ARMMCTargetDesc.h"
11#include "llvm/BinaryFormat/ELF.h"
12#include "llvm/MC/MCContext.h"
13#include "llvm/MC/MCELFObjectWriter.h"
14#include "llvm/MC/MCExpr.h"
15#include "llvm/MC/MCFixup.h"
16#include "llvm/MC/MCObjectFileInfo.h"
17#include "llvm/MC/MCObjectWriter.h"
18#include "llvm/MC/MCValue.h"
19#include "llvm/Support/ErrorHandling.h"
20#include "llvm/Support/raw_ostream.h"
21#include <cstdint>
22
23using namespace llvm;
24
25namespace {
26
27  class ARMELFObjectWriter : public MCELFObjectTargetWriter {
28    enum { DefaultEABIVersion = 0x05000000U };
29
30    unsigned GetRelocTypeInner(const MCValue &Target, const MCFixup &Fixup,
31                               bool IsPCRel, MCContext &Ctx) const;
32
33  public:
34    ARMELFObjectWriter(uint8_t OSABI);
35
36    ~ARMELFObjectWriter() override = default;
37
38    unsigned getRelocType(MCContext &Ctx, const MCValue &Target,
39                          const MCFixup &Fixup, bool IsPCRel) const override;
40
41    bool needsRelocateWithSymbol(const MCSymbol &Sym,
42                                 unsigned Type) const override;
43
44    void addTargetSectionFlags(MCContext &Ctx, MCSectionELF &Sec) override;
45  };
46
47} // end anonymous namespace
48
49ARMELFObjectWriter::ARMELFObjectWriter(uint8_t OSABI)
50  : MCELFObjectTargetWriter(/*Is64Bit*/ false, OSABI,
51                            ELF::EM_ARM,
52                            /*HasRelocationAddend*/ false) {}
53
54bool ARMELFObjectWriter::needsRelocateWithSymbol(const MCSymbol &Sym,
55                                                 unsigned Type) const {
56  // FIXME: This is extremely conservative. This really needs to use an
57  // explicit list with a clear explanation for why each realocation needs to
58  // point to the symbol, not to the section.
59  switch (Type) {
60  default:
61    return true;
62
63  case ELF::R_ARM_PREL31:
64  case ELF::R_ARM_ABS32:
65    return false;
66  }
67}
68
69// Need to examine the Fixup when determining whether to
70// emit the relocation as an explicit symbol or as a section relative
71// offset
72unsigned ARMELFObjectWriter::getRelocType(MCContext &Ctx, const MCValue &Target,
73                                          const MCFixup &Fixup,
74                                          bool IsPCRel) const {
75  return GetRelocTypeInner(Target, Fixup, IsPCRel, Ctx);
76}
77
78unsigned ARMELFObjectWriter::GetRelocTypeInner(const MCValue &Target,
79                                               const MCFixup &Fixup,
80                                               bool IsPCRel,
81                                               MCContext &Ctx) const {
82  unsigned Kind = Fixup.getTargetKind();
83  if (Kind >= FirstLiteralRelocationKind)
84    return Kind - FirstLiteralRelocationKind;
85  MCSymbolRefExpr::VariantKind Modifier = Target.getAccessVariant();
86
87  if (IsPCRel) {
88    switch (Fixup.getTargetKind()) {
89    default:
90      Ctx.reportFatalError(Fixup.getLoc(), "unsupported relocation on symbol");
91      return ELF::R_ARM_NONE;
92    case FK_Data_4:
93      switch (Modifier) {
94      default:
95        Ctx.reportError(Fixup.getLoc(),
96                        "invalid fixup for 4-byte pc-relative data relocation");
97        return ELF::R_ARM_NONE;
98      case MCSymbolRefExpr::VK_None: {
99        if (const MCSymbolRefExpr *SymRef = Target.getSymA()) {
100          // For GNU AS compatibility expressions such as
101          // _GLOBAL_OFFSET_TABLE_ - label emit a R_ARM_BASE_PREL relocation.
102          if (SymRef->getSymbol().getName() == "_GLOBAL_OFFSET_TABLE_")
103            return ELF::R_ARM_BASE_PREL;
104        }
105        return ELF::R_ARM_REL32;
106      }
107      case MCSymbolRefExpr::VK_GOTTPOFF:
108        return ELF::R_ARM_TLS_IE32;
109      case MCSymbolRefExpr::VK_ARM_GOT_PREL:
110        return ELF::R_ARM_GOT_PREL;
111      case MCSymbolRefExpr::VK_ARM_PREL31:
112        return ELF::R_ARM_PREL31;
113      }
114    case ARM::fixup_arm_blx:
115    case ARM::fixup_arm_uncondbl:
116      switch (Modifier) {
117      case MCSymbolRefExpr::VK_PLT:
118        return ELF::R_ARM_CALL;
119      case MCSymbolRefExpr::VK_TLSCALL:
120        return ELF::R_ARM_TLS_CALL;
121      default:
122        return ELF::R_ARM_CALL;
123      }
124    case ARM::fixup_arm_condbl:
125    case ARM::fixup_arm_condbranch:
126    case ARM::fixup_arm_uncondbranch:
127      return ELF::R_ARM_JUMP24;
128    case ARM::fixup_t2_condbranch:
129      return ELF::R_ARM_THM_JUMP19;
130    case ARM::fixup_t2_uncondbranch:
131      return ELF::R_ARM_THM_JUMP24;
132    case ARM::fixup_arm_movt_hi16:
133      return ELF::R_ARM_MOVT_PREL;
134    case ARM::fixup_arm_movw_lo16:
135      return ELF::R_ARM_MOVW_PREL_NC;
136    case ARM::fixup_t2_movt_hi16:
137      return ELF::R_ARM_THM_MOVT_PREL;
138    case ARM::fixup_t2_movw_lo16:
139      return ELF::R_ARM_THM_MOVW_PREL_NC;
140    case ARM::fixup_arm_thumb_br:
141      return ELF::R_ARM_THM_JUMP11;
142    case ARM::fixup_arm_thumb_bcc:
143      return ELF::R_ARM_THM_JUMP8;
144    case ARM::fixup_arm_thumb_bl:
145    case ARM::fixup_arm_thumb_blx:
146      switch (Modifier) {
147      case MCSymbolRefExpr::VK_TLSCALL:
148        return ELF::R_ARM_THM_TLS_CALL;
149      default:
150        return ELF::R_ARM_THM_CALL;
151      }
152    case ARM::fixup_bf_target:
153      return ELF::R_ARM_THM_BF16;
154    case ARM::fixup_bfc_target:
155      return ELF::R_ARM_THM_BF12;
156    case ARM::fixup_bfl_target:
157      return ELF::R_ARM_THM_BF18;
158    }
159  }
160  switch (Kind) {
161  default:
162    Ctx.reportFatalError(Fixup.getLoc(), "unsupported relocation on symbol");
163    return ELF::R_ARM_NONE;
164  case FK_Data_1:
165    switch (Modifier) {
166    default:
167      Ctx.reportError(Fixup.getLoc(),
168                      "invalid fixup for 1-byte data relocation");
169      return ELF::R_ARM_NONE;
170    case MCSymbolRefExpr::VK_None:
171      return ELF::R_ARM_ABS8;
172    }
173  case FK_Data_2:
174    switch (Modifier) {
175    default:
176      Ctx.reportError(Fixup.getLoc(),
177                      "invalid fixup for 2-byte data relocation");
178      return ELF::R_ARM_NONE;
179    case MCSymbolRefExpr::VK_None:
180      return ELF::R_ARM_ABS16;
181    }
182  case FK_Data_4:
183    switch (Modifier) {
184    default:
185      Ctx.reportError(Fixup.getLoc(),
186                      "invalid fixup for 4-byte data relocation");
187      return ELF::R_ARM_NONE;
188    case MCSymbolRefExpr::VK_ARM_NONE:
189      return ELF::R_ARM_NONE;
190    case MCSymbolRefExpr::VK_GOT:
191      return ELF::R_ARM_GOT_BREL;
192    case MCSymbolRefExpr::VK_TLSGD:
193      return ELF::R_ARM_TLS_GD32;
194    case MCSymbolRefExpr::VK_TPOFF:
195      return ELF::R_ARM_TLS_LE32;
196    case MCSymbolRefExpr::VK_GOTTPOFF:
197      return ELF::R_ARM_TLS_IE32;
198    case MCSymbolRefExpr::VK_None:
199      return ELF::R_ARM_ABS32;
200    case MCSymbolRefExpr::VK_GOTOFF:
201      return ELF::R_ARM_GOTOFF32;
202    case MCSymbolRefExpr::VK_ARM_GOT_PREL:
203      return ELF::R_ARM_GOT_PREL;
204    case MCSymbolRefExpr::VK_ARM_TARGET1:
205      return ELF::R_ARM_TARGET1;
206    case MCSymbolRefExpr::VK_ARM_TARGET2:
207      return ELF::R_ARM_TARGET2;
208    case MCSymbolRefExpr::VK_ARM_PREL31:
209      return ELF::R_ARM_PREL31;
210    case MCSymbolRefExpr::VK_ARM_SBREL:
211      return ELF::R_ARM_SBREL32;
212    case MCSymbolRefExpr::VK_ARM_TLSLDO:
213      return ELF::R_ARM_TLS_LDO32;
214    case MCSymbolRefExpr::VK_TLSCALL:
215      return ELF::R_ARM_TLS_CALL;
216    case MCSymbolRefExpr::VK_TLSDESC:
217      return ELF::R_ARM_TLS_GOTDESC;
218    case MCSymbolRefExpr::VK_TLSLDM:
219      return ELF::R_ARM_TLS_LDM32;
220    case MCSymbolRefExpr::VK_ARM_TLSDESCSEQ:
221      return ELF::R_ARM_TLS_DESCSEQ;
222    }
223  case ARM::fixup_arm_condbranch:
224  case ARM::fixup_arm_uncondbranch:
225    return ELF::R_ARM_JUMP24;
226  case ARM::fixup_arm_movt_hi16:
227    switch (Modifier) {
228    default:
229      Ctx.reportError(Fixup.getLoc(), "invalid fixup for ARM MOVT instruction");
230      return ELF::R_ARM_NONE;
231    case MCSymbolRefExpr::VK_None:
232      return ELF::R_ARM_MOVT_ABS;
233    case MCSymbolRefExpr::VK_ARM_SBREL:
234      return ELF::R_ARM_MOVT_BREL;
235    }
236  case ARM::fixup_arm_movw_lo16:
237    switch (Modifier) {
238    default:
239      Ctx.reportError(Fixup.getLoc(), "invalid fixup for ARM MOVW instruction");
240      return ELF::R_ARM_NONE;
241    case MCSymbolRefExpr::VK_None:
242      return ELF::R_ARM_MOVW_ABS_NC;
243    case MCSymbolRefExpr::VK_ARM_SBREL:
244      return ELF::R_ARM_MOVW_BREL_NC;
245    }
246  case ARM::fixup_t2_movt_hi16:
247    switch (Modifier) {
248    default:
249      Ctx.reportError(Fixup.getLoc(),
250                      "invalid fixup for Thumb MOVT instruction");
251      return ELF::R_ARM_NONE;
252    case MCSymbolRefExpr::VK_None:
253      return ELF::R_ARM_THM_MOVT_ABS;
254    case MCSymbolRefExpr::VK_ARM_SBREL:
255      return ELF::R_ARM_THM_MOVT_BREL;
256    }
257  case ARM::fixup_t2_movw_lo16:
258    switch (Modifier) {
259    default:
260      Ctx.reportError(Fixup.getLoc(),
261                      "invalid fixup for Thumb MOVW instruction");
262      return ELF::R_ARM_NONE;
263    case MCSymbolRefExpr::VK_None:
264      return ELF::R_ARM_THM_MOVW_ABS_NC;
265    case MCSymbolRefExpr::VK_ARM_SBREL:
266      return ELF::R_ARM_THM_MOVW_BREL_NC;
267    }
268  }
269}
270
271void ARMELFObjectWriter::addTargetSectionFlags(MCContext &Ctx,
272                                               MCSectionELF &Sec) {
273  // The mix of execute-only and non-execute-only at link time is
274  // non-execute-only. To avoid the empty implicitly created .text
275  // section from making the whole .text section non-execute-only, we
276  // mark it execute-only if it is empty and there is at least one
277  // execute-only section in the object.
278  MCSectionELF *TextSection =
279      static_cast<MCSectionELF *>(Ctx.getObjectFileInfo()->getTextSection());
280  if (Sec.getKind().isExecuteOnly() && !TextSection->hasInstructions()) {
281    for (auto &F : TextSection->getFragmentList())
282      if (auto *DF = dyn_cast<MCDataFragment>(&F))
283        if (!DF->getContents().empty())
284          return;
285    TextSection->setFlags(TextSection->getFlags() | ELF::SHF_ARM_PURECODE);
286  }
287}
288
289std::unique_ptr<MCObjectTargetWriter>
290llvm::createARMELFObjectWriter(uint8_t OSABI) {
291  return std::make_unique<ARMELFObjectWriter>(OSABI);
292}
293