diff --git a/llvm/include/llvm/MC/MCAsmLayout.h b/llvm/include/llvm/MC/MCAsmLayout.h --- a/llvm/include/llvm/MC/MCAsmLayout.h +++ b/llvm/include/llvm/MC/MCAsmLayout.h @@ -10,6 +10,7 @@ #define LLVM_MC_MCASMLAYOUT_H #include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallVector.h" namespace llvm { @@ -31,6 +32,9 @@ /// List of sections in layout order. llvm::SmallVector SectionOrder; + /// Set of fragments currently being laid out. + mutable SmallPtrSet LayingOutFragmentsSet; + /// The last fragment which was laid out, or 0 if nothing has been laid /// out. Fragments are always laid out in order, so all fragments with a /// lower ordinal will be valid. @@ -49,6 +53,10 @@ /// Get the assembler object this is a layout for. MCAssembler &getAssembler() const { return Assembler; } + bool isFragmentValidating(const MCFragment *F) const { + return LayingOutFragmentsSet.find(F) != LayingOutFragmentsSet.end(); + } + /// Invalidate the fragments starting with F because it has been /// resized. The fragment's size should have already been updated, but /// its bundle padding will be recomputed. 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 @@ -397,6 +397,10 @@ assert((!Prev || isFragmentValid(Prev)) && "Attempt to compute fragment before its predecessor!"); + bool InsertionSuccess{}; + std::tie(std::ignore, InsertionSuccess) = LayingOutFragmentsSet.insert(F); + assert(InsertionSuccess && "Already being laid out!"); + ++stats::FragmentLayouts; // Compute fragment offset and size. @@ -404,6 +408,7 @@ F->Offset = Prev->Offset + getAssembler().computeFragmentSize(*this, *Prev); else F->Offset = 0; + LayingOutFragmentsSet.erase(F); LastValidFragment[F->getParent()] = F; // If bundling is enabled and this fragment has instructions in it, it has to 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 @@ -547,8 +547,10 @@ if (!Asm->getWriter().isSymbolRefDifferenceFullyResolved(*Asm, A, B, InSet)) return; - if (SA.getFragment() == SB.getFragment() && !SA.isVariable() && - !SA.isUnset() && !SB.isVariable() && !SB.isUnset()) { + MCFragment *FA = SA.getFragment(); + MCFragment *FB = SB.getFragment(); + if (FA == FB && !SA.isVariable() && !SA.isUnset() && !SB.isVariable() && + !SB.isUnset()) { Addend += (SA.getOffset() - SB.getOffset()); // Pointers to Thumb symbols need to have their low-bit set to allow @@ -570,12 +572,16 @@ if (!Layout) return; - const MCSection &SecA = *SA.getFragment()->getParent(); - const MCSection &SecB = *SB.getFragment()->getParent(); + const MCSection &SecA = *FA->getParent(); + const MCSection &SecB = *FB->getParent(); if ((&SecA != &SecB) && !Addrs) return; + if (Layout && + (Layout->isFragmentValidating(FA) || Layout->isFragmentValidating(FB))) + return; + // Eagerly evaluate. Addend += Layout->getSymbolOffset(A->getSymbol()) - Layout->getSymbolOffset(B->getSymbol()); diff --git a/llvm/test/MC/AsmParser/pr45805.s b/llvm/test/MC/AsmParser/pr45805.s new file mode 100644 --- /dev/null +++ b/llvm/test/MC/AsmParser/pr45805.s @@ -0,0 +1,10 @@ +// RUN: not llvm-mc --filetype=obj %s -o /dev/null 2>&1 | FileCheck %s + + +fct_end: + +// CHECK: pr45805.s:7:7: error: expected assembly-time absolute expression +.fill (data_start - fct_end), 1, 42 + +data_start: +.long 0x42424242