LLVM API Documentation

 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
PPCMachObjectWriter.cpp
Go to the documentation of this file.
1 //===-- PPCMachObjectWriter.cpp - PPC Mach-O 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/MCAsmLayout.h"
14 #include "llvm/MC/MCAssembler.h"
15 #include "llvm/MC/MCContext.h"
17 #include "llvm/MC/MCSectionMachO.h"
18 #include "llvm/MC/MCValue.h"
20 #include "llvm/Support/Format.h"
21 #include "llvm/Support/MachO.h"
22 
23 using namespace llvm;
24 
25 namespace {
26 class PPCMachObjectWriter : public MCMachObjectTargetWriter {
27  bool RecordScatteredRelocation(MachObjectWriter *Writer,
28  const MCAssembler &Asm,
29  const MCAsmLayout &Layout,
30  const MCFragment *Fragment,
31  const MCFixup &Fixup, MCValue Target,
32  unsigned Log2Size, uint64_t &FixedValue);
33 
34  void RecordPPCRelocation(MachObjectWriter *Writer, const MCAssembler &Asm,
35  const MCAsmLayout &Layout,
36  const MCFragment *Fragment, const MCFixup &Fixup,
37  MCValue Target, uint64_t &FixedValue);
38 
39 public:
40  PPCMachObjectWriter(bool Is64Bit, uint32_t CPUType, uint32_t CPUSubtype)
41  : MCMachObjectTargetWriter(Is64Bit, CPUType, CPUSubtype,
42  /*UseAggressiveSymbolFolding=*/Is64Bit) {}
43 
44  void RecordRelocation(MachObjectWriter *Writer, const MCAssembler &Asm,
45  const MCAsmLayout &Layout, const MCFragment *Fragment,
46  const MCFixup &Fixup, MCValue Target,
47  uint64_t &FixedValue) {
48  if (Writer->is64Bit()) {
49  report_fatal_error("Relocation emission for MachO/PPC64 unimplemented.");
50  } else
51  RecordPPCRelocation(Writer, Asm, Layout, Fragment, Fixup, Target,
52  FixedValue);
53  }
54 };
55 }
56 
57 /// computes the log2 of the size of the relocation,
58 /// used for relocation_info::r_length.
59 static unsigned getFixupKindLog2Size(unsigned Kind) {
60  switch (Kind) {
61  default:
62  report_fatal_error("log2size(FixupKind): Unhandled fixup kind!");
63  case FK_PCRel_1:
64  case FK_Data_1:
65  return 0;
66  case FK_PCRel_2:
67  case FK_Data_2:
68  return 1;
69  case FK_PCRel_4:
73  case FK_Data_4:
74  return 2;
75  case FK_PCRel_8:
76  case FK_Data_8:
77  return 3;
78  }
79  return 0;
80 }
81 
82 /// Translates generic PPC fixup kind to Mach-O/PPC relocation type enum.
83 /// Outline based on PPCELFObjectWriter::getRelocTypeInner().
84 static unsigned getRelocType(const MCValue &Target,
85  const MCFixupKind FixupKind, // from
86  // Fixup.getKind()
87  const bool IsPCRel) {
88  const MCSymbolRefExpr::VariantKind Modifier =
90  : Target.getSymA()->getKind();
91  // determine the type of the relocation
93  if (IsPCRel) { // relative to PC
94  switch ((unsigned)FixupKind) {
95  default:
96  report_fatal_error("Unimplemented fixup kind (relative)");
98  Type = MachO::PPC_RELOC_BR24; // R_PPC_REL24
99  break;
101  Type = MachO::PPC_RELOC_BR14;
102  break;
104  switch (Modifier) {
105  default:
106  llvm_unreachable("Unsupported modifier for half16 fixup");
108  Type = MachO::PPC_RELOC_HA16;
109  break;
111  Type = MachO::PPC_RELOC_LO16;
112  break;
114  Type = MachO::PPC_RELOC_HI16;
115  break;
116  }
117  break;
118  }
119  } else {
120  switch ((unsigned)FixupKind) {
121  default:
122  report_fatal_error("Unimplemented fixup kind (absolute)!");
124  switch (Modifier) {
125  default:
126  llvm_unreachable("Unsupported modifier for half16 fixup");
129  break;
132  break;
135  break;
136  }
137  break;
138  case FK_Data_4:
139  break;
140  case FK_Data_2:
141  break;
142  }
143  }
144  return Type;
145 }
146 
148  const uint32_t FixupOffset, const uint32_t Index,
149  const unsigned IsPCRel, const unsigned Log2Size,
150  const unsigned IsExtern, const unsigned Type) {
151  MRE.r_word0 = FixupOffset;
152  // The bitfield offsets that work (as determined by trial-and-error)
153  // are different than what is documented in the mach-o manuals.
154  // This appears to be an endianness issue; reversing the order of the
155  // documented bitfields in <llvm/Support/MachO.h> fixes this (but
156  // breaks x86/ARM assembly).
157  MRE.r_word1 = ((Index << 8) | // was << 0
158  (IsPCRel << 7) | // was << 24
159  (Log2Size << 5) | // was << 25
160  (IsExtern << 4) | // was << 27
161  (Type << 0)); // was << 28
162 }
163 
164 static void
166  const uint32_t Addr, const unsigned Type,
167  const unsigned Log2Size, const unsigned IsPCRel,
168  const uint32_t Value2) {
169  // For notes on bitfield positions and endianness, see:
170  // https://developer.apple.com/library/mac/documentation/developertools/conceptual/MachORuntime/Reference/reference.html#//apple_ref/doc/uid/20001298-scattered_relocation_entry
171  MRE.r_word0 = ((Addr << 0) | (Type << 24) | (Log2Size << 28) |
172  (IsPCRel << 30) | MachO::R_SCATTERED);
173  MRE.r_word1 = Value2;
174 }
175 
176 /// Compute fixup offset (address).
177 static uint32_t getFixupOffset(const MCAsmLayout &Layout,
178  const MCFragment *Fragment,
179  const MCFixup &Fixup) {
180  uint32_t FixupOffset = Layout.getFragmentOffset(Fragment) + Fixup.getOffset();
181  // On Mach-O, ppc_fixup_half16 relocations must refer to the
182  // start of the instruction, not the second halfword, as ELF does
183  if (unsigned(Fixup.getKind()) == PPC::fixup_ppc_half16)
184  FixupOffset &= ~uint32_t(3);
185  return FixupOffset;
186 }
187 
188 /// \return false if falling back to using non-scattered relocation,
189 /// otherwise true for normal scattered relocation.
190 /// based on X86MachObjectWriter::RecordScatteredRelocation
191 /// and ARMMachObjectWriter::RecordScatteredRelocation
192 bool PPCMachObjectWriter::RecordScatteredRelocation(
193  MachObjectWriter *Writer, const MCAssembler &Asm, const MCAsmLayout &Layout,
194  const MCFragment *Fragment, const MCFixup &Fixup, MCValue Target,
195  unsigned Log2Size, uint64_t &FixedValue) {
196  // caller already computes these, can we just pass and reuse?
197  const uint32_t FixupOffset = getFixupOffset(Layout, Fragment, Fixup);
198  const MCFixupKind FK = Fixup.getKind();
199  const unsigned IsPCRel = Writer->isFixupKindPCRel(Asm, FK);
200  const unsigned Type = getRelocType(Target, FK, IsPCRel);
201 
202  // Is this a local or SECTDIFF relocation entry?
203  // SECTDIFF relocation entries have symbol subtractions,
204  // and require two entries, the first for the add-symbol value,
205  // the second for the subtract-symbol value.
206 
207  // See <reloc.h>.
208  const MCSymbol *A = &Target.getSymA()->getSymbol();
209  MCSymbolData *A_SD = &Asm.getSymbolData(*A);
210 
211  if (!A_SD->getFragment())
212  report_fatal_error("symbol '" + A->getName() +
213  "' can not be undefined in a subtraction expression");
214 
215  uint32_t Value = Writer->getSymbolAddress(A_SD, Layout);
216  uint64_t SecAddr =
217  Writer->getSectionAddress(A_SD->getFragment()->getParent());
218  FixedValue += SecAddr;
219  uint32_t Value2 = 0;
220 
221  if (const MCSymbolRefExpr *B = Target.getSymB()) {
222  MCSymbolData *B_SD = &Asm.getSymbolData(B->getSymbol());
223 
224  if (!B_SD->getFragment())
225  report_fatal_error("symbol '" + B->getSymbol().getName() +
226  "' can not be undefined in a subtraction expression");
227 
228  // FIXME: is Type correct? see include/llvm/Support/MachO.h
229  Value2 = Writer->getSymbolAddress(B_SD, Layout);
230  FixedValue -= Writer->getSectionAddress(B_SD->getFragment()->getParent());
231  }
232  // FIXME: does FixedValue get used??
233 
234  // Relocations are written out in reverse order, so the PAIR comes first.
235  if (Type == MachO::PPC_RELOC_SECTDIFF ||
241  // X86 had this piece, but ARM does not
242  // If the offset is too large to fit in a scattered relocation,
243  // we're hosed. It's an unfortunate limitation of the MachO format.
244  if (FixupOffset > 0xffffff) {
245  char Buffer[32];
246  format("0x%x", FixupOffset).print(Buffer, sizeof(Buffer));
247  Asm.getContext().FatalError(Fixup.getLoc(),
248  Twine("Section too large, can't encode "
249  "r_address (") +
250  Buffer + ") into 24 bits of scattered "
251  "relocation entry.");
252  llvm_unreachable("fatal error returned?!");
253  }
254 
255  // Is this supposed to follow MCTarget/PPCAsmBackend.cpp:adjustFixupValue()?
256  // see PPCMCExpr::EvaluateAsRelocatableImpl()
257  uint32_t other_half = 0;
258  switch (Type) {
260  other_half = (FixedValue >> 16) & 0xffff;
261  // applyFixupOffset longer extracts the high part because it now assumes
262  // this was already done.
263  // It looks like this is not true for the FixedValue needed with Mach-O
264  // relocs.
265  // So we need to adjust FixedValue again here.
266  FixedValue &= 0xffff;
267  break;
269  other_half = FixedValue & 0xffff;
270  FixedValue =
271  ((FixedValue >> 16) + ((FixedValue & 0x8000) ? 1 : 0)) & 0xffff;
272  break;
274  other_half = FixedValue & 0xffff;
275  FixedValue = (FixedValue >> 16) & 0xffff;
276  break;
277  default:
278  llvm_unreachable("Invalid PPC scattered relocation type.");
279  break;
280  }
281 
284  Log2Size, IsPCRel, Value2);
285  Writer->addRelocation(Fragment->getParent(), MRE);
286  } else {
287  // If the offset is more than 24-bits, it won't fit in a scattered
288  // relocation offset field, so we fall back to using a non-scattered
289  // relocation. This is a bit risky, as if the offset reaches out of
290  // the block and the linker is doing scattered loading on this
291  // symbol, things can go badly.
292  //
293  // Required for 'as' compatibility.
294  if (FixupOffset > 0xffffff)
295  return false;
296  }
298  makeScatteredRelocationInfo(MRE, FixupOffset, Type, Log2Size, IsPCRel, Value);
299  Writer->addRelocation(Fragment->getParent(), MRE);
300  return true;
301 }
302 
303 // see PPCELFObjectWriter for a general outline of cases
304 void PPCMachObjectWriter::RecordPPCRelocation(
305  MachObjectWriter *Writer, const MCAssembler &Asm, const MCAsmLayout &Layout,
306  const MCFragment *Fragment, const MCFixup &Fixup, MCValue Target,
307  uint64_t &FixedValue) {
308  const MCFixupKind FK = Fixup.getKind(); // unsigned
309  const unsigned Log2Size = getFixupKindLog2Size(FK);
310  const bool IsPCRel = Writer->isFixupKindPCRel(Asm, FK);
311  const unsigned RelocType = getRelocType(Target, FK, IsPCRel);
312 
313  // If this is a difference or a defined symbol plus an offset, then we need a
314  // scattered relocation entry. Differences always require scattered
315  // relocations.
316  if (Target.getSymB() &&
317  // Q: are branch targets ever scattered?
318  RelocType != MachO::PPC_RELOC_BR24 &&
319  RelocType != MachO::PPC_RELOC_BR14) {
320  RecordScatteredRelocation(Writer, Asm, Layout, Fragment, Fixup, Target,
321  Log2Size, FixedValue);
322  return;
323  }
324 
325  // this doesn't seem right for RIT_PPC_BR24
326  // Get the symbol data, if any.
327  MCSymbolData *SD = 0;
328  if (Target.getSymA())
329  SD = &Asm.getSymbolData(Target.getSymA()->getSymbol());
330 
331  // See <reloc.h>.
332  const uint32_t FixupOffset = getFixupOffset(Layout, Fragment, Fixup);
333  unsigned Index = 0;
334  unsigned IsExtern = 0;
335  unsigned Type = RelocType;
336 
337  if (Target.isAbsolute()) { // constant
338  // SymbolNum of 0 indicates the absolute section.
339  //
340  // FIXME: Currently, these are never generated (see code below). I cannot
341  // find a case where they are actually emitted.
342  report_fatal_error("FIXME: relocations to absolute targets "
343  "not yet implemented");
344  // the above line stolen from ARM, not sure
345  } else {
346  // Resolve constant variables.
347  if (SD->getSymbol().isVariable()) {
348  int64_t Res;
349  if (SD->getSymbol().getVariableValue()->EvaluateAsAbsolute(
350  Res, Layout, Writer->getSectionAddressMap())) {
351  FixedValue = Res;
352  return;
353  }
354  }
355 
356  // Check whether we need an external or internal relocation.
357  if (Writer->doesSymbolRequireExternRelocation(SD)) {
358  IsExtern = 1;
359  Index = SD->getIndex();
360  // For external relocations, make sure to offset the fixup value to
361  // compensate for the addend of the symbol address, if it was
362  // undefined. This occurs with weak definitions, for example.
363  if (!SD->Symbol->isUndefined())
364  FixedValue -= Layout.getSymbolOffset(SD);
365  } else {
366  // The index is the section ordinal (1-based).
367  const MCSectionData &SymSD =
368  Asm.getSectionData(SD->getSymbol().getSection());
369  Index = SymSD.getOrdinal() + 1;
370  FixedValue += Writer->getSectionAddress(&SymSD);
371  }
372  if (IsPCRel)
373  FixedValue -= Writer->getSectionAddress(Fragment->getParent());
374  }
375 
376  // struct relocation_info (8 bytes)
378  makeRelocationInfo(MRE, FixupOffset, Index, IsPCRel, Log2Size, IsExtern,
379  Type);
380  Writer->addRelocation(Fragment->getParent(), MRE);
381 }
382 
384  uint32_t CPUType,
385  uint32_t CPUSubtype) {
386  return createMachObjectWriter(
387  new PPCMachObjectWriter(Is64Bit, CPUType, CPUSubtype), OS,
388  /*IsLittleEndian=*/false);
389 }
COFF::RelocationTypeX86 Type
Definition: COFFYAML.cpp:227
A eight-byte pc relative fixup.
Definition: MCFixup.h:30
const MCSymbol & getSymbol() const
Definition: MCExpr.h:283
SMLoc getLoc() const
Definition: MCFixup.h:107
static void makeRelocationInfo(MachO::any_relocation_info &MRE, const uint32_t FixupOffset, const uint32_t Index, const unsigned IsPCRel, const unsigned Log2Size, const unsigned IsExtern, const unsigned Type)
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)
static uint32_t getFixupOffset(const MCAsmLayout &Layout, const MCFragment *Fragment, const MCFixup &Fixup)
Compute fixup offset (address).
A one-byte pc relative fixup.
Definition: MCFixup.h:27
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
#define llvm_unreachable(msg)
const MCExpr * getVariableValue() const
getVariableValue() - Get the value for variable symbols.
Definition: MCSymbol.h:137
static unsigned getRelocType(const MCValue &Target, const MCFixupKind FixupKind, const bool IsPCRel)
MCSectionData & getSectionData(const MCSection &Section) const
Definition: MCAssembler.h:1128
A four-byte fixup.
Definition: MCFixup.h:25
format_object1< T > format(const char *Fmt, const T &Val)
Definition: Format.h:180
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
static unsigned getFixupKindLog2Size(unsigned Kind)
static void makeScatteredRelocationInfo(MachO::any_relocation_info &MRE, const uint32_t Addr, const unsigned Type, const unsigned Log2Size, const unsigned IsPCRel, const uint32_t Value2)
MCSectionData * getParent() const
Definition: MCAssembler.h:95
MCFixupKind
MCFixupKind - Extensible enumeration to represent the type of a fixup.
Definition: MCFixup.h:22
MCFixupKind getKind() const
Definition: MCFixup.h:88
const MCSymbolRefExpr * getSymB() const
Definition: MCValue.h:44
A one-byte fixup.
Definition: MCFixup.h:23
MCObjectWriter * createPPCMachObjectWriter(raw_ostream &OS, bool Is64Bit, uint32_t CPUType, uint32_t CPUSubtype)
createPPCELFObjectWriter - Construct a PPC Mach-O object writer.
LLVM_ATTRIBUTE_NORETURN void FatalError(SMLoc L, const Twine &Msg)
Definition: MCContext.cpp:394
MCSymbolData & getSymbolData(const MCSymbol &Symbol) const
Definition: MCAssembler.h:1145
A two-byte pc relative fixup.
Definition: MCFixup.h:28
const MCSymbolRefExpr * getSymA() const
Definition: MCValue.h:43
A four-byte pc relative fixup.
Definition: MCFixup.h:29
uint64_t getSymbolOffset(const MCSymbolData *SD) const
Get the offset of the given symbol, as computed in the current layout.
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
VariantKind getKind() const
Definition: MCExpr.h:285
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.