Index: lld/ELF/MarkLive.cpp =================================================================== --- lld/ELF/MarkLive.cpp +++ lld/ELF/MarkLive.cpp @@ -167,6 +167,9 @@ case SHT_PREINIT_ARRAY: return true; default: + if (Sec->Flags & SHF_LINK_ORDER) + return false; + if (!(Sec->Flags & SHF_ALLOC)) return true; Index: lld/test/ELF/gc-sections-metadata.s =================================================================== --- /dev/null +++ lld/test/ELF/gc-sections-metadata.s @@ -0,0 +1,38 @@ +# REQUIRES: x86 + +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o +# RUN: ld.lld --gc-sections %t.o -o %t +# RUN: llvm-objdump -section-headers %t | FileCheck %s + +# CHECK: 1 .foo1 +# CHECK-NEXT: bar1 +# CHECK-NEXT: .zed1 +# CHECK-NEXT: .text +# CHECK-NEXT: .comment +# CHECK-NEXT: .symtab +# CHECK-NEXT: .shstrtab +# CHECK-NEXT: .strtab + +.global _start +_start: +.quad .foo1 + +.section .foo1,"a" +.quad 0 + +.section .foo2,"a" +.quad 0 + +.section bar1,"am",@progbits,.foo1 +.quad .zed1 +.quad .foo1 + +.section bar2,"am",@progbits,.foo2 +.quad .zed2 +.quad .foo2 + +.section .zed1,"a" +.quad 0 + +.section .zed2,"a" +.quad 0 Index: llvm/docs/Extensions.rst =================================================================== --- llvm/docs/Extensions.rst +++ llvm/docs/Extensions.rst @@ -204,6 +204,24 @@ The unique number is not present in the resulting object at all. It is just used in the assembler to differentiate the sections. +The 'm' flag is mapped to SHF_LINK_ORDER. If it is present, a symbol +must be given that identifies the section to be placed is the +.sh_link. + +.. code-block:: gas + + .section .foo,"a",@progbits + .Ltmp: + .section .bar,"am",@progbits,.Ltmp + +which is equivalent to just + +.. code-block:: gas + + .section .foo,"a",@progbits + .section .bar,"am",@progbits,.foo + + Target Specific Behaviour ========================= Index: llvm/include/llvm/MC/MCContext.h =================================================================== --- llvm/include/llvm/MC/MCContext.h +++ llvm/include/llvm/MC/MCContext.h @@ -352,7 +352,15 @@ MCSectionELF *getELFSection(const Twine &Section, unsigned Type, unsigned Flags, unsigned EntrySize, - const Twine &Group, unsigned UniqueID); + const Twine &Group, unsigned UniqueID) { + return getELFSection(Section, Type, Flags, EntrySize, Group, UniqueID, + nullptr); + } + + MCSectionELF *getELFSection(const Twine &Section, unsigned Type, + unsigned Flags, unsigned EntrySize, + const Twine &Group, unsigned UniqueID, + const MCSectionELF *Associated); MCSectionELF *getELFSection(const Twine &Section, unsigned Type, unsigned Flags, unsigned EntrySize, Index: llvm/lib/MC/ELFObjectWriter.cpp =================================================================== --- llvm/lib/MC/ELFObjectWriter.cpp +++ llvm/lib/MC/ELFObjectWriter.cpp @@ -1157,8 +1157,7 @@ break; } - if (TargetObjectWriter->getEMachine() == ELF::EM_ARM && - Section.getType() == ELF::SHT_ARM_EXIDX) + if (Section.getFlags() & ELF::SHF_LINK_ORDER) sh_link = SectionIndexMap.lookup(Section.getAssociatedSection()); WriteSecHdrEntry(StrTabBuilder.getOffset(Section.getSectionName()), Index: llvm/lib/MC/MCContext.cpp =================================================================== --- llvm/lib/MC/MCContext.cpp +++ llvm/lib/MC/MCContext.cpp @@ -358,13 +358,14 @@ MCSectionELF *MCContext::getELFSection(const Twine &Section, unsigned Type, unsigned Flags, unsigned EntrySize, - const Twine &Group, unsigned UniqueID) { + const Twine &Group, unsigned UniqueID, + const MCSectionELF *Associated) { MCSymbolELF *GroupSym = nullptr; if (!Group.isTriviallyEmpty() && !Group.str().empty()) GroupSym = cast(getOrCreateSymbol(Group)); return getELFSection(Section, Type, Flags, EntrySize, GroupSym, UniqueID, - nullptr); + Associated); } MCSectionELF *MCContext::getELFSection(const Twine &Section, unsigned Type, Index: llvm/lib/MC/MCParser/ELFAsmParser.cpp =================================================================== --- llvm/lib/MC/MCParser/ELFAsmParser.cpp +++ llvm/lib/MC/MCParser/ELFAsmParser.cpp @@ -145,6 +145,7 @@ bool maybeParseSectionType(StringRef &TypeName); bool parseMergeSize(int64_t &Size); bool parseGroup(StringRef &GroupName); + bool parseMetadataSym(MCSectionELF *&Associated); bool maybeParseUniqueID(int64_t &UniqueID); }; @@ -286,6 +287,9 @@ case 'w': flags |= ELF::SHF_WRITE; break; + case 'm': + flags |= ELF::SHF_LINK_ORDER; + break; case 'M': flags |= ELF::SHF_MERGE; break; @@ -414,6 +418,21 @@ return false; } +bool ELFAsmParser::parseMetadataSym(MCSectionELF *&Associated) { + MCAsmLexer &L = getLexer(); + if (L.isNot(AsmToken::Comma)) + return TokError("expected metadata symbol"); + Lex(); + StringRef Name; + if (getParser().parseIdentifier(Name)) + return true; + MCSymbol *Sym = getContext().lookupSymbol(Name); + if (!Sym || !Sym->isInSection()) + return TokError("symbol is not in a section: " + Name); + Associated = cast(&Sym->getSection()); + return false; +} + bool ELFAsmParser::maybeParseUniqueID(int64_t &UniqueID) { MCAsmLexer &L = getLexer(); if (L.isNot(AsmToken::Comma)) @@ -449,6 +468,7 @@ const MCExpr *Subsection = nullptr; bool UseLastGroup = false; StringRef UniqueStr; + MCSectionELF *Associated = nullptr; int64_t UniqueID = ~0; // Set the defaults first. @@ -511,6 +531,9 @@ if (Group) if (parseGroup(GroupName)) return true; + if (Flags & ELF::SHF_LINK_ORDER) + if (parseMetadataSym(Associated)) + return true; if (maybeParseUniqueID(UniqueID)) return true; } @@ -560,8 +583,8 @@ } } - MCSection *ELFSection = getContext().getELFSection(SectionName, Type, Flags, - Size, GroupName, UniqueID); + MCSection *ELFSection = getContext().getELFSection( + SectionName, Type, Flags, Size, GroupName, UniqueID, Associated); getStreamer().SwitchSection(ELFSection, Subsection); if (getContext().getGenDwarfForAssembly()) { Index: llvm/test/MC/ELF/section-metadata-err1.s =================================================================== --- /dev/null +++ llvm/test/MC/ELF/section-metadata-err1.s @@ -0,0 +1,5 @@ +// RUN: not llvm-mc -triple x86_64-pc-linux-gnu %s -o - 2>&1 | FileCheck %s + +// CHECK: error: symbol is not in a section: foo + + .section .shf_metadata,"am",@progbits,foo Index: llvm/test/MC/ELF/section-metadata-err2.s =================================================================== --- /dev/null +++ llvm/test/MC/ELF/section-metadata-err2.s @@ -0,0 +1,6 @@ +// RUN: not llvm-mc -triple x86_64-pc-linux-gnu %s -o - 2>&1 | FileCheck %s + +// CHECK: error: symbol is not in a section: foo + + .quad foo + .section .shf_metadata,"am",@progbits,foo Index: llvm/test/MC/ELF/section-metadata-err3.s =================================================================== --- /dev/null +++ llvm/test/MC/ELF/section-metadata-err3.s @@ -0,0 +1,6 @@ +// RUN: not llvm-mc -triple x86_64-pc-linux-gnu %s -o - 2>&1 | FileCheck %s + +// CHECK: error: symbol is not in a section: foo + + foo = 42 + .section .shf_metadata,"am",@progbits,foo Index: llvm/test/MC/ELF/section-metadata-err4.s =================================================================== --- /dev/null +++ llvm/test/MC/ELF/section-metadata-err4.s @@ -0,0 +1,5 @@ +// RUN: not llvm-mc -triple x86_64-pc-linux-gnu %s -o - 2>&1 | FileCheck %s + +// CHECK: error: expected metadata symbol + + .section .shf_metadata,"am",@progbits Index: llvm/test/MC/ELF/section.s =================================================================== --- llvm/test/MC/ELF/section.s +++ llvm/test/MC/ELF/section.s @@ -149,3 +149,69 @@ // CHECK: Name: bar-"foo" // CHECK: Section { // CHECK: Name: foo + +// Test SHF_LINK_ORDER + +.section .shf_metadata_target1, "a" + .quad 0 +.section .shf_metadata_target2, "a", @progbits, unique, 1 +.Lshf_metadata_target2_1: + .quad 0 +.section .shf_metadata_target2, "a", @progbits, unique, 2 +.Lshf_metadata_target2_2: + .quad 0 + +.section .shf_metadata1,"am",@progbits,.Lshf_metadata_target2_1 +.section .shf_metadata2,"am",@progbits,.Lshf_metadata_target2_2 +.section .shf_metadata3,"am",@progbits,.shf_metadata_target1 + +// CHECK: Section { +// CHECK: Index: 22 +// CHECK-NEXT: Name: .shf_metadata_target1 + +// CHECK: Section { +// CHECK: Index: 23 +// CHECK-NEXT: Name: .shf_metadata_target2 + +// CHECK: Section { +// CHECK: Index: 24 +// CHECK-NEXT: Name: .shf_metadata_target2 + +// CHECK: Section { +// CHECK: Name: .shf_metadata1 +// 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: +// CHECK-NEXT: Size: +// CHECK-NEXT: Link: 23 +// CHECK-NEXT: Info: 0 + +// CHECK: Section { +// CHECK: Name: .shf_metadata2 +// 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: +// CHECK-NEXT: Size: +// CHECK-NEXT: Link: 24 +// CHECK-NEXT: Info: 0 + +// CHECK: Section { +// CHECK: Name: .shf_metadata3 +// 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: +// CHECK-NEXT: Size: +// CHECK-NEXT: Link: 22 +// CHECK-NEXT: Info: 0