xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/AArch64/MCTargetDesc/AArch64MachObjectWriter.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
10b57cec5SDimitry Andric //===-- AArch64MachObjectWriter.cpp - ARM Mach Object Writer --------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric 
90b57cec5SDimitry Andric #include "MCTargetDesc/AArch64FixupKinds.h"
100b57cec5SDimitry Andric #include "MCTargetDesc/AArch64MCTargetDesc.h"
110b57cec5SDimitry Andric #include "llvm/ADT/Twine.h"
120b57cec5SDimitry Andric #include "llvm/BinaryFormat/MachO.h"
130b57cec5SDimitry Andric #include "llvm/MC/MCAsmInfo.h"
14*0fca6ea1SDimitry Andric #include "llvm/MC/MCAsmInfoDarwin.h"
150b57cec5SDimitry Andric #include "llvm/MC/MCAssembler.h"
160b57cec5SDimitry Andric #include "llvm/MC/MCContext.h"
170b57cec5SDimitry Andric #include "llvm/MC/MCExpr.h"
180b57cec5SDimitry Andric #include "llvm/MC/MCFixup.h"
190b57cec5SDimitry Andric #include "llvm/MC/MCFragment.h"
200b57cec5SDimitry Andric #include "llvm/MC/MCMachObjectWriter.h"
210b57cec5SDimitry Andric #include "llvm/MC/MCSection.h"
220b57cec5SDimitry Andric #include "llvm/MC/MCSectionMachO.h"
230b57cec5SDimitry Andric #include "llvm/MC/MCSymbol.h"
240b57cec5SDimitry Andric #include "llvm/MC/MCValue.h"
250b57cec5SDimitry Andric #include "llvm/Support/Casting.h"
260b57cec5SDimitry Andric #include "llvm/Support/MathExtras.h"
270b57cec5SDimitry Andric #include <cassert>
280b57cec5SDimitry Andric #include <cstdint>
290b57cec5SDimitry Andric 
300b57cec5SDimitry Andric using namespace llvm;
310b57cec5SDimitry Andric 
320b57cec5SDimitry Andric namespace {
330b57cec5SDimitry Andric 
340b57cec5SDimitry Andric class AArch64MachObjectWriter : public MCMachObjectTargetWriter {
350b57cec5SDimitry Andric   bool getAArch64FixupKindMachOInfo(const MCFixup &Fixup, unsigned &RelocType,
360b57cec5SDimitry Andric                                   const MCSymbolRefExpr *Sym,
370b57cec5SDimitry Andric                                   unsigned &Log2Size, const MCAssembler &Asm);
380b57cec5SDimitry Andric 
390b57cec5SDimitry Andric public:
400b57cec5SDimitry Andric   AArch64MachObjectWriter(uint32_t CPUType, uint32_t CPUSubtype, bool IsILP32)
410b57cec5SDimitry Andric       : MCMachObjectTargetWriter(!IsILP32 /* is64Bit */, CPUType, CPUSubtype) {}
420b57cec5SDimitry Andric 
430b57cec5SDimitry Andric   void recordRelocation(MachObjectWriter *Writer, MCAssembler &Asm,
44*0fca6ea1SDimitry Andric                         const MCFragment *Fragment, const MCFixup &Fixup,
45*0fca6ea1SDimitry Andric                         MCValue Target, uint64_t &FixedValue) override;
460b57cec5SDimitry Andric };
470b57cec5SDimitry Andric 
480b57cec5SDimitry Andric } // end anonymous namespace
490b57cec5SDimitry Andric 
500b57cec5SDimitry Andric bool AArch64MachObjectWriter::getAArch64FixupKindMachOInfo(
510b57cec5SDimitry Andric     const MCFixup &Fixup, unsigned &RelocType, const MCSymbolRefExpr *Sym,
520b57cec5SDimitry Andric     unsigned &Log2Size, const MCAssembler &Asm) {
530b57cec5SDimitry Andric   RelocType = unsigned(MachO::ARM64_RELOC_UNSIGNED);
540b57cec5SDimitry Andric   Log2Size = ~0U;
550b57cec5SDimitry Andric 
568bcb0991SDimitry Andric   switch (Fixup.getTargetKind()) {
570b57cec5SDimitry Andric   default:
580b57cec5SDimitry Andric     return false;
590b57cec5SDimitry Andric 
600b57cec5SDimitry Andric   case FK_Data_1:
610b57cec5SDimitry Andric     Log2Size = Log2_32(1);
620b57cec5SDimitry Andric     return true;
630b57cec5SDimitry Andric   case FK_Data_2:
640b57cec5SDimitry Andric     Log2Size = Log2_32(2);
650b57cec5SDimitry Andric     return true;
660b57cec5SDimitry Andric   case FK_Data_4:
670b57cec5SDimitry Andric     Log2Size = Log2_32(4);
680b57cec5SDimitry Andric     if (Sym->getKind() == MCSymbolRefExpr::VK_GOT)
690b57cec5SDimitry Andric       RelocType = unsigned(MachO::ARM64_RELOC_POINTER_TO_GOT);
700b57cec5SDimitry Andric     return true;
710b57cec5SDimitry Andric   case FK_Data_8:
720b57cec5SDimitry Andric     Log2Size = Log2_32(8);
730b57cec5SDimitry Andric     if (Sym->getKind() == MCSymbolRefExpr::VK_GOT)
740b57cec5SDimitry Andric       RelocType = unsigned(MachO::ARM64_RELOC_POINTER_TO_GOT);
750b57cec5SDimitry Andric     return true;
760b57cec5SDimitry Andric   case AArch64::fixup_aarch64_add_imm12:
770b57cec5SDimitry Andric   case AArch64::fixup_aarch64_ldst_imm12_scale1:
780b57cec5SDimitry Andric   case AArch64::fixup_aarch64_ldst_imm12_scale2:
790b57cec5SDimitry Andric   case AArch64::fixup_aarch64_ldst_imm12_scale4:
800b57cec5SDimitry Andric   case AArch64::fixup_aarch64_ldst_imm12_scale8:
810b57cec5SDimitry Andric   case AArch64::fixup_aarch64_ldst_imm12_scale16:
820b57cec5SDimitry Andric     Log2Size = Log2_32(4);
830b57cec5SDimitry Andric     switch (Sym->getKind()) {
840b57cec5SDimitry Andric     default:
850b57cec5SDimitry Andric       return false;
860b57cec5SDimitry Andric     case MCSymbolRefExpr::VK_PAGEOFF:
870b57cec5SDimitry Andric       RelocType = unsigned(MachO::ARM64_RELOC_PAGEOFF12);
880b57cec5SDimitry Andric       return true;
890b57cec5SDimitry Andric     case MCSymbolRefExpr::VK_GOTPAGEOFF:
900b57cec5SDimitry Andric       RelocType = unsigned(MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12);
910b57cec5SDimitry Andric       return true;
920b57cec5SDimitry Andric     case MCSymbolRefExpr::VK_TLVPPAGEOFF:
930b57cec5SDimitry Andric       RelocType = unsigned(MachO::ARM64_RELOC_TLVP_LOAD_PAGEOFF12);
940b57cec5SDimitry Andric       return true;
950b57cec5SDimitry Andric     }
960b57cec5SDimitry Andric   case AArch64::fixup_aarch64_pcrel_adrp_imm21:
970b57cec5SDimitry Andric     Log2Size = Log2_32(4);
980b57cec5SDimitry Andric     // This encompasses the relocation for the whole 21-bit value.
990b57cec5SDimitry Andric     switch (Sym->getKind()) {
1000b57cec5SDimitry Andric     default:
1010b57cec5SDimitry Andric       Asm.getContext().reportError(Fixup.getLoc(),
1020b57cec5SDimitry Andric                                    "ADR/ADRP relocations must be GOT relative");
1030b57cec5SDimitry Andric       return false;
1040b57cec5SDimitry Andric     case MCSymbolRefExpr::VK_PAGE:
1050b57cec5SDimitry Andric       RelocType = unsigned(MachO::ARM64_RELOC_PAGE21);
1060b57cec5SDimitry Andric       return true;
1070b57cec5SDimitry Andric     case MCSymbolRefExpr::VK_GOTPAGE:
1080b57cec5SDimitry Andric       RelocType = unsigned(MachO::ARM64_RELOC_GOT_LOAD_PAGE21);
1090b57cec5SDimitry Andric       return true;
1100b57cec5SDimitry Andric     case MCSymbolRefExpr::VK_TLVPPAGE:
1110b57cec5SDimitry Andric       RelocType = unsigned(MachO::ARM64_RELOC_TLVP_LOAD_PAGE21);
1120b57cec5SDimitry Andric       return true;
1130b57cec5SDimitry Andric     }
1140b57cec5SDimitry Andric     return true;
1150b57cec5SDimitry Andric   case AArch64::fixup_aarch64_pcrel_branch26:
1160b57cec5SDimitry Andric   case AArch64::fixup_aarch64_pcrel_call26:
1170b57cec5SDimitry Andric     Log2Size = Log2_32(4);
1180b57cec5SDimitry Andric     RelocType = unsigned(MachO::ARM64_RELOC_BRANCH26);
1190b57cec5SDimitry Andric     return true;
1200b57cec5SDimitry Andric   }
1210b57cec5SDimitry Andric }
1220b57cec5SDimitry Andric 
1230b57cec5SDimitry Andric static bool canUseLocalRelocation(const MCSectionMachO &Section,
1240b57cec5SDimitry Andric                                   const MCSymbol &Symbol, unsigned Log2Size) {
1250b57cec5SDimitry Andric   // Debug info sections can use local relocations.
1260b57cec5SDimitry Andric   if (Section.hasAttribute(MachO::S_ATTR_DEBUG))
1270b57cec5SDimitry Andric     return true;
1280b57cec5SDimitry Andric 
1290b57cec5SDimitry Andric   // Otherwise, only pointer sized relocations are supported.
1300b57cec5SDimitry Andric   if (Log2Size != 3)
1310b57cec5SDimitry Andric     return false;
1320b57cec5SDimitry Andric 
1330b57cec5SDimitry Andric   // But only if they don't point to a few forbidden sections.
1340b57cec5SDimitry Andric   if (!Symbol.isInSection())
1350b57cec5SDimitry Andric     return true;
1360b57cec5SDimitry Andric   const MCSectionMachO &RefSec = cast<MCSectionMachO>(Symbol.getSection());
1370b57cec5SDimitry Andric   if (RefSec.getType() == MachO::S_CSTRING_LITERALS)
1380b57cec5SDimitry Andric     return false;
1390b57cec5SDimitry Andric 
1400b57cec5SDimitry Andric   if (RefSec.getSegmentName() == "__DATA" &&
14106c3fb27SDimitry Andric       (RefSec.getName() == "__cfstring" ||
14206c3fb27SDimitry Andric        RefSec.getName() == "__objc_classrefs"))
1430b57cec5SDimitry Andric     return false;
1440b57cec5SDimitry Andric 
14506c3fb27SDimitry Andric   return true;
1460b57cec5SDimitry Andric }
1470b57cec5SDimitry Andric 
1480b57cec5SDimitry Andric void AArch64MachObjectWriter::recordRelocation(
149*0fca6ea1SDimitry Andric     MachObjectWriter *Writer, MCAssembler &Asm, const MCFragment *Fragment,
150*0fca6ea1SDimitry Andric     const MCFixup &Fixup, MCValue Target, uint64_t &FixedValue) {
1510b57cec5SDimitry Andric   unsigned IsPCRel = Writer->isFixupKindPCRel(Asm, Fixup.getKind());
1520b57cec5SDimitry Andric 
1530b57cec5SDimitry Andric   // See <reloc.h>.
154*0fca6ea1SDimitry Andric   uint32_t FixupOffset = Asm.getFragmentOffset(*Fragment);
1550b57cec5SDimitry Andric   unsigned Log2Size = 0;
1560b57cec5SDimitry Andric   int64_t Value = 0;
1570b57cec5SDimitry Andric   unsigned Index = 0;
1580b57cec5SDimitry Andric   unsigned Type = 0;
1590b57cec5SDimitry Andric   unsigned Kind = Fixup.getKind();
1600b57cec5SDimitry Andric   const MCSymbol *RelSymbol = nullptr;
1610b57cec5SDimitry Andric 
1620b57cec5SDimitry Andric   FixupOffset += Fixup.getOffset();
1630b57cec5SDimitry Andric 
1640b57cec5SDimitry Andric   // AArch64 pcrel relocation addends do not include the section offset.
1650b57cec5SDimitry Andric   if (IsPCRel)
1660b57cec5SDimitry Andric     FixedValue += FixupOffset;
1670b57cec5SDimitry Andric 
1680b57cec5SDimitry Andric   // ADRP fixups use relocations for the whole symbol value and only
1690b57cec5SDimitry Andric   // put the addend in the instruction itself. Clear out any value the
1700b57cec5SDimitry Andric   // generic code figured out from the sybmol definition.
1710b57cec5SDimitry Andric   if (Kind == AArch64::fixup_aarch64_pcrel_adrp_imm21)
1720b57cec5SDimitry Andric     FixedValue = 0;
1730b57cec5SDimitry Andric 
1740b57cec5SDimitry Andric   // imm19 relocations are for conditional branches, which require
1750b57cec5SDimitry Andric   // assembler local symbols. If we got here, that's not what we have,
1760b57cec5SDimitry Andric   // so complain loudly.
1770b57cec5SDimitry Andric   if (Kind == AArch64::fixup_aarch64_pcrel_branch19) {
1780b57cec5SDimitry Andric     Asm.getContext().reportError(Fixup.getLoc(),
1790b57cec5SDimitry Andric                                  "conditional branch requires assembler-local"
1800b57cec5SDimitry Andric                                  " label. '" +
1810b57cec5SDimitry Andric                                      Target.getSymA()->getSymbol().getName() +
1820b57cec5SDimitry Andric                                      "' is external.");
1830b57cec5SDimitry Andric     return;
1840b57cec5SDimitry Andric   }
1850b57cec5SDimitry Andric 
1860b57cec5SDimitry Andric   // 14-bit branch relocations should only target internal labels, and so
1870b57cec5SDimitry Andric   // should never get here.
1880b57cec5SDimitry Andric   if (Kind == AArch64::fixup_aarch64_pcrel_branch14) {
1890b57cec5SDimitry Andric     Asm.getContext().reportError(Fixup.getLoc(),
1900b57cec5SDimitry Andric                                  "Invalid relocation on conditional branch!");
1910b57cec5SDimitry Andric     return;
1920b57cec5SDimitry Andric   }
1930b57cec5SDimitry Andric 
1940b57cec5SDimitry Andric   if (!getAArch64FixupKindMachOInfo(Fixup, Type, Target.getSymA(), Log2Size,
1950b57cec5SDimitry Andric                                     Asm)) {
1960b57cec5SDimitry Andric     Asm.getContext().reportError(Fixup.getLoc(), "unknown AArch64 fixup kind!");
1970b57cec5SDimitry Andric     return;
1980b57cec5SDimitry Andric   }
1990b57cec5SDimitry Andric 
2000b57cec5SDimitry Andric   Value = Target.getConstant();
2010b57cec5SDimitry Andric 
2020b57cec5SDimitry Andric   if (Target.isAbsolute()) { // constant
2030b57cec5SDimitry Andric     // FIXME: Should this always be extern?
2040b57cec5SDimitry Andric     // SymbolNum of 0 indicates the absolute section.
2050b57cec5SDimitry Andric     Type = MachO::ARM64_RELOC_UNSIGNED;
2060b57cec5SDimitry Andric 
2070b57cec5SDimitry Andric     if (IsPCRel) {
2080b57cec5SDimitry Andric       Asm.getContext().reportError(Fixup.getLoc(),
2090b57cec5SDimitry Andric                                    "PC relative absolute relocation!");
2100b57cec5SDimitry Andric       return;
2110b57cec5SDimitry Andric 
2120b57cec5SDimitry Andric       // FIXME: x86_64 sets the type to a branch reloc here. Should we do
2130b57cec5SDimitry Andric       // something similar?
2140b57cec5SDimitry Andric     }
2150b57cec5SDimitry Andric   } else if (Target.getSymB()) { // A - B + constant
2160b57cec5SDimitry Andric     const MCSymbol *A = &Target.getSymA()->getSymbol();
217*0fca6ea1SDimitry Andric     const MCSymbol *A_Base = Writer->getAtom(*A);
2180b57cec5SDimitry Andric 
2190b57cec5SDimitry Andric     const MCSymbol *B = &Target.getSymB()->getSymbol();
220*0fca6ea1SDimitry Andric     const MCSymbol *B_Base = Writer->getAtom(*B);
2210b57cec5SDimitry Andric 
2220b57cec5SDimitry Andric     // Check for "_foo@got - .", which comes through here as:
2230b57cec5SDimitry Andric     // Ltmp0:
2240b57cec5SDimitry Andric     //    ... _foo@got - Ltmp0
2250b57cec5SDimitry Andric     if (Target.getSymA()->getKind() == MCSymbolRefExpr::VK_GOT &&
2260b57cec5SDimitry Andric         Target.getSymB()->getKind() == MCSymbolRefExpr::VK_None &&
227*0fca6ea1SDimitry Andric         Asm.getSymbolOffset(*B) ==
228*0fca6ea1SDimitry Andric             Asm.getFragmentOffset(*Fragment) + Fixup.getOffset()) {
2290b57cec5SDimitry Andric       // SymB is the PC, so use a PC-rel pointer-to-GOT relocation.
2300b57cec5SDimitry Andric       Type = MachO::ARM64_RELOC_POINTER_TO_GOT;
2310b57cec5SDimitry Andric       IsPCRel = 1;
2320b57cec5SDimitry Andric       MachO::any_relocation_info MRE;
2330b57cec5SDimitry Andric       MRE.r_word0 = FixupOffset;
2340b57cec5SDimitry Andric       MRE.r_word1 = (IsPCRel << 24) | (Log2Size << 25) | (Type << 28);
2350b57cec5SDimitry Andric       Writer->addRelocation(A_Base, Fragment->getParent(), MRE);
2360b57cec5SDimitry Andric       return;
2370b57cec5SDimitry Andric     } else if (Target.getSymA()->getKind() != MCSymbolRefExpr::VK_None ||
2380b57cec5SDimitry Andric                Target.getSymB()->getKind() != MCSymbolRefExpr::VK_None) {
2390b57cec5SDimitry Andric       // Otherwise, neither symbol can be modified.
2400b57cec5SDimitry Andric       Asm.getContext().reportError(Fixup.getLoc(),
2410b57cec5SDimitry Andric                                    "unsupported relocation of modified symbol");
2420b57cec5SDimitry Andric       return;
2430b57cec5SDimitry Andric     }
2440b57cec5SDimitry Andric 
2450b57cec5SDimitry Andric     // We don't support PCrel relocations of differences.
2460b57cec5SDimitry Andric     if (IsPCRel) {
2470b57cec5SDimitry Andric       Asm.getContext().reportError(Fixup.getLoc(),
2480b57cec5SDimitry Andric                                    "unsupported pc-relative relocation of "
2490b57cec5SDimitry Andric                                    "difference");
2500b57cec5SDimitry Andric       return;
2510b57cec5SDimitry Andric     }
2520b57cec5SDimitry Andric 
2530b57cec5SDimitry Andric     // AArch64 always uses external relocations. If there is no symbol to use as
2540b57cec5SDimitry Andric     // a base address (a local symbol with no preceding non-local symbol),
2550b57cec5SDimitry Andric     // error out.
2560b57cec5SDimitry Andric     //
2570b57cec5SDimitry Andric     // FIXME: We should probably just synthesize an external symbol and use
2580b57cec5SDimitry Andric     // that.
2590b57cec5SDimitry Andric     if (!A_Base) {
2600b57cec5SDimitry Andric       Asm.getContext().reportError(
2610b57cec5SDimitry Andric           Fixup.getLoc(),
2620b57cec5SDimitry Andric           "unsupported relocation of local symbol '" + A->getName() +
2630b57cec5SDimitry Andric               "'. Must have non-local symbol earlier in section.");
2640b57cec5SDimitry Andric       return;
2650b57cec5SDimitry Andric     }
2660b57cec5SDimitry Andric     if (!B_Base) {
2670b57cec5SDimitry Andric       Asm.getContext().reportError(
2680b57cec5SDimitry Andric           Fixup.getLoc(),
2690b57cec5SDimitry Andric           "unsupported relocation of local symbol '" + B->getName() +
2700b57cec5SDimitry Andric               "'. Must have non-local symbol earlier in section.");
2710b57cec5SDimitry Andric       return;
2720b57cec5SDimitry Andric     }
2730b57cec5SDimitry Andric 
2740b57cec5SDimitry Andric     if (A_Base == B_Base && A_Base) {
2750b57cec5SDimitry Andric       Asm.getContext().reportError(
2760b57cec5SDimitry Andric           Fixup.getLoc(), "unsupported relocation with identical base");
2770b57cec5SDimitry Andric       return;
2780b57cec5SDimitry Andric     }
2790b57cec5SDimitry Andric 
280*0fca6ea1SDimitry Andric     Value += (!A->getFragment() ? 0 : Writer->getSymbolAddress(*A, Asm)) -
281*0fca6ea1SDimitry Andric              (!A_Base || !A_Base->getFragment()
282*0fca6ea1SDimitry Andric                   ? 0
283*0fca6ea1SDimitry Andric                   : Writer->getSymbolAddress(*A_Base, Asm));
284*0fca6ea1SDimitry Andric     Value -= (!B->getFragment() ? 0 : Writer->getSymbolAddress(*B, Asm)) -
285*0fca6ea1SDimitry Andric              (!B_Base || !B_Base->getFragment()
286*0fca6ea1SDimitry Andric                   ? 0
287*0fca6ea1SDimitry Andric                   : Writer->getSymbolAddress(*B_Base, Asm));
2880b57cec5SDimitry Andric 
2890b57cec5SDimitry Andric     Type = MachO::ARM64_RELOC_UNSIGNED;
2900b57cec5SDimitry Andric 
2910b57cec5SDimitry Andric     MachO::any_relocation_info MRE;
2920b57cec5SDimitry Andric     MRE.r_word0 = FixupOffset;
2930b57cec5SDimitry Andric     MRE.r_word1 = (IsPCRel << 24) | (Log2Size << 25) | (Type << 28);
2940b57cec5SDimitry Andric     Writer->addRelocation(A_Base, Fragment->getParent(), MRE);
2950b57cec5SDimitry Andric 
2960b57cec5SDimitry Andric     RelSymbol = B_Base;
2970b57cec5SDimitry Andric     Type = MachO::ARM64_RELOC_SUBTRACTOR;
2980b57cec5SDimitry Andric   } else { // A + constant
2990b57cec5SDimitry Andric     const MCSymbol *Symbol = &Target.getSymA()->getSymbol();
3000b57cec5SDimitry Andric     const MCSectionMachO &Section =
3010b57cec5SDimitry Andric         static_cast<const MCSectionMachO &>(*Fragment->getParent());
3020b57cec5SDimitry Andric 
3030b57cec5SDimitry Andric     bool CanUseLocalRelocation =
3040b57cec5SDimitry Andric         canUseLocalRelocation(Section, *Symbol, Log2Size);
3050b57cec5SDimitry Andric     if (Symbol->isTemporary() && (Value || !CanUseLocalRelocation)) {
3060b57cec5SDimitry Andric       // Make sure that the symbol is actually in a section here. If it isn't,
3070b57cec5SDimitry Andric       // emit an error and exit.
3080b57cec5SDimitry Andric       if (!Symbol->isInSection()) {
3090b57cec5SDimitry Andric         Asm.getContext().reportError(
3100b57cec5SDimitry Andric             Fixup.getLoc(),
3110b57cec5SDimitry Andric             "unsupported relocation of local symbol '" + Symbol->getName() +
3120b57cec5SDimitry Andric                 "'. Must have non-local symbol earlier in section.");
3130b57cec5SDimitry Andric         return;
3140b57cec5SDimitry Andric       }
3150b57cec5SDimitry Andric       const MCSection &Sec = Symbol->getSection();
316*0fca6ea1SDimitry Andric       if (!MCAsmInfoDarwin::isSectionAtomizableBySymbols(Sec))
3170b57cec5SDimitry Andric         Symbol->setUsedInReloc();
3180b57cec5SDimitry Andric     }
3190b57cec5SDimitry Andric 
320*0fca6ea1SDimitry Andric     const MCSymbol *Base = Writer->getAtom(*Symbol);
321*0fca6ea1SDimitry Andric 
3220b57cec5SDimitry Andric     // If the symbol is a variable it can either be in a section and
3230b57cec5SDimitry Andric     // we have a base or it is absolute and should have been expanded.
3240b57cec5SDimitry Andric     assert(!Symbol->isVariable() || Base);
3250b57cec5SDimitry Andric 
3260b57cec5SDimitry Andric     // Relocations inside debug sections always use local relocations when
3270b57cec5SDimitry Andric     // possible. This seems to be done because the debugger doesn't fully
3280b57cec5SDimitry Andric     // understand relocation entries and expects to find values that
3290b57cec5SDimitry Andric     // have already been fixed up.
3300b57cec5SDimitry Andric     if (Symbol->isInSection()) {
3310b57cec5SDimitry Andric       if (Section.hasAttribute(MachO::S_ATTR_DEBUG))
3320b57cec5SDimitry Andric         Base = nullptr;
3330b57cec5SDimitry Andric     }
3340b57cec5SDimitry Andric 
3350b57cec5SDimitry Andric     // AArch64 uses external relocations as much as possible. For debug
3360b57cec5SDimitry Andric     // sections, and for pointer-sized relocations (.quad), we allow section
3370b57cec5SDimitry Andric     // relocations.  It's code sections that run into trouble.
3380b57cec5SDimitry Andric     if (Base) {
3390b57cec5SDimitry Andric       RelSymbol = Base;
3400b57cec5SDimitry Andric 
3410b57cec5SDimitry Andric       // Add the local offset, if needed.
3420b57cec5SDimitry Andric       if (Base != Symbol)
343*0fca6ea1SDimitry Andric         Value += Asm.getSymbolOffset(*Symbol) - Asm.getSymbolOffset(*Base);
3440b57cec5SDimitry Andric     } else if (Symbol->isInSection()) {
3450b57cec5SDimitry Andric       if (!CanUseLocalRelocation) {
3460b57cec5SDimitry Andric         Asm.getContext().reportError(
3470b57cec5SDimitry Andric             Fixup.getLoc(),
3480b57cec5SDimitry Andric             "unsupported relocation of local symbol '" + Symbol->getName() +
3490b57cec5SDimitry Andric                 "'. Must have non-local symbol earlier in section.");
3500b57cec5SDimitry Andric         return;
3510b57cec5SDimitry Andric       }
3520b57cec5SDimitry Andric       // Adjust the relocation to be section-relative.
3530b57cec5SDimitry Andric       // The index is the section ordinal (1-based).
3540b57cec5SDimitry Andric       const MCSection &Sec = Symbol->getSection();
3550b57cec5SDimitry Andric       Index = Sec.getOrdinal() + 1;
356*0fca6ea1SDimitry Andric       Value += Writer->getSymbolAddress(*Symbol, Asm);
3570b57cec5SDimitry Andric 
3580b57cec5SDimitry Andric       if (IsPCRel)
359*0fca6ea1SDimitry Andric         Value -= Writer->getFragmentAddress(Asm, Fragment) + Fixup.getOffset() +
360*0fca6ea1SDimitry Andric                  (1ULL << Log2Size);
3610b57cec5SDimitry Andric     } else {
3620b57cec5SDimitry Andric       llvm_unreachable(
3630b57cec5SDimitry Andric           "This constant variable should have been expanded during evaluation");
3640b57cec5SDimitry Andric     }
3650b57cec5SDimitry Andric   }
3660b57cec5SDimitry Andric 
3670b57cec5SDimitry Andric   // If the relocation kind is Branch26, Page21, or Pageoff12, any addend
3680b57cec5SDimitry Andric   // is represented via an Addend relocation, not encoded directly into
3690b57cec5SDimitry Andric   // the instruction.
3700b57cec5SDimitry Andric   if ((Type == MachO::ARM64_RELOC_BRANCH26 ||
3710b57cec5SDimitry Andric        Type == MachO::ARM64_RELOC_PAGE21 ||
3720b57cec5SDimitry Andric        Type == MachO::ARM64_RELOC_PAGEOFF12) &&
3730b57cec5SDimitry Andric       Value) {
374e8d8bef9SDimitry Andric     if (!isInt<24>(Value)) {
375e8d8bef9SDimitry Andric       Asm.getContext().reportError(Fixup.getLoc(),
376e8d8bef9SDimitry Andric                                    "addend too big for relocation");
377e8d8bef9SDimitry Andric       return;
378e8d8bef9SDimitry Andric     }
3790b57cec5SDimitry Andric 
3800b57cec5SDimitry Andric     MachO::any_relocation_info MRE;
3810b57cec5SDimitry Andric     MRE.r_word0 = FixupOffset;
3820b57cec5SDimitry Andric     MRE.r_word1 =
3830b57cec5SDimitry Andric         (Index << 0) | (IsPCRel << 24) | (Log2Size << 25) | (Type << 28);
3840b57cec5SDimitry Andric     Writer->addRelocation(RelSymbol, Fragment->getParent(), MRE);
3850b57cec5SDimitry Andric 
3860b57cec5SDimitry Andric     // Now set up the Addend relocation.
3870b57cec5SDimitry Andric     Type = MachO::ARM64_RELOC_ADDEND;
3880b57cec5SDimitry Andric     Index = Value;
3890b57cec5SDimitry Andric     RelSymbol = nullptr;
3900b57cec5SDimitry Andric     IsPCRel = 0;
3910b57cec5SDimitry Andric     Log2Size = 2;
3920b57cec5SDimitry Andric 
3930b57cec5SDimitry Andric     // Put zero into the instruction itself. The addend is in the relocation.
3940b57cec5SDimitry Andric     Value = 0;
3950b57cec5SDimitry Andric   }
3960b57cec5SDimitry Andric 
3970b57cec5SDimitry Andric   // If there's any addend left to handle, encode it in the instruction.
3980b57cec5SDimitry Andric   FixedValue = Value;
3990b57cec5SDimitry Andric 
4000b57cec5SDimitry Andric   // struct relocation_info (8 bytes)
4010b57cec5SDimitry Andric   MachO::any_relocation_info MRE;
4020b57cec5SDimitry Andric   MRE.r_word0 = FixupOffset;
4030b57cec5SDimitry Andric   MRE.r_word1 =
4040b57cec5SDimitry Andric       (Index << 0) | (IsPCRel << 24) | (Log2Size << 25) | (Type << 28);
4050b57cec5SDimitry Andric   Writer->addRelocation(RelSymbol, Fragment->getParent(), MRE);
4060b57cec5SDimitry Andric }
4070b57cec5SDimitry Andric 
4080b57cec5SDimitry Andric std::unique_ptr<MCObjectTargetWriter>
4090b57cec5SDimitry Andric llvm::createAArch64MachObjectWriter(uint32_t CPUType, uint32_t CPUSubtype,
4100b57cec5SDimitry Andric                                     bool IsILP32) {
4118bcb0991SDimitry Andric   return std::make_unique<AArch64MachObjectWriter>(CPUType, CPUSubtype,
4120b57cec5SDimitry Andric                                                    IsILP32);
4130b57cec5SDimitry Andric }
414