ARMMachObjectWriter.cpp revision 288943
1139749Simp//===-- ARMMachObjectWriter.cpp - ARM Mach Object Writer ------------------===//
2193640Sariff//
3193640Sariff//                     The LLVM Compiler Infrastructure
450724Scg//
550724Scg// This file is distributed under the University of Illinois Open Source
650724Scg// License. See LICENSE.TXT for details.
750724Scg//
850724Scg//===----------------------------------------------------------------------===//
950724Scg
1050724Scg#include "MCTargetDesc/ARMMCTargetDesc.h"
1150724Scg#include "MCTargetDesc/ARMBaseInfo.h"
1250724Scg#include "MCTargetDesc/ARMFixupKinds.h"
1350724Scg#include "llvm/ADT/Twine.h"
1450724Scg#include "llvm/MC/MCAsmLayout.h"
1550724Scg#include "llvm/MC/MCAssembler.h"
1650724Scg#include "llvm/MC/MCContext.h"
1750724Scg#include "llvm/MC/MCExpr.h"
1850724Scg#include "llvm/MC/MCFixup.h"
1950724Scg#include "llvm/MC/MCFixupKindInfo.h"
2050724Scg#include "llvm/MC/MCMachObjectWriter.h"
2150724Scg#include "llvm/MC/MCSection.h"
2250724Scg#include "llvm/MC/MCValue.h"
2350724Scg#include "llvm/Support/ErrorHandling.h"
2450724Scg#include "llvm/Support/MachO.h"
2550724Scgusing namespace llvm;
2650724Scg
2750733Speternamespace {
2850724Scgclass ARMMachObjectWriter : public MCMachObjectTargetWriter {
2950724Scg  void RecordARMScatteredRelocation(MachObjectWriter *Writer,
30242435Shselasky                                    const MCAssembler &Asm,
31242435Shselasky                                    const MCAsmLayout &Layout,
32242435Shselasky                                    const MCFragment *Fragment,
33170815Sariff                                    const MCFixup &Fixup,
34170815Sariff                                    MCValue Target,
35170815Sariff                                    unsigned Type,
3674763Scg                                    unsigned Log2Size,
3774763Scg                                    uint64_t &FixedValue);
3874763Scg  void RecordARMScatteredHalfRelocation(MachObjectWriter *Writer,
39170815Sariff                                        const MCAssembler &Asm,
40162588Snetchild                                        const MCAsmLayout &Layout,
4150724Scg                                        const MCFragment *Fragment,
4270944Sjhb                                        const MCFixup &Fixup, MCValue Target,
43246454Shselasky                                        uint64_t &FixedValue);
4470944Sjhb
45246454Shselasky  bool requiresExternRelocation(MachObjectWriter *Writer,
4670944Sjhb                                const MCAssembler &Asm,
4770618Sjhb                                const MCFragment &Fragment, unsigned RelocType,
48170815Sariff                                const MCSymbol &S, uint64_t FixedValue);
49170815Sariff
50246421Shselaskypublic:
51246421Shselasky  ARMMachObjectWriter(bool Is64Bit, uint32_t CPUType, uint32_t CPUSubtype)
52170815Sariff      : MCMachObjectTargetWriter(Is64Bit, CPUType, CPUSubtype) {}
53170815Sariff
54170815Sariff  void recordRelocation(MachObjectWriter *Writer, MCAssembler &Asm,
55170815Sariff                        const MCAsmLayout &Layout, const MCFragment *Fragment,
56170815Sariff                        const MCFixup &Fixup, MCValue Target,
57170815Sariff                        uint64_t &FixedValue) override;
5874763Scg};
5974763Scg}
6074763Scg
6174763Scgstatic bool getARMFixupKindMachOInfo(unsigned Kind, unsigned &RelocType,
62162738Sariff                              unsigned &Log2Size) {
63162738Sariff  RelocType = unsigned(MachO::ARM_RELOC_VANILLA);
64162738Sariff  Log2Size = ~0U;
65162738Sariff
6674763Scg  switch (Kind) {
67184610Salfred  default:
6850724Scg    return false;
69162588Snetchild
70162588Snetchild  case FK_Data_1:
71170815Sariff    Log2Size = llvm::Log2_32(1);
72170815Sariff    return true;
73170815Sariff  case FK_Data_2:
74170815Sariff    Log2Size = llvm::Log2_32(2);
75170815Sariff    return true;
76170815Sariff  case FK_Data_4:
7774763Scg    Log2Size = llvm::Log2_32(4);
7874763Scg    return true;
7974763Scg  case FK_Data_8:
8074763Scg    Log2Size = llvm::Log2_32(8);
81170815Sariff    return true;
82170815Sariff
8370134Scg    // These fixups are expected to always be resolvable at assembly time and
84160385Snetchild    // have no relocations supported.
85242435Shselasky  case ARM::fixup_arm_ldst_pcrel_12:
86242435Shselasky  case ARM::fixup_arm_pcrel_10:
87  case ARM::fixup_arm_adr_pcrel_12:
88  case ARM::fixup_arm_thumb_br:
89    return false;
90
91    // Handle 24-bit branch kinds.
92  case ARM::fixup_arm_condbranch:
93  case ARM::fixup_arm_uncondbranch:
94  case ARM::fixup_arm_uncondbl:
95  case ARM::fixup_arm_condbl:
96  case ARM::fixup_arm_blx:
97    RelocType = unsigned(MachO::ARM_RELOC_BR24);
98    // Report as 'long', even though that is not quite accurate.
99    Log2Size = llvm::Log2_32(4);
100    return true;
101
102  case ARM::fixup_t2_uncondbranch:
103  case ARM::fixup_arm_thumb_bl:
104  case ARM::fixup_arm_thumb_blx:
105    RelocType = unsigned(MachO::ARM_THUMB_RELOC_BR22);
106    Log2Size = llvm::Log2_32(4);
107    return true;
108
109  // For movw/movt r_type relocations they always have a pair following them and
110  // the r_length bits are used differently.  The encoding of the r_length is as
111  // follows:
112  //   low bit of r_length:
113  //      0 - :lower16: for movw instructions
114  //      1 - :upper16: for movt instructions
115  //   high bit of r_length:
116  //      0 - arm instructions
117  //      1 - thumb instructions
118  case ARM::fixup_arm_movt_hi16:
119    RelocType = unsigned(MachO::ARM_RELOC_HALF);
120    Log2Size = 1;
121    return true;
122  case ARM::fixup_t2_movt_hi16:
123    RelocType = unsigned(MachO::ARM_RELOC_HALF);
124    Log2Size = 3;
125    return true;
126
127  case ARM::fixup_arm_movw_lo16:
128    RelocType = unsigned(MachO::ARM_RELOC_HALF);
129    Log2Size = 0;
130    return true;
131  case ARM::fixup_t2_movw_lo16:
132    RelocType = unsigned(MachO::ARM_RELOC_HALF);
133    Log2Size = 2;
134    return true;
135  }
136}
137
138void ARMMachObjectWriter::
139RecordARMScatteredHalfRelocation(MachObjectWriter *Writer,
140                                 const MCAssembler &Asm,
141                                 const MCAsmLayout &Layout,
142                                 const MCFragment *Fragment,
143                                 const MCFixup &Fixup,
144                                 MCValue Target,
145                                 uint64_t &FixedValue) {
146  uint32_t FixupOffset = Layout.getFragmentOffset(Fragment)+Fixup.getOffset();
147  unsigned IsPCRel = Writer->isFixupKindPCRel(Asm, Fixup.getKind());
148  unsigned Type = MachO::ARM_RELOC_HALF;
149
150  // See <reloc.h>.
151  const MCSymbol *A = &Target.getSymA()->getSymbol();
152
153  if (!A->getFragment())
154    Asm.getContext().reportFatalError(Fixup.getLoc(),
155                       "symbol '" + A->getName() +
156                       "' can not be undefined in a subtraction expression");
157
158  uint32_t Value = Writer->getSymbolAddress(*A, Layout);
159  uint32_t Value2 = 0;
160  uint64_t SecAddr = Writer->getSectionAddress(A->getFragment()->getParent());
161  FixedValue += SecAddr;
162
163  if (const MCSymbolRefExpr *B = Target.getSymB()) {
164    const MCSymbol *SB = &B->getSymbol();
165
166    if (!SB->getFragment())
167      Asm.getContext().reportFatalError(Fixup.getLoc(),
168                         "symbol '" + B->getSymbol().getName() +
169                         "' can not be undefined in a subtraction expression");
170
171    // Select the appropriate difference relocation type.
172    Type = MachO::ARM_RELOC_HALF_SECTDIFF;
173    Value2 = Writer->getSymbolAddress(B->getSymbol(), Layout);
174    FixedValue -= Writer->getSectionAddress(SB->getFragment()->getParent());
175  }
176
177  // Relocations are written out in reverse order, so the PAIR comes first.
178  // ARM_RELOC_HALF and ARM_RELOC_HALF_SECTDIFF abuse the r_length field:
179  //
180  // For these two r_type relocations they always have a pair following them and
181  // the r_length bits are used differently.  The encoding of the r_length is as
182  // follows:
183  //   low bit of r_length:
184  //      0 - :lower16: for movw instructions
185  //      1 - :upper16: for movt instructions
186  //   high bit of r_length:
187  //      0 - arm instructions
188  //      1 - thumb instructions
189  // the other half of the relocated expression is in the following pair
190  // relocation entry in the low 16 bits of r_address field.
191  unsigned ThumbBit = 0;
192  unsigned MovtBit = 0;
193  switch ((unsigned)Fixup.getKind()) {
194  default: break;
195  case ARM::fixup_arm_movt_hi16:
196    MovtBit = 1;
197    // The thumb bit shouldn't be set in the 'other-half' bit of the
198    // relocation, but it will be set in FixedValue if the base symbol
199    // is a thumb function. Clear it out here.
200    if (Asm.isThumbFunc(A))
201      FixedValue &= 0xfffffffe;
202    break;
203  case ARM::fixup_t2_movt_hi16:
204    if (Asm.isThumbFunc(A))
205      FixedValue &= 0xfffffffe;
206    MovtBit = 1;
207    // Fallthrough
208  case ARM::fixup_t2_movw_lo16:
209    ThumbBit = 1;
210    break;
211  }
212
213  if (Type == MachO::ARM_RELOC_HALF_SECTDIFF) {
214    uint32_t OtherHalf = MovtBit
215      ? (FixedValue & 0xffff) : ((FixedValue & 0xffff0000) >> 16);
216
217    MachO::any_relocation_info MRE;
218    MRE.r_word0 = ((OtherHalf             <<  0) |
219                   (MachO::ARM_RELOC_PAIR << 24) |
220                   (MovtBit               << 28) |
221                   (ThumbBit              << 29) |
222                   (IsPCRel               << 30) |
223                   MachO::R_SCATTERED);
224    MRE.r_word1 = Value2;
225    Writer->addRelocation(nullptr, Fragment->getParent(), MRE);
226  }
227
228  MachO::any_relocation_info MRE;
229  MRE.r_word0 = ((FixupOffset <<  0) |
230                 (Type        << 24) |
231                 (MovtBit     << 28) |
232                 (ThumbBit    << 29) |
233                 (IsPCRel     << 30) |
234                 MachO::R_SCATTERED);
235  MRE.r_word1 = Value;
236  Writer->addRelocation(nullptr, Fragment->getParent(), MRE);
237}
238
239void ARMMachObjectWriter::RecordARMScatteredRelocation(MachObjectWriter *Writer,
240                                                    const MCAssembler &Asm,
241                                                    const MCAsmLayout &Layout,
242                                                    const MCFragment *Fragment,
243                                                    const MCFixup &Fixup,
244                                                    MCValue Target,
245                                                    unsigned Type,
246                                                    unsigned Log2Size,
247                                                    uint64_t &FixedValue) {
248  uint32_t FixupOffset = Layout.getFragmentOffset(Fragment)+Fixup.getOffset();
249  unsigned IsPCRel = Writer->isFixupKindPCRel(Asm, Fixup.getKind());
250
251  // See <reloc.h>.
252  const MCSymbol *A = &Target.getSymA()->getSymbol();
253
254  if (!A->getFragment())
255    Asm.getContext().reportFatalError(Fixup.getLoc(),
256                       "symbol '" + A->getName() +
257                       "' can not be undefined in a subtraction expression");
258
259  uint32_t Value = Writer->getSymbolAddress(*A, Layout);
260  uint64_t SecAddr = Writer->getSectionAddress(A->getFragment()->getParent());
261  FixedValue += SecAddr;
262  uint32_t Value2 = 0;
263
264  if (const MCSymbolRefExpr *B = Target.getSymB()) {
265    assert(Type == MachO::ARM_RELOC_VANILLA && "invalid reloc for 2 symbols");
266    const MCSymbol *SB = &B->getSymbol();
267
268    if (!SB->getFragment())
269      Asm.getContext().reportFatalError(Fixup.getLoc(),
270                         "symbol '" + B->getSymbol().getName() +
271                         "' can not be undefined in a subtraction expression");
272
273    // Select the appropriate difference relocation type.
274    Type = MachO::ARM_RELOC_SECTDIFF;
275    Value2 = Writer->getSymbolAddress(B->getSymbol(), Layout);
276    FixedValue -= Writer->getSectionAddress(SB->getFragment()->getParent());
277  }
278
279  // Relocations are written out in reverse order, so the PAIR comes first.
280  if (Type == MachO::ARM_RELOC_SECTDIFF ||
281      Type == MachO::ARM_RELOC_LOCAL_SECTDIFF) {
282    MachO::any_relocation_info MRE;
283    MRE.r_word0 = ((0                     <<  0) |
284                   (MachO::ARM_RELOC_PAIR << 24) |
285                   (Log2Size              << 28) |
286                   (IsPCRel               << 30) |
287                   MachO::R_SCATTERED);
288    MRE.r_word1 = Value2;
289    Writer->addRelocation(nullptr, Fragment->getParent(), MRE);
290  }
291
292  MachO::any_relocation_info MRE;
293  MRE.r_word0 = ((FixupOffset <<  0) |
294                 (Type        << 24) |
295                 (Log2Size    << 28) |
296                 (IsPCRel     << 30) |
297                 MachO::R_SCATTERED);
298  MRE.r_word1 = Value;
299  Writer->addRelocation(nullptr, Fragment->getParent(), MRE);
300}
301
302bool ARMMachObjectWriter::requiresExternRelocation(MachObjectWriter *Writer,
303                                                   const MCAssembler &Asm,
304                                                   const MCFragment &Fragment,
305                                                   unsigned RelocType,
306                                                   const MCSymbol &S,
307                                                   uint64_t FixedValue) {
308  // Most cases can be identified purely from the symbol.
309  if (Writer->doesSymbolRequireExternRelocation(S))
310    return true;
311  int64_t Value = (int64_t)FixedValue;  // The displacement is signed.
312  int64_t Range;
313  switch (RelocType) {
314  default:
315    return false;
316  case MachO::ARM_RELOC_BR24:
317    // PC pre-adjustment of 8 for these instructions.
318    Value -= 8;
319    // ARM BL/BLX has a 25-bit offset.
320    Range = 0x1ffffff;
321    break;
322  case MachO::ARM_THUMB_RELOC_BR22:
323    // PC pre-adjustment of 4 for these instructions.
324    Value -= 4;
325    // Thumb BL/BLX has a 24-bit offset.
326    Range = 0xffffff;
327  }
328  // BL/BLX also use external relocations when an internal relocation
329  // would result in the target being out of range. This gives the linker
330  // enough information to generate a branch island.
331  Value += Writer->getSectionAddress(&S.getSection());
332  Value -= Writer->getSectionAddress(Fragment.getParent());
333  // If the resultant value would be out of range for an internal relocation,
334  // use an external instead.
335  if (Value > Range || Value < -(Range + 1))
336    return true;
337  return false;
338}
339
340void ARMMachObjectWriter::recordRelocation(MachObjectWriter *Writer,
341                                           MCAssembler &Asm,
342                                           const MCAsmLayout &Layout,
343                                           const MCFragment *Fragment,
344                                           const MCFixup &Fixup, MCValue Target,
345                                           uint64_t &FixedValue) {
346  unsigned IsPCRel = Writer->isFixupKindPCRel(Asm, Fixup.getKind());
347  unsigned Log2Size;
348  unsigned RelocType = MachO::ARM_RELOC_VANILLA;
349  if (!getARMFixupKindMachOInfo(Fixup.getKind(), RelocType, Log2Size))
350    // If we failed to get fixup kind info, it's because there's no legal
351    // relocation type for the fixup kind. This happens when it's a fixup that's
352    // expected to always be resolvable at assembly time and not have any
353    // relocations needed.
354    Asm.getContext().reportFatalError(Fixup.getLoc(),
355                                "unsupported relocation on symbol");
356
357  // If this is a difference or a defined symbol plus an offset, then we need a
358  // scattered relocation entry.  Differences always require scattered
359  // relocations.
360  if (Target.getSymB()) {
361    if (RelocType == MachO::ARM_RELOC_HALF)
362      return RecordARMScatteredHalfRelocation(Writer, Asm, Layout, Fragment,
363                                              Fixup, Target, FixedValue);
364    return RecordARMScatteredRelocation(Writer, Asm, Layout, Fragment, Fixup,
365                                        Target, RelocType, Log2Size,
366                                        FixedValue);
367  }
368
369  // Get the symbol data, if any.
370  const MCSymbol *A = nullptr;
371  if (Target.getSymA())
372    A = &Target.getSymA()->getSymbol();
373
374  // FIXME: For other platforms, we need to use scattered relocations for
375  // internal relocations with offsets.  If this is an internal relocation with
376  // an offset, it also needs a scattered relocation entry.
377  //
378  // Is this right for ARM?
379  uint32_t Offset = Target.getConstant();
380  if (IsPCRel && RelocType == MachO::ARM_RELOC_VANILLA)
381    Offset += 1 << Log2Size;
382  if (Offset && A && !Writer->doesSymbolRequireExternRelocation(*A))
383    return RecordARMScatteredRelocation(Writer, Asm, Layout, Fragment, Fixup,
384                                        Target, RelocType, Log2Size,
385                                        FixedValue);
386
387  // See <reloc.h>.
388  uint32_t FixupOffset = Layout.getFragmentOffset(Fragment)+Fixup.getOffset();
389  unsigned Index = 0;
390  unsigned Type = 0;
391  const MCSymbol *RelSymbol = nullptr;
392
393  if (Target.isAbsolute()) { // constant
394    // FIXME!
395    report_fatal_error("FIXME: relocations to absolute targets "
396                       "not yet implemented");
397  } else {
398    // Resolve constant variables.
399    if (A->isVariable()) {
400      int64_t Res;
401      if (A->getVariableValue()->evaluateAsAbsolute(
402              Res, Layout, Writer->getSectionAddressMap())) {
403        FixedValue = Res;
404        return;
405      }
406    }
407
408    // Check whether we need an external or internal relocation.
409    if (requiresExternRelocation(Writer, Asm, *Fragment, RelocType, *A,
410                                 FixedValue)) {
411      RelSymbol = A;
412
413      // For external relocations, make sure to offset the fixup value to
414      // compensate for the addend of the symbol address, if it was
415      // undefined. This occurs with weak definitions, for example.
416      if (!A->isUndefined())
417        FixedValue -= Layout.getSymbolOffset(*A);
418    } else {
419      // The index is the section ordinal (1-based).
420      const MCSection &Sec = A->getSection();
421      Index = Sec.getOrdinal() + 1;
422      FixedValue += Writer->getSectionAddress(&Sec);
423    }
424    if (IsPCRel)
425      FixedValue -= Writer->getSectionAddress(Fragment->getParent());
426
427    // The type is determined by the fixup kind.
428    Type = RelocType;
429  }
430
431  // struct relocation_info (8 bytes)
432  MachO::any_relocation_info MRE;
433  MRE.r_word0 = FixupOffset;
434  MRE.r_word1 =
435      (Index << 0) | (IsPCRel << 24) | (Log2Size << 25) | (Type << 28);
436
437  // Even when it's not a scattered relocation, movw/movt always uses
438  // a PAIR relocation.
439  if (Type == MachO::ARM_RELOC_HALF) {
440    // The other-half value only gets populated for the movt and movw
441    // relocation entries.
442    uint32_t Value = 0;
443    switch ((unsigned)Fixup.getKind()) {
444    default: break;
445    case ARM::fixup_arm_movw_lo16:
446    case ARM::fixup_t2_movw_lo16:
447      Value = (FixedValue >> 16) & 0xffff;
448      break;
449    case ARM::fixup_arm_movt_hi16:
450    case ARM::fixup_t2_movt_hi16:
451      Value = FixedValue & 0xffff;
452      break;
453    }
454    MachO::any_relocation_info MREPair;
455    MREPair.r_word0 = Value;
456    MREPair.r_word1 = ((0xffffff              <<  0) |
457                       (Log2Size              << 25) |
458                       (MachO::ARM_RELOC_PAIR << 28));
459
460    Writer->addRelocation(nullptr, Fragment->getParent(), MREPair);
461  }
462
463  Writer->addRelocation(RelSymbol, Fragment->getParent(), MRE);
464}
465
466MCObjectWriter *llvm::createARMMachObjectWriter(raw_pwrite_stream &OS,
467                                                bool Is64Bit, uint32_t CPUType,
468                                                uint32_t CPUSubtype) {
469  return createMachObjectWriter(new ARMMachObjectWriter(Is64Bit,
470                                                        CPUType,
471                                                        CPUSubtype),
472                                OS, /*IsLittleEndian=*/true);
473}
474