From 0b1b695a9e2e747abc650f33c0553edd1bce4802 Mon Sep 17 00:00:00 2001 From: Rui Ueyama Date: Mon, 21 Nov 2016 02:11:05 +0000 Subject: [PATCH] Add comments. This patch rearranges code a bit to make it easy to explain. llvm-svn: 287515 --- lld/ELF/LinkerScript.cpp | 53 ++++++++++++++++++++++++++++++------------------ lld/ELF/LinkerScript.h | 2 +- lld/ELF/Writer.cpp | 37 +++++++++++++++++++++++++++------ 3 files changed, 65 insertions(+), 27 deletions(-) diff --git a/lld/ELF/LinkerScript.cpp b/lld/ELF/LinkerScript.cpp index 5c56388..ff58e44 100644 --- a/lld/ELF/LinkerScript.cpp +++ b/lld/ELF/LinkerScript.cpp @@ -8,12 +8,6 @@ //===----------------------------------------------------------------------===// // // This file contains the parser/evaluator of the linker script. -// It parses a linker script and write the result to Config or ScriptConfig -// objects. -// -// If SECTIONS command is used, a ScriptConfig contains an AST -// of the command which will later be consumed by createSections() and -// assignAddresses(). // //===----------------------------------------------------------------------===// @@ -308,11 +302,14 @@ void LinkerScript::processCommands(OutputSectionFactory &Factory) { for (unsigned I = 0; I < Opt.Commands.size(); ++I) { auto Iter = Opt.Commands.begin() + I; const std::unique_ptr &Base1 = *Iter; + + // Handle symbol assignments outside of any output section. if (auto *Cmd = dyn_cast(Base1.get())) { if (shouldDefine(Cmd)) addSymbol(Cmd); continue; } + if (auto *Cmd = dyn_cast(Base1.get())) { // If we don't have SECTIONS then output sections have already been // created by Writer. The LinkerScript::assignAddresses @@ -325,11 +322,20 @@ void LinkerScript::processCommands(OutputSectionFactory &Factory) { if (auto *Cmd = dyn_cast(Base1.get())) { std::vector *> V = createInputSectionList(*Cmd); + // The output section name `/DISCARD/' is special. + // Any input section assigned to it is discarded. if (Cmd->Name == "/DISCARD/") { discard(V); continue; } + // This is for ONLY_IF_RO and ONLY_IF_RW. An output section directive + // ".foo : ONLY_IF_R[OW] { ... }" is handled only if all member input + // sections satisfy a given constraint. If not, a directive is handled + // as if it wasn't present from the beginning. + // + // Because we'll iterate over Commands many more times, the easiest + // way to "make it as if it wasn't present" is to just remove it. if (!matchConstraints(V, Cmd->Constraint)) { for (InputSectionBase *S : V) S->Assigned = false; @@ -338,25 +344,32 @@ void LinkerScript::processCommands(OutputSectionFactory &Factory) { continue; } + // A directive may contain symbol definitions like this: + // ".foo : { ...; bar = .; }". Handle them. for (const std::unique_ptr &Base : Cmd->Commands) if (auto *OutCmd = dyn_cast(Base.get())) if (shouldDefine(OutCmd)) addSymbol(OutCmd); - for (InputSectionBase *Sec : V) { - addSection(Factory, Sec, Cmd->Name); - if (uint32_t Subalign = Cmd->SubalignExpr ? Cmd->SubalignExpr(0) : 0) - Sec->Alignment = Subalign; + // Handle subalign (e.g. ".foo : SUBALIGN(32) { ... }"). If subalign + // is given, input sections are aligned to that value, whether the + // given value is larger or smaller than the original section alignment. + if (Cmd->SubalignExpr) { + uint32_t Subalign = Cmd->SubalignExpr(0); + for (InputSectionBase *S : V) + S->Alignment = Subalign; } + + // Add input sections to an output section. + for (InputSectionBase *S : V) + addSection(Factory, S, Cmd->Name); } } } +// Add sections that didn't match any sections command. template -void LinkerScript::createSections(OutputSectionFactory &Factory) { - processCommands(Factory); - - // Add orphan sections. +void LinkerScript::addOrphanSections(OutputSectionFactory &Factory) { for (InputSectionBase *S : Symtab::X->Sections) if (S->Live && !S->OutSec) addSection(Factory, S, getOutputSectionName(S->Name)); @@ -482,6 +495,8 @@ findSections(StringRef Name, const std::vector &Sections) { return Ret; } +// This function assigns offsets to input sections and an output section +// for a single sections command (e.g. ".text { *(.text); }"). template void LinkerScript::assignOffsets(OutputSectionCommand *Cmd) { if (Cmd->LMAExpr) @@ -491,6 +506,7 @@ void LinkerScript::assignOffsets(OutputSectionCommand *Cmd) { if (Sections.empty()) return; switchTo(Sections[0]); + // Find the last section output location. We will output orphan sections // there so that end symbols point to the correct location. auto E = std::find_if(Cmd->Commands.rbegin(), Cmd->Commands.rend(), @@ -517,10 +533,9 @@ template void LinkerScript::removeEmptyCommands() { auto Pos = std::remove_if( Opt.Commands.begin(), Opt.Commands.end(), [&](const std::unique_ptr &Base) { - auto *Cmd = dyn_cast(Base.get()); - if (!Cmd) - return false; - return findSections(Cmd->Name, *OutputSections).empty(); + if (auto *Cmd = dyn_cast(Base.get())) + return findSections(Cmd->Name, *OutputSections).empty(); + return false; }); Opt.Commands.erase(Pos, Opt.Commands.end()); } @@ -672,10 +687,8 @@ void LinkerScript::assignAddresses(std::vector> &Phdrs) { } auto *Cmd = cast(Base.get()); - if (Cmd->AddrExpr) Dot = Cmd->AddrExpr(Dot); - assignOffsets(Cmd); } diff --git a/lld/ELF/LinkerScript.h b/lld/ELF/LinkerScript.h index a4bade0..d6dae4d 100644 --- a/lld/ELF/LinkerScript.h +++ b/lld/ELF/LinkerScript.h @@ -224,7 +224,7 @@ public: ~LinkerScript(); void processCommands(OutputSectionFactory &Factory); - void createSections(OutputSectionFactory &Factory); + void addOrphanSections(OutputSectionFactory &Factory); void removeEmptyCommands(); void adjustSectionsBeforeSorting(); void adjustSectionsAfterSorting(); diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp index 7744a60..213ecf6 100644 --- a/lld/ELF/Writer.cpp +++ b/lld/ELF/Writer.cpp @@ -133,18 +133,34 @@ template void elf::writeResult() { Writer().run(); } // The main function of the writer. template void Writer::run() { + // Create linker-synthesized sections such as .got or .plt. + // Such sections are of type input section. createSyntheticSections(); + // We need to create some reserved symbols such as _end. Create them. if (!Config->Relocatable) addReservedSymbols(); + // Some architectures use small displacements for jump instructions. + // It is linker's responsibility to create thunks containing long + // jump instructions if jump targets are too far. Create thunks. if (Target->NeedsThunks) forEachRelSec(createThunks); + // Create output sections. Script::X->OutputSections = &OutputSections; if (ScriptConfig->HasSections) { - Script::X->createSections(Factory); + // If linker script contains SECTIONS commands, let it create sections. + Script::X->processCommands(Factory); + + // Linker scripts may have left some input sections unassigned. + // Assign such sections using the default rule. + Script::X->addOrphanSections(Factory); } else { + // If linker script does not contain SECTIONS commands, create + // output sections by default rules. We still need to give the + // linker script a chance to run, because it might contain + // non-SECTIONS commands such as ASSERT. createSections(); Script::X->processCommands(Factory); } @@ -152,6 +168,10 @@ template void Writer::run() { if (Config->Discard != DiscardPolicy::All) copyLocalSymbols(); + // Now that we have a complete set of output sections. This function + // completes section contents. For example, we need to add strings + // to the string table, and add entries to .got and .plt. + // finalizeSections does that. finalizeSections(); if (HasError) return; @@ -178,6 +198,7 @@ template void Writer::run() { fixAbsoluteSymbols(); } + // Write the result down to a file. openFile(); if (HasError) return; @@ -187,17 +208,21 @@ template void Writer::run() { } else { writeSectionsBinary(); } + + // Backfill .note.gnu.build-id section content. This is done at last + // because the content is usually a hash value of the entire output file. writeBuildId(); if (HasError) return; + if (auto EC = Buffer->commit()) error(EC, "failed to write to the output file"); - if (Config->ExitEarly) { - // Flush the output streams and exit immediately. A full shutdown is a good - // test that we are keeping track of all allocated memory, but actually - // freeing it is a waste of time in a regular linker run. + + // Flush the output streams and exit immediately. A full shutdown + // is a good test that we are keeping track of all allocated memory, + // but actually freeing it is a waste of time in a regular linker run. + if (Config->ExitEarly) exitLld(0); - } } // Initialize Out members. -- 2.7.4