Move everything depending on Object/MachOFormat.h over to Support/MachO.h.
[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, 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:
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::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 =
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::scattered_relocation_info &MRE,
166                             const uint32_t Addr, const unsigned Type,
167                             const unsigned Log2Size, const unsigned IsPCRel,
168                             const uint32_t Value2) {
169   MRE.r_scattered = true;
170   MRE.r_pcrel = IsPCRel;
171   MRE.r_length = Log2Size;
172   MRE.r_type = Type;
173   MRE.r_address = Addr;
174   MRE.r_value = Value2;
175 }
176
177 /// Compute fixup offset (address).
178 static uint32_t getFixupOffset(const MCAsmLayout &Layout,
179                                const MCFragment *Fragment,
180                                const MCFixup &Fixup) {
181   uint32_t FixupOffset = Layout.getFragmentOffset(Fragment) + Fixup.getOffset();
182   // On Mach-O, ppc_fixup_half16 relocations must refer to the
183   // start of the instruction, not the second halfword, as ELF does
184   if (unsigned(Fixup.getKind()) == PPC::fixup_ppc_half16)
185     FixupOffset &= ~uint32_t(3);
186   return FixupOffset;
187 }
188
189 /// \return false if falling back to using non-scattered relocation,
190 /// otherwise true for normal scattered relocation.
191 /// based on X86MachObjectWriter::RecordScatteredRelocation
192 /// and ARMMachObjectWriter::RecordScatteredRelocation
193 bool PPCMachObjectWriter::RecordScatteredRelocation(
194     MachObjectWriter *Writer, const MCAssembler &Asm, const MCAsmLayout &Layout,
195     const MCFragment *Fragment, const MCFixup &Fixup, MCValue Target,
196     unsigned Log2Size, uint64_t &FixedValue) {
197   // caller already computes these, can we just pass and reuse?
198   const uint32_t FixupOffset = getFixupOffset(Layout, Fragment, Fixup);
199   const MCFixupKind FK = Fixup.getKind();
200   const unsigned IsPCRel = Writer->isFixupKindPCRel(Asm, FK);
201   const unsigned Type = getRelocType(Target, FK, IsPCRel);
202
203   // Is this a local or SECTDIFF relocation entry?
204   // SECTDIFF relocation entries have symbol subtractions,
205   // and require two entries, the first for the add-symbol value,
206   // the second for the subtract-symbol value.
207
208   // See <reloc.h>.
209   const MCSymbol *A = &Target.getSymA()->getSymbol();
210   MCSymbolData *A_SD = &Asm.getSymbolData(*A);
211
212   if (!A_SD->getFragment())
213     report_fatal_error("symbol '" + A->getName() +
214                        "' can not be undefined in a subtraction expression");
215
216   uint32_t Value = Writer->getSymbolAddress(A_SD, Layout);
217   uint64_t SecAddr =
218       Writer->getSectionAddress(A_SD->getFragment()->getParent());
219   FixedValue += SecAddr;
220   uint32_t Value2 = 0;
221
222   if (const MCSymbolRefExpr *B = Target.getSymB()) {
223     MCSymbolData *B_SD = &Asm.getSymbolData(B->getSymbol());
224
225     if (!B_SD->getFragment())
226       report_fatal_error("symbol '" + B->getSymbol().getName() +
227                          "' can not be undefined in a subtraction expression");
228
229     // FIXME: is Type correct? see include/llvm/Support/MachO.h
230     Value2 = Writer->getSymbolAddress(B_SD, Layout);
231     FixedValue -= Writer->getSectionAddress(B_SD->getFragment()->getParent());
232   }
233   // FIXME: does FixedValue get used??
234
235   // Relocations are written out in reverse order, so the PAIR comes first.
236   if (Type == MachO::PPC_RELOC_SECTDIFF ||
237       Type == MachO::PPC_RELOC_HI16_SECTDIFF ||
238       Type == MachO::PPC_RELOC_LO16_SECTDIFF ||
239       Type == MachO::PPC_RELOC_HA16_SECTDIFF ||
240       Type == MachO::PPC_RELOC_LO14_SECTDIFF ||
241       Type == MachO::PPC_RELOC_LOCAL_SECTDIFF) {
242     // X86 had this piece, but ARM does not
243     // If the offset is too large to fit in a scattered relocation,
244     // we're hosed. It's an unfortunate limitation of the MachO format.
245     if (FixupOffset > 0xffffff) {
246       char Buffer[32];
247       format("0x%x", FixupOffset).print(Buffer, sizeof(Buffer));
248       Asm.getContext().FatalError(Fixup.getLoc(),
249                                   Twine("Section too large, can't encode "
250                                         "r_address (") +
251                                       Buffer + ") into 24 bits of scattered "
252                                                "relocation entry.");
253       llvm_unreachable("fatal error returned?!");
254     }
255
256     // Is this supposed to follow MCTarget/PPCAsmBackend.cpp:adjustFixupValue()?
257     // see PPCMCExpr::EvaluateAsRelocatableImpl()
258     uint32_t other_half = 0;
259     switch (Type) {
260     case MachO::PPC_RELOC_LO16_SECTDIFF:
261       other_half = (FixedValue >> 16) & 0xffff;
262       // applyFixupOffset longer extracts the high part because it now assumes
263       // this was already done.
264       // It looks like this is not true for the FixedValue needed with Mach-O
265       // relocs.
266       // So we need to adjust FixedValue again here.
267       FixedValue &= 0xffff;
268       break;
269     case MachO::PPC_RELOC_HA16_SECTDIFF:
270       other_half = FixedValue & 0xffff;
271       FixedValue =
272           ((FixedValue >> 16) + ((FixedValue & 0x8000) ? 1 : 0)) & 0xffff;
273       break;
274     case MachO::PPC_RELOC_HI16_SECTDIFF:
275       other_half = FixedValue & 0xffff;
276       FixedValue = (FixedValue >> 16) & 0xffff;
277       break;
278     default:
279       llvm_unreachable("Invalid PPC scattered relocation type.");
280       break;
281     }
282
283     MachO::scattered_relocation_info MRE;
284     makeScatteredRelocationInfo(MRE, other_half, MachO::GENERIC_RELOC_PAIR,
285                                 Log2Size, IsPCRel, Value2);
286     Writer->addRelocation(Fragment->getParent(), MRE);
287   } else {
288     // If the offset is more than 24-bits, it won't fit in a scattered
289     // relocation offset field, so we fall back to using a non-scattered
290     // relocation. This is a bit risky, as if the offset reaches out of
291     // the block and the linker is doing scattered loading on this
292     // symbol, things can go badly.
293     //
294     // Required for 'as' compatibility.
295     if (FixupOffset > 0xffffff)
296       return false;
297   }
298   MachO::scattered_relocation_info MRE;
299   makeScatteredRelocationInfo(MRE, FixupOffset, Type, Log2Size, IsPCRel, Value);
300   Writer->addRelocation(Fragment->getParent(), MRE);
301   return true;
302 }
303
304 // see PPCELFObjectWriter for a general outline of cases
305 void PPCMachObjectWriter::RecordPPCRelocation(
306     MachObjectWriter *Writer, const MCAssembler &Asm, const MCAsmLayout &Layout,
307     const MCFragment *Fragment, const MCFixup &Fixup, MCValue Target,
308     uint64_t &FixedValue) {
309   const MCFixupKind FK = Fixup.getKind(); // unsigned
310   const unsigned Log2Size = getFixupKindLog2Size(FK);
311   const bool IsPCRel = Writer->isFixupKindPCRel(Asm, FK);
312   const unsigned RelocType = getRelocType(Target, FK, IsPCRel);
313
314   // If this is a difference or a defined symbol plus an offset, then we need a
315   // scattered relocation entry. Differences always require scattered
316   // relocations.
317   if (Target.getSymB() &&
318       // Q: are branch targets ever scattered?
319       RelocType != MachO::PPC_RELOC_BR24 &&
320       RelocType != MachO::PPC_RELOC_BR14) {
321     RecordScatteredRelocation(Writer, Asm, Layout, Fragment, Fixup, Target,
322                               Log2Size, FixedValue);
323     return;
324   }
325
326   // this doesn't seem right for RIT_PPC_BR24
327   // Get the symbol data, if any.
328   MCSymbolData *SD = 0;
329   if (Target.getSymA())
330     SD = &Asm.getSymbolData(Target.getSymA()->getSymbol());
331
332   // See <reloc.h>.
333   const uint32_t FixupOffset = getFixupOffset(Layout, Fragment, Fixup);
334   unsigned Index = 0;
335   unsigned IsExtern = 0;
336   unsigned Type = RelocType;
337
338   if (Target.isAbsolute()) { // constant
339                              // SymbolNum of 0 indicates the absolute section.
340                              //
341     // FIXME: Currently, these are never generated (see code below). I cannot
342     // find a case where they are actually emitted.
343     report_fatal_error("FIXME: relocations to absolute targets "
344                        "not yet implemented");
345     // the above line stolen from ARM, not sure
346   } else {
347     // Resolve constant variables.
348     if (SD->getSymbol().isVariable()) {
349       int64_t Res;
350       if (SD->getSymbol().getVariableValue()->EvaluateAsAbsolute(
351               Res, Layout, Writer->getSectionAddressMap())) {
352         FixedValue = Res;
353         return;
354       }
355     }
356
357     // Check whether we need an external or internal relocation.
358     if (Writer->doesSymbolRequireExternRelocation(SD)) {
359       IsExtern = 1;
360       Index = SD->getIndex();
361       // For external relocations, make sure to offset the fixup value to
362       // compensate for the addend of the symbol address, if it was
363       // undefined. This occurs with weak definitions, for example.
364       if (!SD->Symbol->isUndefined())
365         FixedValue -= Layout.getSymbolOffset(SD);
366     } else {
367       // The index is the section ordinal (1-based).
368       const MCSectionData &SymSD =
369           Asm.getSectionData(SD->getSymbol().getSection());
370       Index = SymSD.getOrdinal() + 1;
371       FixedValue += Writer->getSectionAddress(&SymSD);
372     }
373     if (IsPCRel)
374       FixedValue -= Writer->getSectionAddress(Fragment->getParent());
375   }
376
377   MachO::any_relocation_info MRE;
378   makeRelocationInfo(MRE, FixupOffset, Index, IsPCRel, Log2Size, IsExtern,
379                      Type);
380   Writer->addRelocation(Fragment->getParent(), MRE);
381 }
382
383 MCObjectWriter *llvm::createPPCMachObjectWriter(raw_ostream &OS, bool Is64Bit,
384                                                 uint32_t CPUType,
385                                                 uint32_t CPUSubtype) {
386   return createMachObjectWriter(
387       new PPCMachObjectWriter(Is64Bit, CPUType, CPUSubtype), OS,
388       /*IsLittleEndian=*/false);
389 }