LLVM  3.7.0
AArch64MachObjectWriter.cpp
Go to the documentation of this file.
1 //===-- AArch64MachObjectWriter.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 
12 #include "llvm/ADT/Twine.h"
13 #include "llvm/MC/MCAsmInfo.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"
20 #include "llvm/MC/MCSectionMachO.h"
21 #include "llvm/MC/MCValue.h"
23 #include "llvm/Support/MachO.h"
24 using namespace llvm;
25 
26 namespace {
27 class AArch64MachObjectWriter : public MCMachObjectTargetWriter {
28  bool getAArch64FixupKindMachOInfo(const MCFixup &Fixup, unsigned &RelocType,
29  const MCSymbolRefExpr *Sym,
30  unsigned &Log2Size, const MCAssembler &Asm);
31 
32 public:
33  AArch64MachObjectWriter(uint32_t CPUType, uint32_t CPUSubtype)
34  : MCMachObjectTargetWriter(true /* is64Bit */, CPUType, CPUSubtype) {}
35 
36  void recordRelocation(MachObjectWriter *Writer, MCAssembler &Asm,
37  const MCAsmLayout &Layout, const MCFragment *Fragment,
38  const MCFixup &Fixup, MCValue Target,
39  uint64_t &FixedValue) override;
40 };
41 }
42 
43 bool AArch64MachObjectWriter::getAArch64FixupKindMachOInfo(
44  const MCFixup &Fixup, unsigned &RelocType, const MCSymbolRefExpr *Sym,
45  unsigned &Log2Size, const MCAssembler &Asm) {
47  Log2Size = ~0U;
48 
49  switch ((unsigned)Fixup.getKind()) {
50  default:
51  return false;
52 
53  case FK_Data_1:
54  Log2Size = llvm::Log2_32(1);
55  return true;
56  case FK_Data_2:
57  Log2Size = llvm::Log2_32(2);
58  return true;
59  case FK_Data_4:
60  Log2Size = llvm::Log2_32(4);
61  if (Sym->getKind() == MCSymbolRefExpr::VK_GOT)
62  RelocType = unsigned(MachO::ARM64_RELOC_POINTER_TO_GOT);
63  return true;
64  case FK_Data_8:
65  Log2Size = llvm::Log2_32(8);
66  if (Sym->getKind() == MCSymbolRefExpr::VK_GOT)
67  RelocType = unsigned(MachO::ARM64_RELOC_POINTER_TO_GOT);
68  return true;
75  Log2Size = llvm::Log2_32(4);
76  switch (Sym->getKind()) {
77  default:
78  llvm_unreachable("Unexpected symbol reference variant kind!");
81  return true;
84  return true;
87  return true;
88  }
90  Log2Size = llvm::Log2_32(4);
91  // This encompasses the relocation for the whole 21-bit value.
92  switch (Sym->getKind()) {
93  default:
94  Asm.getContext().reportFatalError(Fixup.getLoc(),
95  "ADR/ADRP relocations must be GOT relative");
98  return true;
101  return true;
104  return true;
105  }
106  return true;
109  Log2Size = llvm::Log2_32(4);
111  return true;
112  }
113 }
114 
116  const MCSymbol &Symbol, unsigned Log2Size) {
117  // Debug info sections can use local relocations.
118  if (Section.hasAttribute(MachO::S_ATTR_DEBUG))
119  return true;
120 
121  // Otherwise, only pointer sized relocations are supported.
122  if (Log2Size != 3)
123  return false;
124 
125  // But only if they don't point to a few forbidden sections.
126  if (!Symbol.isInSection())
127  return true;
128  const MCSectionMachO &RefSec = cast<MCSectionMachO>(Symbol.getSection());
129  if (RefSec.getType() == MachO::S_CSTRING_LITERALS)
130  return false;
131 
132  if (RefSec.getSegmentName() == "__DATA" &&
133  RefSec.getSectionName() == "__objc_classrefs")
134  return false;
135 
136  // FIXME: ld64 currently handles internal pointer-sized relocations
137  // incorrectly (applying the addend twice). We should be able to return true
138  // unconditionally by this point when that's fixed.
139  return false;
140 }
141 
142 void AArch64MachObjectWriter::recordRelocation(
143  MachObjectWriter *Writer, MCAssembler &Asm, const MCAsmLayout &Layout,
144  const MCFragment *Fragment, const MCFixup &Fixup, MCValue Target,
145  uint64_t &FixedValue) {
146  unsigned IsPCRel = Writer->isFixupKindPCRel(Asm, Fixup.getKind());
147 
148  // See <reloc.h>.
149  uint32_t FixupOffset = Layout.getFragmentOffset(Fragment);
150  unsigned Log2Size = 0;
151  int64_t Value = 0;
152  unsigned Index = 0;
153  unsigned Type = 0;
154  unsigned Kind = Fixup.getKind();
155  const MCSymbol *RelSymbol = nullptr;
156 
157  FixupOffset += Fixup.getOffset();
158 
159  // AArch64 pcrel relocation addends do not include the section offset.
160  if (IsPCRel)
161  FixedValue += FixupOffset;
162 
163  // ADRP fixups use relocations for the whole symbol value and only
164  // put the addend in the instruction itself. Clear out any value the
165  // generic code figured out from the sybmol definition.
167  FixedValue = 0;
168 
169  // imm19 relocations are for conditional branches, which require
170  // assembler local symbols. If we got here, that's not what we have,
171  // so complain loudly.
173  Asm.getContext().reportFatalError(Fixup.getLoc(),
174  "conditional branch requires assembler-local"
175  " label. '" +
176  Target.getSymA()->getSymbol().getName() +
177  "' is external.");
178  return;
179  }
180 
181  // 14-bit branch relocations should only target internal labels, and so
182  // should never get here.
184  Asm.getContext().reportFatalError(Fixup.getLoc(),
185  "Invalid relocation on conditional branch!");
186  return;
187  }
188 
189  if (!getAArch64FixupKindMachOInfo(Fixup, Type, Target.getSymA(), Log2Size,
190  Asm)) {
191  Asm.getContext().reportFatalError(Fixup.getLoc(), "unknown AArch64 fixup kind!");
192  return;
193  }
194 
195  Value = Target.getConstant();
196 
197  if (Target.isAbsolute()) { // constant
198  // FIXME: Should this always be extern?
199  // SymbolNum of 0 indicates the absolute section.
201 
202  if (IsPCRel) {
203  Asm.getContext().reportFatalError(Fixup.getLoc(),
204  "PC relative absolute relocation!");
205 
206  // FIXME: x86_64 sets the type to a branch reloc here. Should we do
207  // something similar?
208  }
209  } else if (Target.getSymB()) { // A - B + constant
210  const MCSymbol *A = &Target.getSymA()->getSymbol();
211  const MCSymbol *A_Base = Asm.getAtom(*A);
212 
213  const MCSymbol *B = &Target.getSymB()->getSymbol();
214  const MCSymbol *B_Base = Asm.getAtom(*B);
215 
216  // Check for "_foo@got - .", which comes through here as:
217  // Ltmp0:
218  // ... _foo@got - Ltmp0
219  if (Target.getSymA()->getKind() == MCSymbolRefExpr::VK_GOT &&
220  Target.getSymB()->getKind() == MCSymbolRefExpr::VK_None &&
221  Layout.getSymbolOffset(*B) ==
222  Layout.getFragmentOffset(Fragment) + Fixup.getOffset()) {
223  // SymB is the PC, so use a PC-rel pointer-to-GOT relocation.
225  IsPCRel = 1;
227  MRE.r_word0 = FixupOffset;
228  MRE.r_word1 = (IsPCRel << 24) | (Log2Size << 25) | (Type << 28);
229  Writer->addRelocation(A_Base, Fragment->getParent(), MRE);
230  return;
231  } else if (Target.getSymA()->getKind() != MCSymbolRefExpr::VK_None ||
233  // Otherwise, neither symbol can be modified.
234  Asm.getContext().reportFatalError(Fixup.getLoc(),
235  "unsupported relocation of modified symbol");
236 
237  // We don't support PCrel relocations of differences.
238  if (IsPCRel)
239  Asm.getContext().reportFatalError(Fixup.getLoc(),
240  "unsupported pc-relative relocation of "
241  "difference");
242 
243  // AArch64 always uses external relocations. If there is no symbol to use as
244  // a base address (a local symbol with no preceding non-local symbol),
245  // error out.
246  //
247  // FIXME: We should probably just synthesize an external symbol and use
248  // that.
249  if (!A_Base)
251  Fixup.getLoc(),
252  "unsupported relocation of local symbol '" + A->getName() +
253  "'. Must have non-local symbol earlier in section.");
254  if (!B_Base)
256  Fixup.getLoc(),
257  "unsupported relocation of local symbol '" + B->getName() +
258  "'. Must have non-local symbol earlier in section.");
259 
260  if (A_Base == B_Base && A_Base)
261  Asm.getContext().reportFatalError(Fixup.getLoc(),
262  "unsupported relocation with identical base");
263 
264  Value += (!A->getFragment() ? 0 : Writer->getSymbolAddress(*A, Layout)) -
265  (!A_Base || !A_Base->getFragment() ? 0 : Writer->getSymbolAddress(
266  *A_Base, Layout));
267  Value -= (!B->getFragment() ? 0 : Writer->getSymbolAddress(*B, Layout)) -
268  (!B_Base || !B_Base->getFragment() ? 0 : Writer->getSymbolAddress(
269  *B_Base, Layout));
270 
272 
274  MRE.r_word0 = FixupOffset;
275  MRE.r_word1 = (IsPCRel << 24) | (Log2Size << 25) | (Type << 28);
276  Writer->addRelocation(A_Base, Fragment->getParent(), MRE);
277 
278  RelSymbol = B_Base;
280  } else { // A + constant
281  const MCSymbol *Symbol = &Target.getSymA()->getSymbol();
282  const MCSectionMachO &Section =
283  static_cast<const MCSectionMachO &>(*Fragment->getParent());
284 
285  bool CanUseLocalRelocation =
286  canUseLocalRelocation(Section, *Symbol, Log2Size);
287  if (Symbol->isTemporary() && (Value || !CanUseLocalRelocation)) {
288  const MCSection &Sec = Symbol->getSection();
290  Symbol->setUsedInReloc();
291  }
292 
293  const MCSymbol *Base = Asm.getAtom(*Symbol);
294 
295  // If the symbol is a variable and we weren't able to get a Base for it
296  // (i.e., it's not in the symbol table associated with a section) resolve
297  // the relocation based its expansion instead.
298  if (Symbol->isVariable() && !Base) {
299  // If the evaluation is an absolute value, just use that directly
300  // to keep things easy.
301  int64_t Res;
302  if (Symbol->getVariableValue()->evaluateAsAbsolute(
303  Res, Layout, Writer->getSectionAddressMap())) {
304  FixedValue = Res;
305  return;
306  }
307 
308  // FIXME: Will the Target we already have ever have any data in it
309  // we need to preserve and merge with the new Target? How about
310  // the FixedValue?
311  if (!Symbol->getVariableValue()->evaluateAsRelocatable(Target, &Layout,
312  &Fixup))
313  Asm.getContext().reportFatalError(Fixup.getLoc(),
314  "unable to resolve variable '" +
315  Symbol->getName() + "'");
316  return recordRelocation(Writer, Asm, Layout, Fragment, Fixup, Target,
317  FixedValue);
318  }
319 
320  // Relocations inside debug sections always use local relocations when
321  // possible. This seems to be done because the debugger doesn't fully
322  // understand relocation entries and expects to find values that
323  // have already been fixed up.
324  if (Symbol->isInSection()) {
325  if (Section.hasAttribute(MachO::S_ATTR_DEBUG))
326  Base = nullptr;
327  }
328 
329  // AArch64 uses external relocations as much as possible. For debug
330  // sections, and for pointer-sized relocations (.quad), we allow section
331  // relocations. It's code sections that run into trouble.
332  if (Base) {
333  RelSymbol = Base;
334 
335  // Add the local offset, if needed.
336  if (Base != Symbol)
337  Value +=
338  Layout.getSymbolOffset(*Symbol) - Layout.getSymbolOffset(*Base);
339  } else if (Symbol->isInSection()) {
340  if (!CanUseLocalRelocation)
342  Fixup.getLoc(),
343  "unsupported relocation of local symbol '" + Symbol->getName() +
344  "'. Must have non-local symbol earlier in section.");
345  // Adjust the relocation to be section-relative.
346  // The index is the section ordinal (1-based).
347  const MCSection &Sec = Symbol->getSection();
348  Index = Sec.getOrdinal() + 1;
349  Value += Writer->getSymbolAddress(*Symbol, Layout);
350 
351  if (IsPCRel)
352  Value -= Writer->getFragmentAddress(Fragment, Layout) +
353  Fixup.getOffset() + (1ULL << Log2Size);
354  } else {
355  // Resolve constant variables.
356  if (Symbol->isVariable()) {
357  int64_t Res;
358  if (Symbol->getVariableValue()->evaluateAsAbsolute(
359  Res, Layout, Writer->getSectionAddressMap())) {
360  FixedValue = Res;
361  return;
362  }
363  }
364  Asm.getContext().reportFatalError(Fixup.getLoc(),
365  "unsupported relocation of variable '" +
366  Symbol->getName() + "'");
367  }
368  }
369 
370  // If the relocation kind is Branch26, Page21, or Pageoff12, any addend
371  // is represented via an Addend relocation, not encoded directly into
372  // the instruction.
373  if ((Type == MachO::ARM64_RELOC_BRANCH26 ||
374  Type == MachO::ARM64_RELOC_PAGE21 ||
375  Type == MachO::ARM64_RELOC_PAGEOFF12) &&
376  Value) {
377  assert((Value & 0xff000000) == 0 && "Added relocation out of range!");
378 
380  MRE.r_word0 = FixupOffset;
381  MRE.r_word1 =
382  (Index << 0) | (IsPCRel << 24) | (Log2Size << 25) | (Type << 28);
383  Writer->addRelocation(RelSymbol, Fragment->getParent(), MRE);
384 
385  // Now set up the Addend relocation.
387  Index = Value;
388  RelSymbol = nullptr;
389  IsPCRel = 0;
390  Log2Size = 2;
391 
392  // Put zero into the instruction itself. The addend is in the relocation.
393  Value = 0;
394  }
395 
396  // If there's any addend left to handle, encode it in the instruction.
397  FixedValue = Value;
398 
399  // struct relocation_info (8 bytes)
401  MRE.r_word0 = FixupOffset;
402  MRE.r_word1 =
403  (Index << 0) | (IsPCRel << 24) | (Log2Size << 25) | (Type << 28);
404  Writer->addRelocation(RelSymbol, Fragment->getParent(), MRE);
405 }
406 
408  uint32_t CPUType,
409  uint32_t CPUSubtype) {
410  return createMachObjectWriter(
411  new AArch64MachObjectWriter(CPUType, CPUSubtype), OS,
412  /*IsLittleEndian=*/true);
413 }
Instances of this class represent a uniqued identifier for a section in the current translation unit...
Definition: MCSection.h:48
const MCAsmInfo * getAsmInfo() const
Definition: MCContext.h:225
MCSectionMachO - This represents a section on a Mach-O system (used by Mac OS X). ...
const MCSymbol & getSymbol() const
Definition: MCExpr.h:328
SMLoc getLoc() const
Definition: MCFixup.h:108
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
LLVM_ATTRIBUTE_NORETURN void reportFatalError(SMLoc L, const Twine &Msg) const
Definition: MCContext.cpp:474
static bool canUseLocalRelocation(const MCSectionMachO &Section, const MCSymbol &Symbol, unsigned Log2Size)
bool getSymbolOffset(const MCSymbol &S, uint64_t &Val) const
Get the offset of the given symbol, as computed in the current layout.
virtual bool isSectionAtomizableBySymbols(const MCSection &Section) const
True if the section is atomized using the symbols in it.
Definition: MCAsmInfo.cpp:116
MCContext & getContext() const
Definition: MCAssembler.h:731
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:62
Encapsulates the layout of an assembly file at a particular point in time.
Definition: MCAsmLayout.h:29
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
Definition: ErrorHandling.h:98
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 isInSection() const
isInSection - Check if this symbol is defined in some section (i.e., it is defined but not absolute)...
Definition: MCSymbol.h:255
bool isFixupKindPCRel(const MCAssembler &Asm, unsigned Kind)
void addRelocation(const MCSymbol *RelSymbol, const MCSection *Sec, MachO::any_relocation_info &MRE)
StringRef getSectionName() const
bool isAbsolute() const
Is this an absolute (as opposed to relocatable) value.
Definition: MCValue.h:56
const MCSymbol * getAtom(const MCSymbol &S) const
Find the symbol which defines the atom containing the given symbol, or null if there is no such symbo...
uint32_t getOffset() const
Definition: MCFixup.h:91
SectionAddrMap & getSectionAddressMap()
#define true
Definition: ConvertUTF.c:66
The instances of the Type class are immutable: once they are created, they are never changed...
Definition: Type.h:45
bool hasAttribute(unsigned Value) const
void setUsedInReloc() const
Definition: MCSymbol.h:215
MCFragment * getFragment() const
Definition: MCSymbol.h:382
unsigned getOrdinal() const
Definition: MCSection.h:127
MCObjectWriter * createAArch64MachObjectWriter(raw_pwrite_stream &OS, uint32_t CPUType, uint32_t CPUSubtype)
S_CSTRING_LITERALS - Section with literal C strings.
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
MachO::SectionType getType() const
uint64_t getFragmentAddress(const MCFragment *Fragment, const MCAsmLayout &Layout) const
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
bool evaluateAsRelocatable(MCValue &Res, const MCAsmLayout *Layout, const MCFixup *Fixup) const
Try to evaluate the expression to a relocatable value, i.e.
Definition: MCExpr.cpp:595
Target - Wrapper for Target specific information.
MCObjectWriter * createMachObjectWriter(MCMachObjectTargetWriter *MOTW, raw_pwrite_stream &OS, bool IsLittleEndian)
Construct a new Mach-O writer instance.
bool isTemporary() const
isTemporary - Check if this is an assembler temporary symbol.
Definition: MCSymbol.h:222
StringRef getSegmentName() const
StringRef getName() const
getName - Get the symbol name.
Definition: MCSymbol.h:205
S_ATTR_DEBUG - A debug section.
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
VariantKind getKind() const
Definition: MCExpr.h:330
int64_t getConstant() const
Definition: MCValue.h:50
const ARM::ArchExtKind Kind
LLVM Value Representation.
Definition: Value.h:69
uint64_t getSymbolAddress(const MCSymbol &S, const MCAsmLayout &Layout) const
A two-byte fixup.
Definition: MCFixup.h:25