Index: ELF/ScriptParser.cpp =================================================================== --- ELF/ScriptParser.cpp +++ 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: test/ELF/linkerscript/subalign.s =================================================================== --- test/ELF/linkerscript/subalign.s +++ 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 inconsistent +## here 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