diff options
Diffstat (limited to 'contrib/binutils/ld/ldexp.c')
-rw-r--r-- | contrib/binutils/ld/ldexp.c | 397 |
1 files changed, 291 insertions, 106 deletions
diff --git a/contrib/binutils/ld/ldexp.c b/contrib/binutils/ld/ldexp.c index ec449fd8d..e45c470 100644 --- a/contrib/binutils/ld/ldexp.c +++ b/contrib/binutils/ld/ldexp.c @@ -1,6 +1,6 @@ /* This module handles expression trees. Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, - 2001 + 2001, 2002 Free Software Foundation, Inc. Written by Steve Chamberlain of Cygnus Support <sac@cygnus.com>. @@ -39,21 +39,32 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "ldgram.h" #include "ldlang.h" #include "libiberty.h" +#include "safe-ctype.h" -static void exp_print_token PARAMS ((token_code_type code)); +static void exp_print_token PARAMS ((token_code_type code, int infix_p)); static void make_abs PARAMS ((etree_value_type *ptr)); static etree_value_type new_abs PARAMS ((bfd_vma value)); static void check PARAMS ((lang_output_section_statement_type *os, const char *name, const char *op)); static etree_value_type new_rel - PARAMS ((bfd_vma value, lang_output_section_statement_type *section)); + PARAMS ((bfd_vma, char *, lang_output_section_statement_type *section)); static etree_value_type new_rel_from_section PARAMS ((bfd_vma value, lang_output_section_statement_type *section)); +static etree_value_type fold_unary + PARAMS ((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 fold_binary PARAMS ((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 fold_trinary + PARAMS ((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 fold_name PARAMS ((etree_type *tree, lang_output_section_statement_type *current_section, @@ -64,11 +75,17 @@ static etree_value_type exp_fold_tree_no_dot lang_output_section_statement_type *current_section, lang_phase_type allocation_done)); +struct exp_data_seg exp_data_seg; + +/* Print the string representation of the given token. Surround it + with spaces if INFIX_P is true. */ + static void -exp_print_token (code) +exp_print_token (code, infix_p) token_code_type code; + int infix_p; { - static CONST struct + static const struct { token_code_type code; char * name; @@ -114,23 +131,27 @@ exp_print_token (code) { LOADADDR, "LOADADDR" }, { MAX_K, "MAX_K" }, { REL, "relocateable" }, + { DATA_SEGMENT_ALIGN, "DATA_SEGMENT_ALIGN" }, + { DATA_SEGMENT_END, "DATA_SEGMENT_END" } }; unsigned int idx; - for (idx = ARRAY_SIZE (table); idx--;) - { - if (table[idx].code == code) - { - fprintf (config.map_file, " %s ", table[idx].name); - return; - } - } + for (idx = 0; idx < ARRAY_SIZE (table); idx++) + if (table[idx].code == code) + break; - /* Not in table, just print it alone. */ - if (code < 127) - fprintf (config.map_file, " %c ", code); + if (infix_p) + fputc (' ', config.map_file); + + if (idx < ARRAY_SIZE (table)) + fputs (table[idx].name, config.map_file); + else if (code < 127) + fputc (code, config.map_file); else - fprintf (config.map_file, " <code %d> ", code); + fprintf (config.map_file, "<code %d>", code); + + if (infix_p) + fputc (' ', config.map_file); } static void @@ -172,9 +193,22 @@ exp_intop (value) etree_type *new = (etree_type *) stat_alloc (sizeof (new->value)); new->type.node_code = INT; new->value.value = value; + new->value.str = NULL; new->type.node_class = etree_value; return new; +} +etree_type * +exp_bigintop (value, str) + bfd_vma value; + char *str; +{ + etree_type *new = (etree_type *) stat_alloc (sizeof (new->value)); + new->type.node_code = INT; + new->value.value = value; + new->value.str = str; + new->type.node_class = etree_value; + return new; } /* Build an expression representing an unnamed relocateable value. */ @@ -193,13 +227,15 @@ exp_relop (section, value) } static etree_value_type -new_rel (value, section) +new_rel (value, str, section) bfd_vma value; + char *str; lang_output_section_statement_type *section; { etree_value_type new; new.valid_p = true; new.value = value; + new.str = str; new.section = section; return new; } @@ -212,6 +248,7 @@ new_rel_from_section (value, section) etree_value_type new; new.valid_p = true; new.value = value; + new.str = NULL; new.section = section; new.value -= section->bfd_section->vma; @@ -220,6 +257,93 @@ new_rel_from_section (value, section) } static etree_value_type +fold_unary (tree, current_section, allocation_done, dot, dotp) + etree_type *tree; + lang_output_section_statement_type *current_section; + lang_phase_type allocation_done; + bfd_vma dot; + bfd_vma *dotp; +{ + etree_value_type result; + + result = exp_fold_tree (tree->unary.child, + current_section, + allocation_done, dot, dotp); + if (result.valid_p) + { + switch (tree->type.node_code) + { + case ALIGN_K: + if (allocation_done != lang_first_phase_enum) + result = new_rel_from_section (align_n (dot, result.value), + current_section); + else + result.valid_p = false; + break; + + case ABSOLUTE: + if (allocation_done != lang_first_phase_enum) + { + result.value += result.section->bfd_section->vma; + result.section = abs_output_section; + } + else + result.valid_p = false; + break; + + case '~': + make_abs (&result); + result.value = ~result.value; + break; + + case '!': + make_abs (&result); + result.value = !result.value; + break; + + case '-': + make_abs (&result); + result.value = -result.value; + break; + + case NEXT: + /* Return next place aligned to value. */ + if (allocation_done == lang_allocating_phase_enum) + { + make_abs (&result); + result.value = align_n (dot, result.value); + } + else + result.valid_p = false; + break; + + case DATA_SEGMENT_END: + if (allocation_done != lang_first_phase_enum + && current_section == abs_output_section + && (exp_data_seg.phase == exp_dataseg_align_seen + || exp_data_seg.phase == exp_dataseg_adjust + || allocation_done != lang_allocating_phase_enum)) + { + if (exp_data_seg.phase == exp_dataseg_align_seen) + { + exp_data_seg.phase = exp_dataseg_end_seen; + exp_data_seg.end = result.value; + } + } + else + result.valid_p = false; + break; + + default: + FAIL (); + break; + } + } + + return result; +} + +static etree_value_type fold_binary (tree, current_section, allocation_done, dot, dotp) etree_type *tree; lang_output_section_statement_type *current_section; @@ -252,15 +376,14 @@ fold_binary (tree, current_section, allocation_done, dot, dotp) && (tree->type.node_code == '+' || tree->type.node_code == '-')) { - etree_value_type hold; - - /* If there is only one absolute term, make sure it is the - second one. */ if (other.section != abs_output_section) { - hold = result; - result = other; - other = hold; + /* Keep the section of the other term. */ + if (tree->type.node_code == '+') + other.value = result.value + other.value; + else + other.value = result.value - other.value; + return other; } } else if (result.section != other.section @@ -314,6 +437,34 @@ fold_binary (tree, current_section, allocation_done, dot, dotp) result = other; break; + case DATA_SEGMENT_ALIGN: + if (allocation_done != lang_first_phase_enum + && current_section == abs_output_section + && (exp_data_seg.phase == exp_dataseg_none + || exp_data_seg.phase == exp_dataseg_adjust + || allocation_done != lang_allocating_phase_enum)) + { + bfd_vma maxpage = result.value; + + result.value = align_n (dot, maxpage); + if (exp_data_seg.phase != exp_dataseg_adjust) + { + result.value += dot & (maxpage - 1); + if (allocation_done == lang_allocating_phase_enum) + { + exp_data_seg.phase = exp_dataseg_align_seen; + exp_data_seg.base = result.value; + exp_data_seg.pagesize = other.value; + } + } + else if (other.value < maxpage) + result.value += (dot + other.value - 1) + & (maxpage - other.value); + } + else + result.valid_p = false; + break; + default: FAIL (); } @@ -327,6 +478,28 @@ fold_binary (tree, current_section, allocation_done, dot, dotp) return result; } +static etree_value_type +fold_trinary (tree, current_section, allocation_done, dot, dotp) + etree_type *tree; + lang_output_section_statement_type *current_section; + lang_phase_type allocation_done; + bfd_vma dot; + bfd_vma *dotp; +{ + etree_value_type result; + + result = exp_fold_tree (tree->trinary.cond, current_section, + allocation_done, dot, dotp); + if (result.valid_p) + result = exp_fold_tree ((result.value + ? tree->trinary.lhs + : tree->trinary.rhs), + current_section, + allocation_done, dot, dotp); + + return result; +} + etree_value_type invalid () { @@ -419,6 +592,7 @@ fold_name (tree, current_section, allocation_done, dot) being linked with -R? */ result = new_rel ((h->u.def.value + h->u.def.section->output_offset), + NULL, os); } } @@ -436,7 +610,7 @@ fold_name (tree, current_section, allocation_done, dot) os = lang_output_section_find (tree->name.name); check (os, tree->name.name, "ADDR"); - result = new_rel (0, os); + result = new_rel (0, NULL, os); } else result = invalid (); @@ -450,7 +624,7 @@ fold_name (tree, current_section, allocation_done, dot) os = lang_output_section_find (tree->name.name); check (os, tree->name.name, "LOADADDR"); if (os->load_base == NULL) - result = new_rel (0, os); + result = new_rel (0, NULL, os); else result = exp_fold_tree_no_dot (os->load_base, abs_output_section, @@ -501,7 +675,7 @@ exp_fold_tree (tree, current_section, allocation_done, dot, dotp) switch (tree->type.node_class) { case etree_value: - result = new_rel (tree->value.value, current_section); + result = new_rel (tree->value.value, tree->value.str, current_section); break; case etree_rel: @@ -511,6 +685,7 @@ exp_fold_tree (tree, current_section, allocation_done, dot, dotp) result = new_rel ((tree->rel.value + tree->rel.section->output_section->vma + tree->rel.section->output_offset), + NULL, current_section); break; @@ -527,73 +702,8 @@ exp_fold_tree (tree, current_section, allocation_done, dot, dotp) break; case etree_unary: - result = exp_fold_tree (tree->unary.child, - current_section, - allocation_done, dot, dotp); - if (result.valid_p) - { - switch (tree->type.node_code) - { - case ALIGN_K: - if (allocation_done != lang_first_phase_enum) - result = new_rel_from_section (ALIGN_N (dot, result.value), - current_section); - else - result.valid_p = false; - break; - - case ABSOLUTE: - if (allocation_done != lang_first_phase_enum && result.valid_p) - { - result.value += result.section->bfd_section->vma; - result.section = abs_output_section; - } - else - result.valid_p = false; - break; - - case '~': - make_abs (&result); - result.value = ~result.value; - break; - - case '!': - make_abs (&result); - result.value = !result.value; - break; - - case '-': - make_abs (&result); - result.value = -result.value; - break; - - case NEXT: - /* Return next place aligned to value. */ - if (allocation_done == lang_allocating_phase_enum) - { - make_abs (&result); - result.value = ALIGN_N (dot, result.value); - } - else - result.valid_p = false; - break; - - default: - FAIL (); - break; - } - } - break; - - case etree_trinary: - result = exp_fold_tree (tree->trinary.cond, current_section, - allocation_done, dot, dotp); - if (result.valid_p) - result = exp_fold_tree ((result.value - ? tree->trinary.lhs - : tree->trinary.rhs), - current_section, - allocation_done, dot, dotp); + result = fold_unary (tree, current_section, allocation_done, + dot, dotp); break; case etree_binary: @@ -601,6 +711,11 @@ exp_fold_tree (tree, current_section, allocation_done, dot, dotp) dot, dotp); break; + case etree_trinary: + result = fold_trinary (tree, current_section, allocation_done, + dot, dotp); + break; + case etree_assign: case etree_provide: case etree_provided: @@ -615,7 +730,7 @@ exp_fold_tree (tree, current_section, allocation_done, dot, dotp) { result = exp_fold_tree (tree->assign.src, current_section, - lang_allocating_phase_enum, dot, + allocation_done, dot, dotp); if (! result.valid_p) einfo (_("%F%S invalid assignment to location counter\n")); @@ -778,7 +893,7 @@ exp_unop (code, child) etree_type * exp_nameop (code, name) int code; - CONST char *name; + const char *name; { etree_type value, *new; etree_value_type r; @@ -801,7 +916,7 @@ exp_nameop (code, name) etree_type * exp_assop (code, dst, src) int code; - CONST char *dst; + const char *dst; etree_type *src; { etree_type value, *new; @@ -861,13 +976,13 @@ exp_print_tree (tree) { if (config.map_file == NULL) config.map_file = stderr; - + if (tree == NULL) { minfo ("NULL TREE\n"); return; } - + switch (tree->type.node_class) { case etree_value: @@ -887,7 +1002,7 @@ exp_print_tree (tree) fprintf (config.map_file, "%s (UNDEFINED)", tree->assign.dst->name); #endif fprintf (config.map_file, "%s", tree->assign.dst); - exp_print_token (tree->type.node_code); + exp_print_token (tree->type.node_code, true); exp_print_tree (tree->assign.src); break; case etree_provide: @@ -899,7 +1014,7 @@ exp_print_tree (tree) case etree_binary: fprintf (config.map_file, "("); exp_print_tree (tree->binary.lhs); - exp_print_token (tree->type.node_code); + exp_print_token (tree->type.node_code, true); exp_print_tree (tree->binary.rhs); fprintf (config.map_file, ")"); break; @@ -911,10 +1026,10 @@ exp_print_tree (tree) exp_print_tree (tree->trinary.rhs); break; case etree_unary: - exp_print_token (tree->unary.type.node_code); + exp_print_token (tree->unary.type.node_code, false); if (tree->unary.child) { - fprintf (config.map_file, "("); + fprintf (config.map_file, " ("); exp_print_tree (tree->unary.child); fprintf (config.map_file, ")"); } @@ -936,9 +1051,9 @@ exp_print_tree (tree) } else { - exp_print_token (tree->type.node_code); + exp_print_token (tree->type.node_code, false); if (tree->name.name) - fprintf (config.map_file, "(%s)", tree->name.name); + fprintf (config.map_file, " (%s)", tree->name.name); } break; default: @@ -977,6 +1092,65 @@ exp_get_value_int (tree, def, name, allocation_done) return (int) exp_get_vma (tree, (bfd_vma) def, name, allocation_done); } +fill_type * +exp_get_fill (tree, def, name, allocation_done) + etree_type *tree; + fill_type *def; + char *name; + lang_phase_type allocation_done; +{ + fill_type *fill; + etree_value_type r; + size_t len; + unsigned int val; + + if (tree == NULL) + return def; + + r = exp_fold_tree_no_dot (tree, abs_output_section, allocation_done); + if (! r.valid_p && name != NULL) + einfo (_("%F%S nonconstant expression for %s\n"), name); + + if (r.str != NULL && (len = strlen (r.str)) != 0) + { + unsigned char *dst; + unsigned char *s; + fill = (fill_type *) xmalloc ((len + 1) / 2 + sizeof (*fill) - 1); + fill->size = (len + 1) / 2; + dst = fill->data; + s = r.str; + val = 0; + do + { + unsigned int digit; + + digit = *s++ - '0'; + if (digit > 9) + digit = (digit - 'A' + '0' + 10) & 0xf; + val <<= 4; + val += digit; + --len; + if ((len & 1) == 0) + { + *dst++ = val; + val = 0; + } + } + while (len != 0); + } + else + { + fill = (fill_type *) xmalloc (4 + sizeof (*fill) - 1); + val = r.value; + fill->data[0] = (val >> 24) & 0xff; + fill->data[1] = (val >> 16) & 0xff; + fill->data[2] = (val >> 8) & 0xff; + fill->data[3] = (val >> 0) & 0xff; + fill->size = 4; + } + return fill; +} + bfd_vma exp_get_abs_int (tree, def, name, allocation_done) etree_type *tree; @@ -994,3 +1168,14 @@ exp_get_abs_int (tree, def, name, allocation_done) return res.value; } + +bfd_vma align_n (value, align) + bfd_vma value; + bfd_vma align; +{ + if (align <= 1) + return value; + + value = (value + align - 1) / align; + return value * align; +} |