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