From 975f8a9e3144e4d3d3f391e907c8bf94b23dc8b6 Mon Sep 17 00:00:00 2001 From: Alan Modra Date: Fri, 18 Sep 2015 09:14:25 +0930 Subject: [PATCH] Delay converting linker script defined symbols from absolute 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. --- ld/ChangeLog | 13 +++++ ld/ldexp.c | 55 ++++++++++++++++++++-- ld/ldexp.h | 9 ++++ ld/ldlang.c | 3 ++ ld/testsuite/ChangeLog | 13 +++++ ld/testsuite/ld-elf/provide-hidden-2.ld | 2 +- ld/testsuite/ld-mips-elf/gp-hidden.sd | 2 +- ld/testsuite/ld-mips-elf/no-shared-1-n32.d | 2 +- ld/testsuite/ld-mips-elf/no-shared-1-n64.d | 2 +- ld/testsuite/ld-mips-elf/no-shared-1-o32.d | 2 +- ld/testsuite/ld-scripts/expr.exp | 7 +++ ld/testsuite/ld-scripts/pr18963.d | 15 ++++++ ld/testsuite/ld-scripts/pr18963.t | 25 ++++++++++ 13 files changed, 142 insertions(+), 8 deletions(-) create mode 100644 ld/testsuite/ld-scripts/pr18963.d create mode 100644 ld/testsuite/ld-scripts/pr18963.t diff --git a/ld/ChangeLog b/ld/ChangeLog index 6369d9977d..96359f5a7c 100644 --- a/ld/ChangeLog +++ b/ld/ChangeLog @@ -1,3 +1,16 @@ +2015-09-18 Alan Modra + + 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 * po/zh_CN.po: Updated simplified Chinese translation. diff --git a/ld/ldexp.c b/ld/ldexp.c index 1140881015..b7b6e6c57c 100644 --- a/ld/ldexp.c +++ b/ld/ldexp.c @@ -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) { diff --git a/ld/ldexp.h b/ld/ldexp.h index f61df6b459..bea804555b 100644 --- a/ld/ldexp.h +++ b/ld/ldexp.h @@ -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 diff --git a/ld/ldlang.c b/ld/ldlang.c index 3d2cc99495..29869812ac 100644 --- a/ld/ldlang.c +++ b/ld/ldlang.c @@ -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 (); diff --git a/ld/testsuite/ChangeLog b/ld/testsuite/ChangeLog index 9629ddaaa5..575d0482c8 100644 --- a/ld/testsuite/ChangeLog +++ b/ld/testsuite/ChangeLog @@ -1,3 +1,16 @@ +2015-09-18 Alan Modra + + 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 * ld-plugin/lto.exp (lto_link_tests): Add a "ld -r" test for diff --git a/ld/testsuite/ld-elf/provide-hidden-2.ld b/ld/testsuite/ld-elf/provide-hidden-2.ld index 0b04c49971..17e526bff9 100644 --- a/ld/testsuite/ld-elf/provide-hidden-2.ld +++ b/ld/testsuite/ld-elf/provide-hidden-2.ld @@ -1,7 +1,7 @@ SECTIONS { . = 0x12300000; - PROVIDE_HIDDEN (foo = . + 0x11100000); + PROVIDE_HIDDEN (foo = ABSOLUTE (.) + 0x11100000); .data : { *(.data) } .got : { *(.got) } .interp : { *(.interp) } diff --git a/ld/testsuite/ld-mips-elf/gp-hidden.sd b/ld/testsuite/ld-mips-elf/gp-hidden.sd index 2e9cfbf8f2..620eb9a5da 100644 --- a/ld/testsuite/ld-mips-elf/gp-hidden.sd +++ b/ld/testsuite/ld-mips-elf/gp-hidden.sd @@ -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 diff --git a/ld/testsuite/ld-mips-elf/no-shared-1-n32.d b/ld/testsuite/ld-mips-elf/no-shared-1-n32.d index 04c466ea43..6a55008868 100644 --- a/ld/testsuite/ld-mips-elf/no-shared-1-n32.d +++ b/ld/testsuite/ld-mips-elf/no-shared-1-n32.d @@ -16,7 +16,7 @@ Disassembly of section \.text: #... Disassembly of section \.data: -00060000 <\.data>: +00060000 .*: 60000: 00068000 .* #... Disassembly of section \.got: diff --git a/ld/testsuite/ld-mips-elf/no-shared-1-n64.d b/ld/testsuite/ld-mips-elf/no-shared-1-n64.d index 0c919217f3..5813b30e36 100644 --- a/ld/testsuite/ld-mips-elf/no-shared-1-n64.d +++ b/ld/testsuite/ld-mips-elf/no-shared-1-n64.d @@ -15,7 +15,7 @@ Disassembly of section \.text: #... Disassembly of section \.data: -0000000000060000 <\.data>: +0000000000060000 .*: 60000: 00000000 .* 60004: 00068000 .* #... diff --git a/ld/testsuite/ld-mips-elf/no-shared-1-o32.d b/ld/testsuite/ld-mips-elf/no-shared-1-o32.d index b67737fd26..53bac9ef6c 100644 --- a/ld/testsuite/ld-mips-elf/no-shared-1-o32.d +++ b/ld/testsuite/ld-mips-elf/no-shared-1-o32.d @@ -15,7 +15,7 @@ Disassembly of section \.text: #... Disassembly of section \.data: -00060000 <\.data>: +00060000 .*: 60000: 00068000 .* #... Disassembly of section \.got: diff --git a/ld/testsuite/ld-scripts/expr.exp b/ld/testsuite/ld-scripts/expr.exp index 85242ed5fb..babbf435b7 100644 --- a/ld/testsuite/ld-scripts/expr.exp +++ b/ld/testsuite/ld-scripts/expr.exp @@ -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 index 0000000000..699db594ac --- /dev/null +++ b/ld/testsuite/ld-scripts/pr18963.d @@ -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 index 0000000000..b0cd7421eb --- /dev/null +++ b/ld/testsuite/ld-scripts/pr18963.t @@ -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");