5c52b8b0c574a01c16712a180788f6f902884d40
[oota-llvm.git] / lib / Target / PowerPC / MCTargetDesc / PPCMachObjectWriter.cpp
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
10 #include "MCTargetDesc/PPCMCTargetDesc.h"
11 #include "MCTargetDesc/PPCFixupKinds.h"
12 #include "llvm/ADT/Twine.h"
13 #include "llvm/MC/MCAsmLayout.h"
14 #include "llvm/MC/MCAssembler.h"
15 #include "llvm/MC/MCContext.h"
16 #include "llvm/MC/MCMachObjectWriter.h"
17 #include "llvm/MC/MCSectionMachO.h"
18 #include "llvm/MC/MCValue.h"
19 #include "llvm/Support/ErrorHandling.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, MCAssembler &Asm,
45                         const MCAsmLayout &Layout, const MCFragment *Fragment,
46                         const MCFixup &Fixup, MCValue Target,
47                         uint64_t &FixedValue) override {
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:
70   case PPC::fixup_ppc_brcond14:
71   case PPC::fixup_ppc_half16:
72   case PPC::fixup_ppc_br24:
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::GetRelocType().
84 static unsigned getRelocType(const MCValue &Target,
85                              const MCFixupKind FixupKind, // from
86                                                           // Fixup.getKind()
87                              const bool IsPCRel) {
88   const MCSymbolRefExpr::VariantKind Modifier =
89       Target.isAbsolute() ? MCSymbolRefExpr::VK_None
90                           : Target.getSymA()->getKind();
91   // determine the type of the relocation
92   unsigned Type = MachO::GENERIC_RELOC_VANILLA;
93   if (IsPCRel) { // relative to PC
94     switch ((unsigned)FixupKind) {
95     default:
96       report_fatal_error("Unimplemented fixup kind (relative)");
97     case PPC::fixup_ppc_br24:
98       Type = MachO::PPC_RELOC_BR24; // R_PPC_REL24
99       break;
100     case PPC::fixup_ppc_brcond14:
101       Type = MachO::PPC_RELOC_BR14;
102       break;
103     case PPC::fixup_ppc_half16:
104       switch (Modifier) {
105       default:
106         llvm_unreachable("Unsupported modifier for half16 fixup");
107       case MCSymbolRefExpr::VK_PPC_HA:
108         Type = MachO::PPC_RELOC_HA16;
109         break;
110       case MCSymbolRefExpr::VK_PPC_LO:
111         Type = MachO::PPC_RELOC_LO16;
112         break;
113       case MCSymbolRefExpr::VK_PPC_HI:
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)!");
123     case PPC::fixup_ppc_half16:
124       switch (Modifier) {
125       default:
126         llvm_unreachable("Unsupported modifier for half16 fixup");
127       case MCSymbolRefExpr::VK_PPC_HA:
128         Type = MachO::PPC_RELOC_HA16_SECTDIFF;
129         break;
130       case MCSymbolRefExpr::VK_PPC_LO:
131         Type = MachO::PPC_RELOC_LO16_SECTDIFF;
132         break;
133       case MCSymbolRefExpr::VK_PPC_HI:
134         Type = MachO::PPC_RELOC_HI16_SECTDIFF;
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
147 static void makeRelocationInfo(MachO::any_relocation_info &MRE,
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
165 makeScatteredRelocationInfo(MachO::any_relocation_info &MRE,
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   const MCSymbolData *A_SD = &A->getData();
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, 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     const MCSymbolData *B_SD = &B->getSymbol().getData();
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->getSymbol(), 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 ||
236       Type == MachO::PPC_RELOC_HI16_SECTDIFF ||
237       Type == MachO::PPC_RELOC_LO16_SECTDIFF ||
238       Type == MachO::PPC_RELOC_HA16_SECTDIFF ||
239       Type == MachO::PPC_RELOC_LO14_SECTDIFF ||
240       Type == MachO::PPC_RELOC_LOCAL_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().reportFatalError(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) {
259     case MachO::PPC_RELOC_LO16_SECTDIFF:
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;
268     case MachO::PPC_RELOC_HA16_SECTDIFF:
269       other_half = FixedValue & 0xffff;
270       FixedValue =
271           ((FixedValue >> 16) + ((FixedValue & 0x8000) ? 1 : 0)) & 0xffff;
272       break;
273     case MachO::PPC_RELOC_HI16_SECTDIFF:
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
282     MachO::any_relocation_info MRE;
283     makeScatteredRelocationInfo(MRE, other_half, MachO::GENERIC_RELOC_PAIR,
284                                 Log2Size, IsPCRel, Value2);
285     Writer->addRelocation(nullptr, 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   }
297   MachO::any_relocation_info MRE;
298   makeScatteredRelocationInfo(MRE, FixupOffset, Type, Log2Size, IsPCRel, Value);
299   Writer->addRelocation(nullptr, 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   const MCSymbol *A = nullptr;
328   if (Target.getSymA())
329     A = &Target.getSymA()->getSymbol();
330
331   // See <reloc.h>.
332   const uint32_t FixupOffset = getFixupOffset(Layout, Fragment, Fixup);
333   unsigned Index = 0;
334   unsigned Type = RelocType;
335
336   const MCSymbol *RelSymbol = nullptr;
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 (A->isVariable()) {
348       int64_t Res;
349       if (A->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(*A)) {
358       RelSymbol = A;
359       // For external relocations, make sure to offset the fixup value to
360       // compensate for the addend of the symbol address, if it was
361       // undefined. This occurs with weak definitions, for example.
362       if (!A->isUndefined())
363         FixedValue -= Layout.getSymbolOffset(*A);
364     } else {
365       // The index is the section ordinal (1-based).
366       const MCSection &Sec = A->getSection();
367       Index = Sec.getOrdinal() + 1;
368       FixedValue += Writer->getSectionAddress(&Sec);
369     }
370     if (IsPCRel)
371       FixedValue -= Writer->getSectionAddress(Fragment->getParent());
372   }
373
374   // struct relocation_info (8 bytes)
375   MachO::any_relocation_info MRE;
376   makeRelocationInfo(MRE, FixupOffset, Index, IsPCRel, Log2Size, false, Type);
377   Writer->addRelocation(RelSymbol, Fragment->getParent(), MRE);
378 }
379
380 MCObjectWriter *llvm::createPPCMachObjectWriter(raw_pwrite_stream &OS,
381                                                 bool Is64Bit, uint32_t CPUType,
382                                                 uint32_t CPUSubtype) {
383   return createMachObjectWriter(
384       new PPCMachObjectWriter(Is64Bit, CPUType, CPUSubtype), OS,
385       /*IsLittleEndian=*/false);
386 }