LLVM  4.0.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().reportError(Fixup.getLoc(),
155  "symbol '" + A->getName() +
156  "' can not be undefined in a subtraction expression");
157  return;
158  }
159 
160  uint32_t Value = Writer->getSymbolAddress(*A, Layout);
161  uint32_t Value2 = 0;
162  uint64_t SecAddr = Writer->getSectionAddress(A->getFragment()->getParent());
163  FixedValue += SecAddr;
164 
165  if (const MCSymbolRefExpr *B = Target.getSymB()) {
166  const MCSymbol *SB = &B->getSymbol();
167 
168  if (!SB->getFragment()) {
169  Asm.getContext().reportError(Fixup.getLoc(),
170  "symbol '" + B->getSymbol().getName() +
171  "' can not be undefined in a subtraction expression");
172  return;
173  }
174 
175  // Select the appropriate difference relocation type.
177  Value2 = Writer->getSymbolAddress(B->getSymbol(), Layout);
178  FixedValue -= Writer->getSectionAddress(SB->getFragment()->getParent());
179  }
180 
181  // Relocations are written out in reverse order, so the PAIR comes first.
182  // ARM_RELOC_HALF and ARM_RELOC_HALF_SECTDIFF abuse the r_length field:
183  //
184  // For these two r_type relocations they always have a pair following them and
185  // the r_length bits are used differently. The encoding of the r_length is as
186  // follows:
187  // low bit of r_length:
188  // 0 - :lower16: for movw instructions
189  // 1 - :upper16: for movt instructions
190  // high bit of r_length:
191  // 0 - arm instructions
192  // 1 - thumb instructions
193  // the other half of the relocated expression is in the following pair
194  // relocation entry in the low 16 bits of r_address field.
195  unsigned ThumbBit = 0;
196  unsigned MovtBit = 0;
197  switch ((unsigned)Fixup.getKind()) {
198  default: break;
200  MovtBit = 1;
201  // The thumb bit shouldn't be set in the 'other-half' bit of the
202  // relocation, but it will be set in FixedValue if the base symbol
203  // is a thumb function. Clear it out here.
204  if (Asm.isThumbFunc(A))
205  FixedValue &= 0xfffffffe;
206  break;
208  if (Asm.isThumbFunc(A))
209  FixedValue &= 0xfffffffe;
210  MovtBit = 1;
213  ThumbBit = 1;
214  break;
215  }
216 
217  if (Type == MachO::ARM_RELOC_HALF_SECTDIFF) {
218  uint32_t OtherHalf = MovtBit
219  ? (FixedValue & 0xffff) : ((FixedValue & 0xffff0000) >> 16);
220 
222  MRE.r_word0 = ((OtherHalf << 0) |
223  (MachO::ARM_RELOC_PAIR << 24) |
224  (MovtBit << 28) |
225  (ThumbBit << 29) |
226  (IsPCRel << 30) |
228  MRE.r_word1 = Value2;
229  Writer->addRelocation(nullptr, Fragment->getParent(), MRE);
230  }
231 
233  MRE.r_word0 = ((FixupOffset << 0) |
234  (Type << 24) |
235  (MovtBit << 28) |
236  (ThumbBit << 29) |
237  (IsPCRel << 30) |
239  MRE.r_word1 = Value;
240  Writer->addRelocation(nullptr, Fragment->getParent(), MRE);
241 }
242 
243 void ARMMachObjectWriter::RecordARMScatteredRelocation(MachObjectWriter *Writer,
244  const MCAssembler &Asm,
245  const MCAsmLayout &Layout,
246  const MCFragment *Fragment,
247  const MCFixup &Fixup,
248  MCValue Target,
249  unsigned Type,
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 
255  // See <reloc.h>.
256  const MCSymbol *A = &Target.getSymA()->getSymbol();
257 
258  if (!A->getFragment()) {
259  Asm.getContext().reportError(Fixup.getLoc(),
260  "symbol '" + A->getName() +
261  "' can not be undefined in a subtraction expression");
262  return;
263  }
264 
265  uint32_t Value = Writer->getSymbolAddress(*A, Layout);
266  uint64_t SecAddr = Writer->getSectionAddress(A->getFragment()->getParent());
267  FixedValue += SecAddr;
268  uint32_t Value2 = 0;
269 
270  if (const MCSymbolRefExpr *B = Target.getSymB()) {
271  assert(Type == MachO::ARM_RELOC_VANILLA && "invalid reloc for 2 symbols");
272  const MCSymbol *SB = &B->getSymbol();
273 
274  if (!SB->getFragment()) {
275  Asm.getContext().reportError(Fixup.getLoc(),
276  "symbol '" + B->getSymbol().getName() +
277  "' can not be undefined in a subtraction expression");
278  return;
279  }
280 
281  // Select the appropriate difference relocation type.
283  Value2 = Writer->getSymbolAddress(B->getSymbol(), Layout);
284  FixedValue -= Writer->getSectionAddress(SB->getFragment()->getParent());
285  }
286 
287  // Relocations are written out in reverse order, so the PAIR comes first.
288  if (Type == MachO::ARM_RELOC_SECTDIFF ||
291  MRE.r_word0 = ((0 << 0) |
292  (MachO::ARM_RELOC_PAIR << 24) |
293  (Log2Size << 28) |
294  (IsPCRel << 30) |
296  MRE.r_word1 = Value2;
297  Writer->addRelocation(nullptr, Fragment->getParent(), MRE);
298  }
299 
301  MRE.r_word0 = ((FixupOffset << 0) |
302  (Type << 24) |
303  (Log2Size << 28) |
304  (IsPCRel << 30) |
306  MRE.r_word1 = Value;
307  Writer->addRelocation(nullptr, Fragment->getParent(), MRE);
308 }
309 
310 bool ARMMachObjectWriter::requiresExternRelocation(MachObjectWriter *Writer,
311  const MCAssembler &Asm,
312  const MCFragment &Fragment,
313  unsigned RelocType,
314  const MCSymbol &S,
315  uint64_t FixedValue) {
316  // Most cases can be identified purely from the symbol.
317  if (Writer->doesSymbolRequireExternRelocation(S))
318  return true;
319  int64_t Value = (int64_t)FixedValue; // The displacement is signed.
320  int64_t Range;
321  switch (RelocType) {
322  default:
323  return false;
325  // PC pre-adjustment of 8 for these instructions.
326  Value -= 8;
327  // ARM BL/BLX has a 25-bit offset.
328  Range = 0x1ffffff;
329  break;
331  // PC pre-adjustment of 4 for these instructions.
332  Value -= 4;
333  // Thumb BL/BLX has a 24-bit offset.
334  Range = 0xffffff;
335  }
336  // BL/BLX also use external relocations when an internal relocation
337  // would result in the target being out of range. This gives the linker
338  // enough information to generate a branch island.
339  Value += Writer->getSectionAddress(&S.getSection());
340  Value -= Writer->getSectionAddress(Fragment.getParent());
341  // If the resultant value would be out of range for an internal relocation,
342  // use an external instead.
343  if (Value > Range || Value < -(Range + 1))
344  return true;
345  return false;
346 }
347 
348 void ARMMachObjectWriter::recordRelocation(MachObjectWriter *Writer,
349  MCAssembler &Asm,
350  const MCAsmLayout &Layout,
351  const MCFragment *Fragment,
352  const MCFixup &Fixup, MCValue Target,
353  uint64_t &FixedValue) {
354  unsigned IsPCRel = Writer->isFixupKindPCRel(Asm, Fixup.getKind());
355  unsigned Log2Size;
356  unsigned RelocType = MachO::ARM_RELOC_VANILLA;
357  if (!getARMFixupKindMachOInfo(Fixup.getKind(), RelocType, Log2Size)) {
358  // If we failed to get fixup kind info, it's because there's no legal
359  // relocation type for the fixup kind. This happens when it's a fixup that's
360  // expected to always be resolvable at assembly time and not have any
361  // relocations needed.
362  Asm.getContext().reportError(Fixup.getLoc(),
363  "unsupported relocation on symbol");
364  return;
365  }
366 
367  // If this is a difference or a defined symbol plus an offset, then we need a
368  // scattered relocation entry. Differences always require scattered
369  // relocations.
370  if (Target.getSymB()) {
371  if (RelocType == MachO::ARM_RELOC_HALF)
372  return RecordARMScatteredHalfRelocation(Writer, Asm, Layout, Fragment,
373  Fixup, Target, FixedValue);
374  return RecordARMScatteredRelocation(Writer, Asm, Layout, Fragment, Fixup,
375  Target, RelocType, Log2Size,
376  FixedValue);
377  }
378 
379  // Get the symbol data, if any.
380  const MCSymbol *A = nullptr;
381  if (Target.getSymA())
382  A = &Target.getSymA()->getSymbol();
383 
384  // FIXME: For other platforms, we need to use scattered relocations for
385  // internal relocations with offsets. If this is an internal relocation with
386  // an offset, it also needs a scattered relocation entry.
387  //
388  // Is this right for ARM?
389  uint32_t Offset = Target.getConstant();
390  if (IsPCRel && RelocType == MachO::ARM_RELOC_VANILLA)
391  Offset += 1 << Log2Size;
392  if (Offset && A && !Writer->doesSymbolRequireExternRelocation(*A) &&
393  RelocType != MachO::ARM_RELOC_HALF)
394  return RecordARMScatteredRelocation(Writer, Asm, Layout, Fragment, Fixup,
395  Target, RelocType, Log2Size,
396  FixedValue);
397 
398  // See <reloc.h>.
399  uint32_t FixupOffset = Layout.getFragmentOffset(Fragment)+Fixup.getOffset();
400  unsigned Index = 0;
401  unsigned Type = 0;
402  const MCSymbol *RelSymbol = nullptr;
403 
404  if (Target.isAbsolute()) { // constant
405  // FIXME!
406  report_fatal_error("FIXME: relocations to absolute targets "
407  "not yet implemented");
408  } else {
409  // Resolve constant variables.
410  if (A->isVariable()) {
411  int64_t Res;
412  if (A->getVariableValue()->evaluateAsAbsolute(
413  Res, Layout, Writer->getSectionAddressMap())) {
414  FixedValue = Res;
415  return;
416  }
417  }
418 
419  // Check whether we need an external or internal relocation.
420  if (requiresExternRelocation(Writer, Asm, *Fragment, RelocType, *A,
421  FixedValue)) {
422  RelSymbol = A;
423 
424  // For external relocations, make sure to offset the fixup value to
425  // compensate for the addend of the symbol address, if it was
426  // undefined. This occurs with weak definitions, for example.
427  if (!A->isUndefined())
428  FixedValue -= Layout.getSymbolOffset(*A);
429  } else {
430  // The index is the section ordinal (1-based).
431  const MCSection &Sec = A->getSection();
432  Index = Sec.getOrdinal() + 1;
433  FixedValue += Writer->getSectionAddress(&Sec);
434  }
435  if (IsPCRel)
436  FixedValue -= Writer->getSectionAddress(Fragment->getParent());
437 
438  // The type is determined by the fixup kind.
439  Type = RelocType;
440  }
441 
442  // struct relocation_info (8 bytes)
444  MRE.r_word0 = FixupOffset;
445  MRE.r_word1 =
446  (Index << 0) | (IsPCRel << 24) | (Log2Size << 25) | (Type << 28);
447 
448  // Even when it's not a scattered relocation, movw/movt always uses
449  // a PAIR relocation.
450  if (Type == MachO::ARM_RELOC_HALF) {
451  // The entire addend is needed to correctly apply a relocation. One half is
452  // extracted from the instruction itself, the other comes from this
453  // PAIR. I.e. it's correct that we insert the high bits of the addend in the
454  // MOVW case here. relocation entries.
455  uint32_t Value = 0;
456  switch ((unsigned)Fixup.getKind()) {
457  default: break;
460  Value = (FixedValue >> 16) & 0xffff;
461  break;
464  Value = FixedValue & 0xffff;
465  break;
466  }
468  MREPair.r_word0 = Value;
469  MREPair.r_word1 = ((0xffffff << 0) |
470  (Log2Size << 25) |
471  (MachO::ARM_RELOC_PAIR << 28));
472 
473  Writer->addRelocation(nullptr, Fragment->getParent(), MREPair);
474  }
475 
476  Writer->addRelocation(RelSymbol, Fragment->getParent(), MRE);
477 }
478 
480  bool Is64Bit, uint32_t CPUType,
481  uint32_t CPUSubtype) {
482  return createMachObjectWriter(new ARMMachObjectWriter(Is64Bit,
483  CPUType,
484  CPUSubtype),
485  OS, /*IsLittleEndian=*/true);
486 }
Instances of this class represent a uniqued identifier for a section in the current translation unit...
Definition: MCSection.h:40
const MCSymbol & getSymbol() const
Definition: MCExpr.h:311
SMLoc getLoc() const
Definition: MCFixup.h:112
bool doesSymbolRequireExternRelocation(const MCSymbol &S)
LLVM_ATTRIBUTE_NORETURN void report_fatal_error(Error Err, bool gen_crash_diag=true)
Report a serious error, calling any installed error handler.
This represents an "assembler immediate".
Definition: MCValue.h:40
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
bool getSymbolOffset(const MCSymbol &S, uint64_t &Val) const
Get the offset of the given symbol, as computed in the current layout.
Definition: MCFragment.cpp:130
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:258
Defines the object file and target independent interfaces used by the assembler backend to write nati...
Encode information on a single operation to perform on a byte sequence (e.g., an encoded instruction)...
Definition: MCFixup.h:66
Encapsulates the layout of an assembly file at a particular point in time.
Definition: MCAsmLayout.h:29
Represent a reference to a symbol from inside an expression.
Definition: MCExpr.h:161
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:52
static GCRegistry::Add< OcamlGC > B("ocaml","ocaml 3.10-compatible GC")
bool isThumbFunc(const MCSymbol *Func) const
Check whether a given symbol has been flagged with .thumb_func.
uint32_t getOffset() const
Definition: MCFixup.h:95
SectionAddrMap & getSectionAddressMap()
INITIALIZE_PASS(HexagonEarlyIfConversion,"hexagon-eif","Hexagon early if conversion", false, false) bool HexagonEarlyIfConversion MachineBasicBlock * SB
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)
uint32_t Offset
void reportError(SMLoc L, const Twine &Msg)
Definition: MCContext.cpp:510
unsigned getOrdinal() const
Definition: MCSection.h:120
MCFixupKind getKind() const
Definition: MCFixup.h:93
const MCSymbolRefExpr * getSymB() const
Definition: MCValue.h:48
A one-byte fixup.
Definition: MCFixup.h:24
const MCSymbolRefExpr * getSymA() const
Definition: MCValue.h:47
CPUType
These values correspond to the CV_CPU_TYPE_e enumeration, and are documented here: https://msdn...
Definition: CodeView.h:73
MCSection * getParent() const
Definition: MCFragment.h:97
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:513
Target - Wrapper for Target specific information.
const MCExpr * getVariableValue(bool SetUsed=true) const
getVariableValue - Get the value for variable symbols.
Definition: MCSymbol.h:294
MCObjectWriter * createMachObjectWriter(MCMachObjectTargetWriter *MOTW, raw_pwrite_stream &OS, bool IsLittleEndian)
Construct a new Mach-O writer instance.
MCSection & getSection(bool SetUsed=true) const
Get the section associated with a defined, non-absolute symbol.
Definition: MCSymbol.h:264
StringRef getName() const
getName - Get the symbol name.
Definition: MCSymbol.h:199
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.
Definition: MCFragment.cpp:78
bool isVariable() const
isVariable - Check if this is a variable symbol.
Definition: MCSymbol.h:289
MCFragment * getFragment(bool SetUsed=true) const
Definition: MCSymbol.h:377
An abstract base class for streams implementations that also support a pwrite operation.
Definition: raw_ostream.h:333
const unsigned Kind
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
int64_t getConstant() const
Definition: MCValue.h:46
LLVM Value Representation.
Definition: Value.h:71
#define LLVM_FALLTHROUGH
LLVM_FALLTHROUGH - Mark fallthrough cases in switch statements.
Definition: Compiler.h:239
uint64_t getSymbolAddress(const MCSymbol &S, const MCAsmLayout &Layout) const
static GCRegistry::Add< ErlangGC > A("erlang","erlang-compatible garbage collector")
A two-byte fixup.
Definition: MCFixup.h:25
bool isUndefined(bool SetUsed=true) const
isUndefined - Check if this symbol undefined (i.e., implicitly defined).
Definition: MCSymbol.h:256