From 6a84624340dd19ccd927d91d79e0ece135c6d846 Mon Sep 17 00:00:00 2001 From: Alan Modra Date: Mon, 28 Jan 2019 09:59:29 +1030 Subject: [PATCH] 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. --- ld/ChangeLog | 12 +++++++++ ld/ldexp.c | 84 +++++++++++++++++++++++++++++++++--------------------------- ld/ldexp.h | 4 ++- ld/ldlang.c | 9 ++++--- 4 files changed, 66 insertions(+), 43 deletions(-) diff --git a/ld/ChangeLog b/ld/ChangeLog index aa9f250..5bd731f 100644 --- a/ld/ChangeLog +++ b/ld/ChangeLog @@ -1,3 +1,15 @@ +2019-01-28 Alan Modra + + 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 * po/bg.po: Updated Bulgarian translation. diff --git a/ld/ldexp.c b/ld/ldexp.c index a8b833a..60b17ef 100644 --- a/ld/ldexp.c +++ b/ld/ldexp.c @@ -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); - - /* 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); + 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); + } } } - expld.assign_name = NULL; + if (expld.phase != lang_fixed_phase_enum) + expld.assign_name = NULL; } break; diff --git a/ld/ldexp.h b/ld/ldexp.h index 8dc1bf9..71395bc 100644 --- a/ld/ldexp.h +++ b/ld/ldexp.h @@ -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; diff --git a/ld/ldlang.c b/ld/ldlang.c index bddce6d..33f6bda 100644 --- a/ld/ldlang.c +++ b/ld/ldlang.c @@ -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; -- 2.7.4