aboutsummaryrefslogtreecommitdiff
path: root/ld/ldexp.c
diff options
context:
space:
mode:
Diffstat (limited to 'ld/ldexp.c')
-rw-r--r--ld/ldexp.c103
1 files changed, 96 insertions, 7 deletions
diff --git a/ld/ldexp.c b/ld/ldexp.c
index 5c4f8dd..2828933 100644
--- a/ld/ldexp.c
+++ b/ld/ldexp.c
@@ -48,6 +48,19 @@ 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. */
+
+struct definedness_hash_entry
+{
+ struct bfd_hash_entry root;
+ unsigned int by_object : 1;
+ unsigned int by_script : 1;
+ unsigned int iteration : 1;
+};
+
+static struct bfd_hash_table definedness_table;
+
/* Print the string representation of the given token. Surround it
with spaces if INFIX_P is TRUE. */
@@ -244,6 +257,64 @@ new_rel_from_abs (bfd_vma value)
expld.result.section = s;
}
+/* New-function for the definedness hash table. */
+
+static struct bfd_hash_entry *
+definedness_newfunc (struct bfd_hash_entry *entry,
+ struct bfd_hash_table *table ATTRIBUTE_UNUSED,
+ const char *name ATTRIBUTE_UNUSED)
+{
+ struct definedness_hash_entry *ret = (struct definedness_hash_entry *) entry;
+
+ if (ret == NULL)
+ ret = (struct definedness_hash_entry *)
+ bfd_hash_allocate (table, sizeof (struct definedness_hash_entry));
+
+ if (ret == NULL)
+ einfo (_("%P%F: bfd_hash_allocate failed creating symbol %s\n"), name);
+
+ ret->by_object = 0;
+ ret->by_script = 0;
+ ret->iteration = 0;
+ return &ret->root;
+}
+
+/* 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. */
+
+static struct definedness_hash_entry *
+symbol_defined (const char *name)
+{
+ return ((struct definedness_hash_entry *)
+ bfd_hash_lookup (&definedness_table, name, FALSE, FALSE));
+}
+
+/* Update the definedness state of NAME. */
+
+static void
+update_definedness (const char *name, struct bfd_link_hash_entry *h)
+{
+ struct definedness_hash_entry *defentry
+ = (struct definedness_hash_entry *)
+ bfd_hash_lookup (&definedness_table, name, TRUE, FALSE);
+
+ if (defentry == NULL)
+ einfo (_("%P%F: bfd_hash_lookup failed creating symbol %s\n"), name);
+
+ /* 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->by_object = 1;
+
+ defentry->by_script = 1;
+ defentry->iteration = lang_statement_iteration;
+}
+
static void
fold_unary (etree_type *tree)
{
@@ -578,7 +649,7 @@ fold_name (etree_type *tree)
if (expld.phase != lang_first_phase_enum)
{
struct bfd_link_hash_entry *h;
- struct lang_definedness_hash_entry *def;
+ struct definedness_hash_entry *def;
h = bfd_wrapped_link_hash_lookup (link_info.output_bfd,
&link_info,
@@ -588,7 +659,7 @@ fold_name (etree_type *tree)
&& (h->type == bfd_link_hash_defined
|| h->type == bfd_link_hash_defweak
|| h->type == bfd_link_hash_common)
- && ((def = lang_symbol_defined (tree->name.name)) == NULL
+ && ((def = symbol_defined (tree->name.name)) == NULL
|| def->by_object
|| def->iteration == (lang_statement_iteration & 1)));
}
@@ -601,7 +672,7 @@ fold_name (etree_type *tree)
/* 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;
+ struct definedness_hash_entry *def;
h = bfd_wrapped_link_hash_lookup (link_info.output_bfd,
&link_info,
@@ -611,7 +682,7 @@ fold_name (etree_type *tree)
&& (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 = symbol_defined (tree->name.name)) != NULL
&& def->iteration == (lang_statement_iteration & 1)))
expld.assign_name = NULL;
}
@@ -817,11 +888,11 @@ static bfd_boolean
is_sym_value (const etree_type *tree, bfd_vma val)
{
struct bfd_link_hash_entry *h;
- struct lang_definedness_hash_entry *def;
+ struct definedness_hash_entry *def;
return (tree->type.node_class == etree_name
&& tree->type.node_code == NAME
- && (def = lang_symbol_defined (tree->name.name)) != NULL
+ && (def = symbol_defined (tree->name.name)) != NULL
&& def->by_script
&& def->iteration == (lang_statement_iteration & 1)
&& (h = bfd_wrapped_link_hash_lookup (link_info.output_bfd,
@@ -1041,7 +1112,7 @@ exp_fold_tree_1 (etree_type *tree)
/* FIXME: Should we worry if the symbol is already
defined? */
- lang_update_definedness (tree->assign.dst, h);
+ update_definedness (tree->assign.dst, h);
h->type = bfd_link_hash_defined;
h->u.def.value = expld.result.value;
if (expld.result.section == NULL)
@@ -1470,3 +1541,21 @@ align_n (bfd_vma value, bfd_vma align)
value = (value + align - 1) / align;
return value * align;
}
+
+void
+ldexp_init (void)
+{
+ /* The value "13" is ad-hoc, somewhat related to the expected number of
+ assignments in a linker script. */
+ if (!bfd_hash_table_init_n (&definedness_table,
+ definedness_newfunc,
+ sizeof (struct definedness_hash_entry),
+ 13))
+ einfo (_("%P%F: can not create hash table: %E\n"));
+}
+
+void
+ldexp_finish (void)
+{
+ bfd_hash_table_free (&definedness_table);
+}