Delay converting linker script defined symbols from absolute
authorAlan Modra <amodra@gmail.com>
Thu, 17 Sep 2015 23:44:25 +0000 (09:14 +0930)
committerAlan Modra <amodra@gmail.com>
Fri, 18 Sep 2015 03:09:16 +0000 (12:39 +0930)
Giving linker script symbols defined outside of output sections a
section-relative value early, leads to them being used in expressions
as if they were defined inside an output section.  This can mean loss
of the section VMA, and wrong results.

ld/
PR ld/18963
* ldexp.h (struct ldexp_control): Add rel_from_abs.
(ldexp_finalize_syms): Declare.
* ldexp.c (new_rel_from_abs): Keep absolute for expressions
outside of output section statements.  Set rel_from_abs.
(make_abs, exp_fold_tree, exp_fold_tree_no_dot): Clear rel_from_abs.
(struct definedness_hash_entry): Add final_sec, and comment.
(update_definedness): Set final_sec.
(set_sym_sections, ldexp_finalize_syms): New functions.
* ldlang.c (lang_process): Call ldexp_finalize_syms.
ld/testsuite
PR ld/18963
* ld-scripts/pr18963.d,
* ld-scripts/pr18963.t: New test.
* ld-scripts/expr.exp: Run it.
* ld-elf/provide-hidden-2.ld: Explicitly make "dot" absolute.
* ld-mips-elf/gp-hidden.sd: Don't care about _gp section.
* ld-mips-elf/no-shared-1-n32.d: Don't care about symbol shown at
start of .data section.
* ld-mips-elf/no-shared-1-n64.d: Likewise.
* ld-mips-elf/no-shared-1-o32.d: Likewise.

13 files changed:
ld/ChangeLog
ld/ldexp.c
ld/ldexp.h
ld/ldlang.c
ld/testsuite/ChangeLog
ld/testsuite/ld-elf/provide-hidden-2.ld
ld/testsuite/ld-mips-elf/gp-hidden.sd
ld/testsuite/ld-mips-elf/no-shared-1-n32.d
ld/testsuite/ld-mips-elf/no-shared-1-n64.d
ld/testsuite/ld-mips-elf/no-shared-1-o32.d
ld/testsuite/ld-scripts/expr.exp
ld/testsuite/ld-scripts/pr18963.d [new file with mode: 0644]
ld/testsuite/ld-scripts/pr18963.t [new file with mode: 0644]

index 6369d9977df270b5c87715ca658f3ebef30e8f6c..96359f5a7c3fe127dfe5ad8c9e405f77e9a611a6 100644 (file)
@@ -1,3 +1,16 @@
+2015-09-18  Alan Modra  <amodra@gmail.com>
+
+       PR ld/18963
+       * ldexp.h (struct ldexp_control): Add rel_from_abs.
+       (ldexp_finalize_syms): Declare.
+       * ldexp.c (new_rel_from_abs): Keep absolute for expressions
+       outside of output section statements.  Set rel_from_abs.
+       (make_abs, exp_fold_tree, exp_fold_tree_no_dot): Clear rel_from_abs.
+       (struct definedness_hash_entry): Add final_sec, and comment.
+       (update_definedness): Set final_sec.
+       (set_sym_sections, ldexp_finalize_syms): New functions.
+       * ldlang.c (lang_process): Call ldexp_finalize_syms.
+
 2015-09-10  Nick Clifton  <nickc@redhat.com>
 
        * po/zh_CN.po: Updated simplified Chinese translation.
index 1140881015dd15e5fda34b702d9ffb3f351c4513..b7b6e6c57c9d0c31fa8d3ca376b652cb8f14f2f3 100644 (file)
@@ -49,13 +49,25 @@ segment_type *segments;
 struct ldexp_control expld;
 
 /* This structure records symbols for which we need to keep track of
-   definedness for use in the DEFINED () test.  */
+   definedness for use in the DEFINED () test.  It is also used in
+   making absolute symbols section relative late in the link.   */
 
 struct definedness_hash_entry
 {
   struct bfd_hash_entry root;
+
+  /* If this symbol was assigned from "dot" outside of an output
+     section statement, the section we'd like it relative to.  */
+  asection *final_sec;
+
+  /* Symbol was defined by an object file.  */
   unsigned int by_object : 1;
+
+  /* Symbols was defined by a script.  */
   unsigned int by_script : 1;
+
+  /* Low bit of iteration count.  Symbols with matching iteration have
+     been defined in this pass over the script.  */
   unsigned int iteration : 1;
 };
 
@@ -174,6 +186,7 @@ make_abs (void)
   if (expld.result.section != NULL)
     expld.result.value += expld.result.section->vma;
   expld.result.section = bfd_abs_section_ptr;
+  expld.rel_from_abs = FALSE;
 }
 
 static void
