MC: Generate relocation for a branch crossing linker-relaxable FT_Align fragment

"Encode FT_Align in fragment's variable-size tail" or a neighbor change
caused a regression that was similar to the root cause of
ab0931b6389838cb5d7d11914063a1ddd84102f0
(See the new test (.text3 with a call at the start"))

For a FT_Align fragment, the offset between location A (with offset <=
FixedSize) and B (offset == FixedSize+VarSize) cannot be resolved.

In addition, delete unneeded condition `F->isLinkerRelaxable()`.

LoongArch linker relaxation is largely under-tested, but update it as well.
This commit is contained in:
Fangrui Song 2025-07-26 21:19:48 -07:00
parent 59fdd97fe6
commit 69d0078f16
5 changed files with 53 additions and 16 deletions

View File

@ -346,17 +346,16 @@ static void attemptToFoldSymbolOffsetDifference(const MCAssembler *Asm,
Displacement *= -1;
}
// 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.
// Track whether B is before a relaxable instruction/alignment and whether A
// is after a relaxable instruction/alignment. If SA and SB are separated by
// a linker-relaxable instruction/alignment, the difference cannot be
// resolved as it may be changed by the linker.
bool BBeforeRelax = false, AAfterRelax = false;
for (auto F = FB; F; F = F->getNext()) {
auto DF = F->getKind() == MCFragment::FT_Data ? F : nullptr;
if (DF && DF->isLinkerRelaxable()) {
if (&*F != FB || SBOffset != DF->getContents().size())
if (F && F->isLinkerRelaxable()) {
if (&*F != FB || SBOffset != F->getSize())
BBeforeRelax = true;
if (&*F != FA || SAOffset == DF->getContents().size())
if (&*F != FA || SAOffset == F->getSize())
AAfterRelax = true;
if (BBeforeRelax && AAfterRelax)
return;
@ -370,17 +369,15 @@ static void attemptToFoldSymbolOffsetDifference(const MCAssembler *Asm,
}
int64_t Num;
if (DF) {
Displacement += DF->getContents().size();
} else if (F->getKind() == MCFragment::FT_Relaxable &&
if (F->getKind() == MCFragment::FT_Data) {
Displacement += F->getFixedSize();
} else if ((F->getKind() == MCFragment::FT_Relaxable ||
F->getKind() == MCFragment::FT_Align) &&
Asm->hasFinalLayout()) {
// Before finishLayout, a relaxable fragment's size is indeterminate.
// After layout, during relocation generation, it can be treated as a
// data fragment.
Displacement += F->getSize();
} else if (F->getKind() == MCFragment::FT_Align && Layout &&
F->isLinkerRelaxable()) {
Displacement += Asm->computeFragmentSize(*F);
} else if (auto *FF = dyn_cast<MCFillFragment>(F);
FF && FF->getNumValues().evaluateAsAbsolute(Num)) {
Displacement += Num * FF->getValueSize();

View File

@ -254,6 +254,7 @@ bool LoongArchAsmBackend::relaxAlign(MCFragment &F, unsigned &Size) {
MCFixup Fixup =
MCFixup::create(0, Expr, FirstLiteralRelocationKind + ELF::R_LARCH_ALIGN);
F.setVarFixups({Fixup});
F.setLinkerRelaxable();
F.getParent()->setLinkerRelaxable();
return true;
}

View File

@ -320,6 +320,7 @@ bool RISCVAsmBackend::relaxAlign(MCFragment &F, unsigned &Size) {
MCFixup Fixup =
MCFixup::create(0, Expr, FirstLiteralRelocationKind + ELF::R_RISCV_ALIGN);
F.setVarFixups({Fixup});
F.setLinkerRelaxable();
F.getParent()->setLinkerRelaxable();
return true;
}

View File

@ -9,10 +9,10 @@
# CHECK-NEXT:0 Data LinkerRelaxable Size:8 [97,00,00,00,e7,80,00,00]
# CHECK-NEXT: Fixup @0 Value:specifier(19,ext) Kind:4023
# CHECK-NEXT: Symbol @0 $x
# CHECK-NEXT:8 Align Size:0+4 []
# CHECK-NEXT:8 Align LinkerRelaxable Size:0+4 []
# CHECK-NEXT: Align:8 Fill:0 FillLen:1 MaxBytesToEmit:8 Nops
# CHECK-NEXT: Fixup @0 Value:4 Kind:[[#]]
# CHECK-NEXT:12 Align Size:4+4 [13,05,30,00]
# CHECK-NEXT:12 Align LinkerRelaxable Size:4+4 [13,05,30,00]
# CHECK-NEXT: Align:8 Fill:0 FillLen:1 MaxBytesToEmit:8 Nops
# CHECK-NEXT: Fixup @4 Value:4 Kind:[[#]]
# CHECK-NEXT:]

View File

@ -154,3 +154,41 @@ data2:
2:
bnez t1, 1b
bnez t1, 2b
## .text3 with a call at the start
# NORELAX-RELOC: .rela.text3a
# C-OR-ZCA-EXT-NORELAX-RELOC: .rela.text3a
# RELAX-RELOC: .rela.text3a {
# RELAX-RELOC-NEXT: 0x0 R_RISCV_CALL_PLT foo 0x0
# RELAX-RELOC-NEXT: 0x0 R_RISCV_RELAX - 0x0
# RELAX-RELOC-NEXT: 0xC R_RISCV_BRANCH .Ltmp[[#]] 0x0
# RELAX-RELOC-NEXT: 0x10 R_RISCV_ALIGN - 0x4
# RELAX-RELOC-NEXT: 0x14 R_RISCV_BRANCH .Ltmp[[#]] 0x0
# RELAX-RELOC-NEXT: }
.section .text3a, "ax"
call foo
bnez t1, 1f
bnez t2, 2f
1:
.p2align 3
2:
bnez t1, 1b
bnez t1, 2b
## .text3 with a call at the end
# RELAX-RELOC: .rela.text3b {
# RELAX-RELOC-NEXT: 0x4 R_RISCV_BRANCH .Ltmp[[#]] 0x0
# RELAX-RELOC-NEXT: 0x8 R_RISCV_ALIGN - 0x4
# RELAX-RELOC-NEXT: 0xC R_RISCV_BRANCH .Ltmp[[#]] 0x0
# RELAX-RELOC-NEXT: 0x14 R_RISCV_CALL_PLT foo 0x0
# RELAX-RELOC-NEXT: 0x14 R_RISCV_RELAX - 0x0
# RELAX-RELOC-NEXT: }
.section .text3b, "ax"
bnez t1, 1f
bnez t2, 2f
1:
.p2align 3
2:
bnez t1, 1b
bnez t1, 2b
call foo