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.
This commit is contained in:
Alan Modra 2014-01-20 21:28:42 +10:30
parent 24ef1aa73e
commit fa72205cb9
8 changed files with 98 additions and 60 deletions

View file

@ -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>

View file

@ -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)

View file

@ -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;
}

View file

@ -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 *);

View file

@ -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.

View file

@ -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

View file

@ -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

View file

@ -0,0 +1,11 @@
TOTO = 4096;
TOTO += 4096;
SECTIONS
{
.text TOTO :
{
x = ABSOLUTE(TOTO);
*(*.text)
}
}