From 420e579cc4f1252a4e915ad866b49f76bda0c1cd Mon Sep 17 00:00:00 2001 From: Hans-Peter Nilsson Date: Sat, 11 Oct 2003 09:16:20 +0000 Subject: * ld.texinfo (Builtin Functions) : Say that only symbols defined before the statement using DEFINED yield 1. * ldexp.c (fold_name) : In lang_first_phase_enum, call lang_track_definedness on symbol. In subsequent phases, use lang_symbol_definition_iteration and lang_statement_iteration to check whether the symbol was defined before the current statement. (exp_fold_tree) : Call lang_update_definedness before updating symbol type when setting symbol. * ldlang.c (lang_definedness_table): New variable. (lang_definedness_newfunc, lang_track_definedness) (lang_symbol_definition_iteration, lang_update_definedness): New functions. (lang_init): Initialize lang_definedness_table and lang_statement_iteration. (lang_finish): Destroy bfd_hash_table_free. (lang_size_sections): Increment lang_statement_iteration. (lang_do_assignments_1): New function with former lang_do_assignments contents. Change recursive calls to call this function. (lang_do_assignments): Evacuate contents. Increment lang_statement_iteration, then just call lang_do_assignments_1. * ldlang.h (struct lang_definedness_hash_entry) (lang_statement_iteration, lang_track_definedness) (lang_symbol_definition_iteration, lang_update_definedness): Declare. --- ld/ChangeLog | 29 ++++++++++++ ld/ld.texinfo | 3 +- ld/ldexp.c | 12 ++++- ld/ldlang.c | 143 ++++++++++++++++++++++++++++++++++++++++++++++++++++------ ld/ldlang.h | 14 ++++++ 5 files changed, 184 insertions(+), 17 deletions(-) (limited to 'ld') diff --git a/ld/ChangeLog b/ld/ChangeLog index 00840ad..7e70ed4 100644 --- a/ld/ChangeLog +++ b/ld/ChangeLog @@ -1,3 +1,32 @@ +2003-10-11 Hans-Peter Nilsson + + * ld.texinfo (Builtin Functions) : Say that only symbols + defined before the statement using DEFINED yield 1. + * ldexp.c (fold_name) : In lang_first_phase_enum, + call lang_track_definedness on symbol. In subsequent phases, use + lang_symbol_definition_iteration and lang_statement_iteration to + check whether the symbol was defined before the current statement. + (exp_fold_tree) : Call + lang_update_definedness before updating symbol type when setting + symbol. + * ldlang.c (lang_definedness_table): New variable. + (lang_definedness_newfunc, lang_track_definedness) + (lang_symbol_definition_iteration, lang_update_definedness): New + functions. + (lang_init): Initialize lang_definedness_table and + lang_statement_iteration. + (lang_finish): Destroy bfd_hash_table_free. + (lang_size_sections): Increment lang_statement_iteration. + (lang_do_assignments_1): New function with former + lang_do_assignments contents. Change recursive calls to call this + function. + (lang_do_assignments): Evacuate contents. Increment + lang_statement_iteration, then just call lang_do_assignments_1. + * ldlang.h (struct lang_definedness_hash_entry) + (lang_statement_iteration, lang_track_definedness) + (lang_symbol_definition_iteration, lang_update_definedness): + Declare. + 2003-10-09 H.J. Lu * scripttempl/elf.sc (__executable_start): Provide. diff --git a/ld/ld.texinfo b/ld/ld.texinfo index b01a105..1713294 100644 --- a/ld/ld.texinfo +++ b/ld/ld.texinfo @@ -4452,7 +4452,8 @@ evaluation purposes. @kindex DEFINED(@var{symbol}) @cindex symbol defaults Return 1 if @var{symbol} is in the linker global symbol table and is -defined, otherwise return 0. You can use this function to provide +defined before the statement using DEFINED in the script, otherwise +return 0. You can use this function to provide default values for symbols. For example, the following script fragment shows how to set a global symbol @samp{begin} to the first location in the @samp{.text} section---but if a symbol called @samp{begin} already diff --git a/ld/ldexp.c b/ld/ldexp.c index cce0cdf..80d79cf 100644 --- a/ld/ldexp.c +++ b/ld/ldexp.c @@ -485,10 +485,15 @@ fold_name (etree_type *tree, break; case DEFINED: if (allocation_done == lang_first_phase_enum) - result.valid_p = FALSE; + { + lang_track_definedness (tree->name.name); + result.valid_p = FALSE; + } else { struct bfd_link_hash_entry *h; + int def_iteration + = lang_symbol_definition_iteration (tree->name.name); h = bfd_wrapped_link_hash_lookup (output_bfd, &link_info, tree->name.name, @@ -496,7 +501,9 @@ fold_name (etree_type *tree, result.value = (h != NULL && (h->type == bfd_link_hash_defined || h->type == bfd_link_hash_defweak - || h->type == bfd_link_hash_common)); + || h->type == bfd_link_hash_common) + && (def_iteration == lang_statement_iteration + || def_iteration == -1)); result.section = abs_output_section; result.valid_p = TRUE; } @@ -738,6 +745,7 @@ exp_fold_tree (etree_type *tree, { /* FIXME: Should we worry if the symbol is already defined? */ + lang_update_definedness (tree->assign.dst, h); h->type = bfd_link_hash_defined; h->u.def.value = result.value; h->u.def.section = result.section->bfd_section; diff --git a/ld/ldlang.c b/ld/ldlang.c index 2d1f5d5..039c7cb 100644 --- a/ld/ldlang.c +++ b/ld/ldlang.c @@ -60,6 +60,7 @@ static const char *current_target; static const char *output_target; static lang_statement_list_type statement_list; static struct lang_phdr *lang_phdr_list; +static struct bfd_hash_table lang_definedness_table; /* Forward declarations. */ static void exp_init_os (etree_type *); @@ -67,6 +68,8 @@ static bfd_boolean wildcardp (const char *); static lang_input_statement_type *lookup_name (const char *); static bfd_boolean load_symbols (lang_input_statement_type *, lang_statement_list_type *); +static struct bfd_hash_entry *lang_definedness_newfunc + (struct bfd_hash_entry *, struct bfd_hash_table *, const char *); static void insert_undefined (const char *); static void print_statement (lang_statement_union_type *, lang_output_section_statement_type *); @@ -95,6 +98,7 @@ bfd_boolean delete_output_file_on_failure = FALSE; struct lang_nocrossrefs *nocrossref_list; struct unique_sections *unique_section_list; static bfd_boolean ldlang_sysrooted_script = FALSE; +int lang_statement_iteration = 0; etree_type *base; /* Relocation base - or null */ @@ -477,6 +481,19 @@ lang_init (void) lang_output_section_statement_lookup (BFD_ABS_SECTION_NAME); 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. */ + if (bfd_hash_table_init_n (&lang_definedness_table, + lang_definedness_newfunc, 3) != TRUE) + einfo (_("%P%F: out of memory during initialization")); + + /* Callers of exp_fold_tree need to increment this. */ + lang_statement_iteration = 0; } /*---------------------------------------------------------------------- @@ -1867,6 +1884,85 @@ lang_reasonable_defaults (void) #endif } +/* 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 * +lang_definedness_newfunc (struct bfd_hash_entry *entry, + struct bfd_hash_table *table ATTRIBUTE_UNUSED, + const char *name ATTRIBUTE_UNUSED) +{ + struct lang_definedness_hash_entry *ret + = (struct lang_definedness_hash_entry *) entry; + + if (ret == NULL) + ret = (struct lang_definedness_hash_entry *) + bfd_hash_allocate (table, sizeof (struct lang_definedness_hash_entry)); + + if (ret == NULL) + einfo (_("%P%F: bfd_hash_allocate failed creating symbol %s\n"), name); + + ret->iteration = -1; + 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. */ + +int +lang_symbol_definition_iteration (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; +} + +/* Update the definedness state of NAME. */ + +void +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); + + /* We don't keep track of symbols not tested with DEFINED. */ + if (defentry == NULL) + return; + + /* 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 + && h->type != bfd_link_hash_common + && h->type != bfd_link_hash_new + && defentry->iteration == -1) + return; + + defentry->iteration = lang_statement_iteration; +} + /* Add the supplied name to the symbol table as an undefined reference. This is a two step process as the symbol table doesn't even exist at the time the ld command line is processed. First we put the name @@ -3132,6 +3228,9 @@ lang_size_sections { bfd_vma result; + /* Callers of exp_fold_tree need to increment this. */ + lang_statement_iteration++; + exp_data_seg.phase = exp_dataseg_none; result = lang_size_sections_1 (s, output_section_statement, prev, fill, dot, relax, check_regions); @@ -3157,8 +3256,10 @@ lang_size_sections return result; } -bfd_vma -lang_do_assignments +/* Worker function for lang_do_assignments. Recursiveness goes here. */ + +static bfd_vma +lang_do_assignments_1 (lang_statement_union_type *s, lang_output_section_statement_type *output_section_statement, fill_type *fill, @@ -3172,10 +3273,10 @@ lang_do_assignments switch (s->header.type) { case lang_constructors_statement_enum: - dot = lang_do_assignments (constructor_list.head, - output_section_statement, - fill, - dot); + dot = lang_do_assignments_1 (constructor_list.head, + output_section_statement, + fill, + dot); break; case lang_output_section_statement_enum: @@ -3186,8 +3287,8 @@ lang_do_assignments if (os->bfd_section != NULL) { dot = os->bfd_section->vma; - (void) lang_do_assignments (os->children.head, os, - os->fill, dot); + (void) lang_do_assignments_1 (os->children.head, os, + os->fill, dot); dot = os->bfd_section->vma + os->bfd_section->_raw_size / opb; } @@ -3206,9 +3307,9 @@ lang_do_assignments break; case lang_wild_statement_enum: - dot = lang_do_assignments (s->wild_statement.children.head, - output_section_statement, - fill, dot); + dot = lang_do_assignments_1 (s->wild_statement.children.head, + output_section_statement, + fill, dot); break; @@ -3301,9 +3402,9 @@ lang_do_assignments break; case lang_group_statement_enum: - dot = lang_do_assignments (s->group_statement.children.head, - output_section_statement, - fill, dot); + dot = lang_do_assignments_1 (s->group_statement.children.head, + output_section_statement, + fill, dot); break; @@ -3318,6 +3419,18 @@ lang_do_assignments return dot; } +bfd_vma +lang_do_assignments (lang_statement_union_type *s, + lang_output_section_statement_type + *output_section_statement, + fill_type *fill, + bfd_vma dot) +{ + /* Callers of exp_fold_tree need to increment this. */ + lang_statement_iteration++; + lang_do_assignments_1 (s, output_section_statement, fill, dot); +} + /* Fix any .startof. or .sizeof. symbols. When the assemblers see the operator .startof. (section_name), it produces an undefined symbol .startof.section_name. Similarly, when it sees @@ -3445,6 +3558,8 @@ lang_finish (void) } } } + + bfd_hash_table_free (&lang_definedness_table); } /* This is a small function used when we want to ignore errors from diff --git a/ld/ldlang.h b/ld/ldlang.h index d3e87b1..d0195d0 100644 --- a/ld/ldlang.h +++ b/ld/ldlang.h @@ -361,6 +361,14 @@ struct unique_sections { const char *name; }; +/* This structure records symbols for which we need to keep track of + definedness for use in the DEFINED () test. */ + +struct lang_definedness_hash_entry { + struct bfd_hash_entry root; + int iteration; +}; + extern struct unique_sections *unique_section_list; extern lang_output_section_statement_type *abs_output_section; @@ -375,6 +383,8 @@ extern const char *entry_section; extern bfd_boolean entry_from_cmdline; extern lang_statement_list_type file_chain; +extern int lang_statement_iteration; + extern void lang_init (void); extern struct memory_region_struct *lang_memory_region_lookup @@ -517,5 +527,9 @@ 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 void lang_update_definedness + (const char *, struct bfd_link_hash_entry *); #endif -- cgit v1.1