PR24008, Wrong value of ternary expression in map file

PR 24008
	* ldexp.h (lang_phase_type): Add lang_fixed_phase_enum.
	* ldexp.c (fold_name): Move expld.assign_name check later to
	avoid an extra lookup.
	(exp_fold_tree_1): When lang_fixed_phase_enum, don't change symbol
	values, and don't clear expld.assign_name.
	* ldlang.c (lang_map): Set expld.phase to lang_fixed_phase_enum.
	(print_assignment): Resolve entire assignment expression.
	Don't access symbol u.def unless symbol is defined.
This commit is contained in:
Alan Modra 2019-01-28 09:59:29 +10:30
parent e044973b0c
commit 6a84624340
4 changed files with 65 additions and 42 deletions

View File

@ -1,3 +1,15 @@
2019-01-28 Alan Modra <amodra@gmail.com>
PR 24008
* ldexp.h (lang_phase_type): Add lang_fixed_phase_enum.
* ldexp.c (fold_name): Move expld.assign_name check later to
avoid an extra lookup.
(exp_fold_tree_1): When lang_fixed_phase_enum, don't change symbol
values, and don't clear expld.assign_name.
* ldlang.c (lang_map): Set expld.phase to lang_fixed_phase_enum.
(print_assignment): Resolve entire assignment expression.
Don't access symbol u.def unless symbol is defined.
2019-01-25 Nick Clifton <nickc@redhat.com>
* po/bg.po: Updated Bulgarian translation.

View File

@ -720,23 +720,6 @@ fold_name (etree_type *tree)
break;
case NAME:
if (expld.assign_name != NULL
&& strcmp (expld.assign_name, tree->name.name) == 0)
{
/* Self-assignment is only allowed for absolute symbols
defined in a linker script. */
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 = symbol_defined (tree->name.name)) != NULL
&& def->iteration == (lang_statement_iteration & 255)))
expld.assign_name = NULL;
}
if (tree->name.name[0] == '.' && tree->name.name[1] == 0)
new_rel_from_abs (expld.dot);
else
@ -787,6 +770,18 @@ fold_name (etree_type *tree)
expld.assign_src = h;
else
expld.assign_src = (struct bfd_link_hash_entry *) - 1;
/* Self-assignment is only allowed for absolute symbols
defined in a linker script. */
if (expld.assign_name != NULL
&& strcmp (expld.assign_name, tree->name.name) == 0
&& !(h != NULL
&& (h->type == bfd_link_hash_defined
|| h->type == bfd_link_hash_defweak)
&& h->u.def.section == bfd_abs_section_ptr
&& (def = symbol_defined (tree->name.name)) != NULL
&& def->iteration == (lang_statement_iteration & 255)))
expld.assign_name = NULL;
}
break;
@ -1158,7 +1153,8 @@ exp_fold_tree_1 (etree_type *tree)
converted to absolute values, as is required by many
expressions, until final section sizing is complete. */
if (expld.phase == lang_final_phase_enum
|| expld.assign_name != NULL)
|| expld.phase == lang_fixed_phase_enum
|| expld.assign_name != NULL)
{
if (tree->type.node_class == etree_provide)
tree->type.node_class = etree_provided;
@ -1199,28 +1195,40 @@ exp_fold_tree_1 (etree_type *tree)
(&link_info, h, link_info.output_bfd,
expld.result.section, expld.result.value);
}
h->type = bfd_link_hash_defined;
h->u.def.value = expld.result.value;
h->u.def.section = expld.result.section;
h->linker_def = ! tree->assign.type.lineno;
h->ldscript_def = 1;
h->rel_from_abs = expld.rel_from_abs;
if (tree->assign.hidden)
bfd_link_hide_symbol (link_info.output_bfd,
&link_info, h);
if (expld.phase == lang_fixed_phase_enum)
{
if (h->type == bfd_link_hash_defined)
{
expld.result.value = h->u.def.value;
expld.result.section = h->u.def.section;
}
}
else
{
h->type = bfd_link_hash_defined;
h->u.def.value = expld.result.value;
h->u.def.section = expld.result.section;
h->linker_def = ! tree->assign.type.lineno;
h->ldscript_def = 1;
h->rel_from_abs = expld.rel_from_abs;
if (tree->assign.hidden)
bfd_link_hide_symbol (link_info.output_bfd,
&link_info, h);
/* Copy the symbol type if this is an expression only
referencing a single symbol. (If the expression
contains ternary conditions, ignoring symbols on
false branches.) */
if (expld.assign_src != NULL
&& (expld.assign_src
!= (struct bfd_link_hash_entry *) -1))
bfd_copy_link_hash_symbol_type (link_info.output_bfd, h,
expld.assign_src);
/* Copy the symbol type if this is an expression only
referencing a single symbol. (If the expression
contains ternary conditions, ignoring symbols on
false branches.) */
if (expld.assign_src != NULL
&& (expld.assign_src
!= (struct bfd_link_hash_entry *) -1))
bfd_copy_link_hash_symbol_type (link_info.output_bfd,
h, expld.assign_src);
}
}
}
expld.assign_name = NULL;
if (expld.phase != lang_fixed_phase_enum)
expld.assign_name = NULL;
}
break;

View File

@ -106,7 +106,9 @@ typedef enum
/* During assignment of symbol values when relaxation in progress. */
lang_assigning_phase_enum,
/* Final assignment of symbol values. */
lang_final_phase_enum
lang_final_phase_enum,
/* Run after symbol values have been fixed, for lang_map. */
lang_fixed_phase_enum
} lang_phase_type;
union lang_statement_union;

View File

@ -2315,6 +2315,7 @@ lang_map (void)
obstack_begin (&map_obstack, 1000);
bfd_link_hash_traverse (link_info.hash, sort_def_symbol, 0);
}
expld.phase = lang_fixed_phase_enum;
lang_statement_iteration++;
print_statements ();
@ -4244,9 +4245,7 @@ print_assignment (lang_assignment_statement_type *assignment,
const char *dst = assignment->exp->assign.dst;
is_dot = (dst[0] == '.' && dst[1] == 0);
if (!is_dot)
expld.assign_name = dst;
tree = assignment->exp->assign.src;
tree = assignment->exp;
}
osec = output_section->bfd_section;
@ -4281,7 +4280,9 @@ print_assignment (lang_assignment_statement_type *assignment,
h = bfd_link_hash_lookup (link_info.hash, assignment->exp->assign.dst,
FALSE, FALSE, TRUE);
if (h)
if (h != NULL
&& (h->type == bfd_link_hash_defined
|| h->type == bfd_link_hash_defweak))
{
value = h->u.def.value;
value += h->u.def.section->output_section->vma;