diff --git a/llvm/include/llvm/MC/MCAsmBackend.h b/llvm/include/llvm/MC/MCAsmBackend.h --- a/llvm/include/llvm/MC/MCAsmBackend.h +++ b/llvm/include/llvm/MC/MCAsmBackend.h @@ -129,10 +129,6 @@ uint64_t Value, bool IsResolved, const MCSubtargetInfo *STI) const = 0; - /// Check whether the given target requires emitting differences of two - /// symbols as a set of relocations. - virtual bool requiresDiffExpressionRelocations() const { return false; } - /// @} /// \name Target Relaxation Interfaces diff --git a/llvm/include/llvm/MC/MCFixup.h b/llvm/include/llvm/MC/MCFixup.h --- a/llvm/include/llvm/MC/MCFixup.h +++ b/llvm/include/llvm/MC/MCFixup.h @@ -41,16 +41,6 @@ FK_SecRel_2, ///< A two-byte section relative fixup. FK_SecRel_4, ///< A four-byte section relative fixup. FK_SecRel_8, ///< A eight-byte section relative fixup. - FK_Data_Add_1, ///< A one-byte add fixup. - FK_Data_Add_2, ///< A two-byte add fixup. - FK_Data_Add_4, ///< A four-byte add fixup. - FK_Data_Add_8, ///< A eight-byte add fixup. - FK_Data_Add_6b, ///< A six-bits add fixup. - FK_Data_Sub_1, ///< A one-byte sub fixup. - FK_Data_Sub_2, ///< A two-byte sub fixup. - FK_Data_Sub_4, ///< A four-byte sub fixup. - FK_Data_Sub_8, ///< A eight-byte sub fixup. - FK_Data_Sub_6b, ///< A six-bits sub fixup. FirstTargetFixupKind = 128, @@ -105,28 +95,6 @@ return FI; } - /// Return a fixup corresponding to the add half of a add/sub fixup pair for - /// the given Fixup. - static MCFixup createAddFor(const MCFixup &Fixup) { - MCFixup FI; - FI.Value = Fixup.getValue(); - FI.Offset = Fixup.getOffset(); - FI.Kind = getAddKindForKind(Fixup.getKind()); - FI.Loc = Fixup.getLoc(); - return FI; - } - - /// Return a fixup corresponding to the sub half of a add/sub fixup pair for - /// the given Fixup. - static MCFixup createSubFor(const MCFixup &Fixup) { - MCFixup FI; - FI.Value = Fixup.getValue(); - FI.Offset = Fixup.getOffset(); - FI.Kind = getSubKindForKind(Fixup.getKind()); - FI.Loc = Fixup.getLoc(); - return FI; - } - MCFixupKind getKind() const { return Kind; } unsigned getTargetKind() const { return Kind; } @@ -172,32 +140,6 @@ } } - /// Return the generic fixup kind for an addition with a given size. It - /// is an error to pass an unsupported size. - static MCFixupKind getAddKindForKind(MCFixupKind Kind) { - switch (Kind) { - default: llvm_unreachable("Unknown type to convert!"); - case FK_Data_1: return FK_Data_Add_1; - case FK_Data_2: return FK_Data_Add_2; - case FK_Data_4: return FK_Data_Add_4; - case FK_Data_8: return FK_Data_Add_8; - case FK_Data_6b: return FK_Data_Add_6b; - } - } - - /// Return the generic fixup kind for an subtraction with a given size. It - /// is an error to pass an unsupported size. - static MCFixupKind getSubKindForKind(MCFixupKind Kind) { - switch (Kind) { - default: llvm_unreachable("Unknown type to convert!"); - case FK_Data_1: return FK_Data_Sub_1; - case FK_Data_2: return FK_Data_Sub_2; - case FK_Data_4: return FK_Data_Sub_4; - case FK_Data_8: return FK_Data_Sub_8; - case FK_Data_6b: return FK_Data_Sub_6b; - } - } - SMLoc getLoc() const { return Loc; } }; diff --git a/llvm/lib/MC/ELFObjectWriter.cpp b/llvm/lib/MC/ELFObjectWriter.cpp --- a/llvm/lib/MC/ELFObjectWriter.cpp +++ b/llvm/lib/MC/ELFObjectWriter.cpp @@ -1427,7 +1427,10 @@ uint64_t FixupOffset = Layout.getFragmentOffset(Fragment) + Fixup.getOffset(); MCContext &Ctx = Asm.getContext(); - if (const MCSymbolRefExpr *RefB = Target.getSymB()) { + const MCSymbolRefExpr *RefA = Target.getSymA(); + const MCSymbolRefExpr *RefB = Target.getSymB(); + + if (RefB) { const auto &SymB = cast(RefB->getSymbol()); if (SymB.isUndefined()) { Ctx.reportError(Fixup.getLoc(), @@ -1438,7 +1441,13 @@ assert(!SymB.isAbsolute() && "Should have been folded"); const MCSection &SecB = SymB.getSection(); - if (&SecB != &FixupSection) { + + bool ResolveSymbolicDifference = + RefA ? Asm.getWriter().isSymbolRefDifferenceFullyResolved(Asm, RefA, + RefB, false) + : false; + + if (!ResolveSymbolicDifference && &SecB != &FixupSection) { Ctx.reportError(Fixup.getLoc(), "Cannot represent a difference across sections"); return; @@ -1450,7 +1459,6 @@ } // We either rejected the fixup or folded B into C at this point. - const MCSymbolRefExpr *RefA = Target.getSymA(); const auto *SymA = RefA ? cast(&RefA->getSymbol()) : nullptr; bool ViaWeakRef = false; @@ -1516,6 +1524,11 @@ SymA.getType() == ELF::STT_GNU_IFUNC) return false; } + // RISC-V requires the relocation to be split up to handle the ADD_SUB split + // relocation. These are required to ensure that symbolic differences are + // emitted as paired ADD/SUB relocations. + if (!InSet && TargetObjectWriter->getEMachine() == ELF::EM_RISCV) + return !Asm.getRelaxAll(); return MCObjectWriter::isSymbolRefDifferenceFullyResolvedImpl(Asm, SymA, FB, InSet, IsPCRel); } diff --git a/llvm/lib/MC/MCAsmBackend.cpp b/llvm/lib/MC/MCAsmBackend.cpp --- a/llvm/lib/MC/MCAsmBackend.cpp +++ b/llvm/lib/MC/MCAsmBackend.cpp @@ -95,16 +95,7 @@ {"FK_SecRel_2", 0, 16, 0}, {"FK_SecRel_4", 0, 32, 0}, {"FK_SecRel_8", 0, 64, 0}, - {"FK_Data_Add_1", 0, 8, 0}, - {"FK_Data_Add_2", 0, 16, 0}, - {"FK_Data_Add_4", 0, 32, 0}, - {"FK_Data_Add_8", 0, 64, 0}, - {"FK_Data_Add_6b", 0, 6, 0}, - {"FK_Data_Sub_1", 0, 8, 0}, - {"FK_Data_Sub_2", 0, 16, 0}, - {"FK_Data_Sub_4", 0, 32, 0}, - {"FK_Data_Sub_8", 0, 64, 0}, - {"FK_Data_Sub_6b", 0, 6, 0}}; + }; assert((size_t)Kind <= array_lengthof(Builtins) && "Unknown fixup kind"); return Builtins[Kind]; diff --git a/llvm/lib/MC/MCAssembler.cpp b/llvm/lib/MC/MCAssembler.cpp --- a/llvm/lib/MC/MCAssembler.cpp +++ b/llvm/lib/MC/MCAssembler.cpp @@ -792,26 +792,7 @@ // The fixup was unresolved, we need a relocation. Inform the object // writer of the relocation, and give it an opportunity to adjust the // fixup value if need be. - if (Target.getSymA() && Target.getSymB() && - getBackend().requiresDiffExpressionRelocations()) { - // The fixup represents the difference between two symbols, which the - // backend has indicated must be resolved at link time. Split up the fixup - // into two relocations, one for the add, and one for the sub, and emit - // both of these. The constant will be associated with the add half of the - // expression. - MCFixup FixupAdd = MCFixup::createAddFor(Fixup); - MCValue TargetAdd = - MCValue::get(Target.getSymA(), nullptr, Target.getConstant()); - getWriter().recordRelocation(*this, Layout, &F, FixupAdd, TargetAdd, - FixedValue); - MCFixup FixupSub = MCFixup::createSubFor(Fixup); - MCValue TargetSub = MCValue::get(Target.getSymB()); - getWriter().recordRelocation(*this, Layout, &F, FixupSub, TargetSub, - FixedValue); - } else { - getWriter().recordRelocation(*this, Layout, &F, Fixup, Target, - FixedValue); - } + getWriter().recordRelocation(*this, Layout, &F, Fixup, Target, FixedValue); } return std::make_tuple(Target, FixedValue, IsResolved); } @@ -1113,28 +1094,8 @@ raw_svector_ostream OSE(Data); DF.getFixups().clear(); - if (!getBackend().requiresDiffExpressionRelocations()) { - MCDwarfLineAddr::Encode(Context, getDWARFLinetableParams(), LineDelta, - AddrDelta, OSE); - } else { - uint32_t Offset; - uint32_t Size; - bool SetDelta; - std::tie(Offset, Size, SetDelta) = - MCDwarfLineAddr::fixedEncode(Context, LineDelta, AddrDelta, OSE); - // Add Fixups for address delta or new address. - const MCExpr *FixupExpr; - if (SetDelta) { - FixupExpr = &DF.getAddrDelta(); - } else { - const MCBinaryExpr *ABE = cast(&DF.getAddrDelta()); - FixupExpr = ABE->getLHS(); - } - DF.getFixups().push_back( - MCFixup::create(Offset, FixupExpr, - MCFixup::getKindForSize(Size, false /*isPCRel*/))); - } - + MCDwarfLineAddr::Encode(Context, getDWARFLinetableParams(), LineDelta, + AddrDelta, OSE); return OldSize != Data.size(); } @@ -1151,20 +1112,7 @@ raw_svector_ostream OSE(Data); DF.getFixups().clear(); - if (getBackend().requiresDiffExpressionRelocations()) { - uint32_t Offset; - uint32_t Size; - MCDwarfFrameEmitter::EncodeAdvanceLoc(Context, AddrDelta, OSE, &Offset, - &Size); - if (Size) { - DF.getFixups().push_back(MCFixup::create( - Offset, &DF.getAddrDelta(), - MCFixup::getKindForSizeInBits(Size /*In bits.*/, false /*isPCRel*/))); - } - } else { - MCDwarfFrameEmitter::EncodeAdvanceLoc(Context, AddrDelta, OSE); - } - + MCDwarfFrameEmitter::EncodeAdvanceLoc(Context, AddrDelta, OSE); return OldSize != Data.size(); } @@ -1194,10 +1142,6 @@ raw_svector_ostream OSE(Data); PF.getFixups().clear(); - // Relocations should not be needed in general except on RISC-V which we are - // not targeted for now. - assert(!getBackend().requiresDiffExpressionRelocations() && - "cannot relax relocations"); // AddrDelta is a signed integer encodeSLEB128(AddrDelta, OSE, OldSize); return OldSize != Data.size(); diff --git a/llvm/lib/MC/MCExpr.cpp b/llvm/lib/MC/MCExpr.cpp --- a/llvm/lib/MC/MCExpr.cpp +++ b/llvm/lib/MC/MCExpr.cpp @@ -671,24 +671,6 @@ } } -static bool canFold(const MCAssembler *Asm, const MCSymbolRefExpr *A, - const MCSymbolRefExpr *B, bool InSet) { - if (InSet) - return true; - - if (!Asm->getBackend().requiresDiffExpressionRelocations()) - return true; - - const MCSymbol &CheckSym = A ? A->getSymbol() : B->getSymbol(); - if (!CheckSym.isInSection()) - return true; - - if (!CheckSym.getSection().hasInstructions()) - return true; - - return false; -} - /// Evaluate the result of an add between (conceptually) two MCValues. /// /// This routine conceptually attempts to construct an MCValue: @@ -725,11 +707,8 @@ assert((!Layout || Asm) && "Must have an assembler object if layout is given!"); - // If we have a layout, we can fold resolved differences. Do not do this if - // the backend requires this to be emitted as individual relocations, unless - // the InSet flag is set to get the current difference anyway (used for - // example to calculate symbol sizes). - if (Asm && canFold(Asm, LHS_A, LHS_B, InSet)) { + // If we have a layout, we can fold resolved differences. + if (Asm) { // First, fold out any differences which are fully resolved. By // reassociating terms in // Result = (LHS_A - LHS_B + LHS_Cst) + (RHS_A - RHS_B + RHS_Cst). diff --git a/llvm/lib/MC/MCObjectStreamer.cpp b/llvm/lib/MC/MCObjectStreamer.cpp --- a/llvm/lib/MC/MCObjectStreamer.cpp +++ b/llvm/lib/MC/MCObjectStreamer.cpp @@ -130,9 +130,6 @@ static Optional absoluteSymbolDiff(MCAssembler &Asm, const MCSymbol *Hi, const MCSymbol *Lo) { assert(Hi && Lo); - if (Asm.getBackendPtr()->requiresDiffExpressionRelocations()) - return None; - if (!Hi->getFragment() || Hi->getFragment() != Lo->getFragment() || Hi->isVariable() || Lo->isVariable()) return None; diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.h b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.h --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.h +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.h @@ -42,20 +42,6 @@ void setForceRelocs() { ForceRelocs = true; } - // Returns true if relocations will be forced for shouldForceRelocation by - // default. This will be true if relaxation is enabled or had previously - // been enabled. - bool willForceRelocations() const { - return ForceRelocs || STI.getFeatureBits()[RISCV::FeatureRelax]; - } - - // Generate diff expression relocations if the relax feature is enabled or had - // previously been enabled, otherwise it is safe for the assembler to - // calculate these internally. - bool requiresDiffExpressionRelocations() const override { - return willForceRelocations(); - } - // Return Size with extra Nop Bytes for alignment directive in code section. bool shouldInsertExtraNopBytesForCodeAlign(const MCAlignFragment &AF, unsigned &Size) override; diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp @@ -70,7 +70,12 @@ {"fixup_riscv_call", 0, 64, MCFixupKindInfo::FKF_IsPCRel}, {"fixup_riscv_call_plt", 0, 64, MCFixupKindInfo::FKF_IsPCRel}, {"fixup_riscv_relax", 0, 0, 0}, - {"fixup_riscv_align", 0, 0, 0}}; + {"fixup_riscv_align", 0, 0, 0}, + {"fixup_riscv_add_sub_8", 0, 8, 0}, + {"fixup_riscv_add_sub_16", 0, 16, 0}, + {"fixup_riscv_add_sub_32", 0, 32, 0}, + {"fixup_riscv_add_sub_64", 0, 64, 0}, + }; static_assert((array_lengthof(Infos)) == RISCV::NumTargetFixupKinds, "Not all fixup kinds added to Infos array"); @@ -388,8 +393,10 @@ MCFixupKind Kind = Fixup.getKind(); if (Kind >= FirstLiteralRelocationKind) return; + MCContext &Ctx = Asm.getContext(); MCFixupKindInfo Info = getFixupKindInfo(Kind); + if (!Value) return; // Doesn't change encoding. // Apply any target-specific value adjustments. diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp @@ -15,6 +15,8 @@ #include "llvm/MC/MCObjectWriter.h" #include "llvm/Support/ErrorHandling.h" +#include + using namespace llvm; namespace { @@ -33,6 +35,9 @@ return true; } + void sortRelocs(const MCAssembler &Asm, + std::vector &Relocs) override; + protected: unsigned getRelocType(MCContext &Ctx, const MCValue &Target, const MCFixup &Fixup, bool IsPCRel) const override; @@ -50,18 +55,35 @@ const MCFixup &Fixup, bool IsPCRel) const { const MCExpr *Expr = Fixup.getValue(); + // Determine the type of the relocation unsigned Kind = Fixup.getTargetKind(); if (Kind >= FirstLiteralRelocationKind) return Kind - FirstLiteralRelocationKind; + if (IsPCRel) { switch (Kind) { default: Ctx.reportError(Fixup.getLoc(), "Unsupported relocation type"); return ELF::R_RISCV_NONE; + case FK_Data_8: + if (isa(Expr)) + return RISCV::fixup_riscv_add_sub_64; + Ctx.reportError(Fixup.getLoc(), "Unsupported relocation type"); + return ELF::R_RISCV_NONE; case FK_Data_4: case FK_PCRel_4: + if (isa(Expr)) + return RISCV::fixup_riscv_add_sub_32; return ELF::R_RISCV_32_PCREL; + case FK_Data_2: + if (isa(Expr)) + return RISCV::fixup_riscv_add_sub_16; + break; + case FK_Data_1: + if (isa(Expr)) + return RISCV::fixup_riscv_add_sub_8; + break; case RISCV::fixup_riscv_pcrel_hi20: return ELF::R_RISCV_PCREL_HI20; case RISCV::fixup_riscv_pcrel_lo12_i: @@ -106,26 +128,6 @@ return ELF::R_RISCV_32; case FK_Data_8: return ELF::R_RISCV_64; - case FK_Data_Add_1: - return ELF::R_RISCV_ADD8; - case FK_Data_Add_2: - return ELF::R_RISCV_ADD16; - case FK_Data_Add_4: - return ELF::R_RISCV_ADD32; - case FK_Data_Add_8: - return ELF::R_RISCV_ADD64; - case FK_Data_Add_6b: - return ELF::R_RISCV_SET6; - case FK_Data_Sub_1: - return ELF::R_RISCV_SUB8; - case FK_Data_Sub_2: - return ELF::R_RISCV_SUB16; - case FK_Data_Sub_4: - return ELF::R_RISCV_SUB32; - case FK_Data_Sub_8: - return ELF::R_RISCV_SUB64; - case FK_Data_Sub_6b: - return ELF::R_RISCV_SUB6; case RISCV::fixup_riscv_hi20: return ELF::R_RISCV_HI20; case RISCV::fixup_riscv_lo12_i: @@ -147,6 +149,36 @@ } } +void RISCVELFObjectWriter::sortRelocs(const MCAssembler &Asm, + std::vector &Relocs) { + for (unsigned long RI = 0, RE = Relocs.size(); RI < RE; ++RI) { + std::tuple paired; + + switch (Relocs[RI].Type) { + default: continue; + case RISCV::Fixups::fixup_riscv_add_sub_8: + paired = std::make_tuple(ELF::R_RISCV_ADD8, ELF::R_RISCV_SUB8); + break; + case RISCV::Fixups::fixup_riscv_add_sub_16: + paired = std::make_tuple(ELF::R_RISCV_ADD16, ELF::R_RISCV_SUB16); + break; + case RISCV::Fixups::fixup_riscv_add_sub_32: + paired = std::make_tuple(ELF::R_RISCV_ADD32, ELF::R_RISCV_SUB32); + break; + case RISCV::Fixups::fixup_riscv_add_sub_64: + paired = std::make_tuple(ELF::R_RISCV_ADD64, ELF::R_RISCV_SUB64); + break; + } + + auto iterator = std::begin(Relocs); + std::advance(iterator, RI); + Relocs[RI].Type = std::get<0>(paired); + Relocs.emplace(iterator, Relocs[RI].Offset, nullptr, std::get<1>(paired), 0, + nullptr, 0); + ++RI, ++RE; + } +} + std::unique_ptr llvm::createRISCVELFObjectWriter(uint8_t OSABI, bool Is64Bit) { return std::make_unique(OSABI, Is64Bit); diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.cpp --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.cpp +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.cpp @@ -58,6 +58,7 @@ } MCA.setELFHeaderEFlags(EFlags); + MCA.setRelaxAll(STI.getFeatureBits()[RISCV::FeatureRelax]); } MCELFStreamer &RISCVTargetELFStreamer::getStreamer() { diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h @@ -82,6 +82,11 @@ // relaxation. fixup_riscv_align, + fixup_riscv_add_sub_8, + fixup_riscv_add_sub_16, + fixup_riscv_add_sub_32, + fixup_riscv_add_sub_64, + // fixup_riscv_invalid - used as a sentinel and a marker, must be last fixup fixup_riscv_invalid, NumTargetFixupKinds = fixup_riscv_invalid - FirstTargetFixupKind