From 0659800ef07c653d5549ab3bb44c7de816f51051 Mon Sep 17 00:00:00 2001 From: George Rimar Date: Thu, 28 Jul 2016 21:51:30 +0000 Subject: [PATCH] [ELF] - Linkerscript: implemented filename specification. Scripts can contain something like: KEEP (*crtbegin.o(.ctors)) What means that "*crtbegin.o" is a wildcard of file to take the sections from. This is some kind of opposite to EXCLUDE_FILE and used in FreeBSD script: https://svnweb.freebsd.org/base/head/sys/conf/ldscript.amd64?revision=284870&view=markup#l122 Patch implements this. Differential revision: https://reviews.llvm.org/D22852 llvm-svn: 277042 --- lld/ELF/LinkerScript.cpp | 78 ++++++++++++---------- lld/ELF/LinkerScript.h | 3 +- .../Inputs/linkerscript-filename-spec.s | 2 + .../ELF/linkerscript/linkerscript-filename-spec.s | 41 ++++++++++++ 4 files changed, 89 insertions(+), 35 deletions(-) create mode 100644 lld/test/ELF/linkerscript/Inputs/linkerscript-filename-spec.s create mode 100644 lld/test/ELF/linkerscript/linkerscript-filename-spec.s diff --git a/lld/ELF/LinkerScript.cpp b/lld/ELF/LinkerScript.cpp index 339c06d..c1c5fa8 100644 --- a/lld/ELF/LinkerScript.cpp +++ b/lld/ELF/LinkerScript.cpp @@ -92,20 +92,27 @@ LinkerScript::getSectionMap() { return Ret; } +static bool fileMatches(const InputSectionDescription *Desc, + StringRef Filename) { + if (!globMatch(Desc->FilePattern, Filename)) + return false; + return Desc->ExcludedFiles.empty() || !match(Desc->ExcludedFiles, Filename); +} + // Returns input sections filtered by given glob patterns. template std::vector *> LinkerScript::getInputSections(const InputSectionDescription *I) { - ArrayRef Patterns = I->Patterns; - ArrayRef ExcludedFiles = I->ExcludedFiles; + ArrayRef Patterns = I->SectionPatterns; 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())) - if (ExcludedFiles.empty() || - !match(ExcludedFiles, sys::path::filename(F->getName()))) + Symtab::X->getObjectFiles()) { + if (fileMatches(I, sys::path::filename(F->getName()))) + for (InputSectionBase *S : F->getSections()) + if (!isDiscarded(S) && !S->OutSec && + match(Patterns, S->getSectionName())) Ret.push_back(S); + } if ((llvm::find(Patterns, "COMMON") != Patterns.end())) Ret.push_back(CommonInputSection::X); @@ -428,9 +435,7 @@ private: void readAsNeeded(); void readEntry(); void readExtern(); - std::unique_ptr readFilePattern(); void readGroup(); - void readKeep(OutputSectionCommand *Cmd); void readInclude(); void readNothing() {} void readOutput(); @@ -443,6 +448,8 @@ private: SymbolAssignment *readAssignment(StringRef Name); void readOutputSectionDescription(StringRef OutSec); std::vector readOutputSectionPhdrs(); + std::unique_ptr readInputSectionDescription(); + void readInputSectionRules(InputSectionDescription *InCmd, bool Keep); unsigned readPhdrType(); void readProvide(bool Hidden); void readAlign(OutputSectionCommand *Cmd); @@ -672,32 +679,38 @@ static int precedence(StringRef Op) { .Default(-1); } -std::unique_ptr ScriptParser::readFilePattern() { - expect("*"); +void ScriptParser::readInputSectionRules(InputSectionDescription *InCmd, bool Keep) { + InCmd->FilePattern = next(); expect("("); - auto InCmd = llvm::make_unique(); - if (skip("EXCLUDE_FILE")) { expect("("); while (!Error && !skip(")")) InCmd->ExcludedFiles.push_back(next()); - InCmd->Patterns.push_back(next()); + } + + while (!Error && !skip(")")) { + if (Keep) + Opt.KeptSections.push_back(peek()); + InCmd->SectionPatterns.push_back(next()); + } +} + +std::unique_ptr +ScriptParser::readInputSectionDescription() { + auto InCmd = std::make_unique(); + + // Input section wildcard can be surrounded by KEEP. + // https://sourceware.org/binutils/docs/ld/Input-Section-Keep.html#Input-Section-Keep + if (skip("KEEP")) { + expect("("); + readInputSectionRules(InCmd.get(), true); expect(")"); } else { - while (!Error && !skip(")")) - InCmd->Patterns.push_back(next()); + readInputSectionRules(InCmd.get(), false); } - 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(")"); + return InCmd; } void ScriptParser::readAlign(OutputSectionCommand *Cmd) { @@ -734,16 +747,13 @@ void ScriptParser::readOutputSectionDescription(StringRef OutSec) { expect("{"); while (!Error && !skip("}")) { + if ((!peek().empty() && peek()[0] == '*') || peek() == "KEEP") { + Cmd->Commands.push_back(readInputSectionDescription()); + continue; + } + StringRef Tok = next(); - if (Tok == "*") { - auto *InCmd = new InputSectionDescription(); - Cmd->Commands.emplace_back(InCmd); - expect("("); - while (!Error && !skip(")")) - InCmd->Patterns.push_back(next()); - } else if (Tok == "KEEP") { - readKeep(Cmd); - } else if (Tok == "PROVIDE") { + if (Tok == "PROVIDE") { readProvide(false); } else if (Tok == "PROVIDE_HIDDEN") { readProvide(true); diff --git a/lld/ELF/LinkerScript.h b/lld/ELF/LinkerScript.h index 103be68..5134888 100644 --- a/lld/ELF/LinkerScript.h +++ b/lld/ELF/LinkerScript.h @@ -84,8 +84,9 @@ struct OutputSectionCommand : BaseCommand { struct InputSectionDescription : BaseCommand { InputSectionDescription() : BaseCommand(InputSectionKind) {} static bool classof(const BaseCommand *C); + StringRef FilePattern; std::vector ExcludedFiles; - std::vector Patterns; + std::vector SectionPatterns; }; struct PhdrsCommand { diff --git a/lld/test/ELF/linkerscript/Inputs/linkerscript-filename-spec.s b/lld/test/ELF/linkerscript/Inputs/linkerscript-filename-spec.s new file mode 100644 index 0000000..a688b4d --- /dev/null +++ b/lld/test/ELF/linkerscript/Inputs/linkerscript-filename-spec.s @@ -0,0 +1,2 @@ +.section .foo,"a" + .quad 0x11 diff --git a/lld/test/ELF/linkerscript/linkerscript-filename-spec.s b/lld/test/ELF/linkerscript/linkerscript-filename-spec.s new file mode 100644 index 0000000..b2ea484 --- /dev/null +++ b/lld/test/ELF/linkerscript/linkerscript-filename-spec.s @@ -0,0 +1,41 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %tfirst.o +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux \ +# RUN: %p/Inputs/linkerscript-filename-spec.s -o %tsecond.o + +# RUN: echo "SECTIONS { .foo : { \ +# RUN: KEEP(*first.o(.foo)) \ +# RUN: KEEP(*second.o(.foo)) } }" > %t1.script +# RUN: ld.lld -o %t1 --script %t1.script %tfirst.o %tsecond.o +# RUN: llvm-objdump -s %t1 | FileCheck --check-prefix=FIRSTSECOND %s +# FIRSTSECOND: Contents of section .foo: +# FIRSTSECOND-NEXT: 0120 01000000 00000000 11000000 00000000 + +# RUN: echo "SECTIONS { .foo : { \ +# RUN: KEEP(*second.o(.foo)) \ +# RUN: KEEP(*first.o(.foo)) } }" > %t2.script +# RUN: ld.lld -o %t2 --script %t2.script %tfirst.o %tsecond.o +# RUN: llvm-objdump -s %t2 | FileCheck --check-prefix=SECONDFIRST %s +# SECONDFIRST: Contents of section .foo: +# SECONDFIRST-NEXT: 0120 11000000 00000000 01000000 00000000 + +## Now the same tests but without KEEP. Checking that file name inside +## KEEP is parsed fine. +# RUN: echo "SECTIONS { .foo : { \ +# RUN: *first.o(.foo) \ +# RUN: *second.o(.foo) } }" > %t3.script +# RUN: ld.lld -o %t3 --script %t3.script %tfirst.o %tsecond.o +# RUN: llvm-objdump -s %t3 | FileCheck --check-prefix=FIRSTSECOND %s + +# RUN: echo "SECTIONS { .foo : { \ +# RUN: *second.o(.foo) \ +# RUN: *first.o(.foo) } }" > %t4.script +# RUN: ld.lld -o %t4 --script %t4.script %tfirst.o %tsecond.o +# RUN: llvm-objdump -s %t4 | FileCheck --check-prefix=SECONDFIRST %s + +.global _start +_start: + nop + +.section .foo,"a" + .quad 1 -- 2.7.4