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 @@ -513,6 +513,8 @@ const MCSymbol &SA = A->getSymbol(); const MCSymbol &SB = B->getSymbol(); + const MCFragment *FragA = SA.getFragment(); + const MCFragment *FragB = SB.getFragment(); if (SA.isUndefined() || SB.isUndefined()) return; @@ -520,8 +522,9 @@ if (!Asm->getWriter().isSymbolRefDifferenceFullyResolved(*Asm, A, B, InSet)) return; - if (SA.getFragment() == SB.getFragment() && !SA.isVariable() && - !SA.isUnset() && !SB.isVariable() && !SB.isUnset()) { + if (FragA == FragB && !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 @@ -540,13 +543,39 @@ return; } - if (!Layout) + const MCSection &SecA = *FragA->getParent(); + const MCSection &SecB = *FragB->getParent(); + + if ((&SecA != &SecB) && !Addrs) return; - const MCSection &SecA = *SA.getFragment()->getParent(); - const MCSection &SecB = *SB.getFragment()->getParent(); + // Pointers to Thumb symbols need to have their low-bit set to allow + if ((&SecA != &SecB) && !Addrs) + return; - if ((&SecA != &SecB) && !Addrs) + if (SecB.getFragmentList().getNextNode(*FragB) == FragA && + dyn_cast(FragA) && dyn_cast(FragB)) { + Addend += + (SA.getOffset() + (cast(FragB))->getContents().size() - + SB.getOffset()); + + // Pointers to Thumb symbols need to have their low-bit set to allow + // for interworking. + if (Asm->isThumbFunc(&SA)) + Addend |= 1; + + // If symbol is labeled as micromips, we set low-bit to ensure + // correct offset in .gcc_except_table + if (Asm->getBackend().isMicroMips(&SA)) + Addend |= 1; + + // Clear the symbol expr pointers to indicate we have folded these + // operands. + A = B = nullptr; + return; + } + + if (!Layout) return; // Eagerly evaluate.