diff --git a/lld/ELF/LinkerScript.cpp b/lld/ELF/LinkerScript.cpp index eecbe9cef18c..ec3f282e565d 100644 --- a/lld/ELF/LinkerScript.cpp +++ b/lld/ELF/LinkerScript.cpp @@ -84,29 +84,28 @@ template static SymbolBody *addRegular(SymbolAssignment *Cmd) { return Sym->body(); } -OutputSection *LinkerScript::getOutputSection(const Twine &Loc, - StringRef Name) { - for (OutputSection *Sec : *OutputSections) - if (Sec->Name == Name) - return Sec; - - static OutputSection Dummy("", 0, 0); - if (ErrorOnMissingSection) - error(Loc + ": undefined section " + Name); - return &Dummy; +OutputSectionCommand * +LinkerScript::createOutputSectionCommand(StringRef Name, StringRef Location) { + OutputSectionCommand *&CmdRef = NameToOutputSectionCommand[Name]; + OutputSectionCommand *Cmd; + if (CmdRef && CmdRef->Location.empty()) { + // There was a forward reference. + Cmd = CmdRef; + } else { + Cmd = make(Name); + if (!CmdRef) + CmdRef = Cmd; + } + Cmd->Location = Location; + return Cmd; } -// This function is essentially the same as getOutputSection(Name)->Size, -// but it won't print out an error message if a given section is not found. -// -// Linker script does not create an output section if its content is empty. -// We want to allow SIZEOF(.foo) where .foo is a section which happened to -// be empty. That is why this function is different from getOutputSection(). -uint64_t LinkerScript::getOutputSectionSize(StringRef Name) { - for (OutputSection *Sec : *OutputSections) - if (Sec->Name == Name) - return Sec->Size; - return 0; +OutputSectionCommand * +LinkerScript::getOrCreateOutputSectionCommand(StringRef Name) { + OutputSectionCommand *&CmdRef = NameToOutputSectionCommand[Name]; + if (!CmdRef) + CmdRef = make(Name); + return CmdRef; } void LinkerScript::setDot(Expr E, const Twine &Loc, bool InSec) { @@ -456,7 +455,7 @@ void LinkerScript::fabricateDefaultCommands() { // For each OutputSection that needs a VA fabricate an OutputSectionCommand // with an InputSectionDescription describing the InputSections for (OutputSection *Sec : *OutputSections) { - auto *OSCmd = make(Sec->Name); + auto *OSCmd = createOutputSectionCommand(Sec->Name, ""); OSCmd->Sec = Sec; SecToCommand[Sec] = OSCmd; @@ -843,7 +842,7 @@ void LinkerScript::placeOrphanSections() { // representations agree on which input sections to use. OutputSectionCommand *Cmd = getCmd(Sec); if (!Cmd) { - Cmd = make(Name); + Cmd = createOutputSectionCommand(Name, ""); Opt.Commands.insert(CmdIter, Cmd); ++CmdIndex; diff --git a/lld/ELF/LinkerScript.h b/lld/ELF/LinkerScript.h index 08f60f4517a7..819d7c5e1d91 100644 --- a/lld/ELF/LinkerScript.h +++ b/lld/ELF/LinkerScript.h @@ -221,6 +221,8 @@ struct ScriptConfiguration { class LinkerScript final { llvm::DenseMap SecToCommand; + llvm::DenseMap NameToOutputSectionCommand; + void assignSymbol(SymbolAssignment *Cmd, bool InSec); void setDot(Expr E, const Twine &Loc, bool InSec); @@ -241,7 +243,6 @@ class LinkerScript final { void process(BaseCommand &Base); OutputSection *Aether; - bool ErrorOnMissingSection = false; uint64_t Dot; uint64_t ThreadBssOffset = 0; @@ -251,11 +252,14 @@ class LinkerScript final { MemoryRegion *CurMemRegion = nullptr; public: + bool ErrorOnMissingSection = false; + OutputSectionCommand *createOutputSectionCommand(StringRef Name, + StringRef Location); + OutputSectionCommand *getOrCreateOutputSectionCommand(StringRef Name); + OutputSectionCommand *getCmd(OutputSection *Sec) const; bool hasPhdrsCommands() { return !Opt.PhdrsCommands.empty(); } uint64_t getDot() { return Dot; } - OutputSection *getOutputSection(const Twine &Loc, StringRef S); - uint64_t getOutputSectionSize(StringRef S); void discard(ArrayRef V); ExprValue getSymbolValue(const Twine &Loc, StringRef S); diff --git a/lld/ELF/ScriptParser.cpp b/lld/ELF/ScriptParser.cpp index 4b77e35b9bae..02212fa8ba14 100644 --- a/lld/ELF/ScriptParser.cpp +++ b/lld/ELF/ScriptParser.cpp @@ -55,6 +55,7 @@ public: private: void addFile(StringRef Path); + OutputSection *checkSection(OutputSectionCommand *Cmd, StringRef Loccation); void readAsNeeded(); void readEntry(); @@ -564,8 +565,8 @@ uint32_t ScriptParser::readFill() { OutputSectionCommand * ScriptParser::readOutputSectionDescription(StringRef OutSec) { - OutputSectionCommand *Cmd = make(OutSec); - Cmd->Location = getCurrentLocation(); + OutputSectionCommand *Cmd = + Script->createOutputSectionCommand(OutSec, getCurrentLocation()); // Read an address expression. // https://sourceware.org/binutils/docs/ld/Output-Section-Address.html @@ -819,6 +820,16 @@ StringRef ScriptParser::readParenLiteral() { return Tok; } +OutputSection *ScriptParser::checkSection(OutputSectionCommand *Cmd, + StringRef Location) { + if (Cmd->Location.empty() && Script->ErrorOnMissingSection) + error(Location + ": undefined section " + Cmd->Name); + if (Cmd->Sec) + return Cmd->Sec; + static OutputSection Dummy("", 0, 0); + return &Dummy; +} + Expr ScriptParser::readPrimary() { if (peek() == "(") return readParenExpr(); @@ -847,9 +858,8 @@ Expr ScriptParser::readPrimary() { } if (Tok == "ADDR") { StringRef Name = readParenLiteral(); - return [=]() -> ExprValue { - return {Script->getOutputSection(Location, Name), 0}; - }; + OutputSectionCommand *Cmd = Script->getOrCreateOutputSectionCommand(Name); + return [=]() -> ExprValue { return {checkSection(Cmd, Location), 0}; }; } if (Tok == "ALIGN") { expect("("); @@ -867,7 +877,8 @@ Expr ScriptParser::readPrimary() { } if (Tok == "ALIGNOF") { StringRef Name = readParenLiteral(); - return [=] { return Script->getOutputSection(Location, Name)->Alignment; }; + OutputSectionCommand *Cmd = Script->getOrCreateOutputSectionCommand(Name); + return [=] { return checkSection(Cmd, Location)->Alignment; }; } if (Tok == "ASSERT") return readAssertExpr(); @@ -912,7 +923,8 @@ Expr ScriptParser::readPrimary() { } if (Tok == "LOADADDR") { StringRef Name = readParenLiteral(); - return [=] { return Script->getOutputSection(Location, Name)->getLMA(); }; + OutputSectionCommand *Cmd = Script->getOrCreateOutputSectionCommand(Name); + return [=] { return checkSection(Cmd, Location)->getLMA(); }; } if (Tok == "ORIGIN") { StringRef Name = readParenLiteral(); @@ -930,7 +942,11 @@ Expr ScriptParser::readPrimary() { } if (Tok == "SIZEOF") { StringRef Name = readParenLiteral(); - return [=] { return Script->getOutputSectionSize(Name); }; + OutputSectionCommand *Cmd = Script->getOrCreateOutputSectionCommand(Name); + // Linker script does not create an output section if its content is empty. + // We want to allow SIZEOF(.foo) where .foo is a section which happened to + // be empty. + return [=] { return Cmd->Sec ? Cmd->Sec->Size : 0; }; } if (Tok == "SIZEOF_HEADERS") return [=] { return elf::getHeaderSize(); };