Delay evaluation of alignment expressions in output sections
authorAlan Modra <amodra@gmail.com>
Sun, 26 Aug 2018 04:53:38 +0000 (14:23 +0930)
committerAlan Modra <amodra@gmail.com>
Sun, 26 Aug 2018 13:15:59 +0000 (22:45 +0930)
git commit 702d16713 broke expressions using CONSTANT(COMMONPAGESIZE)
in ALIGN or SUBALIGN of output section statements, because these
optional fields were evaluated at script parse time and the patch in
question delayed setting of config.commonpagesize.  The right thing to
do is keep the tree representation of those fields for later
evaluation.

PR 23571
* ldlang.h (section_alignment): Make it an expression tree.
(subsection_alignment): Likewise.
* ldlang.c (topower): Delete.
(output_section_statement_newfunc): Adjust initialization.
(init_os): Evaluate section_alignment.
(lang_size_sections_1): Likewise.
(size_input_section): Evaluate subsection_alignment.
(lang_enter_output_section_statement): Don't evaluate here.
(lang_new_phdr): Use exp_get_vma rather than exp_get_value_int.
* ldexp.h (exp_get_value_int): Delete.
(exp_get_power): Declare.
* ldexp.c (exp_get_value_int): Delete.
(exp_get_power): New function.
* emultempl/pe.em (place_orphan): Build expression for section
alignment.
* emultempl/pep.em (place_orphan): Likewise.
* testsuite/ld-scripts/pr23571.d,
* testsuite/ld-scripts/pr23571.t: New test.
* testsuite/ld-scripts/align.exp: Run it.

ld/ChangeLog
ld/emultempl/pe.em
ld/emultempl/pep.em
ld/ldexp.c
ld/ldexp.h
ld/ldlang.c
ld/ldlang.h
ld/testsuite/ld-scripts/align.exp
ld/testsuite/ld-scripts/pr23571.d [new file with mode: 0644]
ld/testsuite/ld-scripts/pr23571.t [new file with mode: 0644]

index 5488c85a0dd198071e23c3cc79708c28faf6dae7..96232df3f3a9cc023c522a865caaba827d3cdf0c 100644 (file)
@@ -1,3 +1,26 @@
+2018-08-26  Alan Modra  <amodra@gmail.com>
+
+       PR 23571
+       * ldlang.h (section_alignment): Make it an expression tree.
+       (subsection_alignment): Likewise.
+       * ldlang.c (topower): Delete.
+       (output_section_statement_newfunc): Adjust initialization.
+       (init_os): Evaluate section_alignment.
+       (lang_size_sections_1): Likewise.
+       (size_input_section): Evaluate subsection_alignment.
+       (lang_enter_output_section_statement): Don't evaluate here.
+       (lang_new_phdr): Use exp_get_vma rather than exp_get_value_int.
+       * ldexp.h (exp_get_value_int): Delete.
+       (exp_get_power): Declare.
+       * ldexp.c (exp_get_value_int): Delete.
+       (exp_get_power): New function.
+       * emultempl/pe.em (place_orphan): Build expression for section
+       alignment.
+       * emultempl/pep.em (place_orphan): Likewise.
+       * testsuite/ld-scripts/pr23571.d,
+       * testsuite/ld-scripts/pr23571.t: New test.
+       * testsuite/ld-scripts/align.exp: Run it.
+
 2018-08-24  Chenghua Xu  <paul.hua.gm@gmail.com>
 
        * testsuite/ld-mips-elf/mips-elf-flags.exp
index 463b85481d8ef0952daf80b0d32795b11d50e94d..663d4ce86202fc2352d6d07874048b1c92d0abf0 100644 (file)
@@ -2165,7 +2165,7 @@ gld_${EMULATION_NAME}_place_orphan (asection *s,
                               &add_child);
       if (bfd_link_relocatable (&link_info))
        {
-         os->section_alignment = s->alignment_power;
+         os->section_alignment = exp_intop (1U << s->alignment_power);
          os->bfd_section->alignment_power = s->alignment_power;
        }
     }
index 1a7394ea465fdb3f0a7787318710f0ddca0ab9e3..1dc1664f9851bca872875763b20f1252b4787da7 100644 (file)
@@ -1962,7 +1962,7 @@ gld_${EMULATION_NAME}_place_orphan (asection *s,
                               &add_child);
       if (bfd_link_relocatable (&link_info))
        {
-         os->section_alignment = s->alignment_power;
+         os->section_alignment = exp_intop (1U << s->alignment_power);
          os->bfd_section->alignment_power = s->alignment_power;
        }
     }
