xref: /openbsd-src/gnu/llvm/llvm/lib/Target/X86/MCTargetDesc/X86MachObjectWriter.cpp (revision 73471bf04ceb096474c7f0fa83b1b65c70a787a1)
109467b48Spatrick //===-- X86MachObjectWriter.cpp - X86 Mach-O Writer -----------------------===//
209467b48Spatrick //
309467b48Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
409467b48Spatrick // See https://llvm.org/LICENSE.txt for license information.
509467b48Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
609467b48Spatrick //
709467b48Spatrick //===----------------------------------------------------------------------===//
809467b48Spatrick 
909467b48Spatrick #include "MCTargetDesc/X86FixupKinds.h"
1009467b48Spatrick #include "MCTargetDesc/X86MCTargetDesc.h"
1109467b48Spatrick #include "llvm/ADT/Twine.h"
1209467b48Spatrick #include "llvm/BinaryFormat/MachO.h"
1309467b48Spatrick #include "llvm/MC/MCAsmInfo.h"
1409467b48Spatrick #include "llvm/MC/MCAsmLayout.h"
1509467b48Spatrick #include "llvm/MC/MCAssembler.h"
1609467b48Spatrick #include "llvm/MC/MCContext.h"
1709467b48Spatrick #include "llvm/MC/MCMachObjectWriter.h"
1809467b48Spatrick #include "llvm/MC/MCSectionMachO.h"
1909467b48Spatrick #include "llvm/MC/MCValue.h"
2009467b48Spatrick #include "llvm/Support/ErrorHandling.h"
2109467b48Spatrick #include "llvm/Support/Format.h"
2209467b48Spatrick 
2309467b48Spatrick using namespace llvm;
2409467b48Spatrick 
2509467b48Spatrick namespace {
2609467b48Spatrick class X86MachObjectWriter : public MCMachObjectTargetWriter {
2709467b48Spatrick   bool recordScatteredRelocation(MachObjectWriter *Writer,
2809467b48Spatrick                                  const MCAssembler &Asm,
2909467b48Spatrick                                  const MCAsmLayout &Layout,
3009467b48Spatrick                                  const MCFragment *Fragment,
3109467b48Spatrick                                  const MCFixup &Fixup,
3209467b48Spatrick                                  MCValue Target,
3309467b48Spatrick                                  unsigned Log2Size,
3409467b48Spatrick                                  uint64_t &FixedValue);
3509467b48Spatrick   void recordTLVPRelocation(MachObjectWriter *Writer,
3609467b48Spatrick                             const MCAssembler &Asm,
3709467b48Spatrick                             const MCAsmLayout &Layout,
3809467b48Spatrick                             const MCFragment *Fragment,
3909467b48Spatrick                             const MCFixup &Fixup,
4009467b48Spatrick                             MCValue Target,
4109467b48Spatrick                             uint64_t &FixedValue);
4209467b48Spatrick 
4309467b48Spatrick   void RecordX86Relocation(MachObjectWriter *Writer,
4409467b48Spatrick                               const MCAssembler &Asm,
4509467b48Spatrick                               const MCAsmLayout &Layout,
4609467b48Spatrick                               const MCFragment *Fragment,
4709467b48Spatrick                               const MCFixup &Fixup,
4809467b48Spatrick                               MCValue Target,
4909467b48Spatrick                               uint64_t &FixedValue);
5009467b48Spatrick   void RecordX86_64Relocation(MachObjectWriter *Writer, MCAssembler &Asm,
5109467b48Spatrick                               const MCAsmLayout &Layout,
5209467b48Spatrick                               const MCFragment *Fragment, const MCFixup &Fixup,
5309467b48Spatrick                               MCValue Target, uint64_t &FixedValue);
5409467b48Spatrick 
5509467b48Spatrick public:
X86MachObjectWriter(bool Is64Bit,uint32_t CPUType,uint32_t CPUSubtype)5609467b48Spatrick   X86MachObjectWriter(bool Is64Bit, uint32_t CPUType, uint32_t CPUSubtype)
5709467b48Spatrick       : MCMachObjectTargetWriter(Is64Bit, CPUType, CPUSubtype) {}
5809467b48Spatrick 
recordRelocation(MachObjectWriter * Writer,MCAssembler & Asm,const MCAsmLayout & Layout,const MCFragment * Fragment,const MCFixup & Fixup,MCValue Target,uint64_t & FixedValue)5909467b48Spatrick   void recordRelocation(MachObjectWriter *Writer, MCAssembler &Asm,
6009467b48Spatrick                         const MCAsmLayout &Layout, const MCFragment *Fragment,
6109467b48Spatrick                         const MCFixup &Fixup, MCValue Target,
6209467b48Spatrick                         uint64_t &FixedValue) override {
6309467b48Spatrick     if (Writer->is64Bit())
6409467b48Spatrick       RecordX86_64Relocation(Writer, Asm, Layout, Fragment, Fixup, Target,
6509467b48Spatrick                              FixedValue);
6609467b48Spatrick     else
6709467b48Spatrick       RecordX86Relocation(Writer, Asm, Layout, Fragment, Fixup, Target,
6809467b48Spatrick                           FixedValue);
6909467b48Spatrick   }
7009467b48Spatrick };
71*73471bf0Spatrick } // namespace
7209467b48Spatrick 
isFixupKindRIPRel(unsigned Kind)7309467b48Spatrick static bool isFixupKindRIPRel(unsigned Kind) {
7409467b48Spatrick   return Kind == X86::reloc_riprel_4byte ||
7509467b48Spatrick          Kind == X86::reloc_riprel_4byte_movq_load ||
7609467b48Spatrick          Kind == X86::reloc_riprel_4byte_relax ||
7709467b48Spatrick          Kind == X86::reloc_riprel_4byte_relax_rex;
7809467b48Spatrick }
7909467b48Spatrick 
getFixupKindLog2Size(unsigned Kind)8009467b48Spatrick static unsigned getFixupKindLog2Size(unsigned Kind) {
8109467b48Spatrick   switch (Kind) {
8209467b48Spatrick   default:
8309467b48Spatrick     llvm_unreachable("invalid fixup kind!");
8409467b48Spatrick   case FK_PCRel_1:
8509467b48Spatrick   case FK_Data_1: return 0;
8609467b48Spatrick   case FK_PCRel_2:
8709467b48Spatrick   case FK_Data_2: return 1;
8809467b48Spatrick   case FK_PCRel_4:
8909467b48Spatrick     // FIXME: Remove these!!!
9009467b48Spatrick   case X86::reloc_riprel_4byte:
9109467b48Spatrick   case X86::reloc_riprel_4byte_relax:
9209467b48Spatrick   case X86::reloc_riprel_4byte_relax_rex:
9309467b48Spatrick   case X86::reloc_riprel_4byte_movq_load:
9409467b48Spatrick   case X86::reloc_signed_4byte:
9509467b48Spatrick   case X86::reloc_signed_4byte_relax:
9609467b48Spatrick   case X86::reloc_branch_4byte_pcrel:
9709467b48Spatrick   case FK_Data_4: return 2;
9809467b48Spatrick   case FK_Data_8: return 3;
9909467b48Spatrick   }
10009467b48Spatrick }
10109467b48Spatrick 
RecordX86_64Relocation(MachObjectWriter * Writer,MCAssembler & Asm,const MCAsmLayout & Layout,const MCFragment * Fragment,const MCFixup & Fixup,MCValue Target,uint64_t & FixedValue)10209467b48Spatrick void X86MachObjectWriter::RecordX86_64Relocation(
10309467b48Spatrick     MachObjectWriter *Writer, MCAssembler &Asm, const MCAsmLayout &Layout,
10409467b48Spatrick     const MCFragment *Fragment, const MCFixup &Fixup, MCValue Target,
10509467b48Spatrick     uint64_t &FixedValue) {
10609467b48Spatrick   unsigned IsPCRel = Writer->isFixupKindPCRel(Asm, Fixup.getKind());
10709467b48Spatrick   unsigned IsRIPRel = isFixupKindRIPRel(Fixup.getKind());
10809467b48Spatrick   unsigned Log2Size = getFixupKindLog2Size(Fixup.getKind());
10909467b48Spatrick 
11009467b48Spatrick   // See <reloc.h>.
11109467b48Spatrick   uint32_t FixupOffset =
11209467b48Spatrick     Layout.getFragmentOffset(Fragment) + Fixup.getOffset();
11309467b48Spatrick   uint32_t FixupAddress =
11409467b48Spatrick     Writer->getFragmentAddress(Fragment, Layout) + Fixup.getOffset();
11509467b48Spatrick   int64_t Value = 0;
11609467b48Spatrick   unsigned Index = 0;
11709467b48Spatrick   unsigned IsExtern = 0;
11809467b48Spatrick   unsigned Type = 0;
11909467b48Spatrick   const MCSymbol *RelSymbol = nullptr;
12009467b48Spatrick 
12109467b48Spatrick   Value = Target.getConstant();
12209467b48Spatrick 
12309467b48Spatrick   if (IsPCRel) {
12409467b48Spatrick     // Compensate for the relocation offset, Darwin x86_64 relocations only have
12509467b48Spatrick     // the addend and appear to have attempted to define it to be the actual
12609467b48Spatrick     // expression addend without the PCrel bias. However, instructions with data
12709467b48Spatrick     // following the relocation are not accommodated for (see comment below
12809467b48Spatrick     // regarding SIGNED{1,2,4}), so it isn't exactly that either.
12909467b48Spatrick     Value += 1LL << Log2Size;
13009467b48Spatrick   }
13109467b48Spatrick 
13209467b48Spatrick   if (Target.isAbsolute()) { // constant
13309467b48Spatrick     // SymbolNum of 0 indicates the absolute section.
13409467b48Spatrick     Type = MachO::X86_64_RELOC_UNSIGNED;
13509467b48Spatrick 
13609467b48Spatrick     // FIXME: I believe this is broken, I don't think the linker can understand
13709467b48Spatrick     // it. I think it would require a local relocation, but I'm not sure if that
13809467b48Spatrick     // would work either. The official way to get an absolute PCrel relocation
13909467b48Spatrick     // is to use an absolute symbol (which we don't support yet).
14009467b48Spatrick     if (IsPCRel) {
14109467b48Spatrick       IsExtern = 1;
14209467b48Spatrick       Type = MachO::X86_64_RELOC_BRANCH;
14309467b48Spatrick     }
14409467b48Spatrick   } else if (Target.getSymB()) { // A - B + constant
14509467b48Spatrick     const MCSymbol *A = &Target.getSymA()->getSymbol();
14609467b48Spatrick     if (A->isTemporary())
14709467b48Spatrick       A = &Writer->findAliasedSymbol(*A);
14809467b48Spatrick     const MCSymbol *A_Base = Asm.getAtom(*A);
14909467b48Spatrick 
15009467b48Spatrick     const MCSymbol *B = &Target.getSymB()->getSymbol();
15109467b48Spatrick     if (B->isTemporary())
15209467b48Spatrick       B = &Writer->findAliasedSymbol(*B);
15309467b48Spatrick     const MCSymbol *B_Base = Asm.getAtom(*B);
15409467b48Spatrick 
15509467b48Spatrick     // Neither symbol can be modified.
15609467b48Spatrick     if (Target.getSymA()->getKind() != MCSymbolRefExpr::VK_None) {
15709467b48Spatrick       Asm.getContext().reportError(Fixup.getLoc(),
15809467b48Spatrick                                    "unsupported relocation of modified symbol");
15909467b48Spatrick       return;
16009467b48Spatrick     }
16109467b48Spatrick 
16209467b48Spatrick     // We don't support PCrel relocations of differences. Darwin 'as' doesn't
16309467b48Spatrick     // implement most of these correctly.
16409467b48Spatrick     if (IsPCRel) {
16509467b48Spatrick       Asm.getContext().reportError(
16609467b48Spatrick           Fixup.getLoc(), "unsupported pc-relative relocation of difference");
16709467b48Spatrick       return;
16809467b48Spatrick     }
16909467b48Spatrick 
17009467b48Spatrick     // The support for the situation where one or both of the symbols would
17109467b48Spatrick     // require a local relocation is handled just like if the symbols were
17209467b48Spatrick     // external.  This is certainly used in the case of debug sections where the
17309467b48Spatrick     // section has only temporary symbols and thus the symbols don't have base
17409467b48Spatrick     // symbols.  This is encoded using the section ordinal and non-extern
17509467b48Spatrick     // relocation entries.
17609467b48Spatrick 
17709467b48Spatrick     // Darwin 'as' doesn't emit correct relocations for this (it ends up with a
17809467b48Spatrick     // single SIGNED relocation); reject it for now.  Except the case where both
17909467b48Spatrick     // symbols don't have a base, equal but both NULL.
18009467b48Spatrick     if (A_Base == B_Base && A_Base) {
18109467b48Spatrick       Asm.getContext().reportError(
18209467b48Spatrick           Fixup.getLoc(), "unsupported relocation with identical base");
18309467b48Spatrick       return;
18409467b48Spatrick     }
18509467b48Spatrick 
18609467b48Spatrick     // A subtraction expression where either symbol is undefined is a
18709467b48Spatrick     // non-relocatable expression.
18809467b48Spatrick     if (A->isUndefined() || B->isUndefined()) {
18909467b48Spatrick       StringRef Name = A->isUndefined() ? A->getName() : B->getName();
19009467b48Spatrick       Asm.getContext().reportError(Fixup.getLoc(),
19109467b48Spatrick         "unsupported relocation with subtraction expression, symbol '" +
19209467b48Spatrick         Name + "' can not be undefined in a subtraction expression");
19309467b48Spatrick       return;
19409467b48Spatrick     }
19509467b48Spatrick 
19609467b48Spatrick     Value += Writer->getSymbolAddress(*A, Layout) -
19709467b48Spatrick              (!A_Base ? 0 : Writer->getSymbolAddress(*A_Base, Layout));
19809467b48Spatrick     Value -= Writer->getSymbolAddress(*B, Layout) -
19909467b48Spatrick              (!B_Base ? 0 : Writer->getSymbolAddress(*B_Base, Layout));
20009467b48Spatrick 
20109467b48Spatrick     if (!A_Base)
20209467b48Spatrick       Index = A->getFragment()->getParent()->getOrdinal() + 1;
20309467b48Spatrick     Type = MachO::X86_64_RELOC_UNSIGNED;
20409467b48Spatrick 
20509467b48Spatrick     MachO::any_relocation_info MRE;
20609467b48Spatrick     MRE.r_word0 = FixupOffset;
20709467b48Spatrick     MRE.r_word1 =
20809467b48Spatrick         (Index << 0) | (IsPCRel << 24) | (Log2Size << 25) | (Type << 28);
20909467b48Spatrick     Writer->addRelocation(A_Base, Fragment->getParent(), MRE);
21009467b48Spatrick 
21109467b48Spatrick     if (B_Base)
21209467b48Spatrick       RelSymbol = B_Base;
21309467b48Spatrick     else
21409467b48Spatrick       Index = B->getFragment()->getParent()->getOrdinal() + 1;
21509467b48Spatrick     Type = MachO::X86_64_RELOC_SUBTRACTOR;
21609467b48Spatrick   } else {
21709467b48Spatrick     const MCSymbol *Symbol = &Target.getSymA()->getSymbol();
21809467b48Spatrick     if (Symbol->isTemporary() && Value) {
21909467b48Spatrick       const MCSection &Sec = Symbol->getSection();
22009467b48Spatrick       if (!Asm.getContext().getAsmInfo()->isSectionAtomizableBySymbols(Sec))
22109467b48Spatrick         Symbol->setUsedInReloc();
22209467b48Spatrick     }
22309467b48Spatrick     RelSymbol = Asm.getAtom(*Symbol);
22409467b48Spatrick 
22509467b48Spatrick     // Relocations inside debug sections always use local relocations when
22609467b48Spatrick     // possible. This seems to be done because the debugger doesn't fully
22709467b48Spatrick     // understand x86_64 relocation entries, and expects to find values that
22809467b48Spatrick     // have already been fixed up.
22909467b48Spatrick     if (Symbol->isInSection()) {
23009467b48Spatrick       const MCSectionMachO &Section =
23109467b48Spatrick           static_cast<const MCSectionMachO &>(*Fragment->getParent());
23209467b48Spatrick       if (Section.hasAttribute(MachO::S_ATTR_DEBUG))
23309467b48Spatrick         RelSymbol = nullptr;
23409467b48Spatrick     }
23509467b48Spatrick 
23609467b48Spatrick     // x86_64 almost always uses external relocations, except when there is no
23709467b48Spatrick     // symbol to use as a base address (a local symbol with no preceding
23809467b48Spatrick     // non-local symbol).
23909467b48Spatrick     if (RelSymbol) {
24009467b48Spatrick       // Add the local offset, if needed.
24109467b48Spatrick       if (RelSymbol != Symbol)
24209467b48Spatrick         Value += Layout.getSymbolOffset(*Symbol) -
24309467b48Spatrick                  Layout.getSymbolOffset(*RelSymbol);
24409467b48Spatrick     } else if (Symbol->isInSection() && !Symbol->isVariable()) {
24509467b48Spatrick       // The index is the section ordinal (1-based).
24609467b48Spatrick       Index = Symbol->getFragment()->getParent()->getOrdinal() + 1;
24709467b48Spatrick       Value += Writer->getSymbolAddress(*Symbol, Layout);
24809467b48Spatrick 
24909467b48Spatrick       if (IsPCRel)
25009467b48Spatrick         Value -= FixupAddress + (1 << Log2Size);
25109467b48Spatrick     } else if (Symbol->isVariable()) {
25209467b48Spatrick       const MCExpr *Value = Symbol->getVariableValue();
25309467b48Spatrick       int64_t Res;
25409467b48Spatrick       bool isAbs = Value->evaluateAsAbsolute(Res, Layout,
25509467b48Spatrick                                              Writer->getSectionAddressMap());
25609467b48Spatrick       if (isAbs) {
25709467b48Spatrick         FixedValue = Res;
25809467b48Spatrick         return;
25909467b48Spatrick       } else {
26009467b48Spatrick         Asm.getContext().reportError(Fixup.getLoc(),
26109467b48Spatrick                                      "unsupported relocation of variable '" +
26209467b48Spatrick                                          Symbol->getName() + "'");
26309467b48Spatrick         return;
26409467b48Spatrick       }
26509467b48Spatrick     } else {
26609467b48Spatrick       Asm.getContext().reportError(
26709467b48Spatrick           Fixup.getLoc(), "unsupported relocation of undefined symbol '" +
26809467b48Spatrick                               Symbol->getName() + "'");
26909467b48Spatrick       return;
27009467b48Spatrick     }
27109467b48Spatrick 
27209467b48Spatrick     MCSymbolRefExpr::VariantKind Modifier = Target.getSymA()->getKind();
27309467b48Spatrick     if (IsPCRel) {
27409467b48Spatrick       if (IsRIPRel) {
27509467b48Spatrick         if (Modifier == MCSymbolRefExpr::VK_GOTPCREL) {
27609467b48Spatrick           // x86_64 distinguishes movq foo@GOTPCREL so that the linker can
27709467b48Spatrick           // rewrite the movq to an leaq at link time if the symbol ends up in
27809467b48Spatrick           // the same linkage unit.
27909467b48Spatrick           if (Fixup.getTargetKind() == X86::reloc_riprel_4byte_movq_load)
28009467b48Spatrick             Type = MachO::X86_64_RELOC_GOT_LOAD;
28109467b48Spatrick           else
28209467b48Spatrick             Type = MachO::X86_64_RELOC_GOT;
28309467b48Spatrick         }  else if (Modifier == MCSymbolRefExpr::VK_TLVP) {
28409467b48Spatrick           Type = MachO::X86_64_RELOC_TLV;
28509467b48Spatrick         }  else if (Modifier != MCSymbolRefExpr::VK_None) {
28609467b48Spatrick           Asm.getContext().reportError(
28709467b48Spatrick               Fixup.getLoc(), "unsupported symbol modifier in relocation");
28809467b48Spatrick           return;
28909467b48Spatrick         } else {
29009467b48Spatrick           Type = MachO::X86_64_RELOC_SIGNED;
29109467b48Spatrick 
29209467b48Spatrick           // The Darwin x86_64 relocation format has a problem where it cannot
29309467b48Spatrick           // encode an address (L<foo> + <constant>) which is outside the atom
29409467b48Spatrick           // containing L<foo>. Generally, this shouldn't occur but it does
29509467b48Spatrick           // happen when we have a RIPrel instruction with data following the
29609467b48Spatrick           // relocation entry (e.g., movb $012, L0(%rip)). Even with the PCrel
29709467b48Spatrick           // adjustment Darwin x86_64 uses, the offset is still negative and the
29809467b48Spatrick           // linker has no way to recognize this.
29909467b48Spatrick           //
30009467b48Spatrick           // To work around this, Darwin uses several special relocation types
30109467b48Spatrick           // to indicate the offsets. However, the specification or
30209467b48Spatrick           // implementation of these seems to also be incomplete; they should
30309467b48Spatrick           // adjust the addend as well based on the actual encoded instruction
30409467b48Spatrick           // (the additional bias), but instead appear to just look at the final
30509467b48Spatrick           // offset.
30609467b48Spatrick           switch (-(Target.getConstant() + (1LL << Log2Size))) {
30709467b48Spatrick           case 1: Type = MachO::X86_64_RELOC_SIGNED_1; break;
30809467b48Spatrick           case 2: Type = MachO::X86_64_RELOC_SIGNED_2; break;
30909467b48Spatrick           case 4: Type = MachO::X86_64_RELOC_SIGNED_4; break;
31009467b48Spatrick           }
31109467b48Spatrick         }
31209467b48Spatrick       } else {
31309467b48Spatrick         if (Modifier != MCSymbolRefExpr::VK_None) {
31409467b48Spatrick           Asm.getContext().reportError(
31509467b48Spatrick               Fixup.getLoc(),
31609467b48Spatrick               "unsupported symbol modifier in branch relocation");
31709467b48Spatrick           return;
31809467b48Spatrick         }
31909467b48Spatrick 
32009467b48Spatrick         Type = MachO::X86_64_RELOC_BRANCH;
32109467b48Spatrick       }
32209467b48Spatrick     } else {
32309467b48Spatrick       if (Modifier == MCSymbolRefExpr::VK_GOT) {
32409467b48Spatrick         Type = MachO::X86_64_RELOC_GOT;
32509467b48Spatrick       } else if (Modifier == MCSymbolRefExpr::VK_GOTPCREL) {
32609467b48Spatrick         // GOTPCREL is allowed as a modifier on non-PCrel instructions, in which
32709467b48Spatrick         // case all we do is set the PCrel bit in the relocation entry; this is
32809467b48Spatrick         // used with exception handling, for example. The source is required to
32909467b48Spatrick         // include any necessary offset directly.
33009467b48Spatrick         Type = MachO::X86_64_RELOC_GOT;
33109467b48Spatrick         IsPCRel = 1;
33209467b48Spatrick       } else if (Modifier == MCSymbolRefExpr::VK_TLVP) {
33309467b48Spatrick         Asm.getContext().reportError(
33409467b48Spatrick             Fixup.getLoc(), "TLVP symbol modifier should have been rip-rel");
33509467b48Spatrick         return;
33609467b48Spatrick       } else if (Modifier != MCSymbolRefExpr::VK_None) {
33709467b48Spatrick         Asm.getContext().reportError(
33809467b48Spatrick             Fixup.getLoc(), "unsupported symbol modifier in relocation");
33909467b48Spatrick         return;
34009467b48Spatrick       } else {
34109467b48Spatrick         Type = MachO::X86_64_RELOC_UNSIGNED;
34209467b48Spatrick         if (Fixup.getTargetKind() == X86::reloc_signed_4byte) {
34309467b48Spatrick           Asm.getContext().reportError(
34409467b48Spatrick               Fixup.getLoc(),
34509467b48Spatrick               "32-bit absolute addressing is not supported in 64-bit mode");
34609467b48Spatrick           return;
34709467b48Spatrick         }
34809467b48Spatrick       }
34909467b48Spatrick     }
35009467b48Spatrick   }
35109467b48Spatrick 
35209467b48Spatrick   // x86_64 always writes custom values into the fixups.
35309467b48Spatrick   FixedValue = Value;
35409467b48Spatrick 
35509467b48Spatrick   // struct relocation_info (8 bytes)
35609467b48Spatrick   MachO::any_relocation_info MRE;
35709467b48Spatrick   MRE.r_word0 = FixupOffset;
35809467b48Spatrick   MRE.r_word1 = (Index << 0) | (IsPCRel << 24) | (Log2Size << 25) |
35909467b48Spatrick                 (IsExtern << 27) | (Type << 28);
36009467b48Spatrick   Writer->addRelocation(RelSymbol, Fragment->getParent(), MRE);
36109467b48Spatrick }
36209467b48Spatrick 
recordScatteredRelocation(MachObjectWriter * Writer,const MCAssembler & Asm,const MCAsmLayout & Layout,const MCFragment * Fragment,const MCFixup & Fixup,MCValue Target,unsigned Log2Size,uint64_t & FixedValue)36309467b48Spatrick bool X86MachObjectWriter::recordScatteredRelocation(MachObjectWriter *Writer,
36409467b48Spatrick                                                     const MCAssembler &Asm,
36509467b48Spatrick                                                     const MCAsmLayout &Layout,
36609467b48Spatrick                                                     const MCFragment *Fragment,
36709467b48Spatrick                                                     const MCFixup &Fixup,
36809467b48Spatrick                                                     MCValue Target,
36909467b48Spatrick                                                     unsigned Log2Size,
37009467b48Spatrick                                                     uint64_t &FixedValue) {
37109467b48Spatrick   uint64_t OriginalFixedValue = FixedValue;
37209467b48Spatrick   uint32_t FixupOffset = Layout.getFragmentOffset(Fragment)+Fixup.getOffset();
37309467b48Spatrick   unsigned IsPCRel = Writer->isFixupKindPCRel(Asm, Fixup.getKind());
37409467b48Spatrick   unsigned Type = MachO::GENERIC_RELOC_VANILLA;
37509467b48Spatrick 
37609467b48Spatrick   // See <reloc.h>.
37709467b48Spatrick   const MCSymbol *A = &Target.getSymA()->getSymbol();
37809467b48Spatrick 
37909467b48Spatrick   if (!A->getFragment()) {
38009467b48Spatrick     Asm.getContext().reportError(
38109467b48Spatrick         Fixup.getLoc(),
38209467b48Spatrick         "symbol '" + A->getName() +
38309467b48Spatrick             "' can not be undefined in a subtraction expression");
38409467b48Spatrick     return false;
38509467b48Spatrick   }
38609467b48Spatrick 
38709467b48Spatrick   uint32_t Value = Writer->getSymbolAddress(*A, Layout);
38809467b48Spatrick   uint64_t SecAddr = Writer->getSectionAddress(A->getFragment()->getParent());
38909467b48Spatrick   FixedValue += SecAddr;
39009467b48Spatrick   uint32_t Value2 = 0;
39109467b48Spatrick 
39209467b48Spatrick   if (const MCSymbolRefExpr *B = Target.getSymB()) {
39309467b48Spatrick     const MCSymbol *SB = &B->getSymbol();
39409467b48Spatrick 
39509467b48Spatrick     if (!SB->getFragment()) {
39609467b48Spatrick       Asm.getContext().reportError(
39709467b48Spatrick           Fixup.getLoc(),
39809467b48Spatrick           "symbol '" + SB->getName() +
39909467b48Spatrick               "' can not be undefined in a subtraction expression");
40009467b48Spatrick       return false;
40109467b48Spatrick     }
40209467b48Spatrick 
40309467b48Spatrick     // Select the appropriate difference relocation type.
40409467b48Spatrick     //
40509467b48Spatrick     // Note that there is no longer any semantic difference between these two
40609467b48Spatrick     // relocation types from the linkers point of view, this is done solely for
40709467b48Spatrick     // pedantic compatibility with 'as'.
40809467b48Spatrick     Type = A->isExternal() ? (unsigned)MachO::GENERIC_RELOC_SECTDIFF
40909467b48Spatrick                            : (unsigned)MachO::GENERIC_RELOC_LOCAL_SECTDIFF;
41009467b48Spatrick     Value2 = Writer->getSymbolAddress(*SB, Layout);
41109467b48Spatrick     FixedValue -= Writer->getSectionAddress(SB->getFragment()->getParent());
41209467b48Spatrick   }
41309467b48Spatrick 
41409467b48Spatrick   // Relocations are written out in reverse order, so the PAIR comes first.
41509467b48Spatrick   if (Type == MachO::GENERIC_RELOC_SECTDIFF ||
41609467b48Spatrick       Type == MachO::GENERIC_RELOC_LOCAL_SECTDIFF) {
41709467b48Spatrick     // If the offset is too large to fit in a scattered relocation,
41809467b48Spatrick     // we're hosed. It's an unfortunate limitation of the MachO format.
41909467b48Spatrick     if (FixupOffset > 0xffffff) {
42009467b48Spatrick       char Buffer[32];
42109467b48Spatrick       format("0x%x", FixupOffset).print(Buffer, sizeof(Buffer));
42209467b48Spatrick       Asm.getContext().reportError(Fixup.getLoc(),
42309467b48Spatrick                          Twine("Section too large, can't encode "
42409467b48Spatrick                                 "r_address (") + Buffer +
42509467b48Spatrick                          ") into 24 bits of scattered "
42609467b48Spatrick                          "relocation entry.");
42709467b48Spatrick       return false;
42809467b48Spatrick     }
42909467b48Spatrick 
43009467b48Spatrick     MachO::any_relocation_info MRE;
43109467b48Spatrick     MRE.r_word0 = ((0                         <<  0) | // r_address
43209467b48Spatrick                    (MachO::GENERIC_RELOC_PAIR << 24) | // r_type
43309467b48Spatrick                    (Log2Size                  << 28) |
43409467b48Spatrick                    (IsPCRel                   << 30) |
43509467b48Spatrick                    MachO::R_SCATTERED);
43609467b48Spatrick     MRE.r_word1 = Value2;
43709467b48Spatrick     Writer->addRelocation(nullptr, Fragment->getParent(), MRE);
43809467b48Spatrick   } else {
43909467b48Spatrick     // If the offset is more than 24-bits, it won't fit in a scattered
44009467b48Spatrick     // relocation offset field, so we fall back to using a non-scattered
44109467b48Spatrick     // relocation. This is a bit risky, as if the offset reaches out of
44209467b48Spatrick     // the block and the linker is doing scattered loading on this
44309467b48Spatrick     // symbol, things can go badly.
44409467b48Spatrick     //
44509467b48Spatrick     // Required for 'as' compatibility.
44609467b48Spatrick     if (FixupOffset > 0xffffff) {
44709467b48Spatrick       FixedValue = OriginalFixedValue;
44809467b48Spatrick       return false;
44909467b48Spatrick     }
45009467b48Spatrick   }
45109467b48Spatrick 
45209467b48Spatrick   MachO::any_relocation_info MRE;
45309467b48Spatrick   MRE.r_word0 = ((FixupOffset <<  0) |
45409467b48Spatrick                  (Type        << 24) |
45509467b48Spatrick                  (Log2Size    << 28) |
45609467b48Spatrick                  (IsPCRel     << 30) |
45709467b48Spatrick                  MachO::R_SCATTERED);
45809467b48Spatrick   MRE.r_word1 = Value;
45909467b48Spatrick   Writer->addRelocation(nullptr, Fragment->getParent(), MRE);
46009467b48Spatrick   return true;
46109467b48Spatrick }
46209467b48Spatrick 
recordTLVPRelocation(MachObjectWriter * Writer,const MCAssembler & Asm,const MCAsmLayout & Layout,const MCFragment * Fragment,const MCFixup & Fixup,MCValue Target,uint64_t & FixedValue)46309467b48Spatrick void X86MachObjectWriter::recordTLVPRelocation(MachObjectWriter *Writer,
46409467b48Spatrick                                                const MCAssembler &Asm,
46509467b48Spatrick                                                const MCAsmLayout &Layout,
46609467b48Spatrick                                                const MCFragment *Fragment,
46709467b48Spatrick                                                const MCFixup &Fixup,
46809467b48Spatrick                                                MCValue Target,
46909467b48Spatrick                                                uint64_t &FixedValue) {
47009467b48Spatrick   const MCSymbolRefExpr *SymA = Target.getSymA();
47109467b48Spatrick   assert(SymA->getKind() == MCSymbolRefExpr::VK_TLVP && !is64Bit() &&
47209467b48Spatrick          "Should only be called with a 32-bit TLVP relocation!");
47309467b48Spatrick 
47409467b48Spatrick   unsigned Log2Size = getFixupKindLog2Size(Fixup.getKind());
47509467b48Spatrick   uint32_t Value = Layout.getFragmentOffset(Fragment)+Fixup.getOffset();
47609467b48Spatrick   unsigned IsPCRel = 0;
47709467b48Spatrick 
47809467b48Spatrick   // We're only going to have a second symbol in pic mode and it'll be a
47909467b48Spatrick   // subtraction from the picbase. For 32-bit pic the addend is the difference
48009467b48Spatrick   // between the picbase and the next address.  For 32-bit static the addend is
48109467b48Spatrick   // zero.
48209467b48Spatrick   if (auto *SymB = Target.getSymB()) {
48309467b48Spatrick     // If this is a subtraction then we're pcrel.
48409467b48Spatrick     uint32_t FixupAddress =
48509467b48Spatrick       Writer->getFragmentAddress(Fragment, Layout) + Fixup.getOffset();
48609467b48Spatrick     IsPCRel = 1;
48709467b48Spatrick     FixedValue = FixupAddress -
48809467b48Spatrick                  Writer->getSymbolAddress(SymB->getSymbol(), Layout) +
48909467b48Spatrick                  Target.getConstant();
49009467b48Spatrick     FixedValue += 1ULL << Log2Size;
49109467b48Spatrick   } else {
49209467b48Spatrick     FixedValue = 0;
49309467b48Spatrick   }
49409467b48Spatrick 
49509467b48Spatrick   // struct relocation_info (8 bytes)
49609467b48Spatrick   MachO::any_relocation_info MRE;
49709467b48Spatrick   MRE.r_word0 = Value;
49809467b48Spatrick   MRE.r_word1 =
49909467b48Spatrick       (IsPCRel << 24) | (Log2Size << 25) | (MachO::GENERIC_RELOC_TLV << 28);
50009467b48Spatrick   Writer->addRelocation(&SymA->getSymbol(), Fragment->getParent(), MRE);
50109467b48Spatrick }
50209467b48Spatrick 
RecordX86Relocation(MachObjectWriter * Writer,const MCAssembler & Asm,const MCAsmLayout & Layout,const MCFragment * Fragment,const MCFixup & Fixup,MCValue Target,uint64_t & FixedValue)50309467b48Spatrick void X86MachObjectWriter::RecordX86Relocation(MachObjectWriter *Writer,
50409467b48Spatrick                                               const MCAssembler &Asm,
50509467b48Spatrick                                               const MCAsmLayout &Layout,
50609467b48Spatrick                                               const MCFragment *Fragment,
50709467b48Spatrick                                               const MCFixup &Fixup,
50809467b48Spatrick                                               MCValue Target,
50909467b48Spatrick                                               uint64_t &FixedValue) {
51009467b48Spatrick   unsigned IsPCRel = Writer->isFixupKindPCRel(Asm, Fixup.getKind());
51109467b48Spatrick   unsigned Log2Size = getFixupKindLog2Size(Fixup.getKind());
51209467b48Spatrick 
51309467b48Spatrick   // If this is a 32-bit TLVP reloc it's handled a bit differently.
51409467b48Spatrick   if (Target.getSymA() &&
51509467b48Spatrick       Target.getSymA()->getKind() == MCSymbolRefExpr::VK_TLVP) {
51609467b48Spatrick     recordTLVPRelocation(Writer, Asm, Layout, Fragment, Fixup, Target,
51709467b48Spatrick                          FixedValue);
51809467b48Spatrick     return;
51909467b48Spatrick   }
52009467b48Spatrick 
52109467b48Spatrick   // If this is a difference or a defined symbol plus an offset, then we need a
52209467b48Spatrick   // scattered relocation entry. Differences always require scattered
52309467b48Spatrick   // relocations.
52409467b48Spatrick   if (Target.getSymB()) {
52509467b48Spatrick     recordScatteredRelocation(Writer, Asm, Layout, Fragment, Fixup,
52609467b48Spatrick                               Target, Log2Size, FixedValue);
52709467b48Spatrick     return;
52809467b48Spatrick   }
52909467b48Spatrick 
53009467b48Spatrick   // Get the symbol data, if any.
53109467b48Spatrick   const MCSymbol *A = nullptr;
53209467b48Spatrick   if (Target.getSymA())
53309467b48Spatrick     A = &Target.getSymA()->getSymbol();
53409467b48Spatrick 
53509467b48Spatrick   // If this is an internal relocation with an offset, it also needs a scattered
53609467b48Spatrick   // relocation entry.
53709467b48Spatrick   uint32_t Offset = Target.getConstant();
53809467b48Spatrick   if (IsPCRel)
53909467b48Spatrick     Offset += 1 << Log2Size;
540*73471bf0Spatrick 
54109467b48Spatrick   // Try to record the scattered relocation if needed. Fall back to non
54209467b48Spatrick   // scattered if necessary (see comments in recordScatteredRelocation()
54309467b48Spatrick   // for details).
54409467b48Spatrick   if (Offset && A && !Writer->doesSymbolRequireExternRelocation(*A) &&
54509467b48Spatrick       recordScatteredRelocation(Writer, Asm, Layout, Fragment, Fixup, Target,
54609467b48Spatrick                                 Log2Size, FixedValue))
54709467b48Spatrick     return;
54809467b48Spatrick 
54909467b48Spatrick   // See <reloc.h>.
55009467b48Spatrick   uint32_t FixupOffset = Layout.getFragmentOffset(Fragment)+Fixup.getOffset();
55109467b48Spatrick   unsigned Index = 0;
55209467b48Spatrick   unsigned Type = 0;
55309467b48Spatrick   const MCSymbol *RelSymbol = nullptr;
55409467b48Spatrick 
55509467b48Spatrick   if (Target.isAbsolute()) { // constant
55609467b48Spatrick     // SymbolNum of 0 indicates the absolute section.
55709467b48Spatrick     //
55809467b48Spatrick     // FIXME: Currently, these are never generated (see code below). I cannot
55909467b48Spatrick     // find a case where they are actually emitted.
56009467b48Spatrick     Type = MachO::GENERIC_RELOC_VANILLA;
56109467b48Spatrick   } else {
562*73471bf0Spatrick     assert(A && "Unknown symbol data");
563*73471bf0Spatrick 
56409467b48Spatrick     // Resolve constant variables.
56509467b48Spatrick     if (A->isVariable()) {
56609467b48Spatrick       int64_t Res;
56709467b48Spatrick       if (A->getVariableValue()->evaluateAsAbsolute(
56809467b48Spatrick               Res, Layout, Writer->getSectionAddressMap())) {
56909467b48Spatrick         FixedValue = Res;
57009467b48Spatrick         return;
57109467b48Spatrick       }
57209467b48Spatrick     }
57309467b48Spatrick 
57409467b48Spatrick     // Check whether we need an external or internal relocation.
57509467b48Spatrick     if (Writer->doesSymbolRequireExternRelocation(*A)) {
57609467b48Spatrick       RelSymbol = A;
57709467b48Spatrick       // For external relocations, make sure to offset the fixup value to
57809467b48Spatrick       // compensate for the addend of the symbol address, if it was
57909467b48Spatrick       // undefined. This occurs with weak definitions, for example.
58009467b48Spatrick       if (!A->isUndefined())
58109467b48Spatrick         FixedValue -= Layout.getSymbolOffset(*A);
58209467b48Spatrick     } else {
58309467b48Spatrick       // The index is the section ordinal (1-based).
58409467b48Spatrick       const MCSection &Sec = A->getSection();
58509467b48Spatrick       Index = Sec.getOrdinal() + 1;
58609467b48Spatrick       FixedValue += Writer->getSectionAddress(&Sec);
58709467b48Spatrick     }
58809467b48Spatrick     if (IsPCRel)
58909467b48Spatrick       FixedValue -= Writer->getSectionAddress(Fragment->getParent());
59009467b48Spatrick 
59109467b48Spatrick     Type = MachO::GENERIC_RELOC_VANILLA;
59209467b48Spatrick   }
59309467b48Spatrick 
59409467b48Spatrick   // struct relocation_info (8 bytes)
59509467b48Spatrick   MachO::any_relocation_info MRE;
59609467b48Spatrick   MRE.r_word0 = FixupOffset;
59709467b48Spatrick   MRE.r_word1 =
59809467b48Spatrick       (Index << 0) | (IsPCRel << 24) | (Log2Size << 25) | (Type << 28);
59909467b48Spatrick   Writer->addRelocation(RelSymbol, Fragment->getParent(), MRE);
60009467b48Spatrick }
60109467b48Spatrick 
60209467b48Spatrick std::unique_ptr<MCObjectTargetWriter>
createX86MachObjectWriter(bool Is64Bit,uint32_t CPUType,uint32_t CPUSubtype)60309467b48Spatrick llvm::createX86MachObjectWriter(bool Is64Bit, uint32_t CPUType,
60409467b48Spatrick                                 uint32_t CPUSubtype) {
60509467b48Spatrick   return std::make_unique<X86MachObjectWriter>(Is64Bit, CPUType, CPUSubtype);
60609467b48Spatrick }
607