OpenCores
URL https://opencores.org/ocsvn/open8_urisc/open8_urisc/trunk

Subversion Repositories open8_urisc

[/] [open8_urisc/] [trunk/] [gnu/] [binutils/] [ld/] [ldexp.c] - Diff between revs 145 and 166

Only display areas with differences | Details | Blame | View Log

Rev 145 Rev 166
/* This module handles expression trees.
/* This module handles expression trees.
   Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
   Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
   2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
   2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
   Free Software Foundation, Inc.
   Free Software Foundation, Inc.
   Written by Steve Chamberlain of Cygnus Support <sac@cygnus.com>.
   Written by Steve Chamberlain of Cygnus Support <sac@cygnus.com>.
 
 
   This file is part of the GNU Binutils.
   This file is part of the GNU Binutils.
 
 
   This program is free software; you can redistribute it and/or modify
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 3 of the License, or
   the Free Software Foundation; either version 3 of the License, or
   (at your option) any later version.
   (at your option) any later version.
 
 
   This program is distributed in the hope that it will be useful,
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
   GNU General Public License for more details.
 
 
   You should have received a copy of the GNU General Public License
   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   along with this program; if not, write to the Free Software
   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
   MA 02110-1301, USA.  */
   MA 02110-1301, USA.  */
 
 
 
 
/* This module is in charge of working out the contents of expressions.
/* 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
   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)
   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
   which contains a value, a section to which it is relative and a
   valid bit.  */
   valid bit.  */
 
 
#include "sysdep.h"
#include "sysdep.h"
#include "bfd.h"
#include "bfd.h"
#include "bfdlink.h"
#include "bfdlink.h"
 
 
#include "ld.h"
#include "ld.h"
#include "ldmain.h"
#include "ldmain.h"
#include "ldmisc.h"
#include "ldmisc.h"
#include "ldexp.h"
#include "ldexp.h"
#include "ldlex.h"
#include "ldlex.h"
#include <ldgram.h>
#include <ldgram.h>
#include "ldlang.h"
#include "ldlang.h"
#include "libiberty.h"
#include "libiberty.h"
#include "safe-ctype.h"
#include "safe-ctype.h"
 
 
static void exp_fold_tree_1 (etree_type *);
static void exp_fold_tree_1 (etree_type *);
static bfd_vma align_n (bfd_vma, bfd_vma);
static bfd_vma align_n (bfd_vma, bfd_vma);
 
 
segment_type *segments;
segment_type *segments;
 
 
struct ldexp_control expld;
struct ldexp_control expld;
 
 
/* Print the string representation of the given token.  Surround it
/* Print the string representation of the given token.  Surround it
   with spaces if INFIX_P is TRUE.  */
   with spaces if INFIX_P is TRUE.  */
 
 
