Allow self-assignment for absolute symbols defined in a linker script
authorAlan Modra <amodra@gmail.com>
Mon, 20 Jan 2014 10:58:42 +0000 (21:28 +1030)
committerAlan Modra <amodra@gmail.com>
Mon, 20 Jan 2014 10:58:42 +0000 (21:28 +1030)
Modifies ld machinery tracking linker script assignments to notice all
assignments, not just those symbols mentioned in DEFINED().

ld/
PR ld/14962
* ldlang.h (struct lang_definedness_hash_entry): Add by_object and
by_script.  Make iteration a single bit field.
(lang_track_definedness, lang_symbol_definition_iteration): Delete.
(lang_symbol_defined): Declare.
* ldlang.c (lang_statement_iteration): Expand comment a little.
(lang_init <lang_definedness_table>): Make it bigger.
(lang_track_definedness, lang_symbol_definition): Delete.
(lang_definedness_newfunc): Update.
(lang_symbol_defined): New function.
(lang_update_definedness): Create entries here.  Do track whether
script definition of symbol is valid, even when also defined in
an object file.
* ldexp.c (fold_name <DEFINED>): Update.
(fold_name <NAME>): Allow self-assignment for absolute symbols
defined in a linker script.
ld/testsuite/
* ld-scripts/pr14962-2.d,
* ld-scripts/pr14962-2.t: New test.
* ld-scripts/expr.exp: Run it.

ld/ChangeLog
ld/ldexp.c
ld/ldlang.c
ld/ldlang.h
ld/testsuite/ChangeLog
ld/testsuite/ld-scripts/expr.exp
ld/testsuite/ld-scripts/pr14962-2.d [new file with mode: 0644]
ld/testsuite/ld-scripts/pr14962-2.t [new file with mode: 0644]

index a022cba570014c63e0e3171b11b98354fa189272..bc46e5f5da8edb48fc9c3e799c98f3a8fc2ad357 100644 (file)
@@ -1,3 +1,21 @@
+2014-01-20  Alan Modra  <amodra@gmail.com>
+
+       * ldlang.h (struct lang_definedness_hash_entry): Add by_object and
+       by_script.  Make iteration a single bit field.
+       (lang_track_definedness, lang_symbol_definition_iteration): Delete.
+       (lang_symbol_defined): Declare.
+       * ldlang.c (lang_statement_iteration): Expand comment a little.
+       (lang_init <lang_definedness_table>): Make it bigger.
+       (lang_track_definedness, lang_symbol_definition): Delete.
+       (lang_definedness_newfunc): Update.
+       (lang_symbol_defined): New function.
+       (lang_update_definedness): Create entries here.  Do track whether
+       script definition of symbol is valid, even when also defined in
+       an object file.
+       * ldexp.c (fold_name <DEFINED>): Update.
+       (fold_name <NAME>): Allow self-assignment for absolute symbols
+       defined in a linker script.
+
 2014-01-20  Guy Martin <gmsoft@tuxicoman.be>
            Alan Modra  <amodra@gmail.com>
 
index 49e7c65f4176f1d5990ec856a433e30fb978c385..9a529dbb6516df1e2f416b44c131e412e28ad5b0 100644 (file)
@@ -575,13 +575,10 @@ fold_name (etree_type *tree)
       break;
 
     case DEFINED:
-      if (expld.phase == lang_first_phase_enum)
-       lang_track_definedness (tree->name.name);
-      else
+      if (expld.phase != lang_first_phase_enum)
        {
          struct bfd_link_hash_entry *h;
-         int def_iteration
-           = lang_symbol_definition_iteration (tree->name.name);
+         struct lang_definedness_hash_entry *def;
 
          h = bfd_wrapped_link_hash_lookup (link_info.output_bfd,
                                            &link_info,
@@ -591,15 +588,33 @@ fold_name (etree_type *tree)
                      && (h->type == bfd_link_hash_defined
                          || h->type == bfd_link_hash_defweak
                          || h->type == bfd_link_hash_common)
-                     && (def_iteration == lang_statement_iteration
-                         || def_iteration == -1));
+                     && ((def = lang_symbol_defined (tree->name.name)) == NULL
+                         || def->by_object
+                         || def->iteration == (lang_statement_iteration & 1)));
        }
       break;
 
     case NAME:
       if (expld.assign_name != NULL
          && strcmp (expld.assign_name, tree->name.name) == 0)
