<div dir="ltr">Nice!<div><br></div><div>-- Sean Silva</div></div><div class="gmail_extra"><br><div class="gmail_quote">On Fri, Feb 12, 2016 at 1:47 PM, Rui Ueyama via llvm-commits <span dir="ltr"><<a href="mailto:llvm-commits@lists.llvm.org" target="_blank">llvm-commits@lists.llvm.org</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Author: ruiu<br>
Date: Fri Feb 12 15:47:28 2016<br>
New Revision: 260745<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=260745&view=rev" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project?rev=260745&view=rev</a><br>
Log:<br>
ELF: Add wildcard pattern matching to SECTIONS linker script command.<br>
<br>
Each rule in SECTIONS commands is something like ".foo *(.baz.*)",<br>
which instructs the linker to collect all sections whose name matches<br>
".baz.*" from all files and put them into .foo section.<br>
<br>
Previously, we didn't recognize the wildcard character. This patch<br>
adds that feature.<br>
<br>
Performance impact is a bit concerning because a linker script can<br>
contain hundreds of SECTIONS rules, and doing pattern matching against<br>
each rule would be too expensive. We could merge all patterns into<br>
single DFA so that it takes O(n) to the input size. However, it is<br>
probably too much at this moment -- we don't know whether the<br>
performance of pattern matching matters or not. So I chose to<br>
implement the simplest algorithm in this patch. I hope this simple<br>
pattern matcher is sufficient.<br>
<br>
Modified:<br>
lld/trunk/ELF/LinkerScript.cpp<br>
lld/trunk/ELF/LinkerScript.h<br>
lld/trunk/ELF/Writer.cpp<br>
lld/trunk/test/ELF/linkerscript-sections.s<br>
<br>
Modified: lld/trunk/ELF/LinkerScript.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/LinkerScript.cpp?rev=260745&r1=260744&r2=260745&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/LinkerScript.cpp?rev=260745&r1=260744&r2=260745&view=diff</a><br>
==============================================================================<br>
--- lld/trunk/ELF/LinkerScript.cpp (original)<br>
+++ lld/trunk/ELF/LinkerScript.cpp Fri Feb 12 15:47:28 2016<br>
@@ -16,6 +16,7 @@<br>
#include "LinkerScript.h"<br>
#include "Config.h"<br>
#include "Driver.h"<br>
+#include "InputSection.h"<br>
#include "SymbolTable.h"<br>
#include "llvm/Support/FileSystem.h"<br>
#include "llvm/Support/MemoryBuffer.h"<br>
@@ -23,17 +24,23 @@<br>
#include "llvm/Support/StringSaver.h"<br>
<br>
using namespace llvm;<br>
+using namespace llvm::object;<br>
using namespace lld;<br>
using namespace lld::elf2;<br>
<br>
LinkerScript *elf2::Script;<br>
<br>
-StringRef LinkerScript::getOutputSection(StringRef S) {<br>
- return Sections.lookup(S);<br>
+template <class ELFT><br>
+StringRef LinkerScript::getOutputSection(InputSectionBase<ELFT> *S) {<br>
+ for (SectionRule &R : Sections)<br>
+ if (R.match(S))<br>
+ return R.Dest;<br>
+ return "";<br>
}<br>
<br>
-bool LinkerScript::isDiscarded(StringRef S) {<br>
- return Sections.lookup(S) == "/DISCARD/";<br>
+template <class ELFT><br>
+bool LinkerScript::isDiscarded(InputSectionBase<ELFT> *S) {<br>
+ return getOutputSection(S) == "/DISCARD/";<br>
}<br>
<br>
// A compartor to sort output sections. Returns -1 or 1 if both<br>
@@ -48,6 +55,33 @@ int LinkerScript::compareSections(String<br>
return I < J ? -1 : 1;<br>
}<br>
<br>
+// Returns true if S matches T. S may contain a meta character '*'<br>
+// which matches zero or more occurrences of any character.<br>
+static bool matchStr(StringRef S, StringRef T) {<br>
+ for (;;) {<br>
+ if (S.empty())<br>
+ return T.empty();<br>
+ if (S[0] == '*') {<br>
+ S = S.substr(1);<br>
+ if (S.empty())<br>
+ // Fast path. If a pattern is '*', it matches anything.<br>
+ return true;<br>
+ for (size_t I = 0, E = T.size(); I < E; ++I)<br>
+ if (matchStr(S, T.substr(I)))<br>
+ return true;<br>
+ return false;<br>
+ }<br>
+ if (T.empty() || S[0] != T[0])<br>
+ return false;<br>
+ S = S.substr(1);<br>
+ T = T.substr(1);<br>
+ }<br>
+}<br>
+<br>
+template <class ELFT> bool SectionRule::match(InputSectionBase<ELFT> *S) {<br>
+ return matchStr(SectionPattern, S->getSectionName());<br>
+}<br>
+<br>
class elf2::ScriptParser {<br>
public:<br>
ScriptParser(BumpPtrAllocator *A, StringRef S, bool B)<br>
@@ -352,7 +386,7 @@ void ScriptParser::readOutputSectionDesc<br>
next(); // Skip input file name.<br>
expect("(");<br>
while (!Error && !skip(")"))<br>
- Script->Sections[next()] = OutSec;<br>
+ Script->Sections.push_back({OutSec, next()});<br>
}<br>
}<br>
<br>
@@ -370,3 +404,18 @@ void LinkerScript::read(MemoryBufferRef<br>
StringRef Path = MB.getBufferIdentifier();<br>
ScriptParser(&Alloc, MB.getBuffer(), isUnderSysroot(Path)).run();<br>
}<br>
+<br>
+template StringRef LinkerScript::getOutputSection(InputSectionBase<ELF32LE> *);<br>
+template StringRef LinkerScript::getOutputSection(InputSectionBase<ELF32BE> *);<br>
+template StringRef LinkerScript::getOutputSection(InputSectionBase<ELF64LE> *);<br>
+template StringRef LinkerScript::getOutputSection(InputSectionBase<ELF64BE> *);<br>
+<br>
+template bool LinkerScript::isDiscarded(InputSectionBase<ELF32LE> *);<br>
+template bool LinkerScript::isDiscarded(InputSectionBase<ELF32BE> *);<br>
+template bool LinkerScript::isDiscarded(InputSectionBase<ELF64LE> *);<br>
+template bool LinkerScript::isDiscarded(InputSectionBase<ELF64BE> *);<br>
+<br>
+template bool SectionRule::match(InputSectionBase<ELF32LE> *);<br>
+template bool SectionRule::match(InputSectionBase<ELF32BE> *);<br>
+template bool SectionRule::match(InputSectionBase<ELF64LE> *);<br>
+template bool SectionRule::match(InputSectionBase<ELF64BE> *);<br>
<br>
Modified: lld/trunk/ELF/LinkerScript.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/LinkerScript.h?rev=260745&r1=260744&r2=260745&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/LinkerScript.h?rev=260745&r1=260744&r2=260745&view=diff</a><br>
==============================================================================<br>
--- lld/trunk/ELF/LinkerScript.h (original)<br>
+++ lld/trunk/ELF/LinkerScript.h Fri Feb 12 15:47:28 2016<br>
@@ -20,7 +20,23 @@ namespace lld {<br>
namespace elf2 {<br>
<br>
class ScriptParser;<br>
+template <class ELFT> class InputSectionBase;<br>
<br>
+// This class represents each rule in SECTIONS command.<br>
+class SectionRule {<br>
+public:<br>
+ SectionRule(StringRef D, StringRef S) : Dest(D), SectionPattern(S) {}<br>
+<br>
+ // Returns true if S should be in Dest section.<br>
+ template <class ELFT> bool match(InputSectionBase<ELFT> *S);<br>
+<br>
+ StringRef Dest;<br>
+<br>
+private:<br>
+ StringRef SectionPattern;<br>
+};<br>
+<br>
+// This is a runner of the linker script.<br>
class LinkerScript {<br>
friend class ScriptParser;<br>
<br>
@@ -29,14 +45,13 @@ public:<br>
// this object and Config.<br>
void read(MemoryBufferRef MB);<br>
<br>
- StringRef getOutputSection(StringRef InputSection);<br>
- bool isDiscarded(StringRef InputSection);<br>
+ template <class ELFT> StringRef getOutputSection(InputSectionBase<ELFT> *S);<br>
+ template <class ELFT> bool isDiscarded(InputSectionBase<ELFT> *S);<br>
int compareSections(StringRef A, StringRef B);<br>
<br>
private:<br>
- // A map for SECTIONS command. The key is input section name<br>
- // and the value is the corresponding output section name.<br>
- llvm::DenseMap<StringRef, StringRef> Sections;<br>
+ // SECTIONS commands.<br>
+ std::vector<SectionRule> Sections;<br>
<br>
// Output sections are sorted by this order.<br>
std::vector<StringRef> SectionOrder;<br>
<br>
Modified: lld/trunk/ELF/Writer.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Writer.cpp?rev=260745&r1=260744&r2=260745&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Writer.cpp?rev=260745&r1=260744&r2=260745&view=diff</a><br>
==============================================================================<br>
--- lld/trunk/ELF/Writer.cpp (original)<br>
+++ lld/trunk/ELF/Writer.cpp Fri Feb 12 15:47:28 2016<br>
@@ -74,7 +74,7 @@ private:<br>
void writeHeader();<br>
void writeSections();<br>
bool isDiscarded(InputSectionBase<ELFT> *IS) const;<br>
- StringRef getOutputSectionName(StringRef S) const;<br>
+ StringRef getOutputSectionName(InputSectionBase<ELFT> *S) const;<br>
bool needsInterpSection() const {<br>
return !Symtab.getSharedFiles().empty() && !Config->DynamicLinker.empty();<br>
}<br>
@@ -726,16 +726,17 @@ void Writer<ELFT>::addCopyRelSymbols(std<br>
}<br>
<br>
template <class ELFT><br>
-StringRef Writer<ELFT>::getOutputSectionName(StringRef S) const {<br>
- StringRef Out = Script->getOutputSection(S);<br>
- if (!Out.empty())<br>
- return Out;<br>
+StringRef Writer<ELFT>::getOutputSectionName(InputSectionBase<ELFT> *S) const {<br>
+ StringRef Dest = Script->getOutputSection<ELFT>(S);<br>
+ if (!Dest.empty())<br>
+ return Dest;<br>
<br>
+ StringRef Name = S->getSectionName();<br>
for (StringRef V : {".text.", ".rodata.", ".<a href="http://data.rel.ro" rel="noreferrer" target="_blank">data.rel.ro</a>.", ".data.", ".bss.",<br>
".init_array.", ".fini_array.", ".ctors.", ".dtors."})<br>
- if (S.startswith(V))<br>
+ if (Name.startswith(V))<br>
return V.drop_back();<br>
- return S;<br>
+ return Name;<br>
}<br>
<br>
template <class ELFT><br>
@@ -750,7 +751,7 @@ void reportDiscarded(InputSectionBase<EL<br>
template <class ELFT><br>
bool Writer<ELFT>::isDiscarded(InputSectionBase<ELFT> *S) const {<br>
return !S || !S->isLive() || S == &InputSection<ELFT>::Discarded ||<br>
- Script->isDiscarded(S->getSectionName());<br>
+ Script->isDiscarded(S);<br>
}<br>
<br>
// The beginning and the ending of .rel[a].plt section are marked<br>
@@ -934,8 +935,7 @@ template <class ELFT> bool Writer<ELFT>:<br>
}<br>
OutputSectionBase<ELFT> *Sec;<br>
bool IsNew;<br>
- std::tie(Sec, IsNew) =<br>
- Factory.create(C, getOutputSectionName(C->getSectionName()));<br>
+ std::tie(Sec, IsNew) = Factory.create(C, getOutputSectionName(C));<br>
if (IsNew) {<br>
OwningSections.emplace_back(Sec);<br>
OutputSections.push_back(Sec);<br>
<br>
Modified: lld/trunk/test/ELF/linkerscript-sections.s<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/linkerscript-sections.s?rev=260745&r1=260744&r2=260745&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/linkerscript-sections.s?rev=260745&r1=260744&r2=260745&view=diff</a><br>
==============================================================================<br>
--- lld/trunk/test/ELF/linkerscript-sections.s (original)<br>
+++ lld/trunk/test/ELF/linkerscript-sections.s Fri Feb 12 15:47:28 2016<br>
@@ -38,6 +38,20 @@<br>
# RUN: llvm-objdump -section-headers %t3 | \<br>
# RUN: FileCheck -check-prefix=SEC-ORDER %s<br>
<br>
+# The same test as above but with wildcard patterns.<br>
+# RUN: echo "SECTIONS { \<br>
+# RUN: .bss : { *(.bss) } \<br>
+# RUN: other : { *(o*er) } \<br>
+# RUN: .shstrtab : { *(.shstrt*) } \<br>
+# RUN: .symtab : { *(.symtab) } \<br>
+# RUN: .strtab : { *(.strtab) } \<br>
+# RUN: .data : { *(*data) } \<br>
+# RUN: .text : { *(.text) } }" > %t.script<br>
+# RUN: cp %t %t.abc<br>
+# RUN: ld.lld -o %t3 --script %t.script %t.abc<br>
+# RUN: llvm-objdump -section-headers %t3 | \<br>
+# RUN: FileCheck -check-prefix=SEC-ORDER %s<br>
+<br>
# Idx Name Size<br>
# SEC-ORDER: 1 .bss 00000002 {{[0-9a-f]*}} BSS<br>
# SEC-ORDER: 2 other 00000003 {{[0-9a-f]*}} DATA<br>
<br>
<br>
_______________________________________________<br>
llvm-commits mailing list<br>
<a href="mailto:llvm-commits@lists.llvm.org">llvm-commits@lists.llvm.org</a><br>
<a href="http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits" rel="noreferrer" target="_blank">http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits</a><br>
</blockquote></div><br></div>