10b57cec5SDimitry Andric //===-- X86MachObjectWriter.cpp - X86 Mach-O 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/X86FixupKinds.h" 100b57cec5SDimitry Andric #include "MCTargetDesc/X86MCTargetDesc.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/MCMachObjectWriter.h" 180b57cec5SDimitry Andric #include "llvm/MC/MCSectionMachO.h" 190b57cec5SDimitry Andric #include "llvm/MC/MCValue.h" 200b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h" 210b57cec5SDimitry Andric #include "llvm/Support/Format.h" 220b57cec5SDimitry Andric 230b57cec5SDimitry Andric using namespace llvm; 240b57cec5SDimitry Andric 250b57cec5SDimitry Andric namespace { 260b57cec5SDimitry Andric class X86MachObjectWriter : public MCMachObjectTargetWriter { 270b57cec5SDimitry Andric bool recordScatteredRelocation(MachObjectWriter *Writer, 280b57cec5SDimitry Andric const MCAssembler &Asm, 290b57cec5SDimitry Andric const MCFragment *Fragment, 300b57cec5SDimitry Andric const MCFixup &Fixup, 310b57cec5SDimitry Andric MCValue Target, 320b57cec5SDimitry Andric unsigned Log2Size, 330b57cec5SDimitry Andric uint64_t &FixedValue); 340b57cec5SDimitry Andric void recordTLVPRelocation(MachObjectWriter *Writer, 350b57cec5SDimitry Andric const MCAssembler &Asm, 360b57cec5SDimitry Andric const MCFragment *Fragment, 370b57cec5SDimitry Andric const MCFixup &Fixup, 380b57cec5SDimitry Andric MCValue Target, 390b57cec5SDimitry Andric uint64_t &FixedValue); 400b57cec5SDimitry Andric 410b57cec5SDimitry Andric void RecordX86Relocation(MachObjectWriter *Writer, 420b57cec5SDimitry Andric const MCAssembler &Asm, 430b57cec5SDimitry Andric const MCFragment *Fragment, 440b57cec5SDimitry Andric const MCFixup &Fixup, 450b57cec5SDimitry Andric MCValue Target, 460b57cec5SDimitry Andric uint64_t &FixedValue); 470b57cec5SDimitry Andric void RecordX86_64Relocation(MachObjectWriter *Writer, MCAssembler &Asm, 480b57cec5SDimitry Andric const MCFragment *Fragment, const MCFixup &Fixup, 490b57cec5SDimitry Andric MCValue Target, uint64_t &FixedValue); 500b57cec5SDimitry Andric 510b57cec5SDimitry Andric public: 520b57cec5SDimitry Andric X86MachObjectWriter(bool Is64Bit, uint32_t CPUType, uint32_t CPUSubtype) 530b57cec5SDimitry Andric : MCMachObjectTargetWriter(Is64Bit, CPUType, CPUSubtype) {} 540b57cec5SDimitry Andric 550b57cec5SDimitry Andric void recordRelocation(MachObjectWriter *Writer, MCAssembler &Asm, 56*0fca6ea1SDimitry Andric const MCFragment *Fragment, const MCFixup &Fixup, 57*0fca6ea1SDimitry Andric MCValue Target, uint64_t &FixedValue) override { 580b57cec5SDimitry Andric if (Writer->is64Bit()) 59*0fca6ea1SDimitry Andric RecordX86_64Relocation(Writer, Asm, Fragment, Fixup, Target, FixedValue); 600b57cec5SDimitry Andric else 61*0fca6ea1SDimitry Andric RecordX86Relocation(Writer, Asm, Fragment, Fixup, Target, FixedValue); 620b57cec5SDimitry Andric } 630b57cec5SDimitry Andric }; 64e8d8bef9SDimitry Andric } // namespace 650b57cec5SDimitry Andric 660b57cec5SDimitry Andric static bool isFixupKindRIPRel(unsigned Kind) { 670b57cec5SDimitry Andric return Kind == X86::reloc_riprel_4byte || 680b57cec5SDimitry Andric Kind == X86::reloc_riprel_4byte_movq_load || 690b57cec5SDimitry Andric Kind == X86::reloc_riprel_4byte_relax || 700b57cec5SDimitry Andric Kind == X86::reloc_riprel_4byte_relax_rex; 710b57cec5SDimitry Andric } 720b57cec5SDimitry Andric 730b57cec5SDimitry Andric static unsigned getFixupKindLog2Size(unsigned Kind) { 740b57cec5SDimitry Andric switch (Kind) { 750b57cec5SDimitry Andric default: 760b57cec5SDimitry Andric llvm_unreachable("invalid fixup kind!"); 770b57cec5SDimitry Andric case FK_PCRel_1: 780b57cec5SDimitry Andric case FK_Data_1: return 0; 790b57cec5SDimitry Andric case FK_PCRel_2: 800b57cec5SDimitry Andric case FK_Data_2: return 1; 810b57cec5SDimitry Andric case FK_PCRel_4: 820b57cec5SDimitry Andric // FIXME: Remove these!!! 830b57cec5SDimitry Andric case X86::reloc_riprel_4byte: 840b57cec5SDimitry Andric case X86::reloc_riprel_4byte_relax: 850b57cec5SDimitry Andric case X86::reloc_riprel_4byte_relax_rex: 860b57cec5SDimitry Andric case X86::reloc_riprel_4byte_movq_load: 870b57cec5SDimitry Andric case X86::reloc_signed_4byte: 880b57cec5SDimitry Andric case X86::reloc_signed_4byte_relax: 890b57cec5SDimitry Andric case X86::reloc_branch_4byte_pcrel: 900b57cec5SDimitry Andric case FK_Data_4: return 2; 910b57cec5SDimitry Andric case FK_Data_8: return 3; 920b57cec5SDimitry Andric } 930b57cec5SDimitry Andric } 940b57cec5SDimitry Andric 950b57cec5SDimitry Andric void X86MachObjectWriter::RecordX86_64Relocation( 96*0fca6ea1SDimitry Andric MachObjectWriter *Writer, MCAssembler &Asm, const MCFragment *Fragment, 97*0fca6ea1SDimitry Andric const MCFixup &Fixup, MCValue Target, uint64_t &FixedValue) { 980b57cec5SDimitry Andric unsigned IsPCRel = Writer->isFixupKindPCRel(Asm, Fixup.getKind()); 990b57cec5SDimitry Andric unsigned IsRIPRel = isFixupKindRIPRel(Fixup.getKind()); 1000b57cec5SDimitry Andric unsigned Log2Size = getFixupKindLog2Size(Fixup.getKind()); 1010b57cec5SDimitry Andric 1020b57cec5SDimitry Andric // See <reloc.h>. 103*0fca6ea1SDimitry Andric uint32_t FixupOffset = Asm.getFragmentOffset(*Fragment) + Fixup.getOffset(); 1040b57cec5SDimitry Andric uint32_t FixupAddress = 105*0fca6ea1SDimitry Andric Writer->getFragmentAddress(Asm, Fragment) + Fixup.getOffset(); 1060b57cec5SDimitry Andric int64_t Value = 0; 1070b57cec5SDimitry Andric unsigned Index = 0; 1080b57cec5SDimitry Andric unsigned IsExtern = 0; 1090b57cec5SDimitry Andric unsigned Type = 0; 1100b57cec5SDimitry Andric const MCSymbol *RelSymbol = nullptr; 1110b57cec5SDimitry Andric 1120b57cec5SDimitry Andric Value = Target.getConstant(); 1130b57cec5SDimitry Andric 1140b57cec5SDimitry Andric if (IsPCRel) { 1150b57cec5SDimitry Andric // Compensate for the relocation offset, Darwin x86_64 relocations only have 1160b57cec5SDimitry Andric // the addend and appear to have attempted to define it to be the actual 1170b57cec5SDimitry Andric // expression addend without the PCrel bias. However, instructions with data 1180b57cec5SDimitry Andric // following the relocation are not accommodated for (see comment below 1190b57cec5SDimitry Andric // regarding SIGNED{1,2,4}), so it isn't exactly that either. 1200b57cec5SDimitry Andric Value += 1LL << Log2Size; 1210b57cec5SDimitry Andric } 1220b57cec5SDimitry Andric 1230b57cec5SDimitry Andric if (Target.isAbsolute()) { // constant 1240b57cec5SDimitry Andric // SymbolNum of 0 indicates the absolute section. 1250b57cec5SDimitry Andric Type = MachO::X86_64_RELOC_UNSIGNED; 1260b57cec5SDimitry Andric 1270b57cec5SDimitry Andric // FIXME: I believe this is broken, I don't think the linker can understand 1280b57cec5SDimitry Andric // it. I think it would require a local relocation, but I'm not sure if that 1290b57cec5SDimitry Andric // would work either. The official way to get an absolute PCrel relocation 1300b57cec5SDimitry Andric // is to use an absolute symbol (which we don't support yet). 1310b57cec5SDimitry Andric if (IsPCRel) { 1320b57cec5SDimitry Andric IsExtern = 1; 1330b57cec5SDimitry Andric Type = MachO::X86_64_RELOC_BRANCH; 1340b57cec5SDimitry Andric } 1350b57cec5SDimitry Andric } else if (Target.getSymB()) { // A - B + constant 1360b57cec5SDimitry Andric const MCSymbol *A = &Target.getSymA()->getSymbol(); 1370b57cec5SDimitry Andric if (A->isTemporary()) 1380b57cec5SDimitry Andric A = &Writer->findAliasedSymbol(*A); 139*0fca6ea1SDimitry Andric const MCSymbol *A_Base = Writer->getAtom(*A); 1400b57cec5SDimitry Andric 1410b57cec5SDimitry Andric const MCSymbol *B = &Target.getSymB()->getSymbol(); 1420b57cec5SDimitry Andric if (B->isTemporary()) 1430b57cec5SDimitry Andric B = &Writer->findAliasedSymbol(*B); 144*0fca6ea1SDimitry Andric const MCSymbol *B_Base = Writer->getAtom(*B); 1450b57cec5SDimitry Andric 1460b57cec5SDimitry Andric // Neither symbol can be modified. 1470b57cec5SDimitry Andric if (Target.getSymA()->getKind() != MCSymbolRefExpr::VK_None) { 1480b57cec5SDimitry Andric Asm.getContext().reportError(Fixup.getLoc(), 1490b57cec5SDimitry Andric "unsupported relocation of modified symbol"); 1500b57cec5SDimitry Andric return; 1510b57cec5SDimitry Andric } 1520b57cec5SDimitry Andric 1530b57cec5SDimitry Andric // We don't support PCrel relocations of differences. Darwin 'as' doesn't 1540b57cec5SDimitry Andric // implement most of these correctly. 1550b57cec5SDimitry Andric if (IsPCRel) { 1560b57cec5SDimitry Andric Asm.getContext().reportError( 1570b57cec5SDimitry Andric Fixup.getLoc(), "unsupported pc-relative relocation of difference"); 1580b57cec5SDimitry Andric return; 1590b57cec5SDimitry Andric } 1600b57cec5SDimitry Andric 1610b57cec5SDimitry Andric // The support for the situation where one or both of the symbols would 1620b57cec5SDimitry Andric // require a local relocation is handled just like if the symbols were 1630b57cec5SDimitry Andric // external. This is certainly used in the case of debug sections where the 1640b57cec5SDimitry Andric // section has only temporary symbols and thus the symbols don't have base 1650b57cec5SDimitry Andric // symbols. This is encoded using the section ordinal and non-extern 1660b57cec5SDimitry Andric // relocation entries. 1670b57cec5SDimitry Andric 1680b57cec5SDimitry Andric // Darwin 'as' doesn't emit correct relocations for this (it ends up with a 1690b57cec5SDimitry Andric // single SIGNED relocation); reject it for now. Except the case where both 1700b57cec5SDimitry Andric // symbols don't have a base, equal but both NULL. 1710b57cec5SDimitry Andric if (A_Base == B_Base && A_Base) { 1720b57cec5SDimitry Andric Asm.getContext().reportError( 1730b57cec5SDimitry Andric Fixup.getLoc(), "unsupported relocation with identical base"); 1740b57cec5SDimitry Andric return; 1750b57cec5SDimitry Andric } 1760b57cec5SDimitry Andric 1770b57cec5SDimitry Andric // A subtraction expression where either symbol is undefined is a 1780b57cec5SDimitry Andric // non-relocatable expression. 1790b57cec5SDimitry Andric if (A->isUndefined() || B->isUndefined()) { 1800b57cec5SDimitry Andric StringRef Name = A->isUndefined() ? A->getName() : B->getName(); 1810b57cec5SDimitry Andric Asm.getContext().reportError(Fixup.getLoc(), 1820b57cec5SDimitry Andric "unsupported relocation with subtraction expression, symbol '" + 1830b57cec5SDimitry Andric Name + "' can not be undefined in a subtraction expression"); 1840b57cec5SDimitry Andric return; 1850b57cec5SDimitry Andric } 1860b57cec5SDimitry Andric 187*0fca6ea1SDimitry Andric Value += Writer->getSymbolAddress(*A, Asm) - 188*0fca6ea1SDimitry Andric (!A_Base ? 0 : Writer->getSymbolAddress(*A_Base, Asm)); 189*0fca6ea1SDimitry Andric Value -= Writer->getSymbolAddress(*B, Asm) - 190*0fca6ea1SDimitry Andric (!B_Base ? 0 : Writer->getSymbolAddress(*B_Base, Asm)); 1910b57cec5SDimitry Andric 1920b57cec5SDimitry Andric if (!A_Base) 1930b57cec5SDimitry Andric Index = A->getFragment()->getParent()->getOrdinal() + 1; 1940b57cec5SDimitry Andric Type = MachO::X86_64_RELOC_UNSIGNED; 1950b57cec5SDimitry Andric 1960b57cec5SDimitry Andric MachO::any_relocation_info MRE; 1970b57cec5SDimitry Andric MRE.r_word0 = FixupOffset; 1980b57cec5SDimitry Andric MRE.r_word1 = 1990b57cec5SDimitry Andric (Index << 0) | (IsPCRel << 24) | (Log2Size << 25) | (Type << 28); 2000b57cec5SDimitry Andric Writer->addRelocation(A_Base, Fragment->getParent(), MRE); 2010b57cec5SDimitry Andric 2020b57cec5SDimitry Andric if (B_Base) 2030b57cec5SDimitry Andric RelSymbol = B_Base; 2040b57cec5SDimitry Andric else 2050b57cec5SDimitry Andric Index = B->getFragment()->getParent()->getOrdinal() + 1; 2060b57cec5SDimitry Andric Type = MachO::X86_64_RELOC_SUBTRACTOR; 2070b57cec5SDimitry Andric } else { 2080b57cec5SDimitry Andric const MCSymbol *Symbol = &Target.getSymA()->getSymbol(); 2090b57cec5SDimitry Andric if (Symbol->isTemporary() && Value) { 2100b57cec5SDimitry Andric const MCSection &Sec = Symbol->getSection(); 211*0fca6ea1SDimitry Andric if (!MCAsmInfoDarwin::isSectionAtomizableBySymbols(Sec)) 2120b57cec5SDimitry Andric Symbol->setUsedInReloc(); 2130b57cec5SDimitry Andric } 214*0fca6ea1SDimitry Andric RelSymbol = Writer->getAtom(*Symbol); 2150b57cec5SDimitry Andric 2160b57cec5SDimitry Andric // Relocations inside debug sections always use local relocations when 2170b57cec5SDimitry Andric // possible. This seems to be done because the debugger doesn't fully 2180b57cec5SDimitry Andric // understand x86_64 relocation entries, and expects to find values that 2190b57cec5SDimitry Andric // have already been fixed up. 2200b57cec5SDimitry Andric if (Symbol->isInSection()) { 2210b57cec5SDimitry Andric const MCSectionMachO &Section = 2220b57cec5SDimitry Andric static_cast<const MCSectionMachO &>(*Fragment->getParent()); 2230b57cec5SDimitry Andric if (Section.hasAttribute(MachO::S_ATTR_DEBUG)) 2240b57cec5SDimitry Andric RelSymbol = nullptr; 2250b57cec5SDimitry Andric } 2260b57cec5SDimitry Andric 2270b57cec5SDimitry Andric // x86_64 almost always uses external relocations, except when there is no 2280b57cec5SDimitry Andric // symbol to use as a base address (a local symbol with no preceding 2290b57cec5SDimitry Andric // non-local symbol). 2300b57cec5SDimitry Andric if (RelSymbol) { 2310b57cec5SDimitry Andric // Add the local offset, if needed. 2320b57cec5SDimitry Andric if (RelSymbol != Symbol) 233*0fca6ea1SDimitry Andric Value += Asm.getSymbolOffset(*Symbol) - Asm.getSymbolOffset(*RelSymbol); 2340b57cec5SDimitry Andric } else if (Symbol->isInSection() && !Symbol->isVariable()) { 2350b57cec5SDimitry Andric // The index is the section ordinal (1-based). 2360b57cec5SDimitry Andric Index = Symbol->getFragment()->getParent()->getOrdinal() + 1; 237*0fca6ea1SDimitry Andric Value += Writer->getSymbolAddress(*Symbol, Asm); 2380b57cec5SDimitry Andric 2390b57cec5SDimitry Andric if (IsPCRel) 2400b57cec5SDimitry Andric Value -= FixupAddress + (1 << Log2Size); 2410b57cec5SDimitry Andric } else if (Symbol->isVariable()) { 2420b57cec5SDimitry Andric const MCExpr *Value = Symbol->getVariableValue(); 2430b57cec5SDimitry Andric int64_t Res; 244*0fca6ea1SDimitry Andric bool isAbs = 245*0fca6ea1SDimitry Andric Value->evaluateAsAbsolute(Res, Asm, Writer->getSectionAddressMap()); 2460b57cec5SDimitry Andric if (isAbs) { 2470b57cec5SDimitry Andric FixedValue = Res; 2480b57cec5SDimitry Andric return; 2490b57cec5SDimitry Andric } else { 2500b57cec5SDimitry Andric Asm.getContext().reportError(Fixup.getLoc(), 2510b57cec5SDimitry Andric "unsupported relocation of variable '" + 2520b57cec5SDimitry Andric Symbol->getName() + "'"); 2530b57cec5SDimitry Andric return; 2540b57cec5SDimitry Andric } 2550b57cec5SDimitry Andric } else { 2560b57cec5SDimitry Andric Asm.getContext().reportError( 2570b57cec5SDimitry Andric Fixup.getLoc(), "unsupported relocation of undefined symbol '" + 2580b57cec5SDimitry Andric Symbol->getName() + "'"); 2590b57cec5SDimitry Andric return; 2600b57cec5SDimitry Andric } 2610b57cec5SDimitry Andric 2620b57cec5SDimitry Andric MCSymbolRefExpr::VariantKind Modifier = Target.getSymA()->getKind(); 2630b57cec5SDimitry Andric if (IsPCRel) { 2640b57cec5SDimitry Andric if (IsRIPRel) { 2650b57cec5SDimitry Andric if (Modifier == MCSymbolRefExpr::VK_GOTPCREL) { 2660b57cec5SDimitry Andric // x86_64 distinguishes movq foo@GOTPCREL so that the linker can 2670b57cec5SDimitry Andric // rewrite the movq to an leaq at link time if the symbol ends up in 2680b57cec5SDimitry Andric // the same linkage unit. 2698bcb0991SDimitry Andric if (Fixup.getTargetKind() == X86::reloc_riprel_4byte_movq_load) 2700b57cec5SDimitry Andric Type = MachO::X86_64_RELOC_GOT_LOAD; 2710b57cec5SDimitry Andric else 2720b57cec5SDimitry Andric Type = MachO::X86_64_RELOC_GOT; 2730b57cec5SDimitry Andric } else if (Modifier == MCSymbolRefExpr::VK_TLVP) { 2740b57cec5SDimitry Andric Type = MachO::X86_64_RELOC_TLV; 2750b57cec5SDimitry Andric } else if (Modifier != MCSymbolRefExpr::VK_None) { 2760b57cec5SDimitry Andric Asm.getContext().reportError( 2770b57cec5SDimitry Andric Fixup.getLoc(), "unsupported symbol modifier in relocation"); 2780b57cec5SDimitry Andric return; 2790b57cec5SDimitry Andric } else { 2800b57cec5SDimitry Andric Type = MachO::X86_64_RELOC_SIGNED; 2810b57cec5SDimitry Andric 2820b57cec5SDimitry Andric // The Darwin x86_64 relocation format has a problem where it cannot 2830b57cec5SDimitry Andric // encode an address (L<foo> + <constant>) which is outside the atom 2840b57cec5SDimitry Andric // containing L<foo>. Generally, this shouldn't occur but it does 2850b57cec5SDimitry Andric // happen when we have a RIPrel instruction with data following the 2860b57cec5SDimitry Andric // relocation entry (e.g., movb $012, L0(%rip)). Even with the PCrel 2870b57cec5SDimitry Andric // adjustment Darwin x86_64 uses, the offset is still negative and the 2880b57cec5SDimitry Andric // linker has no way to recognize this. 2890b57cec5SDimitry Andric // 2900b57cec5SDimitry Andric // To work around this, Darwin uses several special relocation types 2910b57cec5SDimitry Andric // to indicate the offsets. However, the specification or 2920b57cec5SDimitry Andric // implementation of these seems to also be incomplete; they should 2930b57cec5SDimitry Andric // adjust the addend as well based on the actual encoded instruction 2940b57cec5SDimitry Andric // (the additional bias), but instead appear to just look at the final 2950b57cec5SDimitry Andric // offset. 2960b57cec5SDimitry Andric switch (-(Target.getConstant() + (1LL << Log2Size))) { 2970b57cec5SDimitry Andric case 1: Type = MachO::X86_64_RELOC_SIGNED_1; break; 2980b57cec5SDimitry Andric case 2: Type = MachO::X86_64_RELOC_SIGNED_2; break; 2990b57cec5SDimitry Andric case 4: Type = MachO::X86_64_RELOC_SIGNED_4; break; 3000b57cec5SDimitry Andric } 3010b57cec5SDimitry Andric } 3020b57cec5SDimitry Andric } else { 3030b57cec5SDimitry Andric if (Modifier != MCSymbolRefExpr::VK_None) { 3040b57cec5SDimitry Andric Asm.getContext().reportError( 3050b57cec5SDimitry Andric Fixup.getLoc(), 3060b57cec5SDimitry Andric "unsupported symbol modifier in branch relocation"); 3070b57cec5SDimitry Andric return; 3080b57cec5SDimitry Andric } 3090b57cec5SDimitry Andric 3100b57cec5SDimitry Andric Type = MachO::X86_64_RELOC_BRANCH; 3110b57cec5SDimitry Andric } 3120b57cec5SDimitry Andric } else { 3130b57cec5SDimitry Andric if (Modifier == MCSymbolRefExpr::VK_GOT) { 3140b57cec5SDimitry Andric Type = MachO::X86_64_RELOC_GOT; 3150b57cec5SDimitry Andric } else if (Modifier == MCSymbolRefExpr::VK_GOTPCREL) { 3160b57cec5SDimitry Andric // GOTPCREL is allowed as a modifier on non-PCrel instructions, in which 3170b57cec5SDimitry Andric // case all we do is set the PCrel bit in the relocation entry; this is 3180b57cec5SDimitry Andric // used with exception handling, for example. The source is required to 3190b57cec5SDimitry Andric // include any necessary offset directly. 3200b57cec5SDimitry Andric Type = MachO::X86_64_RELOC_GOT; 3210b57cec5SDimitry Andric IsPCRel = 1; 3220b57cec5SDimitry Andric } else if (Modifier == MCSymbolRefExpr::VK_TLVP) { 3230b57cec5SDimitry Andric Asm.getContext().reportError( 3240b57cec5SDimitry Andric Fixup.getLoc(), "TLVP symbol modifier should have been rip-rel"); 3250b57cec5SDimitry Andric return; 3260b57cec5SDimitry Andric } else if (Modifier != MCSymbolRefExpr::VK_None) { 3270b57cec5SDimitry Andric Asm.getContext().reportError( 3280b57cec5SDimitry Andric Fixup.getLoc(), "unsupported symbol modifier in relocation"); 3290b57cec5SDimitry Andric return; 3300b57cec5SDimitry Andric } else { 3310b57cec5SDimitry Andric Type = MachO::X86_64_RELOC_UNSIGNED; 3328bcb0991SDimitry Andric if (Fixup.getTargetKind() == X86::reloc_signed_4byte) { 3330b57cec5SDimitry Andric Asm.getContext().reportError( 3340b57cec5SDimitry Andric Fixup.getLoc(), 3350b57cec5SDimitry Andric "32-bit absolute addressing is not supported in 64-bit mode"); 3360b57cec5SDimitry Andric return; 3370b57cec5SDimitry Andric } 3380b57cec5SDimitry Andric } 3390b57cec5SDimitry Andric } 3400b57cec5SDimitry Andric } 3410b57cec5SDimitry Andric 3420b57cec5SDimitry Andric // x86_64 always writes custom values into the fixups. 3430b57cec5SDimitry Andric FixedValue = Value; 3440b57cec5SDimitry Andric 3450b57cec5SDimitry Andric // struct relocation_info (8 bytes) 3460b57cec5SDimitry Andric MachO::any_relocation_info MRE; 3470b57cec5SDimitry Andric MRE.r_word0 = FixupOffset; 3480b57cec5SDimitry Andric MRE.r_word1 = (Index << 0) | (IsPCRel << 24) | (Log2Size << 25) | 3490b57cec5SDimitry Andric (IsExtern << 27) | (Type << 28); 3500b57cec5SDimitry Andric Writer->addRelocation(RelSymbol, Fragment->getParent(), MRE); 3510b57cec5SDimitry Andric } 3520b57cec5SDimitry Andric 3530b57cec5SDimitry Andric bool X86MachObjectWriter::recordScatteredRelocation(MachObjectWriter *Writer, 3540b57cec5SDimitry Andric const MCAssembler &Asm, 3550b57cec5SDimitry Andric const MCFragment *Fragment, 3560b57cec5SDimitry Andric const MCFixup &Fixup, 3570b57cec5SDimitry Andric MCValue Target, 3580b57cec5SDimitry Andric unsigned Log2Size, 3590b57cec5SDimitry Andric uint64_t &FixedValue) { 3600b57cec5SDimitry Andric uint64_t OriginalFixedValue = FixedValue; 361*0fca6ea1SDimitry Andric uint32_t FixupOffset = Asm.getFragmentOffset(*Fragment) + Fixup.getOffset(); 3620b57cec5SDimitry Andric unsigned IsPCRel = Writer->isFixupKindPCRel(Asm, Fixup.getKind()); 3630b57cec5SDimitry Andric unsigned Type = MachO::GENERIC_RELOC_VANILLA; 3640b57cec5SDimitry Andric 3650b57cec5SDimitry Andric // See <reloc.h>. 3660b57cec5SDimitry Andric const MCSymbol *A = &Target.getSymA()->getSymbol(); 3670b57cec5SDimitry Andric 3680b57cec5SDimitry Andric if (!A->getFragment()) { 3690b57cec5SDimitry Andric Asm.getContext().reportError( 3700b57cec5SDimitry Andric Fixup.getLoc(), 3710b57cec5SDimitry Andric "symbol '" + A->getName() + 3720b57cec5SDimitry Andric "' can not be undefined in a subtraction expression"); 3730b57cec5SDimitry Andric return false; 3740b57cec5SDimitry Andric } 3750b57cec5SDimitry Andric 376*0fca6ea1SDimitry Andric uint32_t Value = Writer->getSymbolAddress(*A, Asm); 3770b57cec5SDimitry Andric uint64_t SecAddr = Writer->getSectionAddress(A->getFragment()->getParent()); 3780b57cec5SDimitry Andric FixedValue += SecAddr; 3790b57cec5SDimitry Andric uint32_t Value2 = 0; 3800b57cec5SDimitry Andric 3810b57cec5SDimitry Andric if (const MCSymbolRefExpr *B = Target.getSymB()) { 3820b57cec5SDimitry Andric const MCSymbol *SB = &B->getSymbol(); 3830b57cec5SDimitry Andric 3840b57cec5SDimitry Andric if (!SB->getFragment()) { 3850b57cec5SDimitry Andric Asm.getContext().reportError( 3860b57cec5SDimitry Andric Fixup.getLoc(), 3870b57cec5SDimitry Andric "symbol '" + SB->getName() + 3880b57cec5SDimitry Andric "' can not be undefined in a subtraction expression"); 3890b57cec5SDimitry Andric return false; 3900b57cec5SDimitry Andric } 3910b57cec5SDimitry Andric 3920b57cec5SDimitry Andric // Select the appropriate difference relocation type. 3930b57cec5SDimitry Andric // 3940b57cec5SDimitry Andric // Note that there is no longer any semantic difference between these two 3950b57cec5SDimitry Andric // relocation types from the linkers point of view, this is done solely for 3960b57cec5SDimitry Andric // pedantic compatibility with 'as'. 3970b57cec5SDimitry Andric Type = A->isExternal() ? (unsigned)MachO::GENERIC_RELOC_SECTDIFF 3980b57cec5SDimitry Andric : (unsigned)MachO::GENERIC_RELOC_LOCAL_SECTDIFF; 399*0fca6ea1SDimitry Andric Value2 = Writer->getSymbolAddress(*SB, Asm); 4000b57cec5SDimitry Andric FixedValue -= Writer->getSectionAddress(SB->getFragment()->getParent()); 4010b57cec5SDimitry Andric } 4020b57cec5SDimitry Andric 4030b57cec5SDimitry Andric // Relocations are written out in reverse order, so the PAIR comes first. 4040b57cec5SDimitry Andric if (Type == MachO::GENERIC_RELOC_SECTDIFF || 4050b57cec5SDimitry Andric Type == MachO::GENERIC_RELOC_LOCAL_SECTDIFF) { 4060b57cec5SDimitry Andric // If the offset is too large to fit in a scattered relocation, 4070b57cec5SDimitry Andric // we're hosed. It's an unfortunate limitation of the MachO format. 4080b57cec5SDimitry Andric if (FixupOffset > 0xffffff) { 4090b57cec5SDimitry Andric char Buffer[32]; 4100b57cec5SDimitry Andric format("0x%x", FixupOffset).print(Buffer, sizeof(Buffer)); 4110b57cec5SDimitry Andric Asm.getContext().reportError(Fixup.getLoc(), 4120b57cec5SDimitry Andric Twine("Section too large, can't encode " 4130b57cec5SDimitry Andric "r_address (") + Buffer + 4140b57cec5SDimitry Andric ") into 24 bits of scattered " 4150b57cec5SDimitry Andric "relocation entry."); 4160b57cec5SDimitry Andric return false; 4170b57cec5SDimitry Andric } 4180b57cec5SDimitry Andric 4190b57cec5SDimitry Andric MachO::any_relocation_info MRE; 4200b57cec5SDimitry Andric MRE.r_word0 = ((0 << 0) | // r_address 4210b57cec5SDimitry Andric (MachO::GENERIC_RELOC_PAIR << 24) | // r_type 4220b57cec5SDimitry Andric (Log2Size << 28) | 4230b57cec5SDimitry Andric (IsPCRel << 30) | 4240b57cec5SDimitry Andric MachO::R_SCATTERED); 4250b57cec5SDimitry Andric MRE.r_word1 = Value2; 4260b57cec5SDimitry Andric Writer->addRelocation(nullptr, Fragment->getParent(), MRE); 4270b57cec5SDimitry Andric } else { 4280b57cec5SDimitry Andric // If the offset is more than 24-bits, it won't fit in a scattered 4290b57cec5SDimitry Andric // relocation offset field, so we fall back to using a non-scattered 4300b57cec5SDimitry Andric // relocation. This is a bit risky, as if the offset reaches out of 4310b57cec5SDimitry Andric // the block and the linker is doing scattered loading on this 4320b57cec5SDimitry Andric // symbol, things can go badly. 4330b57cec5SDimitry Andric // 4340b57cec5SDimitry Andric // Required for 'as' compatibility. 4350b57cec5SDimitry Andric if (FixupOffset > 0xffffff) { 4360b57cec5SDimitry Andric FixedValue = OriginalFixedValue; 4370b57cec5SDimitry Andric return false; 4380b57cec5SDimitry Andric } 4390b57cec5SDimitry Andric } 4400b57cec5SDimitry Andric 4410b57cec5SDimitry Andric MachO::any_relocation_info MRE; 4420b57cec5SDimitry Andric MRE.r_word0 = ((FixupOffset << 0) | 4430b57cec5SDimitry Andric (Type << 24) | 4440b57cec5SDimitry Andric (Log2Size << 28) | 4450b57cec5SDimitry Andric (IsPCRel << 30) | 4460b57cec5SDimitry Andric MachO::R_SCATTERED); 4470b57cec5SDimitry Andric MRE.r_word1 = Value; 4480b57cec5SDimitry Andric Writer->addRelocation(nullptr, Fragment->getParent(), MRE); 4490b57cec5SDimitry Andric return true; 4500b57cec5SDimitry Andric } 4510b57cec5SDimitry Andric 4520b57cec5SDimitry Andric void X86MachObjectWriter::recordTLVPRelocation(MachObjectWriter *Writer, 4530b57cec5SDimitry Andric const MCAssembler &Asm, 4540b57cec5SDimitry Andric const MCFragment *Fragment, 4550b57cec5SDimitry Andric const MCFixup &Fixup, 4560b57cec5SDimitry Andric MCValue Target, 4570b57cec5SDimitry Andric uint64_t &FixedValue) { 4580b57cec5SDimitry Andric const MCSymbolRefExpr *SymA = Target.getSymA(); 4590b57cec5SDimitry Andric assert(SymA->getKind() == MCSymbolRefExpr::VK_TLVP && !is64Bit() && 4600b57cec5SDimitry Andric "Should only be called with a 32-bit TLVP relocation!"); 4610b57cec5SDimitry Andric 4620b57cec5SDimitry Andric unsigned Log2Size = getFixupKindLog2Size(Fixup.getKind()); 463*0fca6ea1SDimitry Andric uint32_t Value = Asm.getFragmentOffset(*Fragment) + Fixup.getOffset(); 4640b57cec5SDimitry Andric unsigned IsPCRel = 0; 4650b57cec5SDimitry Andric 4660b57cec5SDimitry Andric // We're only going to have a second symbol in pic mode and it'll be a 4670b57cec5SDimitry Andric // subtraction from the picbase. For 32-bit pic the addend is the difference 4680b57cec5SDimitry Andric // between the picbase and the next address. For 32-bit static the addend is 4690b57cec5SDimitry Andric // zero. 4700b57cec5SDimitry Andric if (auto *SymB = Target.getSymB()) { 4710b57cec5SDimitry Andric // If this is a subtraction then we're pcrel. 4720b57cec5SDimitry Andric uint32_t FixupAddress = 473*0fca6ea1SDimitry Andric Writer->getFragmentAddress(Asm, Fragment) + Fixup.getOffset(); 4740b57cec5SDimitry Andric IsPCRel = 1; 4750b57cec5SDimitry Andric FixedValue = FixupAddress - 476*0fca6ea1SDimitry Andric Writer->getSymbolAddress(SymB->getSymbol(), Asm) + 4770b57cec5SDimitry Andric Target.getConstant(); 4780b57cec5SDimitry Andric FixedValue += 1ULL << Log2Size; 4790b57cec5SDimitry Andric } else { 4800b57cec5SDimitry Andric FixedValue = 0; 4810b57cec5SDimitry Andric } 4820b57cec5SDimitry Andric 4830b57cec5SDimitry Andric // struct relocation_info (8 bytes) 4840b57cec5SDimitry Andric MachO::any_relocation_info MRE; 4850b57cec5SDimitry Andric MRE.r_word0 = Value; 4860b57cec5SDimitry Andric MRE.r_word1 = 4870b57cec5SDimitry Andric (IsPCRel << 24) | (Log2Size << 25) | (MachO::GENERIC_RELOC_TLV << 28); 4880b57cec5SDimitry Andric Writer->addRelocation(&SymA->getSymbol(), Fragment->getParent(), MRE); 4890b57cec5SDimitry Andric } 4900b57cec5SDimitry Andric 4910b57cec5SDimitry Andric void X86MachObjectWriter::RecordX86Relocation(MachObjectWriter *Writer, 4920b57cec5SDimitry Andric const MCAssembler &Asm, 4930b57cec5SDimitry Andric const MCFragment *Fragment, 4940b57cec5SDimitry Andric const MCFixup &Fixup, 4950b57cec5SDimitry Andric MCValue Target, 4960b57cec5SDimitry Andric uint64_t &FixedValue) { 4970b57cec5SDimitry Andric unsigned IsPCRel = Writer->isFixupKindPCRel(Asm, Fixup.getKind()); 4980b57cec5SDimitry Andric unsigned Log2Size = getFixupKindLog2Size(Fixup.getKind()); 4990b57cec5SDimitry Andric 5000b57cec5SDimitry Andric // If this is a 32-bit TLVP reloc it's handled a bit differently. 5010b57cec5SDimitry Andric if (Target.getSymA() && 5020b57cec5SDimitry Andric Target.getSymA()->getKind() == MCSymbolRefExpr::VK_TLVP) { 503*0fca6ea1SDimitry Andric recordTLVPRelocation(Writer, Asm, Fragment, Fixup, Target, FixedValue); 5040b57cec5SDimitry Andric return; 5050b57cec5SDimitry Andric } 5060b57cec5SDimitry Andric 5070b57cec5SDimitry Andric // If this is a difference or a defined symbol plus an offset, then we need a 5080b57cec5SDimitry Andric // scattered relocation entry. Differences always require scattered 5090b57cec5SDimitry Andric // relocations. 5100b57cec5SDimitry Andric if (Target.getSymB()) { 511*0fca6ea1SDimitry Andric recordScatteredRelocation(Writer, Asm, Fragment, Fixup, Target, Log2Size, 512*0fca6ea1SDimitry Andric FixedValue); 5130b57cec5SDimitry Andric return; 5140b57cec5SDimitry Andric } 5150b57cec5SDimitry Andric 5160b57cec5SDimitry Andric // Get the symbol data, if any. 5170b57cec5SDimitry Andric const MCSymbol *A = nullptr; 5180b57cec5SDimitry Andric if (Target.getSymA()) 5190b57cec5SDimitry Andric A = &Target.getSymA()->getSymbol(); 5200b57cec5SDimitry Andric 5210b57cec5SDimitry Andric // If this is an internal relocation with an offset, it also needs a scattered 5220b57cec5SDimitry Andric // relocation entry. 5230b57cec5SDimitry Andric uint32_t Offset = Target.getConstant(); 5240b57cec5SDimitry Andric if (IsPCRel) 5250b57cec5SDimitry Andric Offset += 1 << Log2Size; 526fe6060f1SDimitry Andric 5270b57cec5SDimitry Andric // Try to record the scattered relocation if needed. Fall back to non 5280b57cec5SDimitry Andric // scattered if necessary (see comments in recordScatteredRelocation() 5290b57cec5SDimitry Andric // for details). 5300b57cec5SDimitry Andric if (Offset && A && !Writer->doesSymbolRequireExternRelocation(*A) && 531*0fca6ea1SDimitry Andric recordScatteredRelocation(Writer, Asm, Fragment, Fixup, Target, Log2Size, 532*0fca6ea1SDimitry Andric FixedValue)) 5330b57cec5SDimitry Andric return; 5340b57cec5SDimitry Andric 5350b57cec5SDimitry Andric // See <reloc.h>. 536*0fca6ea1SDimitry Andric uint32_t FixupOffset = Asm.getFragmentOffset(*Fragment) + Fixup.getOffset(); 5370b57cec5SDimitry Andric unsigned Index = 0; 5380b57cec5SDimitry Andric unsigned Type = 0; 5390b57cec5SDimitry Andric const MCSymbol *RelSymbol = nullptr; 5400b57cec5SDimitry Andric 5410b57cec5SDimitry Andric if (Target.isAbsolute()) { // constant 5420b57cec5SDimitry Andric // SymbolNum of 0 indicates the absolute section. 5430b57cec5SDimitry Andric // 5440b57cec5SDimitry Andric // FIXME: Currently, these are never generated (see code below). I cannot 5450b57cec5SDimitry Andric // find a case where they are actually emitted. 5460b57cec5SDimitry Andric Type = MachO::GENERIC_RELOC_VANILLA; 5470b57cec5SDimitry Andric } else { 548fe6060f1SDimitry Andric assert(A && "Unknown symbol data"); 549fe6060f1SDimitry Andric 5500b57cec5SDimitry Andric // Resolve constant variables. 5510b57cec5SDimitry Andric if (A->isVariable()) { 5520b57cec5SDimitry Andric int64_t Res; 5530b57cec5SDimitry Andric if (A->getVariableValue()->evaluateAsAbsolute( 554*0fca6ea1SDimitry Andric Res, Asm, Writer->getSectionAddressMap())) { 5550b57cec5SDimitry Andric FixedValue = Res; 5560b57cec5SDimitry Andric return; 5570b57cec5SDimitry Andric } 5580b57cec5SDimitry Andric } 5590b57cec5SDimitry Andric 5600b57cec5SDimitry Andric // Check whether we need an external or internal relocation. 5610b57cec5SDimitry Andric if (Writer->doesSymbolRequireExternRelocation(*A)) { 5620b57cec5SDimitry Andric RelSymbol = A; 5630b57cec5SDimitry Andric // For external relocations, make sure to offset the fixup value to 5640b57cec5SDimitry Andric // compensate for the addend of the symbol address, if it was 5650b57cec5SDimitry Andric // undefined. This occurs with weak definitions, for example. 5660b57cec5SDimitry Andric if (!A->isUndefined()) 567*0fca6ea1SDimitry Andric FixedValue -= Asm.getSymbolOffset(*A); 5680b57cec5SDimitry Andric } else { 5690b57cec5SDimitry Andric // The index is the section ordinal (1-based). 5700b57cec5SDimitry Andric const MCSection &Sec = A->getSection(); 5710b57cec5SDimitry Andric Index = Sec.getOrdinal() + 1; 5720b57cec5SDimitry Andric FixedValue += Writer->getSectionAddress(&Sec); 5730b57cec5SDimitry Andric } 5740b57cec5SDimitry Andric if (IsPCRel) 5750b57cec5SDimitry Andric FixedValue -= Writer->getSectionAddress(Fragment->getParent()); 5760b57cec5SDimitry Andric 5770b57cec5SDimitry Andric Type = MachO::GENERIC_RELOC_VANILLA; 5780b57cec5SDimitry Andric } 5790b57cec5SDimitry Andric 5800b57cec5SDimitry Andric // struct relocation_info (8 bytes) 5810b57cec5SDimitry Andric MachO::any_relocation_info MRE; 5820b57cec5SDimitry Andric MRE.r_word0 = FixupOffset; 5830b57cec5SDimitry Andric MRE.r_word1 = 5840b57cec5SDimitry Andric (Index << 0) | (IsPCRel << 24) | (Log2Size << 25) | (Type << 28); 5850b57cec5SDimitry Andric Writer->addRelocation(RelSymbol, Fragment->getParent(), MRE); 5860b57cec5SDimitry Andric } 5870b57cec5SDimitry Andric 5880b57cec5SDimitry Andric std::unique_ptr<MCObjectTargetWriter> 5890b57cec5SDimitry Andric llvm::createX86MachObjectWriter(bool Is64Bit, uint32_t CPUType, 5900b57cec5SDimitry Andric uint32_t CPUSubtype) { 5918bcb0991SDimitry Andric return std::make_unique<X86MachObjectWriter>(Is64Bit, CPUType, CPUSubtype); 5920b57cec5SDimitry Andric } 593