From fa72205cb90527fd34753203993859907a53ead2 Mon Sep 17 00:00:00 2001 From: Alan Modra Date: Mon, 20 Jan 2014 21:28:42 +1030 Subject: Allow self-assignment for absolute symbols defined in a linker script 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 ): 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 ): Update. (fold_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 | 18 +++++++++ ld/ldexp.c | 31 ++++++++++++---- ld/ldlang.c | 74 +++++++++++++------------------------ ld/ldlang.h | 7 ++-- ld/testsuite/ChangeLog | 6 +++ ld/testsuite/ld-scripts/expr.exp | 1 + ld/testsuite/ld-scripts/pr14962-2.d | 10 +++++ ld/testsuite/ld-scripts/pr14962-2.t | 11 ++++++ 8 files changed, 98 insertions(+), 60 deletions(-) create mode 100644 ld/testsuite/ld-scripts/pr14962-2.d create mode 100644 ld/testsuite/ld-scripts/pr14962-2.t diff --git a/ld/ChangeLog b/ld/ChangeLog index a022cba..bc46e5f 100644 --- a/ld/ChangeLog +++ b/ld/ChangeLog @@ -1,3 +1,21 @@ +2014-01-20 Alan Modra + + * 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 ): 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 ): Update. + (fold_name ): Allow self-assignment for absolute symbols + defined in a linker script. + 2014-01-20 Guy Martin Alan Modra diff --git a/ld/ldexp.c b/ld/ldexp.c index 49e7c65..9a529db 100644 --- a/ld/ldexp.c +++ b/ld/ldexp.c @@ -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) diff --git a/ld/ldlang.c b/ld/ldlang.c index f6d713c..9e35527 100644 --- a/ld/ldlang.c +++ b/ld/ldlang.c @@ -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; } diff --git a/ld/ldlang.h b/ld/ldlang.h index e91153c..8c815c6 100644 --- a/ld/ldlang.h +++ b/ld/ldlang.h @@ -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 *); diff --git a/ld/testsuite/ChangeLog b/ld/testsuite/ChangeLog index 8fbd375..4cfe40d 100644 --- a/ld/testsuite/ChangeLog +++ b/ld/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2014-01-20 Alan Modra + + * ld-scripts/pr14962-2.d, + * ld-scripts/pr14962-2.t: New test. + * ld-scripts/expr.exp: Run it. + 2014-01-15 Alan Modra * ld-elf/ehdr_start-shared.d: New. diff --git a/ld/testsuite/ld-scripts/expr.exp b/ld/testsuite/ld-scripts/expr.exp index 0f92d97..ee8da7f 100644 --- a/ld/testsuite/ld-scripts/expr.exp +++ b/ld/testsuite/ld-scripts/expr.exp @@ -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 index 0000000..5e71433 --- /dev/null +++ b/ld/testsuite/ld-scripts/pr14962-2.d @@ -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 index 0000000..f2c603b --- /dev/null +++ b/ld/testsuite/ld-scripts/pr14962-2.t @@ -0,0 +1,11 @@ +TOTO = 4096; +TOTO += 4096; + +SECTIONS +{ + .text TOTO : + { + x = ABSOLUTE(TOTO); + *(*.text) + } +} -- cgit v1.1