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