-       expld.assign_name = NULL;
+       {
+         /* Self-assignment is only allowed for absolute symbols
+            defined in a linker script.  */
+         struct bfd_link_hash_entry *h;
+         struct lang_definedness_hash_entry *def;
+
+         h = bfd_wrapped_link_hash_lookup (link_info.output_bfd,
+                                           &link_info,
+                                           tree->name.name,
+                                           FALSE, FALSE, TRUE);
+         if (!(h != NULL
+               && (h->type == bfd_link_hash_defined
+                   || h->type == bfd_link_hash_defweak)
+               && h->u.def.section == bfd_abs_section_ptr
+               && (def = lang_symbol_defined (tree->name.name)) != NULL
+               && def->iteration == (lang_statement_iteration & 1)))
+           expld.assign_name = NULL;
+       }
       if (expld.phase == lang_first_phase_enum)
        ;
       else if (tree->name.name[0] == '.' && tree->name.name[1] == 0)
index f6d713c22d6f97ed65c632fef4b3d6e29719b3a5..9e355273fdef38037d852dc14979dfb12551f0b6 100644 (file)
@@ -107,7 +107,7 @@ struct lang_phdr *lang_phdr_list;
 struct lang_nocrossrefs *nocrossref_list;
 
  /* Functions that traverse the linker script and might evaluate
-    DEFINED() need to increment this.  */
+    DEFINED() need to increment this at the start of the traversal.  */
 int lang_statement_iteration = 0;
 
 etree_type *base; /* Relocation base - or null */
@@ -1221,16 +1221,12 @@ lang_init (void)
 
   abs_output_section->bfd_section = bfd_abs_section_ptr;
 
-  /* The value "3" is ad-hoc, somewhat related to the expected number of
-     DEFINED expressions in a linker script.  For most default linker
-     scripts, there are none.  Why a hash table then?  Well, it's somewhat
-     simpler to re-use working machinery than using a linked list in terms
-     of code-complexity here in ld, besides the initialization which just
-     looks like other code here.  */
+  /* The value "13" is ad-hoc, somewhat related to the expected number of
+     assignments in a linker script.  */
   if (!bfd_hash_table_init_n (&lang_definedness_table,
                              lang_definedness_newfunc,
                              sizeof (struct lang_definedness_hash_entry),
-                             3))
+                             13))
     einfo (_("%P%F: can not create hash table: %E\n"));
 }
 
@@ -2054,7 +2050,7 @@ lang_map (void)
       obstack_begin (&map_obstack, 1000);
       bfd_link_hash_traverse (link_info.hash, sort_def_symbol, 0);
     }
-  lang_statement_iteration ++;
+  lang_statement_iteration++;
   print_statements ();
 }
 
@@ -3286,15 +3282,6 @@ open_input_bfds (lang_statement_union_type *s, enum open_bfd_mode mode)
     einfo ("%F");
 }
 
-/* Add a symbol to a hash of symbols used in DEFINED (NAME) expressions.  */
-
-void
-lang_track_definedness (const char *name)
-{
-  if (bfd_hash_lookup (&lang_definedness_table, name, TRUE, FALSE) == NULL)
-    einfo (_("%P%F: bfd_hash_lookup failed creating symbol %s\n"), name);
-}
-
 /* New-function for the definedness hash table.  */
 
 static struct bfd_hash_entry *
@@ -3312,28 +3299,22 @@ lang_definedness_newfunc (struct bfd_hash_entry *entry,
   if (ret == NULL)
     einfo (_("%P%F: bfd_hash_allocate failed creating symbol %s\n"), name);
 
-  ret->iteration = -1;
+  ret->by_object = 0;
+  ret->by_script = 0;
+  ret->iteration = 0;
   return &ret->root;
 }
 
-/* Return the iteration when the definition of NAME was last updated.  A
-   value of -1 means that the symbol is not defined in the linker script
-   or the command line, but may be defined in the linker symbol table.  */
+/* Called during processing of linker script script expressions.
+   For symbols assigned in a linker script, return a struct describing
+   where the symbol is defined relative to the current expression,
+   otherwise return NULL.  */
 
-int
-lang_symbol_definition_iteration (const char *name)
+struct lang_definedness_hash_entry *
+lang_symbol_defined (const char *name)
 {
-  struct lang_definedness_hash_entry *defentry
-    = (struct lang_definedness_hash_entry *)
-    bfd_hash_lookup (&lang_definedness_table, name, FALSE, FALSE);
-
-  /* We've already created this one on the presence of DEFINED in the
-     script, so it can't be NULL unless something is borked elsewhere in
-     the code.  */
-  if (defentry == NULL)
-    FAIL ();
-
-  return defentry->iteration;
+  return ((struct lang_definedness_hash_entry *)
+         bfd_hash_lookup (&lang_definedness_table, name, FALSE, FALSE));
 }
 
 /* Update the definedness state of NAME.  */
