Index: ELF/LinkerScript.cpp =================================================================== --- ELF/LinkerScript.cpp +++ ELF/LinkerScript.cpp @@ -752,25 +752,6 @@ } } -static bool isAllSectionDescription(const OutputSection &Cmd) { - // We do not remove empty sections that are explicitly - // assigned to any segment. - if (!Cmd.Phdrs.empty()) - return false; - - // We do not want to remove sections that have custom address or align - // expressions set even if them are empty. We keep them because we - // want to be sure that any expressions can be evaluated and report - // an error otherwise. - if (Cmd.AddrExpr || Cmd.AlignExpr || Cmd.LMAExpr) - return false; - - for (BaseCommand *Base : Cmd.SectionCommands) - if (!isa(*Base)) - return false; - return true; -} - void LinkerScript::adjustSectionsBeforeSorting() { // If the output section contains only symbol assignments, create a // corresponding output section. The issue is what to do with linker script @@ -803,7 +784,7 @@ continue; } - if (!isAllSectionDescription(*Sec)) + if (!Sec->isAllSectionDescription()) Sec->Flags = Flags; else Cmd = nullptr; Index: ELF/OutputSections.h =================================================================== --- ELF/OutputSections.h +++ ELF/OutputSections.h @@ -42,6 +42,8 @@ public: OutputSection(StringRef Name, uint32_t Type, uint64_t Flags); + bool isAllSectionDescription() const; + static bool classof(const SectionBase *S) { return S->kind() == SectionBase::Output; } Index: ELF/OutputSections.cpp =================================================================== --- ELF/OutputSections.cpp +++ ELF/OutputSections.cpp @@ -76,6 +76,25 @@ Live = false; } +bool OutputSection::isAllSectionDescription() const { + // We do not remove empty sections that are explicitly + // assigned to any segment. + if (!Phdrs.empty()) + return false; + + // We do not want to remove sections that have custom address or align + // expressions set even if them are empty. We keep them because we + // want to be sure that any expressions can be evaluated and report + // an error otherwise. + if (AddrExpr || AlignExpr || LMAExpr) + return false; + + for (BaseCommand *Base : SectionCommands) + if (!isa(*Base)) + return false; + return true; +} + // We allow sections of types listed below to merged into a // single progbits section. This is typically done by linker // scripts. Merging nobits and progbits will force disk space Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -1385,7 +1385,7 @@ // If there are no other alive input sections left, we remove output // section from the output. - if (getInputSections(OS).empty()) + if (getInputSections(OS).empty() && OS->isAllSectionDescription()) OS->Live = false; } } Index: test/ELF/linkerscript/empty-synthetic-removed-flags.s =================================================================== --- test/ELF/linkerscript/empty-synthetic-removed-flags.s +++ test/ELF/linkerscript/empty-synthetic-removed-flags.s @@ -7,8 +7,7 @@ ## We have ".got.plt" synthetic section with SHF_ALLOC|SHF_WRITE flags. ## It is empty, so linker removes it, but it have to keep ".got.plt" output ## section because of BYTE command. Here we check that result output section -## gets the same flags as previous allocatable section and does not get -## SHF_WRITE flag from removed syntethic input section. +## still remembers what the flags of .got.plt are. # CHECK: Section { # CHECK: Index: 2 @@ -16,13 +15,22 @@ # CHECK-NEXT: Type: SHT_PROGBITS # CHECK-NEXT: Flags [ # CHECK-NEXT: SHF_ALLOC -# CHECK-NEXT: SHF_EXECINSTR +# CHECK-NEXT: SHF_WRITE # CHECK-NEXT: ] ## Check flags are the same if we omit empty synthetic section in script. # RUN: echo "SECTIONS { .foo : { *(.foo) } .bar : { BYTE(0x11) }}" > %t.script # RUN: ld.lld -o %t --script %t.script %t.o -# RUN: llvm-readobj -s %t | FileCheck %s +# RUN: llvm-readobj -s %t | FileCheck --check-prefix=EMPTY %s + +# EMPTY: Section { +# EMPTY: Index: 2 +# EMPTY: Name: .bar +# EMPTY-NEXT: Type: SHT_PROGBITS +# EMPTY-NEXT: Flags [ +# EMPTY-NEXT: SHF_ALLOC +# EMPTY-NEXT: SHF_EXECINSTR +# EMPTY-NEXT: ] .section .foo,"ax" .quad 0 Index: test/ELF/pr36475.s =================================================================== --- /dev/null +++ test/ELF/pr36475.s @@ -0,0 +1,29 @@ +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o +# RUN: echo "PHDRS {" > %t.script +# RUN: echo " ph_text PT_LOAD FLAGS (0x1 | 0x4);" >> %t.script +# RUN: echo " ph_data PT_LOAD FLAGS (0x2 | 0x4);" >> %t.script +# RUN: echo "}" >> %t.script +# RUN: echo "SECTIONS {" >> %t.script +# RUN: echo " .text : { *(.text*) } : ph_text" >> %t.script +# RUN: echo " . = ALIGN(0x4000);" >> %t.script +# RUN: echo " .got.plt : { BYTE(42); *(.got); } : ph_data" >> %t.script +# RUN: echo "}" >> %t.script +# RUN: ld.lld -T %t.script %t.o -o %t.elf +# RUN: llvm-readobj -l -elf-output-style=GNU %t.elf | FileCheck %s + +# CHECK: Section to Segment mapping: +# CHECK-NEXT: Segment Sections... +# CHECK-NEXT: 00 .text executable +# CHECK-NEXT: 01 .got.plt + +.text +.globl _start +.type _start,@function +_start: + callq custom_func + ret + +.section executable,"ax",@progbits +.type custom_func,@function +custom_func: + ret