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