LLVM  3.7.0
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"
21 #include "llvm/MC/MCSection.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 Type,
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, unsigned RelocType,
48  const MCSymbol &S, uint64_t FixedValue);
49 
50 public:
51  ARMMachObjectWriter(bool Is64Bit, uint32_t CPUType, uint32_t CPUSubtype)
52  : MCMachObjectTargetWriter(Is64Bit, CPUType, CPUSubtype) {}
53 
54  void recordRelocation(MachObjectWriter *Writer, MCAssembler &Asm,
55  const MCAsmLayout &Layout, const MCFragment *Fragment,
56  const MCFixup &Fixup, MCValue Target,
57  uint64_t &FixedValue) override;
58 };
59 }
60 
61 static bool getARMFixupKindMachOInfo(unsigned Kind, unsigned &RelocType,
62  unsigned &Log2Size) {
64  Log2Size = ~0U;
65 
66  switch (Kind) {
67  default:
68  return false;
69 
70  case FK_Data_1:
71  Log2Size = llvm::Log2_32(1);
72  return true;
73  case FK_Data_2:
74  Log2Size = llvm::Log2_32(2);
75  return true;
76  case FK_Data_4:
77  Log2Size = llvm::Log2_32(4);
78  return true;
79  case FK_Data_8:
80  Log2Size = llvm::Log2_32(8);
81  return true;
82 
83  // These fixups are expected to always be resolvable at assembly time and
84  // have no relocations supported.
89  return false;
90 
91  // Handle 24-bit branch kinds.
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 
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
119  RelocType = unsigned(MachO::ARM_RELOC_HALF);
120  Log2Size = 1;
121  return true;
123  RelocType = unsigned(MachO::ARM_RELOC_HALF);
124  Log2Size = 3;
125  return true;
126 
128  RelocType = unsigned(MachO::ARM_RELOC_HALF);
129  Log2Size = 0;
130  return true;
132  RelocType = unsigned(MachO::ARM_RELOC_HALF);
133  Log2Size = 2;
134  return true;
135  }
136 }
137 
138 void ARMMachObjectWriter::
139 RecordARMScatteredHalfRelocation(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.
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;
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;
204  if (Asm.isThumbFunc(A))
205  FixedValue &= 0xfffffffe;
206  MovtBit = 1;
207  // Fallthrough
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 
218  MRE.r_word0 = ((OtherHalf << 0) |
219  (MachO::ARM_RELOC_PAIR << 24) |
220  (MovtBit << 28) |
221  (ThumbBit << 29) |
222  (IsPCRel << 30) |
224  MRE.r_word1 = Value2;
225  Writer->addRelocation(nullptr, Fragment->getParent(), MRE);
226  }
227 
229  MRE.r_word0 = ((FixupOffset << 0) |
230  (Type << 24) |
231  (MovtBit << 28) |
232  (ThumbBit << 29) |
233  (IsPCRel << 30) |
235  MRE.r_word1 = Value;
236  Writer->addRelocation(nullptr, Fragment->getParent(), MRE);
237 }
238 
239 void 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.
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 ||
283  MRE.r_word0 = ((0 << 0) |
284  (MachO::ARM_RELOC_PAIR << 24) |
285  (Log2Size << 28) |
286  (IsPCRel << 30) |
288  MRE.r_word1 = Value2;
289  Writer->addRelocation(nullptr, Fragment->getParent(), MRE);
290  }
291 
293  MRE.r_word0 = ((FixupOffset << 0) |
294  (Type << 24) |
295  (Log2Size << 28) |
296  (IsPCRel << 30) |
298  MRE.r_word1 = Value;
299  Writer->addRelocation(nullptr, Fragment->getParent(), MRE);
300 }
301 
302 bool 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;
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;
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 
340 void 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)
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;
447  Value = (FixedValue >> 16) & 0xffff;
448  break;
451  Value = FixedValue & 0xffff;
452  break;
453  }
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 
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 }
Instances of this class represent a uniqued identifier for a section in the current translation unit...
Definition: MCSection.h:48
const MCSymbol & getSymbol() const
Definition: MCExpr.h:328
SMLoc getLoc() const
Definition: MCFixup.h:108
bool doesSymbolRequireExternRelocation(const MCSymbol &S)
This represents an "assembler immediate".
Definition: MCValue.h:44
MCSymbol - Instances of this class represent a symbol name in the MC file, and MCSymbols are created ...
Definition: MCSymbol.h:39
uint64_t getSectionAddress(const MCSection *Sec) const
LLVM_ATTRIBUTE_NORETURN void reportFatalError(SMLoc L, const Twine &Msg) const
Definition: MCContext.cpp:474
bool getSymbolOffset(const MCSymbol &S, uint64_t &Val) const
Get the offset of the given symbol, as computed in the current layout.
MCObjectWriter * createARMMachObjectWriter(raw_pwrite_stream &OS, bool Is64Bit, uint32_t CPUType, uint32_t CPUSubtype)
Construct an ARM Mach-O object writer.
MCContext & getContext() const
Definition: MCAssembler.h:731
Defines the object file and target independent interfaces used by the assembler backend to write nati...
LLVM_ATTRIBUTE_NORETURN void report_fatal_error(const char *reason, bool gen_crash_diag=true)
Reports a serious error, calling any installed error handler.
Encode information on a single operation to perform on a byte sequence (e.g., an encoded instruction)...
Definition: MCFixup.h:62
Encapsulates the layout of an assembly file at a particular point in time.
Definition: MCAsmLayout.h:29
const MCExpr * getVariableValue() const
getVariableValue() - Get the value for variable symbols.
Definition: MCSymbol.h:299
Represent a reference to a symbol from inside an expression.
Definition: MCExpr.h:159
A four-byte fixup.
Definition: MCFixup.h:26
bool isFixupKindPCRel(const MCAssembler &Asm, unsigned Kind)
void addRelocation(const MCSymbol *RelSymbol, const MCSection *Sec, MachO::any_relocation_info &MRE)
bool isAbsolute() const
Is this an absolute (as opposed to relocatable) value.
Definition: MCValue.h:56
bool isThumbFunc(const MCSymbol *Func) const
Check whether a given symbol has been flagged with .thumb_func.
uint32_t getOffset() const
Definition: MCFixup.h:91
SectionAddrMap & getSectionAddressMap()
The instances of the Type class are immutable: once they are created, they are never changed...
Definition: Type.h:45
static bool getARMFixupKindMachOInfo(unsigned Kind, unsigned &RelocType, unsigned &Log2Size)
MCFragment * getFragment() const
Definition: MCSymbol.h:382
unsigned getOrdinal() const
Definition: MCSection.h:127
MCFixupKind getKind() const
Definition: MCFixup.h:89
const MCSymbolRefExpr * getSymB() const
Definition: MCValue.h:52
A one-byte fixup.
Definition: MCFixup.h:24
PowerPC TLS Dynamic Call Fixup
const MCSymbolRefExpr * getSymA() const
Definition: MCValue.h:51
MCSection & getSection() const
Get the section associated with a defined, non-absolute symbol.
Definition: MCSymbol.h:264
MCSection * getParent() const
Definition: MCAssembler.h:118
unsigned Log2_32(uint32_t Value)
Log2_32 - This function returns the floor log base 2 of the specified value, -1 if the value is zero...
Definition: MathExtras.h:468
Target - Wrapper for Target specific information.
MCObjectWriter * createMachObjectWriter(MCMachObjectTargetWriter *MOTW, raw_pwrite_stream &OS, bool IsLittleEndian)
Construct a new Mach-O writer instance.
StringRef getName() const
getName - Get the symbol name.
Definition: MCSymbol.h:205
A eight-byte fixup.
Definition: MCFixup.h:27
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:294
An abstract base class for streams implementations that also support a pwrite operation.
Definition: raw_ostream.h:321
int64_t getConstant() const
Definition: MCValue.h:50
const ARM::ArchExtKind Kind
LLVM Value Representation.
Definition: Value.h:69
bool isUndefined() const
isUndefined - Check if this symbol undefined (i.e., implicitly defined).
Definition: MCSymbol.h:258
uint64_t getSymbolAddress(const MCSymbol &S, const MCAsmLayout &Layout) const
A two-byte fixup.
Definition: MCFixup.h:25