/* This module handles expression trees.
- Copyright (C) 1991, 92, 93, 94, 95, 96, 97, 98, 99, 2000
+ Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
+ 2001, 2002
Free Software Foundation, Inc.
Written by Steve Chamberlain of Cygnus Support <sac@cygnus.com>.
#include "ldmain.h"
#include "ldmisc.h"
#include "ldexp.h"
-#include "ldgram.h"
+#include <ldgram.h>
#include "ldlang.h"
-
-static void exp_print_token PARAMS ((token_code_type code));
-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));
+#include "libiberty.h"
+#include "safe-ctype.h"
+
+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,
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;
- } table[] = {
+ char * name;
+ }
+ table[] =
+ {
{ INT, "int" },
- { REL, "relocateable" },
{ NAME, "NAME" },
{ PLUSEQ, "+=" },
{ MINUSEQ, "-=" },
{ LE, "<=" },
{ GE, ">=" },
{ LSHIFT, "<<" },
- { RSHIFT, ">>=" },
+ { RSHIFT, ">>" },
{ ALIGN_K, "ALIGN" },
{ BLOCK, "BLOCK" },
+ { QUAD, "QUAD" },
+ { SQUAD, "SQUAD" },
+ { LONG, "LONG" },
+ { SHORT, "SHORT" },
+ { BYTE, "BYTE" },
{ SECTIONS, "SECTIONS" },
{ SIZEOF_HEADERS, "SIZEOF_HEADERS" },
- { NEXT, "NEXT" },
- { SIZEOF, "SIZEOF" },
- { ADDR, "ADDR" },
- { LOADADDR, "LOADADDR" },
{ MEMORY, "MEMORY" },
{ DEFINED, "DEFINED" },
{ TARGET_K, "TARGET" },
{ SEARCH_DIR, "SEARCH_DIR" },
{ MAP, "MAP" },
- { QUAD, "QUAD" },
- { SQUAD, "SQUAD" },
- { LONG, "LONG" },
- { SHORT, "SHORT" },
- { BYTE, "BYTE" },
{ ENTRY, "ENTRY" },
- { 0, (char *) NULL }
+ { NEXT, "NEXT" },
+ { SIZEOF, "SIZEOF" },
+ { ADDR, "ADDR" },
+ { 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 = 0; table[idx].name != (char *) NULL; idx++)
- {
- if (table[idx].code == code)
- {
- fprintf (config.map_file, "%s", table[idx].name);
- return;
- }
- }
- /* Not in table, just print it alone */
- fprintf (config.map_file, "%c", code);
+ for (idx = 0; idx < ARRAY_SIZE (table); idx++)
+ if (table[idx].code == code)
+ break;
+
+ 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);
+
+ if (infix_p)
+ fputc (' ', config.map_file);
}
static void
bfd_vma value;
{
etree_value_type new;
- new.valid_p = true;
+ new.valid_p = TRUE;
new.section = abs_output_section;
new.value = value;
return new;
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. */
}
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.valid_p = TRUE;
new.value = value;
+ new.str = str;
new.section = section;
return new;
}
lang_output_section_statement_type *section;
{
etree_value_type new;
- new.valid_p = true;
+ new.valid_p = TRUE;
new.value = value;
+ new.str = NULL;
new.section = section;
new.value -= section->bfd_section->vma;
return new;
}
+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;
&& (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
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 ();
}
}
else
{
- result.valid_p = false;
+ result.valid_p = FALSE;
}
}
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 ()
{
etree_value_type new;
- new.valid_p = false;
+ new.valid_p = FALSE;
return new;
}
bfd_vma dot;
{
etree_value_type result;
+
switch (tree->type.node_code)
{
case SIZEOF_HEADERS:
}
else
{
- result.valid_p = false;
+ result.valid_p = FALSE;
}
break;
case DEFINED:
if (allocation_done == lang_first_phase_enum)
- result.valid_p = false;
+ result.valid_p = FALSE;
else
{
struct bfd_link_hash_entry *h;
h = bfd_wrapped_link_hash_lookup (output_bfd, &link_info,
tree->name.name,
- false, false, true);
+ FALSE, FALSE, TRUE);
result.value = (h != (struct bfd_link_hash_entry *) NULL
&& (h->type == bfd_link_hash_defined
|| h->type == bfd_link_hash_defweak
|| h->type == bfd_link_hash_common));
result.section = 0;
- result.valid_p = true;
+ result.valid_p = TRUE;
}
break;
case NAME:
- result.valid_p = false;
+ result.valid_p = FALSE;
if (tree->name.name[0] == '.' && tree->name.name[1] == 0)
{
if (allocation_done != lang_first_phase_enum)
h = bfd_wrapped_link_hash_lookup (output_bfd, &link_info,
tree->name.name,
- false, false, true);
+ FALSE, FALSE, TRUE);
if (h != NULL
&& (h->type == bfd_link_hash_defined
|| h->type == bfd_link_hash_defweak))
being linked with -R? */
result = new_rel ((h->u.def.value
+ h->u.def.section->output_offset),
+ NULL,
os);
}
}
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 ();
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,
if (tree == NULL)
{
- result.valid_p = false;
+ result.valid_p = FALSE;
return result;
}
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:
if (allocation_done != lang_final_phase_enum)
- result.valid_p = false;
+ result.valid_p = FALSE;
else
result = new_rel ((tree->rel.value
+ tree->rel.section->output_section->vma
+ tree->rel.section->output_offset),
+ NULL,
current_section);
break;
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:
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:
if (tree->assign.dst[0] == '.' && tree->assign.dst[1] == 0)
{
- /* Assignment to dot can only be done during allocation */
- if (tree->type.node_class == etree_provide)
+ /* Assignment to dot can only be done during allocation. */
+ if (tree->type.node_class != etree_assign)
einfo (_("%F%S can not PROVIDE assignment to location counter\n"));
if (allocation_done == lang_allocating_phase_enum
|| (allocation_done == lang_final_phase_enum
{
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"));
+ current_section->bfd_section->vma);
if (nextdot < dot
&& current_section != abs_output_section)
- {
- einfo (_("%F%S cannot move location counter backwards (from %V to %V)\n"),
- dot, nextdot);
- }
+ einfo (_("%F%S cannot move location counter backwards (from %V to %V)\n"),
+ dot, nextdot);
else
*dotp = nextdot;
}
dot, dotp);
if (result.valid_p)
{
- boolean create;
+ bfd_boolean create;
struct bfd_link_hash_entry *h;
if (tree->type.node_class == etree_assign)
- create = true;
+ create = TRUE;
else
- create = false;
+ create = FALSE;
h = bfd_link_hash_lookup (link_info.hash, tree->assign.dst,
- create, false, false);
+ create, FALSE, FALSE);
if (h == (struct bfd_link_hash_entry *) NULL)
{
if (tree->type.node_class == etree_assign)
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;
}
}
}
(lang_output_section_statement_type *) NULL,
lang_first_phase_enum);
if (r.valid_p)
- {
- return exp_intop (r.value);
- }
+ return exp_intop (r.value);
+
new = (etree_type *) stat_alloc (sizeof (new->trinary));
memcpy ((char *) new, (char *) &value, sizeof (new->trinary));
return new;
r = exp_fold_tree_no_dot (&value, abs_output_section,
lang_first_phase_enum);
if (r.valid_p)
- {
- return exp_intop (r.value);
- }
+ return exp_intop (r.value);
+
new = (etree_type *) stat_alloc (sizeof (new->unary));
memcpy ((char *) new, (char *) &value, sizeof (new->unary));
return new;
etree_type *
exp_nameop (code, name)
int code;
- CONST char *name;
+ const char *name;
{
etree_type value, *new;
etree_value_type r;
(lang_output_section_statement_type *) NULL,
lang_first_phase_enum);
if (r.valid_p)
- {
- return exp_intop (r.value);
- }
+ return exp_intop (r.value);
+
new = (etree_type *) stat_alloc (sizeof (new->name));
memcpy ((char *) new, (char *) &value, sizeof (new->name));
return new;
etree_type *
exp_assop (code, dst, src)
int code;
- CONST char *dst;
+ const char *dst;
etree_type *src;
{
etree_type value, *new;
#if 0
if (exp_fold_tree_no_dot (&value, &result))
- {
- return exp_intop (result);
- }
+ return exp_intop (result);
#endif
new = (etree_type *) stat_alloc (sizeof (new->assign));
memcpy ((char *) new, (char *) &value, sizeof (new->assign));
exp_print_tree (tree)
etree_type *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:
case etree_assign:
#if 0
if (tree->assign.dst->sdefs != (asymbol *) NULL)
- {
- fprintf (config.map_file, "%s (%x) ", tree->assign.dst->name,
- tree->assign.dst->sdefs->value);
- }
+ fprintf (config.map_file, "%s (%x) ", tree->assign.dst->name,
+ tree->assign.dst->sdefs->value);
else
- {
- fprintf (config.map_file, "%s (UNDEFINED)", tree->assign.dst->name);
- }
+ 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:
+ case etree_provided:
fprintf (config.map_file, "PROVIDE (%s, ", tree->assign.dst);
exp_print_tree (tree->assign.src);
fprintf (config.map_file, ")");
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;
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, ")");
}
}
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:
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;
res = exp_fold_tree_no_dot (tree, abs_output_section, allocation_done);
if (res.valid_p)
- {
- res.value += res.section->bfd_section->vma;
- }
+ res.value += res.section->bfd_section->vma;
else
- {
- einfo (_("%F%S non constant expression for %s\n"), name);
- }
+ einfo (_("%F%S non constant expression for %s\n"), name);
+
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;
+}