diff options
author | H.J. Lu <hjl.tools@gmail.com> | 2018-01-19 03:23:56 -0800 |
---|---|---|
committer | H.J. Lu <hjl.tools@gmail.com> | 2018-01-19 03:23:56 -0800 |
commit | 4ba8500d63991518aefef86474576de565e00237 (patch) | |
tree | 143d752c8f0244812621ee2a09cd2bbb5b08071c /ld/ldexp.c | |
parent | b8cc0ceb40868b1d4d42854e4d89372aa5aef921 (diff) | |
parent | c935ff02abfbf5bb80aa043340f7d101aac262f2 (diff) | |
download | gdb-users/hjl/linux/release/2.29.51.0.1.zip gdb-users/hjl/linux/release/2.29.51.0.1.tar.gz gdb-users/hjl/linux/release/2.29.51.0.1.tar.bz2 |
Merge remote-tracking branch 'origin/users/hjl/linux/master' into users/hjl/linux/appliedusers/hjl/linux/release/2.29.51.0.1users/hjl/linux/applied
Diffstat (limited to 'ld/ldexp.c')
-rw-r--r-- | ld/ldexp.c | 387 |
1 files changed, 187 insertions, 200 deletions
@@ -1,5 +1,5 @@ /* This module handles expression trees. - Copyright (C) 1991-2017 Free Software Foundation, Inc. + Copyright (C) 1991-2018 Free Software Foundation, Inc. Written by Steve Chamberlain of Cygnus Support <sac@cygnus.com>. This file is part of the GNU Binutils. @@ -60,15 +60,12 @@ struct definedness_hash_entry section statement, the section we'd like it relative to. */ asection *final_sec; + /* Low bits of iteration count. Symbols with matching iteration have + been defined in this pass over the script. */ + unsigned int iteration : 8; + /* Symbol was defined by an object file. */ unsigned int by_object : 1; - - /* Symbols was defined by a script. */ - unsigned int by_script : 1; - - /* Low bit of iteration count. Symbols with matching iteration have - been defined in this pass over the script. */ - unsigned int iteration : 1; }; static struct bfd_hash_table definedness_table; @@ -286,7 +283,6 @@ definedness_newfunc (struct bfd_hash_entry *entry, einfo (_("%P%F: bfd_hash_allocate failed creating symbol %s\n"), name); ret->by_object = 0; - ret->by_script = 0; ret->iteration = 0; return &ret->root; } @@ -320,7 +316,7 @@ update_definedness (const char *name, struct bfd_link_hash_entry *h) /* If the symbol was already defined, and not by a script, then it must be defined by an object file or by the linker target code. */ ret = TRUE; - if (!defentry->by_script + if (!h->ldscript_def && (h->type == bfd_link_hash_defined || h->type == bfd_link_hash_defweak || h->type == bfd_link_hash_common)) @@ -332,7 +328,6 @@ update_definedness (const char *name, struct bfd_link_hash_entry *h) ret = FALSE; } - defentry->by_script = 1; defentry->iteration = lang_statement_iteration; defentry->final_sec = bfd_abs_section_ptr; if (expld.phase == lang_final_phase_enum @@ -343,6 +338,30 @@ update_definedness (const char *name, struct bfd_link_hash_entry *h) } static void +fold_segment_end (seg_align_type *seg) +{ + if (expld.phase == lang_first_phase_enum + || expld.section != bfd_abs_section_ptr) + { + expld.result.valid_p = FALSE; + } + else if (seg->phase == exp_seg_align_seen + || seg->phase == exp_seg_relro_seen) + { + seg->phase = exp_seg_end_seen; + seg->end = expld.result.value; + } + else if (seg->phase == exp_seg_done + || seg->phase == exp_seg_adjust + || seg->phase == exp_seg_relro_adjust) + { + /* OK. */ + } + else + expld.result.valid_p = FALSE; +} + +static void fold_unary (etree_type *tree) { exp_fold_tree_1 (tree->unary.child); @@ -389,25 +408,7 @@ fold_unary (etree_type *tree) break; case DATA_SEGMENT_END: - if (expld.phase == lang_first_phase_enum - || expld.section != bfd_abs_section_ptr) - { - expld.result.valid_p = FALSE; - } - else if (expld.dataseg.phase == exp_dataseg_align_seen - || expld.dataseg.phase == exp_dataseg_relro_seen) - { - expld.dataseg.phase = exp_dataseg_end_seen; - expld.dataseg.end = expld.result.value; - } - else if (expld.dataseg.phase == exp_dataseg_done - || expld.dataseg.phase == exp_dataseg_adjust - || expld.dataseg.phase == exp_dataseg_relro_adjust) - { - /* OK. */ - } - else - expld.result.valid_p = FALSE; + fold_segment_end (&expld.dataseg); break; default: @@ -444,6 +445,84 @@ arith_result_section (const etree_value_type *lhs) } static void +fold_segment_align (seg_align_type *seg, etree_value_type *lhs) +{ + seg->relro = exp_seg_relro_start; + if (expld.phase == lang_first_phase_enum + || expld.section != bfd_abs_section_ptr) + expld.result.valid_p = FALSE; + else + { + bfd_vma maxpage = lhs->value; + bfd_vma commonpage = expld.result.value; + + expld.result.value = align_n (expld.dot, maxpage); + if (seg->phase == exp_seg_relro_adjust) + expld.result.value = seg->base; + else if (seg->phase == exp_seg_adjust) + { + if (commonpage < maxpage) + expld.result.value += ((expld.dot + commonpage - 1) + & (maxpage - commonpage)); + } + else + { + expld.result.value += expld.dot & (maxpage - 1); + if (seg->phase == exp_seg_done) + { + /* OK. */ + } + else if (seg->phase == exp_seg_none) + { + seg->phase = exp_seg_align_seen; + seg->base = expld.result.value; + seg->pagesize = commonpage; + seg->maxpagesize = maxpage; + seg->relro_end = 0; + } + else + expld.result.valid_p = FALSE; + } + } +} + +static void +fold_segment_relro_end (seg_align_type *seg, etree_value_type *lhs) +{ + /* Operands swapped! XXX_SEGMENT_RELRO_END(offset,exp) has offset + in expld.result and exp in lhs. */ + seg->relro = exp_seg_relro_end; + seg->relro_offset = expld.result.value; + if (expld.phase == lang_first_phase_enum + || expld.section != bfd_abs_section_ptr) + expld.result.valid_p = FALSE; + else if (seg->phase == exp_seg_align_seen + || seg->phase == exp_seg_adjust + || seg->phase == exp_seg_relro_adjust + || seg->phase == exp_seg_done) + { + if (seg->phase == exp_seg_align_seen + || seg->phase == exp_seg_relro_adjust) + seg->relro_end = lhs->value + expld.result.value; + + if (seg->phase == exp_seg_relro_adjust + && (seg->relro_end & (seg->pagesize - 1))) + { + seg->relro_end += seg->pagesize - 1; + seg->relro_end &= ~(seg->pagesize - 1); + expld.result.value = seg->relro_end - expld.result.value; + } + else + expld.result.value = lhs->value; + + if (seg->phase == exp_seg_align_seen) + seg->phase = exp_seg_relro_seen; + } + else + expld.result.valid_p = FALSE; +} + +static void fold_binary (etree_type *tree) { etree_value_type lhs; @@ -573,79 +652,11 @@ fold_binary (etree_type *tree) break; case DATA_SEGMENT_ALIGN: - expld.dataseg.relro = exp_dataseg_relro_start; - if (expld.phase == lang_first_phase_enum - || expld.section != bfd_abs_section_ptr) - expld.result.valid_p = FALSE; - else - { - bfd_vma maxpage = lhs.value; - bfd_vma commonpage = expld.result.value; - - expld.result.value = align_n (expld.dot, maxpage); - if (expld.dataseg.phase == exp_dataseg_relro_adjust) - expld.result.value = expld.dataseg.base; - else if (expld.dataseg.phase == exp_dataseg_adjust) - { - if (commonpage < maxpage) - expld.result.value += ((expld.dot + commonpage - 1) - & (maxpage - commonpage)); - } - else - { - expld.result.value += expld.dot & (maxpage - 1); - if (expld.dataseg.phase == exp_dataseg_done) - { - /* OK. */ - } - else if (expld.dataseg.phase == exp_dataseg_none) - { - expld.dataseg.phase = exp_dataseg_align_seen; - expld.dataseg.base = expld.result.value; - expld.dataseg.pagesize = commonpage; - expld.dataseg.maxpagesize = maxpage; - expld.dataseg.relro_end = 0; - } - else - expld.result.valid_p = FALSE; - } - } + fold_segment_align (&expld.dataseg, &lhs); break; case DATA_SEGMENT_RELRO_END: - /* Operands swapped! DATA_SEGMENT_RELRO_END(offset,exp) - has offset in expld.result and exp in lhs. */ - expld.dataseg.relro = exp_dataseg_relro_end; - expld.dataseg.relro_offset = expld.result.value; - if (expld.phase == lang_first_phase_enum - || expld.section != bfd_abs_section_ptr) - expld.result.valid_p = FALSE; - else if (expld.dataseg.phase == exp_dataseg_align_seen - || expld.dataseg.phase == exp_dataseg_adjust - || expld.dataseg.phase == exp_dataseg_relro_adjust - || expld.dataseg.phase == exp_dataseg_done) - { - if (expld.dataseg.phase == exp_dataseg_align_seen - || expld.dataseg.phase == exp_dataseg_relro_adjust) - expld.dataseg.relro_end = lhs.value + expld.result.value; - - if (expld.dataseg.phase == exp_dataseg_relro_adjust - && (expld.dataseg.relro_end - & (expld.dataseg.pagesize - 1))) - { - expld.dataseg.relro_end += expld.dataseg.pagesize - 1; - expld.dataseg.relro_end &= ~(expld.dataseg.pagesize - 1); - expld.result.value = (expld.dataseg.relro_end - - expld.result.value); - } - else - expld.result.value = lhs.value; - - if (expld.dataseg.phase == exp_dataseg_align_seen) - expld.dataseg.phase = exp_dataseg_relro_seen; - } - else - expld.result.valid_p = FALSE; + fold_segment_relro_end (&expld.dataseg, &lhs); break; default: @@ -657,7 +668,10 @@ fold_binary (etree_type *tree) static void fold_trinary (etree_type *tree) { + struct bfd_link_hash_entry *save = expld.assign_src; + exp_fold_tree_1 (tree->trinary.cond); + expld.assign_src = save; if (expld.result.valid_p) exp_fold_tree_1 (expld.result.value ? tree->trinary.lhs @@ -667,6 +681,9 @@ fold_trinary (etree_type *tree) static void fold_name (etree_type *tree) { + struct bfd_link_hash_entry *h; + struct definedness_hash_entry *def; + memset (&expld.result, 0, sizeof (expld.result)); switch (tree->type.node_code) @@ -684,23 +701,18 @@ fold_name (etree_type *tree) break; case DEFINED: - if (expld.phase != lang_first_phase_enum) - { - struct bfd_link_hash_entry *h; - struct definedness_hash_entry *def; - - h = bfd_wrapped_link_hash_lookup (link_info.output_bfd, - &link_info, - tree->name.name, - FALSE, FALSE, TRUE); - new_number (h != NULL - && (h->type == bfd_link_hash_defined - || h->type == bfd_link_hash_defweak - || h->type == bfd_link_hash_common) - && ((def = symbol_defined (tree->name.name)) == NULL - || def->by_object - || def->iteration == (lang_statement_iteration & 1))); - } + h = bfd_wrapped_link_hash_lookup (link_info.output_bfd, + &link_info, + tree->name.name, + FALSE, FALSE, TRUE); + new_number (h != NULL + && (h->type == bfd_link_hash_defined + || h->type == bfd_link_hash_defweak + || h->type == bfd_link_hash_common) + && (!h->ldscript_def + || (def = symbol_defined (tree->name.name)) == NULL + || def->by_object + || def->iteration == (lang_statement_iteration & 255))); break; case NAME: @@ -709,9 +721,6 @@ fold_name (etree_type *tree) { /* Self-assignment is only allowed for absolute symbols defined in a linker script. */ - struct bfd_link_hash_entry *h; - struct definedness_hash_entry *def; - h = bfd_wrapped_link_hash_lookup (link_info.output_bfd, &link_info, tree->name.name, @@ -721,17 +730,13 @@ fold_name (etree_type *tree) || 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 & 1))) + && def->iteration == (lang_statement_iteration & 255))) expld.assign_name = NULL; } - if (expld.phase == lang_first_phase_enum) - ; - else if (tree->name.name[0] == '.' && tree->name.name[1] == 0) + if (tree->name.name[0] == '.' && tree->name.name[1] == 0) new_rel_from_abs (expld.dot); else { - struct bfd_link_hash_entry *h; - h = bfd_wrapped_link_hash_lookup (link_info.output_bfd, &link_info, tree->name.name, @@ -746,7 +751,7 @@ fold_name (etree_type *tree) output_section = h->u.def.section->output_section; if (output_section == NULL) { - if (expld.phase == lang_mark_phase_enum) + if (expld.phase <= lang_mark_phase_enum) new_rel (h->u.def.value, h->u.def.section); else einfo (_("%X%S: unresolvable symbol `%s'" @@ -774,6 +779,10 @@ fold_name (etree_type *tree) if (h->u.undef.next == NULL && h != link_info.hash->undefs_tail) bfd_link_add_undef (link_info.hash, h); } + if (expld.assign_src == NULL) + expld.assign_src = h; + else + expld.assign_src = (struct bfd_link_hash_entry *) 0 - 1; } break; @@ -934,12 +943,12 @@ is_sym_value (const etree_type *tree, bfd_vma val) return (tree->type.node_class == etree_name && tree->type.node_code == NAME && (def = symbol_defined (tree->name.name)) != NULL - && def->by_script - && def->iteration == (lang_statement_iteration & 1) + && def->iteration == (lang_statement_iteration & 255) && (h = bfd_wrapped_link_hash_lookup (link_info.output_bfd, &link_info, tree->name.name, FALSE, FALSE, TRUE)) != NULL + && h->ldscript_def && h->type == bfd_link_hash_defined && h->u.def.section == bfd_abs_section_ptr && h->u.def.value == val); @@ -985,19 +994,6 @@ is_align_conditional (const etree_type *tree) return FALSE; } -/* Subroutine of exp_fold_tree_1 for copying a symbol type. */ - -static void -try_copy_symbol_type (struct bfd_link_hash_entry *h, etree_type *src) -{ - struct bfd_link_hash_entry *hsrc; - - hsrc = bfd_link_hash_lookup (link_info.hash, src->name.name, - FALSE, FALSE, TRUE); - if (hsrc != NULL) - bfd_copy_link_hash_symbol_type (link_info.output_bfd, h, hsrc); -} - static void exp_fold_tree_1 (etree_type *tree) { @@ -1146,6 +1142,7 @@ exp_fold_tree_1 (etree_type *tree) } expld.assign_name = tree->assign.dst; + expld.assign_src = NULL; exp_fold_tree_1 (tree->assign.src); /* expld.assign_name remaining equal to tree->assign.dst below indicates the evaluation of tree->assign.src did @@ -1156,13 +1153,12 @@ exp_fold_tree_1 (etree_type *tree) 2) Section relative symbol values cannot be correctly converted to absolute values, as is required by many expressions, until final section sizing is complete. */ - if ((expld.result.valid_p - && (expld.phase == lang_final_phase_enum - || expld.assign_name != NULL)) - || (expld.phase <= lang_mark_phase_enum - && tree->type.node_class == etree_assign - && tree->assign.defsym)) + if (expld.phase == lang_final_phase_enum + || expld.assign_name != NULL) { + if (tree->type.node_class == etree_provide) + tree->type.node_class = etree_provided; + if (h == NULL) { h = bfd_link_hash_lookup (link_info.hash, tree->assign.dst, @@ -1172,57 +1168,50 @@ exp_fold_tree_1 (etree_type *tree) tree->assign.dst); } - if (expld.result.section == NULL) - expld.result.section = expld.section; - if (!update_definedness (tree->assign.dst, h) && 0) - { - /* Symbol was already defined. For now this error - is disabled because it causes failures in the ld - testsuite: ld-elf/var1, ld-scripts/defined5, and - ld-scripts/pr14962. Some of these no doubt - reflect scripts used in the wild. */ - (*link_info.callbacks->multiple_definition) - (&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; - if (tree->type.node_class == etree_provide) - tree->type.node_class = etree_provided; - - /* Copy the symbol type if this is a simple assignment of - one symbol to another. Also, handle the case of a foldable - ternary conditional with names on either side. */ - if (tree->assign.src->type.node_class == etree_name) - try_copy_symbol_type (h, tree->assign.src); - else if (tree->assign.src->type.node_class == etree_trinary) + /* If the expression is not valid then fake a zero value. In + the final phase any errors will already have been raised, + in earlier phases we want to create this definition so + that it can be seen by other expressions. */ + if (!expld.result.valid_p + && h->type == bfd_link_hash_new) + { + expld.result.value = 0; + expld.result.section = NULL; + expld.result.valid_p = TRUE; + } + + if (expld.result.valid_p) { - exp_fold_tree_1 (tree->assign.src->trinary.cond); - if (expld.result.valid_p) + if (expld.result.section == NULL) + expld.result.section = expld.section; + if (!update_definedness (tree->assign.dst, h) && 0) { - if (expld.result.value - && tree->assign.src->trinary.lhs->type.node_class - == etree_name) - try_copy_symbol_type (h, tree->assign.src->trinary.lhs); - - if (!expld.result.value - && tree->assign.src->trinary.rhs->type.node_class - == etree_name) - try_copy_symbol_type (h, tree->assign.src->trinary.rhs); + /* Symbol was already defined. For now this error + is disabled because it causes failures in the ld + testsuite: ld-elf/var1, ld-scripts/defined5, and + ld-scripts/pr14962. Some of these no doubt + reflect scripts used in the wild. */ + (*link_info.callbacks->multiple_definition) + (&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; + + /* 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 *) 0 - 1)) + bfd_copy_link_hash_symbol_type (link_info.output_bfd, h, + expld.assign_src); } } - else if (expld.phase == lang_final_phase_enum) - { - h = bfd_link_hash_lookup (link_info.hash, tree->assign.dst, - FALSE, FALSE, TRUE); - if (h != NULL - && h->type == bfd_link_hash_new) - h->type = bfd_link_hash_undefined; - } expld.assign_name = NULL; } break; @@ -1349,7 +1338,6 @@ static etree_type * exp_assop (const char *dst, etree_type *src, enum node_tree_enum class, - bfd_boolean defsym, bfd_boolean hidden) { etree_type *n; @@ -1361,7 +1349,6 @@ exp_assop (const char *dst, n->assign.type.node_class = class; n->assign.src = src; n->assign.dst = dst; - n->assign.defsym = defsym; n->assign.hidden = hidden; return n; } @@ -1371,7 +1358,7 @@ exp_assop (const char *dst, etree_type * exp_assign (const char *dst, etree_type *src, bfd_boolean hidden) { - return exp_assop (dst, src, etree_assign, FALSE, hidden); + return exp_assop (dst, src, etree_assign, hidden); } /* Handle --defsym command-line option. */ @@ -1379,7 +1366,7 @@ exp_assign (const char *dst, etree_type *src, bfd_boolean hidden) etree_type * exp_defsym (const char *dst, etree_type *src) { - return exp_assop (dst, src, etree_assign, TRUE, FALSE); + return exp_assop (dst, src, etree_assign, FALSE); } /* Handle PROVIDE. */ @@ -1387,7 +1374,7 @@ exp_defsym (const char *dst, etree_type *src) etree_type * exp_provide (const char *dst, etree_type *src, bfd_boolean hidden) { - return exp_assop (dst, src, etree_provide, FALSE, hidden); + return exp_assop (dst, src, etree_provide, hidden); } /* Handle ASSERT. */ @@ -1438,7 +1425,7 @@ exp_print_tree (etree_type *tree) break; case etree_provide: case etree_provided: - fprintf (config.map_file, "PROVIDE (%s, ", tree->assign.dst); + fprintf (config.map_file, "PROVIDE (%s = ", tree->assign.dst); exp_print_tree (tree->assign.src); fputc (')', config.map_file); break; |