blob: d8e45b8af4999e33758822c34e7a02251d06189e [file] [log] [blame]
David Fangb88cdf62013-08-08 20:14:40 +00001//===-- 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"
David Fangb88cdf62013-08-08 20:14:40 +000019#include "llvm/Support/ErrorHandling.h"
20#include "llvm/Support/Format.h"
Charles Davis8bdfafd2013-09-01 04:28:48 +000021#include "llvm/Support/MachO.h"
David Fangb88cdf62013-08-08 20:14:40 +000022
23using namespace llvm;
David Fangb88cdf62013-08-08 20:14:40 +000024
25namespace {
26class 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
39public:
40 PPCMachObjectWriter(bool Is64Bit, uint32_t CPUType, uint32_t CPUSubtype)
41 : MCMachObjectTargetWriter(Is64Bit, CPUType, CPUSubtype,
42 /*UseAggressiveSymbolFolding=*/Is64Bit) {}
43
Rafael Espindola26585542015-01-19 21:11:14 +000044 void RecordRelocation(MachObjectWriter *Writer, MCAssembler &Asm,
David Fangb88cdf62013-08-08 20:14:40 +000045 const MCAsmLayout &Layout, const MCFragment *Fragment,
46 const MCFixup &Fixup, MCValue Target,
Craig Topper0d3fa922014-04-29 07:57:37 +000047 uint64_t &FixedValue) override {
David Fangb88cdf62013-08-08 20:14:40 +000048 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.
59static 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.
Benjamin Kramer8c90fd72014-09-03 11:41:21 +000083/// Outline based on PPCELFObjectWriter::GetRelocType().
David Fangb88cdf62013-08-08 20:14:40 +000084static 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
Charles Davis8bdfafd2013-09-01 04:28:48 +000092 unsigned Type = MachO::GENERIC_RELOC_VANILLA;
David Fangb88cdf62013-08-08 20:14:40 +000093 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:
Charles Davis8bdfafd2013-09-01 04:28:48 +000098 Type = MachO::PPC_RELOC_BR24; // R_PPC_REL24
David Fangb88cdf62013-08-08 20:14:40 +000099 break;
100 case PPC::fixup_ppc_brcond14:
Charles Davis8bdfafd2013-09-01 04:28:48 +0000101 Type = MachO::PPC_RELOC_BR14;
David Fangb88cdf62013-08-08 20:14:40 +0000102 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:
Charles Davis8bdfafd2013-09-01 04:28:48 +0000108 Type = MachO::PPC_RELOC_HA16;
David Fangb88cdf62013-08-08 20:14:40 +0000109 break;
110 case MCSymbolRefExpr::VK_PPC_LO:
Charles Davis8bdfafd2013-09-01 04:28:48 +0000111 Type = MachO::PPC_RELOC_LO16;
David Fangb88cdf62013-08-08 20:14:40 +0000112 break;
113 case MCSymbolRefExpr::VK_PPC_HI:
Charles Davis8bdfafd2013-09-01 04:28:48 +0000114 Type = MachO::PPC_RELOC_HI16;
David Fangb88cdf62013-08-08 20:14:40 +0000115 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:
Charles Davis8bdfafd2013-09-01 04:28:48 +0000128 Type = MachO::PPC_RELOC_HA16_SECTDIFF;
David Fangb88cdf62013-08-08 20:14:40 +0000129 break;
130 case MCSymbolRefExpr::VK_PPC_LO:
Charles Davis8bdfafd2013-09-01 04:28:48 +0000131 Type = MachO::PPC_RELOC_LO16_SECTDIFF;
David Fangb88cdf62013-08-08 20:14:40 +0000132 break;
133 case MCSymbolRefExpr::VK_PPC_HI:
Charles Davis8bdfafd2013-09-01 04:28:48 +0000134 Type = MachO::PPC_RELOC_HI16_SECTDIFF;
David Fangb88cdf62013-08-08 20:14:40 +0000135 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
Charles Davis8bdfafd2013-09-01 04:28:48 +0000147static void makeRelocationInfo(MachO::any_relocation_info &MRE,
David Fangb88cdf62013-08-08 20:14:40 +0000148 const uint32_t FixupOffset, const uint32_t Index,
149 const unsigned IsPCRel, const unsigned Log2Size,
150 const unsigned IsExtern, const unsigned Type) {
Charles Davis8bdfafd2013-09-01 04:28:48 +0000151 MRE.r_word0 = FixupOffset;
David Fangb88cdf62013-08-08 20:14:40 +0000152 // The bitfield offsets that work (as determined by trial-and-error)
153 // are different than what is documented in the mach-o manuals.
Charles Davis8bdfafd2013-09-01 04:28:48 +0000154 // 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
David Fangb88cdf62013-08-08 20:14:40 +0000162}
163
164static void
Charles Davis8bdfafd2013-09-01 04:28:48 +0000165makeScatteredRelocationInfo(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) {
Charles Davis1827bd82013-08-27 05:38:30 +0000169 // 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
Charles Davis8bdfafd2013-09-01 04:28:48 +0000171 MRE.r_word0 = ((Addr << 0) | (Type << 24) | (Log2Size << 28) |
172 (IsPCRel << 30) | MachO::R_SCATTERED);
173 MRE.r_word1 = Value2;
David Fangb88cdf62013-08-08 20:14:40 +0000174}
175
176/// Compute fixup offset (address).
177static 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
David Fang2f1b0b52013-08-08 21:29:30 +0000183 if (unsigned(Fixup.getKind()) == PPC::fixup_ppc_half16)
David Fangb88cdf62013-08-08 20:14:40 +0000184 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
192bool 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();
David Fangb88cdf62013-08-08 20:14:40 +0000209
Rafael Espindola4d37b2a2015-05-29 21:45:01 +0000210 if (!A->getFragment())
David Fangb88cdf62013-08-08 20:14:40 +0000211 report_fatal_error("symbol '" + A->getName() +
212 "' can not be undefined in a subtraction expression");
213
Duncan P. N. Exon Smith99d8a8e2015-05-20 00:02:39 +0000214 uint32_t Value = Writer->getSymbolAddress(*A, Layout);
Rafael Espindola4d37b2a2015-05-29 21:45:01 +0000215 uint64_t SecAddr = Writer->getSectionAddress(A->getFragment()->getParent());
David Fangb88cdf62013-08-08 20:14:40 +0000216 FixedValue += SecAddr;
217 uint32_t Value2 = 0;
218
219 if (const MCSymbolRefExpr *B = Target.getSymB()) {
Rafael Espindola4d37b2a2015-05-29 21:45:01 +0000220 const MCSymbol *SB = &B->getSymbol();
David Fangb88cdf62013-08-08 20:14:40 +0000221
Rafael Espindola4d37b2a2015-05-29 21:45:01 +0000222 if (!SB->getFragment())
David Fangb88cdf62013-08-08 20:14:40 +0000223 report_fatal_error("symbol '" + B->getSymbol().getName() +
224 "' can not be undefined in a subtraction expression");
225
Charles Davis8bdfafd2013-09-01 04:28:48 +0000226 // FIXME: is Type correct? see include/llvm/Support/MachO.h
Duncan P. N. Exon Smith99d8a8e2015-05-20 00:02:39 +0000227 Value2 = Writer->getSymbolAddress(B->getSymbol(), Layout);
Rafael Espindola4d37b2a2015-05-29 21:45:01 +0000228 FixedValue -= Writer->getSectionAddress(SB->getFragment()->getParent());
David Fangb88cdf62013-08-08 20:14:40 +0000229 }
230 // FIXME: does FixedValue get used??
231
232 // Relocations are written out in reverse order, so the PAIR comes first.
Charles Davis8bdfafd2013-09-01 04:28:48 +0000233 if (Type == MachO::PPC_RELOC_SECTDIFF ||
234 Type == MachO::PPC_RELOC_HI16_SECTDIFF ||
235 Type == MachO::PPC_RELOC_LO16_SECTDIFF ||
236 Type == MachO::PPC_RELOC_HA16_SECTDIFF ||
237 Type == MachO::PPC_RELOC_LO14_SECTDIFF ||
238 Type == MachO::PPC_RELOC_LOCAL_SECTDIFF) {
David Fangb88cdf62013-08-08 20:14:40 +0000239 // X86 had this piece, but ARM does not
240 // If the offset is too large to fit in a scattered relocation,
241 // we're hosed. It's an unfortunate limitation of the MachO format.
242 if (FixupOffset > 0xffffff) {
243 char Buffer[32];
244 format("0x%x", FixupOffset).print(Buffer, sizeof(Buffer));
Jim Grosbach6f482002015-05-18 18:43:14 +0000245 Asm.getContext().reportFatalError(Fixup.getLoc(),
David Fangb88cdf62013-08-08 20:14:40 +0000246 Twine("Section too large, can't encode "
247 "r_address (") +
248 Buffer + ") into 24 bits of scattered "
249 "relocation entry.");
250 llvm_unreachable("fatal error returned?!");
251 }
252
253 // Is this supposed to follow MCTarget/PPCAsmBackend.cpp:adjustFixupValue()?
254 // see PPCMCExpr::EvaluateAsRelocatableImpl()
255 uint32_t other_half = 0;
256 switch (Type) {
Charles Davis8bdfafd2013-09-01 04:28:48 +0000257 case MachO::PPC_RELOC_LO16_SECTDIFF:
David Fangb88cdf62013-08-08 20:14:40 +0000258 other_half = (FixedValue >> 16) & 0xffff;
259 // applyFixupOffset longer extracts the high part because it now assumes
260 // this was already done.
261 // It looks like this is not true for the FixedValue needed with Mach-O
262 // relocs.
263 // So we need to adjust FixedValue again here.
264 FixedValue &= 0xffff;
265 break;
Charles Davis8bdfafd2013-09-01 04:28:48 +0000266 case MachO::PPC_RELOC_HA16_SECTDIFF:
David Fangb88cdf62013-08-08 20:14:40 +0000267 other_half = FixedValue & 0xffff;
268 FixedValue =
269 ((FixedValue >> 16) + ((FixedValue & 0x8000) ? 1 : 0)) & 0xffff;
270 break;
Charles Davis8bdfafd2013-09-01 04:28:48 +0000271 case MachO::PPC_RELOC_HI16_SECTDIFF:
David Fangb88cdf62013-08-08 20:14:40 +0000272 other_half = FixedValue & 0xffff;
273 FixedValue = (FixedValue >> 16) & 0xffff;
274 break;
275 default:
276 llvm_unreachable("Invalid PPC scattered relocation type.");
277 break;
278 }
279
Charles Davis8bdfafd2013-09-01 04:28:48 +0000280 MachO::any_relocation_info MRE;
281 makeScatteredRelocationInfo(MRE, other_half, MachO::GENERIC_RELOC_PAIR,
282 Log2Size, IsPCRel, Value2);
Rafael Espindola61e724a2015-05-26 01:15:30 +0000283 Writer->addRelocation(nullptr, Fragment->getParent(), MRE);
David Fangb88cdf62013-08-08 20:14:40 +0000284 } else {
285 // If the offset is more than 24-bits, it won't fit in a scattered
286 // relocation offset field, so we fall back to using a non-scattered
287 // relocation. This is a bit risky, as if the offset reaches out of
288 // the block and the linker is doing scattered loading on this
289 // symbol, things can go badly.
290 //
291 // Required for 'as' compatibility.
292 if (FixupOffset > 0xffffff)
293 return false;
294 }
Charles Davis8bdfafd2013-09-01 04:28:48 +0000295 MachO::any_relocation_info MRE;
David Fangb88cdf62013-08-08 20:14:40 +0000296 makeScatteredRelocationInfo(MRE, FixupOffset, Type, Log2Size, IsPCRel, Value);
Rafael Espindola61e724a2015-05-26 01:15:30 +0000297 Writer->addRelocation(nullptr, Fragment->getParent(), MRE);
David Fangb88cdf62013-08-08 20:14:40 +0000298 return true;
299}
300
301// see PPCELFObjectWriter for a general outline of cases
302void PPCMachObjectWriter::RecordPPCRelocation(
303 MachObjectWriter *Writer, const MCAssembler &Asm, const MCAsmLayout &Layout,
304 const MCFragment *Fragment, const MCFixup &Fixup, MCValue Target,
305 uint64_t &FixedValue) {
306 const MCFixupKind FK = Fixup.getKind(); // unsigned
307 const unsigned Log2Size = getFixupKindLog2Size(FK);
308 const bool IsPCRel = Writer->isFixupKindPCRel(Asm, FK);
309 const unsigned RelocType = getRelocType(Target, FK, IsPCRel);
310
311 // If this is a difference or a defined symbol plus an offset, then we need a
312 // scattered relocation entry. Differences always require scattered
313 // relocations.
314 if (Target.getSymB() &&
315 // Q: are branch targets ever scattered?
Charles Davis8bdfafd2013-09-01 04:28:48 +0000316 RelocType != MachO::PPC_RELOC_BR24 &&
317 RelocType != MachO::PPC_RELOC_BR14) {
David Fangb88cdf62013-08-08 20:14:40 +0000318 RecordScatteredRelocation(Writer, Asm, Layout, Fragment, Fixup, Target,
319 Log2Size, FixedValue);
320 return;
321 }
322
323 // this doesn't seem right for RIT_PPC_BR24
324 // Get the symbol data, if any.
Duncan P. N. Exon Smith08b87262015-05-20 15:16:14 +0000325 const MCSymbol *A = nullptr;
David Fangb88cdf62013-08-08 20:14:40 +0000326 if (Target.getSymA())
Duncan P. N. Exon Smith08b87262015-05-20 15:16:14 +0000327 A = &Target.getSymA()->getSymbol();
David Fangb88cdf62013-08-08 20:14:40 +0000328
329 // See <reloc.h>.
330 const uint32_t FixupOffset = getFixupOffset(Layout, Fragment, Fixup);
331 unsigned Index = 0;
David Fangb88cdf62013-08-08 20:14:40 +0000332 unsigned Type = RelocType;
333
Duncan P. N. Exon Smith6e23e5a2015-05-16 01:14:19 +0000334 const MCSymbol *RelSymbol = nullptr;
David Fangb88cdf62013-08-08 20:14:40 +0000335 if (Target.isAbsolute()) { // constant
336 // SymbolNum of 0 indicates the absolute section.
337 //
338 // FIXME: Currently, these are never generated (see code below). I cannot
339 // find a case where they are actually emitted.
340 report_fatal_error("FIXME: relocations to absolute targets "
341 "not yet implemented");
342 // the above line stolen from ARM, not sure
343 } else {
344 // Resolve constant variables.
Duncan P. N. Exon Smith08b87262015-05-20 15:16:14 +0000345 if (A->isVariable()) {
David Fangb88cdf62013-08-08 20:14:40 +0000346 int64_t Res;
Duncan P. N. Exon Smith08b87262015-05-20 15:16:14 +0000347 if (A->getVariableValue()->EvaluateAsAbsolute(
David Fangb88cdf62013-08-08 20:14:40 +0000348 Res, Layout, Writer->getSectionAddressMap())) {
349 FixedValue = Res;
350 return;
351 }
352 }
353
354 // Check whether we need an external or internal relocation.
Duncan P. N. Exon Smith08b87262015-05-20 15:16:14 +0000355 if (Writer->doesSymbolRequireExternRelocation(*A)) {
356 RelSymbol = A;
David Fangb88cdf62013-08-08 20:14:40 +0000357 // For external relocations, make sure to offset the fixup value to
358 // compensate for the addend of the symbol address, if it was
359 // undefined. This occurs with weak definitions, for example.
Duncan P. N. Exon Smith08b87262015-05-20 15:16:14 +0000360 if (!A->isUndefined())
361 FixedValue -= Layout.getSymbolOffset(*A);
David Fangb88cdf62013-08-08 20:14:40 +0000362 } else {
363 // The index is the section ordinal (1-based).
Rafael Espindola6e6820a2015-05-25 14:12:48 +0000364 const MCSection &Sec = A->getSection();
Rafael Espindola6e6820a2015-05-25 14:12:48 +0000365 Index = Sec.getOrdinal() + 1;
Rafael Espindola079027e2015-05-26 00:52:18 +0000366 FixedValue += Writer->getSectionAddress(&Sec);
David Fangb88cdf62013-08-08 20:14:40 +0000367 }
368 if (IsPCRel)
Rafael Espindola079027e2015-05-26 00:52:18 +0000369 FixedValue -= Writer->getSectionAddress(Fragment->getParent());
David Fangb88cdf62013-08-08 20:14:40 +0000370 }
371
Charles Davis1827bd82013-08-27 05:38:30 +0000372 // struct relocation_info (8 bytes)
Charles Davis8bdfafd2013-09-01 04:28:48 +0000373 MachO::any_relocation_info MRE;
Rafael Espindola26585542015-01-19 21:11:14 +0000374 makeRelocationInfo(MRE, FixupOffset, Index, IsPCRel, Log2Size, false, Type);
Rafael Espindola61e724a2015-05-26 01:15:30 +0000375 Writer->addRelocation(RelSymbol, Fragment->getParent(), MRE);
David Fangb88cdf62013-08-08 20:14:40 +0000376}
377
Rafael Espindola5560a4c2015-04-14 22:14:34 +0000378MCObjectWriter *llvm::createPPCMachObjectWriter(raw_pwrite_stream &OS,
379 bool Is64Bit, uint32_t CPUType,
David Fangb88cdf62013-08-08 20:14:40 +0000380 uint32_t CPUSubtype) {
381 return createMachObjectWriter(
382 new PPCMachObjectWriter(Is64Bit, CPUType, CPUSubtype), OS,
383 /*IsLittleEndian=*/false);
384}