index 4ca812e9b20c93fba004225864351f94f623bab1..e123f0e35fe12fd129e7d49830c1b9255dd6752e 100644 (file)
@@ -1523,10 +1523,26 @@ exp_get_vma (etree_type *tree, bfd_vma def, char *name)
   return def;
 }
 
+/* Return the smallest non-negative integer such that two raised to
+   that power is at least as large as the vma evaluated at TREE, if
+   TREE is a non-NULL expression that can be resolved.  If TREE is
+   NULL or cannot be resolved, return -1.  */
+
 int
-exp_get_value_int (etree_type *tree, int def, char *name)
+exp_get_power (etree_type *tree, char *name)
 {
-  return exp_get_vma (tree, def, name);
+  bfd_vma x = exp_get_vma (tree, -1, name);
+  bfd_vma p2;
+  int n;
+
+  if (x == (bfd_vma) -1)
+    return -1;
+
+  for (n = 0, p2 = 1; p2 < x; ++n, p2 <<= 1)
+    if (p2 == 0)
+      break;
+
+  return n;
 }
 
 fill_type *
index d58cacba1c5baef7e56f3cb3cb9d56ac16807578..094911127ec968125946158f6ec147942ebaea59 100644 (file)
@@ -229,8 +229,8 @@ void exp_print_tree
   (etree_type *);
 bfd_vma exp_get_vma
   (etree_type *, bfd_vma, char *);
-int exp_get_value_int
-  (etree_type *, int, char *);
+int exp_get_power
+  (etree_type *, char *);
 fill_type *exp_get_fill
   (etree_type *, fill_type *, char *);
 bfd_vma exp_get_abs_int
index 350baf2912f3862c529c35d6a4ecca912bce1c4a..8878ccdb63677103b61500720fd2e2b36ef8affa 100644 (file)
@@ -1199,8 +1199,8 @@ output_section_statement_newfunc (struct bfd_hash_entry *entry,
   ret = (struct out_section_hash_entry *) entry;
   memset (&ret->s, 0, sizeof (ret->s));
   ret->s.header.type = lang_output_section_statement_enum;
-  ret->s.output_section_statement.subsection_alignment = -1;
-  ret->s.output_section_statement.section_alignment = -1;
+  ret->s.output_section_statement.subsection_alignment = NULL;
+  ret->s.output_section_statement.section_alignment = NULL;
   ret->s.output_section_statement.block_value = 1;
   lang_list_init (&ret->s.output_section_statement.children);
   lang_statement_append (stat_ptr, &ret->s, &ret->s.header.next);
@@ -2193,8 +2193,9 @@ init_os (lang_output_section_statement_type *s, flagword flags)
     exp_init_os (s->load_base);
 
   /* If supplied an alignment, set it.  */
-  if (s->section_alignment != -1)
-    s->bfd_section->alignment_power = s->section_alignment;
+  if (s->section_alignment != NULL)
+    s->bfd_section->alignment_power = exp_get_power (s->section_alignment,
+                                                    "section alignment");
 }
 
 /* Make sure that all output sections mentioned in an expression are
@@ -4706,8 +4707,10 @@ size_input_section
         is greater than any seen before, then record it too.  Perform
         the alignment by inserting a magic 'padding' statement.  */
 
-      if (output_section_statement->subsection_alignment != -1)
-       i->alignment_power = output_section_statement->subsection_alignment;
+      if (output_section_statement->subsection_alignment != NULL)
+       i->alignment_power
+         = exp_get_power (output_section_statement->subsection_alignment,
+                          "subsection alignment");
 
       if (o->alignment_power < i->alignment_power)
        o->alignment_power = i->alignment_power;
@@ -5147,7 +5150,8 @@ lang_size_sections_1
                    section_alignment = os->bfd_section->alignment_power;
                  }
                else
-                 section_alignment = os->section_alignment;
+                 section_alignment = exp_get_power (os->section_alignment,
+                                                    "section alignment");
 
                /* Align to what the section needs.  */
                if (section_alignment > 0)
@@ -5225,7 +5229,8 @@ lang_size_sections_1
                       only align according to the value in the output
                       statement.  */
                    if (os->lma_region != os->region)
