Index: lld/ELF/InputFiles.cpp =================================================================== --- lld/ELF/InputFiles.cpp +++ lld/ELF/InputFiles.cpp @@ -323,7 +323,7 @@ fatal(toString(this) + ": invalid sh_link index: " + Twine(Sec.sh_link)); auto *IS = cast>(Sections[Sec.sh_link]); - IS->DependentSection = Sections[I]; + 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_ASSOCIATED) { + 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. 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,"ao" +.quad .bar1 - . + +.section foo2,"ao" +.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 'o' and it maps to SHF_ASSOCIATIVE. + Target Specific Behaviour ========================= Index: llvm/include/llvm/Support/ELF.h =================================================================== --- llvm/include/llvm/Support/ELF.h +++ llvm/include/llvm/Support/ELF.h @@ -746,6 +746,9 @@ // Identifies a section containing compressed data. SHF_COMPRESSED = 0x800U, + // FIXME: Tentative value. + SHF_ASSOCIATED = 0x1000U, + // This section is excluded from the final executable or shared library. SHF_EXCLUDE = 0x80000000U, 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 'o': + flags |= ELF::SHF_ASSOCIATED; + 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,"ao" +// CHECK: Section { +// CHECK: Name: .shf_link_order +// CHECK-NEXT: Type: SHT_PROGBITS +// CHECK-NEXT: Flags [ +// CHECK-NEXT: SHF_ALLOC +// CHECK-NEXT: SHF_ASSOCIATED +// CHECK-NEXT: ] +// CHECK-NEXT: Address: +// CHECK-NEXT: Offset: 0x40 +// CHECK-NEXT: Size: 0 +// CHECK-NEXT: Link: 0 Index: llvm/tools/llvm-readobj/ELFDumper.cpp =================================================================== --- llvm/tools/llvm-readobj/ELFDumper.cpp +++ llvm/tools/llvm-readobj/ELFDumper.cpp @@ -1055,6 +1055,7 @@ ENUM_ENT(SHF_MASKOS, "o"), ENUM_ENT(SHF_MASKPROC, "p"), ENUM_ENT_1(SHF_COMPRESSED), + ENUM_ENT_1(SHF_ASSOCIATED), }; static const EnumEntry ElfXCoreSectionFlags[] = {