@@ -3343,25 +3324,20 @@ lang_update_definedness (const char *name, struct bfd_link_hash_entry *h)
 {
   struct lang_definedness_hash_entry *defentry
     = (struct lang_definedness_hash_entry *)
-    bfd_hash_lookup (&lang_definedness_table, name, FALSE, FALSE);
+    bfd_hash_lookup (&lang_definedness_table, name, TRUE, FALSE);
 
-  /* We don't keep track of symbols not tested with DEFINED.  */
   if (defentry == NULL)
-    return;
+    einfo (_("%P%F: bfd_hash_lookup failed creating symbol %s\n"), name);
 
-  /* If the symbol was already defined, and not from an earlier statement
-     iteration, don't update the definedness iteration, because that'd
-     make the symbol seem defined in the linker script at this point, and
-     it wasn't; it was defined in some object.  If we do anyway, DEFINED
-     would start to yield false before this point and the construct "sym =
-     DEFINED (sym) ? sym : X;" would change sym to X despite being defined
-     in an object.  */
-  if (h->type != bfd_link_hash_undefined
+  /* If the symbol was already defined, and not by a script, then it
+     must be defined by an object file.  */
+  if (!defentry->by_script
+      && h->type != bfd_link_hash_undefined
       && h->type != bfd_link_hash_common
-      && h->type != bfd_link_hash_new
-      && defentry->iteration == -1)
-    return;
+      && h->type != bfd_link_hash_new)
+    defentry->by_object = 1;
 
+  defentry->by_script = 1;
   defentry->iteration = lang_statement_iteration;
 }
 
index e91153ca03e68b1d94e71eae0412eee8871942c3..8c815c67c166eb2369f1444b0d689b9fc538f0a3 100644 (file)
@@ -465,7 +465,9 @@ struct unique_sections
 struct lang_definedness_hash_entry
 {
   struct bfd_hash_entry root;
-  int iteration;
+  unsigned int by_object : 1;
+  unsigned int by_script : 1;
+  unsigned int iteration : 1;
 };
 
 /* Used by place_orphan to keep track of orphan sections and statements.  */
@@ -658,8 +660,7 @@ extern void lang_add_unique
   (const char *);
 extern const char *lang_get_output_target
   (void);
-extern void lang_track_definedness (const char *);
-extern int lang_symbol_definition_iteration (const char *);
+extern struct lang_definedness_hash_entry *lang_symbol_defined (const char *);
 extern void lang_update_definedness
   (const char *, struct bfd_link_hash_entry *);
 
index 8fbd3754bb53f46d6ad07ed5291b6fef90d62f55..4cfe40d3aad1cea7101a67497e731cdb64a17f1e 100644 (file)
@@ -1,3 +1,9 @@
+2014-01-20  Alan Modra  <amodra@gmail.com>
+
+       * ld-scripts/pr14962-2.d,
+       * ld-scripts/pr14962-2.t: New test.
+       * ld-scripts/expr.exp: Run it.
+
 2014-01-15  Alan Modra  <amodra@gmail.com>
 
        * ld-elf/ehdr_start-shared.d: New.
index 0f92d979e43c4ae29e4ea5bf3114d8a0284993b1..ee8da7f3c0456b732a529eade7b1d2bd8c137dc9 100644 (file)
@@ -25,3 +25,4 @@ run_dump_test expr2
 run_dump_test sane1
 run_dump_test assign-loc
 run_dump_test pr14962
+run_dump_test pr14962-2
diff --git a/ld/testsuite/ld-scripts/pr14962-2.d b/ld/testsuite/ld-scripts/pr14962-2.d
new file mode 100644 (file)
index 0000000..5e71433
--- /dev/null
@@ -0,0 +1,10 @@
+#ld: -T pr14962-2.t
+#source: pr14962a.s
+#nm: -n
+#notarget: rx-*-* frv-linux
+
+#...
+0+2000 [AT] _start
+#...
+0+2000 A x
+#pass
diff --git a/ld/testsuite/ld-scripts/pr14962-2.t b/ld/testsuite/ld-scripts/pr14962-2.t
new file mode 100644 (file)
index 0000000..f2c603b
--- /dev/null
@@ -0,0 +1,11 @@
+TOTO = 4096;
+TOTO += 4096;
+
+SECTIONS
+{
+  .text TOTO :
+  {
+    x = ABSOLUTE(TOTO);
+    *(*.text)
+  }
+}