Index: ELF/LinkerScript.h =================================================================== --- ELF/LinkerScript.h +++ ELF/LinkerScript.h @@ -49,6 +49,10 @@ // to get the output section pointer. std::function Section; + // Initially contains symbols this expression uses. During + // processing commands, resolved dependencies are removed. + std::vector DependsOn; + uint64_t operator()(uint64_t Dot) const { return Val(Dot); } operator bool() const { return (bool)Val; } @@ -277,6 +281,7 @@ int getSectionIndex(StringRef Name); private: + bool canCalculate(SymbolAssignment *Cmd); void assignSymbol(SymbolAssignment *Cmd, bool InSec = false); void addSymbol(SymbolAssignment *Cmd); void computeInputSections(InputSectionDescription *); Index: ELF/LinkerScript.cpp =================================================================== --- ELF/LinkerScript.cpp +++ ELF/LinkerScript.cpp @@ -107,6 +107,22 @@ CurOutSec->Size = Dot - CurOutSec->Addr; } +template +bool LinkerScript::canCalculate(SymbolAssignment *Cmd) { + if (Cmd->Expression.DependsOn.empty()) + return true; + + std::vector Dep = std::move(Cmd->Expression.DependsOn); + for (StringRef Name : Dep) { + const OutputSection *OutSec = getSymbolSection(Name); + if (!OutSec || OutSec->HasAddr) + continue; + Cmd->Expression.DependsOn.push_back(Name); + } + + return Cmd->Expression.DependsOn.empty(); +} + // Sets value of a symbol. Two kinds of symbols are processed: synthetic // symbols, whose value is an offset from beginning of section and regular // symbols whose value is absolute. @@ -452,6 +468,7 @@ Dot = alignTo(Dot, CurOutSec->Addralign); CurOutSec->Addr = isTbss(CurOutSec) ? Dot + ThreadBssOffset : Dot; + CurOutSec->HasAddr = true; // If neither AT nor AT> is specified for an allocatable section, the linker // will set the LMA such that the difference between VMA and LMA for the @@ -791,9 +808,17 @@ Aether->SectionIndex = 1; switchTo(Aether); + std::vector PendingAssignments; for (const std::unique_ptr &Base : Opt.Commands) { + // Sometimes we cannot calculate the symbols value right now. + // For example it may depend on offset of input section, which + // was not yet assigned because corresponding OutputSectionCommand + // was not processed. We postpone execution in that case. if (auto *Cmd = dyn_cast(Base.get())) { - assignSymbol(Cmd); + if (!canCalculate(Cmd)) + PendingAssignments.push_back(Cmd); + else + assignSymbol(Cmd); continue; } @@ -804,6 +829,15 @@ auto *Cmd = cast(Base.get()); assignOffsets(Cmd); + + for (auto I = PendingAssignments.begin(); I != PendingAssignments.end();) { + if (!canCalculate(*I)) { + ++I; + continue; + } + assignSymbol(*I); + I = PendingAssignments.erase(I); + } } uintX_t MinVA = std::numeric_limits::max(); @@ -1881,9 +1915,12 @@ // Tok is a symbol name. if (Tok != "." && !isValidCIdentifier(Tok)) setError("malformed number: " + Tok); - return {[=](uint64_t Dot) { return getSymbolValue(Location, Tok, Dot); }, - [=] { return isAbsolute(Tok); }, - [=] { return ScriptBase->getSymbolSection(Tok); }}; + Expr E = {[=](uint64_t Dot) { return getSymbolValue(Location, Tok, Dot); }, + [=] { return isAbsolute(Tok); }, + [=] { return ScriptBase->getSymbolSection(Tok); }}; + if (Tok != ".") + E.DependsOn.push_back(Tok); + return E; } Expr ScriptParser::readTernary(Expr Cond) { Index: ELF/OutputSections.h =================================================================== --- ELF/OutputSections.h +++ ELF/OutputSections.h @@ -57,6 +57,9 @@ // Typically the first section of each PT_LOAD segment has this flag. bool PageAlign = false; + // true means that VA was assigned to section. + bool HasAddr = false; + // Pointer to the first section in PT_LOAD segment, which this section // also resides in. This field is used to correctly compute file offset // of a section. When two sections share the same load segment, difference Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -1483,6 +1483,7 @@ Sec->Addr = TVA; ThreadBssOffset = TVA - VA + Sec->Size; } + Sec->HasAddr = true; } } Index: test/ELF/linkerscript/symbols-dependency.s =================================================================== --- test/ELF/linkerscript/symbols-dependency.s +++ test/ELF/linkerscript/symbols-dependency.s @@ -0,0 +1,19 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t +# RUN: echo "SECTIONS { barsym1 = barsym; .bar : { *(.bar*) } }" > %t.script +# RUN: ld.lld %t --script %t.script -o %t1 +# RUN: llvm-readobj -symbols %t1 | FileCheck %s + +# CHECK: Symbol { +# CHECK: Name: barsym +# CHECK-NEXT: Value: 0x[[VAL:.*]] +# CHECK: Name: barsym1 +# CHECK-NEXT: Value: 0x[[VAL]] + +.section .bar.1, "a" +.quad 0 + +.section .bar.2, "a" +.quad 0 +.global barsym +barsym: