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