From 4906c7f5c4a8750becab20f72776bb373acd5d2c Mon Sep 17 00:00:00 2001 From: George Rimar Date: Fri, 16 Sep 2016 13:07:02 +0000 Subject: [PATCH] [ELF] - Linkerscript: implement EXCLUDE_FILE in the middle of a input section description. This is PR30387: From PR description: We fail to parse SECTIONS { foo : { *(sec0 EXCLUDE_FILE (zed1.o) sec1 EXCLUDE_FILE (zed2.o) sec2 ) } } The semantics according to bfd are: Include sec1 from every file but zed1.o Include sec2 from every file but zed2.o Include sec0 from every file Patch implements the support. Differential revision: https://reviews.llvm.org/D24650 llvm-svn: 281721 --- lld/ELF/LinkerScript.cpp | 78 +++++++++++++++------- lld/ELF/LinkerScript.h | 4 +- .../ELF/linkerscript/Inputs/exclude-multiple1.s | 8 +++ .../ELF/linkerscript/Inputs/exclude-multiple2.s | 8 +++ lld/test/ELF/linkerscript/exclude-multiple.s | 28 ++++++++ 5 files changed, 100 insertions(+), 26 deletions(-) create mode 100644 lld/test/ELF/linkerscript/Inputs/exclude-multiple1.s create mode 100644 lld/test/ELF/linkerscript/Inputs/exclude-multiple2.s create mode 100644 lld/test/ELF/linkerscript/exclude-multiple.s diff --git a/lld/ELF/LinkerScript.cpp b/lld/ELF/LinkerScript.cpp index f58f4d7..71fa4cb 100644 --- a/lld/ELF/LinkerScript.cpp +++ b/lld/ELF/LinkerScript.cpp @@ -104,10 +104,10 @@ bool LinkerScript::shouldKeep(InputSectionBase *S) { return false; } -static bool fileMatches(const InputSectionDescription *Desc, - StringRef Filename) { - return const_cast(Desc->FileRe).match(Filename) && - !const_cast(Desc->ExcludedFileRe).match(Filename); +static bool fileMatches(const llvm::Regex &FileRe, + const llvm::Regex &ExcludedFileRe, StringRef Filename) { + return const_cast(FileRe).match(Filename) && + !const_cast(ExcludedFileRe).match(Filename); } static bool comparePriority(InputSectionData *A, InputSectionData *B) { @@ -155,17 +155,21 @@ static bool matchConstraints(ArrayRef *> Sections, template std::vector *> LinkerScript::getInputSections(const InputSectionDescription *I) { - const Regex &Re = I->SectionRe; std::vector *> Ret; - for (ObjectFile *F : Symtab::X->getObjectFiles()) - if (fileMatches(I, sys::path::filename(F->getName()))) - for (InputSectionBase *S : F->getSections()) - if (!isDiscarded(S) && !S->OutSec && - const_cast(Re).match(S->Name)) - Ret.push_back(S); - - if (const_cast(Re).match("COMMON")) - Ret.push_back(CommonInputSection::X); + for (const std::pair &V : I->SectionsVec) { + for (ObjectFile *F : Symtab::X->getObjectFiles()) { + if (fileMatches(I->FileRe, V.first, sys::path::filename(F->getName()))) { + + Regex &Re = const_cast(V.second); + for (InputSectionBase *S : F->getSections()) + if (!isDiscarded(S) && !S->OutSec && Re.match(S->Name)) + Ret.push_back(S); + + if (Re.match("COMMON")) + Ret.push_back(CommonInputSection::X); + } + } + } return Ret; } @@ -687,6 +691,7 @@ private: std::vector readOutputSectionPhdrs(); InputSectionDescription *readInputSectionDescription(StringRef Tok); Regex readFilePatterns(); + void readSectionExcludes(InputSectionDescription *Cmd); InputSectionDescription *readInputSectionRules(StringRef FilePattern); unsigned readPhdrType(); SortKind readSortKind(); @@ -981,17 +986,41 @@ SortKind ScriptParser::readSortKind() { return SortNone; } +// Method reads a list of sequence of excluded files and section globs given in +// a following form: ((EXCLUDE_FILE(file_pattern+))? section_pattern+)+ +// Example: *(.foo.1 EXCLUDE_FILE (*a.o) .foo.2 EXCLUDE_FILE (*b.o) .foo.3) +void ScriptParser::readSectionExcludes(InputSectionDescription *Cmd) { + llvm::Regex ExcludeFileRe; + std::vector V; + + while (!Error) { + if (skip(")")) { + Cmd->SectionsVec.push_back( + {std::move(ExcludeFileRe), compileGlobPatterns(V)}); + return; + } + + if (skip("EXCLUDE_FILE")) { + if (!V.empty()) { + Cmd->SectionsVec.push_back( + {std::move(ExcludeFileRe), compileGlobPatterns(V)}); + V.clear(); + } + + expect("("); + ExcludeFileRe = readFilePatterns(); + continue; + } + + V.push_back(next()); + } +} + InputSectionDescription * ScriptParser::readInputSectionRules(StringRef FilePattern) { auto *Cmd = new InputSectionDescription(FilePattern); expect("("); - // Read EXCLUDE_FILE(). - if (skip("EXCLUDE_FILE")) { - expect("("); - Cmd->ExcludedFileRe = readFilePatterns(); - } - // Read SORT(). if (SortKind K1 = readSortKind()) { Cmd->SortOuter = K1; @@ -999,16 +1028,16 @@ ScriptParser::readInputSectionRules(StringRef FilePattern) { if (SortKind K2 = readSortKind()) { Cmd->SortInner = K2; expect("("); - Cmd->SectionRe = readFilePatterns(); + Cmd->SectionsVec.push_back({llvm::Regex(), readFilePatterns()}); expect(")"); } else { - Cmd->SectionRe = readFilePatterns(); + Cmd->SectionsVec.push_back({llvm::Regex(), readFilePatterns()}); } expect(")"); return Cmd; } - Cmd->SectionRe = readFilePatterns(); + readSectionExcludes(Cmd); return Cmd; } @@ -1021,7 +1050,8 @@ ScriptParser::readInputSectionDescription(StringRef Tok) { StringRef FilePattern = next(); InputSectionDescription *Cmd = readInputSectionRules(FilePattern); expect(")"); - Opt.KeptSections.push_back(&Cmd->SectionRe); + for (std::pair &Regex : Cmd->SectionsVec) + Opt.KeptSections.push_back(&Regex.second); return Cmd; } return readInputSectionRules(Tok); diff --git a/lld/ELF/LinkerScript.h b/lld/ELF/LinkerScript.h index 0503df6..f906d8c 100644 --- a/lld/ELF/LinkerScript.h +++ b/lld/ELF/LinkerScript.h @@ -105,8 +105,8 @@ struct InputSectionDescription : BaseCommand { llvm::Regex FileRe; SortKind SortOuter = SortNone; SortKind SortInner = SortNone; - llvm::Regex ExcludedFileRe; - llvm::Regex SectionRe; + // Pairs of section regex and files excluded. + std::vector> SectionsVec; }; struct AssertCommand : BaseCommand { diff --git a/lld/test/ELF/linkerscript/Inputs/exclude-multiple1.s b/lld/test/ELF/linkerscript/Inputs/exclude-multiple1.s new file mode 100644 index 0000000..1e0f741 --- /dev/null +++ b/lld/test/ELF/linkerscript/Inputs/exclude-multiple1.s @@ -0,0 +1,8 @@ +.section .foo.1,"a" + .quad 4 + +.section .foo.2,"a" + .quad 5 + +.section .foo.3,"a" + .quad 6 diff --git a/lld/test/ELF/linkerscript/Inputs/exclude-multiple2.s b/lld/test/ELF/linkerscript/Inputs/exclude-multiple2.s new file mode 100644 index 0000000..60f790f --- /dev/null +++ b/lld/test/ELF/linkerscript/Inputs/exclude-multiple2.s @@ -0,0 +1,8 @@ +.section .foo.1,"a" + .quad 7 + +.section .foo.2,"a" + .quad 8 + +.section .foo.3,"a" + .quad 9 diff --git a/lld/test/ELF/linkerscript/exclude-multiple.s b/lld/test/ELF/linkerscript/exclude-multiple.s new file mode 100644 index 0000000..24c7f2f --- /dev/null +++ b/lld/test/ELF/linkerscript/exclude-multiple.s @@ -0,0 +1,28 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %tfile1.o +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/exclude-multiple1.s -o %tfile2.o +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/exclude-multiple2.s -o %tfile3.o +# RUN: echo "SECTIONS { \ +# RUN: .foo : { *(.foo.1 EXCLUDE_FILE (*file1.o) .foo.2 EXCLUDE_FILE (*file2.o) .foo.3) } \ +# RUN: }" > %t1.script +# RUN: ld.lld -script %t1.script %tfile1.o %tfile2.o %tfile3.o -o %t1.o +# RUN: llvm-objdump -s %t1.o | FileCheck %s + +# CHECK: Contents of section .foo: +# CHECK-NEXT: 0120 01000000 00000000 04000000 00000000 +# CHECK-NEXT: 0130 07000000 00000000 05000000 00000000 +# CHECK-NEXT: 0140 08000000 00000000 03000000 00000000 +# CHECK-NEXT: 0150 09000000 00000000 +# CHECK-NEXT: Contents of section .foo.2: +# CHECK-NEXT: 0158 02000000 00000000 +# CHECK-NEXT: Contents of section .foo.3: +# CHECK-NEXT: 0160 06000000 00000000 + +.section .foo.1,"a" + .quad 1 + +.section .foo.2,"a" + .quad 2 + +.section .foo.3,"a" + .quad 3 -- 2.7.4