LLVM  4.0.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  return false;
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().reportError(Fixup.getLoc(),
95  "ADR/ADRP relocations must be GOT relative");
96  return false;
97  }
100  return true;
103  return true;
106  return true;
107  }
108  return true;
111  Log2Size = llvm::Log2_32(4);
113  return true;
114  }
115 }
116 
118  const MCSymbol &Symbol, unsigned Log2Size) {
119  // Debug info sections can use local relocations.
120  if (Section.hasAttribute(MachO::S_ATTR_DEBUG))
121  return true;
122 
123  // Otherwise, only pointer sized relocations are supported.
124  if (Log2Size != 3)
125  return false;
126 
127  // But only if they don't point to a few forbidden sections.
128  if (!Symbol.isInSection())
129  return true;
130  const MCSectionMachO &RefSec = cast<MCSectionMachO>(Symbol.getSection());
131  if (RefSec.getType() == MachO::S_CSTRING_LITERALS)
132  return false;
133 
134  if (RefSec.getSegmentName() == "__DATA" &&
135  RefSec.getSectionName() == "__objc_classrefs")
136  return false;
137 
138  // FIXME: ld64 currently handles internal pointer-sized relocations
139  // incorrectly (applying the addend twice). We should be able to return true
140  // unconditionally by this point when that's fixed.
141  return false;
142 }
143 
144 void AArch64MachObjectWriter::recordRelocation(
145  MachObjectWriter *Writer, MCAssembler &Asm, const MCAsmLayout &Layout,
146  const MCFragment *Fragment, const MCFixup &Fixup, MCValue Target,
147  uint64_t &FixedValue) {
148  unsigned IsPCRel = Writer->isFixupKindPCRel(Asm, Fixup.getKind());
149 
150  // See <reloc.h>.
151  uint32_t FixupOffset = Layout.getFragmentOffset(Fragment);
152  unsigned Log2Size = 0;
153  int64_t Value = 0;
154  unsigned Index = 0;
155  unsigned Type = 0;
156  unsigned Kind = Fixup.getKind();
157  const MCSymbol *RelSymbol = nullptr;
158 
159  FixupOffset += Fixup.getOffset();
160 
161  // AArch64 pcrel relocation addends do not include the section offset.
162  if (IsPCRel)
163  FixedValue += FixupOffset;
164 
165  // ADRP fixups use relocations for the whole symbol value and only
166  // put the addend in the instruction itself. Clear out any value the
167  // generic code figured out from the sybmol definition.
169  FixedValue = 0;
170 
171  // imm19 relocations are for conditional branches, which require
172  // assembler local symbols. If we got here, that's not what we have,
173  // so complain loudly.
175  Asm.getContext().reportError(Fixup.getLoc(),
176  "conditional branch requires assembler-local"
177  " label. '" +
178  Target.getSymA()->getSymbol().getName() +
179  "' is external.");
180  return;
181  }
182 
183  // 14-bit branch relocations should only target internal labels, and so
184  // should never get here.
186  Asm.getContext().reportError(Fixup.getLoc(),
187  "Invalid relocation on conditional branch!");
188  return;
189  }
190 
191  if (!getAArch64FixupKindMachOInfo(Fixup, Type, Target.getSymA(), Log2Size,
192  Asm)) {
193  Asm.getContext().reportError(Fixup.getLoc(), "unknown AArch64 fixup kind!");
194  return;
195  }
196 
197  Value = Target.getConstant();
198 
199  if (Target.isAbsolute()) { // constant
200  // FIXME: Should this always be extern?
201  // SymbolNum of 0 indicates the absolute section.
203 
204  if (IsPCRel) {
205  Asm.getContext().reportError(Fixup.getLoc(),
206  "PC relative absolute relocation!");
207  return;
208 
209  // FIXME: x86_64 sets the type to a branch reloc here. Should we do
210  // something similar?
211  }
212  } else if (Target.getSymB()) { // A - B + constant
213  const MCSymbol *A = &Target.getSymA()->getSymbol();
214  const MCSymbol *A_Base = Asm.getAtom(*A);
215 
216  const MCSymbol *B = &Target.getSymB()->getSymbol();
217  const MCSymbol *B_Base = Asm.getAtom(*B);
218 
219  // Check for "_foo@got - .", which comes through here as:
220  // Ltmp0:
221  // ... _foo@got - Ltmp0
222  if (Target.getSymA()->getKind() == MCSymbolRefExpr::VK_GOT &&
223  Target.getSymB()->getKind() == MCSymbolRefExpr::VK_None &&
224  Layout.getSymbolOffset(*B) ==
225  Layout.getFragmentOffset(Fragment) + Fixup.getOffset()) {
226  // SymB is the PC, so use a PC-rel pointer-to-GOT relocation.
228  IsPCRel = 1;
230  MRE.r_word0 = FixupOffset;
231  MRE.r_word1 = (IsPCRel << 24) | (Log2Size << 25) | (Type << 28);
232  Writer->addRelocation(A_Base, Fragment->getParent(), MRE);
233  return;
234  } else if (Target.getSymA()->getKind() != MCSymbolRefExpr::VK_None ||
235  Target.getSymB()->getKind() != MCSymbolRefExpr::VK_None) {
236  // Otherwise, neither symbol can be modified.
237  Asm.getContext().reportError(Fixup.getLoc(),
238  "unsupported relocation of modified symbol");
239  return;
240  }
241 
242  // We don't support PCrel relocations of differences.
243  if (IsPCRel) {
244  Asm.getContext().reportError(Fixup.getLoc(),
245  "unsupported pc-relative relocation of "
246  "difference");
247  return;
248  }
249 
250  // AArch64 always uses external relocations. If there is no symbol to use as
251  // a base address (a local symbol with no preceding non-local symbol),
252  // error out.
253  //
254  // FIXME: We should probably just synthesize an external symbol and use
255  // that.
256  if (!A_Base) {
257  Asm.getContext().reportError(
258  Fixup.getLoc(),
259  "unsupported relocation of local symbol '" + A->getName() +
260  "'. Must have non-local symbol earlier in section.");
261  return;
262  }
263  if (!B_Base) {
264  Asm.getContext().reportError(
265  Fixup.getLoc(),
266  "unsupported relocation of local symbol '" + B->getName() +
267  "'. Must have non-local symbol earlier in section.");
268  return;
269  }
270 
271  if (A_Base == B_Base && A_Base) {
272  Asm.getContext().reportError(
273  Fixup.getLoc(), "unsupported relocation with identical base");
274  return;
275  }
276 
277  Value += (!A->getFragment() ? 0 : Writer->getSymbolAddress(*A, Layout)) -
278  (!A_Base || !A_Base->getFragment() ? 0 : Writer->getSymbolAddress(
279  *A_Base, Layout));
280  Value -= (!B->getFragment() ? 0 : Writer->getSymbolAddress(*B, Layout)) -
281  (!B_Base || !B_Base->getFragment() ? 0 : Writer->getSymbolAddress(
282  *B_Base, Layout));
283 
285 
287  MRE.r_word0 = FixupOffset;
288  MRE.r_word1 = (IsPCRel << 24) | (Log2Size << 25) | (Type << 28);
289  Writer->addRelocation(A_Base, Fragment->getParent(), MRE);
290 
291  RelSymbol = B_Base;
293  } else { // A + constant
294  const MCSymbol *Symbol = &Target.getSymA()->getSymbol();
295  const MCSectionMachO &Section =
296  static_cast<const MCSectionMachO &>(*Fragment->getParent());
297 
298  bool CanUseLocalRelocation =
299  canUseLocalRelocation(Section, *Symbol, Log2Size);
300  if (Symbol->isTemporary() && (Value || !CanUseLocalRelocation)) {
301  const MCSection &Sec = Symbol->getSection();
303  Symbol->setUsedInReloc();
304  }
305 
306  const MCSymbol *Base = Asm.getAtom(*Symbol);
307 
308  // If the symbol is a variable and we weren't able to get a Base for it
309  // (i.e., it's not in the symbol table associated with a section) resolve
310  // the relocation based its expansion instead.
311  if (Symbol->isVariable() && !Base) {
312  // If the evaluation is an absolute value, just use that directly
313  // to keep things easy.
314  int64_t Res;
315  if (Symbol->getVariableValue()->evaluateAsAbsolute(
316  Res, Layout, Writer->getSectionAddressMap())) {
317  FixedValue = Res;
318  return;
319  }
320 
321  // FIXME: Will the Target we already have ever have any data in it
322  // we need to preserve and merge with the new Target? How about
323  // the FixedValue?
324  if (!Symbol->getVariableValue()->evaluateAsRelocatable(Target, &Layout,
325  &Fixup)) {
326  Asm.getContext().reportError(Fixup.getLoc(),
327  "unable to resolve variable '" +
328  Symbol->getName() + "'");
329  return;
330  }
331  return recordRelocation(Writer, Asm, Layout, Fragment, Fixup, Target,
332  FixedValue);
333  }
334 
335  // Relocations inside debug sections always use local relocations when
336  // possible. This seems to be done because the debugger doesn't fully
337  // understand relocation entries and expects to find values that
338  // have already been fixed up.
339  if (Symbol->isInSection()) {
340  if (Section.hasAttribute(MachO::S_ATTR_DEBUG))
341  Base = nullptr;
342  }
343 
344  // AArch64 uses external relocations as much as possible. For debug
345  // sections, and for pointer-sized relocations (.quad), we allow section
346  // relocations. It's code sections that run into trouble.
347  if (Base) {
348  RelSymbol = Base;
349 
350  // Add the local offset, if needed.
351  if (Base != Symbol)
352  Value +=
353  Layout.getSymbolOffset(*Symbol) - Layout.getSymbolOffset(*Base);
354  } else if (Symbol->isInSection()) {
355  if (!CanUseLocalRelocation) {
356  Asm.getContext().reportError(
357  Fixup.getLoc(),
358  "unsupported relocation of local symbol '" + Symbol->getName() +
359  "'. Must have non-local symbol earlier in section.");
360  return;
361  }
362  // Adjust the relocation to be section-relative.
363  // The index is the section ordinal (1-based).
364  const MCSection &Sec = Symbol->getSection();
365  Index = Sec.getOrdinal() + 1;
366  Value += Writer->getSymbolAddress(*Symbol, Layout);
367 
368  if (IsPCRel)
369  Value -= Writer->getFragmentAddress(Fragment, Layout) +
370  Fixup.getOffset() + (1ULL << Log2Size);
371  } else {
372  // Resolve constant variables.
373  if (Symbol->isVariable()) {
374  int64_t Res;
375  if (Symbol->getVariableValue()->evaluateAsAbsolute(
376  Res, Layout, Writer->getSectionAddressMap())) {
377  FixedValue = Res;
378  return;
379  }
380  }
381  Asm.getContext().reportError(Fixup.getLoc(),
382  "unsupported relocation of variable '" +
383  Symbol->getName() + "'");
384  return;
385  }
386  }
387 
388  // If the relocation kind is Branch26, Page21, or Pageoff12, any addend
389  // is represented via an Addend relocation, not encoded directly into
390  // the instruction.
391  if ((Type == MachO::ARM64_RELOC_BRANCH26 ||
392  Type == MachO::ARM64_RELOC_PAGE21 ||
393  Type == MachO::ARM64_RELOC_PAGEOFF12) &&
394  Value) {
395  assert((Value & 0xff000000) == 0 && "Added relocation out of range!");
396 
398  MRE.r_word0 = FixupOffset;
399  MRE.r_word1 =
400  (Index << 0) | (IsPCRel << 24) | (Log2Size << 25) | (Type << 28);
401  Writer->addRelocation(RelSymbol, Fragment->getParent(), MRE);
402 
403  // Now set up the Addend relocation.
405  Index = Value;
406  RelSymbol = nullptr;
407  IsPCRel = 0;
408  Log2Size = 2;
409 
410  // Put zero into the instruction itself. The addend is in the relocation.
411  Value = 0;
412  }
413 
414  // If there's any addend left to handle, encode it in the instruction.
415  FixedValue = Value;
416 
417  // struct relocation_info (8 bytes)
419  MRE.r_word0 = FixupOffset;
420  MRE.r_word1 =
421  (Index << 0) | (IsPCRel << 24) | (Log2Size << 25) | (Type << 28);
422  Writer->addRelocation(RelSymbol, Fragment->getParent(), MRE);
423 }
424 
427  uint32_t CPUSubtype) {
428  return createMachObjectWriter(
429  new AArch64MachObjectWriter(CPUType, CPUSubtype), OS,
430  /*IsLittleEndian=*/true);
431 }
Instances of this class represent a uniqued identifier for a section in the current translation unit...
Definition: MCSection.h:40
const MCAsmInfo * getAsmInfo() const
Definition: MCContext.h:243
This represents a section on a Mach-O system (used by Mac OS X).
const MCSymbol & getSymbol() const
Definition: MCExpr.h:311
SMLoc getLoc() const
Definition: MCFixup.h:112
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
S_ATTR_DEBUG - A debug section.
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.
Definition: MCFragment.cpp:130
virtual bool isSectionAtomizableBySymbols(const MCSection &Section) const
True if the section is atomized using the symbols in it.
Definition: MCAsmInfo.cpp:117
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)
StringRef getSectionName() const
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")
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:95
SectionAddrMap & getSectionAddressMap()
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:209
void reportError(SMLoc L, const Twine &Msg)
Definition: MCContext.cpp:510
unsigned getOrdinal() const
Definition: MCSection.h:120
MCObjectWriter * createAArch64MachObjectWriter(raw_pwrite_stream &OS, uint32_t CPUType, uint32_t CPUSubtype)
bool isInSection(bool SetUsed=true) const
isInSection - Check if this symbol is defined in some section (i.e., it is defined but not absolute)...
Definition: MCSymbol.h:251
S_CSTRING_LITERALS - Section with literal C strings.
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
MachO::SectionType getType() const
uint64_t getFragmentAddress(const MCFragment *Fragment, const MCAsmLayout &Layout) const
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
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:581
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.
bool isTemporary() const
isTemporary - Check if this is an assembler temporary symbol.
Definition: MCSymbol.h:216
StringRef getSegmentName() const
MCSection & getSection(bool SetUsed=true) const
Get the section associated with a defined, non-absolute symbol.
Definition: MCSymbol.h:264
Basic Alias true
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
VariantKind getKind() const
Definition: MCExpr.h:313
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
int64_t getConstant() const
Definition: MCValue.h:46
LLVM Value Representation.
Definition: Value.h:71
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