LLVM API Documentation

 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
ARMMachObjectWriter.cpp
Go to the documentation of this file.
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 
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"
22 #include "llvm/MC/MCValue.h"
24 #include "llvm/Support/MachO.h"
25 using namespace llvm;
26 
27 namespace {
28 class ARMMachObjectWriter : public MCMachObjectTargetWriter {
29  void RecordARMScatteredRelocation(MachObjectWriter *Writer,
30  const MCAssembler &Asm,
31  const MCAsmLayout &Layout,
32  const MCFragment *Fragment,
33  const MCFixup &Fixup,
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 
44  bool requiresExternRelocation(MachObjectWriter *Writer,
45  const MCAssembler &Asm,
46  const MCFragment &Fragment,
47  unsigned RelocType, const MCSymbolData *SD,
48  uint64_t FixedValue);
49 
50 public:
51  ARMMachObjectWriter(bool Is64Bit, uint32_t CPUType,
52  uint32_t CPUSubtype)
53  : MCMachObjectTargetWriter(Is64Bit, CPUType, CPUSubtype,
54  /*UseAggressiveSymbolFolding=*/true) {}
55 
56  void RecordRelocation(MachObjectWriter *Writer,
57  const MCAssembler &Asm, const MCAsmLayout &Layout,
58  const MCFragment *Fragment, const MCFixup &Fixup,
59  MCValue Target, uint64_t &FixedValue);
60 };
61 }
62 
63 static bool getARMFixupKindMachOInfo(unsigned Kind, unsigned &RelocType,
64  unsigned &Log2Size) {
66  Log2Size = ~0U;
67 
68  switch (Kind) {
69  default:
70  return false;
71 
72  case FK_Data_1:
73  Log2Size = llvm::Log2_32(1);
74  return true;
75  case FK_Data_2:
76  Log2Size = llvm::Log2_32(2);
77  return true;
78  case FK_Data_4:
79  Log2Size = llvm::Log2_32(4);
80  return true;
81  case FK_Data_8:
82  Log2Size = llvm::Log2_32(8);
83  return true;
84 
85  // Handle 24-bit branch kinds.
93  case ARM::fixup_arm_blx:
94  RelocType = unsigned(MachO::ARM_RELOC_BR24);
95  // Report as 'long', even though that is not quite accurate.
96  Log2Size = llvm::Log2_32(4);
97  return true;
98 
99  // Handle Thumb branches.
102  Log2Size = llvm::Log2_32(2);
103  return true;
104 
109  Log2Size = llvm::Log2_32(4);
110  return true;
111 
112  // For movw/movt r_type relocations they always have a pair following them and
113  // the r_length bits are used differently. The encoding of the r_length is as
114  // follows:
115  // low bit of r_length:
116  // 0 - :lower16: for movw instructions
117  // 1 - :upper16: for movt instructions
118  // high bit of r_length:
119  // 0 - arm instructions
120  // 1 - thumb instructions
123  RelocType = unsigned(MachO::ARM_RELOC_HALF);
124  Log2Size = 1;
125  return true;
128  RelocType = unsigned(MachO::ARM_RELOC_HALF);
129  Log2Size = 3;
130  return true;
131 
134  RelocType = unsigned(MachO::ARM_RELOC_HALF);
135  Log2Size = 0;
136  return true;
139  RelocType = unsigned(MachO::ARM_RELOC_HALF);
140  Log2Size = 2;
141  return true;
142  }
143 }
144 
145 void ARMMachObjectWriter::
146 RecordARMScatteredHalfRelocation(MachObjectWriter *Writer,
147  const MCAssembler &Asm,
148  const MCAsmLayout &Layout,
149  const MCFragment *Fragment,
150  const MCFixup &Fixup,
151  MCValue Target,
152  uint64_t &FixedValue) {
153  uint32_t FixupOffset = Layout.getFragmentOffset(Fragment)+Fixup.getOffset();
154  unsigned IsPCRel = Writer->isFixupKindPCRel(Asm, Fixup.getKind());
155  unsigned Type = MachO::ARM_RELOC_HALF;
156 
157  // See <reloc.h>.
158  const MCSymbol *A = &Target.getSymA()->getSymbol();
159  MCSymbolData *A_SD = &Asm.getSymbolData(*A);
160 
161  if (!A_SD->getFragment())
162  Asm.getContext().FatalError(Fixup.getLoc(),
163  "symbol '" + A->getName() +
164  "' can not be undefined in a subtraction expression");
165 
166  uint32_t Value = Writer->getSymbolAddress(A_SD, Layout);
167  uint32_t Value2 = 0;
168  uint64_t SecAddr =
169  Writer->getSectionAddress(A_SD->getFragment()->getParent());
170  FixedValue += SecAddr;
171 
172  if (const MCSymbolRefExpr *B = Target.getSymB()) {
173  MCSymbolData *B_SD = &Asm.getSymbolData(B->getSymbol());
174 
175  if (!B_SD->getFragment())
176  Asm.getContext().FatalError(Fixup.getLoc(),
177  "symbol '" + B->getSymbol().getName() +
178  "' can not be undefined in a subtraction expression");
179 
180  // Select the appropriate difference relocation type.
182  Value2 = Writer->getSymbolAddress(B_SD, Layout);
183  FixedValue -= Writer->getSectionAddress(B_SD->getFragment()->getParent());
184  }
185 
186  // Relocations are written out in reverse order, so the PAIR comes first.
187  // ARM_RELOC_HALF and ARM_RELOC_HALF_SECTDIFF abuse the r_length field:
188  //
189  // For these two r_type relocations they always have a pair following them and
190  // the r_length bits are used differently. The encoding of the r_length is as
191  // follows:
192  // low bit of r_length:
193  // 0 - :lower16: for movw instructions
194  // 1 - :upper16: for movt instructions
195  // high bit of r_length:
196  // 0 - arm instructions
197  // 1 - thumb instructions
198  // the other half of the relocated expression is in the following pair
199  // relocation entry in the low 16 bits of r_address field.
200  unsigned ThumbBit = 0;
201  unsigned MovtBit = 0;
202  switch ((unsigned)Fixup.getKind()) {
203  default: break;
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 (A_SD->getFlags() & SF_ThumbFunc)
211  FixedValue &= 0xfffffffe;
212  break;
215  if (A_SD->getFlags() & SF_ThumbFunc)
216  FixedValue &= 0xfffffffe;
217  MovtBit = 1;
218  // Fallthrough
221  ThumbBit = 1;
222  break;
223  }
224 
225  if (Type == MachO::ARM_RELOC_HALF_SECTDIFF) {
226  uint32_t OtherHalf = MovtBit
227  ? (FixedValue & 0xffff) : ((FixedValue & 0xffff0000) >> 16);
228 
230  MRE.r_word0 = ((OtherHalf << 0) |
231  (MachO::ARM_RELOC_PAIR << 24) |
232  (MovtBit << 28) |
233  (ThumbBit << 29) |
234  (IsPCRel << 30) |
235  MachO::R_SCATTERED);
236  MRE.r_word1 = Value2;
237  Writer->addRelocation(Fragment->getParent(), MRE);
238  }
239 
241  MRE.r_word0 = ((FixupOffset << 0) |
242  (Type << 24) |
243  (MovtBit << 28) |
244  (ThumbBit << 29) |
245  (IsPCRel << 30) |
246  MachO::R_SCATTERED);
247  MRE.r_word1 = Value;
248  Writer->addRelocation(Fragment->getParent(), MRE);
249 }
250 
251 void ARMMachObjectWriter::RecordARMScatteredRelocation(MachObjectWriter *Writer,
252  const MCAssembler &Asm,
253  const MCAsmLayout &Layout,
254  const MCFragment *Fragment,
255  const MCFixup &Fixup,
256  MCValue Target,
257  unsigned Log2Size,
258  uint64_t &FixedValue) {
259  uint32_t FixupOffset = Layout.getFragmentOffset(Fragment)+Fixup.getOffset();
260  unsigned IsPCRel = Writer->isFixupKindPCRel(Asm, Fixup.getKind());
261  unsigned Type = MachO::ARM_RELOC_VANILLA;
262 
263  // See <reloc.h>.
264  const MCSymbol *A = &Target.getSymA()->getSymbol();
265  MCSymbolData *A_SD = &Asm.getSymbolData(*A);
266 
267  if (!A_SD->getFragment())
268  Asm.getContext().FatalError(Fixup.getLoc(),
269  "symbol '" + A->getName() +
270  "' can not be undefined in a subtraction expression");
271 
272  uint32_t Value = Writer->getSymbolAddress(A_SD, Layout);
273  uint64_t SecAddr = Writer->getSectionAddress(A_SD->getFragment()->getParent());
274  FixedValue += SecAddr;
275  uint32_t Value2 = 0;
276 
277  if (const MCSymbolRefExpr *B = Target.getSymB()) {
278  MCSymbolData *B_SD = &Asm.getSymbolData(B->getSymbol());
279 
280  if (!B_SD->getFragment())
281  Asm.getContext().FatalError(Fixup.getLoc(),
282  "symbol '" + B->getSymbol().getName() +
283  "' can not be undefined in a subtraction expression");
284 
285  // Select the appropriate difference relocation type.
287  Value2 = Writer->getSymbolAddress(B_SD, Layout);
288  FixedValue -= Writer->getSectionAddress(B_SD->getFragment()->getParent());
289  }
290 
291  // Relocations are written out in reverse order, so the PAIR comes first.
292  if (Type == MachO::ARM_RELOC_SECTDIFF ||
295  MRE.r_word0 = ((0 << 0) |
296  (MachO::ARM_RELOC_PAIR << 24) |
297  (Log2Size << 28) |
298  (IsPCRel << 30) |
299  MachO::R_SCATTERED);
300  MRE.r_word1 = Value2;
301  Writer->addRelocation(Fragment->getParent(), MRE);
302  }
303 
305  MRE.r_word0 = ((FixupOffset << 0) |
306  (Type << 24) |
307  (Log2Size << 28) |
308  (IsPCRel << 30) |
309  MachO::R_SCATTERED);
310  MRE.r_word1 = Value;
311  Writer->addRelocation(Fragment->getParent(), MRE);
312 }
313 
314 bool ARMMachObjectWriter::requiresExternRelocation(MachObjectWriter *Writer,
315  const MCAssembler &Asm,
316  const MCFragment &Fragment,
317  unsigned RelocType,
318  const MCSymbolData *SD,
319  uint64_t FixedValue) {
320  // Most cases can be identified purely from the symbol.
321  if (Writer->doesSymbolRequireExternRelocation(SD))
322  return true;
323  int64_t Value = (int64_t)FixedValue; // The displacement is signed.
324  int64_t Range;
325  switch (RelocType) {
326  default:
327  return false;
329  // PC pre-adjustment of 8 for these instructions.
330  Value -= 8;
331  // ARM BL/BLX has a 25-bit offset.
332  Range = 0x1ffffff;
333  break;
335  // PC pre-adjustment of 4 for these instructions.
336  Value -= 4;
337  // Thumb BL/BLX has a 24-bit offset.
338  Range = 0xffffff;
339  }
340  // BL/BLX also use external relocations when an internal relocation
341  // would result in the target being out of range. This gives the linker
342  // enough information to generate a branch island.
343  const MCSectionData &SymSD = Asm.getSectionData(
344  SD->getSymbol().getSection());
345  Value += Writer->getSectionAddress(&SymSD);
346  Value -= Writer->getSectionAddress(Fragment.getParent());
347  // If the resultant value would be out of range for an internal relocation,
348  // use an external instead.
349  if (Value > Range || Value < -(Range + 1))
350  return true;
351  return false;
352 }
353 
354 void ARMMachObjectWriter::RecordRelocation(MachObjectWriter *Writer,
355  const MCAssembler &Asm,
356  const MCAsmLayout &Layout,
357  const MCFragment *Fragment,
358  const MCFixup &Fixup,
359  MCValue Target,
360  uint64_t &FixedValue) {
361  unsigned IsPCRel = Writer->isFixupKindPCRel(Asm, Fixup.getKind());
362  unsigned Log2Size;
363  unsigned RelocType = MachO::ARM_RELOC_VANILLA;
364  if (!getARMFixupKindMachOInfo(Fixup.getKind(), RelocType, Log2Size))
365  // If we failed to get fixup kind info, it's because there's no legal
366  // relocation type for the fixup kind. This happens when it's a fixup that's
367  // expected to always be resolvable at assembly time and not have any
368  // relocations needed.
369  Asm.getContext().FatalError(Fixup.getLoc(),
370  "unsupported relocation on symbol");
371 
372  // If this is a difference or a defined symbol plus an offset, then we need a
373  // scattered relocation entry. Differences always require scattered
374  // relocations.
375  if (Target.getSymB()) {
376  if (RelocType == MachO::ARM_RELOC_HALF)
377  return RecordARMScatteredHalfRelocation(Writer, Asm, Layout, Fragment,
378  Fixup, Target, FixedValue);
379  return RecordARMScatteredRelocation(Writer, Asm, Layout, Fragment, Fixup,
380  Target, Log2Size, FixedValue);
381  }
382 
383  // Get the symbol data, if any.
384  MCSymbolData *SD = 0;
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, Log2Size, FixedValue);
399 
400  // See <reloc.h>.
401  uint32_t FixupOffset = Layout.getFragmentOffset(Fragment)+Fixup.getOffset();
402  unsigned Index = 0;
403  unsigned IsExtern = 0;
404  unsigned Type = 0;
405 
406  if (Target.isAbsolute()) { // constant
407  // FIXME!
408  report_fatal_error("FIXME: relocations to absolute targets "
409  "not yet implemented");
410  } else {
411  // Resolve constant variables.
412  if (SD->getSymbol().isVariable()) {
413  int64_t Res;
414  if (SD->getSymbol().getVariableValue()->EvaluateAsAbsolute(
415  Res, Layout, Writer->getSectionAddressMap())) {
416  FixedValue = Res;
417  return;
418  }
419  }
420 
421  // Check whether we need an external or internal relocation.
422  if (requiresExternRelocation(Writer, Asm, *Fragment, RelocType, SD,
423  FixedValue)) {
424  IsExtern = 1;
425  Index = SD->getIndex();
426 
427  // For external relocations, make sure to offset the fixup value to
428  // compensate for the addend of the symbol address, if it was
429  // undefined. This occurs with weak definitions, for example.
430  if (!SD->Symbol->isUndefined())
431  FixedValue -= Layout.getSymbolOffset(SD);
432  } else {
433  // The index is the section ordinal (1-based).
434  const MCSectionData &SymSD = Asm.getSectionData(
435  SD->getSymbol().getSection());
436  Index = SymSD.getOrdinal() + 1;
437  FixedValue += Writer->getSectionAddress(&SymSD);
438  }
439  if (IsPCRel)
440  FixedValue -= Writer->getSectionAddress(Fragment->getParent());
441 
442  // The type is determined by the fixup kind.
443  Type = RelocType;
444  }
445 
446  // struct relocation_info (8 bytes)
448  MRE.r_word0 = FixupOffset;
449  MRE.r_word1 = ((Index << 0) |
450  (IsPCRel << 24) |
451  (Log2Size << 25) |
452  (IsExtern << 27) |
453  (Type << 28));
454 
455  // Even when it's not a scattered relocation, movw/movt always uses
456  // a PAIR relocation.
457  if (Type == MachO::ARM_RELOC_HALF) {
458  // The other-half value only gets populated for the movt and movw
459  // relocation entries.
460  uint32_t Value = 0;
461  switch ((unsigned)Fixup.getKind()) {
462  default: break;
467  Value = (FixedValue >> 16) & 0xffff;
468  break;
473  Value = FixedValue & 0xffff;
474  break;
475  }
477  MREPair.r_word0 = Value;
478  MREPair.r_word1 = ((0xffffff << 0) |
479  (Log2Size << 25) |
480  (MachO::ARM_RELOC_PAIR << 28));
481 
482  Writer->addRelocation(Fragment->getParent(), MREPair);
483  }
484 
485  Writer->addRelocation(Fragment->getParent(), MRE);
486 }
487 
489  bool Is64Bit,
490  uint32_t CPUType,
491  uint32_t CPUSubtype) {
492  return createMachObjectWriter(new ARMMachObjectWriter(Is64Bit,
493  CPUType,
494  CPUSubtype),
495  OS, /*IsLittleEndian=*/true);
496 }
const MCSymbol & getSymbol() const
Definition: MCExpr.h:283
SMLoc getLoc() const
Definition: MCFixup.h:107
MCContext & getContext() const
Definition: MCAssembler.h:992
const MCSymbol & getSymbol() const
Definition: MCAssembler.h:718
LLVM_ATTRIBUTE_NORETURN void report_fatal_error(const char *reason, bool gen_crash_diag=true)
uint64_t getIndex() const
getIndex - Get the (implementation defined) index.
Definition: MCAssembler.h:781
const MCSection & getSection() const
Definition: MCSymbol.h:111
uint64_t getSymbolAddress(const MCSymbolData *SD, const MCAsmLayout &Layout) const
const MCExpr * getVariableValue() const
getVariableValue() - Get the value for variable symbols.
Definition: MCSymbol.h:137
MCSectionData & getSectionData(const MCSection &Section) const
Definition: MCAssembler.h:1128
A four-byte fixup.
Definition: MCFixup.h:25
bool isFixupKindPCRel(const MCAssembler &Asm, unsigned Kind)
uint64_t getSectionAddress(const MCSectionData *SD) const
bool isAbsolute() const
isAbsolute - Is this an absolute (as opposed to relocatable) value.
Definition: MCValue.h:47
MCFragment * getFragment() const
Definition: MCAssembler.h:720
uint32_t getOffset() const
Definition: MCFixup.h:90
SectionAddrMap & getSectionAddressMap()
unsigned getOrdinal() const
Definition: MCAssembler.h:613
#define true
Definition: ConvertUTF.c:65
MCSectionData * getParent() const
Definition: MCAssembler.h:95
static bool getARMFixupKindMachOInfo(unsigned Kind, unsigned &RelocType, unsigned &Log2Size)
uint32_t getFlags() const
getFlags - Get the (implementation defined) symbol flags.
Definition: MCAssembler.h:770
MCFixupKind getKind() const
Definition: MCFixup.h:88
const MCSymbolRefExpr * getSymB() const
Definition: MCValue.h:44
A one-byte fixup.
Definition: MCFixup.h:23
LLVM_ATTRIBUTE_NORETURN void FatalError(SMLoc L, const Twine &Msg)
Definition: MCContext.cpp:394
MCObjectWriter * createARMMachObjectWriter(raw_ostream &OS, bool Is64Bit, uint32_t CPUType, uint32_t CPUSubtype)
createARMMachObjectWriter - Construct an ARM Mach-O object writer.
MCSymbolData & getSymbolData(const MCSymbol &Symbol) const
Definition: MCAssembler.h:1145
const MCSymbolRefExpr * getSymA() const
Definition: MCValue.h:43
uint64_t getSymbolOffset(const MCSymbolData *SD) const
Get the offset of the given symbol, as computed in the current layout.
unsigned Log2_32(uint32_t Value)
Definition: MathExtras.h:443
bool doesSymbolRequireExternRelocation(const MCSymbolData *SD)
StringRef getName() const
getName - Get the symbol name.
Definition: MCSymbol.h:70
A eight-byte fixup.
Definition: MCFixup.h:26
uint64_t getFragmentOffset(const MCFragment *F) const
Get the offset of the given fragment inside its containing section.
bool isVariable() const
isVariable - Check if this is a variable symbol.
Definition: MCSymbol.h:132
int64_t getConstant() const
Definition: MCValue.h:42
LLVM Value Representation.
Definition: Value.h:66
void addRelocation(const MCSectionData *SD, MachO::any_relocation_info &MRE)
bool isUndefined() const
isUndefined - Check if this symbol undefined (i.e., implicitly defined).
Definition: MCSymbol.h:100
const MCSymbol * Symbol
Definition: MCAssembler.h:671
A two-byte fixup.
Definition: MCFixup.h:24
MCObjectWriter * createMachObjectWriter(MCMachObjectTargetWriter *MOTW, raw_ostream &OS, bool IsLittleEndian)
Construct a new Mach-O writer instance.