Index: lld/trunk/ELF/ScriptParser.cpp =================================================================== --- lld/trunk/ELF/ScriptParser.cpp +++ lld/trunk/ELF/ScriptParser.cpp @@ -642,6 +642,17 @@ } } +static Expr checkAlignment(Expr E, std::string &Loc) { + return [=] { + uint64_t Alignment = std::max((uint64_t)1, E().getValue()); + if (!isPowerOf2_64(Alignment)) { + error(Loc + ": alignment must be power of 2"); + return (uint64_t)1; // Return a dummy value. + } + return Alignment; + }; +} + OutputSection *ScriptParser::readOutputSectionDescription(StringRef OutSec) { OutputSection *Cmd = Script->createOutputSection(OutSec, getCurrentLocation()); @@ -650,12 +661,13 @@ readSectionAddressType(Cmd); expect(":"); + std::string Location = getCurrentLocation(); if (consume("AT")) Cmd->LMAExpr = readParenExpr(); if (consume("ALIGN")) - Cmd->AlignExpr = readParenExpr(); + Cmd->AlignExpr = checkAlignment(readParenExpr(), Location); if (consume("SUBALIGN")) - Cmd->SubalignExpr = readParenExpr(); + Cmd->SubalignExpr = checkAlignment(readParenExpr(), Location); // Parse constraints. if (consume("ONLY_IF_RO")) @@ -959,16 +971,16 @@ if (Tok == "ALIGN") { expect("("); Expr E = readExpr(); - if (consume(")")) - return [=] { - return alignTo(Script->getDot(), std::max((uint64_t)1, E().getValue())); - }; + if (consume(")")) { + E = checkAlignment(E, Location); + return [=] { return alignTo(Script->getDot(), E().getValue()); }; + } expect(","); - Expr E2 = readExpr(); + Expr E2 = checkAlignment(readExpr(), Location); expect(")"); return [=] { ExprValue V = E(); - V.Alignment = std::max((uint64_t)1, E2().getValue()); + V.Alignment = E2().getValue(); return V; }; } Index: lld/trunk/test/ELF/linkerscript/align.s =================================================================== --- lld/trunk/test/ELF/linkerscript/align.s +++ lld/trunk/test/ELF/linkerscript/align.s @@ -81,6 +81,14 @@ # RUN: ld.lld -o %t5 --script %t.script %t # RUN: llvm-objdump -section-headers %t5 | FileCheck %s -check-prefix=ZERO +## Test we fail gracefuly when alignment value is not a power of 2 (#1). +# RUN: echo "SECTIONS { . = 0x123; . = ALIGN(0x123, 3); .aaa : { *(.aaa) } }" > %t.script +# RUN: not ld.lld -o %t6 --script %t.script %t 2>&1 | FileCheck -check-prefix=ERR %s +# ERR: {{.*}}.script:1: alignment must be power of 2 + +## Test we fail gracefuly when alignment value is not a power of 2 (#2). +# RUN: echo "SECTIONS { . = 0x123; . = ALIGN(3); .aaa : { *(.aaa) } }" > %t.script +# RUN: not ld.lld -o %t7 --script %t.script %t 2>&1 | FileCheck -check-prefix=ERR %s # RUN: echo "SECTIONS { \ # RUN: . = 0xff8; \ Index: lld/trunk/test/ELF/linkerscript/subalign.s =================================================================== --- lld/trunk/test/ELF/linkerscript/subalign.s +++ lld/trunk/test/ELF/linkerscript/subalign.s @@ -22,6 +22,23 @@ # SUBALIGN: 01000000 00000000 02000000 00000000 # SUBALIGN: 03000000 00000000 04000000 00000000 +## Test we do not assert or crash when dot(.) is used inside SUBALIGN. +## ld.bfd does not allow to use dot in such expressions, our behavior is +## different for simplicity of implementation. Value of dot is undefined. +# RUN: echo "SECTIONS { . = 0x32; .aaa : SUBALIGN(.) { *(.aaa*) } }" > %t3.script +# RUN: ld.lld %t1.o --script %t3.script -o %t3 +# RUN: llvm-objdump -s %t3 > /dev/null + +## Test we are able to link with zero alignment, this is consistent with bfd 2.26.1. +# RUN: echo "SECTIONS { .aaa : SUBALIGN(0) { *(.aaa*) } }" > %t4.script +# RUN: ld.lld %t1.o --script %t4.script -o %t4 +# RUN: llvm-objdump -s %t4 | FileCheck -check-prefix=SUBALIGN %s + +## Test we fail gracefuly when alignment value is not a power of 2. +# RUN: echo "SECTIONS { .aaa : SUBALIGN(3) { *(.aaa*) } }" > %t5.script +# RUN: not ld.lld %t1.o --script %t5.script -o %t5 2>&1 | FileCheck -check-prefix=ERR %s +# ERR: {{.*}}.script:1: alignment must be power of 2 + .global _start _start: nop