diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp index c8c0a7cdbf10..855d520b6194 100644 --- a/lld/ELF/InputSection.cpp +++ b/lld/ELF/InputSection.cpp @@ -1548,10 +1548,7 @@ void MergeInputSection::splitIntoPieces() { } SectionPiece &MergeInputSection::getSectionPiece(uint64_t offset) { - if (content().size() <= offset) { - Err(getCtx()) << this << ": offset is outside the section"; - return pieces[0]; - } + assert(offset < content().size()); return partition_point( pieces, [=](SectionPiece p) { return p.inputOff <= offset; })[-1]; } diff --git a/lld/ELF/MarkLive.cpp b/lld/ELF/MarkLive.cpp index c43022a6b9d3..1727bd1db069 100644 --- a/lld/ELF/MarkLive.cpp +++ b/lld/ELF/MarkLive.cpp @@ -145,6 +145,11 @@ void MarkLive::resolveReloc(InputSectionBase &sec, offset += rel.addend; else offset += getAddend(ctx, sec, rel); + // Skip out-of-bounds offsets to avoid an assertion failure in + // getSectionPiece. + if (auto *ms = dyn_cast(relSec); + ms && offset >= ms->content().size()) + return; } // fromFDE being true means this is referenced by a FDE in a .eh_frame diff --git a/lld/ELF/Symbols.cpp b/lld/ELF/Symbols.cpp index d9c46c9d28d3..34727f24ddde 100644 --- a/lld/ELF/Symbols.cpp +++ b/lld/ELF/Symbols.cpp @@ -88,8 +88,16 @@ static uint64_t getSymVA(Ctx &ctx, const Symbol &sym, int64_t addend) { // To make this work, we incorporate the addend into the section // offset (and zero out the addend for later processing) so that // we find the right object in the section. - if (d.isSection()) + if (d.isSection()) { offset += addend; + if (auto *ms = dyn_cast(isec); + ms && offset >= ms->content().size()) { + if (offset > ms->content().size()) + Err(ctx) << ms << ": offset 0x" << Twine::utohexstr(offset) + << " is outside the section"; + return 0; + } + } // In the typical case, this is actually very simple and boils // down to adding together 3 numbers: diff --git a/lld/test/ELF/merge-piece-oob.s b/lld/test/ELF/merge-piece-oob.s index ac552cc1498a..1ff34768a4d1 100644 --- a/lld/test/ELF/merge-piece-oob.s +++ b/lld/test/ELF/merge-piece-oob.s @@ -1,18 +1,25 @@ # REQUIRES: x86 ## Test out-of-bounds section symbol offsets in SHF_MERGE sections. +## Non-section symbols and offset <= section_size are accepted, matching GNU ld. # RUN: llvm-mc %s -o %t.o -filetype=obj -triple=x86_64 # RUN: not ld.lld %t.o -o /dev/null -shared 2>&1 | FileCheck %s -DPREFIX=error --implicit-check-not=error: # RUN: ld.lld %t.o -o /dev/null -shared --noinhibit-exec 2>&1 | FileCheck %s -DPREFIX=warning --implicit-check-not=warning: -# CHECK: [[PREFIX]]: {{.*}}:(.foo): offset is outside the section -# CHECK-NEXT: [[PREFIX]]: {{.*}}:(.foo): offset is outside the section -# CHECK-NEXT: [[PREFIX]]: {{.*}}:(.foo): offset is outside the section -# CHECK-NEXT: [[PREFIX]]: {{.*}}:(.foo): offset is outside the section -## .rodata.str1.1 is "abc\0" (4 bytes). -# CHECK-NEXT: [[PREFIX]]: {{.*}}:(.rodata.str1.1): offset is outside the section +## .foo is 8 bytes with entsize=8 (1 piece). .foo+8 (offset==size) is accepted. +# CHECK: [[PREFIX]]: {{.*}}:(.foo): offset 0x9 is outside the section +# CHECK-NEXT: [[PREFIX]]: {{.*}}:(.foo): offset 0x100000000 is outside the section +# CHECK-NEXT: [[PREFIX]]: {{.*}}:(.foo): offset 0xffffffffffffffff is outside the section +## .rodata.str1.1 is "abc\0" (4 bytes). offset<=size is accepted. +# CHECK-NEXT: [[PREFIX]]: {{.*}}:(.rodata.str1.1): offset 0x5 is outside the section ## .data.retain references .foo-1 as well. -# CHECK-NEXT: [[PREFIX]]: {{.*}}:(.foo): offset is outside the section +# CHECK-NEXT: [[PREFIX]]: {{.*}}:(.foo): offset 0xfffffffffffffffe is outside the section + +## Test that --gc-sections with an out-of-bounds offset doesn't crash. +## .data is discarded but .data.retain (SHF_GNU_RETAIN) is kept. +## The bad offset prevents the piece from being marked live, so .foo is discarded. +# RUN: not ld.lld %t.o -o /dev/null --gc-sections 2>&1 | FileCheck %s --check-prefix=GC +# GC: error: relocation refers to a discarded section: .foo .globl _start _start: @@ -24,12 +31,13 @@ _start: .quad .foo - 1 .quad .rodata.str1.1 + 3 .quad .rodata.str1.1 + 4 +.quad .rodata.str1.1 + 5 .quad a0 - 1 .quad a0 + 9 .section .data.retain,"awR" -.quad .foo - 1 +.quad .foo - 2 .section .foo,"aM",@progbits,8 a0: