summaryrefslogtreecommitdiffstats
path: root/contrib/binutils/ld/ldexp.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/binutils/ld/ldexp.c')
-rw-r--r--contrib/binutils/ld/ldexp.c397
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;
+}
OpenPOWER on IntegriCloud