Index: include/llvm/MC/MCWinCOFFObjectWriter.h =================================================================== --- include/llvm/MC/MCWinCOFFObjectWriter.h +++ include/llvm/MC/MCWinCOFFObjectWriter.h @@ -32,7 +32,6 @@ unsigned getMachine() const { return Machine; } virtual unsigned getRelocType(MCContext &Ctx, const MCReloc &Reloc, - bool IsCrossSection, const MCAsmBackend &MAB) const = 0; virtual bool recordRelocation(const MCReloc &) const { return true; } }; Index: lib/MC/ELFObjectWriter.cpp =================================================================== --- lib/MC/ELFObjectWriter.cpp +++ lib/MC/ELFObjectWriter.cpp @@ -625,53 +625,12 @@ const MCAsmLayout &Layout, const MCFragment *Fragment, MCReloc &Fixup) { - bool IsPCRel = Asm.getBackend().getFixupKindInfo(Fixup.getKind()).Flags & - MCFixupKindInfo::FKF_IsPCRel; MCReloc &Target = Fixup; uint64_t &FixedValue = Fixup.getConstant(); const MCSectionELF &FixupSection = cast(*Fragment->getParent()); uint64_t C = Target.getConstant(); uint64_t FixupOffset = Layout.getFragmentOffset(Fragment) + Fixup.getOffset(); - MCContext &Ctx = Asm.getContext(); - - if (const MCSymbol *SymBP = Target.getSymB()) { - // Let A, B and C being the components of Target and R be the location of - // the fixup. If the fixup is not pcrel, we want to compute (A - B + C). - // If it is pcrel, we want to compute (A - B + C - R). - - // In general, ELF has no relocations for -B. It can only represent (A + C) - // or (A + C - R). If B = R + K and the relocation is not pcrel, we can - // replace B to implement it: (A - R - K + C) - if (IsPCRel) { - Ctx.reportError( - Fixup.getLoc(), - "No relocation available to represent this relative expression"); - return; - } - - const MCSymbol &SymB = *SymBP; - - if (SymB.isUndefined()) { - Ctx.reportError(Fixup.getLoc(), - Twine("symbol '") + SymB.getName() + - "' can not be undefined in a subtraction expression"); - return; - } - - assert(!SymB.isAbsolute() && "Should have been folded"); - const MCSection &SecB = SymB.getSection(); - if (&SecB != &FixupSection) { - Ctx.reportError(Fixup.getLoc(), - "Cannot represent a difference across sections"); - return; - } - - Fixup.setKind(Asm.getBackend().getPCRelKind(Fixup.getKind())); - uint64_t SymBOffset = Layout.getSymbolOffset(SymB); - uint64_t K = SymBOffset - FixupOffset; - IsPCRel = true; - C -= K; - } + assert(!Target.getSymB()); // We either rejected the fixup or folded B into C at this point. const MCSymbolRefExpr *RefA = Target.getSymA(); Index: lib/MC/MCAssembler.cpp =================================================================== --- lib/MC/MCAssembler.cpp +++ lib/MC/MCAssembler.cpp @@ -26,6 +26,7 @@ #include "llvm/MC/MCFixupKindInfo.h" #include "llvm/MC/MCFragment.h" #include "llvm/MC/MCInst.h" +#include "llvm/MC/MCObjectFileInfo.h" #include "llvm/MC/MCObjectWriter.h" #include "llvm/MC/MCSection.h" #include "llvm/MC/MCSectionELF.h" @@ -185,6 +186,55 @@ return S.getFragment()->getAtom(); } +static bool tryConvertingToPcRel(const MCAsmLayout &Layout, + const MCFragment &Fragment, + MCReloc &Reloc) { + MCAssembler &Asm = Layout.getAssembler(); + MCContext &Ctx = Asm.getContext(); + + // Don't do this for MachO. One would expect to only need to check + // the atom the same way we check the section, but there are still too many + // odd broken tests with that. + if (Ctx.getObjectFileInfo()->getObjectFileType() == MCObjectFileInfo::IsMachO) + return false; + + // Let A, B and C being the components of Target and R be the location of + // the relocation. If the relocation is not pcrel, we want to compute (A - B + + // C). If it is pcrel, we want to compute (A - B + C - R). + + // If B = R + K and the relocation is not pcrel, we can replace B to + // implement it: (A - R - K + C). This is particularly important for + // ELF and COFF which don't have relocations that subtract an + // arbitrary symbol. + const MCSymbol *SymB = Reloc.getSymB(); + if (!SymB) + return false; + if (SymB->isUndefined()) { + Ctx.reportError(Reloc.getLoc(), + Twine("symbol '") + SymB->getName() + + "' can not be undefined in a subtraction expression"); + return true; + } + assert(!SymB->isAbsolute() && "Should have been folded"); + + const MCSection &SecB = SymB->getSection(); + const MCSection &RelocSection = *Fragment.getParent(); + if (&SecB != &RelocSection) { + Ctx.reportError(Reloc.getLoc(), + "Cannot represent a difference across sections"); + return true; + } + + MCFixupKind PCKind = Asm.getBackend().getPCRelKind(Reloc.getKind()); + uint64_t SymBOffset = Layout.getSymbolOffset(*SymB); + uint64_t FixupOffset = Layout.getFragmentOffset(&Fragment) + Reloc.getOffset(); + uint64_t Delta = SymBOffset - FixupOffset; + Reloc.setConstant(Reloc.getConstant() - Delta); + Reloc.setKind(PCKind); + Reloc.setSymB(nullptr); + return false; +} + bool MCAssembler::evaluateFixup(const MCAsmLayout &Layout, const MCFixup &Fixup, const MCFragment *DF, MCValue &Target, MCReloc &Reloc) const { @@ -246,6 +296,9 @@ Value = Target.getConstant(); + if (tryConvertingToPcRel(Layout, *DF, Reloc)) + return true; + // Let the backend force a relocation if needed. if (IsResolved && Backend.shouldForceRelocation(*this, Fixup, Target)) IsResolved = false; Index: lib/MC/WasmObjectWriter.cpp =================================================================== --- lib/MC/WasmObjectWriter.cpp +++ lib/MC/WasmObjectWriter.cpp @@ -356,47 +356,9 @@ uint64_t &FixedValue = Fixup.getConstant(); uint64_t C = Target.getConstant(); uint64_t FixupOffset = Layout.getFragmentOffset(Fragment) + Fixup.getOffset(); - MCContext &Ctx = Asm.getContext(); bool IsPCRel = Asm.getBackend().getFixupKindInfo(Fixup.getKind()).Flags & MCFixupKindInfo::FKF_IsPCRel; - - if (const MCSymbol *SymBP = Fixup.getSymB()) { - // Let A, B and C being the components of Target and R be the location of - // the fixup. If the fixup is not pcrel, we want to compute (A - B + C). - // If it is pcrel, we want to compute (A - B + C - R). - - // In general, Wasm has no relocations for -B. It can only represent (A + C) - // or (A + C - R). If B = R + K and the relocation is not pcrel, we can - // replace B to implement it: (A - R - K + C) - if (IsPCRel) { - Ctx.reportError( - Fixup.getLoc(), - "No relocation available to represent this relative expression"); - return; - } - - const MCSymbol &SymB = *SymBP; - - if (SymB.isUndefined()) { - Ctx.reportError(Fixup.getLoc(), - Twine("symbol '") + SymB.getName() + - "' can not be undefined in a subtraction expression"); - return; - } - - assert(!SymB.isAbsolute() && "Should have been folded"); - const MCSection &SecB = SymB.getSection(); - if (&SecB != &FixupSection) { - Ctx.reportError(Fixup.getLoc(), - "Cannot represent a difference across sections"); - return; - } - - uint64_t SymBOffset = Layout.getSymbolOffset(SymB); - uint64_t K = SymBOffset - FixupOffset; - IsPCRel = true; - C -= K; - } + assert(!Fixup.getSymB()); // We either rejected the fixup or folded B into C at this point. const MCSymbolRefExpr *RefA = Target.getSymA(); Index: lib/MC/WinCOFFObjectWriter.cpp =================================================================== --- lib/MC/WinCOFFObjectWriter.cpp +++ lib/MC/WinCOFFObjectWriter.cpp @@ -735,28 +735,8 @@ "Section must already have been defined in executePostLayoutBinding!"); COFFSection *Sec = SectionMap[MCSec]; - const MCSymbol *B = Target.getSymB(); - - if (B) { - if (!B->getFragment()) { - Asm.getContext().reportError( - Fixup.getLoc(), - Twine("symbol '") + B->getName() + - "' can not be undefined in a subtraction expression"); - return; - } - - // Offset of the symbol in the section - int64_t OffsetOfB = Layout.getSymbolOffset(*B); - - // Offset of the relocation in the section - int64_t OffsetOfRelocation = - Layout.getFragmentOffset(Fragment) + Fixup.getOffset(); - - FixedValue = (OffsetOfRelocation - OffsetOfB) + Target.getConstant(); - } else { - FixedValue = Target.getConstant(); - } + assert(!Target.getSymB()); + FixedValue = Target.getConstant(); COFFRelocation Reloc; @@ -782,7 +762,7 @@ Reloc.Data.VirtualAddress += Fixup.getOffset(); Reloc.Data.Type = TargetObjectWriter->getRelocType( - Asm.getContext(), Fixup, B, Asm.getBackend()); + Asm.getContext(), Fixup, Asm.getBackend()); // FIXME: Can anyone explain what this does other than adjust for the size // of the offset? Index: lib/Target/AArch64/MCTargetDesc/AArch64WinCOFFObjectWriter.cpp =================================================================== --- lib/Target/AArch64/MCTargetDesc/AArch64WinCOFFObjectWriter.cpp +++ lib/Target/AArch64/MCTargetDesc/AArch64WinCOFFObjectWriter.cpp @@ -32,7 +32,6 @@ ~AArch64WinCOFFObjectWriter() override = default; unsigned getRelocType(MCContext &Ctx, const MCReloc &Fixup, - bool IsCrossSection, const MCAsmBackend &MAB) const override; bool recordRelocation(const MCReloc &) const override; @@ -41,8 +40,8 @@ } // end anonymous namespace unsigned -AArch64WinCOFFObjectWriter::getRelocType(MCContext &Ctx, const MCReloc &Fixup, - bool IsCrossSection, +AArch64WinCOFFObjectWriter::getRelocType(MCContext &Ctx, + const MCReloc &Fixup, const MCAsmBackend &MAB) const { const MCReloc &Target = Fixup; auto Modifier = Target.isAbsolute() ? MCSymbolRefExpr::VK_None Index: lib/Target/ARM/MCTargetDesc/ARMWinCOFFObjectWriter.cpp =================================================================== --- lib/Target/ARM/MCTargetDesc/ARMWinCOFFObjectWriter.cpp +++ lib/Target/ARM/MCTargetDesc/ARMWinCOFFObjectWriter.cpp @@ -34,7 +34,6 @@ ~ARMWinCOFFObjectWriter() override = default; unsigned getRelocType(MCContext &Ctx, const MCReloc &Reloc, - bool IsCrossSection, const MCAsmBackend &MAB) const override; bool recordRelocation(const MCReloc &) const override; @@ -44,7 +43,6 @@ unsigned ARMWinCOFFObjectWriter::getRelocType(MCContext &Context, const MCReloc &Fixup, - bool IsCrossSection, const MCAsmBackend &MAB) const { const MCReloc &Target = Fixup; assert(getMachine() == COFF::IMAGE_FILE_MACHINE_ARMNT && Index: lib/Target/X86/MCTargetDesc/X86WinCOFFObjectWriter.cpp =================================================================== --- lib/Target/X86/MCTargetDesc/X86WinCOFFObjectWriter.cpp +++ lib/Target/X86/MCTargetDesc/X86WinCOFFObjectWriter.cpp @@ -27,7 +27,6 @@ ~X86WinCOFFObjectWriter() override = default; unsigned getRelocType(MCContext &Ctx, const MCReloc &Reloc, - bool IsCrossSection, const MCAsmBackend &MAB) const override; }; @@ -39,23 +38,19 @@ unsigned X86WinCOFFObjectWriter::getRelocType(MCContext &Ctx, const MCReloc &Fixup, - bool IsCrossSection, const MCAsmBackend &MAB) const { const MCReloc &Target = Fixup; unsigned FixupKind = Fixup.getKind(); - if (IsCrossSection) { - if (FixupKind != FK_Data_4 && FixupKind != llvm::X86::reloc_signed_4byte) { - Ctx.reportError(Fixup.getLoc(), "Cannot represent this expression"); - return COFF::IMAGE_REL_AMD64_ADDR32; - } - FixupKind = FK_PCRel_4; - } - MCSymbolRefExpr::VariantKind Modifier = Target.isAbsolute() ? MCSymbolRefExpr::VK_None : Target.getSymA()->getKind(); if (getMachine() == COFF::IMAGE_FILE_MACHINE_AMD64) { switch (FixupKind) { + case FK_PCRel_1: + case FK_PCRel_2: + case FK_PCRel_8: + Ctx.reportError(Fixup.getLoc(), "Cannot represent this expression"); + return COFF::IMAGE_REL_AMD64_ADDR32; case FK_PCRel_4: case X86::reloc_riprel_4byte: case X86::reloc_riprel_4byte_movq_load: Index: test/MC/AArch64/error-location.s =================================================================== --- test/MC/AArch64/error-location.s +++ test/MC/AArch64/error-location.s @@ -10,7 +10,7 @@ // CHECK: :[[@LINE+1]]:{{[0-9]+}}: error: expected relocatable expression .word -undef -// CHECK: :[[@LINE+1]]:{{[0-9]+}}: error: No relocation available to represent this relative expression +// CHECK: :[[@LINE+1]]:{{[0-9]+}}: error: symbol 'undef' can not be undefined in a subtraction expression adr x0, #a-undef // CHECK: :[[@LINE+1]]:{{[0-9]+}}: error: Cannot represent a difference across sections Index: test/MC/ARM/error-location.s =================================================================== --- test/MC/ARM/error-location.s +++ test/MC/ARM/error-location.s @@ -10,7 +10,7 @@ @ CHECK: :[[@LINE+1]]:{{[0-9]+}}: error: expected relocatable expression .word -undef -@ CHECK: :[[@LINE+1]]:{{[0-9]+}}: error: No relocation available to represent this relative expression +@ CHECK: :[[@LINE+1]]:{{[0-9]+}}: error: symbol 'undef' can not be undefined in a subtraction expression adr r0, #a-undef @ CHECK: :[[@LINE+1]]:{{[0-9]+}}: error: Cannot represent a difference across sections Index: test/MC/ELF/bad-expr2.s =================================================================== --- test/MC/ELF/bad-expr2.s +++ test/MC/ELF/bad-expr2.s @@ -1,7 +1,7 @@ // RUN: not llvm-mc -filetype=obj -triple x86_64-pc-linux-gnu %s -o /dev/null \ // RUN: 2>&1 | FileCheck %s -// CHECK: [[@LINE+2]]:{{[0-9]+}}: error: No relocation available to represent this relative expression +// CHECK: [[@LINE+2]]:{{[0-9]+}}: error: Cannot represent a difference across sections // CHECK-NEXT: call foo - bar call foo - bar