1//===-- ARMMachObjectWriter.cpp - ARM Mach Object 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/ARMMCTargetDesc.h"
11#include "MCTargetDesc/ARMBaseInfo.h"
12#include "MCTargetDesc/ARMFixupKinds.h"
13#include "llvm/ADT/Twine.h"
14#include "llvm/MC/MCAsmLayout.h"
15#include "llvm/MC/MCAssembler.h"
16#include "llvm/MC/MCContext.h"
17#include "llvm/MC/MCExpr.h"
18#include "llvm/MC/MCFixup.h"
19#include "llvm/MC/MCFixupKindInfo.h"
20#include "llvm/MC/MCMachOSymbolFlags.h"
21#include "llvm/MC/MCMachObjectWriter.h"
22#include "llvm/MC/MCValue.h"
23#include "llvm/Support/ErrorHandling.h"
24#include "llvm/Support/MachO.h"
25using namespace llvm;
26
27namespace {
28class ARMMachObjectWriter : public MCMachObjectTargetWriter {
29  void RecordARMScatteredRelocation(MachObjectWriter *Writer,
30                                    const MCAssembler &Asm,
31                                    const MCAsmLayout &Layout,
32                                    const MCFragment *Fragment,
33                                    const MCFixup &Fixup,
34                                    MCValue Target,
35                                    unsigned Type,
36                                    unsigned Log2Size,
37                                    uint64_t &FixedValue);
38  void RecordARMScatteredHalfRelocation(MachObjectWriter *Writer,
39                                        const MCAssembler &Asm,
40                                        const MCAsmLayout &Layout,
41                                        const MCFragment *Fragment,
42                                        const MCFixup &Fixup, MCValue Target,
43                                        uint64_t &FixedValue);
44
45  bool requiresExternRelocation(MachObjectWriter *Writer,
46                                const MCAssembler &Asm,
47                                const MCFragment &Fragment,
48                                unsigned RelocType, const MCSymbolData *SD,
49                                uint64_t FixedValue);
50
51public:
52  ARMMachObjectWriter(bool Is64Bit, uint32_t CPUType,
53                      uint32_t CPUSubtype)
54    : MCMachObjectTargetWriter(Is64Bit, CPUType, CPUSubtype,
55                               /*UseAggressiveSymbolFolding=*/true) {}
56
57  void RecordRelocation(MachObjectWriter *Writer,
58                        const MCAssembler &Asm, const MCAsmLayout &Layout,
59                        const MCFragment *Fragment, const MCFixup &Fixup,
60                        MCValue Target, uint64_t &FixedValue) override;
61};
62}
63
64static bool getARMFixupKindMachOInfo(unsigned Kind, unsigned &RelocType,
65                              unsigned &Log2Size) {
66  RelocType = unsigned(MachO::ARM_RELOC_VANILLA);
67  Log2Size = ~0U;
68
69  switch (Kind) {
70  default:
71    return false;
72
73  case FK_Data_1:
74    Log2Size = llvm::Log2_32(1);
75    return true;
76  case FK_Data_2:
77    Log2Size = llvm::Log2_32(2);
78    return true;
79  case FK_Data_4:
80    Log2Size = llvm::Log2_32(4);
81    return true;
82  case FK_Data_8:
83    Log2Size = llvm::Log2_32(8);
84    return true;
85
86    // These fixups are expected to always be resolvable at assembly time and
87    // have no relocations supported.
88  case ARM::fixup_arm_ldst_pcrel_12:
89  case ARM::fixup_arm_pcrel_10:
90  case ARM::fixup_arm_adr_pcrel_12:
91    return false;
92
93    // Handle 24-bit branch kinds.
94  case ARM::fixup_arm_condbranch:
95  case ARM::fixup_arm_uncondbranch:
96  case ARM::fixup_arm_uncondbl:
97  case ARM::fixup_arm_condbl:
98  case ARM::fixup_arm_blx:
99    RelocType = unsigned(MachO::ARM_RELOC_BR24);
100    // Report as 'long', even though that is not quite accurate.
101    Log2Size = llvm::Log2_32(4);
102    return true;
103
104    // Handle Thumb branches.
105  case ARM::fixup_arm_thumb_br:
106    RelocType = unsigned(MachO::ARM_THUMB_RELOC_BR22);
107    Log2Size = llvm::Log2_32(2);
108    return true;
109
110  case ARM::fixup_t2_uncondbranch:
111  case ARM::fixup_arm_thumb_bl:
112  case ARM::fixup_arm_thumb_blx:
113    RelocType = unsigned(MachO::ARM_THUMB_RELOC_BR22);
114    Log2Size = llvm::Log2_32(4);
115    return true;
116
117  // For movw/movt r_type relocations they always have a pair following them and
118  // the r_length bits are used differently.  The encoding of the r_length is as
119  // follows:
120  //   low bit of r_length:
121  //      0 - :lower16: for movw instructions
122  //      1 - :upper16: for movt instructions
123  //   high bit of r_length:
124  //      0 - arm instructions
125  //      1 - thumb instructions
126  case ARM::fixup_arm_movt_hi16:
127    RelocType = unsigned(MachO::ARM_RELOC_HALF);
128    Log2Size = 1;
129    return true;
130  case ARM::fixup_t2_movt_hi16:
131    RelocType = unsigned(MachO::ARM_RELOC_HALF);
132    Log2Size = 3;
133    return true;
134
135  case ARM::fixup_arm_movw_lo16:
136    RelocType = unsigned(MachO::ARM_RELOC_HALF);
137    Log2Size = 0;
138    return true;
139  case ARM::fixup_t2_movw_lo16:
140    RelocType = unsigned(MachO::ARM_RELOC_HALF);
141    Log2Size = 2;
142    return true;
143  }
144}
145
146void ARMMachObjectWriter::
147RecordARMScatteredHalfRelocation(MachObjectWriter *Writer,
148                                 const MCAssembler &Asm,
149                                 const MCAsmLayout &Layout,
150                                 const MCFragment *Fragment,
151                                 const MCFixup &Fixup,
152                                 MCValue Target,
153                                 uint64_t &FixedValue) {
154  uint32_t FixupOffset = Layout.getFragmentOffset(Fragment)+Fixup.getOffset();
155  unsigned IsPCRel = Writer->isFixupKindPCRel(Asm, Fixup.getKind());
156  unsigned Type = MachO::ARM_RELOC_HALF;
157
158  // See <reloc.h>.
159  const MCSymbol *A = &Target.getSymA()->getSymbol();
160  const MCSymbolData *A_SD = &Asm.getSymbolData(*A);
161
162  if (!A_SD->getFragment())
163    Asm.getContext().FatalError(Fixup.getLoc(),
164                       "symbol '" + A->getName() +
165                       "' can not be undefined in a subtraction expression");
166
167  uint32_t Value = Writer->getSymbolAddress(A_SD, Layout);
168  uint32_t Value2 = 0;
169  uint64_t SecAddr =
170    Writer->getSectionAddress(A_SD->getFragment()->getParent());
171  FixedValue += SecAddr;
172
173  if (const MCSymbolRefExpr *B = Target.getSymB()) {
174    const MCSymbolData *B_SD = &Asm.getSymbolData(B->getSymbol());
175
176    if (!B_SD->getFragment())
177      Asm.getContext().FatalError(Fixup.getLoc(),
178                         "symbol '" + B->getSymbol().getName() +
179                         "' can not be undefined in a subtraction expression");
180
181    // Select the appropriate difference relocation type.
182    Type = MachO::ARM_RELOC_HALF_SECTDIFF;
183    Value2 = Writer->getSymbolAddress(B_SD, Layout);
184    FixedValue -= Writer->getSectionAddress(B_SD->getFragment()->getParent());
185  }
186
187  // Relocations are written out in reverse order, so the PAIR comes first.
188  // ARM_RELOC_HALF and ARM_RELOC_HALF_SECTDIFF abuse the r_length field:
189  //
190  // For these two r_type relocations they always have a pair following them and
191  // the r_length bits are used differently.  The encoding of the r_length is as
192  // follows:
193  //   low bit of r_length:
194  //      0 - :lower16: for movw instructions
195  //      1 - :upper16: for movt instructions
196  //   high bit of r_length:
197  //      0 - arm instructions
198  //      1 - thumb instructions
199  // the other half of the relocated expression is in the following pair
200  // relocation entry in the low 16 bits of r_address field.
201  unsigned ThumbBit = 0;
202  unsigned MovtBit = 0;
203  switch ((unsigned)Fixup.getKind()) {
204  default: break;
205  case ARM::fixup_arm_movt_hi16:
206    MovtBit = 1;
207    // The thumb bit shouldn't be set in the 'other-half' bit of the
208    // relocation, but it will be set in FixedValue if the base symbol
209    // is a thumb function. Clear it out here.
210    if (Asm.isThumbFunc(A))
211      FixedValue &= 0xfffffffe;
212    break;
213  case ARM::fixup_t2_movt_hi16:
214    if (Asm.isThumbFunc(A))
215      FixedValue &= 0xfffffffe;
216    MovtBit = 1;
217    // Fallthrough
218  case ARM::fixup_t2_movw_lo16:
219    ThumbBit = 1;
220    break;
221  }
222
223  if (Type == MachO::ARM_RELOC_HALF_SECTDIFF) {
224    uint32_t OtherHalf = MovtBit
225      ? (FixedValue & 0xffff) : ((FixedValue & 0xffff0000) >> 16);
226
227    MachO::any_relocation_info MRE;
228    MRE.r_word0 = ((OtherHalf             <<  0) |
229                   (MachO::ARM_RELOC_PAIR << 24) |
230                   (MovtBit               << 28) |
231                   (ThumbBit              << 29) |
232                   (IsPCRel               << 30) |
233                   MachO::R_SCATTERED);
234    MRE.r_word1 = Value2;
235    Writer->addRelocation(Fragment->getParent(), MRE);
236  }
237
238  MachO::any_relocation_info MRE;
239  MRE.r_word0 = ((FixupOffset <<  0) |
240                 (Type        << 24) |
241                 (MovtBit     << 28) |
242                 (ThumbBit    << 29) |
243                 (IsPCRel     << 30) |
244                 MachO::R_SCATTERED);
245  MRE.r_word1 = Value;
246  Writer->addRelocation(Fragment->getParent(), MRE);
247}
248
249void ARMMachObjectWriter::RecordARMScatteredRelocation(MachObjectWriter *Writer,
250                                                    const MCAssembler &Asm,
251                                                    const MCAsmLayout &Layout,
252                                                    const MCFragment *Fragment,
253                                                    const MCFixup &Fixup,
254                                                    MCValue Target,
255                                                    unsigned Type,
256                                                    unsigned Log2Size,
257                                                    uint64_t &FixedValue) {
258  uint32_t FixupOffset = Layout.getFragmentOffset(Fragment)+Fixup.getOffset();
259  unsigned IsPCRel = Writer->isFixupKindPCRel(Asm, Fixup.getKind());
260
261  // See <reloc.h>.
262  const MCSymbol *A = &Target.getSymA()->getSymbol();
263  const MCSymbolData *A_SD = &Asm.getSymbolData(*A);
264
265  if (!A_SD->getFragment())
266    Asm.getContext().FatalError(Fixup.getLoc(),
267                       "symbol '" + A->getName() +
268                       "' can not be undefined in a subtraction expression");
269
270  uint32_t Value = Writer->getSymbolAddress(A_SD, Layout);
271  uint64_t SecAddr = Writer->getSectionAddress(A_SD->getFragment()->getParent());
272  FixedValue += SecAddr;
273  uint32_t Value2 = 0;
274
275  if (const MCSymbolRefExpr *B = Target.getSymB()) {
276    assert(Type == MachO::ARM_RELOC_VANILLA && "invalid reloc for 2 symbols");
277    const MCSymbolData *B_SD = &Asm.getSymbolData(B->getSymbol());
278
279    if (!B_SD->getFragment())
280      Asm.getContext().FatalError(Fixup.getLoc(),
281                         "symbol '" + B->getSymbol().getName() +
282                         "' can not be undefined in a subtraction expression");
283
284    // Select the appropriate difference relocation type.
285    Type = MachO::ARM_RELOC_SECTDIFF;
286    Value2 = Writer->getSymbolAddress(B_SD, Layout);
287    FixedValue -= Writer->getSectionAddress(B_SD->getFragment()->getParent());
288  }
289
290  // Relocations are written out in reverse order, so the PAIR comes first.
291  if (Type == MachO::ARM_RELOC_SECTDIFF ||
292      Type == MachO::ARM_RELOC_LOCAL_SECTDIFF) {
293    MachO::any_relocation_info MRE;
294    MRE.r_word0 = ((0                     <<  0) |
295                   (MachO::ARM_RELOC_PAIR << 24) |
296                   (Log2Size              << 28) |
297                   (IsPCRel               << 30) |
298                   MachO::R_SCATTERED);
299    MRE.r_word1 = Value2;
300    Writer->addRelocation(Fragment->getParent(), MRE);
301  }
302
303  MachO::any_relocation_info MRE;
304  MRE.r_word0 = ((FixupOffset <<  0) |
305                 (Type        << 24) |
306                 (Log2Size    << 28) |
307                 (IsPCRel     << 30) |
308                 MachO::R_SCATTERED);
309  MRE.r_word1 = Value;
310  Writer->addRelocation(Fragment->getParent(), MRE);
311}
312
313bool ARMMachObjectWriter::requiresExternRelocation(MachObjectWriter *Writer,
314                                                   const MCAssembler &Asm,
315                                                   const MCFragment &Fragment,
316                                                   unsigned RelocType,
317                                                   const MCSymbolData *SD,
318                                                   uint64_t FixedValue) {
319  // Most cases can be identified purely from the symbol.
320  if (Writer->doesSymbolRequireExternRelocation(SD))
321    return true;
322  int64_t Value = (int64_t)FixedValue;  // The displacement is signed.
323  int64_t Range;
324  switch (RelocType) {
325  default:
326    return false;
327  case MachO::ARM_RELOC_BR24:
328    // PC pre-adjustment of 8 for these instructions.
329    Value -= 8;
330    // ARM BL/BLX has a 25-bit offset.
331    Range = 0x1ffffff;
332    break;
333  case MachO::ARM_THUMB_RELOC_BR22:
334    // PC pre-adjustment of 4 for these instructions.
335    Value -= 4;
336    // Thumb BL/BLX has a 24-bit offset.
337    Range = 0xffffff;
338  }
339  // BL/BLX also use external relocations when an internal relocation
340  // would result in the target being out of range. This gives the linker
341  // enough information to generate a branch island.
342  const MCSectionData &SymSD = Asm.getSectionData(
343    SD->getSymbol().getSection());
344  Value += Writer->getSectionAddress(&SymSD);
345  Value -= Writer->getSectionAddress(Fragment.getParent());
346  // If the resultant value would be out of range for an internal relocation,
347  // use an external instead.
348  if (Value > Range || Value < -(Range + 1))
349    return true;
350  return false;
351}
352
353void ARMMachObjectWriter::RecordRelocation(MachObjectWriter *Writer,
354                                           const MCAssembler &Asm,
355                                           const MCAsmLayout &Layout,
356                                           const MCFragment *Fragment,
357                                           const MCFixup &Fixup,
358                                           MCValue Target,
359                                           uint64_t &FixedValue) {
360  unsigned IsPCRel = Writer->isFixupKindPCRel(Asm, Fixup.getKind());
361  unsigned Log2Size;
362  unsigned RelocType = MachO::ARM_RELOC_VANILLA;
363  if (!getARMFixupKindMachOInfo(Fixup.getKind(), RelocType, Log2Size))
364    // If we failed to get fixup kind info, it's because there's no legal
365    // relocation type for the fixup kind. This happens when it's a fixup that's
366    // expected to always be resolvable at assembly time and not have any
367    // relocations needed.
368    Asm.getContext().FatalError(Fixup.getLoc(),
369                                "unsupported relocation on symbol");
370
371  // If this is a difference or a defined symbol plus an offset, then we need a
372  // scattered relocation entry.  Differences always require scattered
373  // relocations.
374  if (Target.getSymB()) {
375    if (RelocType == MachO::ARM_RELOC_HALF)
376      return RecordARMScatteredHalfRelocation(Writer, Asm, Layout, Fragment,
377                                              Fixup, Target, FixedValue);
378    return RecordARMScatteredRelocation(Writer, Asm, Layout, Fragment, Fixup,
379                                        Target, RelocType, Log2Size,
380                                        FixedValue);
381  }
382
383  // Get the symbol data, if any.
384  const MCSymbolData *SD = nullptr;
385  if (Target.getSymA())
386    SD = &Asm.getSymbolData(Target.getSymA()->getSymbol());
387
388  // FIXME: For other platforms, we need to use scattered relocations for
389  // internal relocations with offsets.  If this is an internal relocation with
390  // an offset, it also needs a scattered relocation entry.
391  //
392  // Is this right for ARM?
393  uint32_t Offset = Target.getConstant();
394  if (IsPCRel && RelocType == MachO::ARM_RELOC_VANILLA)
395    Offset += 1 << Log2Size;
396  if (Offset && SD && !Writer->doesSymbolRequireExternRelocation(SD))
397    return RecordARMScatteredRelocation(Writer, Asm, Layout, Fragment, Fixup,
398                                        Target, RelocType, Log2Size,
399                                        FixedValue);
400
401  // See <reloc.h>.
402  uint32_t FixupOffset = Layout.getFragmentOffset(Fragment)+Fixup.getOffset();
403  unsigned Index = 0;
404  unsigned IsExtern = 0;
405  unsigned Type = 0;
406
407  if (Target.isAbsolute()) { // constant
408    // FIXME!
409    report_fatal_error("FIXME: relocations to absolute targets "
410                       "not yet implemented");
411  } else {
412    // Resolve constant variables.
413    if (SD->getSymbol().isVariable()) {
414      int64_t Res;
415      if (SD->getSymbol().getVariableValue()->EvaluateAsAbsolute(
416            Res, Layout, Writer->getSectionAddressMap())) {
417        FixedValue = Res;
418        return;
419      }
420    }
421
422    // Check whether we need an external or internal relocation.
423    if (requiresExternRelocation(Writer, Asm, *Fragment, RelocType, SD,
424                                 FixedValue)) {
425      IsExtern = 1;
426      Index = SD->getIndex();
427
428      // For external relocations, make sure to offset the fixup value to
429      // compensate for the addend of the symbol address, if it was
430      // undefined. This occurs with weak definitions, for example.
431      if (!SD->Symbol->isUndefined())
432        FixedValue -= Layout.getSymbolOffset(SD);
433    } else {
434      // The index is the section ordinal (1-based).
435      const MCSectionData &SymSD = Asm.getSectionData(
436        SD->getSymbol().getSection());
437      Index = SymSD.getOrdinal() + 1;
438      FixedValue += Writer->getSectionAddress(&SymSD);
439    }
440    if (IsPCRel)
441      FixedValue -= Writer->getSectionAddress(Fragment->getParent());
442
443    // The type is determined by the fixup kind.
444    Type = RelocType;
445  }
446
447  // struct relocation_info (8 bytes)
448  MachO::any_relocation_info MRE;
449  MRE.r_word0 = FixupOffset;
450  MRE.r_word1 = ((Index     <<  0) |
451                 (IsPCRel   << 24) |
452                 (Log2Size  << 25) |
453                 (IsExtern  << 27) |
454                 (Type      << 28));
455
456  // Even when it's not a scattered relocation, movw/movt always uses
457  // a PAIR relocation.
458  if (Type == MachO::ARM_RELOC_HALF) {
459    // The other-half value only gets populated for the movt and movw
460    // relocation entries.
461    uint32_t Value = 0;
462    switch ((unsigned)Fixup.getKind()) {
463    default: break;
464    case ARM::fixup_arm_movw_lo16:
465    case ARM::fixup_t2_movw_lo16:
466      Value = (FixedValue >> 16) & 0xffff;
467      break;
468    case ARM::fixup_arm_movt_hi16:
469    case ARM::fixup_t2_movt_hi16:
470      Value = FixedValue & 0xffff;
471      break;
472    }
473    MachO::any_relocation_info MREPair;
474    MREPair.r_word0 = Value;
475    MREPair.r_word1 = ((0xffffff              <<  0) |
476                       (Log2Size              << 25) |
477                       (MachO::ARM_RELOC_PAIR << 28));
478
479    Writer->addRelocation(Fragment->getParent(), MREPair);
480  }
481
482  Writer->addRelocation(Fragment->getParent(), MRE);
483}
484
485MCObjectWriter *llvm::createARMMachObjectWriter(raw_ostream &OS,
486                                                bool Is64Bit,
487                                                uint32_t CPUType,
488                                                uint32_t CPUSubtype) {
489  return createMachObjectWriter(new ARMMachObjectWriter(Is64Bit,
490                                                        CPUType,
491                                                        CPUSubtype),
492                                OS, /*IsLittleEndian=*/true);
493}
494