* ld.texinfo (Builtin Functions) <DEFINED>: Say that only symbols
authorHans-Peter Nilsson <hp@axis.com>
Sat, 11 Oct 2003 09:16:20 +0000 (09:16 +0000)
committerHans-Peter Nilsson <hp@axis.com>
Sat, 11 Oct 2003 09:16:20 +0000 (09:16 +0000)
defined before the statement using DEFINED yield 1.
* ldexp.c (fold_name) <case DEFINED>: 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) <case etree_assign et al>: 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
ld/ld.texinfo
ld/ldexp.c
ld/ldlang.c
ld/ldlang.h

index 00840ad0b459b9b435eb52e2049a5a383129e76d..7e70ed4af222cf490259e34d62432b4126412df1 100644 (file)
@@ -1,3 +1,32 @@
+2003-10-11  Hans-Peter Nilsson  <hp@bitrange.com>
+
+       * ld.texinfo (Builtin Functions) <DEFINED>: Say that only symbols
+       defined before the statement using DEFINED yield 1.
+       * ldexp.c (fold_name) <case DEFINED>: 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) <case etree_assign et al>: 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  <hongjiu.lu@intel.com>
 
        * scripttempl/elf.sc (__executable_start): Provide.
index b01a10513f7b7907432fbc8ec2e404f9acf9c1f0..1713294cac6191e545be7830e5beeb5a9db354e7 100644 (file)
@@ -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
index cce0cdfc6deba0fee392d4a5aa80cd0b9ec48261..80d79cf1935400a0563917fbeb2bdcc6cd244337 100644 (file)
@@ -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;
index 2d1f5d50823f1c36fc0b871c8b49fab8559ef276..039c7cbf57bc2642073127d8f8689d0979f61052 100644 (file)
@@ -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
index d3e87b128b7372c7563a93e6d3252e1484ecd244..d0195d0563efb6d5073bbeb0401a54c143537a84 100644 (file)
@@ -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