Index: ELF/LinkerScript.h =================================================================== --- ELF/LinkerScript.h +++ ELF/LinkerScript.h @@ -93,6 +93,9 @@ bool Provide = false; bool Hidden = false; + // Whether the command is within SECTIONS command. + bool InSections = true; + // Holds file name and line number for error reporting. std::string Location; }; @@ -149,6 +152,9 @@ static bool classof(const BaseCommand *C); Expr Expression; + + // Whether the command is within SECTIONS command. + bool InSections = true; }; // Represents BYTE(), SHORT(), LONG(), or QUAD(). @@ -257,6 +263,7 @@ void allocateHeaders(std::vector &Phdrs); void addSymbol(SymbolAssignment *Cmd); void processCommands(OutputSectionFactory &Factory); + void processOutsideSectionsCommands(); // Parsed linker script configurations are set to this struct. ScriptConfiguration Opt; Index: ELF/LinkerScript.cpp =================================================================== --- ELF/LinkerScript.cpp +++ ELF/LinkerScript.cpp @@ -773,6 +773,22 @@ } } +void LinkerScript::processOutsideSectionsCommands() { + for (BaseCommand *Base : Opt.Commands) { + if (auto *Cmd = dyn_cast(Base)) { + if (!Cmd->InSections) + assignSymbol(Cmd, false); + continue; + } + + if (auto *Cmd = dyn_cast(Base)) { + if (!Cmd->InSections) + Cmd->Expression(); + continue; + } + } +} + void LinkerScript::assignAddresses() { // Assign addresses as instructed by linker script SECTIONS sub-commands. Dot = 0; @@ -787,12 +803,14 @@ for (BaseCommand *Base : Opt.Commands) { if (auto *Cmd = dyn_cast(Base)) { - assignSymbol(Cmd, false); + if (Cmd->InSections) + assignSymbol(Cmd, false); continue; } if (auto *Cmd = dyn_cast(Base)) { - Cmd->Expression(); + if (Cmd->InSections) + Cmd->Expression(); continue; } Index: ELF/ScriptParser.cpp =================================================================== --- ELF/ScriptParser.cpp +++ ELF/ScriptParser.cpp @@ -217,7 +217,9 @@ continue; if (Tok == "ASSERT") { - Script->Opt.Commands.push_back(readAssert()); + AssertCommand *Cmd = readAssert(); + Cmd->InSections = false; + Script->Opt.Commands.push_back(Cmd); } else if (Tok == "ENTRY") { readEntry(); } else if (Tok == "EXTERN") { @@ -243,6 +245,7 @@ } else if (Tok == "VERSION") { readVersion(); } else if (SymbolAssignment *Cmd = readProvideOrAssignment(Tok)) { + Cmd->InSections = false; Script->Opt.Commands.push_back(Cmd); } else { setError("unknown directive: " + Tok); Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -224,6 +224,11 @@ fixPredefinedSymbols(); } + // Now that the value of all predefined symbols have been fixed, we can + // process symbol assignments outside SECTIONS commands (because these may + // be referring to the predefined symbols). + Script->processOutsideSectionsCommands(); + // It does not make sense try to open the file if we have error already. if (ErrorCount) return; Index: test/ELF/linkerscript/symbol-reserved.s =================================================================== --- test/ELF/linkerscript/symbol-reserved.s +++ test/ELF/linkerscript/symbol-reserved.s @@ -27,6 +27,12 @@ # RUN: llvm-objdump -t %t1 | FileCheck --check-prefix=ALIGN-SUB %s # ALIGN-SUB: 0000000000000006 *ABS* 00000000 .hidden newsym +# RUN: echo "PROVIDE_HIDDEN(newsym = ALIGN(_end, CONSTANT(MAXPAGESIZE)) + 5);" > %t.script +# RUN: ld.lld -o %t1 %t %t.script +# RUN: llvm-objdump -t %t1 | FileCheck --check-prefix=RELATIVE %s +# RELATIVE: 0000000000202005 .text 00000000 .hidden newsym +# RELATIVE: 0000000000201007 .text 00000000 _end + # RUN: echo "PROVIDE_HIDDEN(newsym = ALIGN(_end, CONSTANT(MAXPAGESIZE)) + 5);" > %t.script # RUN: ld.lld -o %t1 --script %p/Inputs/symbol-reserved.script %t %t.script # RUN: llvm-objdump -t %t1 | FileCheck --check-prefix=RELATIVE-ADD %s