Index: ELF/LinkerScript.h =================================================================== --- ELF/LinkerScript.h +++ ELF/LinkerScript.h @@ -264,6 +264,7 @@ bool shouldKeep(InputSectionBase *S); void assignOffsets(OutputSectionCommand *Cmd); void placeOrphanSections(); + void processNonSectionCommands(); void assignAddresses(std::vector &Phdrs); bool hasPhdrsCommands(); uint64_t getHeaderSize() override; Index: ELF/LinkerScript.cpp =================================================================== --- ELF/LinkerScript.cpp +++ ELF/LinkerScript.cpp @@ -130,11 +130,6 @@ return; Cmd->Sym = addRegular(Cmd); - - // If there are sections, then let the value be assigned later in - // `assignAddresses`. - if (!ScriptConfig->HasSections) - assignSymbol(Cmd); } bool SymbolAssignment::classof(const BaseCommand *C) { @@ -324,15 +319,6 @@ 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 - // will not be called, so ASSERT should be evaluated now. - if (!Opt.HasSections) - Cmd->Expression(); - continue; - } - if (auto *Cmd = dyn_cast(Base1.get())) { std::vector V = createInputSectionList(*Cmd); @@ -763,6 +749,16 @@ } template +void LinkerScript::processNonSectionCommands() { + for (const std::unique_ptr &Base : Opt.Commands) { + if (auto *Cmd = dyn_cast(Base.get())) + assignSymbol(Cmd); + else if (auto *Cmd = dyn_cast(Base.get())) + Cmd->Expression(); + } +} + +template void LinkerScript::assignAddresses(std::vector &Phdrs) { // Assign addresses as instructed by linker script SECTIONS sub-commands. Dot = 0; @@ -1577,14 +1573,8 @@ SymbolAssignment *ScriptParser::readAssignment(StringRef Name) { StringRef Op = next(); - Expr E; assert(Op == "=" || Op == "+="); - if (consume("ABSOLUTE")) { - E = readExpr(); - E.IsAbsolute = [] { return true; }; - } else { - E = readExpr(); - } + Expr E = readExpr(); if (Op == "+=") { std::string Loc = getCurrentLocation(); E = [=] { return ScriptBase->getSymbolValue(Loc, Name) + E(); }; @@ -1760,6 +1750,11 @@ // Built-in functions are parsed here. // https://sourceware.org/binutils/docs/ld/Builtin-Functions.html. + if (Tok == "ABSOLUTE") { + Expr E = readParenExpr(); + E.IsAbsolute = [] { return true; }; + return E; + } if (Tok == "ADDR") { StringRef Name = readParenLiteral(); return {[=] { return ScriptBase->getOutputSection(Location, Name)->Addr; }, Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -270,6 +270,7 @@ } else { fixSectionAlignments(); assignAddresses(); + Script::X->processNonSectionCommands(); } // Remove empty PT_LOAD to avoid causing the dynamic linker to try to mmap a Index: test/ELF/linkerscript/absolute.s =================================================================== --- test/ELF/linkerscript/absolute.s +++ test/ELF/linkerscript/absolute.s @@ -4,6 +4,11 @@ # RUN: ld.lld -o %t --script %t.script %t.o # RUN: llvm-readobj --symbols %t | FileCheck %s +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o +# RUN: echo "PROVIDE(foo = 1 + ABSOLUTE(ADDR(.text)));" > %t.script +# RUN: ld.lld -o %t --script %t.script %t.o +# RUN: llvm-readobj --symbols %t | FileCheck --check-prefix=CHECK-RHS %s + # CHECK: Name: foo # CHECK-NEXT: Value: # CHECK-NEXT: Size: @@ -13,6 +18,18 @@ # CHECK-NEXT: Section: Absolute # CHECK-NEXT: } +# CHECK-RHS: Name: foo +# CHECK-RHS-NEXT: Value: 0x201001 +# CHECK-RHS-NEXT: Size: +# CHECK-RHS-NEXT: Binding: +# CHECK-RHS-NEXT: Type: +# CHECK-RHS-NEXT: Other: +# CHECK-RHS-NEXT: Section: Absolute +# CHECK-RHS-NEXT: } + .text .globl _start _start: + nop + +.global foo