diff --git a/lld/ELF/MarkLive.cpp b/lld/ELF/MarkLive.cpp --- a/lld/ELF/MarkLive.cpp +++ b/lld/ELF/MarkLive.cpp @@ -56,7 +56,7 @@ void mark(); template - void resolveReloc(InputSectionBase &sec, RelTy &rel, bool isLSDA); + void resolveReloc(InputSectionBase &sec, RelTy &rel, bool fromFDE); template void scanEhFrameSection(EhInputSection &eh, ArrayRef rels); @@ -89,7 +89,7 @@ template template void MarkLive::resolveReloc(InputSectionBase &sec, RelTy &rel, - bool isLSDA) { + bool fromFDE) { Symbol &sym = sec.getFile()->getRelocTargetSym(rel); // If a symbol is referenced in a live section, it is used. @@ -104,7 +104,16 @@ if (d->isSection()) offset += getAddend(sec, rel); - if (!isLSDA || !(relSec->flags & SHF_EXECINSTR)) + // fromFDE being true means this is referenced by a FDE in a .eh_frame + // piece. The relocation points to the described function or to a LSDA. We + // only need to keep the LSDA live, so ignore anything that points to + // executable sections. If the LSDA is in a section group, we ignore the + // relocation as well because (a) if the associated text section is live, + // the LSDA will be retained due to section group rules (b) if the + // associated text section should be discarded, marking the LSDA will + // unnecessarily retain the text section. + if (!(fromFDE && + ((relSec->flags & SHF_EXECINSTR) || relSec->nextInSectionGroup))) enqueue(relSec, offset); return; } @@ -148,9 +157,6 @@ continue; } - // This is a FDE. The relocations point to the described function or to - // a LSDA. We only need to keep the LSDA alive, so ignore anything that - // points to executable sections. uint64_t pieceEnd = piece.inputOff + piece.size; for (size_t j = firstRelI, end2 = rels.size(); j < end2 && rels[j].r_offset < pieceEnd; ++j) diff --git a/lld/test/ELF/gc-sections-lsda.s b/lld/test/ELF/gc-sections-lsda.s --- a/lld/test/ELF/gc-sections-lsda.s +++ b/lld/test/ELF/gc-sections-lsda.s @@ -1,21 +1,48 @@ -// REQUIRES: x86 - -// RUN: llvm-mc %s -o %t.o -filetype=obj -triple=x86_64-pc-linux -// RUN: ld.lld -shared --gc-sections %t.o -o %t - -// Test that we handle .eh_frame keeping sections alive. We could be more -// precise and gc the entire contents of this file, but test that at least -// we are consistent: if we keep .abc, we have to keep .foo - -// RUN: llvm-readobj -S %t | FileCheck %s -// CHECK: Name: .abc -// CHECK: Name: .foo - - .cfi_startproc - .cfi_lsda 0x1b,zed - .cfi_endproc - .section .abc,"a" -zed: - .long bar-. - .section .foo,"ax" -bar: +# REQUIRES: x86 +# RUN: llvm-mc %s -o %t.o -filetype=obj -triple=x86_64-pc-linux + +## Discard an unused .gcc_except_table in a COMDAT group if the associated text +## section is discarded. + +# RUN: ld.lld --gc-sections --print-gc-sections -u _Z3foov %t.o -o /dev/null | \ +# RUN: FileCheck %s --implicit-check-not=.gcc_except_table + +# CHECK: removing unused section {{.*}}.o:(.text._Z6comdatv) +# CHECK-NEXT: removing unused section {{.*}}.o:(.gcc_except_table._Z6comdatv) + +## An unused non-group .gcc_except_table is not discarded. + +# RUN: ld.lld --gc-sections --print-gc-sections -u _Z6comdatv %t.o -o /dev/null | \ +# RUN: FileCheck /dev/null --implicit-check-not=.gcc_except_table + +## If the text sections are live, the .gcc_except_table sections are retained as +## well because they are referenced by .eh_frame pieces. + +# RUN: ld.lld --gc-sections --print-gc-sections -u _Z3foov -u _Z6comdatv %t.o -o /dev/null | \ +# RUN: FileCheck %s --check-prefix=KEEP + +# KEEP-NOT: .gcc_except_table + +.section .text._Z3foov,"ax",@progbits +.globl _Z3foov +_Z3foov: + .cfi_startproc + ret + .cfi_lsda 0x1b,.Lexception0 + .cfi_endproc + +.section .text._Z6comdatv,"axG",@progbits,_Z6comdatv,comdat +.globl _Z6comdatv +_Z6comdatv: + .cfi_startproc + ret + .cfi_lsda 0x1b,.Lexception1 + .cfi_endproc + +.section .gcc_except_table._Z3foov,"a",@progbits +.Lexception0: + .byte 255 + +.section .gcc_except_table._Z6comdatv,"aG",@progbits,_Z6comdatv,comdat +.Lexception1: + .byte 255