binutils-gdb/ld/ldexp.c
Alan Modra 2c382fb6f5 Support arbitrary length fill patterns.
* ldexp.h (etree_value_type): Add "str" field.
	(union etree_union): Add "str" to "value" struct.
	(exp_bigintop): Declare.
	(exp_get_fill): Declare.
	* ldexp.c: Include "safe-ctype.h".
	(exp_intop): Set value.str to NULL.
	(exp_bigintop): New function.
	(new_rel): Pass in "str", and set new.str from it.
	(new_rel_from_section): Set new.str to NULL.
	(fold_name): Adjust calls to new_rel.
	(exp_fold_tree): Likewise.
	(exp_get_fill): New function.
	* ldgram.y (struct big_int bigint, fill_type *fill): New.
	(INT): Returns a "bigint".  Adjust all code handling INTs.
	(fill_opt): Returns a "fill".
	(fill_exp): Split out of fill_opt, use for FILL.
	* ldlang.h (struct _fill_type): New.
	(fill_type): Move typedef to ldexp.h.
	(lang_output_section_statement_type): "fill" is now a pointer.
	(lang_fill_statement_type): Likewise.
	(lang_padding_statement_type): Likewise.
	(lang_add_fill): Now takes a "fill_type *" param.
	(lang_leave_output_section_statement): Likewise.
	(lang_do_assignments): Likewise.
	(lang_size_sections): Likewise.
	(lang_leave_overlay_section): Likewise.
	(lang_leave_overlay): Likewise.
	* ldlang.c: Include ldgram.h after ldexp.h.
	(lang_output_section_statement_lookup): Adjust for fill_type change.
	(print_fill_statement): Likewise.
	(print_padding_statement): Likewise.
	(insert_pad): Now takes a "fill_type *" arg.
	(size_input_section): Likewise.
	(lang_size_sections_1): Likewise.
	(lang_size_sections): Likewise.
	(lang_do_assignments): Likewise.
	(lang_add_fill): Likewise.
	(lang_leave_output_section_statement): Likewise.
	(lang_leave_overlay_section): Likewise.
	(lang_leave_overlay): Likewise.
	Adjust all callers of the above function.
	* ldlex.l: Include ldgram.h after ldexp.h.  Allow hex numbers
	starting with "0X" as well as "0x".  Return bigint.str for hex
	numbers starting with "0x" or "0X", zero bigint.str otherwise.
	Always use base 16 for numbers starting with "$".
	* ldmain.c: Include ldgram.h after ldexp.h.
	* ldwrite.c (build_link_order): Use bfd_data_link_order in place
	of bfd_fill_link_order.
	* pe-dll.c: Adjust lang_do_assignments calls.
	* emultempl/elf32.em: Likewise.
	* emultempl/hppaelf.em: Likewise.
	* emultempl/ppc64elf.em: Likewise.
	* emultempl/beos.em: Include ldgram.h after ldexp.h, adjust
	lang_add_assignment call.
	* emultempl/pe.em: Likewise.
2002-02-15 02:11:05 +00:00

1123 lines
27 KiB
C

