aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/MC/MCExpr.cpp
diff options
context:
space:
mode:
authorFangrui Song <i@maskray.me>2023-06-29 09:39:57 -0700
committerFangrui Song <i@maskray.me>2023-06-29 09:39:57 -0700
commite6fed06335f4a05aac900380c975b2daf8cbb934 (patch)
treebf662b85629e698c553a876cbe81d13c9a1b6ce5 /llvm/lib/MC/MCExpr.cpp
parentff79eb3af6f0def0be2c1d5907e952b394406a08 (diff)
downloadllvm-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.cpp18
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;