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:
parent
24ef1aa73e
commit
fa72205cb9
8 changed files with 98 additions and 60 deletions
18
ld/ChangeLog
18
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>
|
||||
|
||||
|
|
31
ld/ldexp.c
31
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)
|
||||
|
|
74
ld/ldlang.c
74
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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 *);
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
10
ld/testsuite/ld-scripts/pr14962-2.d
Normal file
10
ld/testsuite/ld-scripts/pr14962-2.d
Normal 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
|
11
ld/testsuite/ld-scripts/pr14962-2.t
Normal file
11
ld/testsuite/ld-scripts/pr14962-2.t
Normal file
|
@ -0,0 +1,11 @@
|
|||
TOTO = 4096;
|
||||
TOTO += 4096;
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
.text TOTO :
|
||||
{
|
||||
x = ABSOLUTE(TOTO);
|
||||
*(*.text)
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue