ARMMachObjectWriter.cpp revision d04a8d4b33ff316ca4cf961e06c9e312eff8e64f
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/Object/MachOFormat.h"
24#include "llvm/Support/ErrorHandling.h"
25using namespace llvm;
26using namespace llvm::object;
27
28namespace {
29class ARMMachObjectWriter : public MCMachObjectTargetWriter {
30  void RecordARMScatteredRelocation(MachObjectWriter *Writer,
31                                    const MCAssembler &Asm,
32                                    const MCAsmLayout &Layout,
33                                    const MCFragment *Fragment,
34                                    const MCFixup &Fixup,
35                                    MCValue Target,
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);
61};
62}
63
64static bool getARMFixupKindMachOInfo(unsigned Kind, unsigned &RelocType,
65                              unsigned &Log2Size) {
66  RelocType = unsigned(macho::RIT_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    // Handle 24-bit branch kinds.
87  case ARM::fixup_arm_ldst_pcrel_12:
88  case ARM::fixup_arm_pcrel_10:
89  case ARM::fixup_arm_adr_pcrel_12:
90  case ARM::fixup_arm_condbranch:
91  case ARM::fixup_arm_uncondbranch:
92  case ARM::fixup_arm_uncondbl:
93  case ARM::fixup_arm_condbl:
94  case ARM::fixup_arm_blx:
95    RelocType = unsigned(macho::RIT_ARM_Branch24Bit);
96    // Report as 'long', even though that is not quite accurate.
97    Log2Size = llvm::Log2_32(4);
98    return true;
99
100    // Handle Thumb branches.
101  case ARM::fixup_arm_thumb_br:
102    RelocType = unsigned(macho::RIT_ARM_ThumbBranch22Bit);
103    Log2Size = llvm::Log2_32(2);
104    return true;
105
106  case ARM::fixup_t2_uncondbranch:
107  case ARM::fixup_arm_thumb_bl:
108  case ARM::fixup_arm_thumb_blx:
109    RelocType = unsigned(macho::RIT_ARM_ThumbBranch22Bit);
110    Log2Size = llvm::Log2_32(4);
111    return true;
112
113  // For movw/movt r_type relocations they always have a pair following them and
114  // the r_length bits are used differently.  The encoding of the r_length is as
115  // follows:
116  //   low bit of r_length:
117  //      0 - :lower16: for movw instructions
118  //      1 - :upper16: for movt instructions
119  //   high bit of r_length:
120  //      0 - arm instructions
121  //      1 - thumb instructions
122  case ARM::fixup_arm_movt_hi16:
123  case ARM::fixup_arm_movt_hi16_pcrel:
124    RelocType = unsigned(macho::RIT_ARM_Half);
125    Log2Size = 1;
126    return true;
127  case ARM::fixup_t2_movt_hi16:
128  case ARM::fixup_t2_movt_hi16_pcrel:
129    RelocType = unsigned(macho::RIT_ARM_Half);
130    Log2Size = 3;
131    return true;
132
133  case ARM::fixup_arm_movw_lo16:
134  case ARM::fixup_arm_movw_lo16_pcrel:
135    RelocType = unsigned(macho::RIT_ARM_Half);
136    Log2Size = 0;
137    return true;
138  case ARM::fixup_t2_movw_lo16:
139  case ARM::fixup_t2_movw_lo16_pcrel:
140    RelocType = unsigned(macho::RIT_ARM_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::RIT_ARM_Half;
157
158  // See <reloc.h>.
159  const MCSymbol *A = &Target.getSymA()->getSymbol();
160  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    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::RIT_ARM_HalfDifference;
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  case ARM::fixup_arm_movt_hi16_pcrel:
207    MovtBit = 1;
208    // The thumb bit shouldn't be set in the 'other-half' bit of the
209    // relocation, but it will be set in FixedValue if the base symbol
210    // is a thumb function. Clear it out here.
211    if (A_SD->getFlags() & SF_ThumbFunc)
212      FixedValue &= 0xfffffffe;
213    break;
214  case ARM::fixup_t2_movt_hi16:
215  case ARM::fixup_t2_movt_hi16_pcrel:
216    if (A_SD->getFlags() & SF_ThumbFunc)
217      FixedValue &= 0xfffffffe;
218    MovtBit = 1;
219    // Fallthrough
220  case ARM::fixup_t2_movw_lo16:
221  case ARM::fixup_t2_movw_lo16_pcrel:
222    ThumbBit = 1;
223    break;
224  }
225
226  if (Type == macho::RIT_ARM_HalfDifference) {
227    uint32_t OtherHalf = MovtBit
228      ? (FixedValue & 0xffff) : ((FixedValue & 0xffff0000) >> 16);
229
230    macho::RelocationEntry MRE;
231    MRE.Word0 = ((OtherHalf       <<  0) |
232                 (macho::RIT_Pair << 24) |
233                 (MovtBit         << 28) |
234                 (ThumbBit        << 29) |
235                 (IsPCRel         << 30) |
236                 macho::RF_Scattered);
237    MRE.Word1 = Value2;
238    Writer->addRelocation(Fragment->getParent(), MRE);
239  }
240
241  macho::RelocationEntry MRE;
242  MRE.Word0 = ((FixupOffset <<  0) |
243               (Type        << 24) |
244               (MovtBit     << 28) |
245               (ThumbBit    << 29) |
246               (IsPCRel     << 30) |
247               macho::RF_Scattered);
248  MRE.Word1 = Value;
249  Writer->addRelocation(Fragment->getParent(), MRE);
250}
251
252void ARMMachObjectWriter::RecordARMScatteredRelocation(MachObjectWriter *Writer,
253                                                    const MCAssembler &Asm,
254                                                    const MCAsmLayout &Layout,
255                                                    const MCFragment *Fragment,
256                                                    const MCFixup &Fixup,
257                                                    MCValue Target,
258                                                    unsigned Log2Size,
259                                                    uint64_t &FixedValue) {
260  uint32_t FixupOffset = Layout.getFragmentOffset(Fragment)+Fixup.getOffset();
261  unsigned IsPCRel = Writer->isFixupKindPCRel(Asm, Fixup.getKind());
262  unsigned Type = macho::RIT_Vanilla;
263
264  // See <reloc.h>.
265  const MCSymbol *A = &Target.getSymA()->getSymbol();
266  MCSymbolData *A_SD = &Asm.getSymbolData(*A);
267
268  if (!A_SD->getFragment())
269    Asm.getContext().FatalError(Fixup.getLoc(),
270                       "symbol '" + A->getName() +
271                       "' can not be undefined in a subtraction expression");
272
273  uint32_t Value = Writer->getSymbolAddress(A_SD, Layout);
274  uint64_t SecAddr = Writer->getSectionAddress(A_SD->getFragment()->getParent());
275  FixedValue += SecAddr;
276  uint32_t Value2 = 0;
277
278  if (const MCSymbolRefExpr *B = Target.getSymB()) {
279    MCSymbolData *B_SD = &Asm.getSymbolData(B->getSymbol());
280
281    if (!B_SD->getFragment())
282      Asm.getContext().FatalError(Fixup.getLoc(),
283                         "symbol '" + B->getSymbol().getName() +
284                         "' can not be undefined in a subtraction expression");
285
286    // Select the appropriate difference relocation type.
287    Type = macho::RIT_Difference;
288    Value2 = Writer->getSymbolAddress(B_SD, Layout);
289    FixedValue -= Writer->getSectionAddress(B_SD->getFragment()->getParent());
290  }
291
292  // Relocations are written out in reverse order, so the PAIR comes first.
293  if (Type == macho::RIT_Difference ||
294      Type == macho::RIT_Generic_LocalDifference) {
295    macho::RelocationEntry MRE;
296    MRE.Word0 = ((0         <<  0) |
297                 (macho::RIT_Pair  << 24) |
298                 (Log2Size  << 28) |
299                 (IsPCRel   << 30) |
300                 macho::RF_Scattered);
301    MRE.Word1 = Value2;
302    Writer->addRelocation(Fragment->getParent(), MRE);
303  }
304
305  macho::RelocationEntry MRE;
306  MRE.Word0 = ((FixupOffset <<  0) |
307               (Type        << 24) |
308               (Log2Size    << 28) |
309               (IsPCRel     << 30) |
310               macho::RF_Scattered);
311  MRE.Word1 = Value;
312  Writer->addRelocation(Fragment->getParent(), MRE);
313}
314
315bool ARMMachObjectWriter::requiresExternRelocation(MachObjectWriter *Writer,
316                                                   const MCAssembler &Asm,
317                                                   const MCFragment &Fragment,
318                                                   unsigned RelocType,
319                                                   const MCSymbolData *SD,
320                                                   uint64_t FixedValue) {
321  // Most cases can be identified purely from the symbol.
322  if (Writer->doesSymbolRequireExternRelocation(SD))
323    return true;
324  int64_t Value = (int64_t)FixedValue;  // The displacement is signed.
325  int64_t Range;
326  switch (RelocType) {
327  default:
328    return false;
329  case macho::RIT_ARM_Branch24Bit:
330    // PC pre-adjustment of 8 for these instructions.
331    Value -= 8;
332    // ARM BL/BLX has a 25-bit offset.
333    Range = 0x1ffffff;
334    break;
335  case macho::RIT_ARM_ThumbBranch22Bit:
336    // PC pre-adjustment of 4 for these instructions.
337    Value -= 4;
338    // Thumb BL/BLX has a 24-bit offset.
339    Range = 0xffffff;
340  }
341  // BL/BLX also use external relocations when an internal relocation
342  // would result in the target being out of range. This gives the linker
343  // enough information to generate a branch island.
344  const MCSectionData &SymSD = Asm.getSectionData(
345    SD->getSymbol().getSection());
346  Value += Writer->getSectionAddress(&SymSD);
347  Value -= Writer->getSectionAddress(Fragment.getParent());
348  // If the resultant value would be out of range for an internal relocation,
349  // use an external instead.
350  if (Value > Range || Value < -(Range + 1))
351    return true;
352  return false;
353}
354
355void ARMMachObjectWriter::RecordRelocation(MachObjectWriter *Writer,
356                                           const MCAssembler &Asm,
357                                           const MCAsmLayout &Layout,
358                                           const MCFragment *Fragment,
359                                           const MCFixup &Fixup,
360                                           MCValue Target,
361                                           uint64_t &FixedValue) {
362  unsigned IsPCRel = Writer->isFixupKindPCRel(Asm, Fixup.getKind());
363  unsigned Log2Size;
364  unsigned RelocType = macho::RIT_Vanilla;
365  if (!getARMFixupKindMachOInfo(Fixup.getKind(), RelocType, Log2Size))
366    // If we failed to get fixup kind info, it's because there's no legal
367    // relocation type for the fixup kind. This happens when it's a fixup that's
368    // expected to always be resolvable at assembly time and not have any
369    // relocations needed.
370    Asm.getContext().FatalError(Fixup.getLoc(),
371                                "unsupported relocation on symbol");
372
373  // If this is a difference or a defined symbol plus an offset, then we need a
374  // scattered relocation entry.  Differences always require scattered
375  // relocations.
376  if (Target.getSymB()) {
377    if (RelocType == macho::RIT_ARM_Half)
378      return RecordARMScatteredHalfRelocation(Writer, Asm, Layout, Fragment,
379                                              Fixup, Target, FixedValue);
380    return RecordARMScatteredRelocation(Writer, Asm, Layout, Fragment, Fixup,
381                                        Target, Log2Size, FixedValue);
382  }
383
384  // Get the symbol data, if any.
385  MCSymbolData *SD = 0;
386  if (Target.getSymA())
387    SD = &Asm.getSymbolData(Target.getSymA()->getSymbol());
388
389  // FIXME: For other platforms, we need to use scattered relocations for
390  // internal relocations with offsets.  If this is an internal relocation with
391  // an offset, it also needs a scattered relocation entry.
392  //
393  // Is this right for ARM?
394  uint32_t Offset = Target.getConstant();
395  if (IsPCRel && RelocType == macho::RIT_Vanilla)
396    Offset += 1 << Log2Size;
397  if (Offset && SD && !Writer->doesSymbolRequireExternRelocation(SD))
398    return RecordARMScatteredRelocation(Writer, Asm, Layout, Fragment, Fixup,
399                                        Target, Log2Size, 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::RelocationEntry MRE;
449  MRE.Word0 = FixupOffset;
450  MRE.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::RIT_ARM_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_arm_movw_lo16_pcrel:
466    case ARM::fixup_t2_movw_lo16:
467    case ARM::fixup_t2_movw_lo16_pcrel:
468      Value = (FixedValue >> 16) & 0xffff;
469      break;
470    case ARM::fixup_arm_movt_hi16:
471    case ARM::fixup_arm_movt_hi16_pcrel:
472    case ARM::fixup_t2_movt_hi16:
473    case ARM::fixup_t2_movt_hi16_pcrel:
474      Value = FixedValue & 0xffff;
475      break;
476    }
477    macho::RelocationEntry MREPair;
478    MREPair.Word0 = Value;
479    MREPair.Word1 = ((0xffffff) |
480                     (Log2Size << 25) |
481                     (macho::RIT_Pair << 28));
482
483    Writer->addRelocation(Fragment->getParent(), MREPair);
484  }
485
486  Writer->addRelocation(Fragment->getParent(), MRE);
487}
488
489MCObjectWriter *llvm::createARMMachObjectWriter(raw_ostream &OS,
490                                                bool Is64Bit,
491                                                uint32_t CPUType,
492                                                uint32_t CPUSubtype) {
493  return createMachObjectWriter(new ARMMachObjectWriter(Is64Bit,
494                                                        CPUType,
495                                                        CPUSubtype),
496                                OS, /*IsLittleEndian=*/true);
497}
498