ldexp.c

来自「基于4个mips核的noc设计」· C语言 代码 · 共 993 行 · 第 1/2 页

C
993
字号
/* This module handles expression trees.   Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,   2001   Free Software Foundation, Inc.   Written by Steve Chamberlain of Cygnus Support <sac@cygnus.com>.This file is part of GLD, the Gnu Linker.GLD is free software; you can redistribute it and/or modifyit under the terms of the GNU General Public License as published bythe Free Software Foundation; either version 2, or (at your option)any later version.GLD is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See theGNU General Public License for more details.You should have received a copy of the GNU General Public Licensealong with GLD; see the file COPYING.  If not, write to the FreeSoftware Foundation, 59 Temple Place - Suite 330, Boston, MA02111-1307, USA.  *//* This module is in charge of working out the contents of expressions.   It has to keep track of the relative/absness of a symbol etc. This   is done by keeping all values in a struct (an etree_value_type)   which contains a value, a section to which it is relative and a   valid bit.  */#include "bfd.h"#include "sysdep.h"#include "bfdlink.h"#include "ld.h"#include "ldmain.h"#include "ldmisc.h"#include "ldexp.h"#include "ldgram.h"#include "ldlang.h"static void exp_print_token PARAMS ((token_code_type code));static void make_abs PARAMS ((etree_value_type *ptr));static etree_value_type new_abs PARAMS ((bfd_vma value));static void check PARAMS ((lang_output_section_statement_type *os,			   const char *name, const char *op));static etree_value_type new_rel  PARAMS ((bfd_vma value, lang_output_section_statement_type *section));static etree_value_type new_rel_from_section  PARAMS ((bfd_vma value, lang_output_section_statement_type *section));static etree_value_type fold_binary  PARAMS ((etree_type *tree,	   lang_output_section_statement_type *current_section,	   lang_phase_type allocation_done,	   bfd_vma dot, bfd_vma *dotp));static etree_value_type fold_name  PARAMS ((etree_type *tree,	   lang_output_section_statement_type *current_section,	   lang_phase_type allocation_done,	   bfd_vma dot));static etree_value_type exp_fold_tree_no_dot  PARAMS ((etree_type *tree,	   lang_output_section_statement_type *current_section,	   lang_phase_type allocation_done));static voidexp_print_token (code)     token_code_type code;{  static CONST struct {    token_code_type code;    char *name;  } table[] = {    { INT, "int" },    { REL, "relocateable" },    { NAME, "NAME" },    { PLUSEQ, "+=" },    { MINUSEQ, "-=" },    { MULTEQ, "*=" },    { DIVEQ, "/=" },    { LSHIFTEQ, "<<=" },    { RSHIFTEQ, ">>=" },    { ANDEQ, "&=" },    { OREQ, "|=" },    { OROR, "||" },    { ANDAND, "&&" },    { EQ, "==" },    { NE, "!=" },    { LE, "<=" },    { GE, ">=" },    { LSHIFT, "<<" },    { RSHIFT, ">>=" },    { ALIGN_K, "ALIGN" },    { BLOCK, "BLOCK" },    { SECTIONS, "SECTIONS" },    { SIZEOF_HEADERS, "SIZEOF_HEADERS" },    { NEXT, "NEXT" },    { SIZEOF, "SIZEOF" },    { ADDR, "ADDR" },    { LOADADDR, "LOADADDR" },    { MEMORY, "MEMORY" },    { DEFINED, "DEFINED" },    { TARGET_K, "TARGET" },    { SEARCH_DIR, "SEARCH_DIR" },    { MAP, "MAP" },    { QUAD, "QUAD" },    { SQUAD, "SQUAD" },    { LONG, "LONG" },    { SHORT, "SHORT" },    { BYTE, "BYTE" },    { ENTRY, "ENTRY" },    { 0, (char *) NULL }  };  unsigned int idx;  for (idx = 0; table[idx].name != (char *) NULL; idx++)    {      if (table[idx].code == code)	{	  fprintf (config.map_file, "%s", table[idx].name);	  return;	}    }  /* Not in table, just print it alone */  fprintf (config.map_file, "%c", code);}static voidmake_abs (ptr)     etree_value_type *ptr;{  asection *s = ptr->section->bfd_section;  ptr->value += s->vma;  ptr->section = abs_output_section;}static etree_value_typenew_abs (value)     bfd_vma value;{  etree_value_type new;  new.valid_p = true;  new.section = abs_output_section;  new.value = value;  return new;}static voidcheck (os, name, op)     lang_output_section_statement_type *os;     const char *name;     const char *op;{  if (os == NULL)    einfo (_("%F%P: %s uses undefined section %s\n"), op, name);  if (! os->processed)    einfo (_("%F%P: %s forward reference of section %s\n"), op, name);}etree_type *exp_intop (value)     bfd_vma value;{  etree_type *new = (etree_type *) stat_alloc (sizeof (new->value));  new->type.node_code = INT;  new->value.value = value;  new->type.node_class = etree_value;  return new;}/* Build an expression representing an unnamed relocateable value.  */etree_type *exp_relop (section, value)     asection *section;     bfd_vma value;{  etree_type *new = (etree_type *) stat_alloc (sizeof (new->rel));  new->type.node_code = REL;  new->type.node_class = etree_rel;  new->rel.section = section;  new->rel.value = value;  return new;}static etree_value_typenew_rel (value, section)     bfd_vma value;     lang_output_section_statement_type *section;{  etree_value_type new;  new.valid_p = true;  new.value = value;  new.section = section;  return new;}static etree_value_typenew_rel_from_section (value, section)     bfd_vma value;     lang_output_section_statement_type *section;{  etree_value_type new;  new.valid_p = true;  new.value = value;  new.section = section;  new.value -= section->bfd_section->vma;  return new;}static etree_value_typefold_binary (tree, current_section, allocation_done, dot, dotp)     etree_type *tree;     lang_output_section_statement_type *current_section;     lang_phase_type allocation_done;     bfd_vma dot;     bfd_vma *dotp;{  etree_value_type result;  result = exp_fold_tree (tree->binary.lhs, current_section,			  allocation_done, dot, dotp);  if (result.valid_p)    {      etree_value_type other;      other = exp_fold_tree (tree->binary.rhs,			     current_section,			     allocation_done, dot, dotp);      if (other.valid_p)	{	  /* If the values are from different sections, or this is an	     absolute expression, make both the source arguments	     absolute.  However, adding or subtracting an absolute	     value from a relative value is meaningful, and is an	     exception.  */	  if (current_section != abs_output_section	      && (other.section == abs_output_section		  || (result.section == abs_output_section		      && tree->type.node_code == '+'))	      && (tree->type.node_code == '+'		  || tree->type.node_code == '-'))	    {	      etree_value_type hold;	      /* If there is only one absolute term, make sure it is the		 second one.  */	      if (other.section != abs_output_section)		{		  hold = result;		  result = other;		  other = hold;		}	    }	  else if (result.section != other.section		   || current_section == abs_output_section)	    {	      make_abs (&result);	      make_abs (&other);	    }	  switch (tree->type.node_code)	    {	    case '%':	      if (other.value == 0)		einfo (_("%F%S %% by zero\n"));	      result.value = ((bfd_signed_vma) result.value			      % (bfd_signed_vma) other.value);	      break;	    case '/':	      if (other.value == 0)		einfo (_("%F%S / by zero\n"));	      result.value = ((bfd_signed_vma) result.value			      / (bfd_signed_vma) other.value);	      break;#define BOP(x,y) case x : result.value = result.value y other.value; break;	      BOP ('+', +);	      BOP ('*', *);	      BOP ('-', -);	      BOP (LSHIFT, <<);	      BOP (RSHIFT, >>);	      BOP (EQ, ==);	      BOP (NE, !=);	      BOP ('<', <);	      BOP ('>', >);	      BOP (LE, <=);	      BOP (GE, >=);	      BOP ('&', &);	      BOP ('^', ^);	      BOP ('|', |);	      BOP (ANDAND, &&);	      BOP (OROR, ||);	    case MAX_K:	      if (result.value < other.value)		result = other;	      break;	    case MIN_K:	      if (result.value > other.value)		result = other;	      break;	    default:	      FAIL ();	    }	}      else	{	  result.valid_p = false;	}    }  return result;}etree_value_typeinvalid (){  etree_value_type new;  new.valid_p = false;  return new;}static etree_value_typefold_name (tree, current_section, allocation_done, dot)     etree_type *tree;     lang_output_section_statement_type *current_section;     lang_phase_type allocation_done;     bfd_vma dot;{  etree_value_type result;  switch (tree->type.node_code)    {    case SIZEOF_HEADERS:      if (allocation_done != lang_first_phase_enum)	{	  result = new_abs ((bfd_vma)			    bfd_sizeof_headers (output_bfd,						link_info.relocateable));	}      else	{	  result.valid_p = false;	}      break;    case DEFINED:      if (allocation_done == lang_first_phase_enum)	result.valid_p = false;      else	{	  struct bfd_link_hash_entry *h;	  h = bfd_wrapped_link_hash_lookup (output_bfd, &link_info,					    tree->name.name,					    false, false, true);	  result.value = (h != (struct bfd_link_hash_entry *) NULL			  && (h->type == bfd_link_hash_defined			      || h->type == bfd_link_hash_defweak			      || h->type == bfd_link_hash_common));	  result.section = 0;	  result.valid_p = true;	}      break;    case NAME:      result.valid_p = false;      if (tree->name.name[0] == '.' && tree->name.name[1] == 0)	{	  if (allocation_done != lang_first_phase_enum)	    result = new_rel_from_section (dot, current_section);	  else	    result = invalid ();	}      else if (allocation_done != lang_first_phase_enum)	{	  struct bfd_link_hash_entry *h;	  h = bfd_wrapped_link_hash_lookup (output_bfd, &link_info,					    tree->name.name,					    false, false, true);	  if (h != NULL	      && (h->type == bfd_link_hash_defined		  || h->type == bfd_link_hash_defweak))	    {	      if (bfd_is_abs_section (h->u.def.section))		result = new_abs (h->u.def.value);	      else if (allocation_done == lang_final_phase_enum		       || allocation_done == lang_allocating_phase_enum)		{		  asection *output_section;		  output_section = h->u.def.section->output_section;		  if (output_section == NULL)		    einfo (_("%X%S: unresolvable symbol `%s' referenced in expression\n"),			   tree->name.name);		  else		    {		      lang_output_section_statement_type *os;		      os = (lang_output_section_statement_lookup			    (bfd_get_section_name (output_bfd,						   output_section)));		      /* FIXME: Is this correct if this section is			 being linked with -R?  */		      result = new_rel ((h->u.def.value					 + h->u.def.section->output_offset),					os);		    }		}	    }	  else if (allocation_done == lang_final_phase_enum)	    einfo (_("%F%S: undefined symbol `%s' referenced in expression\n"),		   tree->name.name);	}      break;    case ADDR:      if (allocation_done != lang_first_phase_enum)	{	  lang_output_section_statement_type *os;	  os = lang_output_section_find (tree->name.name);	  check (os, tree->name.name, "ADDR");	  result = new_rel (0, os);	}      else	result = invalid ();      break;    case LOADADDR:      if (allocation_done != lang_first_phase_enum)	{	  lang_output_section_statement_type *os;	  os = lang_output_section_find (tree->name.name);	  check (os, tree->name.name, "LOADADDR");	  if (os->load_base == NULL)	    result = new_rel (0, os);	  else	    result = exp_fold_tree_no_dot (os->load_base,					   abs_output_section,					   allocation_done);	}      else	result = invalid ();      break;    case SIZEOF:      if (allocation_done != lang_first_phase_enum)	{	  int opb = bfd_octets_per_byte (output_bfd);	  lang_output_section_statement_type *os;	  os = lang_output_section_find (tree->name.name);	  check (os, tree->name.name, "SIZEOF");	  result = new_abs (os->bfd_section->_raw_size / opb);	}      else	result = invalid ();      break;    default:      FAIL ();      break;    }  return result;}etree_value_typeexp_fold_tree (tree, current_section, allocation_done, dot, dotp)     etree_type *tree;     lang_output_section_statement_type *current_section;     lang_phase_type allocation_done;     bfd_vma dot;     bfd_vma *dotp;{  etree_value_type result;  if (tree == NULL)    {      result.valid_p = false;      return result;    }  switch (tree->type.node_class)    {    case etree_value:      result = new_rel (tree->value.value, current_section);      break;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?