Index: lld/trunk/ELF/LinkerScript.h =================================================================== --- lld/trunk/ELF/LinkerScript.h +++ lld/trunk/ELF/LinkerScript.h @@ -83,6 +83,7 @@ struct InputSectionDescription : BaseCommand { InputSectionDescription() : BaseCommand(InputSectionKind) {} static bool classof(const BaseCommand *C); + std::vector ExcludedFiles; std::vector Patterns; }; @@ -132,10 +133,11 @@ bool hasPhdrsCommands(); private: - std::vector>> getSectionMap(); + std::vector> + getSectionMap(); std::vector *> - getInputSections(ArrayRef Patterns); + getInputSections(const InputSectionDescription *); // "ScriptConfig" is a bit too long, so define a short name for it. ScriptConfiguration &Opt = *ScriptConfig; Index: lld/trunk/ELF/LinkerScript.cpp =================================================================== --- lld/trunk/ELF/LinkerScript.cpp +++ lld/trunk/ELF/LinkerScript.cpp @@ -79,15 +79,15 @@ // input sections start with ".foo." or ".bar." should be added to // ".text" section. template -std::vector>> +std::vector> LinkerScript::getSectionMap() { - std::vector>> Ret; + std::vector> Ret; for (const std::unique_ptr &Base1 : Opt.Commands) if (auto *Cmd1 = dyn_cast(Base1.get())) for (const std::unique_ptr &Base2 : Cmd1->Commands) if (auto *Cmd2 = dyn_cast(Base2.get())) - Ret.emplace_back(Cmd1->Name, Cmd2->Patterns); + Ret.emplace_back(Cmd1->Name, Cmd2); return Ret; } @@ -95,13 +95,17 @@ // Returns input sections filtered by given glob patterns. template std::vector *> -LinkerScript::getInputSections(ArrayRef Patterns) { +LinkerScript::getInputSections(const InputSectionDescription *I) { + ArrayRef Patterns = I->Patterns; + ArrayRef ExcludedFiles = I->ExcludedFiles; std::vector *> Ret; for (const std::unique_ptr> &F : Symtab::X->getObjectFiles()) for (InputSectionBase *S : F->getSections()) if (!isDiscarded(S) && !S->OutSec && match(Patterns, S->getSectionName())) - Ret.push_back(S); + if (ExcludedFiles.empty() || + !match(ExcludedFiles, sys::path::filename(F->getName()))) + Ret.push_back(S); return Ret; } @@ -123,8 +127,8 @@ for (auto &P : getSectionMap()) { StringRef OutputName = P.first; - ArrayRef InputPatterns = P.second; - for (InputSectionBase *S : getInputSections(InputPatterns)) { + const InputSectionDescription *I = P.second; + for (InputSectionBase *S : getInputSections(I)) { if (OutputName == "/DISCARD/") { S->Live = false; reportDiscarded(S); @@ -420,6 +424,7 @@ void readAsNeeded(); void readEntry(); void readExtern(); + std::unique_ptr readFilePattern(); void readGroup(); void readKeep(OutputSectionCommand *Cmd); void readInclude(); @@ -662,16 +667,31 @@ .Default(-1); } -void ScriptParser::readKeep(OutputSectionCommand *Cmd) { - expect("("); +std::unique_ptr ScriptParser::readFilePattern() { expect("*"); expect("("); - auto *InCmd = new InputSectionDescription(); - Cmd->Commands.emplace_back(InCmd); - while (!Error && !skip(")")) { - Opt.KeptSections.push_back(peek()); + + auto InCmd = llvm::make_unique(); + + if (skip("EXCLUDE_FILE")) { + expect("("); + while (!Error && !skip(")")) + InCmd->ExcludedFiles.push_back(next()); InCmd->Patterns.push_back(next()); + expect(")"); + } else { + while (!Error && !skip(")")) + InCmd->Patterns.push_back(next()); } + return InCmd; +} + +void ScriptParser::readKeep(OutputSectionCommand *Cmd) { + expect("("); + std::unique_ptr InCmd = readFilePattern(); + Opt.KeptSections.insert(Opt.KeptSections.end(), InCmd->Patterns.begin(), + InCmd->Patterns.end()); + Cmd->Commands.push_back(std::move(InCmd)); expect(")"); } Index: lld/trunk/test/ELF/linkerscript/Inputs/include.s =================================================================== --- lld/trunk/test/ELF/linkerscript/Inputs/include.s +++ lld/trunk/test/ELF/linkerscript/Inputs/include.s @@ -0,0 +1,5 @@ +.section .text +.globl _potato +_potato: + nop + nop Index: lld/trunk/test/ELF/linkerscript/Inputs/notinclude.s =================================================================== --- lld/trunk/test/ELF/linkerscript/Inputs/notinclude.s +++ lld/trunk/test/ELF/linkerscript/Inputs/notinclude.s @@ -0,0 +1,4 @@ +.section .text +.globl tomato +tomato: + movl $1, %eax Index: lld/trunk/test/ELF/linkerscript/linkerscript-excludefile.s =================================================================== --- lld/trunk/test/ELF/linkerscript/linkerscript-excludefile.s +++ lld/trunk/test/ELF/linkerscript/linkerscript-excludefile.s @@ -0,0 +1,48 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux \ +# RUN: %p/Inputs/include.s -o %t2 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux \ +# RUN: %p/Inputs/notinclude.s -o %t3.notinclude + +# RUN: echo "SECTIONS {} " > %t.script +# RUN: ld.lld -o %t --script %t.script %t1 %t2 %t3.notinclude +# RUN: llvm-objdump -d %t | \ +# RUN: FileCheck %s + +# CHECK: Disassembly of section .text: +# CHECK: _start: +# CHECK: 120: 48 c7 c0 3c 00 00 00 movq $60, %rax +# CHECK: 127: 48 c7 c7 2a 00 00 00 movq $42, %rdi +# CHECK: 12e: 00 00 addb %al, (%rax) +# CHECK: _potato: +# CHECK: 130: 90 nop +# CHECK: 131: 90 nop +# CHECK: 132: 00 00 addb %al, (%rax) +# CHECK: tomato: +# CHECK: 134: b8 01 00 00 00 movl $1, %eax + +# RUN: echo "SECTIONS { .patatino : \ +# RUN: { KEEP(*(EXCLUDE_FILE(*notinclude) .text)) } }" \ +# RUN: > %t.script +# RUN: ld.lld -o %t2 --script %t.script %t1 %t2 %t3.notinclude +# RUN: llvm-objdump -d %t2 | \ +# RUN: FileCheck %s --check-prefix=EXCLUDE + +# EXCLUDE: Disassembly of section .patatino: +# EXCLUDE: _start: +# EXCLUDE: 120: 48 c7 c0 3c 00 00 00 movq $60, %rax +# EXCLUDE: 127: 48 c7 c7 2a 00 00 00 movq $42, %rdi +# EXCLUDE: 12e: 00 00 addb %al, (%rax) +# EXCLUDE: _potato: +# EXCLUDE: 130: 90 nop +# EXCLUDE: 131: 90 nop +# EXCLUDE: Disassembly of section .text: +# EXCLUDE: tomato: +# EXCLUDE: 134: b8 01 00 00 00 movl $1, %eax + +.section .text +.globl _start +_start: + mov $60, %rax + mov $42, %rdi