diff options
Diffstat (limited to 'ld/ldexp.c')
-rw-r--r-- | ld/ldexp.c | 261 |
1 files changed, 200 insertions, 61 deletions
@@ -41,8 +41,12 @@ #include "libiberty.h" #include "safe-ctype.h" +static etree_value_type exp_fold_tree_1 + (etree_type *, lang_output_section_statement_type *, + lang_phase_type, bfd_vma, bfd_vma *, bfd_boolean); static etree_value_type exp_fold_tree_no_dot - (etree_type *, lang_output_section_statement_type *, lang_phase_type); + (etree_type *, lang_output_section_statement_type *, lang_phase_type, + bfd_boolean); static bfd_vma align_n (bfd_vma, bfd_vma); @@ -219,13 +223,14 @@ fold_unary (etree_type *tree, lang_output_section_statement_type *current_section, lang_phase_type allocation_done, bfd_vma dot, - bfd_vma *dotp) + bfd_vma *dotp, + bfd_boolean mark_used) { etree_value_type result; - result = exp_fold_tree (tree->unary.child, - current_section, - allocation_done, dot, dotp); + result = exp_fold_tree_1 (tree->unary.child, + current_section, + allocation_done, dot, dotp, mark_used); if (result.valid_p) { switch (tree->type.node_code) @@ -308,12 +313,13 @@ fold_binary (etree_type *tree, lang_output_section_statement_type *current_section, lang_phase_type allocation_done, bfd_vma dot, - bfd_vma *dotp) + bfd_vma *dotp, + bfd_boolean mark_used) { etree_value_type result; - result = exp_fold_tree (tree->binary.lhs, current_section, - allocation_done, dot, dotp); + result = exp_fold_tree_1 (tree->binary.lhs, current_section, + allocation_done, dot, dotp, mark_used); /* The SEGMENT_START operator is special because its first operand is a string, not the name of a symbol. */ @@ -338,9 +344,10 @@ fold_binary (etree_type *tree, { etree_value_type other; - other = exp_fold_tree (tree->binary.rhs, - current_section, - allocation_done, dot, dotp); + other = exp_fold_tree_1 (tree->binary.rhs, + current_section, + allocation_done, + dot, dotp, mark_used); if (other.valid_p) { /* If the values are from different sections, or this is an @@ -498,18 +505,20 @@ fold_trinary (etree_type *tree, lang_output_section_statement_type *current_section, lang_phase_type allocation_done, bfd_vma dot, - bfd_vma *dotp) + bfd_vma *dotp, + bfd_boolean mark_used) { etree_value_type result; - result = exp_fold_tree (tree->trinary.cond, current_section, - allocation_done, dot, dotp); + result = exp_fold_tree_1 (tree->trinary.cond, current_section, + allocation_done, dot, dotp, mark_used); if (result.valid_p) - result = exp_fold_tree ((result.value - ? tree->trinary.lhs - : tree->trinary.rhs), - current_section, - allocation_done, dot, dotp); + result = exp_fold_tree_1 ((result.value + ? tree->trinary.lhs + : tree->trinary.rhs), + current_section, + allocation_done, + dot, dotp, mark_used); return result; } @@ -518,7 +527,8 @@ static etree_value_type fold_name (etree_type *tree, lang_output_section_statement_type *current_section, lang_phase_type allocation_done, - bfd_vma dot) + bfd_vma dot, + bfd_boolean mark_used) { etree_value_type result; @@ -596,6 +606,7 @@ fold_name (etree_type *tree, + h->u.def.section->output_offset), NULL, os); + os->bfd_section->flags |= SEC_KEEP; } } } @@ -619,8 +630,12 @@ fold_name (etree_type *tree, lang_output_section_statement_type *os; os = lang_output_section_find (tree->name.name); - if (os && os->processed > 0) - result = new_rel (0, NULL, os); + if (os) + { + os->bfd_section->flags |= SEC_KEEP; + if (os->processed > 0) + result = new_rel (0, NULL, os); + } } break; @@ -630,14 +645,19 @@ fold_name (etree_type *tree, lang_output_section_statement_type *os; os = lang_output_section_find (tree->name.name); - if (os && os->processed != 0) + if (os) { - if (os->load_base == NULL) - result = new_rel (0, NULL, os); - else - result = exp_fold_tree_no_dot (os->load_base, - abs_output_section, - allocation_done); + os->bfd_section->flags |= SEC_KEEP; + if (os->processed != 0) + { + if (os->load_base == NULL) + result = new_rel (0, NULL, os); + else + result = exp_fold_tree_no_dot (os->load_base, + abs_output_section, + allocation_done, + mark_used); + } } } break; @@ -649,8 +669,12 @@ fold_name (etree_type *tree, lang_output_section_statement_type *os; os = lang_output_section_find (tree->name.name); - if (os && os->processed > 0) - result = new_abs (os->bfd_section->size / opb); + if (os) + { + os->bfd_section->flags |= SEC_KEEP; + if (os->processed > 0) + result = new_abs (os->bfd_section->size / opb); + } } break; @@ -688,12 +712,13 @@ fold_name (etree_type *tree, return result; } -etree_value_type -exp_fold_tree (etree_type *tree, - lang_output_section_statement_type *current_section, - lang_phase_type allocation_done, - bfd_vma dot, - bfd_vma *dotp) +static etree_value_type +exp_fold_tree_1 (etree_type *tree, + lang_output_section_statement_type *current_section, + lang_phase_type allocation_done, + bfd_vma dot, + bfd_vma *dotp, + bfd_boolean mark_used) { etree_value_type result; @@ -721,26 +746,34 @@ exp_fold_tree (etree_type *tree, break; case etree_assert: - result = exp_fold_tree (tree->assert_s.child, - current_section, - allocation_done, dot, dotp); - if (result.valid_p && !result.value) - einfo ("%X%P: %s\n", tree->assert_s.message); + result = exp_fold_tree_1 (tree->assert_s.child, + current_section, + allocation_done, dot, dotp, + mark_used); + if (result.valid_p) + { + if (mark_used) + /* We don't care if assert fails or not when we are just + marking if a section is used or not. */ + result.value = 1; + else if (!result.value) + einfo ("%X%P: %s\n", tree->assert_s.message); + } break; case etree_unary: result = fold_unary (tree, current_section, allocation_done, - dot, dotp); + dot, dotp, mark_used); break; case etree_binary: result = fold_binary (tree, current_section, allocation_done, - dot, dotp); + dot, dotp, mark_used); break; case etree_trinary: result = fold_trinary (tree, current_section, allocation_done, - dot, dotp); + dot, dotp, mark_used); break; case etree_assign: @@ -757,9 +790,10 @@ exp_fold_tree (etree_type *tree, { /* Notify the folder that this is an assignment to dot. */ assigning_to_dot = TRUE; - result = exp_fold_tree (tree->assign.src, - current_section, - allocation_done, dot, dotp); + result = exp_fold_tree_1 (tree->assign.src, + current_section, + allocation_done, + dot, dotp, mark_used); assigning_to_dot = FALSE; if (! result.valid_p) @@ -788,9 +822,9 @@ exp_fold_tree (etree_type *tree, } else { - result = exp_fold_tree (tree->assign.src, - current_section, allocation_done, - dot, dotp); + result = exp_fold_tree_1 (tree->assign.src, + current_section, allocation_done, + dot, dotp, mark_used); if (result.valid_p) { bfd_boolean create; @@ -832,7 +866,8 @@ exp_fold_tree (etree_type *tree, break; case etree_name: - result = fold_name (tree, current_section, allocation_done, dot); + result = fold_name (tree, current_section, allocation_done, dot, + mark_used); break; default: @@ -844,12 +879,25 @@ exp_fold_tree (etree_type *tree, return result; } +etree_value_type +exp_fold_tree (etree_type *tree, + lang_output_section_statement_type *current_section, + lang_phase_type allocation_done, + bfd_vma dot, + bfd_vma *dotp) +{ + return exp_fold_tree_1 (tree, current_section, allocation_done, + dot, dotp, FALSE); +} + static etree_value_type exp_fold_tree_no_dot (etree_type *tree, lang_output_section_statement_type *current_section, - lang_phase_type allocation_done) + lang_phase_type allocation_done, + bfd_boolean mark_used) { - return exp_fold_tree (tree, current_section, allocation_done, 0, NULL); + return exp_fold_tree_1 (tree, current_section, allocation_done, 0, + NULL, mark_used); } etree_type * @@ -864,7 +912,7 @@ exp_binop (int code, etree_type *lhs, etree_type *rhs) value.type.node_class = etree_binary; r = exp_fold_tree_no_dot (&value, abs_output_section, - lang_first_phase_enum); + lang_first_phase_enum, FALSE); if (r.valid_p) { return exp_intop (r.value); @@ -884,7 +932,7 @@ exp_trinop (int code, etree_type *cond, etree_type *lhs, etree_type *rhs) value.trinary.cond = cond; value.trinary.rhs = rhs; value.type.node_class = etree_trinary; - r = exp_fold_tree_no_dot (&value, NULL, lang_first_phase_enum); + r = exp_fold_tree_no_dot (&value, NULL, lang_first_phase_enum, FALSE); if (r.valid_p) return exp_intop (r.value); @@ -903,7 +951,7 @@ exp_unop (int code, etree_type *child) value.unary.child = child; value.unary.type.node_class = etree_unary; r = exp_fold_tree_no_dot (&value, abs_output_section, - lang_first_phase_enum); + lang_first_phase_enum, FALSE); if (r.valid_p) return exp_intop (r.value); @@ -921,7 +969,7 @@ exp_nameop (int code, const char *name) value.name.name = name; value.name.type.node_class = etree_name; - r = exp_fold_tree_no_dot (&value, NULL, lang_first_phase_enum); + r = exp_fold_tree_no_dot (&value, NULL, lang_first_phase_enum, FALSE); if (r.valid_p) return exp_intop (r.value); @@ -1071,7 +1119,8 @@ exp_get_vma (etree_type *tree, if (tree != NULL) { - r = exp_fold_tree_no_dot (tree, abs_output_section, allocation_done); + r = exp_fold_tree_no_dot (tree, abs_output_section, + allocation_done, FALSE); if (! r.valid_p && name != NULL) einfo (_("%F%S nonconstant expression for %s\n"), name); return r.value; @@ -1103,7 +1152,8 @@ exp_get_fill (etree_type *tree, if (tree == NULL) return def; - r = exp_fold_tree_no_dot (tree, abs_output_section, allocation_done); + r = exp_fold_tree_no_dot (tree, abs_output_section, allocation_done, + FALSE); if (! r.valid_p && name != NULL) einfo (_("%F%S nonconstant expression for %s\n"), name); @@ -1154,7 +1204,8 @@ exp_get_abs_int (etree_type *tree, lang_phase_type allocation_done) { etree_value_type res; - res = exp_fold_tree_no_dot (tree, abs_output_section, allocation_done); + res = exp_fold_tree_no_dot (tree, abs_output_section, allocation_done, + FALSE); if (res.valid_p) res.value += res.section->bfd_section->vma; @@ -1173,3 +1224,91 @@ align_n (bfd_vma value, bfd_vma align) value = (value + align - 1) / align; return value * align; } + +void +exp_mark_used_section + (etree_type *tree, + lang_output_section_statement_type *current_section) +{ + switch (tree->type.node_class) + { + case etree_value: + break; + + case etree_rel: + break; + + case etree_assert: + break; + + case etree_unary: + break; + + case etree_binary: + break; + + case etree_trinary: + break; + + case etree_assign: + case etree_provide: + case etree_provided: + if (tree->assign.dst[0] != '.' || tree->assign.dst[1] != 0) + { + etree_value_type result; + bfd_vma dot = 0; + + result = exp_fold_tree_1 (tree->assign.src, + current_section, + lang_allocating_phase_enum, + dot, &dot, TRUE); + if (result.valid_p) + { + bfd_boolean create; + struct bfd_link_hash_entry *h; + + if (tree->type.node_class == etree_assign) + create = TRUE; + else + create = FALSE; + h = bfd_link_hash_lookup (link_info.hash, tree->assign.dst, + create, FALSE, TRUE); + if (h == NULL) + { + if (create) + einfo (_("%P%F:%s: hash creation failed\n"), + tree->assign.dst); + } + else if (tree->type.node_class == etree_provide + && h->type != bfd_link_hash_new + && h->type != bfd_link_hash_undefined + && h->type != bfd_link_hash_common) + { + /* Do nothing. The symbol was defined by some + object. */ + } + else + { + /* FIXME: Should we worry if the symbol is already + defined? */ + lang_update_definedness (tree->assign.dst, h); + h->type = bfd_link_hash_defined; + h->u.def.value = result.value; + h->u.def.section = result.section->bfd_section; + if (tree->type.node_class == etree_provide) + tree->type.node_class = etree_provided; + } + } + } + break; + + case etree_name: + fold_name (tree, current_section, lang_allocating_phase_enum, 0, + TRUE); + break; + + default: + abort (); + break; + } +} |