diff options
author | Fangrui Song <i@maskray.me> | 2023-06-29 09:39:57 -0700 |
---|---|---|
committer | Fangrui Song <i@maskray.me> | 2023-06-29 09:39:57 -0700 |
commit | e6fed06335f4a05aac900380c975b2daf8cbb934 (patch) | |
tree | bf662b85629e698c553a876cbe81d13c9a1b6ce5 /llvm/lib/MC/MCExpr.cpp | |
parent | ff79eb3af6f0def0be2c1d5907e952b394406a08 (diff) | |
download | llvm-e6fed06335f4a05aac900380c975b2daf8cbb934.zip llvm-e6fed06335f4a05aac900380c975b2daf8cbb934.tar.gz llvm-e6fed06335f4a05aac900380c975b2daf8cbb934.tar.bz2 |
[RISCV] Make linker-relaxable instructions terminate MCDataFragment
`MCExpr::evaluateAsAbsolute` has a longstanding bug. When the MCAssembler is
non-null and the MCAsmLayout is null, it may incorrectly fold A-B even if A and
B are separated by a linker-relaxable instruction. This behavior can suppress
some ADD/SUB relocations and lead to wrong results if the linker performs
relaxation.
To fix the bug, ensure that linker-relaxable instructions only appear at the end
of an MCDataFragment, thereby making them terminate the fragment. When computing
A-B, suppress folding if A and B are separated by a linker-relaxable
instruction.
* `.subsection` now correctly give errors for non-foldable expressions.
* gen-dwarf.s will pass even if we add back the .debug_line or .eh_frame/.debug_frame code from D150004
* This will fix suppressed relocation when we add R_RISCV_SET_ULEB128/R_RISCV_SUB_ULEB128.
In the future, we should investigate the desired behavior for
`MCExpr::evaluateAsAbsolute` when both MCAssembler and MCAsmLayout are non-null.
(Note: MCRelaxableFragment is only for assembler-relaxation. If we ever need
linker-relaxable MCRelaxableFragment, we would need to adjust RISCVMCExpr.cpp
(D58943/D73211).)
Depends on D153096
Differential Revision: https://reviews.llvm.org/D153097
Diffstat (limited to 'llvm/lib/MC/MCExpr.cpp')
-rw-r--r-- | llvm/lib/MC/MCExpr.cpp | 18 |
1 files changed, 17 insertions, 1 deletions
diff --git a/llvm/lib/MC/MCExpr.cpp b/llvm/lib/MC/MCExpr.cpp index a8d3fef..a73ae52 100644 --- a/llvm/lib/MC/MCExpr.cpp +++ b/llvm/lib/MC/MCExpr.cpp @@ -659,7 +659,6 @@ static void AttemptToFoldSymbolOffsetDifference( // Try to find a constant displacement from FA to FB, add the displacement // between the offset in FA of SA and the offset in FB of SB. - int64_t Displacement = SA.getOffset() - SB.getOffset(); bool Reverse = false; if (FA == FB) { Reverse = SA.getOffset() < SB.getOffset(); @@ -667,14 +666,31 @@ static void AttemptToFoldSymbolOffsetDifference( Reverse = std::find_if(std::next(FA->getIterator()), SecA.end(), [&](auto &I) { return &I == FB; }) != SecA.end(); } + + uint64_t SAOffset = SA.getOffset(), SBOffset = SB.getOffset(); + int64_t Displacement = SA.getOffset() - SB.getOffset(); if (Reverse) { std::swap(FA, FB); + std::swap(SAOffset, SBOffset); Displacement *= -1; } [[maybe_unused]] bool Found = false; + // Track whether B is before a relaxable instruction and whether A is after + // a relaxable instruction. If SA and SB are separated by a linker-relaxable + // instruction, the difference cannot be resolved as it may be changed by + // the linker. + bool BBeforeRelax = false, AAfterRelax = false; for (auto FI = FB->getIterator(), FE = SecA.end(); FI != FE; ++FI) { auto DF = dyn_cast<MCDataFragment>(FI); + if (DF && DF->isLinkerRelaxable()) { + if (&*FI != FB || SBOffset != DF->getContents().size()) + BBeforeRelax = true; + if (&*FI != FA || SAOffset == DF->getContents().size()) + AAfterRelax = true; + if (BBeforeRelax && AAfterRelax) + return; + } if (&*FI == FA) { Found = true; break; |