Skip to content

Commit

Permalink
Split LinkerScript::createSections into small functions.
Browse files Browse the repository at this point in the history
createSections function is getting longer, so it is time to split it
into small functions. The reason why the function is long is because
it has deeply nested for-loops. This patch constructs temporary data
to reduce nesting level.

Differential Revision: https://reviews.llvm.org/D22786

llvm-svn: 276706
  • Loading branch information
rui314 committed Jul 25, 2016
1 parent 63dc650 commit 6b27481
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 37 deletions.
85 changes: 48 additions & 37 deletions lld/ELF/LinkerScript.cpp
Expand Up @@ -74,65 +74,76 @@ static bool match(ArrayRef<StringRef> Patterns, StringRef S) {
return false;
}

// Create a vector of (<output section name>, <input section name patterns>).
// For example, if a returned vector contains (".text" (".foo.*" ".bar.*")),
// input sections start with ".foo." or ".bar." should be added to
// ".text" section.
template <class ELFT>
std::vector<std::pair<StringRef, ArrayRef<StringRef>>>
LinkerScript<ELFT>::getSectionMap() {
std::vector<std::pair<StringRef, ArrayRef<StringRef>>> Ret;

for (const std::unique_ptr<BaseCommand> &Base1 : Opt.Commands)
if (auto *Cmd1 = dyn_cast<OutputSectionCommand>(Base1.get()))
for (const std::unique_ptr<BaseCommand> &Base2 : Cmd1->Commands)
if (auto *Cmd2 = dyn_cast<InputSectionDescription>(Base2.get()))
Ret.emplace_back(Cmd1->Name, Cmd2->Patterns);

return Ret;
}

// Returns input sections filtered by given glob patterns.
template <class ELFT>
std::vector<InputSectionBase<ELFT> *>
LinkerScript<ELFT>::getInputSections(ArrayRef<StringRef> Patterns) {
std::vector<InputSectionBase<ELFT> *> Ret;
for (const std::unique_ptr<ObjectFile<ELFT>> &F :
Symtab<ELFT>::X->getObjectFiles())
for (InputSectionBase<ELFT> *S : F->getSections())
if (!isDiscarded(S) && !S->OutSec && match(Patterns, S->getSectionName()))
Ret.push_back(S);
return Ret;
}

template <class ELFT>
std::vector<OutputSectionBase<ELFT> *>
LinkerScript<ELFT>::createSections(OutputSectionFactory<ELFT> &Factory) {
typedef const std::unique_ptr<ObjectFile<ELFT>> ObjectFile;
std::vector<OutputSectionBase<ELFT> *> Result;
std::vector<OutputSectionBase<ELFT> *> Ret;

// Add input section to output section. If there is no output section yet,
// then create it and add to output section list.
auto AddInputSec = [&](InputSectionBase<ELFT> *C, StringRef Name) {
auto Add = [&](InputSectionBase<ELFT> *C, StringRef Name) {
OutputSectionBase<ELFT> *Sec;
bool IsNew;
std::tie(Sec, IsNew) = Factory.create(C, Name);
if (IsNew)
Result.push_back(Sec);
Ret.push_back(Sec);
Sec->addSection(C);
};

// Select input sections matching rule and add them to corresponding
// output section. Section rules are processed in order they're listed
// in script, so correct input section order is maintained by design.
for (const std::unique_ptr<BaseCommand> &Base : Opt.Commands) {
auto *OutCmd = dyn_cast<OutputSectionCommand>(Base.get());
if (!OutCmd)
continue;

for (const std::unique_ptr<BaseCommand> &Cmd : OutCmd->Commands) {
auto *InCmd = dyn_cast<InputSectionDescription>(Cmd.get());
if (!InCmd)
for (auto &P : getSectionMap()) {
StringRef OutputName = P.first;
ArrayRef<StringRef> InputPatterns = P.second;
for (InputSectionBase<ELFT> *S : getInputSections(InputPatterns)) {
if (OutputName == "/DISCARD/") {
S->Live = false;
reportDiscarded(S);
continue;

for (ObjectFile &F : Symtab<ELFT>::X->getObjectFiles()) {
for (InputSectionBase<ELFT> *S : F->getSections()) {
if (isDiscarded(S) || S->OutSec)
continue;

if (match(InCmd->Patterns, S->getSectionName())) {
if (OutCmd->Name == "/DISCARD/")
S->Live = false;
else
AddInputSec(S, OutCmd->Name);
}
}
}
Add(S, OutputName);
}
}

// Add all other input sections, which are not listed in script.
for (ObjectFile &F : Symtab<ELFT>::X->getObjectFiles())
for (InputSectionBase<ELFT> *S : F->getSections()) {
if (!isDiscarded(S)) {
if (!S->OutSec)
AddInputSec(S, getOutputSectionName(S));
} else
reportDiscarded(S);
}
for (const std::unique_ptr<ObjectFile<ELFT>> &F :
Symtab<ELFT>::X->getObjectFiles())
for (InputSectionBase<ELFT> *S : F->getSections())
if (!isDiscarded(S) && !S->OutSec)
Add(S, getOutputSectionName(S));

// Remove from the output all the sections which did not meet
// the optional constraints.
return filter(Result);
return filter(Ret);
}

// Process ONLY_IF_RO and ONLY_IF_RW.
Expand Down
5 changes: 5 additions & 0 deletions lld/ELF/LinkerScript.h
Expand Up @@ -131,6 +131,11 @@ template <class ELFT> class LinkerScript {
bool hasPhdrsCommands();

private:
std::vector<std::pair<StringRef, ArrayRef<StringRef>>> getSectionMap();

std::vector<InputSectionBase<ELFT> *>
getInputSections(ArrayRef<StringRef> Patterns);

// "ScriptConfig" is a bit too long, so define a short name for it.
ScriptConfiguration &Opt = *ScriptConfig;

Expand Down

0 comments on commit 6b27481

Please sign in to comment.