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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-old/] [binutils-2.18.50/] [ld/] [ldexp.c] - Diff between revs 156 and 816

Go to most recent revision | Only display areas with differences | Details | Blame | View Log

Rev 156 Rev 816
/* 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
   2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
   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 void exp_fold_tree_no_dot (etree_type *);
static void exp_fold_tree_no_dot (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" },
    { MAX_K, "MAX_K" },
    { MAX_K, "MAX_K" },
    { 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)
{
{
  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 = stat_alloc (sizeof (new->value));
  etree_type *new = stat_alloc (sizeof (new->value));
  new->type.node_code = INT;
  new->type.node_code = INT;
  new->type.lineno = lineno;
  new->type.lineno = lineno;
  new->value.value = value;
  new->value.value = value;
  new->value.str = NULL;
  new->value.str = NULL;
  new->type.node_class = etree_value;
  new->type.node_class = etree_value;
  return new;
  return new;
}
}
 
 
etree_type *
etree_type *
exp_bigintop (bfd_vma value, char *str)
exp_bigintop (bfd_vma value, char *str)
{
{
  etree_type *new = stat_alloc (sizeof (new->value));
  etree_type *new = stat_alloc (sizeof (new->value));
  new->type.node_code = INT;
  new->type.node_code = INT;
  new->type.lineno = lineno;
  new->type.lineno = lineno;
  new->value.value = value;
  new->value.value = value;
  new->value.str = str;
  new->value.str = str;
  new->type.node_class = etree_value;
  new->type.node_class = etree_value;
  return new;
  return new;
}
}
 
 
/* 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 = stat_alloc (sizeof (new->rel));
  etree_type *new = stat_alloc (sizeof (new->rel));
  new->type.node_code = REL;
  new->type.node_code = REL;
  new->type.lineno = lineno;
  new->type.lineno = lineno;
  new->type.node_class = etree_rel;
  new->type.node_class = etree_rel;
  new->rel.section = section;
  new->rel.section = section;
  new->rel.value = value;
  new->rel.value = value;
  return new;
  return new;
}
}
 
 
static void
static void
new_rel (bfd_vma value, char *str, asection *section)
new_rel (bfd_vma value, char *str, asection *section)
{
{
  expld.result.valid_p = TRUE;
  expld.result.valid_p = TRUE;
  expld.result.value = value;
  expld.result.value = value;
  expld.result.str = str;
  expld.result.str = str;
  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 '~':
          make_abs ();
          make_abs ();
          expld.result.value = ~expld.result.value;
          expld.result.value = ~expld.result.value;
          break;
          break;
 
 
        case '!':
        case '!':
          make_abs ();
          make_abs ();
          expld.result.value = !expld.result.value;
          expld.result.value = !expld.result.value;
          break;
          break;
 
 
        case '-':
        case '-':
          make_abs ();
          make_abs ();
          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.dataseg.phase == exp_dataseg_align_seen
              && (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_adjust
                  || expld.dataseg.phase == exp_dataseg_adjust
                  || expld.dataseg.phase == exp_dataseg_relro_adjust
                  || expld.dataseg.phase == exp_dataseg_relro_adjust
                  || expld.phase == lang_final_phase_enum))
                  || expld.phase == lang_final_phase_enum))
            {
            {
              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)
                {
                {
                  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
          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)
{
{
  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.  */
     operand is a string, not the name of a symbol.  */
  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)
          {
          {
            seg->used = TRUE;
            seg->used = TRUE;
            expld.result.value = seg->value;
            expld.result.value = seg->value;
            expld.result.str = NULL;
            expld.result.str = NULL;
            expld.result.section = NULL;
            expld.result.section = NULL;
            break;
            break;
          }
          }
    }
    }
  else if (expld.result.valid_p)
  else if (expld.result.valid_p)
    {
    {
      etree_value_type lhs = expld.result;
      etree_value_type lhs = expld.result;
 
 
      exp_fold_tree_1 (tree->binary.rhs);
      exp_fold_tree_1 (tree->binary.rhs);
      if (expld.result.valid_p)
      if (expld.result.valid_p)
        {
        {
          /* If the values are from different sections, or this is an
          /* If the values are from different sections, or this is an
             absolute expression, make both the source arguments
             absolute expression, make both the source arguments
             absolute.  However, adding or subtracting an absolute
             absolute.  However, adding or subtracting an absolute
             value from a relative value is meaningful, and is an
             value from a relative value is meaningful, and is an
             exception.  */
             exception.  */
          if (expld.section != bfd_abs_section_ptr
          if (expld.section != bfd_abs_section_ptr
              && lhs.section == bfd_abs_section_ptr
              && lhs.section == bfd_abs_section_ptr
              && tree->type.node_code == '+')
              && tree->type.node_code == '+')
            {
            {
              /* Keep the section of the rhs term.  */
              /* Keep the section of the rhs term.  */
              expld.result.value = lhs.value + expld.result.value;
              expld.result.value = lhs.value + expld.result.value;
              return;
              return;
            }
            }
          else if (expld.section != bfd_abs_section_ptr
          else if (expld.section != bfd_abs_section_ptr
              && expld.result.section == bfd_abs_section_ptr
              && expld.result.section == bfd_abs_section_ptr
              && (tree->type.node_code == '+'
              && (tree->type.node_code == '+'
                  || tree->type.node_code == '-'))
                  || tree->type.node_code == '-'))
            {
            {
              /* Keep the section of the lhs term.  */
              /* Keep the section of the lhs term.  */
              expld.result.section = lhs.section;
              expld.result.section = lhs.section;
            }
            }
          else if (expld.result.section != lhs.section
          else if (expld.result.section != lhs.section
                   || expld.section == bfd_abs_section_ptr)
                   || expld.section == bfd_abs_section_ptr)
            {
            {
              make_abs ();
              make_abs ();
              lhs.value += lhs.section->vma;
              lhs.value += lhs.section->vma;
            }
            }
 
 
          switch (tree->type.node_code)
          switch (tree->type.node_code)
            {
            {
            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"));
              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"));
              break;
              break;
 
 
#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;      \
              break;
              break;
 
 
              BOP ('+', +);
              BOP ('+', +);
              BOP ('*', *);
              BOP ('*', *);
              BOP ('-', -);
              BOP ('-', -);
              BOP (LSHIFT, <<);
              BOP (LSHIFT, <<);
              BOP (RSHIFT, >>);
              BOP (RSHIFT, >>);
              BOP (EQ, ==);
              BOP (EQ, ==);
              BOP (NE, !=);
              BOP (NE, !=);
              BOP ('<', <);
              BOP ('<', <);
              BOP ('>', >);
              BOP ('>', >);
              BOP (LE, <=);
              BOP (LE, <=);
              BOP (GE, >=);
              BOP (GE, >=);
              BOP ('&', &);
              BOP ('&', &);
              BOP ('^', ^);
              BOP ('^', ^);
              BOP ('|', |);
              BOP ('|', |);
              BOP (ANDAND, &&);
              BOP (ANDAND, &&);
              BOP (OROR, ||);
              BOP (OROR, ||);
 
 
            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.dataseg.phase == exp_dataseg_none
                  && (expld.dataseg.phase == exp_dataseg_none
                      || 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.phase == lang_final_phase_enum))
                      || expld.phase == lang_final_phase_enum))
                {
                {
                  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)
                    {
                    {
                      expld.result.value += expld.dot & (maxpage - 1);
                      expld.result.value += expld.dot & (maxpage - 1);
                      if (expld.phase == lang_allocating_phase_enum)
                      if (expld.phase == lang_allocating_phase_enum)
                        {
                        {
                          expld.dataseg.phase = exp_dataseg_align_seen;
                          expld.dataseg.phase = exp_dataseg_align_seen;
                          expld.dataseg.min_base = align_n (expld.dot, maxpage);
                          expld.dataseg.min_base = align_n (expld.dot, maxpage);
                          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 if (commonpage < maxpage)
                  else 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.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.dataseg.phase == exp_dataseg_align_seen
                  && (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.phase == lang_final_phase_enum))
                      || expld.phase == lang_final_phase_enum))
                {
                {
                  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 ();
            }
            }
        }
        }
      else
      else
        expld.result.valid_p = FALSE;
        expld.result.valid_p = FALSE;
    }
    }
}
}
 
 
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_abs (hdr_size);
          new_abs (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);
          expld.result.value = (h != NULL
          expld.result.value = (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));
          expld.result.section = bfd_abs_section_ptr;
          expld.result.section = bfd_abs_section_ptr;
          expld.result.valid_p = TRUE;
          expld.result.valid_p = TRUE;
        }
        }
      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)
            {
            {
              if (bfd_is_abs_section (h->u.def.section))
              if (bfd_is_abs_section (h->u.def.section))
                new_abs (h->u.def.value);
                new_abs (h->u.def.value);
              else
              else
                {
                {
                  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)
                        einfo (_("%X%S: unresolvable symbol `%s'"
                        einfo (_("%X%S: unresolvable symbol `%s'"
                                 " referenced in expression\n"),
                                 " referenced in expression\n"),
                               tree->name.name);
                               tree->name.name);
                    }
                    }
                  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,
                             NULL, output_section);
                             NULL, 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' referenced in expression\n"),
                   tree->name.name);
                   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' referenced in expression\n"),
                       tree->name.name);
                       tree->name.name);
            }
            }
          else if (os->processed_vma)
          else if (os->processed_vma)
            new_rel (0, NULL, os->bfd_section);
            new_rel (0, NULL, 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' referenced in expression\n"),
                       tree->name.name);
                       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' referenced in expression\n"),
                       tree->name.name);
                       tree->name.name);
              new_abs (0);
              new_abs (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_abs (val);
              new_abs (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_abs (mem->length);
          new_abs (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->name.name);
      }
      }
      break;
      break;
 
 
    case ORIGIN:
    case ORIGIN:
      {
      {
        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_abs (mem->origin);
          new_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->name.name);
      }
      }
      break;
      break;
 
 
    case CONSTANT:
    case CONSTANT:
      if (strcmp (tree->name.name, "MAXPAGESIZE") == 0)
      if (strcmp (tree->name.name, "MAXPAGESIZE") == 0)
        new_abs (bfd_emul_get_maxpagesize (default_target));
        new_abs (bfd_emul_get_maxpagesize (default_target));
      else if (strcmp (tree->name.name, "COMMONPAGESIZE") == 0)
      else if (strcmp (tree->name.name, "COMMONPAGESIZE") == 0)
        new_abs (bfd_emul_get_commonpagesize (default_target));
        new_abs (bfd_emul_get_commonpagesize (default_target));
      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->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:
      new_rel (tree->value.value, tree->value.str, expld.section);
      new_rel (tree->value.value, tree->value.str, expld.section);
      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,
                   NULL, output_section);
                   NULL, 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)
        {
        {
          /* Assignment to dot can only be done during allocation.  */
          /* Assignment to dot can only be done during allocation.  */
          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"));
          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_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"));
                }
                }
              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"));
              else
              else
                {
                {
                  bfd_vma nextdot;
                  bfd_vma nextdot;
 
 
                  nextdot = expld.result.value + expld.section->vma;
                  nextdot = expld.result.value + 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"), 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
        {
        {
          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;
                }
                }
            }
            }
 
 
          exp_fold_tree_1 (tree->assign.src);
          exp_fold_tree_1 (tree->assign.src);
          if (expld.result.valid_p)
          if (expld.result.valid_p)
            {
            {
              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;
              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;
            }
            }
        }
        }
      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);
}
}
 
 
static void
static 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;
  etree_type value, *new;
 
 
  value.type.node_code = code;
  value.type.node_code = code;
  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 = stat_alloc (sizeof (new->binary));
  new = stat_alloc (sizeof (new->binary));
  memcpy (new, &value, sizeof (new->binary));
  memcpy (new, &value, sizeof (new->binary));
  return new;
  return new;
}
}
 
 
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;
  etree_type value, *new;
 
 
  value.type.node_code = code;
  value.type.node_code = code;
  value.type.lineno = lhs->type.lineno;
  value.type.lineno = lhs->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 = stat_alloc (sizeof (new->trinary));
  new = stat_alloc (sizeof (new->trinary));
  memcpy (new, &value, sizeof (new->trinary));
  memcpy (new, &value, sizeof (new->trinary));
  return new;
  return new;
}
}
 
 
etree_type *
etree_type *
exp_unop (int code, etree_type *child)
exp_unop (int code, etree_type *child)
{
{
  etree_type value, *new;
  etree_type value, *new;
 
 
  value.unary.type.node_code = code;
  value.unary.type.node_code = code;
  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 = stat_alloc (sizeof (new->unary));
  new = stat_alloc (sizeof (new->unary));
  memcpy (new, &value, sizeof (new->unary));
  memcpy (new, &value, sizeof (new->unary));
  return new;
  return new;
}
}
 
 
etree_type *
etree_type *
exp_nameop (int code, const char *name)
exp_nameop (int code, const char *name)
{
{
  etree_type value, *new;
  etree_type value, *new;
 
 
  value.name.type.node_code = code;
  value.name.type.node_code = code;
  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 = stat_alloc (sizeof (new->name));
  new = stat_alloc (sizeof (new->name));
  memcpy (new, &value, sizeof (new->name));
  memcpy (new, &value, sizeof (new->name));
  return new;
  return new;
 
 
}
}
 
 
etree_type *
etree_type *
exp_assop (int code, const char *dst, etree_type *src)
exp_assop (int code, const char *dst, etree_type *src)
{
{
  etree_type *new;
  etree_type *new;
 
 
  new = stat_alloc (sizeof (new->assign));
  new = stat_alloc (sizeof (new->assign));
  new->type.node_code = code;
  new->type.node_code = code;
  new->type.lineno = src->type.lineno;
  new->type.lineno = src->type.lineno;
  new->type.node_class = etree_assign;
  new->type.node_class = etree_assign;
  new->assign.src = src;
  new->assign.src = src;
  new->assign.dst = dst;
  new->assign.dst = dst;
  return new;
  return new;
}
}
 
 
/* 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)
{
{
  etree_type *n;
  etree_type *n;
 
 
  n = stat_alloc (sizeof (n->assign));
  n = stat_alloc (sizeof (n->assign));
  n->assign.type.node_code = '=';
  n->assign.type.node_code = '=';
  n->assign.type.lineno = src->type.lineno;
  n->assign.type.lineno = src->type.lineno;
  n->assign.type.node_class = etree_provide;
  n->assign.type.node_class = etree_provide;
  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;
}
}
 
 
/* 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 = stat_alloc (sizeof (n->assert_s));
  n = stat_alloc (sizeof (n->assert_s));
  n->assert_s.type.node_code = '!';
  n->assert_s.type.node_code = '!';
  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)
{
{
  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:
      fprintf (config.map_file, "%s", tree->assign.dst);
      fprintf (config.map_file, "%s", tree->assign.dst);
      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);
      fprintf (config.map_file, ")");
      fprintf (config.map_file, ")");
      break;
      break;
    case etree_binary:
    case etree_binary:
      fprintf (config.map_file, "(");
      fprintf (config.map_file, "(");
      exp_print_tree (tree->binary.lhs);
      exp_print_tree (tree->binary.lhs);
      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);
      fprintf (config.map_file, ")");
      fprintf (config.map_file, ")");
      break;
      break;
    case etree_trinary:
    case etree_trinary:
      exp_print_tree (tree->trinary.cond);
      exp_print_tree (tree->trinary.cond);
      fprintf (config.map_file, "?");
      fprintf (config.map_file, "?");
      exp_print_tree (tree->trinary.lhs);
      exp_print_tree (tree->trinary.lhs);
      fprintf (config.map_file, ":");
      fprintf (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);
          fprintf (config.map_file, ")");
          fprintf (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)
        {
        {
          fprintf (config.map_file, "%s", tree->name.name);
          fprintf (config.map_file, "%s", tree->name.name);
        }
        }
      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"), 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"), 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 = xmalloc ((len + 1) / 2 + sizeof (*fill) - 1);
      fill = 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 = xmalloc (4 + sizeof (*fill) - 1);
      fill = 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)
        {
        {
          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;
          lineno = tree->type.lineno;
          einfo (_("%F%S: nonconstant expression for %s\n"), name);
          einfo (_("%F%S: nonconstant expression for %s\n"), 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.