aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlan Modra <amodra@gmail.com>2014-01-20 21:28:42 +1030
committerAlan Modra <amodra@gmail.com>2014-01-20 21:28:42 +1030
commitfa72205cb90527fd34753203993859907a53ead2 (patch)
tree287b960405c90fec23679e85d9a8688e8d5dec17
parent24ef1aa73ed312282bd1a755b3ac94681c9f1544 (diff)
downloadgdb-fa72205cb90527fd34753203993859907a53ead2.zip
gdb-fa72205cb90527fd34753203993859907a53ead2.tar.gz
gdb-fa72205cb90527fd34753203993859907a53ead2.tar.bz2
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 <lang_definedness_table>): 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 <DEFINED>): Update. (fold_name <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.
-rw-r--r--ld/ChangeLog18
-rw-r--r--ld/ldexp.c31
-rw-r--r--ld/ldlang.c74
-rw-r--r--ld/ldlang.h7
-rw-r--r--ld/testsuite/ChangeLog6
-rw-r--r--ld/testsuite/ld-scripts/expr.exp1
-rw-r--r--ld/testsuite/ld-scripts/pr14962-2.d10
-rw-r--r--ld/testsuite/ld-scripts/pr14962-2.t11
8 files changed, 98 insertions, 60 deletions
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 <amodra@gmail.com>
+
+ * 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 <lang_definedness_table>): 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 <DEFINED>): Update.
+ (fold_name <NAME>): Allow self-assignment for absolute symbols
+ defined in a linker script.
+
2014-01-20 Guy Martin <gmsoft@tuxicoman.be>
Alan Modra <amodra@gmail.com>
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 <amodra@gmail.com>
+
+ * ld-scripts/pr14962-2.d,
+ * ld-scripts/pr14962-2.t: New test.
+ * ld-scripts/expr.exp: Run it.
+
2014-01-15 Alan Modra <amodra@gmail.com>
* 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)
+ }
+}