1226584Sdim//===-- X86MachObjectWriter.cpp - X86 Mach-O Writer -----------------------===//
2226584Sdim//
3226584Sdim//                     The LLVM Compiler Infrastructure
4226584Sdim//
5226584Sdim// This file is distributed under the University of Illinois Open Source
6226584Sdim// License. See LICENSE.TXT for details.
7226584Sdim//
8226584Sdim//===----------------------------------------------------------------------===//
9226584Sdim
10249423Sdim#include "MCTargetDesc/X86MCTargetDesc.h"
11226584Sdim#include "MCTargetDesc/X86FixupKinds.h"
12249423Sdim#include "llvm/ADT/Twine.h"
13249423Sdim#include "llvm/MC/MCAsmLayout.h"
14226584Sdim#include "llvm/MC/MCAssembler.h"
15243830Sdim#include "llvm/MC/MCContext.h"
16226584Sdim#include "llvm/MC/MCMachObjectWriter.h"
17226584Sdim#include "llvm/MC/MCSectionMachO.h"
18226584Sdim#include "llvm/MC/MCValue.h"
19226584Sdim#include "llvm/Support/ErrorHandling.h"
20243830Sdim#include "llvm/Support/Format.h"
21263508Sdim#include "llvm/Support/MachO.h"
22226584Sdim
23226584Sdimusing namespace llvm;
24226584Sdim
25226584Sdimnamespace {
26226584Sdimclass X86MachObjectWriter : public MCMachObjectTargetWriter {
27243830Sdim  bool RecordScatteredRelocation(MachObjectWriter *Writer,
28226584Sdim                                 const MCAssembler &Asm,
29226584Sdim                                 const MCAsmLayout &Layout,
30226584Sdim                                 const MCFragment *Fragment,
31226584Sdim                                 const MCFixup &Fixup,
32226584Sdim                                 MCValue Target,
33226584Sdim                                 unsigned Log2Size,
34226584Sdim                                 uint64_t &FixedValue);
35226584Sdim  void RecordTLVPRelocation(MachObjectWriter *Writer,
36226584Sdim                            const MCAssembler &Asm,
37226584Sdim                            const MCAsmLayout &Layout,
38226584Sdim                            const MCFragment *Fragment,
39226584Sdim                            const MCFixup &Fixup,
40226584Sdim                            MCValue Target,
41226584Sdim                            uint64_t &FixedValue);
42226584Sdim
43226584Sdim  void RecordX86Relocation(MachObjectWriter *Writer,
44226584Sdim                              const MCAssembler &Asm,
45226584Sdim                              const MCAsmLayout &Layout,
46226584Sdim                              const MCFragment *Fragment,
47226584Sdim                              const MCFixup &Fixup,
48226584Sdim                              MCValue Target,
49226584Sdim                              uint64_t &FixedValue);
50226584Sdim  void RecordX86_64Relocation(MachObjectWriter *Writer,
51226584Sdim                              const MCAssembler &Asm,
52226584Sdim                              const MCAsmLayout &Layout,
53226584Sdim                              const MCFragment *Fragment,
54226584Sdim                              const MCFixup &Fixup,
55226584Sdim                              MCValue Target,
56226584Sdim                              uint64_t &FixedValue);
57226584Sdimpublic:
58226584Sdim  X86MachObjectWriter(bool Is64Bit, uint32_t CPUType,
59226584Sdim                      uint32_t CPUSubtype)
60226584Sdim    : MCMachObjectTargetWriter(Is64Bit, CPUType, CPUSubtype,
61226584Sdim                               /*UseAggressiveSymbolFolding=*/Is64Bit) {}
62226584Sdim
63226584Sdim  void RecordRelocation(MachObjectWriter *Writer,
64226584Sdim                        const MCAssembler &Asm, const MCAsmLayout &Layout,
65226584Sdim                        const MCFragment *Fragment, const MCFixup &Fixup,
66226584Sdim                        MCValue Target, uint64_t &FixedValue) {
67226584Sdim    if (Writer->is64Bit())
68226584Sdim      RecordX86_64Relocation(Writer, Asm, Layout, Fragment, Fixup, Target,
69226584Sdim                             FixedValue);
70226584Sdim    else
71226584Sdim      RecordX86Relocation(Writer, Asm, Layout, Fragment, Fixup, Target,
72226584Sdim                          FixedValue);
73226584Sdim  }
74226584Sdim};
75226584Sdim}
76226584Sdim
77226584Sdimstatic bool isFixupKindRIPRel(unsigned Kind) {
78226584Sdim  return Kind == X86::reloc_riprel_4byte ||
79226584Sdim    Kind == X86::reloc_riprel_4byte_movq_load;
80226584Sdim}
81226584Sdim
82226584Sdimstatic unsigned getFixupKindLog2Size(unsigned Kind) {
83226584Sdim  switch (Kind) {
84226584Sdim  default:
85226584Sdim    llvm_unreachable("invalid fixup kind!");
86226584Sdim  case FK_PCRel_1:
87226584Sdim  case FK_Data_1: return 0;
88226584Sdim  case FK_PCRel_2:
89226584Sdim  case FK_Data_2: return 1;
90226584Sdim  case FK_PCRel_4:
91226584Sdim    // FIXME: Remove these!!!
92226584Sdim  case X86::reloc_riprel_4byte:
93226584Sdim  case X86::reloc_riprel_4byte_movq_load:
94226584Sdim  case X86::reloc_signed_4byte:
95226584Sdim  case FK_Data_4: return 2;
96226584Sdim  case FK_Data_8: return 3;
97226584Sdim  }
98226584Sdim}
99226584Sdim
100226584Sdimvoid X86MachObjectWriter::RecordX86_64Relocation(MachObjectWriter *Writer,
101226584Sdim                                                 const MCAssembler &Asm,
102226584Sdim                                                 const MCAsmLayout &Layout,
103226584Sdim                                                 const MCFragment *Fragment,
104226584Sdim                                                 const MCFixup &Fixup,
105226584Sdim                                                 MCValue Target,
106226584Sdim                                                 uint64_t &FixedValue) {
107226584Sdim  unsigned IsPCRel = Writer->isFixupKindPCRel(Asm, Fixup.getKind());
108226584Sdim  unsigned IsRIPRel = isFixupKindRIPRel(Fixup.getKind());
109226584Sdim  unsigned Log2Size = getFixupKindLog2Size(Fixup.getKind());
110226584Sdim
111226584Sdim  // See <reloc.h>.
112226584Sdim  uint32_t FixupOffset =
113226584Sdim    Layout.getFragmentOffset(Fragment) + Fixup.getOffset();
114226584Sdim  uint32_t FixupAddress =
115226584Sdim    Writer->getFragmentAddress(Fragment, Layout) + Fixup.getOffset();
116226584Sdim  int64_t Value = 0;
117226584Sdim  unsigned Index = 0;
118226584Sdim  unsigned IsExtern = 0;
119226584Sdim  unsigned Type = 0;
120226584Sdim
121226584Sdim  Value = Target.getConstant();
122226584Sdim
123226584Sdim  if (IsPCRel) {
124226584Sdim    // Compensate for the relocation offset, Darwin x86_64 relocations only have
125226584Sdim    // the addend and appear to have attempted to define it to be the actual
126226584Sdim    // expression addend without the PCrel bias. However, instructions with data
127226584Sdim    // following the relocation are not accommodated for (see comment below
128226584Sdim    // regarding SIGNED{1,2,4}), so it isn't exactly that either.
129226584Sdim    Value += 1LL << Log2Size;
130226584Sdim  }
131226584Sdim
132226584Sdim  if (Target.isAbsolute()) { // constant
133226584Sdim    // SymbolNum of 0 indicates the absolute section.
134263508Sdim    Type = MachO::X86_64_RELOC_UNSIGNED;
135226584Sdim    Index = 0;
136226584Sdim
137226584Sdim    // FIXME: I believe this is broken, I don't think the linker can understand
138226584Sdim    // it. I think it would require a local relocation, but I'm not sure if that
139226584Sdim    // would work either. The official way to get an absolute PCrel relocation
140226584Sdim    // is to use an absolute symbol (which we don't support yet).
141226584Sdim    if (IsPCRel) {
142226584Sdim      IsExtern = 1;
143263508Sdim      Type = MachO::X86_64_RELOC_BRANCH;
144226584Sdim    }
145226584Sdim  } else if (Target.getSymB()) { // A - B + constant
146226584Sdim    const MCSymbol *A = &Target.getSymA()->getSymbol();
147263508Sdim    if (A->isTemporary())
148263508Sdim      A = &A->AliasedSymbol();
149226584Sdim    MCSymbolData &A_SD = Asm.getSymbolData(*A);
150226584Sdim    const MCSymbolData *A_Base = Asm.getAtom(&A_SD);
151226584Sdim
152226584Sdim    const MCSymbol *B = &Target.getSymB()->getSymbol();
153263508Sdim    if (B->isTemporary())
154263508Sdim      B = &B->AliasedSymbol();
155226584Sdim    MCSymbolData &B_SD = Asm.getSymbolData(*B);
156226584Sdim    const MCSymbolData *B_Base = Asm.getAtom(&B_SD);
157226584Sdim
158226584Sdim    // Neither symbol can be modified.
159226584Sdim    if (Target.getSymA()->getKind() != MCSymbolRefExpr::VK_None ||
160226584Sdim        Target.getSymB()->getKind() != MCSymbolRefExpr::VK_None)
161263508Sdim      report_fatal_error("unsupported relocation of modified symbol", false);
162226584Sdim
163226584Sdim    // We don't support PCrel relocations of differences. Darwin 'as' doesn't
164226584Sdim    // implement most of these correctly.
165226584Sdim    if (IsPCRel)
166263508Sdim      report_fatal_error("unsupported pc-relative relocation of difference",
167263508Sdim                         false);
168226584Sdim
169226584Sdim    // The support for the situation where one or both of the symbols would
170226584Sdim    // require a local relocation is handled just like if the symbols were
171226584Sdim    // external.  This is certainly used in the case of debug sections where the
172226584Sdim    // section has only temporary symbols and thus the symbols don't have base
173226584Sdim    // symbols.  This is encoded using the section ordinal and non-extern
174226584Sdim    // relocation entries.
175226584Sdim
176226584Sdim    // Darwin 'as' doesn't emit correct relocations for this (it ends up with a
177226584Sdim    // single SIGNED relocation); reject it for now.  Except the case where both
178226584Sdim    // symbols don't have a base, equal but both NULL.
179226584Sdim    if (A_Base == B_Base && A_Base)
180263508Sdim      report_fatal_error("unsupported relocation with identical base", false);
181226584Sdim
182263508Sdim    // A subtraction expression where both symbols are undefined is a
183263508Sdim    // non-relocatable expression.
184263508Sdim    if (A->isUndefined() && B->isUndefined())
185263508Sdim      report_fatal_error("unsupported relocation with subtraction expression",
186263508Sdim                         false);
187263508Sdim
188226584Sdim    Value += Writer->getSymbolAddress(&A_SD, Layout) -
189226584Sdim      (A_Base == NULL ? 0 : Writer->getSymbolAddress(A_Base, Layout));
190226584Sdim    Value -= Writer->getSymbolAddress(&B_SD, Layout) -
191226584Sdim      (B_Base == NULL ? 0 : Writer->getSymbolAddress(B_Base, Layout));
192226584Sdim
193226584Sdim    if (A_Base) {
194226584Sdim      Index = A_Base->getIndex();
195226584Sdim      IsExtern = 1;
196226584Sdim    }
197226584Sdim    else {
198226584Sdim      Index = A_SD.getFragment()->getParent()->getOrdinal() + 1;
199226584Sdim      IsExtern = 0;
200226584Sdim    }
201263508Sdim    Type = MachO::X86_64_RELOC_UNSIGNED;
202226584Sdim
203263508Sdim    MachO::any_relocation_info MRE;
204263508Sdim    MRE.r_word0 = FixupOffset;
205263508Sdim    MRE.r_word1 = ((Index     <<  0) |
206263508Sdim                   (IsPCRel   << 24) |
207263508Sdim                   (Log2Size  << 25) |
208263508Sdim                   (IsExtern  << 27) |
209263508Sdim                   (Type      << 28));
210226584Sdim    Writer->addRelocation(Fragment->getParent(), MRE);
211226584Sdim
212226584Sdim    if (B_Base) {
213226584Sdim      Index = B_Base->getIndex();
214226584Sdim      IsExtern = 1;
215226584Sdim    }
216226584Sdim    else {
217226584Sdim      Index = B_SD.getFragment()->getParent()->getOrdinal() + 1;
218226584Sdim      IsExtern = 0;
219226584Sdim    }
220263508Sdim    Type = MachO::X86_64_RELOC_SUBTRACTOR;
221226584Sdim  } else {
222226584Sdim    const MCSymbol *Symbol = &Target.getSymA()->getSymbol();
223226584Sdim    MCSymbolData &SD = Asm.getSymbolData(*Symbol);
224226584Sdim    const MCSymbolData *Base = Asm.getAtom(&SD);
225226584Sdim
226226584Sdim    // Relocations inside debug sections always use local relocations when
227226584Sdim    // possible. This seems to be done because the debugger doesn't fully
228226584Sdim    // understand x86_64 relocation entries, and expects to find values that
229226584Sdim    // have already been fixed up.
230226584Sdim    if (Symbol->isInSection()) {
231226584Sdim      const MCSectionMachO &Section = static_cast<const MCSectionMachO&>(
232226584Sdim        Fragment->getParent()->getSection());
233226584Sdim      if (Section.hasAttribute(MCSectionMachO::S_ATTR_DEBUG))
234226584Sdim        Base = 0;
235226584Sdim    }
236226584Sdim
237226584Sdim    // x86_64 almost always uses external relocations, except when there is no
238226584Sdim    // symbol to use as a base address (a local symbol with no preceding
239226584Sdim    // non-local symbol).
240226584Sdim    if (Base) {
241226584Sdim      Index = Base->getIndex();
242226584Sdim      IsExtern = 1;
243226584Sdim
244226584Sdim      // Add the local offset, if needed.
245226584Sdim      if (Base != &SD)
246226584Sdim        Value += Layout.getSymbolOffset(&SD) - Layout.getSymbolOffset(Base);
247226584Sdim    } else if (Symbol->isInSection() && !Symbol->isVariable()) {
248226584Sdim      // The index is the section ordinal (1-based).
249226584Sdim      Index = SD.getFragment()->getParent()->getOrdinal() + 1;
250226584Sdim      IsExtern = 0;
251226584Sdim      Value += Writer->getSymbolAddress(&SD, Layout);
252226584Sdim
253226584Sdim      if (IsPCRel)
254226584Sdim        Value -= FixupAddress + (1 << Log2Size);
255226584Sdim    } else if (Symbol->isVariable()) {
256226584Sdim      const MCExpr *Value = Symbol->getVariableValue();
257226584Sdim      int64_t Res;
258226584Sdim      bool isAbs = Value->EvaluateAsAbsolute(Res, Layout,
259226584Sdim                                             Writer->getSectionAddressMap());
260226584Sdim      if (isAbs) {
261226584Sdim        FixedValue = Res;
262226584Sdim        return;
263226584Sdim      } else {
264226584Sdim        report_fatal_error("unsupported relocation of variable '" +
265263508Sdim                           Symbol->getName() + "'", false);
266226584Sdim      }
267226584Sdim    } else {
268226584Sdim      report_fatal_error("unsupported relocation of undefined symbol '" +
269263508Sdim                         Symbol->getName() + "'", false);
270226584Sdim    }
271226584Sdim
272226584Sdim    MCSymbolRefExpr::VariantKind Modifier = Target.getSymA()->getKind();
273226584Sdim    if (IsPCRel) {
274226584Sdim      if (IsRIPRel) {
275226584Sdim        if (Modifier == MCSymbolRefExpr::VK_GOTPCREL) {
276226584Sdim          // x86_64 distinguishes movq foo@GOTPCREL so that the linker can
277226584Sdim          // rewrite the movq to an leaq at link time if the symbol ends up in
278226584Sdim          // the same linkage unit.
279226584Sdim          if (unsigned(Fixup.getKind()) == X86::reloc_riprel_4byte_movq_load)
280263508Sdim            Type = MachO::X86_64_RELOC_GOT_LOAD;
281226584Sdim          else
282263508Sdim            Type = MachO::X86_64_RELOC_GOT;
283226584Sdim        }  else if (Modifier == MCSymbolRefExpr::VK_TLVP) {
284263508Sdim          Type = MachO::X86_64_RELOC_TLV;
285226584Sdim        }  else if (Modifier != MCSymbolRefExpr::VK_None) {
286263508Sdim          report_fatal_error("unsupported symbol modifier in relocation",
287263508Sdim                             false);
288226584Sdim        } else {
289263508Sdim          Type = MachO::X86_64_RELOC_SIGNED;
290226584Sdim
291226584Sdim          // The Darwin x86_64 relocation format has a problem where it cannot
292226584Sdim          // encode an address (L<foo> + <constant>) which is outside the atom
293226584Sdim          // containing L<foo>. Generally, this shouldn't occur but it does
294226584Sdim          // happen when we have a RIPrel instruction with data following the
295226584Sdim          // relocation entry (e.g., movb $012, L0(%rip)). Even with the PCrel
296226584Sdim          // adjustment Darwin x86_64 uses, the offset is still negative and the
297226584Sdim          // linker has no way to recognize this.
298226584Sdim          //
299226584Sdim          // To work around this, Darwin uses several special relocation types
300226584Sdim          // to indicate the offsets. However, the specification or
301226584Sdim          // implementation of these seems to also be incomplete; they should
302226584Sdim          // adjust the addend as well based on the actual encoded instruction
303226584Sdim          // (the additional bias), but instead appear to just look at the final
304226584Sdim          // offset.
305226584Sdim          switch (-(Target.getConstant() + (1LL << Log2Size))) {
306263508Sdim          case 1: Type = MachO::X86_64_RELOC_SIGNED_1; break;
307263508Sdim          case 2: Type = MachO::X86_64_RELOC_SIGNED_2; break;
308263508Sdim          case 4: Type = MachO::X86_64_RELOC_SIGNED_4; break;
309226584Sdim          }
310226584Sdim        }
311226584Sdim      } else {
312226584Sdim        if (Modifier != MCSymbolRefExpr::VK_None)
313226584Sdim          report_fatal_error("unsupported symbol modifier in branch "
314263508Sdim                             "relocation", false);
315226584Sdim
316263508Sdim        Type = MachO::X86_64_RELOC_BRANCH;
317226584Sdim      }
318226584Sdim    } else {
319226584Sdim      if (Modifier == MCSymbolRefExpr::VK_GOT) {
320263508Sdim        Type = MachO::X86_64_RELOC_GOT;
321226584Sdim      } else if (Modifier == MCSymbolRefExpr::VK_GOTPCREL) {
322226584Sdim        // GOTPCREL is allowed as a modifier on non-PCrel instructions, in which
323226584Sdim        // case all we do is set the PCrel bit in the relocation entry; this is
324226584Sdim        // used with exception handling, for example. The source is required to
325226584Sdim        // include any necessary offset directly.
326263508Sdim        Type = MachO::X86_64_RELOC_GOT;
327226584Sdim        IsPCRel = 1;
328226584Sdim      } else if (Modifier == MCSymbolRefExpr::VK_TLVP) {
329263508Sdim        report_fatal_error("TLVP symbol modifier should have been rip-rel",
330263508Sdim                           false);
331226584Sdim      } else if (Modifier != MCSymbolRefExpr::VK_None)
332263508Sdim        report_fatal_error("unsupported symbol modifier in relocation", false);
333263508Sdim      else {
334263508Sdim        Type = MachO::X86_64_RELOC_UNSIGNED;
335263508Sdim        unsigned Kind = Fixup.getKind();
336263508Sdim        if (Kind == X86::reloc_signed_4byte)
337263508Sdim          report_fatal_error("32-bit absolute addressing is not supported in "
338263508Sdim                             "64-bit mode", false);
339263508Sdim      }
340226584Sdim    }
341226584Sdim  }
342226584Sdim
343226584Sdim  // x86_64 always writes custom values into the fixups.
344226584Sdim  FixedValue = Value;
345226584Sdim
346226584Sdim  // struct relocation_info (8 bytes)
347263508Sdim  MachO::any_relocation_info MRE;
348263508Sdim  MRE.r_word0 = FixupOffset;
349263508Sdim  MRE.r_word1 = ((Index     <<  0) |
350263508Sdim                 (IsPCRel   << 24) |
351263508Sdim                 (Log2Size  << 25) |
352263508Sdim                 (IsExtern  << 27) |
353263508Sdim                 (Type      << 28));
354226584Sdim  Writer->addRelocation(Fragment->getParent(), MRE);
355226584Sdim}
356226584Sdim
357243830Sdimbool X86MachObjectWriter::RecordScatteredRelocation(MachObjectWriter *Writer,
358226584Sdim                                                    const MCAssembler &Asm,
359226584Sdim                                                    const MCAsmLayout &Layout,
360226584Sdim                                                    const MCFragment *Fragment,
361226584Sdim                                                    const MCFixup &Fixup,
362226584Sdim                                                    MCValue Target,
363226584Sdim                                                    unsigned Log2Size,
364226584Sdim                                                    uint64_t &FixedValue) {
365226584Sdim  uint32_t FixupOffset = Layout.getFragmentOffset(Fragment)+Fixup.getOffset();
366226584Sdim  unsigned IsPCRel = Writer->isFixupKindPCRel(Asm, Fixup.getKind());
367263508Sdim  unsigned Type = MachO::GENERIC_RELOC_VANILLA;
368226584Sdim
369226584Sdim  // See <reloc.h>.
370226584Sdim  const MCSymbol *A = &Target.getSymA()->getSymbol();
371226584Sdim  MCSymbolData *A_SD = &Asm.getSymbolData(*A);
372226584Sdim
373226584Sdim  if (!A_SD->getFragment())
374226584Sdim    report_fatal_error("symbol '" + A->getName() +
375263508Sdim                       "' can not be undefined in a subtraction expression",
376263508Sdim                       false);
377226584Sdim
378226584Sdim  uint32_t Value = Writer->getSymbolAddress(A_SD, Layout);
379226584Sdim  uint64_t SecAddr = Writer->getSectionAddress(A_SD->getFragment()->getParent());
380226584Sdim  FixedValue += SecAddr;
381226584Sdim  uint32_t Value2 = 0;
382226584Sdim
383226584Sdim  if (const MCSymbolRefExpr *B = Target.getSymB()) {
384226584Sdim    MCSymbolData *B_SD = &Asm.getSymbolData(B->getSymbol());
385226584Sdim
386226584Sdim    if (!B_SD->getFragment())
387226584Sdim      report_fatal_error("symbol '" + B->getSymbol().getName() +
388263508Sdim                         "' can not be undefined in a subtraction expression",
389263508Sdim                         false);
390226584Sdim
391226584Sdim    // Select the appropriate difference relocation type.
392226584Sdim    //
393226584Sdim    // Note that there is no longer any semantic difference between these two
394226584Sdim    // relocation types from the linkers point of view, this is done solely for
395226584Sdim    // pedantic compatibility with 'as'.
396263508Sdim    Type = A_SD->isExternal() ? (unsigned)MachO::GENERIC_RELOC_SECTDIFF :
397263508Sdim      (unsigned)MachO::GENERIC_RELOC_LOCAL_SECTDIFF;
398226584Sdim    Value2 = Writer->getSymbolAddress(B_SD, Layout);
399226584Sdim    FixedValue -= Writer->getSectionAddress(B_SD->getFragment()->getParent());
400226584Sdim  }
401226584Sdim
402226584Sdim  // Relocations are written out in reverse order, so the PAIR comes first.
403263508Sdim  if (Type == MachO::GENERIC_RELOC_SECTDIFF ||
404263508Sdim      Type == MachO::GENERIC_RELOC_LOCAL_SECTDIFF) {
405243830Sdim    // If the offset is too large to fit in a scattered relocation,
406243830Sdim    // we're hosed. It's an unfortunate limitation of the MachO format.
407243830Sdim    if (FixupOffset > 0xffffff) {
408243830Sdim      char Buffer[32];
409243830Sdim      format("0x%x", FixupOffset).print(Buffer, sizeof(Buffer));
410243830Sdim      Asm.getContext().FatalError(Fixup.getLoc(),
411243830Sdim                         Twine("Section too large, can't encode "
412243830Sdim                                "r_address (") + Buffer +
413243830Sdim                         ") into 24 bits of scattered "
414243830Sdim                         "relocation entry.");
415243830Sdim      llvm_unreachable("fatal error returned?!");
416243830Sdim    }
417243830Sdim
418263508Sdim    MachO::any_relocation_info MRE;
419263508Sdim    MRE.r_word0 = ((0                         <<  0) | // r_address
420263508Sdim                   (MachO::GENERIC_RELOC_PAIR << 24) | // r_type
421263508Sdim                   (Log2Size                  << 28) |
422263508Sdim                   (IsPCRel                   << 30) |
423263508Sdim                   MachO::R_SCATTERED);
424263508Sdim    MRE.r_word1 = Value2;
425226584Sdim    Writer->addRelocation(Fragment->getParent(), MRE);
426243830Sdim  } else {
427243830Sdim    // If the offset is more than 24-bits, it won't fit in a scattered
428243830Sdim    // relocation offset field, so we fall back to using a non-scattered
429243830Sdim    // relocation. This is a bit risky, as if the offset reaches out of
430243830Sdim    // the block and the linker is doing scattered loading on this
431243830Sdim    // symbol, things can go badly.
432243830Sdim    //
433243830Sdim    // Required for 'as' compatibility.
434243830Sdim    if (FixupOffset > 0xffffff)
435243830Sdim      return false;
436226584Sdim  }
437226584Sdim
438263508Sdim  MachO::any_relocation_info MRE;
439263508Sdim  MRE.r_word0 = ((FixupOffset <<  0) |
440263508Sdim                 (Type        << 24) |
441263508Sdim                 (Log2Size    << 28) |
442263508Sdim                 (IsPCRel     << 30) |
443263508Sdim                 MachO::R_SCATTERED);
444263508Sdim  MRE.r_word1 = Value;
445226584Sdim  Writer->addRelocation(Fragment->getParent(), MRE);
446243830Sdim  return true;
447226584Sdim}
448226584Sdim
449226584Sdimvoid X86MachObjectWriter::RecordTLVPRelocation(MachObjectWriter *Writer,
450226584Sdim                                               const MCAssembler &Asm,
451226584Sdim                                               const MCAsmLayout &Layout,
452226584Sdim                                               const MCFragment *Fragment,
453226584Sdim                                               const MCFixup &Fixup,
454226584Sdim                                               MCValue Target,
455226584Sdim                                               uint64_t &FixedValue) {
456226584Sdim  assert(Target.getSymA()->getKind() == MCSymbolRefExpr::VK_TLVP &&
457226584Sdim         !is64Bit() &&
458226584Sdim         "Should only be called with a 32-bit TLVP relocation!");
459226584Sdim
460226584Sdim  unsigned Log2Size = getFixupKindLog2Size(Fixup.getKind());
461226584Sdim  uint32_t Value = Layout.getFragmentOffset(Fragment)+Fixup.getOffset();
462226584Sdim  unsigned IsPCRel = 0;
463226584Sdim
464226584Sdim  // Get the symbol data.
465226584Sdim  MCSymbolData *SD_A = &Asm.getSymbolData(Target.getSymA()->getSymbol());
466226584Sdim  unsigned Index = SD_A->getIndex();
467226584Sdim
468226584Sdim  // We're only going to have a second symbol in pic mode and it'll be a
469226584Sdim  // subtraction from the picbase. For 32-bit pic the addend is the difference
470226584Sdim  // between the picbase and the next address.  For 32-bit static the addend is
471226584Sdim  // zero.
472226584Sdim  if (Target.getSymB()) {
473226584Sdim    // If this is a subtraction then we're pcrel.
474226584Sdim    uint32_t FixupAddress =
475226584Sdim      Writer->getFragmentAddress(Fragment, Layout) + Fixup.getOffset();
476226584Sdim    MCSymbolData *SD_B = &Asm.getSymbolData(Target.getSymB()->getSymbol());
477226584Sdim    IsPCRel = 1;
478226584Sdim    FixedValue = (FixupAddress - Writer->getSymbolAddress(SD_B, Layout) +
479226584Sdim                  Target.getConstant());
480226584Sdim    FixedValue += 1ULL << Log2Size;
481226584Sdim  } else {
482226584Sdim    FixedValue = 0;
483226584Sdim  }
484226584Sdim
485226584Sdim  // struct relocation_info (8 bytes)
486263508Sdim  MachO::any_relocation_info MRE;
487263508Sdim  MRE.r_word0 = Value;
488263508Sdim  MRE.r_word1 = ((Index                    <<  0) |
489263508Sdim                 (IsPCRel                  << 24) |
490263508Sdim                 (Log2Size                 << 25) |
491263508Sdim                 (1                        << 27) | // r_extern
492263508Sdim                 (MachO::GENERIC_RELOC_TLV << 28)); // r_type
493226584Sdim  Writer->addRelocation(Fragment->getParent(), MRE);
494226584Sdim}
495226584Sdim
496226584Sdimvoid X86MachObjectWriter::RecordX86Relocation(MachObjectWriter *Writer,
497226584Sdim                                              const MCAssembler &Asm,
498226584Sdim                                              const MCAsmLayout &Layout,
499226584Sdim                                              const MCFragment *Fragment,
500226584Sdim                                              const MCFixup &Fixup,
501226584Sdim                                              MCValue Target,
502226584Sdim                                              uint64_t &FixedValue) {
503226584Sdim  unsigned IsPCRel = Writer->isFixupKindPCRel(Asm, Fixup.getKind());
504226584Sdim  unsigned Log2Size = getFixupKindLog2Size(Fixup.getKind());
505226584Sdim
506226584Sdim  // If this is a 32-bit TLVP reloc it's handled a bit differently.
507226584Sdim  if (Target.getSymA() &&
508226584Sdim      Target.getSymA()->getKind() == MCSymbolRefExpr::VK_TLVP) {
509226584Sdim    RecordTLVPRelocation(Writer, Asm, Layout, Fragment, Fixup, Target,
510226584Sdim                         FixedValue);
511226584Sdim    return;
512226584Sdim  }
513226584Sdim
514226584Sdim  // If this is a difference or a defined symbol plus an offset, then we need a
515226584Sdim  // scattered relocation entry. Differences always require scattered
516226584Sdim  // relocations.
517243830Sdim  if (Target.getSymB()) {
518243830Sdim    RecordScatteredRelocation(Writer, Asm, Layout, Fragment, Fixup,
519243830Sdim                              Target, Log2Size, FixedValue);
520243830Sdim    return;
521243830Sdim  }
522226584Sdim
523226584Sdim  // Get the symbol data, if any.
524226584Sdim  MCSymbolData *SD = 0;
525226584Sdim  if (Target.getSymA())
526226584Sdim    SD = &Asm.getSymbolData(Target.getSymA()->getSymbol());
527226584Sdim
528226584Sdim  // If this is an internal relocation with an offset, it also needs a scattered
529226584Sdim  // relocation entry.
530226584Sdim  uint32_t Offset = Target.getConstant();
531226584Sdim  if (IsPCRel)
532226584Sdim    Offset += 1 << Log2Size;
533243830Sdim  // Try to record the scattered relocation if needed. Fall back to non
534243830Sdim  // scattered if necessary (see comments in RecordScatteredRelocation()
535243830Sdim  // for details).
536243830Sdim  if (Offset && SD && !Writer->doesSymbolRequireExternRelocation(SD) &&
537243830Sdim      RecordScatteredRelocation(Writer, Asm, Layout, Fragment, Fixup,
538243830Sdim                                Target, Log2Size, FixedValue))
539243830Sdim    return;
540226584Sdim
541226584Sdim  // See <reloc.h>.
542226584Sdim  uint32_t FixupOffset = Layout.getFragmentOffset(Fragment)+Fixup.getOffset();
543226584Sdim  unsigned Index = 0;
544226584Sdim  unsigned IsExtern = 0;
545226584Sdim  unsigned Type = 0;
546226584Sdim
547226584Sdim  if (Target.isAbsolute()) { // constant
548226584Sdim    // SymbolNum of 0 indicates the absolute section.
549226584Sdim    //
550226584Sdim    // FIXME: Currently, these are never generated (see code below). I cannot
551226584Sdim    // find a case where they are actually emitted.
552263508Sdim    Type = MachO::GENERIC_RELOC_VANILLA;
553226584Sdim  } else {
554226584Sdim    // Resolve constant variables.
555226584Sdim    if (SD->getSymbol().isVariable()) {
556226584Sdim      int64_t Res;
557226584Sdim      if (SD->getSymbol().getVariableValue()->EvaluateAsAbsolute(
558226584Sdim            Res, Layout, Writer->getSectionAddressMap())) {
559226584Sdim        FixedValue = Res;
560226584Sdim        return;
561226584Sdim      }
562226584Sdim    }
563226584Sdim
564226584Sdim    // Check whether we need an external or internal relocation.
565226584Sdim    if (Writer->doesSymbolRequireExternRelocation(SD)) {
566226584Sdim      IsExtern = 1;
567226584Sdim      Index = SD->getIndex();
568226584Sdim      // For external relocations, make sure to offset the fixup value to
569226584Sdim      // compensate for the addend of the symbol address, if it was
570226584Sdim      // undefined. This occurs with weak definitions, for example.
571226584Sdim      if (!SD->Symbol->isUndefined())
572226584Sdim        FixedValue -= Layout.getSymbolOffset(SD);
573226584Sdim    } else {
574226584Sdim      // The index is the section ordinal (1-based).
575226584Sdim      const MCSectionData &SymSD = Asm.getSectionData(
576226584Sdim        SD->getSymbol().getSection());
577226584Sdim      Index = SymSD.getOrdinal() + 1;
578226584Sdim      FixedValue += Writer->getSectionAddress(&SymSD);
579226584Sdim    }
580226584Sdim    if (IsPCRel)
581226584Sdim      FixedValue -= Writer->getSectionAddress(Fragment->getParent());
582226584Sdim
583263508Sdim    Type = MachO::GENERIC_RELOC_VANILLA;
584226584Sdim  }
585226584Sdim
586226584Sdim  // struct relocation_info (8 bytes)
587263508Sdim  MachO::any_relocation_info MRE;
588263508Sdim  MRE.r_word0 = FixupOffset;
589263508Sdim  MRE.r_word1 = ((Index     <<  0) |
590263508Sdim                 (IsPCRel   << 24) |
591263508Sdim                 (Log2Size  << 25) |
592263508Sdim                 (IsExtern  << 27) |
593263508Sdim                 (Type      << 28));
594226584Sdim  Writer->addRelocation(Fragment->getParent(), MRE);
595226584Sdim}
596226584Sdim
597226584SdimMCObjectWriter *llvm::createX86MachObjectWriter(raw_ostream &OS,
598226584Sdim                                                bool Is64Bit,
599226584Sdim                                                uint32_t CPUType,
600226584Sdim                                                uint32_t CPUSubtype) {
601226584Sdim  return createMachObjectWriter(new X86MachObjectWriter(Is64Bit,
602226584Sdim                                                        CPUType,
603226584Sdim                                                        CPUSubtype),
604226584Sdim                                OS, /*IsLittleEndian=*/true);
605226584Sdim}
606