Index: lld/trunk/ELF/LinkerScript.cpp =================================================================== --- lld/trunk/ELF/LinkerScript.cpp +++ lld/trunk/ELF/LinkerScript.cpp @@ -643,7 +643,7 @@ expect("{"); while (!Error && !skip("}")) { StringRef Tok = next(); - if (peek() == "=") { + if (peek() == "=" || peek() == "+=") { readAssignment(Tok); expect(";"); } else if (Tok == "PROVIDE") { @@ -777,19 +777,10 @@ expect(";"); } -SymbolAssignment *ScriptParser::readAssignment(StringRef Name) { - expect("="); - Expr E = readExpr(); - auto *Cmd = new SymbolAssignment(Name, E); - Opt.Commands.emplace_back(Cmd); - return Cmd; -} +static uint64_t getSymbolValue(StringRef S, uint64_t Dot) { + if (S == ".") + return Dot; -// This is an operator-precedence parser to parse a linker -// script expression. -Expr ScriptParser::readExpr() { return readExpr1(readPrimary(), 0); } - -static uint64_t getSymbolValue(StringRef S) { switch (Config->EKind) { case ELF32LEKind: if (SymbolBody *B = Symtab::X->find(S)) @@ -814,6 +805,21 @@ return 0; } +SymbolAssignment *ScriptParser::readAssignment(StringRef Name) { + StringRef Op = next(); + assert(Op == "=" || Op == "+="); + Expr E = readExpr(); + if (Op == "+=") + E = [=](uint64_t Dot) { return getSymbolValue(Name, Dot) + E(Dot); }; + auto *Cmd = new SymbolAssignment(Name, E); + Opt.Commands.emplace_back(Cmd); + return Cmd; +} + +// This is an operator-precedence parser to parse a linker +// script expression. +Expr ScriptParser::readExpr() { return readExpr1(readPrimary(), 0); } + // This is a part of the operator-precedence parser. This function // assumes that the remaining token stream starts with an operator. Expr ScriptParser::readExpr1(Expr Lhs, int MinPrec) { @@ -853,9 +859,6 @@ Expr ScriptParser::readPrimary() { StringRef Tok = next(); - if (Tok == ".") - return [](uint64_t Dot) { return Dot; }; - if (Tok == "(") { Expr E = readExpr(); expect(")"); @@ -914,9 +917,9 @@ // Parse a symbol name or a number literal. uint64_t V = 0; if (Tok.getAsInteger(0, V)) { - if (!isValidCIdentifier(Tok)) + if (Tok != "." && !isValidCIdentifier(Tok)) setError("malformed number: " + Tok); - return [=](uint64_t Dot) { return getSymbolValue(Tok); }; + return [=](uint64_t Dot) { return getSymbolValue(Tok, Dot); }; } return [=](uint64_t Dot) { return V; }; } Index: lld/trunk/test/ELF/linkerscript/linkerscript-locationcounter.s =================================================================== --- lld/trunk/test/ELF/linkerscript/linkerscript-locationcounter.s +++ lld/trunk/test/ELF/linkerscript/linkerscript-locationcounter.s @@ -37,6 +37,9 @@ # RUN: . = DATA_SEGMENT_ALIGN (CONSTANT (MAXPAGESIZE), CONSTANT (COMMONPAGESIZE)); \ # RUN: .datasegmentalign : { *(.datasegmentalign) } \ # RUN: . = DATA_SEGMENT_END (.); \ +# RUN: . = 0x27000; \ +# RUN: . += 0x1000; \ +# RUN: .plusassign : { *(.plusassign) } \ # RUN: }" > %t.script # RUN: ld.lld %t --script %t.script -o %t2 # RUN: llvm-readobj -s %t2 | FileCheck %s @@ -296,6 +299,21 @@ # CHECK-NEXT: AddressAlignment: # CHECK-NEXT: EntrySize: # CHECK-NEXT: } +# CHECK-NEXT: Section { +# CHECK-NEXT: Index: +# CHECK-NEXT: Name: .plusassign +# CHECK-NEXT: Type: SHT_PROGBITS +# CHECK-NEXT: Flags [ +# CHECK-NEXT: SHF_ALLOC +# CHECK-NEXT: ] +# CHECK-NEXT: Address: 0x28000 +# CHECK-NEXT: Offset: +# CHECK-NEXT: Size: +# CHECK-NEXT: Link: +# CHECK-NEXT: Info: +# CHECK-NEXT: AddressAlignment: +# CHECK-NEXT: EntrySize: +# CHECK-NEXT: } ## Mailformed number error. # RUN: echo "SECTIONS { \ @@ -399,3 +417,6 @@ .section .datasegmentalign, "a" .quad 0 + +.section .plusassign, "a" +.quad 0