-                     section_alignment = os->section_alignment;
+                     section_alignment = exp_get_power (os->section_alignment,
+                                                        "section alignment");
                    if (section_alignment > 0)
                      lma = align_power (lma, section_alignment);
                  }
@@ -6673,25 +6678,6 @@ lang_add_output (const char *name, int from_script)
     }
 }
 
-static int
-topower (int x)
-{
-  unsigned int i = 1;
-  int l;
-
-  if (x < 0)
-    return -1;
-
-  for (l = 0; l < 32; l++)
-    {
-      if (i >= (unsigned int) x)
-       return l;
-      i <<= 1;
-    }
-
-  return 0;
-}
-
 lang_output_section_statement_type *
 lang_enter_output_section_statement (const char *output_section_statement_name,
                                     etree_type *address_exp,
@@ -6727,10 +6713,8 @@ lang_enter_output_section_statement (const char *output_section_statement_name,
     einfo (_("%F%P:%pS: error: align with input and explicit align specified\n"),
           NULL);
 
-  os->subsection_alignment =
-    topower (exp_get_value_int (subalign, -1, "subsection alignment"));
-  os->section_alignment =
-    topower (exp_get_value_int (align, -1, "section alignment"));
+  os->subsection_alignment = subalign;
+  os->section_alignment = align;
 
   os->load_base = ebase;
   return os;
@@ -7748,7 +7732,7 @@ lang_new_phdr (const char *name,
   n = (struct lang_phdr *) stat_alloc (sizeof (struct lang_phdr));
   n->next = NULL;
   n->name = name;
-  n->type = exp_get_value_int (type, 0, "program header type");
+  n->type = exp_get_vma (type, 0, "program header type");
   n->filehdr = filehdr;
   n->phdrs = phdrs;
   n->at = at;
index 3d661696873f449dea6a0cd3cfadd31a30784e64..dfac0b1b68ec2915a536f7c63c9a80cb998eaec8 100644 (file)
@@ -143,6 +143,8 @@ typedef struct lang_output_section_statement_struct
   fill_type *fill;
   union etree_union *addr_tree;
   union etree_union *load_base;
+  union etree_union *section_alignment;
+  union etree_union *subsection_alignment;
 
   /* If non-null, an expression to evaluate after setting the section's
      size.  The expression is evaluated inside REGION (above) with '.'
@@ -153,8 +155,6 @@ typedef struct lang_output_section_statement_struct
   lang_output_section_phdr_list *phdrs;
 
   unsigned int block_value;
-  int subsection_alignment;    /* Alignment of components.  */
-  int section_alignment;       /* Alignment of start of section.  */
   int constraint;
   flagword flags;
   enum section_type sectype;
index f9523d26af64970ba4bda2ac8a0fb22100b4ba64..25d4f6dfed5b4a97fecf8cf559d7c1239c11ac83 100644 (file)
@@ -53,3 +53,7 @@ if ![is_aout_format] {
 }
 run_dump_test align2c
 set LDFLAGS "$saved_LDFLAGS"
+
+if { [is_elf_format] && ![is_generic_elf] } {
+    run_dump_test pr23571
+}
diff --git a/ld/testsuite/ld-scripts/pr23571.d b/ld/testsuite/ld-scripts/pr23571.d
new file mode 100644 (file)
index 0000000..adf4796
--- /dev/null
@@ -0,0 +1,10 @@
+#source: align2a.s
+#ld: -T pr23571.t -z common-page-size=0x1000
+#objdump: -h -w
+
+.*: +file format .*
+
+Sections:
+Idx Name +Size +VMA +LMA +File off +Algn +Flags
+ +0 \.text +[0-9a-f]* +0+1000 +0+1000 .*
+ +1 \.data +[0-9a-f]* +0+2000 +0+2000 +[0-9a-f]* +2\*\*12 .*
diff --git a/ld/testsuite/ld-scripts/pr23571.t b/ld/testsuite/ld-scripts/pr23571.t
new file mode 100644 (file)
index 0000000..290cdf5
--- /dev/null
@@ -0,0 +1,11 @@
+SECTIONS
+{
+  .text CONSTANT(COMMONPAGESIZE) : {
+    *(.text)
+  }
+
+  .data : ALIGN(CONSTANT(COMMONPAGESIZE)) {
+    *(.data)
+  }
+  /DISCARD/ : {*(*)}
+}