Index: ELF/LinkerScript.cpp =================================================================== --- ELF/LinkerScript.cpp +++ ELF/LinkerScript.cpp @@ -259,6 +259,18 @@ } template +static void updateFlags(OutputSectionBase *OutSec, + ArrayRef *> InputSec) { + typedef typename ELFT::uint uintX_t; + + uintX_t Flags = OutSec->getFlags(); + for (InputSectionBase *I : InputSec) + Flags |= I->getSectionHdr()->sh_flags; + + OutSec->setFlags(Flags & ~SHF_GROUP & ~SHF_COMPRESSED); +} + +template void LinkerScript::createSections(OutputSectionFactory &Factory) { for (const std::unique_ptr &Base1 : Opt.Commands) { if (auto *Cmd = dyn_cast(Base1.get())) { @@ -285,6 +297,7 @@ OutputSections->push_back(OutSec); for (InputSectionBase *Sec : V) OutSec->addSection(Sec); + updateFlags(OutSec, V); } } @@ -300,6 +313,7 @@ if (IsNew) OutputSections->push_back(OutSec); OutSec->addSection(S); + updateFlags(OutSec, S); } } } Index: ELF/OutputSections.h =================================================================== --- ELF/OutputSections.h +++ ELF/OutputSections.h @@ -93,6 +93,7 @@ uintX_t getSize() const { return Header.sh_size; } void setSize(uintX_t Val) { Header.sh_size = Val; } uintX_t getFlags() const { return Header.sh_flags; } + void setFlags(uintX_t Val) { Header.sh_flags = Val; } uint32_t getPhdrFlags() const; uintX_t getFileOff() const { return Header.sh_offset; } uintX_t getAlignment() const { return Header.sh_addralign; } Index: ELF/OutputSections.cpp =================================================================== --- ELF/OutputSections.cpp +++ ELF/OutputSections.cpp @@ -1817,7 +1817,12 @@ OutputSectionFactory::createKey(InputSectionBase *C, StringRef OutsecName) { const Elf_Shdr *H = C->getSectionHdr(); - uintX_t Flags = H->sh_flags & ~SHF_GROUP & ~SHF_COMPRESSED; + + // Ignore flags part of the key if linkerscript has SECTIONS command. + // We combine input sections with different attributes into single output + // section in this case. Flags are updated later. + uintX_t Flags = ScriptConfig->HasContents ? 0 : H->sh_flags & ~SHF_GROUP & + ~SHF_COMPRESSED; // For SHF_MERGE we create different output sections for each alignment. // This makes each output section simple and keeps a single level mapping from Index: test/ELF/linkerscript/linkerscript-phdrs.s =================================================================== --- test/ELF/linkerscript/linkerscript-phdrs.s +++ test/ELF/linkerscript/linkerscript-phdrs.s @@ -17,8 +17,9 @@ # CHECK-NEXT: PhysicalAddress: 0x10000000 # CHECK-NEXT: FileSize: 521 # CHECK-NEXT: MemSize: 521 -# CHECK-NEXT: Flags [ (0x5) +# CHECK-NEXT: Flags [ (0x7) # CHECK-NEXT: PF_R (0x4) +# CHECK-NEXT: PF_W (0x2) # CHECK-NEXT: PF_X (0x1) # CHECK-NEXT: ] Index: test/ELF/linkerscript/linkerscript-repsection-va.s =================================================================== --- test/ELF/linkerscript/linkerscript-repsection-va.s +++ test/ELF/linkerscript/linkerscript-repsection-va.s @@ -7,8 +7,19 @@ # CHECK: Sections: # CHECK-NEXT: Idx Name Size Address Type # CHECK-NEXT: 0 00000000 0000000000000000 -# CHECK-NEXT: 1 .foo 00000008 0000000000000120 DATA -# CHECK-NEXT: 2 .text 00000001 0000000000000128 TEXT DATA +# CHECK-NEXT: 1 .foo 0000000c 0000000000000158 TEXT DATA +# CHECK-NEXT: 2 .text 00000001 0000000000000164 TEXT DATA + +# RUN: llvm-readobj -sections %t1 | FileCheck %s --check-prefix=ATTR +# ATTR: Section { +# ATTR: Index: +# ATTR: Name: .foo +# ATTR-NEXT: Type: +# ATTR-NEXT: Flags [ +# ATTR-NEXT: SHF_ALLOC +# ATTR-NEXT: SHF_EXECINSTR +# ATTR-NEXT: SHF_WRITE +# ATTR-NEXT: ] .global _start _start: @@ -21,3 +32,7 @@ .section .foo.2,"aw" foo2: .long 0 + +.section .foo.3,"ax" +foo3: + .long 0