[lld][ELF] Fix crash when relaxation pass encounters synthetic sections
In LoongArch and RISC-V, the relaxation pass iterates over input sections within executable output sections. When a linker script places a synthetic section (e.g., .got) into such an output section, the linker would crash because synthetic sections do not have the relaxAux field initialized. The relaxAux data structure is only allocated for non-synthetic sections in initSymbolAnchors. This patch adds the necessary null checks in the relaxation loops (relaxOnce and finalizeRelax) to skip sections that do not require relaxation. A null check is also added to elf::initSymbolAnchors to ensure the subsequent sorting of anchors is safe. Fixes: #184757 Reviewers: MaskRay Pull Request: https://github.com/llvm/llvm-project/pull/184758
This commit is contained in:
@@ -1686,7 +1686,8 @@ bool LoongArch::relaxOnce(int pass) const {
|
||||
if (!(osec->flags & SHF_EXECINSTR))
|
||||
continue;
|
||||
for (InputSection *sec : getInputSections(*osec, storage))
|
||||
changed |= relax(ctx, *sec);
|
||||
if (sec->relaxAux)
|
||||
changed |= relax(ctx, *sec);
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
@@ -1698,6 +1699,8 @@ void LoongArch::finalizeRelax(int passes) const {
|
||||
if (!(osec->flags & SHF_EXECINSTR))
|
||||
continue;
|
||||
for (InputSection *sec : getInputSections(*osec, storage)) {
|
||||
if (!sec->relaxAux)
|
||||
continue;
|
||||
RelaxAux &aux = *sec->relaxAux;
|
||||
if (!aux.relocDeltas)
|
||||
continue;
|
||||
|
||||
@@ -834,6 +834,8 @@ void elf::initSymbolAnchors(Ctx &ctx) {
|
||||
if (!(osec->flags & SHF_EXECINSTR))
|
||||
continue;
|
||||
for (InputSection *sec : getInputSections(*osec, storage)) {
|
||||
if (isa<SyntheticSection>(sec))
|
||||
continue;
|
||||
sec->relaxAux = make<RelaxAux>();
|
||||
if (sec->relocs().size()) {
|
||||
sec->relaxAux->relocDeltas =
|
||||
@@ -878,6 +880,8 @@ void elf::initSymbolAnchors(Ctx &ctx) {
|
||||
if (!(osec->flags & SHF_EXECINSTR))
|
||||
continue;
|
||||
for (InputSection *sec : getInputSections(*osec, storage)) {
|
||||
if (!sec->relaxAux)
|
||||
continue;
|
||||
llvm::sort(sec->relaxAux->anchors, [](auto &a, auto &b) {
|
||||
return std::make_pair(a.offset, a.end) <
|
||||
std::make_pair(b.offset, b.end);
|
||||
@@ -1108,7 +1112,8 @@ bool RISCV::relaxOnce(int pass) const {
|
||||
if (!(osec->flags & SHF_EXECINSTR))
|
||||
continue;
|
||||
for (InputSection *sec : getInputSections(*osec, storage))
|
||||
changed |= relax(ctx, pass, *sec);
|
||||
if (sec->relaxAux)
|
||||
changed |= relax(ctx, pass, *sec);
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
@@ -1232,6 +1237,8 @@ void RISCV::finalizeRelax(int passes) const {
|
||||
if (!(osec->flags & SHF_EXECINSTR))
|
||||
continue;
|
||||
for (InputSection *sec : getInputSections(*osec, storage)) {
|
||||
if (!sec->relaxAux)
|
||||
continue;
|
||||
RelaxAux &aux = *sec->relaxAux;
|
||||
if (!aux.relocDeltas)
|
||||
continue;
|
||||
|
||||
31
lld/test/ELF/loongarch-relax-synthetic-in-text.s
Normal file
31
lld/test/ELF/loongarch-relax-synthetic-in-text.s
Normal file
@@ -0,0 +1,31 @@
|
||||
# REQUIRES: loongarch
|
||||
# RUN: rm -rf %t && split-file %s %t
|
||||
# RUN: llvm-mc --filetype=obj -triple=loongarch64 -mattr=+relax %t/a.s -o %t/a.o
|
||||
|
||||
## Do not crash when we encounter a synthetic section (like .got) that has
|
||||
## been placed inside an executable output section via a linker script.
|
||||
## Synthetic sections do not have relaxAux data structures initialized.
|
||||
|
||||
# RUN: ld.lld -T %t/a.ld %t/a.o -o %t/a.out
|
||||
# RUN: llvm-objdump -s %t/a.out | FileCheck %s
|
||||
|
||||
# CHECK: Contents of section .text:
|
||||
# CHECK-NEXT: 0400001a 8440c002 10000000 00000000
|
||||
|
||||
#--- a.s
|
||||
.global _start
|
||||
_start:
|
||||
pcalau12i $a0, %got_pc_hi20(sym)
|
||||
ld.d $a0, $a0, %got_pc_lo12(sym)
|
||||
|
||||
.data
|
||||
sym:
|
||||
.word 0
|
||||
|
||||
#--- a.ld
|
||||
SECTIONS {
|
||||
.text : {
|
||||
*(.text)
|
||||
*(.got)
|
||||
}
|
||||
}
|
||||
33
lld/test/ELF/riscv-relax-synthetic-in-text.s
Normal file
33
lld/test/ELF/riscv-relax-synthetic-in-text.s
Normal file
@@ -0,0 +1,33 @@
|
||||
# REQUIRES: riscv
|
||||
# RUN: rm -rf %t && split-file %s %t
|
||||
# RUN: llvm-mc --filetype=obj -triple=riscv64 -mattr=+relax %t/a.s -o %t/a.o
|
||||
|
||||
## Do not crash when we encounter a synthetic section (like .got) that has
|
||||
## been placed inside an executable output section via a linker script.
|
||||
## Synthetic sections do not have relaxAux data structures initialized.
|
||||
|
||||
# RUN: ld.lld -T %t/a.ld %t/a.o -o %t/a.out
|
||||
# RUN: llvm-objdump -s %t/a.out | FileCheck %s
|
||||
|
||||
# CHECK: Contents of section .text:
|
||||
# CHECK-NEXT: 17050000 03350501 00000000 00000000
|
||||
# CHECK-NEXT: 18000000 00000000
|
||||
|
||||
#--- a.s
|
||||
.global _start
|
||||
_start:
|
||||
1:
|
||||
auipc a0, %got_pcrel_hi(sym)
|
||||
ld a0, %pcrel_lo(1b)(a0)
|
||||
|
||||
.data
|
||||
sym:
|
||||
.word 0
|
||||
|
||||
#--- a.ld
|
||||
SECTIONS {
|
||||
.text : {
|
||||
*(.text)
|
||||
*(.got)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user