@@ -249,8 +262,7 @@ new_rel_from_abs (bfd_vma value)
 {
   asection *s = expld.section;
 
-  if (s == bfd_abs_section_ptr && expld.phase == lang_final_phase_enum)
-    s = section_for_dot ();
+  expld.rel_from_abs = TRUE;
   expld.result.valid_p = TRUE;
   expld.result.value = value - s->vma;
   expld.result.str = NULL;
@@ -322,6 +334,11 @@ update_definedness (const char *name, struct bfd_link_hash_entry *h)
 
   defentry->by_script = 1;
   defentry->iteration = lang_statement_iteration;
+  defentry->final_sec = bfd_abs_section_ptr;
+  if (expld.phase == lang_final_phase_enum
+      && expld.rel_from_abs
+      && expld.result.section == bfd_abs_section_ptr)
+    defentry->final_sec = section_for_dot ();
   return ret;
 }
 
@@ -1189,6 +1206,7 @@ exp_fold_tree_1 (etree_type *tree)
 void
 exp_fold_tree (etree_type *tree, asection *current_section, bfd_vma *dotp)
 {
+  expld.rel_from_abs = FALSE;
   expld.dot = *dotp;
   expld.dotp = dotp;
   expld.section = current_section;
@@ -1198,6 +1216,7 @@ exp_fold_tree (etree_type *tree, asection *current_section, bfd_vma *dotp)
 void
 exp_fold_tree_no_dot (etree_type *tree)
 {
+  expld.rel_from_abs = FALSE;
   expld.dot = 0;
   expld.dotp = NULL;
   expld.section = bfd_abs_section_ptr;
@@ -1581,6 +1600,36 @@ ldexp_init (void)
     einfo (_("%P%F: can not create hash table: %E\n"));
 }
 
+/* Convert absolute symbols defined by a script from "dot" (also
+   SEGMENT_START or ORIGIN) outside of an output section statement,
+   to section relative.  */
+
+static bfd_boolean
+set_sym_sections (struct bfd_hash_entry *bh, void *inf ATTRIBUTE_UNUSED)
+{
+  struct definedness_hash_entry *def = (struct definedness_hash_entry *) bh;
+  if (def->final_sec != bfd_abs_section_ptr)
+    {
+      struct bfd_link_hash_entry *h;
+      h = bfd_link_hash_lookup (link_info.hash, bh->string,
+                               FALSE, FALSE, TRUE);
+      if (h != NULL
+         && h->type == bfd_link_hash_defined
+         && h->u.def.section == bfd_abs_section_ptr)
+       {
+         h->u.def.value -= def->final_sec->vma;
+         h->u.def.section = def->final_sec;
+       }
+    }
+  return TRUE;
+}
+
+void
+ldexp_finalize_syms (void)
+{
+  bfd_hash_traverse (&definedness_table, set_sym_sections, NULL);
+}
+
 void
 ldexp_finish (void)
 {
index f61df6b45931b684624b5e58b4d737bee749caab..bea804555b355a051aa9431fc1e405338c031462 100644 (file)
@@ -138,6 +138,14 @@ struct ldexp_control {
 
   /* Principally used for diagnostics.  */
   bfd_boolean assigning_to_dot;
+
+  /* Set if the current expression used "dot", SEGMENT_START or
+     ORIGIN, but not ABSOLUTE or combined symbols in a way that forces
+     an absolute result.  Used in tracking symbols assigned from dot
+     outside of output section statements, in order to later convert
+     them from absolute.  */
+  bfd_boolean rel_from_abs;
+
   /* If evaluating an assignment, the destination.  Cleared if an
      etree_name NAME matches this, to signal a self-assignment.
      Note that an etree_name DEFINED does not clear this field, nor
@@ -222,6 +230,7 @@ fill_type *exp_get_fill
 bfd_vma exp_get_abs_int
   (etree_type *, int, char *);
 void ldexp_init (void);
+void ldexp_finalize_syms (void);
 void ldexp_finish (void);
 
 #endif
index 3d2cc99495e169598e24e15d29f5c381e2cf7335..29869812acff0b56b544ab84ebb8232230b3fa6b 100644 (file)
@@ -6882,6 +6882,9 @@ lang_process (void)
 
   ldemul_finish ();
 
+  /* Convert absolute symbols to section relative.  */
+  ldexp_finalize_syms ();
+
   /* Make sure that the section addresses make sense.  */
   if (command_line.check_section_addresses)
     lang_check_section_addresses ();
index 9629ddaaa58c119b4fb90f44c2a7309acd8a79df..575d0482c85ddb05b92efd9032383c288bc0fa18 100644 (file)
@@ -1,3 +1,16 @@
+2015-09-18  Alan Modra  <amodra@gmail.com>
+
+       PR ld/18963
+       * ld-scripts/pr18963.d,
+       * ld-scripts/pr18963.t: New test.
+       * ld-scripts/expr.exp: Run it.
+       * ld-elf/provide-hidden-2.ld: Explicitly make "dot" absolute.
+       * ld-mips-elf/gp-hidden.sd: Don't care about _gp section.
+       * ld-mips-elf/no-shared-1-n32.d: Don't care about symbol shown at
+       start of .data section.
+       * ld-mips-elf/no-shared-1-n64.d: Likewise.
+       * ld-mips-elf/no-shared-1-o32.d: Likewise.
+
 2015-09-11  H.J. Lu  <hongjiu.lu@intel.com>
 
        * ld-plugin/lto.exp (lto_link_tests): Add a "ld -r" test for
index 0b04c49971dd708c2e7b4e373814bed1798aea98..17e526bff9b7a3b0ab7d263c2fe8161c7ebad67c 100644 (file)
@@ -1,7 +1,7 @@
 SECTIONS
 {
   . = 0x12300000;
-  PROVIDE_HIDDEN (foo = . + 0x11100000);
+  PROVIDE_HIDDEN (foo = ABSOLUTE (.) + 0x11100000);
   .data : { *(.data) }
   .got : { *(.got) }
   .interp : { *(.interp) }
index 2e9cfbf8f2de5183b1f2f130dda177db34cdd047..620eb9a5daa7d01d4777b60d0f7859704ade4c50 100644 (file)
@@ -5,5 +5,5 @@ Symbol table '.dynsym' contains [0-9]+ entries:
 Symbol table '.symtab' contains [0-9]+ entries:
  * Num: * Value * Size * Type * Bind * Vis * Ndx * Name
 #...
- * [0-9a-f]+: * [0-9a-f]+ * 0 * NOTYPE * LOCAL * DEFAULT * ABS * _gp
+ * [0-9a-f]+: * [0-9a-f]+ * 0 * NOTYPE * LOCAL * DEFAULT .* _gp
 #pass
index 04c466ea431d5d11ddd77db3eff17fcd76c3ff35..6a550088683b5e28909f3d64fcfbb7fc239fdb1a 100644 (file)
@@ -16,7 +16,7 @@ Disassembly of section \.text:
 #...
 Disassembly of section \.data:
 
-00060000 <\.data>:
+00060000 .*:
    60000:      00068000        .*
 #...
 Disassembly of section \.got:
index 0c919217f3cb7606a1226464f344be61ef8a456f..5813b30e36310abe209c5b1362cfc81cccad3450 100644 (file)
@@ -15,7 +15,7 @@ Disassembly of section \.text:
 #...
 Disassembly of section \.data:
 
-0000000000060000 <\.data>:
+0000000000060000 .*:
    60000:      00000000        .*
    60004:      00068000        .*
 #...
index b67737fd266a2ebdd38626026d8cc20edbc2cb1a..53bac9ef6c8e536516e11782eec19e9aecde13c5 100644 (file)
@@ -15,7 +15,7 @@ Disassembly of section \.text:
 #...
 Disassembly of section \.data:
 
-00060000 <\.data>:
+00060000 .*:
    60000:      00068000        .*
 #...
 Disassembly of section \.got:
index 85242ed5fb4285af9670fe2dfb55fb4b9a709008..babbf435b79ba8f4b167aa6f3c781763be9e5bdb 100644 (file)
@@ -25,3 +25,10 @@ run_dump_test sane1
 run_dump_test assign-loc
 run_dump_test pr14962
 run_dump_test pr14962-2
+
+set old_ldflags $LDFLAGS
+if { [istarget spu*-*-*] } {
+    set LDFLAGS "$LDFLAGS --no-overlays --local-store 0:0"
+}
+run_dump_test pr18963
+set LDFLAGS $old_ldflags
diff --git a/ld/testsuite/ld-scripts/pr18963.d b/ld/testsuite/ld-scripts/pr18963.d
new file mode 100644 (file)
index 0000000..699db59
--- /dev/null
@@ -0,0 +1,15 @@
+# source: data.s
+# ld: -T pr18963.t
+# nm: -B -n
+
+#...
+0+70000 A D
+#...
+0+70000 A E
+#...
+0+80000 T A
+#...
+0+90000 T B
+#...
+0+a0000 D C
+#pass
diff --git a/ld/testsuite/ld-scripts/pr18963.t b/ld/testsuite/ld-scripts/pr18963.t
new file mode 100644 (file)
index 0000000..b0cd742
--- /dev/null
@@ -0,0 +1,25 @@
+SECTIONS
+{
+  . = 0x80000;
+  A = .;
+  .text :
+  {
+    _start = .;
+    . = 0x10000;
+  }
+  B = .;
+  .data :
+  {
+    . = 0x10000;
+  }
+  C = .;
+  .bss :
+  {
+    . = 0x10000;
+  }
+  D = A - C + B;
+  E = A + B - C;
+  /DISCARD/ : {*(*)}
+}
+
+ASSERT(D == E, "Addition is not commutative");