/// 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.
FragmentType Kind;
+ /// Whether fragment is being laid out.
+ bool IsBeingLaidOut;
+
protected:
bool HasInstructions;
assert((!Prev || isFragmentValid(Prev)) &&
"Attempt to compute fragment before its predecessor!");
+ assert(!F->IsBeingLaidOut && "Already being laid out!");
+ F->IsBeingLaidOut = true;
+
++stats::FragmentLayouts;
// Compute fragment offset and size.
F->Offset = Prev->Offset + getAssembler().computeFragmentSize(*this, *Prev);
else
F->Offset = 0;
+ F->IsBeingLaidOut = false;
LastValidFragment[F->getParent()] = F;
// If bundling is enabled and this fragment has instructions in it, it has to
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
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());
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();
+
+ // A fragment ordered before F is currently being laid out.
+ const MCFragment *FirstInvalidFragment = &*I;
+ if (FirstInvalidFragment->IsBeingLaidOut)
+ 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))
MCFragment::MCFragment(FragmentType Kind, bool HasInstructions,
MCSection *Parent)
: Parent(Parent), Atom(nullptr), Offset(~UINT64_C(0)), LayoutOrder(0),
- Kind(Kind), HasInstructions(HasInstructions) {
+ Kind(Kind), IsBeingLaidOut(false), HasInstructions(HasInstructions) {
if (Parent && !isa<MCDummyFragment>(*this))
Parent->getFragmentList().push_back(this);
}
--- /dev/null
+# RUN: not llvm-mc --filetype=obj %s -o /dev/null 2>&1 | FileCheck %s
+
+fct_end:
+
+# CHECK: layout-interdependency.s:[[#@LINE+1]]:7: error: expected assembly-time absolute expression
+.fill (data_start - fct_end), 1, 42
+# CHECK: layout-interdependency.s:[[#@LINE+1]]:7: error: expected assembly-time absolute expression
+.fill (fct_end - data_start), 1, 42
+
+data_start: