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