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; } + /// \returns whether the offset of fragment \p F can be obtained via + /// getFragmentOffset. + bool canGetFragmentOffset(const MCFragment *F) const; + /// 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 Inserted = LayingOutFragmentsSet.insert(F).second; + assert(Inserted && "Already being laid out!"); + (void)Inserted; + ++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,17 @@ 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; + // One of the symbol involved is part of a fragment being laid out. Quit now + // to avoid a self loop. + if (!Layout->canGetFragmentOffset(FA) || !Layout->canGetFragmentOffset(FB)) + return; + // Eagerly evaluate. Addend += Layout->getSymbolOffset(A->getSymbol()) - Layout->getSymbolOffset(B->getSymbol()); diff --git a/llvm/lib/MC/MCFragment.cpp b/llvm/lib/MC/MCFragment.cpp --- a/llvm/lib/MC/MCFragment.cpp +++ b/llvm/lib/MC/MCFragment.cpp @@ -48,6 +48,25 @@ return F->getLayoutOrder() <= LastValid->getLayoutOrder(); } +bool MCAsmLayout::canGetFragmentOffset(const MCFragment *F) const { + MCSection *Sec = F->getParent(); + MCSection::iterator I; + if (MCFragment *LastValid = LastValidFragment[Sec]) { + // Fragment already valid, offset is available. + if (F->getLayoutOrder() <= LastValid->getLayoutOrder()) + return true; + I = ++MCSection::iterator(LastValid); + } else + I = Sec->begin(); + const MCFragment *FirstInvalidFragment = &*I; + + // A fragment ordered before F is currently being laid out. + if (LayingOutFragmentsSet.count(FirstInvalidFragment)) + return false; + + return true; +} + void MCAsmLayout::invalidateFragmentsFrom(MCFragment *F) { // If this fragment wasn't already valid, we don't need to do anything. if (!isFragmentValid(F)) diff --git a/llvm/test/MC/AsmParser/layout-interdependency.s b/llvm/test/MC/AsmParser/layout-interdependency.s new file mode 100644 --- /dev/null +++ b/llvm/test/MC/AsmParser/layout-interdependency.s @@ -0,0 +1,10 @@ +# RUN: not llvm-mc --filetype=obj %s -o /dev/null 2>&1 | FileCheck %s + + +fct_end: + +# CHECK: layout-interdependency.s:7:7: error: expected assembly-time absolute expression +.fill (data_start - fct_end), 1, 42 +.fill (fct_end - data_start), 1, 42 + +data_start: