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:
X86MachObjectWriter(bool Is64Bit,uint32_t CPUType,uint32_t CPUSubtype)520b57cec5SDimitry Andric X86MachObjectWriter(bool Is64Bit, uint32_t CPUType, uint32_t CPUSubtype)
530b57cec5SDimitry Andric : MCMachObjectTargetWriter(Is64Bit, CPUType, CPUSubtype) {}
540b57cec5SDimitry Andric
recordRelocation(MachObjectWriter * Writer,MCAssembler & Asm,const MCFragment * Fragment,const MCFixup & Fixup,MCValue Target,uint64_t & FixedValue)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
isFixupKindRIPRel(unsigned Kind)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
getFixupKindLog2Size(unsigned Kind)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
RecordX86_64Relocation(MachObjectWriter * Writer,MCAssembler & Asm,const MCFragment * Fragment,const MCFixup & Fixup,MCValue Target,uint64_t & FixedValue)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
recordScatteredRelocation(MachObjectWriter * Writer,const MCAssembler & Asm,const MCFragment * Fragment,const MCFixup & Fixup,MCValue Target,unsigned Log2Size,uint64_t & FixedValue)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
recordTLVPRelocation(MachObjectWriter * Writer,const MCAssembler & Asm,const MCFragment * Fragment,const MCFixup & Fixup,MCValue Target,uint64_t & FixedValue)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
RecordX86Relocation(MachObjectWriter * Writer,const MCAssembler & Asm,const MCFragment * Fragment,const MCFixup & Fixup,MCValue Target,uint64_t & FixedValue)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>
createX86MachObjectWriter(bool Is64Bit,uint32_t CPUType,uint32_t CPUSubtype)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