[ELF] - Linkerscript: fix issue with SUBALIGN.
authorGeorge Rimar <grimar@accesssoftek.com>
Wed, 25 Oct 2017 14:50:51 +0000 (14:50 +0000)
committerGeorge Rimar <grimar@accesssoftek.com>
Wed, 25 Oct 2017 14:50:51 +0000 (14:50 +0000)
This is PR34886.

SUBALIGN command currently triggers failture if result expression
is zero. Patch fixes the issue, treating zero as 1, what is consistent with
other places and ELF spec it seems.

Patch also adds "is power of 2" check for this and other expressions
returning alignment.

Differential revision: https://reviews.llvm.org/D38846

llvm-svn: 316580

lld/ELF/ScriptParser.cpp
lld/test/ELF/linkerscript/align.s
lld/test/ELF/linkerscript/subalign.s

index 5582ce672fbf0c7c99e4f3d4a0e53a6f115d34bf..903be2f503c2dbc9777c57f8046d83d44a0e84d2 100644 (file)
@@ -642,6 +642,17 @@ void ScriptParser::readSectionAddressType(OutputSection *Cmd) {
   }
 }
 
+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 @@ OutputSection *ScriptParser::readOutputSectionDescription(StringRef OutSec) {
     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 @@ Expr ScriptParser::readPrimary() {
   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 1d70fab45fea64e77f371ac10cd7e85798f1c3e0..99e7382daa59d4e0e57b7a4cbabbf1cd0be38516 100644 (file)
 # 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 8b441d440b0ef474969a832b7af4b76cce378e6e..0c4c5627db934523ba5b17d41b763fd6cbf5040c 100644 (file)
 # 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