#include "LinkerScript.h"
#include "Config.h"
#include "Driver.h"
+#include "InputSection.h"
#include "SymbolTable.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/StringSaver.h"
using namespace llvm;
+using namespace llvm::object;
using namespace lld;
using namespace lld::elf2;
LinkerScript *elf2::Script;
-StringRef LinkerScript::getOutputSection(StringRef S) {
- return Sections.lookup(S);
+template <class ELFT>
+StringRef LinkerScript::getOutputSection(InputSectionBase<ELFT> *S) {
+ for (SectionRule &R : Sections)
+ if (R.match(S))
+ return R.Dest;
+ return "";
}
-bool LinkerScript::isDiscarded(StringRef S) {
- return Sections.lookup(S) == "/DISCARD/";
+template <class ELFT>
+bool LinkerScript::isDiscarded(InputSectionBase<ELFT> *S) {
+ return getOutputSection(S) == "/DISCARD/";
}
// A compartor to sort output sections. Returns -1 or 1 if both
return I < J ? -1 : 1;
}
+// Returns true if S matches T. S may contain a meta character '*'
+// which matches zero or more occurrences of any character.
+static bool matchStr(StringRef S, StringRef T) {
+ for (;;) {
+ if (S.empty())
+ return T.empty();
+ if (S[0] == '*') {
+ S = S.substr(1);
+ if (S.empty())
+ // Fast path. If a pattern is '*', it matches anything.
+ return true;
+ for (size_t I = 0, E = T.size(); I < E; ++I)
+ if (matchStr(S, T.substr(I)))
+ return true;
+ return false;
+ }
+ if (T.empty() || S[0] != T[0])
+ return false;
+ S = S.substr(1);
+ T = T.substr(1);
+ }
+}
+
+template <class ELFT> bool SectionRule::match(InputSectionBase<ELFT> *S) {
+ return matchStr(SectionPattern, S->getSectionName());
+}
+
class elf2::ScriptParser {
public:
ScriptParser(BumpPtrAllocator *A, StringRef S, bool B)
next(); // Skip input file name.
expect("(");
while (!Error && !skip(")"))
- Script->Sections[next()] = OutSec;
+ Script->Sections.push_back({OutSec, next()});
}
}
StringRef Path = MB.getBufferIdentifier();
ScriptParser(&Alloc, MB.getBuffer(), isUnderSysroot(Path)).run();
}
+
+template StringRef LinkerScript::getOutputSection(InputSectionBase<ELF32LE> *);
+template StringRef LinkerScript::getOutputSection(InputSectionBase<ELF32BE> *);
+template StringRef LinkerScript::getOutputSection(InputSectionBase<ELF64LE> *);
+template StringRef LinkerScript::getOutputSection(InputSectionBase<ELF64BE> *);
+
+template bool LinkerScript::isDiscarded(InputSectionBase<ELF32LE> *);
+template bool LinkerScript::isDiscarded(InputSectionBase<ELF32BE> *);
+template bool LinkerScript::isDiscarded(InputSectionBase<ELF64LE> *);
+template bool LinkerScript::isDiscarded(InputSectionBase<ELF64BE> *);
+
+template bool SectionRule::match(InputSectionBase<ELF32LE> *);
+template bool SectionRule::match(InputSectionBase<ELF32BE> *);
+template bool SectionRule::match(InputSectionBase<ELF64LE> *);
+template bool SectionRule::match(InputSectionBase<ELF64BE> *);
namespace elf2 {
class ScriptParser;
+template <class ELFT> class InputSectionBase;
+// This class represents each rule in SECTIONS command.
+class SectionRule {
+public:
+ SectionRule(StringRef D, StringRef S) : Dest(D), SectionPattern(S) {}
+
+ // Returns true if S should be in Dest section.
+ template <class ELFT> bool match(InputSectionBase<ELFT> *S);
+
+ StringRef Dest;
+
+private:
+ StringRef SectionPattern;
+};
+
+// This is a runner of the linker script.
class LinkerScript {
friend class ScriptParser;
// this object and Config.
void read(MemoryBufferRef MB);
- StringRef getOutputSection(StringRef InputSection);
- bool isDiscarded(StringRef InputSection);
+ template <class ELFT> StringRef getOutputSection(InputSectionBase<ELFT> *S);
+ template <class ELFT> bool isDiscarded(InputSectionBase<ELFT> *S);
int compareSections(StringRef A, StringRef B);
private:
- // A map for SECTIONS command. The key is input section name
- // and the value is the corresponding output section name.
- llvm::DenseMap<StringRef, StringRef> Sections;
+ // SECTIONS commands.
+ std::vector<SectionRule> Sections;
// Output sections are sorted by this order.
std::vector<StringRef> SectionOrder;
void writeHeader();
void writeSections();
bool isDiscarded(InputSectionBase<ELFT> *IS) const;
- StringRef getOutputSectionName(StringRef S) const;
+ StringRef getOutputSectionName(InputSectionBase<ELFT> *S) const;
bool needsInterpSection() const {
return !Symtab.getSharedFiles().empty() && !Config->DynamicLinker.empty();
}
}
template <class ELFT>
-StringRef Writer<ELFT>::getOutputSectionName(StringRef S) const {
- StringRef Out = Script->getOutputSection(S);
- if (!Out.empty())
- return Out;
+StringRef Writer<ELFT>::getOutputSectionName(InputSectionBase<ELFT> *S) const {
+ StringRef Dest = Script->getOutputSection<ELFT>(S);
+ if (!Dest.empty())
+ return Dest;
+ StringRef Name = S->getSectionName();
for (StringRef V : {".text.", ".rodata.", ".data.rel.ro.", ".data.", ".bss.",
".init_array.", ".fini_array.", ".ctors.", ".dtors."})
- if (S.startswith(V))
+ if (Name.startswith(V))
return V.drop_back();
- return S;
+ return Name;
}
template <class ELFT>
template <class ELFT>
bool Writer<ELFT>::isDiscarded(InputSectionBase<ELFT> *S) const {
return !S || !S->isLive() || S == &InputSection<ELFT>::Discarded ||
- Script->isDiscarded(S->getSectionName());
+ Script->isDiscarded(S);
}
// The beginning and the ending of .rel[a].plt section are marked
}
OutputSectionBase<ELFT> *Sec;
bool IsNew;
- std::tie(Sec, IsNew) =
- Factory.create(C, getOutputSectionName(C->getSectionName()));
+ std::tie(Sec, IsNew) = Factory.create(C, getOutputSectionName(C));
if (IsNew) {
OwningSections.emplace_back(Sec);
OutputSections.push_back(Sec);
# RUN: llvm-objdump -section-headers %t3 | \
# RUN: FileCheck -check-prefix=SEC-ORDER %s
+# The same test as above but with wildcard patterns.
+# RUN: echo "SECTIONS { \
+# RUN: .bss : { *(.bss) } \
+# RUN: other : { *(o*er) } \
+# RUN: .shstrtab : { *(.shstrt*) } \
+# RUN: .symtab : { *(.symtab) } \
+# RUN: .strtab : { *(.strtab) } \
+# RUN: .data : { *(*data) } \
+# RUN: .text : { *(.text) } }" > %t.script
+# RUN: cp %t %t.abc
+# RUN: ld.lld -o %t3 --script %t.script %t.abc
+# RUN: llvm-objdump -section-headers %t3 | \
+# RUN: FileCheck -check-prefix=SEC-ORDER %s
+
# Idx Name Size
# SEC-ORDER: 1 .bss 00000002 {{[0-9a-f]*}} BSS
# SEC-ORDER: 2 other 00000003 {{[0-9a-f]*}} DATA