static void
static void
exp_print_token (token_code_type code, int infix_p)
exp_print_token (token_code_type code, int infix_p)
{
{
  static const struct
  static const struct
  {
  {
    token_code_type code;
    token_code_type code;
    char * name;
    char * name;
  }
  }
  table[] =
  table[] =
  {
  {
    { INT, "int" },
    { INT, "int" },
    { NAME, "NAME" },
    { NAME, "NAME" },
    { PLUSEQ, "+=" },
    { PLUSEQ, "+=" },
    { MINUSEQ, "-=" },
    { MINUSEQ, "-=" },
    { MULTEQ, "*=" },
    { MULTEQ, "*=" },
    { DIVEQ, "/=" },
    { DIVEQ, "/=" },
    { LSHIFTEQ, "<<=" },
    { LSHIFTEQ, "<<=" },
    { RSHIFTEQ, ">>=" },
    { RSHIFTEQ, ">>=" },
    { ANDEQ, "&=" },
    { ANDEQ, "&=" },
    { OREQ, "|=" },
    { OREQ, "|=" },
    { OROR, "||" },
    { OROR, "||" },
    { ANDAND, "&&" },
    { ANDAND, "&&" },
    { EQ, "==" },
    { EQ, "==" },
    { NE, "!=" },
    { NE, "!=" },
    { LE, "<=" },
    { LE, "<=" },
    { GE, ">=" },
    { GE, ">=" },
    { LSHIFT, "<<" },
    { LSHIFT, "<<" },
    { RSHIFT, ">>" },
    { RSHIFT, ">>" },
    { ALIGN_K, "ALIGN" },
    { ALIGN_K, "ALIGN" },
    { BLOCK, "BLOCK" },
    { BLOCK, "BLOCK" },
    { QUAD, "QUAD" },
    { QUAD, "QUAD" },
    { SQUAD, "SQUAD" },
    { SQUAD, "SQUAD" },
    { LONG, "LONG" },
    { LONG, "LONG" },
    { SHORT, "SHORT" },
    { SHORT, "SHORT" },
    { BYTE, "BYTE" },
    { BYTE, "BYTE" },
    { SECTIONS, "SECTIONS" },
    { SECTIONS, "SECTIONS" },
    { SIZEOF_HEADERS, "SIZEOF_HEADERS" },
    { SIZEOF_HEADERS, "SIZEOF_HEADERS" },
    { MEMORY, "MEMORY" },
    { MEMORY, "MEMORY" },
    { DEFINED, "DEFINED" },
    { DEFINED, "DEFINED" },
    { TARGET_K, "TARGET" },
    { TARGET_K, "TARGET" },
    { SEARCH_DIR, "SEARCH_DIR" },
    { SEARCH_DIR, "SEARCH_DIR" },
    { MAP, "MAP" },
    { MAP, "MAP" },
    { ENTRY, "ENTRY" },
    { ENTRY, "ENTRY" },
    { NEXT, "NEXT" },
    { NEXT, "NEXT" },
    { ALIGNOF, "ALIGNOF" },
    { ALIGNOF, "ALIGNOF" },
    { SIZEOF, "SIZEOF" },
    { SIZEOF, "SIZEOF" },
    { ADDR, "ADDR" },
    { ADDR, "ADDR" },
    { LOADADDR, "LOADADDR" },
    { LOADADDR, "LOADADDR" },
    { CONSTANT, "CONSTANT" },
    { CONSTANT, "CONSTANT" },
    { ABSOLUTE, "ABSOLUTE" },
    { ABSOLUTE, "ABSOLUTE" },
    { MAX_K, "MAX" },
    { MAX_K, "MAX" },
    { MIN_K, "MIN" },
    { MIN_K, "MIN" },
    { ASSERT_K, "ASSERT" },
    { ASSERT_K, "ASSERT" },
    { REL, "relocatable" },
    { REL, "relocatable" },
    { DATA_SEGMENT_ALIGN, "DATA_SEGMENT_ALIGN" },
    { DATA_SEGMENT_ALIGN, "DATA_SEGMENT_ALIGN" },
    { DATA_SEGMENT_RELRO_END, "DATA_SEGMENT_RELRO_END" },
    { DATA_SEGMENT_RELRO_END, "DATA_SEGMENT_RELRO_END" },
    { DATA_SEGMENT_END, "DATA_SEGMENT_END" },
    { DATA_SEGMENT_END, "DATA_SEGMENT_END" },
    { ORIGIN, "ORIGIN" },
    { ORIGIN, "ORIGIN" },
    { LENGTH, "LENGTH" },
    { LENGTH, "LENGTH" },
    { SEGMENT_START, "SEGMENT_START" }
    { SEGMENT_START, "SEGMENT_START" }
  };
  };
  unsigned int idx;
  unsigned int idx;
 
 
  for (idx = 0; idx < ARRAY_SIZE (table); idx++)
  for (idx = 0; idx < ARRAY_SIZE (table); idx++)
    if (table[idx].code == code)
    if (table[idx].code == code)
      break;
      break;
 
 
  if (infix_p)
  if (infix_p)
    fputc (' ', config.map_file);
    fputc (' ', config.map_file);
 
 
  if (idx < ARRAY_SIZE (table))
  if (idx < ARRAY_SIZE (table))
    fputs (table[idx].name, config.map_file);
    fputs (table[idx].name, config.map_file);
  else if (code < 127)
  else if (code < 127)
    fputc (code, config.map_file);
    fputc (code, config.map_file);
  else
  else
    fprintf (config.map_file, "<code %d>", code);
    fprintf (config.map_file, "<code %d>", code);
 
 
  if (infix_p)
  if (infix_p)
    fputc (' ', config.map_file);
    fputc (' ', config.map_file);
}
}
 
 
static void
static void
make_abs (void)
make_abs (void)
{
{
  if (expld.result.section != NULL)
  if (expld.result.section != NULL)
    expld.result.value += expld.result.section->vma;
    expld.result.value += expld.result.section->vma;
  expld.result.section = bfd_abs_section_ptr;
  expld.result.section = bfd_abs_section_ptr;
}
}
 
 
static void
static void
new_abs (bfd_vma value)
new_abs (bfd_vma value)
{
{
  expld.result.valid_p = TRUE;
  expld.result.valid_p = TRUE;
  expld.result.section = bfd_abs_section_ptr;
  expld.result.section = bfd_abs_section_ptr;
  expld.result.value = value;
  expld.result.value = value;
  expld.result.str = NULL;
  expld.result.str = NULL;
}
}
 
 
etree_type *
etree_type *
exp_intop (bfd_vma value)
exp_intop (bfd_vma value)
{
{
  etree_type *new_e = (etree_type *) stat_alloc (sizeof (new_e->value));
  etree_type *new_e = (etree_type *) stat_alloc (sizeof (new_e->value));
  new_e->type.node_code = INT;
  new_e->type.node_code = INT;
 
  new_e->type.filename = ldlex_filename ();
  new_e->type.lineno = lineno;
  new_e->type.lineno = lineno;
  new_e->value.value = value;
  new_e->value.value = value;
  new_e->value.str = NULL;
  new_e->value.str = NULL;
  new_e->type.node_class = etree_value;
  new_e->type.node_class = etree_value;
  return new_e;
  return new_e;
}
}
 
 
etree_type *
etree_type *
exp_bigintop (bfd_vma value, char *str)
exp_bigintop (bfd_vma value, char *str)
{
{
  etree_type *new_e = (etree_type *) stat_alloc (sizeof (new_e->value));
  etree_type *new_e = (etree_type *) stat_alloc (sizeof (new_e->value));
  new_e->type.node_code = INT;
  new_e->type.node_code = INT;
 
  new_e->type.filename = ldlex_filename ();
  new_e->type.lineno = lineno;
  new_e->type.lineno = lineno;
  new_e->value.value = value;
  new_e->value.value = value;
  new_e->value.str = str;
  new_e->value.str = str;
  new_e->type.node_class = etree_value;
  new_e->type.node_class = etree_value;
  return new_e;
  return new_e;
}
}
 
 
/* Build an expression representing an unnamed relocatable value.  */
/* Build an expression representing an unnamed relocatable value.  */
 
 
etree_type *
etree_type *
exp_relop (asection *section, bfd_vma value)
exp_relop (asection *section, bfd_vma value)
{
{
  etree_type *new_e = (etree_type *) stat_alloc (sizeof (new_e->rel));
  etree_type *new_e = (etree_type *) stat_alloc (sizeof (new_e->rel));
  new_e->type.node_code = REL;
  new_e->type.node_code = REL;
 
  new_e->type.filename = ldlex_filename ();
  new_e->type.lineno = lineno;
  new_e->type.lineno = lineno;
  new_e->type.node_class = etree_rel;
  new_e->type.node_class = etree_rel;
  new_e->rel.section = section;
  new_e->rel.section = section;
  new_e->rel.value = value;
  new_e->rel.value = value;
  return new_e;
  return new_e;
}
}
 
 
static void
static void
new_number (bfd_vma value)
new_number (bfd_vma value)
{
{
  expld.result.valid_p = TRUE;
  expld.result.valid_p = TRUE;
  expld.result.value = value;
  expld.result.value = value;
  expld.result.str = NULL;
  expld.result.str = NULL;
  expld.result.section = NULL;
  expld.result.section = NULL;
}
}
 
 
static void
static void
new_rel (bfd_vma value, asection *section)
new_rel (bfd_vma value, asection *section)
{
{
  expld.result.valid_p = TRUE;
  expld.result.valid_p = TRUE;
  expld.result.value = value;
  expld.result.value = value;
  expld.result.str = NULL;
  expld.result.str = NULL;
  expld.result.section = section;
  expld.result.section = section;
}
}
 
 
static void
static void
new_rel_from_abs (bfd_vma value)
new_rel_from_abs (bfd_vma value)
{
{
  expld.result.valid_p = TRUE;
  expld.result.valid_p = TRUE;
  expld.result.value = value - expld.section->vma;
  expld.result.value = value - expld.section->vma;
  expld.result.str = NULL;
  expld.result.str = NULL;
  expld.result.section = expld.section;
  expld.result.section = expld.section;
}
}
 
 
static void
static void
fold_unary (etree_type *tree)
fold_unary (etree_type *tree)
{
{
  exp_fold_tree_1 (tree->unary.child);
  exp_fold_tree_1 (tree->unary.child);
  if (expld.result.valid_p)
  if (expld.result.valid_p)
    {
    {
      switch (tree->type.node_code)
      switch (tree->type.node_code)
        {
        {
        case ALIGN_K:
        case ALIGN_K:
          if (expld.phase != lang_first_phase_enum)
          if (expld.phase != lang_first_phase_enum)
            new_rel_from_abs (align_n (expld.dot, expld.result.value));
            new_rel_from_abs (align_n (expld.dot, expld.result.value));
          else
          else
            expld.result.valid_p = FALSE;
            expld.result.valid_p = FALSE;
          break;
          break;
 
 
        case ABSOLUTE:
        case ABSOLUTE:
          make_abs ();
          make_abs ();
          break;
          break;
 
 
        case '~':
        case '~':
          expld.result.value = ~expld.result.value;
          expld.result.value = ~expld.result.value;
          break;
          break;
 
 
        case '!':
        case '!':
          expld.result.value = !expld.result.value;
          expld.result.value = !expld.result.value;
          break;
          break;
 
 
        case '-':
        case '-':
          expld.result.value = -expld.result.value;
          expld.result.value = -expld.result.value;
          break;
          break;
 
 
        case NEXT:
        case NEXT:
          /* Return next place aligned to value.  */
          /* Return next place aligned to value.  */
          if (expld.phase != lang_first_phase_enum)
          if (expld.phase != lang_first_phase_enum)
            {
            {
              make_abs ();
              make_abs ();
              expld.result.value = align_n (expld.dot, expld.result.value);
              expld.result.value = align_n (expld.dot, expld.result.value);
            }
            }
          else
          else
            expld.result.valid_p = FALSE;
            expld.result.valid_p = FALSE;
          break;
          break;
 
 
        case DATA_SEGMENT_END:
        case DATA_SEGMENT_END:
          if (expld.phase == lang_first_phase_enum
          if (expld.phase == lang_first_phase_enum
              || expld.section != bfd_abs_section_ptr)
              || expld.section != bfd_abs_section_ptr)
            {
            {
              expld.result.valid_p = FALSE;
              expld.result.valid_p = FALSE;
            }
            }
          else if (expld.dataseg.phase == exp_dataseg_align_seen
          else if (expld.dataseg.phase == exp_dataseg_align_seen
                   || expld.dataseg.phase == exp_dataseg_relro_seen)
                   || expld.dataseg.phase == exp_dataseg_relro_seen)
            {
            {
              expld.dataseg.phase = exp_dataseg_end_seen;
              expld.dataseg.phase = exp_dataseg_end_seen;
              expld.dataseg.end = expld.result.value;
              expld.dataseg.end = expld.result.value;
            }
            }
          else if (expld.dataseg.phase == exp_dataseg_done
          else if (expld.dataseg.phase == exp_dataseg_done
                   || expld.dataseg.phase == exp_dataseg_adjust
                   || expld.dataseg.phase == exp_dataseg_adjust
                   || expld.dataseg.phase == exp_dataseg_relro_adjust)
                   || expld.dataseg.phase == exp_dataseg_relro_adjust)
            {
            {
              /* OK.  */
              /* OK.  */
            }
            }
          else
          else
            expld.result.valid_p = FALSE;
            expld.result.valid_p = FALSE;
          break;
          break;
 
 
        default:
        default:
          FAIL ();
          FAIL ();
          break;
          break;
        }
        }
    }
    }
}
}
 
 
static void
static void
fold_binary (etree_type *tree)
fold_binary (etree_type *tree)
{
{
  etree_value_type lhs;
  etree_value_type lhs;
  exp_fold_tree_1 (tree->binary.lhs);
  exp_fold_tree_1 (tree->binary.lhs);
 
 
  /* The SEGMENT_START operator is special because its first
  /* The SEGMENT_START operator is special because its first
     operand is a string, not the name of a symbol.  Note that the
     operand is a string, not the name of a symbol.  Note that the
     operands have been swapped, so binary.lhs is second (default)
     operands have been swapped, so binary.lhs is second (default)
     operand, binary.rhs is first operand.  */
     operand, binary.rhs is first operand.  */
  if (expld.result.valid_p && tree->type.node_code == SEGMENT_START)
  if (expld.result.valid_p && tree->type.node_code == SEGMENT_START)
    {
    {
      const char *segment_name;
      const char *segment_name;
      segment_type *seg;
      segment_type *seg;
 
 
      /* Check to see if the user has overridden the default
      /* Check to see if the user has overridden the default
         value.  */
         value.  */
      segment_name = tree->binary.rhs->name.name;
      segment_name = tree->binary.rhs->name.name;
      for (seg = segments; seg; seg = seg->next)
      for (seg = segments; seg; seg = seg->next)
        if (strcmp (seg->name, segment_name) == 0)
        if (strcmp (seg->name, segment_name) == 0)
          {
          {
            if (!seg->used
            if (!seg->used
                && config.magic_demand_paged
                && config.magic_demand_paged
                && (seg->value % config.maxpagesize) != 0)
                && (seg->value % config.maxpagesize) != 0)
              einfo (_("%P: warning: address of `%s' isn't multiple of maximum page size\n"),
              einfo (_("%P: warning: address of `%s' isn't multiple of maximum page size\n"),
                     segment_name);
                     segment_name);
            seg->used = TRUE;
            seg->used = TRUE;
            new_rel_from_abs (seg->value);
            new_rel_from_abs (seg->value);
            break;
            break;
          }
          }
      return;
      return;
    }
    }
 
 
  lhs = expld.result;
  lhs = expld.result;
  exp_fold_tree_1 (tree->binary.rhs);
  exp_fold_tree_1 (tree->binary.rhs);
  expld.result.valid_p &= lhs.valid_p;
  expld.result.valid_p &= lhs.valid_p;
 
 
  if (expld.result.valid_p)
  if (expld.result.valid_p)
    {
    {
      if (lhs.section != expld.result.section)
      if (lhs.section != expld.result.section)
        {
        {
          /* If the values are from different sections, and neither is
          /* If the values are from different sections, and neither is
             just a number, make both the source arguments absolute.  */
             just a number, make both the source arguments absolute.  */
          if (expld.result.section != NULL
          if (expld.result.section != NULL
              && lhs.section != NULL)
              && lhs.section != NULL)
            {
            {
              make_abs ();
              make_abs ();
              lhs.value += lhs.section->vma;
              lhs.value += lhs.section->vma;
              lhs.section = bfd_abs_section_ptr;
              lhs.section = bfd_abs_section_ptr;
            }
            }
 
 
          /* If the rhs is just a number, keep the lhs section.  */
          /* If the rhs is just a number, keep the lhs section.  */
          else if (expld.result.section == NULL)
          else if (expld.result.section == NULL)
            {
            {
              expld.result.section = lhs.section;
              expld.result.section = lhs.section;
              /* Make this NULL so that we know one of the operands
              /* Make this NULL so that we know one of the operands
                 was just a number, for later tests.  */
                 was just a number, for later tests.  */
              lhs.section = NULL;
              lhs.section = NULL;
            }
            }
        }
        }
      /* At this point we know that both operands have the same
      /* At this point we know that both operands have the same
         section, or at least one of them is a plain number.  */
         section, or at least one of them is a plain number.  */
 
 
      switch (tree->type.node_code)
      switch (tree->type.node_code)
        {
        {
          /* Arithmetic operators, bitwise AND, bitwise OR and XOR
          /* Arithmetic operators, bitwise AND, bitwise OR and XOR
             keep the section of one of their operands only when the
             keep the section of one of their operands only when the
             other operand is a plain number.  Losing the section when
             other operand is a plain number.  Losing the section when
             operating on two symbols, ie. a result of a plain number,
             operating on two symbols, ie. a result of a plain number,
             is required for subtraction and XOR.  It's justifiable
             is required for subtraction and XOR.  It's justifiable
             for the other operations on the grounds that adding,
             for the other operations on the grounds that adding,
             multiplying etc. two section relative values does not
             multiplying etc. two section relative values does not
             really make sense unless they are just treated as
             really make sense unless they are just treated as
             numbers.
             numbers.
             The same argument could be made for many expressions
             The same argument could be made for many expressions
             involving one symbol and a number.  For example,
             involving one symbol and a number.  For example,
             "1 << x" and "100 / x" probably should not be given the
             "1 << x" and "100 / x" probably should not be given the
             section of x.  The trouble is that if we fuss about such
             section of x.  The trouble is that if we fuss about such
             things the rules become complex and it is onerous to
             things the rules become complex and it is onerous to
             document ld expression evaluation.  */
             document ld expression evaluation.  */
#define BOP(x, y) \
#define BOP(x, y) \
        case x:                                                 \
        case x:                                                 \
          expld.result.value = lhs.value y expld.result.value;  \
          expld.result.value = lhs.value y expld.result.value;  \
          if (expld.result.section == lhs.section)              \
          if (expld.result.section == lhs.section)              \
            expld.result.section = NULL;                        \
            expld.result.section = NULL;                        \
          break;
          break;
 
 
          /* Comparison operators, logical AND, and logical OR always
          /* Comparison operators, logical AND, and logical OR always
             return a plain number.  */
             return a plain number.  */
#define BOPN(x, y) \
#define BOPN(x, y) \
        case x:                                                 \
        case x:                                                 \
          expld.result.value = lhs.value y expld.result.value;  \
          expld.result.value = lhs.value y expld.result.value;  \
          expld.result.section = NULL;                          \
          expld.result.section = NULL;                          \
          break;
          break;
 
 
          BOP ('+', +);
          BOP ('+', +);
          BOP ('*', *);
          BOP ('*', *);
          BOP ('-', -);
          BOP ('-', -);
          BOP (LSHIFT, <<);
          BOP (LSHIFT, <<);
          BOP (RSHIFT, >>);
          BOP (RSHIFT, >>);
          BOP ('&', &);
          BOP ('&', &);
          BOP ('^', ^);
          BOP ('^', ^);
          BOP ('|', |);
          BOP ('|', |);
          BOPN (EQ, ==);
          BOPN (EQ, ==);
          BOPN (NE, !=);
          BOPN (NE, !=);
          BOPN ('<', <);
          BOPN ('<', <);
          BOPN ('>', >);
          BOPN ('>', >);
          BOPN (LE, <=);
          BOPN (LE, <=);
          BOPN (GE, >=);
          BOPN (GE, >=);
          BOPN (ANDAND, &&);
          BOPN (ANDAND, &&);
          BOPN (OROR, ||);
          BOPN (OROR, ||);
 
 
        case '%':
        case '%':
          if (expld.result.value != 0)
          if (expld.result.value != 0)
            expld.result.value = ((bfd_signed_vma) lhs.value
            expld.result.value = ((bfd_signed_vma) lhs.value
                                  % (bfd_signed_vma) expld.result.value);
                                  % (bfd_signed_vma) expld.result.value);
          else if (expld.phase != lang_mark_phase_enum)
          else if (expld.phase != lang_mark_phase_enum)
            einfo (_("%F%S %% by zero\n"));
            einfo (_("%F%S %% by zero\n"), tree->binary.rhs);
          if (expld.result.section == lhs.section)
          if (expld.result.section == lhs.section)
            expld.result.section = NULL;
            expld.result.section = NULL;
          break;
          break;
 
 
        case '/':
        case '/':
          if (expld.result.value != 0)
          if (expld.result.value != 0)
            expld.result.value = ((bfd_signed_vma) lhs.value
            expld.result.value = ((bfd_signed_vma) lhs.value
                                  / (bfd_signed_vma) expld.result.value);
                                  / (bfd_signed_vma) expld.result.value);
          else if (expld.phase != lang_mark_phase_enum)
          else if (expld.phase != lang_mark_phase_enum)
            einfo (_("%F%S / by zero\n"));
            einfo (_("%F%S / by zero\n"), tree->binary.rhs);
          if (expld.result.section == lhs.section)
          if (expld.result.section == lhs.section)
            expld.result.section = NULL;
            expld.result.section = NULL;
          break;
          break;
 
 
        case MAX_K:
        case MAX_K:
          if (lhs.value > expld.result.value)
          if (lhs.value > expld.result.value)
            expld.result.value = lhs.value;
            expld.result.value = lhs.value;
          break;
          break;
 
 
        case MIN_K:
        case MIN_K:
          if (lhs.value < expld.result.value)
          if (lhs.value < expld.result.value)
            expld.result.value = lhs.value;
            expld.result.value = lhs.value;
          break;
          break;
 
 
        case ALIGN_K:
        case ALIGN_K:
          expld.result.value = align_n (lhs.value, expld.result.value);
          expld.result.value = align_n (lhs.value, expld.result.value);
          break;
          break;
 
 
        case DATA_SEGMENT_ALIGN:
        case DATA_SEGMENT_ALIGN:
          expld.dataseg.relro = exp_dataseg_relro_start;
          expld.dataseg.relro = exp_dataseg_relro_start;
          if (expld.phase == lang_first_phase_enum
          if (expld.phase == lang_first_phase_enum
              || expld.section != bfd_abs_section_ptr)
              || expld.section != bfd_abs_section_ptr)
            expld.result.valid_p = FALSE;
            expld.result.valid_p = FALSE;
          else
          else
            {
            {
              bfd_vma maxpage = lhs.value;
              bfd_vma maxpage = lhs.value;
              bfd_vma commonpage = expld.result.value;
              bfd_vma commonpage = expld.result.value;
 
 
              expld.result.value = align_n (expld.dot, maxpage);
              expld.result.value = align_n (expld.dot, maxpage);
              if (expld.dataseg.phase == exp_dataseg_relro_adjust)
              if (expld.dataseg.phase == exp_dataseg_relro_adjust)
                expld.result.value = expld.dataseg.base;
                expld.result.value = expld.dataseg.base;
              else if (expld.dataseg.phase == exp_dataseg_adjust)
              else if (expld.dataseg.phase == exp_dataseg_adjust)
                {
                {
                  if (commonpage < maxpage)
                  if (commonpage < maxpage)
                    expld.result.value += ((expld.dot + commonpage - 1)
                    expld.result.value += ((expld.dot + commonpage - 1)
                                           & (maxpage - commonpage));
                                           & (maxpage - commonpage));
                }
                }
              else
              else
                {
                {
                  expld.result.value += expld.dot & (maxpage - 1);
                  expld.result.value += expld.dot & (maxpage - 1);
                  if (expld.dataseg.phase == exp_dataseg_done)
                  if (expld.dataseg.phase == exp_dataseg_done)
                    {
                    {
                      /* OK.  */
                      /* OK.  */
                    }
                    }
                  else if (expld.dataseg.phase == exp_dataseg_none)
                  else if (expld.dataseg.phase == exp_dataseg_none)
                    {
                    {
                      expld.dataseg.phase = exp_dataseg_align_seen;
                      expld.dataseg.phase = exp_dataseg_align_seen;
                      expld.dataseg.min_base = expld.dot;
                      expld.dataseg.min_base = expld.dot;
                      expld.dataseg.base = expld.result.value;
                      expld.dataseg.base = expld.result.value;
                      expld.dataseg.pagesize = commonpage;
                      expld.dataseg.pagesize = commonpage;
                      expld.dataseg.maxpagesize = maxpage;
                      expld.dataseg.maxpagesize = maxpage;
                      expld.dataseg.relro_end = 0;
                      expld.dataseg.relro_end = 0;
                    }
                    }
                  else
                  else
                    expld.result.valid_p = FALSE;
                    expld.result.valid_p = FALSE;
                }
                }
            }
            }
          break;
          break;
 
 
        case DATA_SEGMENT_RELRO_END:
        case DATA_SEGMENT_RELRO_END:
          expld.dataseg.relro = exp_dataseg_relro_end;
          expld.dataseg.relro = exp_dataseg_relro_end;
          if (expld.phase == lang_first_phase_enum
          if (expld.phase == lang_first_phase_enum
              || expld.section != bfd_abs_section_ptr)
              || expld.section != bfd_abs_section_ptr)
            expld.result.valid_p = FALSE;
            expld.result.valid_p = FALSE;
          else if (expld.dataseg.phase == exp_dataseg_align_seen
          else if (expld.dataseg.phase == exp_dataseg_align_seen
                   || expld.dataseg.phase == exp_dataseg_adjust
                   || expld.dataseg.phase == exp_dataseg_adjust
                   || expld.dataseg.phase == exp_dataseg_relro_adjust
                   || expld.dataseg.phase == exp_dataseg_relro_adjust
                   || expld.dataseg.phase == exp_dataseg_done)
                   || expld.dataseg.phase == exp_dataseg_done)
            {
            {
              if (expld.dataseg.phase == exp_dataseg_align_seen
              if (expld.dataseg.phase == exp_dataseg_align_seen
                  || expld.dataseg.phase == exp_dataseg_relro_adjust)
                  || expld.dataseg.phase == exp_dataseg_relro_adjust)
                expld.dataseg.relro_end = lhs.value + expld.result.value;
                expld.dataseg.relro_end = lhs.value + expld.result.value;
 
 
              if (expld.dataseg.phase == exp_dataseg_relro_adjust
              if (expld.dataseg.phase == exp_dataseg_relro_adjust
                  && (expld.dataseg.relro_end
                  && (expld.dataseg.relro_end
                      & (expld.dataseg.pagesize - 1)))
                      & (expld.dataseg.pagesize - 1)))
                {
                {
                  expld.dataseg.relro_end += expld.dataseg.pagesize - 1;
                  expld.dataseg.relro_end += expld.dataseg.pagesize - 1;
                  expld.dataseg.relro_end &= ~(expld.dataseg.pagesize - 1);
                  expld.dataseg.relro_end &= ~(expld.dataseg.pagesize - 1);
                  expld.result.value = (expld.dataseg.relro_end
                  expld.result.value = (expld.dataseg.relro_end
                                        - expld.result.value);
                                        - expld.result.value);
                }
                }
              else
              else
                expld.result.value = lhs.value;
                expld.result.value = lhs.value;
 
 
              if (expld.dataseg.phase == exp_dataseg_align_seen)
              if (expld.dataseg.phase == exp_dataseg_align_seen)
                expld.dataseg.phase = exp_dataseg_relro_seen;
                expld.dataseg.phase = exp_dataseg_relro_seen;
            }
            }
          else
          else
            expld.result.valid_p = FALSE;
            expld.result.valid_p = FALSE;
          break;
          break;
 
 
        default:
        default:
          FAIL ();
          FAIL ();
        }
        }
    }
    }
}
}
 
 
static void
static void
fold_trinary (etree_type *tree)
fold_trinary (etree_type *tree)
{
{
  exp_fold_tree_1 (tree->trinary.cond);
  exp_fold_tree_1 (tree->trinary.cond);
  if (expld.result.valid_p)
  if (expld.result.valid_p)
    exp_fold_tree_1 (expld.result.value
    exp_fold_tree_1 (expld.result.value
                     ? tree->trinary.lhs
                     ? tree->trinary.lhs
                     : tree->trinary.rhs);
                     : tree->trinary.rhs);
}
}
 
 
static void
static void
fold_name (etree_type *tree)
fold_name (etree_type *tree)
{
{
  memset (&expld.result, 0, sizeof (expld.result));
  memset (&expld.result, 0, sizeof (expld.result));
 
 
  switch (tree->type.node_code)
  switch (tree->type.node_code)
    {
    {
    case SIZEOF_HEADERS:
    case SIZEOF_HEADERS:
      if (expld.phase != lang_first_phase_enum)
      if (expld.phase != lang_first_phase_enum)
        {
        {
          bfd_vma hdr_size = 0;
          bfd_vma hdr_size = 0;
          /* Don't find the real header size if only marking sections;
          /* Don't find the real header size if only marking sections;
             The bfd function may cache incorrect data.  */
             The bfd function may cache incorrect data.  */
          if (expld.phase != lang_mark_phase_enum)
          if (expld.phase != lang_mark_phase_enum)
            hdr_size = bfd_sizeof_headers (link_info.output_bfd, &link_info);
            hdr_size = bfd_sizeof_headers (link_info.output_bfd, &link_info);
          new_number (hdr_size);
          new_number (hdr_size);
        }
        }
      break;
      break;
 
 
    case DEFINED:
    case DEFINED:
      if (expld.phase == lang_first_phase_enum)
      if (expld.phase == lang_first_phase_enum)
        lang_track_definedness (tree->name.name);
        lang_track_definedness (tree->name.name);
      else
      else
        {
        {
          struct bfd_link_hash_entry *h;
          struct bfd_link_hash_entry *h;
          int def_iteration
          int def_iteration
            = lang_symbol_definition_iteration (tree->name.name);
            = lang_symbol_definition_iteration (tree->name.name);
 
 
          h = bfd_wrapped_link_hash_lookup (link_info.output_bfd,
          h = bfd_wrapped_link_hash_lookup (link_info.output_bfd,
                                            &link_info,
                                            &link_info,
                                            tree->name.name,
                                            tree->name.name,
                                            FALSE, FALSE, TRUE);
                                            FALSE, FALSE, TRUE);
          new_number (h != NULL
          new_number (h != NULL
                      && (h->type == bfd_link_hash_defined
                      && (h->type == bfd_link_hash_defined
                          || h->type == bfd_link_hash_defweak
                          || h->type == bfd_link_hash_defweak
                          || h->type == bfd_link_hash_common)
                          || h->type == bfd_link_hash_common)
                      && (def_iteration == lang_statement_iteration
                      && (def_iteration == lang_statement_iteration
                          || def_iteration == -1));
                          || def_iteration == -1));
        }
        }
      break;
      break;
 
 
    case NAME:
    case NAME:
      if (expld.phase == lang_first_phase_enum)
      if (expld.phase == lang_first_phase_enum)
        ;
        ;
      else if (tree->name.name[0] == '.' && tree->name.name[1] == 0)
      else if (tree->name.name[0] == '.' && tree->name.name[1] == 0)
        new_rel_from_abs (expld.dot);
        new_rel_from_abs (expld.dot);
      else
      else
        {
        {
          struct bfd_link_hash_entry *h;
          struct bfd_link_hash_entry *h;
 
 
          h = bfd_wrapped_link_hash_lookup (link_info.output_bfd,
          h = bfd_wrapped_link_hash_lookup (link_info.output_bfd,
                                            &link_info,
                                            &link_info,
                                            tree->name.name,
                                            tree->name.name,
                                            TRUE, FALSE, TRUE);
                                            TRUE, FALSE, TRUE);
          if (!h)
          if (!h)
            einfo (_("%P%F: bfd_link_hash_lookup failed: %E\n"));
            einfo (_("%P%F: bfd_link_hash_lookup failed: %E\n"));
          else if (h->type == bfd_link_hash_defined
          else if (h->type == bfd_link_hash_defined
                   || h->type == bfd_link_hash_defweak)
                   || h->type == bfd_link_hash_defweak)
            {
            {
              asection *output_section;
              asection *output_section;
 
 
              output_section = h->u.def.section->output_section;
              output_section = h->u.def.section->output_section;
              if (output_section == NULL)
              if (output_section == NULL)
                {
                {
                  if (expld.phase != lang_mark_phase_enum)
                  if (expld.phase == lang_mark_phase_enum)
 
                    new_rel (h->u.def.value, h->u.def.section);
 
                  else
                    einfo (_("%X%S: unresolvable symbol `%s'"
                    einfo (_("%X%S: unresolvable symbol `%s'"
                             " referenced in expression\n"),
                             " referenced in expression\n"),
                           tree->name.name);
                           tree, tree->name.name);
                }
                }
              else if (output_section == bfd_abs_section_ptr
              else if (output_section == bfd_abs_section_ptr
                       && (expld.section != bfd_abs_section_ptr
                       && (expld.section != bfd_abs_section_ptr
                           || config.sane_expr))
                           || config.sane_expr))
                new_number (h->u.def.value + h->u.def.section->output_offset);
                new_number (h->u.def.value + h->u.def.section->output_offset);
              else
              else
                new_rel (h->u.def.value + h->u.def.section->output_offset,
                new_rel (h->u.def.value + h->u.def.section->output_offset,
                         output_section);
                         output_section);
            }
            }
          else if (expld.phase == lang_final_phase_enum
          else if (expld.phase == lang_final_phase_enum
                   || expld.assigning_to_dot)
                   || expld.assigning_to_dot)
            einfo (_("%F%S: undefined symbol `%s' referenced in expression\n"),
            einfo (_("%F%S: undefined symbol `%s'"
                   tree->name.name);
                     " referenced in expression\n"),
 
                   tree, tree->name.name);
          else if (h->type == bfd_link_hash_new)
          else if (h->type == bfd_link_hash_new)
            {
            {
              h->type = bfd_link_hash_undefined;
              h->type = bfd_link_hash_undefined;
              h->u.undef.abfd = NULL;
              h->u.undef.abfd = NULL;
              if (h->u.undef.next == NULL && h != link_info.hash->undefs_tail)
              if (h->u.undef.next == NULL && h != link_info.hash->undefs_tail)
                bfd_link_add_undef (link_info.hash, h);
                bfd_link_add_undef (link_info.hash, h);
            }
            }
        }
        }
      break;
      break;
 
 
    case ADDR:
    case ADDR:
      if (expld.phase != lang_first_phase_enum)
      if (expld.phase != lang_first_phase_enum)
        {
        {
          lang_output_section_statement_type *os;
          lang_output_section_statement_type *os;
 
 
          os = lang_output_section_find (tree->name.name);
          os = lang_output_section_find (tree->name.name);
          if (os == NULL)
          if (os == NULL)
            {
            {
              if (expld.phase == lang_final_phase_enum)
              if (expld.phase == lang_final_phase_enum)
                einfo (_("%F%S: undefined section `%s' referenced in expression\n"),
                einfo (_("%F%S: undefined section `%s'"
                       tree->name.name);
                         " referenced in expression\n"),
 
                       tree, tree->name.name);
            }
            }
          else if (os->processed_vma)
          else if (os->processed_vma)
            new_rel (0, os->bfd_section);
            new_rel (0, os->bfd_section);
        }
        }
      break;
      break;
 
 
    case LOADADDR:
    case LOADADDR:
      if (expld.phase != lang_first_phase_enum)
      if (expld.phase != lang_first_phase_enum)
        {
        {
          lang_output_section_statement_type *os;
          lang_output_section_statement_type *os;
 
 
          os = lang_output_section_find (tree->name.name);
          os = lang_output_section_find (tree->name.name);
          if (os == NULL)
          if (os == NULL)
            {
            {
              if (expld.phase == lang_final_phase_enum)
              if (expld.phase == lang_final_phase_enum)
                einfo (_("%F%S: undefined section `%s' referenced in expression\n"),
                einfo (_("%F%S: undefined section `%s'"
                       tree->name.name);
                         " referenced in expression\n"),
 
                       tree, tree->name.name);
            }
            }
          else if (os->processed_lma)
          else if (os->processed_lma)
            {
            {
              if (os->load_base == NULL)
              if (os->load_base == NULL)
                new_abs (os->bfd_section->lma);
                new_abs (os->bfd_section->lma);
              else
              else
                {
                {
                  exp_fold_tree_1 (os->load_base);
                  exp_fold_tree_1 (os->load_base);
                  if (expld.result.valid_p)
                  if (expld.result.valid_p)
                    make_abs ();
                    make_abs ();
                }
                }
            }
            }
        }
        }
      break;
      break;
 
 
    case SIZEOF:
    case SIZEOF:
    case ALIGNOF:
    case ALIGNOF:
      if (expld.phase != lang_first_phase_enum)
      if (expld.phase != lang_first_phase_enum)
        {
        {
          lang_output_section_statement_type *os;
          lang_output_section_statement_type *os;
 
 
          os = lang_output_section_find (tree->name.name);
          os = lang_output_section_find (tree->name.name);
          if (os == NULL)
          if (os == NULL)
            {
            {
              if (expld.phase == lang_final_phase_enum)
              if (expld.phase == lang_final_phase_enum)
                einfo (_("%F%S: undefined section `%s' referenced in expression\n"),
                einfo (_("%F%S: undefined section `%s'"
                       tree->name.name);
                         " referenced in expression\n"),
 
                       tree, tree->name.name);
              new_number (0);
              new_number (0);
            }
            }
          else if (os->processed_vma)
          else if (os->processed_vma)
            {
            {
              bfd_vma val;
              bfd_vma val;
 
 
              if (tree->type.node_code == SIZEOF)
              if (tree->type.node_code == SIZEOF)
                val = (os->bfd_section->size
                val = (os->bfd_section->size
                       / bfd_octets_per_byte (link_info.output_bfd));
                       / bfd_octets_per_byte (link_info.output_bfd));
              else
              else
                val = (bfd_vma)1 << os->bfd_section->alignment_power;
                val = (bfd_vma)1 << os->bfd_section->alignment_power;
 
 
              new_number (val);
              new_number (val);
            }
            }
        }
        }
      break;
      break;
 
 
    case LENGTH:
    case LENGTH:
      {
      {
        lang_memory_region_type *mem;
        lang_memory_region_type *mem;
 
 
        mem = lang_memory_region_lookup (tree->name.name, FALSE);
        mem = lang_memory_region_lookup (tree->name.name, FALSE);
        if (mem != NULL)
        if (mem != NULL)
          new_number (mem->length);
          new_number (mem->length);
        else
        else
          einfo (_("%F%S: undefined MEMORY region `%s'"
          einfo (_("%F%S: undefined MEMORY region `%s'"
                   " referenced in expression\n"), tree->name.name);
                   " referenced in expression\n"),
 
                 tree, tree->name.name);
      }
      }
      break;
      break;
 
 
    case ORIGIN:
    case ORIGIN:
      if (expld.phase != lang_first_phase_enum)
      if (expld.phase != lang_first_phase_enum)
        {
        {
          lang_memory_region_type *mem;
          lang_memory_region_type *mem;
 
 
          mem = lang_memory_region_lookup (tree->name.name, FALSE);
          mem = lang_memory_region_lookup (tree->name.name, FALSE);
          if (mem != NULL)
          if (mem != NULL)
            new_rel_from_abs (mem->origin);
            new_rel_from_abs (mem->origin);
          else
          else
            einfo (_("%F%S: undefined MEMORY region `%s'"
            einfo (_("%F%S: undefined MEMORY region `%s'"
                     " referenced in expression\n"), tree->name.name);
                     " referenced in expression\n"),
 
                   tree, tree->name.name);
        }
        }
      break;
      break;
 
 
    case CONSTANT:
    case CONSTANT:
      if (strcmp (tree->name.name, "MAXPAGESIZE") == 0)
      if (strcmp (tree->name.name, "MAXPAGESIZE") == 0)
        new_number (config.maxpagesize);
        new_number (config.maxpagesize);
      else if (strcmp (tree->name.name, "COMMONPAGESIZE") == 0)
      else if (strcmp (tree->name.name, "COMMONPAGESIZE") == 0)
        new_number (config.commonpagesize);
        new_number (config.commonpagesize);
      else
      else
        einfo (_("%F%S: unknown constant `%s' referenced in expression\n"),
        einfo (_("%F%S: unknown constant `%s' referenced in expression\n"),
               tree->name.name);
               tree, tree->name.name);
      break;
      break;
 
 
    default:
    default:
      FAIL ();
      FAIL ();
      break;
      break;
    }
    }
}
}
 
 
static void
static void
exp_fold_tree_1 (etree_type *tree)
exp_fold_tree_1 (etree_type *tree)
{
{
  if (tree == NULL)
  if (tree == NULL)
    {
    {
      memset (&expld.result, 0, sizeof (expld.result));
      memset (&expld.result, 0, sizeof (expld.result));
      return;
      return;
    }
    }
 
 
  switch (tree->type.node_class)
  switch (tree->type.node_class)
    {
    {
    case etree_value:
    case etree_value:
      if (expld.section == bfd_abs_section_ptr
      if (expld.section == bfd_abs_section_ptr
          && !config.sane_expr)
          && !config.sane_expr)
        new_abs (tree->value.value);
        new_abs (tree->value.value);
      else
      else
        new_number (tree->value.value);
        new_number (tree->value.value);
      expld.result.str = tree->value.str;
      expld.result.str = tree->value.str;
      break;
      break;
 
 
    case etree_rel:
    case etree_rel:
      if (expld.phase != lang_first_phase_enum)
      if (expld.phase != lang_first_phase_enum)
        {
        {
          asection *output_section = tree->rel.section->output_section;
          asection *output_section = tree->rel.section->output_section;
          new_rel (tree->rel.value + tree->rel.section->output_offset,
          new_rel (tree->rel.value + tree->rel.section->output_offset,
                   output_section);
                   output_section);
        }
        }
      else
      else
        memset (&expld.result, 0, sizeof (expld.result));
        memset (&expld.result, 0, sizeof (expld.result));
      break;
      break;
 
 
    case etree_assert:
    case etree_assert:
      exp_fold_tree_1 (tree->assert_s.child);
      exp_fold_tree_1 (tree->assert_s.child);
      if (expld.phase == lang_final_phase_enum && !expld.result.value)
      if (expld.phase == lang_final_phase_enum && !expld.result.value)
        einfo ("%X%P: %s\n", tree->assert_s.message);
        einfo ("%X%P: %s\n", tree->assert_s.message);
      break;
      break;
 
 
    case etree_unary:
    case etree_unary:
      fold_unary (tree);
      fold_unary (tree);
      break;
      break;
 
 
    case etree_binary:
    case etree_binary:
      fold_binary (tree);
      fold_binary (tree);
      break;
      break;
 
 
    case etree_trinary:
    case etree_trinary:
      fold_trinary (tree);
      fold_trinary (tree);
      break;
      break;
 
 
    case etree_assign:
    case etree_assign:
    case etree_provide:
    case etree_provide:
    case etree_provided:
    case etree_provided:
      if (tree->assign.dst[0] == '.' && tree->assign.dst[1] == 0)
      if (tree->assign.dst[0] == '.' && tree->assign.dst[1] == 0)
        {
        {
          if (tree->type.node_class != etree_assign)
          if (tree->type.node_class != etree_assign)
            einfo (_("%F%S can not PROVIDE assignment to location counter\n"));
            einfo (_("%F%S can not PROVIDE assignment to"
 
                     " location counter\n"), tree);
          /* After allocation, assignment to dot should not be done inside
          /* After allocation, assignment to dot should not be done inside
             an output section since allocation adds a padding statement
             an output section since allocation adds a padding statement
             that effectively duplicates the assignment.  */
             that effectively duplicates the assignment.  */
          if (expld.phase == lang_mark_phase_enum
          if (expld.phase == lang_mark_phase_enum
              || expld.phase == lang_allocating_phase_enum
              || expld.phase == lang_allocating_phase_enum
              || ((expld.phase == lang_assigning_phase_enum
              || ((expld.phase == lang_assigning_phase_enum
                   || expld.phase == lang_final_phase_enum)
                   || expld.phase == lang_final_phase_enum)
                  && expld.section == bfd_abs_section_ptr))
                  && expld.section == bfd_abs_section_ptr))
            {
            {
              /* Notify the folder that this is an assignment to dot.  */
              /* Notify the folder that this is an assignment to dot.  */
              expld.assigning_to_dot = TRUE;
              expld.assigning_to_dot = TRUE;
              exp_fold_tree_1 (tree->assign.src);
              exp_fold_tree_1 (tree->assign.src);
              expld.assigning_to_dot = FALSE;
              expld.assigning_to_dot = FALSE;
 
 
              if (!expld.result.valid_p)
              if (!expld.result.valid_p)
                {
                {
                  if (expld.phase != lang_mark_phase_enum)
                  if (expld.phase != lang_mark_phase_enum)
                    einfo (_("%F%S invalid assignment to location counter\n"));
                    einfo (_("%F%S invalid assignment to"
 
                             " location counter\n"), tree);
                }
                }
              else if (expld.dotp == NULL)
              else if (expld.dotp == NULL)
                einfo (_("%F%S assignment to location counter"
                einfo (_("%F%S assignment to location counter"
                         " invalid outside of SECTION\n"));
                         " invalid outside of SECTION\n"), tree);
              else
              else
                {
                {
                  bfd_vma nextdot;
                  bfd_vma nextdot;
 
 
                  nextdot = expld.result.value;
                  nextdot = expld.result.value;
                  if (expld.result.section != NULL)
                  if (expld.result.section != NULL)
                    nextdot += expld.result.section->vma;
                    nextdot += expld.result.section->vma;
                  else
                  else
                    nextdot += expld.section->vma;
                    nextdot += expld.section->vma;
                  if (nextdot < expld.dot
                  if (nextdot < expld.dot
                      && expld.section != bfd_abs_section_ptr)
                      && expld.section != bfd_abs_section_ptr)
                    einfo (_("%F%S cannot move location counter backwards"
                    einfo (_("%F%S cannot move location counter backwards"
                             " (from %V to %V)\n"), expld.dot, nextdot);
                             " (from %V to %V)\n"),
 
                           tree, expld.dot, nextdot);
                  else
                  else
                    {
                    {
                      expld.dot = nextdot;
                      expld.dot = nextdot;
                      *expld.dotp = nextdot;
                      *expld.dotp = nextdot;
                    }
                    }
                }
                }
            }
            }
          else
          else
            memset (&expld.result, 0, sizeof (expld.result));
            memset (&expld.result, 0, sizeof (expld.result));
        }
        }
      else
      else
        {
        {
          etree_type *name;
          etree_type *name;
 
 
          struct bfd_link_hash_entry *h = NULL;
          struct bfd_link_hash_entry *h = NULL;
 
 
          if (tree->type.node_class == etree_provide)
          if (tree->type.node_class == etree_provide)
            {
            {
              h = bfd_link_hash_lookup (link_info.hash, tree->assign.dst,
              h = bfd_link_hash_lookup (link_info.hash, tree->assign.dst,
                                        FALSE, FALSE, TRUE);
                                        FALSE, FALSE, TRUE);
              if (h == NULL
              if (h == NULL
                  || (h->type != bfd_link_hash_new
                  || (h->type != bfd_link_hash_new
                      && h->type != bfd_link_hash_undefined
                      && h->type != bfd_link_hash_undefined
                      && h->type != bfd_link_hash_common))
                      && h->type != bfd_link_hash_common))
                {
                {
                  /* Do nothing.  The symbol was never referenced, or was
                  /* Do nothing.  The symbol was never referenced, or was
                     defined by some object.  */
                     defined by some object.  */
                  break;
                  break;
                }
                }
            }
            }
 
 
          name = tree->assign.src;
          name = tree->assign.src;
          if (name->type.node_class == etree_trinary)
          if (name->type.node_class == etree_trinary)
            {
            {
              exp_fold_tree_1 (name->trinary.cond);
              exp_fold_tree_1 (name->trinary.cond);
              if (expld.result.valid_p)
              if (expld.result.valid_p)
                name = (expld.result.value
                name = (expld.result.value
                        ? name->trinary.lhs : name->trinary.rhs);
                        ? name->trinary.lhs : name->trinary.rhs);
            }
            }
 
 
          if (name->type.node_class == etree_name
          if (name->type.node_class == etree_name
              && name->type.node_code == NAME
              && name->type.node_code == NAME
              && strcmp (tree->assign.dst, name->name.name) == 0)
              && strcmp (tree->assign.dst, name->name.name) == 0)
            /* Leave it alone.  Do not replace a symbol with its own
            /* Leave it alone.  Do not replace a symbol with its own
               output address, in case there is another section sizing
               output address, in case there is another section sizing
               pass.  Folding does not preserve input sections.  */
               pass.  Folding does not preserve input sections.  */
            break;
            break;
 
 
          exp_fold_tree_1 (tree->assign.src);
          exp_fold_tree_1 (tree->assign.src);
          if (expld.result.valid_p
          if (expld.result.valid_p
              || (expld.phase == lang_first_phase_enum
              || (expld.phase <= lang_mark_phase_enum
                  && tree->type.node_class == etree_assign
                  && tree->type.node_class == etree_assign
                  && tree->assign.hidden))
                  && tree->assign.hidden))
            {
            {
              if (h == NULL)
              if (h == NULL)
                {
                {
                  h = bfd_link_hash_lookup (link_info.hash, tree->assign.dst,
                  h = bfd_link_hash_lookup (link_info.hash, tree->assign.dst,
                                            TRUE, FALSE, TRUE);
                                            TRUE, FALSE, TRUE);
                  if (h == NULL)
                  if (h == NULL)
                    einfo (_("%P%F:%s: hash creation failed\n"),
                    einfo (_("%P%F:%s: hash creation failed\n"),
                           tree->assign.dst);
                           tree->assign.dst);
                }
                }
 
 
              /* FIXME: Should we worry if the symbol is already
              /* FIXME: Should we worry if the symbol is already
                 defined?  */
                 defined?  */
              lang_update_definedness (tree->assign.dst, h);
              lang_update_definedness (tree->assign.dst, h);
              h->type = bfd_link_hash_defined;
              h->type = bfd_link_hash_defined;
              h->u.def.value = expld.result.value;
              h->u.def.value = expld.result.value;
              if (expld.result.section == NULL)
              if (expld.result.section == NULL)
                expld.result.section = expld.section;
                expld.result.section = expld.section;
              h->u.def.section = expld.result.section;
              h->u.def.section = expld.result.section;
              if (tree->type.node_class == etree_provide)
              if (tree->type.node_class == etree_provide)
                tree->type.node_class = etree_provided;
                tree->type.node_class = etree_provided;
 
 
              /* Copy the symbol type if this is a simple assignment of
              /* Copy the symbol type if this is a simple assignment of
                 one symbol to another.  This could be more general
                 one symbol to another.  This could be more general
                 (e.g. a ?: operator with NAMEs in each branch).  */
                 (e.g. a ?: operator with NAMEs in each branch).  */
              if (tree->assign.src->type.node_class == etree_name)
              if (tree->assign.src->type.node_class == etree_name)
                {
                {
                  struct bfd_link_hash_entry *hsrc;
                  struct bfd_link_hash_entry *hsrc;
 
 
                  hsrc = bfd_link_hash_lookup (link_info.hash,
                  hsrc = bfd_link_hash_lookup (link_info.hash,
                                               tree->assign.src->name.name,
                                               tree->assign.src->name.name,
                                               FALSE, FALSE, TRUE);
                                               FALSE, FALSE, TRUE);
                  if (hsrc)
                  if (hsrc)
                    bfd_copy_link_hash_symbol_type (link_info.output_bfd, h,
                    bfd_copy_link_hash_symbol_type (link_info.output_bfd, h,
                                                    hsrc);
                                                    hsrc);
                }
                }
            }
            }
          else if (expld.phase == lang_final_phase_enum)
          else if (expld.phase == lang_final_phase_enum)
            {
            {
              h = bfd_link_hash_lookup (link_info.hash, tree->assign.dst,
              h = bfd_link_hash_lookup (link_info.hash, tree->assign.dst,
                                        FALSE, FALSE, TRUE);
                                        FALSE, FALSE, TRUE);
              if (h != NULL
              if (h != NULL
                  && h->type == bfd_link_hash_new)
                  && h->type == bfd_link_hash_new)
                h->type = bfd_link_hash_undefined;
                h->type = bfd_link_hash_undefined;
            }
            }
        }
        }
      break;
      break;
 
 
    case etree_name:
    case etree_name:
      fold_name (tree);
      fold_name (tree);
      break;
      break;
 
 
    default:
    default:
      FAIL ();
      FAIL ();
      memset (&expld.result, 0, sizeof (expld.result));
      memset (&expld.result, 0, sizeof (expld.result));
      break;
      break;
    }
    }
}
}
 
 
void
void
exp_fold_tree (etree_type *tree, asection *current_section, bfd_vma *dotp)
exp_fold_tree (etree_type *tree, asection *current_section, bfd_vma *dotp)
{
{
  expld.dot = *dotp;
  expld.dot = *dotp;
  expld.dotp = dotp;
  expld.dotp = dotp;
  expld.section = current_section;
  expld.section = current_section;
  exp_fold_tree_1 (tree);
  exp_fold_tree_1 (tree);
}
}
 
 
void
void
exp_fold_tree_no_dot (etree_type *tree)
exp_fold_tree_no_dot (etree_type *tree)
{
{
  expld.dot = 0;
  expld.dot = 0;
  expld.dotp = NULL;
  expld.dotp = NULL;
  expld.section = bfd_abs_section_ptr;
  expld.section = bfd_abs_section_ptr;
  exp_fold_tree_1 (tree);
  exp_fold_tree_1 (tree);
}
}
 
 
etree_type *
etree_type *
exp_binop (int code, etree_type *lhs, etree_type *rhs)
exp_binop (int code, etree_type *lhs, etree_type *rhs)
{
{
  etree_type value, *new_e;
  etree_type value, *new_e;
 
 
  value.type.node_code = code;
  value.type.node_code = code;
 
  value.type.filename = lhs->type.filename;
  value.type.lineno = lhs->type.lineno;
  value.type.lineno = lhs->type.lineno;
  value.binary.lhs = lhs;
  value.binary.lhs = lhs;
  value.binary.rhs = rhs;
  value.binary.rhs = rhs;
  value.type.node_class = etree_binary;
  value.type.node_class = etree_binary;
  exp_fold_tree_no_dot (&value);
  exp_fold_tree_no_dot (&value);
  if (expld.result.valid_p)
  if (expld.result.valid_p)
    return exp_intop (expld.result.value);
    return exp_intop (expld.result.value);
 
 
  new_e = (etree_type *) stat_alloc (sizeof (new_e->binary));
  new_e = (etree_type *) stat_alloc (sizeof (new_e->binary));
  memcpy (new_e, &value, sizeof (new_e->binary));
  memcpy (new_e, &value, sizeof (new_e->binary));
  return new_e;
  return new_e;
}
}
 
 
etree_type *
etree_type *
exp_trinop (int code, etree_type *cond, etree_type *lhs, etree_type *rhs)
exp_trinop (int code, etree_type *cond, etree_type *lhs, etree_type *rhs)
{
{
  etree_type value, *new_e;
  etree_type value, *new_e;
 
 
  value.type.node_code = code;
  value.type.node_code = code;
  value.type.lineno = lhs->type.lineno;
  value.type.filename = cond->type.filename;
 
  value.type.lineno = cond->type.lineno;
  value.trinary.lhs = lhs;
  value.trinary.lhs = lhs;
  value.trinary.cond = cond;
  value.trinary.cond = cond;
  value.trinary.rhs = rhs;
  value.trinary.rhs = rhs;
  value.type.node_class = etree_trinary;
  value.type.node_class = etree_trinary;
  exp_fold_tree_no_dot (&value);
  exp_fold_tree_no_dot (&value);
  if (expld.result.valid_p)
  if (expld.result.valid_p)
    return exp_intop (expld.result.value);
    return exp_intop (expld.result.value);
 
 
  new_e = (etree_type *) stat_alloc (sizeof (new_e->trinary));
  new_e = (etree_type *) stat_alloc (sizeof (new_e->trinary));
  memcpy (new_e, &value, sizeof (new_e->trinary));
  memcpy (new_e, &value, sizeof (new_e->trinary));
  return new_e;
  return new_e;
}
}
 
 
etree_type *
etree_type *
exp_unop (int code, etree_type *child)
exp_unop (int code, etree_type *child)
{
{
  etree_type value, *new_e;
  etree_type value, *new_e;
 
 
  value.unary.type.node_code = code;
  value.unary.type.node_code = code;
 
  value.unary.type.filename = child->type.filename;
  value.unary.type.lineno = child->type.lineno;
  value.unary.type.lineno = child->type.lineno;
  value.unary.child = child;
  value.unary.child = child;
  value.unary.type.node_class = etree_unary;
  value.unary.type.node_class = etree_unary;
  exp_fold_tree_no_dot (&value);
  exp_fold_tree_no_dot (&value);
  if (expld.result.valid_p)
  if (expld.result.valid_p)
    return exp_intop (expld.result.value);
    return exp_intop (expld.result.value);
 
 
  new_e = (etree_type *) stat_alloc (sizeof (new_e->unary));
  new_e = (etree_type *) stat_alloc (sizeof (new_e->unary));
  memcpy (new_e, &value, sizeof (new_e->unary));
  memcpy (new_e, &value, sizeof (new_e->unary));
  return new_e;
  return new_e;
}
}
 
 
etree_type *
etree_type *
exp_nameop (int code, const char *name)
exp_nameop (int code, const char *name)
{
{
  etree_type value, *new_e;
  etree_type value, *new_e;
 
 
  value.name.type.node_code = code;
  value.name.type.node_code = code;
 
  value.name.type.filename = ldlex_filename ();
  value.name.type.lineno = lineno;
  value.name.type.lineno = lineno;
  value.name.name = name;
  value.name.name = name;
  value.name.type.node_class = etree_name;
  value.name.type.node_class = etree_name;
 
 
  exp_fold_tree_no_dot (&value);
  exp_fold_tree_no_dot (&value);
  if (expld.result.valid_p)
  if (expld.result.valid_p)
    return exp_intop (expld.result.value);
    return exp_intop (expld.result.value);
 
 
  new_e = (etree_type *) stat_alloc (sizeof (new_e->name));
  new_e = (etree_type *) stat_alloc (sizeof (new_e->name));
  memcpy (new_e, &value, sizeof (new_e->name));
  memcpy (new_e, &value, sizeof (new_e->name));
  return new_e;
  return new_e;
 
 
}
}
 
 
static etree_type *
static etree_type *
exp_assop (const char *dst,
exp_assop (const char *dst,
           etree_type *src,
           etree_type *src,
           enum node_tree_enum class,
           enum node_tree_enum class,
           bfd_boolean hidden)
           bfd_boolean hidden)
{
{
  etree_type *n;
  etree_type *n;
 
 
  n = (etree_type *) stat_alloc (sizeof (n->assign));
  n = (etree_type *) stat_alloc (sizeof (n->assign));
  n->assign.type.node_code = '=';
  n->assign.type.node_code = '=';
 
  n->assign.type.filename = src->type.filename;
  n->assign.type.lineno = src->type.lineno;
  n->assign.type.lineno = src->type.lineno;
  n->assign.type.node_class = class;
  n->assign.type.node_class = class;
  n->assign.src = src;
  n->assign.src = src;
  n->assign.dst = dst;
  n->assign.dst = dst;
  n->assign.hidden = hidden;
  n->assign.hidden = hidden;
  return n;
  return n;
}
}
 
 
etree_type *
etree_type *
exp_assign (const char *dst, etree_type *src)
exp_assign (const char *dst, etree_type *src)
{
{
  return exp_assop (dst, src, etree_assign, FALSE);
  return exp_assop (dst, src, etree_assign, FALSE);
}
}
 
 
etree_type *
etree_type *
exp_defsym (const char *dst, etree_type *src)
exp_defsym (const char *dst, etree_type *src)
{
{
  return exp_assop (dst, src, etree_assign, TRUE);
  return exp_assop (dst, src, etree_assign, TRUE);
}
}
 
 
/* Handle PROVIDE.  */
/* Handle PROVIDE.  */
 
 
etree_type *
etree_type *
exp_provide (const char *dst, etree_type *src, bfd_boolean hidden)
exp_provide (const char *dst, etree_type *src, bfd_boolean hidden)
{
{
  return exp_assop (dst, src, etree_provide, hidden);
  return exp_assop (dst, src, etree_provide, hidden);
}
}
 
 
/* Handle ASSERT.  */
/* Handle ASSERT.  */
 
 
etree_type *
etree_type *
exp_assert (etree_type *exp, const char *message)
exp_assert (etree_type *exp, const char *message)
{
{
  etree_type *n;
  etree_type *n;
 
 
  n = (etree_type *) stat_alloc (sizeof (n->assert_s));
  n = (etree_type *) stat_alloc (sizeof (n->assert_s));
  n->assert_s.type.node_code = '!';
  n->assert_s.type.node_code = '!';
 
  n->assert_s.type.filename = exp->type.filename;
  n->assert_s.type.lineno = exp->type.lineno;
  n->assert_s.type.lineno = exp->type.lineno;
  n->assert_s.type.node_class = etree_assert;
  n->assert_s.type.node_class = etree_assert;
  n->assert_s.child = exp;
  n->assert_s.child = exp;
  n->assert_s.message = message;
  n->assert_s.message = message;
  return n;
  return n;
}
}
 
 
void
void
exp_print_tree (etree_type *tree)
exp_print_tree (etree_type *tree)
{
{
  bfd_boolean function_like;
  bfd_boolean function_like;
 
 
  if (config.map_file == NULL)
  if (config.map_file == NULL)
    config.map_file = stderr;
    config.map_file = stderr;
 
 
  if (tree == NULL)
  if (tree == NULL)
    {
    {
      minfo ("NULL TREE\n");
      minfo ("NULL TREE\n");
      return;
      return;
    }
    }
 
 
  switch (tree->type.node_class)
  switch (tree->type.node_class)
    {
    {
    case etree_value:
    case etree_value:
      minfo ("0x%v", tree->value.value);
      minfo ("0x%v", tree->value.value);
      return;
      return;
    case etree_rel:
    case etree_rel:
      if (tree->rel.section->owner != NULL)
      if (tree->rel.section->owner != NULL)
        minfo ("%B:", tree->rel.section->owner);
        minfo ("%B:", tree->rel.section->owner);
      minfo ("%s+0x%v", tree->rel.section->name, tree->rel.value);
      minfo ("%s+0x%v", tree->rel.section->name, tree->rel.value);
      return;
      return;
    case etree_assign:
    case etree_assign:
      fputs (tree->assign.dst, config.map_file);
      fputs (tree->assign.dst, config.map_file);
      exp_print_token (tree->type.node_code, TRUE);
      exp_print_token (tree->type.node_code, TRUE);
      exp_print_tree (tree->assign.src);
      exp_print_tree (tree->assign.src);
      break;
      break;
    case etree_provide:
    case etree_provide:
    case etree_provided:
    case etree_provided:
      fprintf (config.map_file, "PROVIDE (%s, ", tree->assign.dst);
      fprintf (config.map_file, "PROVIDE (%s, ", tree->assign.dst);
      exp_print_tree (tree->assign.src);
      exp_print_tree (tree->assign.src);
      fputc (')', config.map_file);
      fputc (')', config.map_file);
      break;
      break;
    case etree_binary:
    case etree_binary:
      function_like = FALSE;
      function_like = FALSE;
      switch (tree->type.node_code)
      switch (tree->type.node_code)
        {
        {
        case MAX_K:
        case MAX_K:
        case MIN_K:
        case MIN_K:
        case ALIGN_K:
        case ALIGN_K:
        case DATA_SEGMENT_ALIGN:
        case DATA_SEGMENT_ALIGN:
        case DATA_SEGMENT_RELRO_END:
        case DATA_SEGMENT_RELRO_END:
          function_like = TRUE;
          function_like = TRUE;
        }
        }
      if (function_like)
      if (function_like)
        {
        {
          exp_print_token (tree->type.node_code, FALSE);
          exp_print_token (tree->type.node_code, FALSE);
          fputc (' ', config.map_file);
          fputc (' ', config.map_file);
        }
        }
      fputc ('(', config.map_file);
      fputc ('(', config.map_file);
      exp_print_tree (tree->binary.lhs);
      exp_print_tree (tree->binary.lhs);
      if (function_like)
      if (function_like)
        fprintf (config.map_file, ", ");
        fprintf (config.map_file, ", ");
      else
      else
        exp_print_token (tree->type.node_code, TRUE);
        exp_print_token (tree->type.node_code, TRUE);
      exp_print_tree (tree->binary.rhs);
      exp_print_tree (tree->binary.rhs);
      fputc (')', config.map_file);
      fputc (')', config.map_file);
      break;
      break;
    case etree_trinary:
    case etree_trinary:
      exp_print_tree (tree->trinary.cond);
      exp_print_tree (tree->trinary.cond);
      fputc ('?', config.map_file);
      fputc ('?', config.map_file);
      exp_print_tree (tree->trinary.lhs);
      exp_print_tree (tree->trinary.lhs);
      fputc (':', config.map_file);
      fputc (':', config.map_file);
      exp_print_tree (tree->trinary.rhs);
      exp_print_tree (tree->trinary.rhs);
      break;
      break;
    case etree_unary:
    case etree_unary:
      exp_print_token (tree->unary.type.node_code, FALSE);
      exp_print_token (tree->unary.type.node_code, FALSE);
      if (tree->unary.child)
      if (tree->unary.child)
        {
        {
          fprintf (config.map_file, " (");
          fprintf (config.map_file, " (");
          exp_print_tree (tree->unary.child);
          exp_print_tree (tree->unary.child);
          fputc (')', config.map_file);
          fputc (')', config.map_file);
        }
        }
      break;
      break;
 
 
    case etree_assert:
    case etree_assert:
      fprintf (config.map_file, "ASSERT (");
      fprintf (config.map_file, "ASSERT (");
      exp_print_tree (tree->assert_s.child);
      exp_print_tree (tree->assert_s.child);
      fprintf (config.map_file, ", %s)", tree->assert_s.message);
      fprintf (config.map_file, ", %s)", tree->assert_s.message);
      break;
      break;
 
 
    case etree_name:
    case etree_name:
      if (tree->type.node_code == NAME)
      if (tree->type.node_code == NAME)
        fputs (tree->name.name, config.map_file);
        fputs (tree->name.name, config.map_file);
      else
      else
        {
        {
          exp_print_token (tree->type.node_code, FALSE);
          exp_print_token (tree->type.node_code, FALSE);
          if (tree->name.name)
          if (tree->name.name)
            fprintf (config.map_file, " (%s)", tree->name.name);
            fprintf (config.map_file, " (%s)", tree->name.name);
        }
        }
      break;
      break;
    default:
    default:
      FAIL ();
      FAIL ();
      break;
      break;
    }
    }
}
}
 
 
bfd_vma
bfd_vma
exp_get_vma (etree_type *tree, bfd_vma def, char *name)
exp_get_vma (etree_type *tree, bfd_vma def, char *name)
{
{
  if (tree != NULL)
  if (tree != NULL)
    {
    {
      exp_fold_tree_no_dot (tree);
      exp_fold_tree_no_dot (tree);
      if (expld.result.valid_p)
      if (expld.result.valid_p)
        return expld.result.value;
        return expld.result.value;
      else if (name != NULL && expld.phase != lang_mark_phase_enum)
      else if (name != NULL && expld.phase != lang_mark_phase_enum)
        einfo (_("%F%S: nonconstant expression for %s\n"), name);
        einfo (_("%F%S: nonconstant expression for %s\n"),
 
               tree, name);
    }
    }
  return def;
  return def;
}
}
 
 
int
int
exp_get_value_int (etree_type *tree, int def, char *name)
exp_get_value_int (etree_type *tree, int def, char *name)
{
{
  return exp_get_vma (tree, def, name);
  return exp_get_vma (tree, def, name);
}
}
 
 
fill_type *
fill_type *
exp_get_fill (etree_type *tree, fill_type *def, char *name)
exp_get_fill (etree_type *tree, fill_type *def, char *name)
{
{
  fill_type *fill;
  fill_type *fill;
  size_t len;
  size_t len;
  unsigned int val;
  unsigned int val;
 
 
  if (tree == NULL)
  if (tree == NULL)
    return def;
    return def;
 
 
  exp_fold_tree_no_dot (tree);
  exp_fold_tree_no_dot (tree);
  if (!expld.result.valid_p)
  if (!expld.result.valid_p)
    {
    {
      if (name != NULL && expld.phase != lang_mark_phase_enum)
      if (name != NULL && expld.phase != lang_mark_phase_enum)
        einfo (_("%F%S: nonconstant expression for %s\n"), name);
        einfo (_("%F%S: nonconstant expression for %s\n"),
 
               tree, name);
      return def;
      return def;
    }
    }
 
 
  if (expld.result.str != NULL && (len = strlen (expld.result.str)) != 0)
  if (expld.result.str != NULL && (len = strlen (expld.result.str)) != 0)
    {
    {
      unsigned char *dst;
      unsigned char *dst;
      unsigned char *s;
      unsigned char *s;
      fill = (fill_type *) xmalloc ((len + 1) / 2 + sizeof (*fill) - 1);
      fill = (fill_type *) xmalloc ((len + 1) / 2 + sizeof (*fill) - 1);
      fill->size = (len + 1) / 2;
      fill->size = (len + 1) / 2;
      dst = fill->data;
      dst = fill->data;
      s = (unsigned char *) expld.result.str;
      s = (unsigned char *) expld.result.str;
      val = 0;
      val = 0;
      do
      do
        {
        {
          unsigned int digit;
          unsigned int digit;
 
 
          digit = *s++ - '0';
          digit = *s++ - '0';
          if (digit > 9)
          if (digit > 9)
            digit = (digit - 'A' + '0' + 10) & 0xf;
            digit = (digit - 'A' + '0' + 10) & 0xf;
          val <<= 4;
          val <<= 4;
          val += digit;
          val += digit;
          --len;
          --len;
          if ((len & 1) == 0)
          if ((len & 1) == 0)
            {
            {
              *dst++ = val;
              *dst++ = val;
              val = 0;
              val = 0;
            }
            }
        }
        }
      while (len != 0);
      while (len != 0);
    }
    }
  else
  else
    {
    {
      fill = (fill_type *) xmalloc (4 + sizeof (*fill) - 1);
      fill = (fill_type *) xmalloc (4 + sizeof (*fill) - 1);
      val = expld.result.value;
      val = expld.result.value;
      fill->data[0] = (val >> 24) & 0xff;
      fill->data[0] = (val >> 24) & 0xff;
      fill->data[1] = (val >> 16) & 0xff;
      fill->data[1] = (val >> 16) & 0xff;
      fill->data[2] = (val >>  8) & 0xff;
      fill->data[2] = (val >>  8) & 0xff;
      fill->data[3] = (val >>  0) & 0xff;
      fill->data[3] = (val >>  0) & 0xff;
      fill->size = 4;
      fill->size = 4;
    }
    }
  return fill;
  return fill;
}
}
 
 
bfd_vma
bfd_vma
exp_get_abs_int (etree_type *tree, int def, char *name)
exp_get_abs_int (etree_type *tree, int def, char *name)
{
{
  if (tree != NULL)
  if (tree != NULL)
    {
    {
      exp_fold_tree_no_dot (tree);
      exp_fold_tree_no_dot (tree);
 
 
      if (expld.result.valid_p)
      if (expld.result.valid_p)
        {
        {
          if (expld.result.section != NULL)
          if (expld.result.section != NULL)
            expld.result.value += expld.result.section->vma;
            expld.result.value += expld.result.section->vma;
          return expld.result.value;
          return expld.result.value;
        }
        }
      else if (name != NULL && expld.phase != lang_mark_phase_enum)
      else if (name != NULL && expld.phase != lang_mark_phase_enum)
        {
        {
          lineno = tree->type.lineno;
          einfo (_("%F%S: nonconstant expression for %s\n"),
          einfo (_("%F%S: nonconstant expression for %s\n"), name);
                 tree, name);
        }
        }
    }
    }
  return def;
  return def;
}
}
 
 
static bfd_vma
static bfd_vma
align_n (bfd_vma value, bfd_vma align)
align_n (bfd_vma value, bfd_vma align)
{
{
  if (align <= 1)
  if (align <= 1)
    return value;
    return value;
 
 
  value = (value + align - 1) / align;
  value = (value + align - 1) / align;
  return value * align;
  return value * align;
}
}
 
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.