Index: ELF/LinkerScript.h =================================================================== --- ELF/LinkerScript.h +++ ELF/LinkerScript.h @@ -69,6 +69,7 @@ : BaseCommand(OutputSectionKind), Name(Name) {} static bool classof(const BaseCommand *C); StringRef Name; + std::vector AddrExpr; std::vector> Commands; std::vector Phdrs; std::vector Filler; Index: ELF/LinkerScript.cpp =================================================================== --- ELF/LinkerScript.cpp +++ ELF/LinkerScript.cpp @@ -377,6 +377,9 @@ if (Sec->getName() != Cmd->Name) continue; + if (!Cmd->AddrExpr.empty()) + Dot = evalExpr(Cmd->AddrExpr, Dot); + if ((Sec->getFlags() & SHF_TLS) && Sec->getType() == SHT_NOBITS) { uintX_t TVA = Dot + ThreadBssOffset; TVA = alignTo(TVA, Sec->getAlignment()); @@ -823,6 +826,10 @@ void ScriptParser::readOutputSectionDescription(StringRef OutSec) { OutputSectionCommand *Cmd = new OutputSectionCommand(OutSec); Opt.Commands.emplace_back(Cmd); + + if (peek() != ":") + Cmd->AddrExpr = readSectionsCommandExpr(); + expect(":"); // Parse constraints. @@ -894,10 +901,17 @@ // This function reads balanced expression until semicolon is seen. std::vector ScriptParser::readSectionsCommandExpr() { int Braces = 0; + int Ternary = 0; std::vector Expr; while (!Error) { StringRef Tok = peek(); + if (Tok == "?") + ++Ternary; + else if (Tok == ":") + if (--Ternary < 0) + break; + if (Tok == "(") Braces++; else if (Tok == ")") Index: test/ELF/linkerscript-diagnostic.s =================================================================== --- test/ELF/linkerscript-diagnostic.s +++ test/ELF/linkerscript-diagnostic.s @@ -11,10 +11,10 @@ # RUN: echo ".temp : { *(.temp) } }" >> %t.script # RUN: ld.lld -shared %t -o %t1 --script %t.script -## Change ":" to "+" at line 2, check that error +## Add 'a' at line 2, check that error ## message starts from correct line number: # RUN: echo "SECTIONS {" > %t.script -# RUN: echo ".text + { *(.text) }" >> %t.script +# RUN: echo ".text : {a *(.text) }" >> %t.script # RUN: echo ".keep : { *(.keep) } /*" >> %t.script # RUN: echo "comment line 1" >> %t.script # RUN: echo "comment line 2 */" >> %t.script @@ -22,24 +22,24 @@ # RUN: not ld.lld -shared %t -o %t1 --script %t.script 2>&1 | FileCheck -check-prefix=ERR1 %s # ERR1: line 2: -## Change ":" to "+" at line 3 now, check correct error line number: +## Add 'a' at line 3 now, check correct error line number: # RUN: echo "SECTIONS {" > %t.script # RUN: echo ".text : { *(.text) }" >> %t.script -# RUN: echo ".keep + { *(.keep) } /*" >> %t.script +# RUN: echo ".keep : {a *(.keep) } /*" >> %t.script # RUN: echo "comment line 1" >> %t.script # RUN: echo "comment line 2 */" >> %t.script # RUN: echo ".temp : { *(.temp) } }" >> %t.script # RUN: not ld.lld -shared %t -o %t1 --script %t.script 2>&1 | FileCheck -check-prefix=ERR2 %s # ERR2: line 3: -## Change ":" to "+" at line 6, after multiline comment, +## Add 'a' at line 6, after multiline comment, ## check correct error line number: # RUN: echo "SECTIONS {" > %t.script # RUN: echo ".text : { *(.text) }" >> %t.script # RUN: echo ".keep : { *(.keep) } /*" >> %t.script # RUN: echo "comment line 1" >> %t.script # RUN: echo "comment line 2 */" >> %t.script -# RUN: echo ".temp + { *(.temp) } }" >> %t.script +# RUN: echo ".temp : {a *(.temp) } }" >> %t.script # RUN: not ld.lld -shared %t -o %t1 --script %t.script 2>&1 | FileCheck -check-prefix=ERR5 %s # ERR5: line 6: @@ -58,9 +58,9 @@ # RUN: echo "SECTIONS {" > %t.script # RUN: echo ".text : { *(.text) }" >> %t.script # RUN: echo ".keep : { *(.keep) }" >> %t.script -# RUN: echo "boom .temp : { *(.temp) } }" >> %t.script +# RUN: echo ".temp : { *'.temp) } }" >> %t.script # RUN: not ld.lld -shared %t -o %t1 --script %t.script > %t.log 2>&1 # RUN: FileCheck -check-prefix=ERR7 %s < %t.log -# ERR7: line 4: : expected, but got .temp -# ERR7-NEXT: boom .temp : { *(.temp) } } -# RUN: grep '^ ^' %t.log +# ERR7: line 4: ( expected, but got ' +# ERR7-NEXT: .temp : { *'.temp) } } +# RUN: grep '^ ^' %t.log Index: test/ELF/linkerscript-locationcounter.s =================================================================== --- test/ELF/linkerscript-locationcounter.s +++ test/ELF/linkerscript-locationcounter.s @@ -319,7 +319,7 @@ # RUN: }" > %t.script # RUN: not ld.lld %t --script %t.script -o %t2 2>&1 | \ # RUN: FileCheck --check-prefix=BRACKETERR2 %s -# BRACKETERR2: expected, but got * +# BRACKETERR2: expected, but got } ## Empty expression. # RUN: echo "SECTIONS { \ Index: test/ELF/linkerscript-outsections-addr.s =================================================================== --- test/ELF/linkerscript-outsections-addr.s +++ test/ELF/linkerscript-outsections-addr.s @@ -0,0 +1,122 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t +# RUN: echo "SECTIONS { \ +# RUN: .aaa 0x2000 : \ +# RUN: { \ +# RUN: *(.aaa) \ +# RUN: } \ +# RUN: .bbb 0x1 ? 0x3000 : 0x4000 : \ +# RUN: { \ +# RUN: *(.bbb) \ +# RUN: } \ +# RUN: .ccc ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) : \ +# RUN: { \ +# RUN: *(.ccc) \ +# RUN: } \ +# RUN: .ddd 0x5001 : \ +# RUN: { \ +# RUN: *(.ddd) \ +# RUN: } \ +# RUN: }" > %t.script +# RUN: ld.lld %t --script %t.script -o %tout +# RUN: llvm-readobj -s %tout | FileCheck %s + +## Check: +## 1) Simple constant as address. +## 2) That something that contains ":" character, like ternary +## operator works as expression. +## 3) That complex expressions work. +## 4) That section alignment still applied to explicitly specified address. + +#CHECK:Sections [ +#CHECK: Section { +#CHECK: Index: 0 +#CHECK: Name: +#CHECK: Type: SHT_NULL +#CHECK: Flags [ +#CHECK: ] +#CHECK: Address: 0x0 +#CHECK: Offset: 0x0 +#CHECK: Size: 0 +#CHECK: Link: 0 +#CHECK: Info: 0 +#CHECK: AddressAlignment: 0 +#CHECK: EntrySize: 0 +#CHECK: } +#CHECK: Section { +#CHECK: Index: 1 +#CHECK: Name: .aaa +#CHECK: Type: SHT_PROGBITS +#CHECK: Flags [ +#CHECK: SHF_ALLOC +#CHECK: ] +#CHECK: Address: 0x2000 +#CHECK: Offset: 0x1000 +#CHECK: Size: 8 +#CHECK: Link: 0 +#CHECK: Info: 0 +#CHECK: AddressAlignment: 1 +#CHECK: EntrySize: 0 +#CHECK: } +#CHECK: Section { +#CHECK: Index: 2 +#CHECK: Name: .bbb +#CHECK: Type: SHT_PROGBITS +#CHECK: Flags [ +#CHECK: SHF_ALLOC +#CHECK: ] +#CHECK: Address: 0x3000 +#CHECK: Offset: 0x2000 +#CHECK: Size: 8 +#CHECK: Link: 0 +#CHECK: Info: 0 +#CHECK: AddressAlignment: 1 +#CHECK: EntrySize: 0 +#CHECK: } +#CHECK: Section { +#CHECK: Index: 3 +#CHECK: Name: .ccc +#CHECK: Type: SHT_PROGBITS +#CHECK: Flags [ +#CHECK: SHF_ALLOC +#CHECK: ] +#CHECK: Address: 0x4008 +#CHECK: Offset: 0x2008 +#CHECK: Size: 8 +#CHECK: Link: 0 +#CHECK: Info: 0 +#CHECK: AddressAlignment: 1 +#CHECK: EntrySize: 0 +#CHECK: } +#CHECK: Section { +#CHECK: Index: 4 +#CHECK: Name: .ddd +#CHECK: Type: SHT_PROGBITS +#CHECK: Flags [ +#CHECK: SHF_ALLOC +#CHECK: ] +#CHECK: Address: 0x5010 +#CHECK: Offset: 0x2010 +#CHECK: Size: 8 +#CHECK: Link: 0 +#CHECK: Info: 0 +#CHECK: AddressAlignment: 16 +#CHECK: EntrySize: 0 +#CHECK: } + +.globl _start +_start: +nop + +.section .aaa, "a" +.quad 0 + +.section .bbb, "a" +.quad 0 + +.section .ccc, "a" +.quad 0 + +.section .ddd, "a" +.align 16 +.quad 0