Index: ELF/LinkerScript.h =================================================================== --- ELF/LinkerScript.h +++ ELF/LinkerScript.h @@ -41,6 +41,7 @@ SectionBase *Sec; uint64_t Val; bool ForceAbsolute; + bool CanCalculateAbs = true; ExprValue(SectionBase *Sec, bool ForceAbsolute, uint64_t Val) : Sec(Sec), Val(Val), ForceAbsolute(ForceAbsolute) {} @@ -213,7 +214,7 @@ class LinkerScript { protected: - void assignSymbol(SymbolAssignment *Cmd, bool InSec); + bool assignSymbol(SymbolAssignment *Cmd, bool InSec); void setDot(Expr E, const Twine &Loc, bool InSec); std::vector @@ -232,6 +233,8 @@ void output(InputSection *Sec); void process(BaseCommand &Base); + void assignDelayedSymbols(); + OutputSection *Aether; bool ErrorOnMissingSection = false; @@ -245,6 +248,8 @@ llvm::DenseSet AlreadyOutputOS; llvm::DenseSet AlreadyOutputIS; + std::vector DelayedAssignments; + public: bool hasPhdrsCommands() { return !Opt.PhdrsCommands.empty(); } uint64_t getDot() { return Dot; } Index: ELF/LinkerScript.cpp =================================================================== --- ELF/LinkerScript.cpp +++ ELF/LinkerScript.cpp @@ -72,7 +72,7 @@ // We want to set symbol values early if we can. This allows us to use symbols // as variables in linker scripts. Doing so allows us to write expressions // like this: `alignment = 16; . = ALIGN(., alignment)` - uint64_t SymValue = Value.isAbsolute() ? Value.getValue() : 0; + uint64_t SymValue = Value.isAbsolute() ? Value.Val : 0; replaceBody(Sym, Cmd->Name, /*IsLocal=*/false, Visibility, STT_NOTYPE, SymValue, 0, Sec, nullptr); return Sym->body(); @@ -121,18 +121,21 @@ // 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. -void LinkerScript::assignSymbol(SymbolAssignment *Cmd, bool InSec) { +bool LinkerScript::assignSymbol(SymbolAssignment *Cmd, bool InSec) { if (Cmd->Name == ".") { setDot(Cmd->Expression, Cmd->Location, InSec); - return; + return true; } if (!Cmd->Sym) - return; + return true; auto *Sym = cast(Cmd->Sym); ExprValue V = Cmd->Expression(); + if (V.isAbsolute()) { + if (!V.CanCalculateAbs) + return false; Sym->Value = V.getValue(); } else { Sym->Section = V.Sec; @@ -141,6 +144,7 @@ else Sym->Value = V.getValue(); } + return true; } static SymbolBody *findSymbol(StringRef S) { @@ -526,6 +530,7 @@ Dot = alignTo(Dot, CurOutSec->Alignment); CurOutSec->Addr = isTbss(CurOutSec) ? Dot + ThreadBssOffset : Dot; + CurOutSec->AddrSet = 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 @@ -846,6 +851,14 @@ } } +void LinkerScript::assignDelayedSymbols() { + std::vector V; + for (SymbolAssignment *Cmd : DelayedAssignments) + if (!assignSymbol(Cmd, false)) + V.push_back(Cmd); + DelayedAssignments.swap(V); +} + void LinkerScript::assignAddresses(std::vector &Phdrs) { // Assign addresses as instructed by linker script SECTIONS sub-commands. Dot = 0; @@ -854,7 +867,8 @@ for (BaseCommand *Base : Opt.Commands) { if (auto *Cmd = dyn_cast(Base)) { - assignSymbol(Cmd, false); + if (!assignSymbol(Cmd, false)) + DelayedAssignments.push_back(Cmd); continue; } @@ -865,6 +879,8 @@ auto *Cmd = cast(Base); assignOffsets(Cmd); + + assignDelayedSymbols(); } uint64_t MinVA = std::numeric_limits::max(); @@ -977,12 +993,36 @@ return INT_MAX; } +// Sometimes expression can not be calculated. For example absolute expressions +// that depends on address of output section which was not assigned yet. +// Function helps find if we can evaluate absolute expression value or not. +static bool canCalcSymValue(DefinedRegular *D, + ArrayRef Delayed) { + // If symbol evaluation was delayed previously, we are unable to + // calculate expression that depends on not yet evaluated symbol value. + for (SymbolAssignment *Cmd : Delayed) + if (Cmd->Sym == D) + return false; + + // Absolute expressions are always calculatable. + if (!D->Section) + return true; + + // We can calculate symbol absolute value if it's input section attached + // to output section and output section has address assigned. + OutputSection *OutSec = D->Section->getOutputSection(); + return OutSec && OutSec->AddrSet; +} + ExprValue LinkerScript::getSymbolValue(const Twine &Loc, StringRef S) { if (S == ".") return {CurOutSec, Dot - CurOutSec->Addr}; if (SymbolBody *B = findSymbol(S)) { - if (auto *D = dyn_cast(B)) - return {D->Section, D->Value}; + if (auto *D = dyn_cast(B)) { + ExprValue E = {D->Section, D->Value}; + E.CanCalculateAbs = canCalcSymValue(D, DelayedAssignments); + return E; + } if (auto *C = dyn_cast(B)) return {InX::Common, C->Offset}; } Index: ELF/OutputSections.h =================================================================== --- ELF/OutputSections.h +++ ELF/OutputSections.h @@ -77,6 +77,11 @@ uint64_t Addr = 0; uint32_t ShName = 0; + // Makes sense when linkerscript is envolved. Flag is set to true when + // script assigns Addr field of section. And that means we can use section + // address in expressions. + bool AddrSet = false; + void addSection(InputSection *S); void sort(std::function Order); void sortInitFini(); Index: ELF/ScriptParser.cpp =================================================================== --- ELF/ScriptParser.cpp +++ ELF/ScriptParser.cpp @@ -131,11 +131,15 @@ static ExprValue add(ExprValue A, ExprValue B) { moveAbsRight(A, B); - return {A.Sec, A.ForceAbsolute, A.Val + B.getValue()}; + ExprValue E = {A.Sec, A.ForceAbsolute, A.Val + B.getValue()}; + E.CanCalculateAbs = A.CanCalculateAbs && B.CanCalculateAbs; + return E; } static ExprValue sub(ExprValue A, ExprValue B) { - return {A.Sec, A.Val - B.getValue()}; + ExprValue E = {A.Sec, A.Val - B.getValue()}; + E.CanCalculateAbs = A.CanCalculateAbs && B.CanCalculateAbs; + return E; } static ExprValue mul(ExprValue A, ExprValue B) { Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -1469,7 +1469,9 @@ Config->ImageBase = Min = std::min(Min, Config->ImageBase); Out::ElfHeader->Addr = Min; + Out::ElfHeader->AddrSet = true; Out::ProgramHeaders->Addr = Min + Out::ElfHeader->Size; + Out::ProgramHeaders->AddrSet = true; if (Script->hasPhdrsCommands()) return true; Index: test/ELF/linkerscript/early-assign-symbol.s =================================================================== --- test/ELF/linkerscript/early-assign-symbol.s +++ test/ELF/linkerscript/early-assign-symbol.s @@ -0,0 +1,23 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o +# RUN: echo "SECTIONS { . = 0x1000; \ +# RUN: aaa = ABSOLUTE(foo - 1); \ +# RUN: bbb = aaa + 2; \ +# RUN: .text : { *(.text*) } }; \ +# RUN: ccc = ABSOLUTE(foo - 1); \ +# RUN: ddd = ccc + 2;" > %t.script +# RUN: ld.lld -o %t --script %t.script %t.o +# RUN: llvm-objdump -t %t | FileCheck %s + +# CHECK: SYMBOL TABLE: +# CHECK: 0000000000000000 *UND* 00000000 +# CHECK: 0000000000001000 .text 00000000 foo +# CHECK: 0000000000000fff *ABS* 00000000 aaa +# CHECK: 0000000000000fff *ABS* 00000000 ccc +# CHECK: 0000000000001001 *ABS* 00000000 bbb +# CHECK: 0000000000001001 *ABS* 00000000 ddd + +.section .text +.globl foo +foo: + nop