Index: ELF/LinkerScript.h =================================================================== --- ELF/LinkerScript.h +++ ELF/LinkerScript.h @@ -85,6 +85,8 @@ std::vector Phdrs; std::vector Filler; ConstraintKind Constraint = ConstraintKind::NoConstraint; + + void *OutputSection = nullptr; }; enum SortKind { SortNone, SortByName, SortByAlignment }; @@ -164,6 +166,9 @@ std::vector *> createInputSectionList(OutputSectionCommand &Cmd); + void addOrphan(OutputSectionFactory &Factory, StringRef OutputName, + InputSectionBase *I); + // "ScriptConfig" is a bit too long, so define a short name for it. ScriptConfiguration &Opt = *ScriptConfig; Index: ELF/LinkerScript.cpp =================================================================== --- ELF/LinkerScript.cpp +++ ELF/LinkerScript.cpp @@ -259,6 +259,55 @@ } template +static typename ELFT::uint getPermissions(OutputSectionBase *Sec) { + return Sec->getFlags() & (SHF_WRITE | SHF_ALLOC | SHF_EXECINSTR); +} + +template +static OutputSectionBase * +getOutputSection(const std::unique_ptr &Base) { + if (auto *Cmd = dyn_cast(Base.get())) + if (Cmd->OutputSection) + return reinterpret_cast *>(Cmd->OutputSection); + return nullptr; +} + +// Places orphan section to desired position. Which is place after +// the last section with the same access attributes. +// If there is no such section - just adds ophan to the end. +template +void LinkerScript::addOrphan(OutputSectionFactory &Factory, + StringRef OutputName, + InputSectionBase *C) { + bool IsNew; + OutputSectionBase *OutSec; + std::tie(OutSec, IsNew) = Factory.create(C, OutputName); + OutSec->addSection(C); + if (!IsNew) + return; + + auto R = std::find_if( + ScriptConfig->Commands.rbegin(), ScriptConfig->Commands.rend(), + [&](std::unique_ptr &Base) { + OutputSectionBase *S = getOutputSection(Base); + if (!S || S->getType() == SHT_NOBITS) + return false; + return getPermissions(S) == getPermissions(OutSec); + }); + + // We want to place orphan section somewhere. Default position (in the case + // if we did not find some section with the same flags) is end. + // Otherwise we just add orphan section after the last section + // with the same attributes we found earlier. + auto Pos = R != ScriptConfig->Commands.rend() ? R.base() + : ScriptConfig->Commands.end(); + + OutputSectionCommand *OutSecCmd = new OutputSectionCommand(OutputName); + OutSecCmd->OutputSection = OutSec; + ScriptConfig->Commands.emplace(Pos, OutSecCmd); +} + +template void LinkerScript::createSections(OutputSectionFactory &Factory) { for (const std::unique_ptr &Base1 : Opt.Commands) { if (auto *Cmd = dyn_cast(Base1.get())) { @@ -282,7 +331,7 @@ bool IsNew; std::tie(OutSec, IsNew) = Factory.create(Head, Cmd->Name); if (IsNew) - OutputSections->push_back(OutSec); + Cmd->OutputSection = OutSec; for (InputSectionBase *Sec : V) if (!Sec->OutSec) OutSec->addSection(Sec); @@ -291,18 +340,15 @@ // Add orphan sections. for (const std::unique_ptr> &F : - Symtab::X->getObjectFiles()) { - for (InputSectionBase *S : F->getSections()) { - if (isDiscarded(S) || S->OutSec) - continue; - OutputSectionBase *OutSec; - bool IsNew; - std::tie(OutSec, IsNew) = Factory.create(S, getOutputSectionName(S)); - if (IsNew) - OutputSections->push_back(OutSec); - OutSec->addSection(S); - } - } + Symtab::X->getObjectFiles()) + for (InputSectionBase *S : F->getSections()) + if (!isDiscarded(S) && !S->OutSec) + addOrphan(Factory, getOutputSectionName(S), S); + + // Add created output sections to the OutputSections list. + for (const std::unique_ptr &Base : Opt.Commands) + if (OutputSectionBase *S = getOutputSection(Base)) + OutputSections->push_back(S); } template void assignOffsets(OutputSectionBase *Sec) { Index: test/ELF/linkerscript/linkerscript-orphans.s =================================================================== --- test/ELF/linkerscript/linkerscript-orphans.s +++ test/ELF/linkerscript/linkerscript-orphans.s @@ -1,31 +1,52 @@ # REQUIRES: x86 # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t -# RUN: echo "SECTIONS { .writable : { *(.writable) } }" > %t.script +# RUN: echo "SECTIONS { \ +# RUN: .text : { *(.text) } \ +# RUN: .foo1 : { *(.foo1) } \ +# RUN: .foo2 : { *(.foo2) } \ +# RUN: .bar1 : { *(.bar1) } \ +# RUN: .bss : { *(.bss) } } " > %t.script # RUN: ld.lld -o %t.out --script %t.script %t -# RUN: llvm-objdump -section-headers %t.out | \ -# RUN: FileCheck -check-prefix=TEXTORPHAN %s +# RUN: llvm-objdump -section-headers %t.out | FileCheck %s -# RUN: echo "SECTIONS { .text : { *(.text) } }" > %t.script -# RUN: ld.lld -o %t.out --script %t.script %t -# RUN: llvm-objdump -section-headers %t.out | \ -# RUN: FileCheck -check-prefix=WRITABLEORPHAN %s - -# TEXTORPHAN: Sections: -# TEXTORPHAN-NEXT: Idx Name -# TEXTORPHAN-NEXT: 0 -# TEXTORPHAN-NEXT: 1 .writable -# TEXTORPHAN-NEXT: 2 .text - -# WRITABLEORPHAN: Sections: -# WRITABLEORPHAN-NEXT: Idx Name -# WRITABLEORPHAN-NEXT: 0 -# WRITABLEORPHAN-NEXT: 1 .text -# WRITABLEORPHAN-NEXT: 2 .writable +# CHECK: Sections: +# CHECK-NEXT: Idx Name Size Address Type +# CHECK-NEXT: 0 00000000 0000000000000000 +# CHECK-NEXT: 1 .text 00000001 0000000000000190 TEXT DATA +# CHECK-NEXT: 2 .foo1 00000004 0000000000000191 DATA +# CHECK-NEXT: 3 .foo2 00000004 0000000000000195 DATA +# CHECK-NEXT: 4 .foo3 00000004 0000000000000199 DATA +# CHECK-NEXT: 5 .bar1 00000004 000000000000019d DATA +# CHECK-NEXT: 6 .bar2 00000004 00000000000001a1 DATA +# CHECK-NEXT: 7 .bss 00000002 00000000000001a5 BSS +# CHECK-NEXT: 8 .symtab 000000a8 0000000000000000 +# CHECK-NEXT: 9 .shstrtab 00000044 0000000000000000 +# CHECK-NEXT: 10 .strtab 00000021 0000000000000000 .global _start _start: - nop + nop + +.section .foo1, "a" +foo1: + .long 1 + +.section .foo2, "a" +foo2: + .long 1 + +.section .foo3, "a" +foo3: + .long 1 + +.section .bar1, "aw" +bar1: + .long 1 + +.section .bar2, "aw" +bar2: + .long 1 -.section .writable,"aw" - .zero 4 +.section .bss,"",@nobits +.short 0 Index: test/ELF/linkerscript/linkerscript-sections-constraint.s =================================================================== --- test/ELF/linkerscript/linkerscript-sections-constraint.s +++ test/ELF/linkerscript/linkerscript-sections-constraint.s @@ -7,10 +7,8 @@ # RUN: llvm-objdump -section-headers %t1 | \ # RUN: FileCheck -check-prefix=BASE %s # BASE: Sections: -# BASE-NEXT: Idx Name Size Address Type -# BASE-NEXT: 0 00000000 0000000000000000 -# BASE-NEXT: 1 .writable 00000004 0000000000000200 DATA -# BASE-NEXT: 2 .readable 00000004 0000000000000204 DATA +# BASE: .writable +# BASE: .readable # RUN: echo "SECTIONS { \ # RUN: .foo : ONLY_IF_RO { *(.foo.*) } \ @@ -22,11 +20,11 @@ # NO1: Sections: # NO1-NEXT: Idx Name Size Address Type # NO1-NEXT: 0 00000000 0000000000000000 -# NO1-NEXT: 1 .writable 00000004 0000000000000200 DATA -# NO1-NEXT: 2 .readable 00000004 0000000000000204 DATA -# NO1-NEXT: 3 .text 00000001 0000000000000208 TEXT DATA -# NO1-NEXT: 4 .foo.2 00000004 0000000000000209 DATA -# NO1-NEXT: 5 .foo.1 00000004 000000000000020d TEXT DATA +# NO1-NEXT: 1 .writable 00000004 00000000000001c8 DATA +# NO1-NEXT: 2 .foo.2 00000004 00000000000001cc DATA +# NO1-NEXT: 3 .readable 00000004 00000000000001d0 DATA +# NO1-NEXT: 4 .text 00000001 00000000000001d4 TEXT DATA +# NO1-NEXT: 5 .foo.1 00000004 00000000000001d5 TEXT DATA .global _start _start: Index: test/ELF/linkerscript/linkerscript-sections.s =================================================================== --- test/ELF/linkerscript/linkerscript-sections.s +++ test/ELF/linkerscript/linkerscript-sections.s @@ -21,8 +21,8 @@ # SEC-DEFAULT: 3 other 00000003 {{[0-9a-f]*}} DATA # SEC-DEFAULT: 4 .bss 00000002 {{[0-9a-f]*}} BSS # SEC-DEFAULT: 5 .shstrtab 00000002 {{[0-9a-f]*}} -# SEC-DEFAULT: 6 .symtab 00000030 {{[0-9a-f]*}} -# SEC-DEFAULT: 7 .shstrtab 00000032 {{[0-9a-f]*}} +# SEC-DEFAULT: 6 .shstrtab 00000032 {{[0-9a-f]*}} +# SEC-DEFAULT: 7 .symtab 00000030 {{[0-9a-f]*}} # SEC-DEFAULT: 8 .strtab 00000008 {{[0-9a-f]*}} # Sections are put in order specified in linker script. @@ -62,8 +62,8 @@ # SEC-SWAP-NAMES: 3 other 00000003 {{[0-9a-f]*}} DATA # SEC-SWAP-NAMES: 4 .bss 00000002 {{[0-9a-f]*}} BSS # SEC-SWAP-NAMES: 5 .shstrtab 00000002 {{[0-9a-f]*}} -# SEC-SWAP-NAMES: 6 .symtab 00000030 {{[0-9a-f]*}} -# SEC-SWAP-NAMES: 7 .shstrtab 00000032 {{[0-9a-f]*}} +# SEC-SWAP-NAMES: 6 .shstrtab 00000032 {{[0-9a-f]*}} +# SEC-SWAP-NAMES: 7 .symtab 00000030 {{[0-9a-f]*}} # SEC-SWAP-NAMES: 8 .strtab 00000008 {{[0-9a-f]*}} # .shstrtab from the input object file is discarded. @@ -99,8 +99,8 @@ # SEC-MULTI: 2 .data 00000023 {{[0-9a-f]*}} DATA # SEC-MULTI: 3 .bss 00000002 {{[0-9a-f]*}} BSS # SEC-MULTI: 4 .shstrtab 00000002 {{[0-9a-f]*}} -# SEC-MULTI: 5 .symtab 00000030 {{[0-9a-f]*}} -# SEC-MULTI: 6 .shstrtab 0000002c {{[0-9a-f]*}} +# SEC-MULTI: 5 .shstrtab 0000002c {{[0-9a-f]*}} +# SEC-MULTI: 6 .symtab 00000030 {{[0-9a-f]*}} # SEC-MULTI: 7 .strtab 00000008 {{[0-9a-f]*}} .globl _start Index: test/ELF/linkerscript/linkerscript-va.s =================================================================== --- test/ELF/linkerscript/linkerscript-va.s +++ test/ELF/linkerscript/linkerscript-va.s @@ -7,9 +7,9 @@ # CHECK: Sections: # CHECK-NEXT: Idx Name Size Address Type # CHECK-NEXT: 0 00000000 0000000000000000 -# CHECK-NEXT: 1 .foo 00000004 0000000000000120 DATA -# CHECK-NEXT: 2 .boo 00000004 0000000000000124 DATA -# CHECK-NEXT: 3 .text 00000001 0000000000000128 TEXT DATA +# CHECK-NEXT: 1 .text 00000001 0000000000000158 TEXT DATA +# CHECK-NEXT: 2 .foo 00000004 0000000000000159 DATA +# CHECK-NEXT: 3 .boo 00000004 000000000000015d DATA .global _start _start: