Index: lld/ELF/InputFiles.cpp =================================================================== --- lld/ELF/InputFiles.cpp +++ lld/ELF/InputFiles.cpp @@ -322,8 +322,10 @@ if (Sec.sh_link >= Sections.size()) fatal(toString(this) + ": invalid sh_link index: " + Twine(Sec.sh_link)); - auto *IS = cast>(Sections[Sec.sh_link]); - IS->DependentSection = Sections[I]; + if (uint32_t Link = Sec.sh_link) { + auto *IS = cast>(Sections[Link]); + IS->DependentSections.push_back(Sections[I]); + } } } } Index: lld/ELF/InputSection.h =================================================================== --- lld/ELF/InputSection.h +++ lld/ELF/InputSection.h @@ -273,8 +273,8 @@ // to. The writer sets a value. uint64_t OutSecOff = 0; - // InputSection that is dependent on us (reverse dependency for GC) - InputSectionBase *DependentSection = nullptr; + // InputSections that are dependent on us (reverse dependency for GC) + std::vector *> DependentSections; static bool classof(const InputSectionData *S); Index: lld/ELF/MarkLive.cpp =================================================================== --- lld/ELF/MarkLive.cpp +++ lld/ELF/MarkLive.cpp @@ -87,8 +87,8 @@ for (const typename ELFT::Rel &Rel : Sec.rels()) Fn(resolveReloc(Sec, Rel)); } - if (Sec.DependentSection) - Fn({Sec.DependentSection, 0}); + for (InputSectionBase *D : Sec.DependentSections) + Fn({D, 0}); } // The .eh_frame section is an unfortunate special case. @@ -235,6 +235,14 @@ // Preserve special sections and those which are specified in linker // script KEEP command. for (InputSectionBase *Sec : Symtab::X->Sections) { + if (Sec->Flags & SHF_LINK_ORDER) { + forEachSuccessor( + cast>(*Sec), [=](ResolvedReloc R) { + cast>(R.Sec)->DependentSections.push_back(Sec); + }); + continue; + } + // .eh_frame is always marked as live now, but also it can reference to // sections that contain personality. We preserve all non-text sections // referred by .eh_frame here. @@ -245,8 +253,10 @@ } // Mark all reachable sections. - while (!Q.empty()) - forEachSuccessor(*Q.pop_back_val(), Enqueue); + while (!Q.empty()) { + InputSection &Sec = *Q.pop_back_val(); + forEachSuccessor(Sec, Enqueue); + } } template void elf::markLive(); Index: lld/test/ELF/gc-sections-invert-edge.s =================================================================== --- /dev/null +++ lld/test/ELF/gc-sections-invert-edge.s @@ -0,0 +1,29 @@ +# REQUIRES: x86 + +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t +# RUN: ld.lld --gc-sections %t -o %t2 +# RUN: llvm-objdump -section-headers %t2 | FileCheck %s + +# CHECK: 1 foo1 +# CHECK-NEXT: .bar1 +# CHECK-NEXT: .text +# CHECK-NEXT: .comment +# CHECK-NEXT: .symtab +# CHECK-NEXT: .shstrtab +# CHECK-NEXT: .strtab + +.global _start +_start: +.quad .bar1 - . + +.section foo1,"al" +.quad .bar1 - . + +.section foo2,"al" +.quad .bar2 - . + +.section .bar1,"a" +.quad 0 +.section .bar2,"a" +.quad 0 + Index: llvm/docs/Extensions.rst =================================================================== --- llvm/docs/Extensions.rst +++ llvm/docs/Extensions.rst @@ -204,6 +204,8 @@ The unique number is not present in the resulting object at all. It is just used in the assembler to differentiate the sections. +The section flags can include an 'l' and it maps to SHF_LINK_ORDER. + Target Specific Behaviour ========================= Index: llvm/lib/MC/MCParser/ELFAsmParser.cpp =================================================================== --- llvm/lib/MC/MCParser/ELFAsmParser.cpp +++ llvm/lib/MC/MCParser/ELFAsmParser.cpp @@ -303,6 +303,9 @@ case 'G': flags |= ELF::SHF_GROUP; break; + case 'l': + flags |= ELF::SHF_LINK_ORDER; + break; case '?': *UseLastGroup = true; break; Index: llvm/test/MC/ELF/section.s =================================================================== --- llvm/test/MC/ELF/section.s +++ llvm/test/MC/ELF/section.s @@ -149,3 +149,18 @@ // CHECK: Name: bar-"foo" // CHECK: Section { // CHECK: Name: foo + +// Test SHF_LINK_ORDER + +.section .shf_link_order,"al" +// CHECK: Section { +// CHECK: Name: .shf_link_order +// CHECK-NEXT: Type: SHT_PROGBITS +// CHECK-NEXT: Flags [ +// CHECK-NEXT: SHF_ALLOC +// CHECK-NEXT: SHF_LINK_ORDER +// CHECK-NEXT: ] +// CHECK-NEXT: Address: +// CHECK-NEXT: Offset: 0x40 +// CHECK-NEXT: Size: 0 +// CHECK-NEXT: Link: 0