/* This module handles expression trees.
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>.
This file is part of GLD, the Gnu Linker.
GLD is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
GLD is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GLD; see the file COPYING. If not, write to the Free
Software Foundation, 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA. */
/* This module is in charge of working out the contents of expressions.
It has to keep track of the relative/absness of a symbol etc. This
is done by keeping all values in a struct (an etree_value_type)
which contains a value, a section to which it is relative and a
valid bit. */
#include "bfd.h"
#include "sysdep.h"
#include "bfdlink.h"
#include "ld.h"
#include "ldmain.h"
#include "ldmisc.h"
#include "ldexp.h"
#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 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, 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_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_name
PARAMS ((etree_type *tree,
lang_output_section_statement_type *current_section,
lang_phase_type allocation_done,
bfd_vma dot));
static etree_value_type exp_fold_tree_no_dot
PARAMS ((etree_type *tree,
lang_output_section_statement_type *current_section,
lang_phase_type allocation_done));
struct exp_data_seg exp_data_seg;
static void
exp_print_token (code)
token_code_type code;
{
static CONST struct
{
token_code_type code;
char * name;
}
table[] =
{
{ INT, "int" },
{ NAME, "NAME" },
{ PLUSEQ, "+=" },
{ MINUSEQ, "-=" },
{ MULTEQ, "*=" },
{ DIVEQ, "/=" },
{ LSHIFTEQ, "<<=" },
{ RSHIFTEQ, ">>=" },
{ ANDEQ, "&=" },
{ OREQ, "|=" },
{ OROR, "||" },
{ ANDAND, "&&" },
{ EQ, "==" },
{ NE, "!=" },
{ LE, "<=" },
{ GE, ">=" },
{ LSHIFT, "<<" },
{ RSHIFT, ">>" },
{ ALIGN_K, "ALIGN" },
{ BLOCK, "BLOCK" },
{ QUAD, "QUAD" },
{ SQUAD, "SQUAD" },
{ LONG, "LONG" },
{ SHORT, "SHORT" },
{ BYTE, "BYTE" },
{ SECTIONS, "SECTIONS" },
{ SIZEOF_HEADERS, "SIZEOF_HEADERS" },
{ MEMORY, "MEMORY" },
{ DEFINED, "DEFINED" },
{ TARGET_K, "TARGET" },
{ SEARCH_DIR, "SEARCH_DIR" },
{ MAP, "MAP" },
{ ENTRY, "ENTRY" },
{ 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 = ARRAY_SIZE (table); idx--;)
{
if (table[idx].code == code)
{
fprintf (config.map_file, " %s ", table[idx].name);
return;
}
}
/* Not in table, just print it alone. */
if (code < 127)
fprintf (config.map_file, " %c ", code);
else
fprintf (config.map_file, " <code %d> ", code);
}
static void
make_abs (ptr)
etree_value_type *ptr;
{
asection *s = ptr->section->bfd_section;
ptr->value += s->vma;
ptr->section = abs_output_section;
}
static etree_value_type
new_abs (value)
bfd_vma value;
{
etree_value_type new;
new.valid_p = true;
new.section = abs_output_section;
new.value = value;
return new;
}
static void
check (os, name, op)
lang_output_section_statement_type *os;
const char *name;
const char *op;
{
if (os == NULL)
einfo (_("%F%P: %s uses undefined section %s\n"), op, name);
if (! os->processed)
einfo (_("%F%P: %s forward reference of section %s\n"), op, name);
}
etree_type *
exp_intop (value)
bfd_vma 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. */
etree_type *
exp_relop (section, value)
asection *section;
bfd_vma value;
{
etree_type *new = (etree_type *) stat_alloc (sizeof (new->rel));
new->type.node_code = REL;
new->type.node_class = etree_rel;
new->rel.section = section;
new->rel.value = value;
return new;
}
static etree_value_type
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;
}
static etree_value_type
new_rel_from_section (value, section)
bfd_vma value;
lang_output_section_statement_type *section;
{
etree_value_type new;
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_binary (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->binary.lhs, current_section,
allocation_done, dot, dotp);
if (result.valid_p)
{
etree_value_type other;
other = exp_fold_tree (tree->binary.rhs,
current_section,
allocation_done, dot, dotp);
if (other.valid_p)
{
/* If the values are from different sections, or this is an
absolute expression, make both the source arguments
absolute. However, adding or subtracting an absolute
value from a relative value is meaningful, and is an
exception. */
if (current_section != abs_output_section
&& (other.section == abs_output_section
|| (result.section == abs_output_section
&& tree->type.node_code == '+'))
&& (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;
}
}
else if (result.section != other.section
|| current_section == abs_output_section)
{
make_abs (&result);
make_abs (&other);
}
switch (tree->type.node_code)
{
case '%':
if (other.value == 0)
einfo (_("%F%S %% by zero\n"));
result.value = ((bfd_signed_vma) result.value
% (bfd_signed_vma) other.value);
break;
case '/':
if (other.value == 0)
einfo (_("%F%S / by zero\n"));
result.value = ((bfd_signed_vma) result.value
/ (bfd_signed_vma) other.value);
break;
#define BOP(x,y) case x : result.value = result.value y other.value; break;
BOP ('+', +);
BOP ('*', *);
BOP ('-', -);
BOP (LSHIFT, <<);
BOP (RSHIFT, >>);
BOP (EQ, ==);
BOP (NE, !=);
BOP ('<', <);
BOP ('>', >);
BOP (LE, <=);
BOP (GE, >=);
BOP ('&', &);
BOP ('^', ^);
BOP ('|', |);
BOP (ANDAND, &&);
BOP (OROR, ||);
case MAX_K:
if (result.value < other.value)
result = other;
break;
case MIN_K:
if (result.value > other.value)
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 & (maxpage - other.value);
}
else
result.valid_p = false;
break;
default:
FAIL ();
}
}
else
{
result.valid_p = false;
}
}
return result;
}
etree_value_type
invalid ()
{
etree_value_type new;
new.valid_p = false;
return new;
}
static etree_value_type
fold_name (tree, current_section, allocation_done, dot)
etree_type *tree;
lang_output_section_statement_type *current_section;
lang_phase_type allocation_done;
bfd_vma dot;
{
etree_value_type result;
switch (tree->type.node_code)
{
case SIZEOF_HEADERS:
if (allocation_done != lang_first_phase_enum)
{
result = new_abs ((bfd_vma)
bfd_sizeof_headers (output_bfd,
link_info.relocateable));
}
else
{
result.valid_p = false;
}
break;
case DEFINED:
if (allocation_done == lang_first_phase_enum)
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);
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;
}
break;
case NAME:
result.valid_p = false;
if (tree->name.name[0] == '.' && tree->name.name[1] == 0)
{
if (allocation_done != lang_first_phase_enum)
result = new_rel_from_section (dot, current_section);
else
result = invalid ();
}
else if (allocation_done != lang_first_phase_enum)
{
struct bfd_link_hash_entry *h;
h = bfd_wrapped_link_hash_lookup (output_bfd, &link_info,
tree->name.name,
false, false, true);
if (h != NULL
&& (h->type == bfd_link_hash_defined
|| h->type == bfd_link_hash_defweak))
{
if (bfd_is_abs_section (h->u.def.section))
result = new_abs (h->u.def.value);
else if (allocation_done == lang_final_phase_enum
|| allocation_done == lang_allocating_phase_enum)
{
asection *output_section;
output_section = h->u.def.section->output_section;
if (output_section == NULL)
einfo (_("%X%S: unresolvable symbol `%s' referenced in expression\n"),
tree->name.name);
else
{
lang_output_section_statement_type *os;
os = (lang_output_section_statement_lookup
(bfd_get_section_name (output_bfd,
output_section)));
/* FIXME: Is this correct if this section is
being linked with -R? */
result = new_rel ((h->u.def.value
+ h->u.def.section->output_offset),
NULL,
os);
}
}
}
else if (allocation_done == lang_final_phase_enum)
einfo (_("%F%S: undefined symbol `%s' referenced in expression\n"),
tree->name.name);
}
break;
case ADDR:
if (allocation_done != lang_first_phase_enum)
{
lang_output_section_statement_type *os;
os = lang_output_section_find (tree->name.name);
check (os, tree->name.name, "ADDR");
result = new_rel (0, NULL, os);
}
else
result = invalid ();
break;
case LOADADDR:
if (allocation_done != lang_first_phase_enum)
{
lang_output_section_statement_type *os;
os = lang_output_section_find (tree->name.name);
check (os, tree->name.name, "LOADADDR");
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);
}
else
result = invalid ();
break;
case SIZEOF:
if (allocation_done != lang_first_phase_enum)
{
int opb = bfd_octets_per_byte (output_bfd);
lang_output_section_statement_type *os;
os = lang_output_section_find (tree->name.name);
check (os, tree->name.name, "SIZEOF");
result = new_abs (os->bfd_section->_raw_size / opb);
}
else
result = invalid ();
break;
default:
FAIL ();
break;
}
return result;
}
etree_value_type
exp_fold_tree (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;
if (tree == NULL)
{
result.valid_p = false;
return result;
}
switch (tree->type.node_class)
{
case etree_value:
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;
else
result = new_rel ((tree->rel.value
+ tree->rel.section->output_section->vma
+ tree->rel.section->output_offset),
NULL,
current_section);
break;
case etree_assert:
result = exp_fold_tree (tree->assert_s.child,
current_section,
allocation_done, dot, dotp);
if (result.valid_p)
{
if (! result.value)
einfo ("%F%P: %s\n", tree->assert_s.message);
return result;
}
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;
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;
}
}
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);
break;
case etree_binary:
result = fold_binary (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_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
&& current_section == abs_output_section))
{
result = exp_fold_tree (tree->assign.src,
current_section,
allocation_done, dot,
dotp);
if (! result.valid_p)
einfo (_("%F%S invalid assignment to location counter\n"));
else
{
if (current_section == NULL)
einfo (_("%F%S assignment to location counter invalid outside of SECTION\n"));
else
{
bfd_vma nextdot;
nextdot = (result.value
+ 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);
else
*dotp = nextdot;
}
}
}
}
else
{
result = exp_fold_tree (tree->assign.src,
current_section, allocation_done,
dot, dotp);
if (result.valid_p)
{
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, false);
if (h == (struct bfd_link_hash_entry *) NULL)
{
if (tree->type.node_class == etree_assign)
einfo (_("%P%F:%s: hash creation failed\n"),
tree->assign.dst);
}
else if (tree->type.node_class == etree_provide
&& 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? */
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:
result = fold_name (tree, current_section, allocation_done, dot);
break;
default:
FAIL ();
break;
}
return result;
}
static etree_value_type
exp_fold_tree_no_dot (tree, current_section, allocation_done)
etree_type *tree;
lang_output_section_statement_type *current_section;
lang_phase_type allocation_done;
{
return exp_fold_tree (tree, current_section, allocation_done,
(bfd_vma) 0, (bfd_vma *) NULL);
}
etree_type *
exp_binop (code, lhs, rhs)
int code;
etree_type *lhs;
etree_type *rhs;
{
etree_type value, *new;
etree_value_type r;
value.type.node_code = code;
value.binary.lhs = lhs;
value.binary.rhs = rhs;
value.type.node_class = etree_binary;
r = exp_fold_tree_no_dot (&value,
abs_output_section,
lang_first_phase_enum);
if (r.valid_p)
{
return exp_intop (r.value);
}
new = (etree_type *) stat_alloc (sizeof (new->binary));
memcpy ((char *) new, (char *) &value, sizeof (new->binary));
return new;
}
etree_type *
exp_trinop (code, cond, lhs, rhs)
int code;
etree_type *cond;
etree_type *lhs;
etree_type *rhs;
{
etree_type value, *new;
etree_value_type r;
value.type.node_code = code;
value.trinary.lhs = lhs;
value.trinary.cond = cond;
value.trinary.rhs = rhs;
value.type.node_class = etree_trinary;
r = exp_fold_tree_no_dot (&value,
(lang_output_section_statement_type *) NULL,
lang_first_phase_enum);
if (r.valid_p)
return exp_intop (r.value);
new = (etree_type *) stat_alloc (sizeof (new->trinary));
memcpy ((char *) new, (char *) &value, sizeof (new->trinary));
return new;
}
etree_type *
exp_unop (code, child)
int code;
etree_type *child;
{
etree_type value, *new;
etree_value_type r;
value.unary.type.node_code = code;
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);
if (r.valid_p)
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;
{
etree_type value, *new;
etree_value_type r;
value.name.type.node_code = code;
value.name.name = name;
value.name.type.node_class = etree_name;
r = exp_fold_tree_no_dot (&value,
(lang_output_section_statement_type *) NULL,
lang_first_phase_enum);
if (r.valid_p)
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;
etree_type *src;
{
etree_type value, *new;
value.assign.type.node_code = code;
value.assign.src = src;
value.assign.dst = dst;
value.assign.type.node_class = etree_assign;
#if 0
if (exp_fold_tree_no_dot (&value, &result))
return exp_intop (result);
#endif
new = (etree_type *) stat_alloc (sizeof (new->assign));
memcpy ((char *) new, (char *) &value, sizeof (new->assign));
return new;
}
/* Handle PROVIDE. */
etree_type *
exp_provide (dst, src)
const char *dst;
etree_type *src;
{
etree_type *n;
n = (etree_type *) stat_alloc (sizeof (n->assign));
n->assign.type.node_code = '=';
n->assign.type.node_class = etree_provide;
n->assign.src = src;
n->assign.dst = dst;
return n;
}
/* Handle ASSERT. */
etree_type *
exp_assert (exp, message)
etree_type *exp;
const char *message;
{
etree_type *n;
n = (etree_type *) stat_alloc (sizeof (n->assert_s));
n->assert_s.type.node_code = '!';
n->assert_s.type.node_class = etree_assert;
n->assert_s.child = exp;
n->assert_s.message = message;
return n;
}
void
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:
minfo ("0x%v", tree->value.value);
return;
case etree_rel:
if (tree->rel.section->owner != NULL)
minfo ("%B:", tree->rel.section->owner);
minfo ("%s+0x%v", tree->rel.section->name, tree->rel.value);
return;
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);
else
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_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, ")");
break;
case etree_binary:
fprintf (config.map_file, "(");
exp_print_tree (tree->binary.lhs);
exp_print_token (tree->type.node_code);
exp_print_tree (tree->binary.rhs);
fprintf (config.map_file, ")");
break;
case etree_trinary:
exp_print_tree (tree->trinary.cond);
fprintf (config.map_file, "?");
exp_print_tree (tree->trinary.lhs);
fprintf (config.map_file, ":");
exp_print_tree (tree->trinary.rhs);
break;
case etree_unary:
exp_print_token (tree->unary.type.node_code);
if (tree->unary.child)
{
fprintf (config.map_file, "(");
exp_print_tree (tree->unary.child);
fprintf (config.map_file, ")");
}
break;
case etree_assert:
fprintf (config.map_file, "ASSERT (");
exp_print_tree (tree->assert_s.child);
fprintf (config.map_file, ", %s)", tree->assert_s.message);
break;
case etree_undef:
fprintf (config.map_file, "????????");
break;
case etree_name:
if (tree->type.node_code == NAME)
{
fprintf (config.map_file, "%s", tree->name.name);
}
else
{
exp_print_token (tree->type.node_code);
if (tree->name.name)
fprintf (config.map_file, "(%s)", tree->name.name);
}
break;
default:
FAIL ();
break;
}
}
bfd_vma
exp_get_vma (tree, def, name, allocation_done)
etree_type *tree;
bfd_vma def;
char *name;
lang_phase_type allocation_done;
{
etree_value_type r;
if (tree != NULL)
{
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);
return r.value;
}
else
return def;
}
int
exp_get_value_int (tree, def, name, allocation_done)
etree_type *tree;
int def;
char *name;
lang_phase_type 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;
int def ATTRIBUTE_UNUSED;
char *name;
lang_phase_type allocation_done;
{
etree_value_type res;
res = exp_fold_tree_no_dot (tree, abs_output_section, allocation_done);
if (res.valid_p)
res.value += res.section->bfd_section->vma;
else
einfo (_("%F%S non constant expression for %s\n"), name);
return res.value;
}