symbols.c revision 104834
133965Sjdp/* symbols.c -symbol table-
278828Sobrien   Copyright 1987, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
3104834Sobrien   1999, 2000, 2001, 2002
433965Sjdp   Free Software Foundation, Inc.
533965Sjdp
633965Sjdp   This file is part of GAS, the GNU Assembler.
733965Sjdp
833965Sjdp   GAS is free software; you can redistribute it and/or modify
933965Sjdp   it under the terms of the GNU General Public License as published by
1033965Sjdp   the Free Software Foundation; either version 2, or (at your option)
1133965Sjdp   any later version.
1233965Sjdp
1333965Sjdp   GAS is distributed in the hope that it will be useful,
1433965Sjdp   but WITHOUT ANY WARRANTY; without even the implied warranty of
1533965Sjdp   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1633965Sjdp   GNU General Public License for more details.
1733965Sjdp
1833965Sjdp   You should have received a copy of the GNU General Public License
1933965Sjdp   along with GAS; see the file COPYING.  If not, write to the Free
2033965Sjdp   Software Foundation, 59 Temple Place - Suite 330, Boston, MA
2133965Sjdp   02111-1307, USA.  */
2233965Sjdp
2377298Sobrien/* #define DEBUG_SYMS / * to debug symbol list maintenance.  */
2433965Sjdp
2533965Sjdp#include "as.h"
2633965Sjdp
2789857Sobrien#include "safe-ctype.h"
2833965Sjdp#include "obstack.h"		/* For "symbols.h" */
2933965Sjdp#include "subsegs.h"
3033965Sjdp
3160484Sobrien#include "struc-symbol.h"
3260484Sobrien
3333965Sjdp/* This is non-zero if symbols are case sensitive, which is the
3433965Sjdp   default.  */
3533965Sjdpint symbols_case_sensitive = 1;
3633965Sjdp
3733965Sjdp#ifndef WORKING_DOT_WORD
3833965Sjdpextern int new_broken_words;
3933965Sjdp#endif
4033965Sjdp
4133965Sjdp/* symbol-name => struct symbol pointer */
4233965Sjdpstatic struct hash_control *sy_hash;
4333965Sjdp
4460484Sobrien/* Table of local symbols.  */
4560484Sobrienstatic struct hash_control *local_hash;
4660484Sobrien
4777298Sobrien/* Below are commented in "symbols.h".  */
4833965SjdpsymbolS *symbol_rootP;
4933965SjdpsymbolS *symbol_lastP;
5033965SjdpsymbolS abs_symbol;
5133965Sjdp
5233965Sjdp#ifdef DEBUG_SYMS
5333965Sjdp#define debug_verify_symchain verify_symbol_chain
5433965Sjdp#else
5533965Sjdp#define debug_verify_symchain(root, last) ((void) 0)
5633965Sjdp#endif
5733965Sjdp
5877298Sobrien#define DOLLAR_LABEL_CHAR	'\001'
5977298Sobrien#define LOCAL_LABEL_CHAR	'\002'
6077298Sobrien
6133965Sjdpstruct obstack notes;
6233965Sjdp
6389857Sobrienstatic char *save_symbol_name PARAMS ((const char *));
6433965Sjdpstatic void fb_label_init PARAMS ((void));
6533965Sjdpstatic long dollar_label_instance PARAMS ((long));
6633965Sjdpstatic long fb_label_instance PARAMS ((long));
6733965Sjdp
6860484Sobrienstatic void print_binary PARAMS ((FILE *, const char *, expressionS *));
6960484Sobrien
7077298Sobrien/* Return a pointer to a new symbol.  Die if we can't make a new
7133965Sjdp   symbol.  Fill in the symbol's values.  Add symbol to end of symbol
7233965Sjdp   chain.
7377298Sobrien
7433965Sjdp   This function should be called in the general case of creating a
7533965Sjdp   symbol.  However, if the output file symbol table has already been
7633965Sjdp   set, and you are certain that this symbol won't be wanted in the
7733965Sjdp   output file, you can call symbol_create.  */
7833965Sjdp
7933965SjdpsymbolS *
8033965Sjdpsymbol_new (name, segment, valu, frag)
8133965Sjdp     const char *name;
8233965Sjdp     segT segment;
8333965Sjdp     valueT valu;
8433965Sjdp     fragS *frag;
8533965Sjdp{
8633965Sjdp  symbolS *symbolP = symbol_create (name, segment, valu, frag);
8733965Sjdp
8877298Sobrien  /* Link to end of symbol chain.  */
8933965Sjdp#ifdef BFD_ASSEMBLER
9033965Sjdp  {
9133965Sjdp    extern int symbol_table_frozen;
9233965Sjdp    if (symbol_table_frozen)
9333965Sjdp      abort ();
9433965Sjdp  }
9533965Sjdp#endif
9633965Sjdp  symbol_append (symbolP, symbol_lastP, &symbol_rootP, &symbol_lastP);
9733965Sjdp
9833965Sjdp  return symbolP;
9933965Sjdp}
10033965Sjdp
10160484Sobrien/* Save a symbol name on a permanent obstack, and convert it according
10260484Sobrien   to the object file format.  */
10360484Sobrien
10460484Sobrienstatic char *
10560484Sobriensave_symbol_name (name)
10660484Sobrien     const char *name;
10733965Sjdp{
10833965Sjdp  unsigned int name_length;
10960484Sobrien  char *ret;
11033965Sjdp
11177298Sobrien  name_length = strlen (name) + 1;	/* +1 for \0.  */
11233965Sjdp  obstack_grow (&notes, name, name_length);
11360484Sobrien  ret = obstack_finish (&notes);
11460484Sobrien
11533965Sjdp#ifdef STRIP_UNDERSCORE
11660484Sobrien  if (ret[0] == '_')
11760484Sobrien    ++ret;
11833965Sjdp#endif
11933965Sjdp
12033965Sjdp#ifdef tc_canonicalize_symbol_name
12160484Sobrien  ret = tc_canonicalize_symbol_name (ret);
12233965Sjdp#endif
12333965Sjdp
12433965Sjdp  if (! symbols_case_sensitive)
12533965Sjdp    {
12689857Sobrien      char *s;
12733965Sjdp
12889857Sobrien      for (s = ret; *s != '\0'; s++)
12989857Sobrien	*s = TOUPPER (*s);
13033965Sjdp    }
13133965Sjdp
13260484Sobrien  return ret;
13360484Sobrien}
13460484Sobrien
13560484SobriensymbolS *
13660484Sobriensymbol_create (name, segment, valu, frag)
13777298Sobrien     const char *name;		/* It is copied, the caller can destroy/modify.  */
13877298Sobrien     segT segment;		/* Segment identifier (SEG_<something>).  */
13977298Sobrien     valueT valu;		/* Symbol value.  */
14077298Sobrien     fragS *frag;		/* Associated fragment.  */
14160484Sobrien{
14260484Sobrien  char *preserved_copy_of_name;
14360484Sobrien  symbolS *symbolP;
14460484Sobrien
14560484Sobrien  preserved_copy_of_name = save_symbol_name (name);
14660484Sobrien
14733965Sjdp  symbolP = (symbolS *) obstack_alloc (&notes, sizeof (symbolS));
14833965Sjdp
14977298Sobrien  /* symbol must be born in some fixed state.  This seems as good as any.  */
15033965Sjdp  memset (symbolP, 0, sizeof (symbolS));
15133965Sjdp
15233965Sjdp#ifdef BFD_ASSEMBLER
15333965Sjdp  symbolP->bsym = bfd_make_empty_symbol (stdoutput);
15433965Sjdp  if (symbolP->bsym == NULL)
15533965Sjdp    as_perror ("%s", "bfd_make_empty_symbol");
15633965Sjdp  symbolP->bsym->udata.p = (PTR) symbolP;
15733965Sjdp#endif
15833965Sjdp  S_SET_NAME (symbolP, preserved_copy_of_name);
15933965Sjdp
16033965Sjdp  S_SET_SEGMENT (symbolP, segment);
16133965Sjdp  S_SET_VALUE (symbolP, valu);
16233965Sjdp  symbol_clear_list_pointers (symbolP);
16333965Sjdp
16433965Sjdp  symbolP->sy_frag = frag;
16533965Sjdp#ifndef BFD_ASSEMBLER
16633965Sjdp  symbolP->sy_number = ~0;
16733965Sjdp  symbolP->sy_name_offset = (unsigned int) ~0;
16833965Sjdp#endif
16933965Sjdp
17033965Sjdp  obj_symbol_new_hook (symbolP);
17133965Sjdp
17233965Sjdp#ifdef tc_symbol_new_hook
17333965Sjdp  tc_symbol_new_hook (symbolP);
17433965Sjdp#endif
17533965Sjdp
17633965Sjdp  return symbolP;
17733965Sjdp}
17833965Sjdp
17960484Sobrien#ifdef BFD_ASSEMBLER
18033965Sjdp
18160484Sobrien/* Local symbol support.  If we can get away with it, we keep only a
18260484Sobrien   small amount of information for local symbols.  */
18360484Sobrien
18460484Sobrienstatic struct local_symbol *local_symbol_make PARAMS ((const char *, segT,
18560484Sobrien						       valueT, fragS *));
18660484Sobrienstatic symbolS *local_symbol_convert PARAMS ((struct local_symbol *));
18760484Sobrien
18860484Sobrien/* Used for statistics.  */
18960484Sobrien
19060484Sobrienstatic unsigned long local_symbol_count;
19160484Sobrienstatic unsigned long local_symbol_conversion_count;
19260484Sobrien
19360484Sobrien/* This macro is called with a symbol argument passed by reference.
19460484Sobrien   It returns whether this is a local symbol.  If necessary, it
19560484Sobrien   changes its argument to the real symbol.  */
19660484Sobrien
19760484Sobrien#define LOCAL_SYMBOL_CHECK(s)						\
19860484Sobrien  (s->bsym == NULL							\
19960484Sobrien   ? (local_symbol_converted_p ((struct local_symbol *) s)		\
20060484Sobrien      ? (s = local_symbol_get_real_symbol ((struct local_symbol *) s),	\
20160484Sobrien	 0)								\
20260484Sobrien      : 1)								\
20360484Sobrien   : 0)
20460484Sobrien
20560484Sobrien/* Create a local symbol and insert it into the local hash table.  */
20660484Sobrien
20760484Sobrienstatic struct local_symbol *
20889857Sobrienlocal_symbol_make (name, section, value, frag)
20960484Sobrien     const char *name;
21060484Sobrien     segT section;
21189857Sobrien     valueT value;
21260484Sobrien     fragS *frag;
21360484Sobrien{
21460484Sobrien  char *name_copy;
21560484Sobrien  struct local_symbol *ret;
21660484Sobrien
21760484Sobrien  ++local_symbol_count;
21860484Sobrien
21960484Sobrien  name_copy = save_symbol_name (name);
22060484Sobrien
22160484Sobrien  ret = (struct local_symbol *) obstack_alloc (&notes, sizeof *ret);
22260484Sobrien  ret->lsy_marker = NULL;
22360484Sobrien  ret->lsy_name = name_copy;
22460484Sobrien  ret->lsy_section = section;
22560484Sobrien  local_symbol_set_frag (ret, frag);
22689857Sobrien  ret->lsy_value = value;
22760484Sobrien
22860484Sobrien  hash_jam (local_hash, name_copy, (PTR) ret);
22960484Sobrien
23060484Sobrien  return ret;
23160484Sobrien}
23260484Sobrien
23360484Sobrien/* Convert a local symbol into a real symbol.  Note that we do not
23460484Sobrien   reclaim the space used by the local symbol.  */
23560484Sobrien
23660484Sobrienstatic symbolS *
23760484Sobrienlocal_symbol_convert (locsym)
23860484Sobrien     struct local_symbol *locsym;
23960484Sobrien{
24060484Sobrien  symbolS *ret;
24160484Sobrien
24260484Sobrien  assert (locsym->lsy_marker == NULL);
24360484Sobrien  if (local_symbol_converted_p (locsym))
24460484Sobrien    return local_symbol_get_real_symbol (locsym);
24560484Sobrien
24660484Sobrien  ++local_symbol_conversion_count;
24760484Sobrien
24889857Sobrien  ret = symbol_new (locsym->lsy_name, locsym->lsy_section, locsym->lsy_value,
24960484Sobrien		    local_symbol_get_frag (locsym));
25060484Sobrien
25160484Sobrien  if (local_symbol_resolved_p (locsym))
25260484Sobrien    ret->sy_resolved = 1;
25360484Sobrien
25460484Sobrien  /* Local symbols are always either defined or used.  */
25560484Sobrien  ret->sy_used = 1;
25660484Sobrien
25789857Sobrien#ifdef TC_LOCAL_SYMFIELD_CONVERT
25889857Sobrien  TC_LOCAL_SYMFIELD_CONVERT (locsym, ret);
25989857Sobrien#endif
26089857Sobrien
26160484Sobrien  symbol_table_insert (ret);
26260484Sobrien
26360484Sobrien  local_symbol_mark_converted (locsym);
26460484Sobrien  local_symbol_set_real_symbol (locsym, ret);
26560484Sobrien
26660484Sobrien  hash_jam (local_hash, locsym->lsy_name, NULL);
26760484Sobrien
26860484Sobrien  return ret;
26960484Sobrien}
27060484Sobrien
27160484Sobrien#else /* ! BFD_ASSEMBLER */
27260484Sobrien
27360484Sobrien#define LOCAL_SYMBOL_CHECK(s) 0
27460484Sobrien#define local_symbol_convert(s) ((symbolS *) s)
27560484Sobrien
27660484Sobrien#endif /* ! BFD_ASSEMBLER */
27760484Sobrien
27877298Sobrien/* We have just seen "<name>:".
27977298Sobrien   Creates a struct symbol unless it already exists.
28060484Sobrien
28177298Sobrien   Gripes if we are redefining a symbol incompatibly (and ignores it).  */
28277298Sobrien
28333965SjdpsymbolS *
28477298Sobriencolon (sym_name)		/* Just seen "x:" - rattle symbols & frags.  */
28577298Sobrien     const char *sym_name;	/* Symbol name, as a cannonical string.  */
28677298Sobrien     /* We copy this string: OK to alter later.  */
28733965Sjdp{
28877298Sobrien  register symbolS *symbolP;	/* Symbol we are working with.  */
28933965Sjdp
29033965Sjdp  /* Sun local labels go out of scope whenever a non-local symbol is
29133965Sjdp     defined.  */
29233965Sjdp  if (LOCAL_LABELS_DOLLAR)
29333965Sjdp    {
29433965Sjdp      int local;
29533965Sjdp
29633965Sjdp#ifdef BFD_ASSEMBLER
29733965Sjdp      local = bfd_is_local_label_name (stdoutput, sym_name);
29833965Sjdp#else
29933965Sjdp      local = LOCAL_LABEL (sym_name);
30033965Sjdp#endif
30133965Sjdp
30233965Sjdp      if (! local)
30333965Sjdp	dollar_label_clear ();
30433965Sjdp    }
30533965Sjdp
30633965Sjdp#ifndef WORKING_DOT_WORD
30733965Sjdp  if (new_broken_words)
30833965Sjdp    {
30933965Sjdp      struct broken_word *a;
31033965Sjdp      int possible_bytes;
31133965Sjdp      fragS *frag_tmp;
31233965Sjdp      char *frag_opcode;
31333965Sjdp
31433965Sjdp      extern const int md_short_jump_size;
31533965Sjdp      extern const int md_long_jump_size;
31633965Sjdp      possible_bytes = (md_short_jump_size
31733965Sjdp			+ new_broken_words * md_long_jump_size);
31833965Sjdp
31933965Sjdp      frag_tmp = frag_now;
32033965Sjdp      frag_opcode = frag_var (rs_broken_word,
32133965Sjdp			      possible_bytes,
32233965Sjdp			      possible_bytes,
32333965Sjdp			      (relax_substateT) 0,
32433965Sjdp			      (symbolS *) broken_words,
32533965Sjdp			      (offsetT) 0,
32633965Sjdp			      NULL);
32733965Sjdp
32877298Sobrien      /* We want to store the pointer to where to insert the jump
32977298Sobrien	 table in the fr_opcode of the rs_broken_word frag.  This
33077298Sobrien	 requires a little hackery.  */
33133965Sjdp      while (frag_tmp
33233965Sjdp	     && (frag_tmp->fr_type != rs_broken_word
33333965Sjdp		 || frag_tmp->fr_opcode))
33433965Sjdp	frag_tmp = frag_tmp->fr_next;
33533965Sjdp      know (frag_tmp);
33633965Sjdp      frag_tmp->fr_opcode = frag_opcode;
33733965Sjdp      new_broken_words = 0;
33833965Sjdp
33933965Sjdp      for (a = broken_words; a && a->dispfrag == 0; a = a->next_broken_word)
34033965Sjdp	a->dispfrag = frag_tmp;
34133965Sjdp    }
34233965Sjdp#endif /* WORKING_DOT_WORD */
34333965Sjdp
34433965Sjdp  if ((symbolP = symbol_find (sym_name)) != 0)
34533965Sjdp    {
34633965Sjdp#ifdef RESOLVE_SYMBOL_REDEFINITION
34733965Sjdp      if (RESOLVE_SYMBOL_REDEFINITION (symbolP))
34833965Sjdp	return symbolP;
34933965Sjdp#endif
35077298Sobrien      /* Now check for undefined symbols.  */
35160484Sobrien      if (LOCAL_SYMBOL_CHECK (symbolP))
35233965Sjdp	{
35360484Sobrien#ifdef BFD_ASSEMBLER
35460484Sobrien	  struct local_symbol *locsym = (struct local_symbol *) symbolP;
35560484Sobrien
35660484Sobrien	  if (locsym->lsy_section != undefined_section
35760484Sobrien	      && (local_symbol_get_frag (locsym) != frag_now
35860484Sobrien		  || locsym->lsy_section != now_seg
35989857Sobrien		  || locsym->lsy_value != frag_now_fix ()))
36060484Sobrien	    {
36189857Sobrien	      as_bad (_("symbol `%s' is already defined"), sym_name);
36260484Sobrien	      return symbolP;
36360484Sobrien	    }
36460484Sobrien
36560484Sobrien	  locsym->lsy_section = now_seg;
36660484Sobrien	  local_symbol_set_frag (locsym, frag_now);
36789857Sobrien	  locsym->lsy_value = frag_now_fix ();
36860484Sobrien#endif
36960484Sobrien	}
37060484Sobrien      else if (!S_IS_DEFINED (symbolP) || S_IS_COMMON (symbolP))
37160484Sobrien	{
37233965Sjdp	  if (S_GET_VALUE (symbolP) == 0)
37333965Sjdp	    {
37433965Sjdp	      symbolP->sy_frag = frag_now;
37533965Sjdp#ifdef OBJ_VMS
37677298Sobrien	      S_SET_OTHER (symbolP, const_flag);
37733965Sjdp#endif
37833965Sjdp	      S_SET_VALUE (symbolP, (valueT) frag_now_fix ());
37933965Sjdp	      S_SET_SEGMENT (symbolP, now_seg);
38033965Sjdp#ifdef N_UNDF
38133965Sjdp	      know (N_UNDF == 0);
38277298Sobrien#endif /* if we have one, it better be zero.  */
38333965Sjdp
38433965Sjdp	    }
38533965Sjdp	  else
38633965Sjdp	    {
38777298Sobrien	      /* There are still several cases to check:
38833965Sjdp
38977298Sobrien		 A .comm/.lcomm symbol being redefined as initialized
39077298Sobrien		 data is OK
39177298Sobrien
39277298Sobrien		 A .comm/.lcomm symbol being redefined with a larger
39377298Sobrien		 size is also OK
39477298Sobrien
39577298Sobrien		 This only used to be allowed on VMS gas, but Sun cc
39677298Sobrien		 on the sparc also depends on it.  */
39777298Sobrien
39833965Sjdp	      if (((!S_IS_DEBUG (symbolP)
39933965Sjdp		    && (!S_IS_DEFINED (symbolP) || S_IS_COMMON (symbolP))
40033965Sjdp		    && S_IS_EXTERNAL (symbolP))
40133965Sjdp		   || S_GET_SEGMENT (symbolP) == bss_section)
40233965Sjdp		  && (now_seg == data_section
40333965Sjdp		      || now_seg == S_GET_SEGMENT (symbolP)))
40433965Sjdp		{
40577298Sobrien		  /* Select which of the 2 cases this is.  */
40633965Sjdp		  if (now_seg != data_section)
40733965Sjdp		    {
40877298Sobrien		      /* New .comm for prev .comm symbol.
40977298Sobrien
41077298Sobrien			 If the new size is larger we just change its
41177298Sobrien			 value.  If the new size is smaller, we ignore
41277298Sobrien			 this symbol.  */
41333965Sjdp		      if (S_GET_VALUE (symbolP)
41433965Sjdp			  < ((unsigned) frag_now_fix ()))
41533965Sjdp			{
41633965Sjdp			  S_SET_VALUE (symbolP, (valueT) frag_now_fix ());
41733965Sjdp			}
41833965Sjdp		    }
41933965Sjdp		  else
42033965Sjdp		    {
42133965Sjdp		      /* It is a .comm/.lcomm being converted to initialized
42233965Sjdp			 data.  */
42333965Sjdp		      symbolP->sy_frag = frag_now;
42433965Sjdp#ifdef OBJ_VMS
42577298Sobrien		      S_SET_OTHER (symbolP, const_flag);
42633965Sjdp#endif
42733965Sjdp		      S_SET_VALUE (symbolP, (valueT) frag_now_fix ());
42877298Sobrien		      S_SET_SEGMENT (symbolP, now_seg);	/* Keep N_EXT bit.  */
42933965Sjdp		    }
43033965Sjdp		}
43133965Sjdp	      else
43233965Sjdp		{
43360484Sobrien#if (!defined (OBJ_AOUT) && !defined (OBJ_MAYBE_AOUT) \
43460484Sobrien     && !defined (OBJ_BOUT) && !defined (OBJ_MAYBE_BOUT))
43560484Sobrien		  static const char *od_buf = "";
43633965Sjdp#else
43760484Sobrien		  char od_buf[100];
43860484Sobrien		  od_buf[0] = '\0';
43960484Sobrien#ifdef BFD_ASSEMBLER
44060484Sobrien		  if (OUTPUT_FLAVOR == bfd_target_aout_flavour)
44160484Sobrien#endif
442104834Sobrien		    sprintf (od_buf, "%d.%d.",
443104834Sobrien			     S_GET_OTHER (symbolP),
444104834Sobrien			     S_GET_DESC (symbolP));
44560484Sobrien#endif
44689857Sobrien		  as_bad (_("symbol `%s' is already defined as \"%s\"/%s%ld"),
44733965Sjdp			    sym_name,
44833965Sjdp			    segment_name (S_GET_SEGMENT (symbolP)),
44960484Sobrien			    od_buf,
45033965Sjdp			    (long) S_GET_VALUE (symbolP));
45133965Sjdp		}
45277298Sobrien	    }			/* if the undefined symbol has no value  */
45333965Sjdp	}
45433965Sjdp      else
45533965Sjdp	{
45677298Sobrien	  /* Don't blow up if the definition is the same.  */
45733965Sjdp	  if (!(frag_now == symbolP->sy_frag
45833965Sjdp		&& S_GET_VALUE (symbolP) == frag_now_fix ()
45933965Sjdp		&& S_GET_SEGMENT (symbolP) == now_seg))
46089857Sobrien	    as_bad (_("symbol `%s' is already defined"), sym_name);
46177298Sobrien	}
46233965Sjdp
46333965Sjdp    }
46460484Sobrien#ifdef BFD_ASSEMBLER
46560484Sobrien  else if (! flag_keep_locals && bfd_is_local_label_name (stdoutput, sym_name))
46660484Sobrien    {
46760484Sobrien      symbolP = (symbolS *) local_symbol_make (sym_name, now_seg,
46860484Sobrien					       (valueT) frag_now_fix (),
46960484Sobrien					       frag_now);
47060484Sobrien    }
47160484Sobrien#endif /* BFD_ASSEMBLER */
47233965Sjdp  else
47333965Sjdp    {
47433965Sjdp      symbolP = symbol_new (sym_name, now_seg, (valueT) frag_now_fix (),
47533965Sjdp			    frag_now);
47633965Sjdp#ifdef OBJ_VMS
47733965Sjdp      S_SET_OTHER (symbolP, const_flag);
47833965Sjdp#endif /* OBJ_VMS */
47933965Sjdp
48033965Sjdp      symbol_table_insert (symbolP);
48177298Sobrien    }
48233965Sjdp
48333965Sjdp  if (mri_common_symbol != NULL)
48433965Sjdp    {
48533965Sjdp      /* This symbol is actually being defined within an MRI common
48633965Sjdp         section.  This requires special handling.  */
48760484Sobrien      if (LOCAL_SYMBOL_CHECK (symbolP))
48860484Sobrien	symbolP = local_symbol_convert ((struct local_symbol *) symbolP);
48933965Sjdp      symbolP->sy_value.X_op = O_symbol;
49033965Sjdp      symbolP->sy_value.X_add_symbol = mri_common_symbol;
49133965Sjdp      symbolP->sy_value.X_add_number = S_GET_VALUE (mri_common_symbol);
49233965Sjdp      symbolP->sy_frag = &zero_address_frag;
49333965Sjdp      S_SET_SEGMENT (symbolP, expr_section);
49433965Sjdp      symbolP->sy_mri_common = 1;
49533965Sjdp    }
49633965Sjdp
49733965Sjdp#ifdef tc_frob_label
49833965Sjdp  tc_frob_label (symbolP);
49933965Sjdp#endif
50033965Sjdp#ifdef obj_frob_label
50133965Sjdp  obj_frob_label (symbolP);
50233965Sjdp#endif
50333965Sjdp
50433965Sjdp  return symbolP;
50533965Sjdp}
50633965Sjdp
50777298Sobrien/* Die if we can't insert the symbol.  */
50833965Sjdp
50977298Sobrienvoid
51033965Sjdpsymbol_table_insert (symbolP)
51133965Sjdp     symbolS *symbolP;
51233965Sjdp{
51333965Sjdp  register const char *error_string;
51433965Sjdp
51533965Sjdp  know (symbolP);
51633965Sjdp  know (S_GET_NAME (symbolP));
51733965Sjdp
51860484Sobrien  if (LOCAL_SYMBOL_CHECK (symbolP))
51960484Sobrien    {
52060484Sobrien      error_string = hash_jam (local_hash, S_GET_NAME (symbolP),
52160484Sobrien			       (PTR) symbolP);
52260484Sobrien      if (error_string != NULL)
52389857Sobrien	as_fatal (_("inserting \"%s\" into symbol table failed: %s"),
52460484Sobrien		  S_GET_NAME (symbolP), error_string);
52560484Sobrien      return;
52660484Sobrien    }
52760484Sobrien
52833965Sjdp  if ((error_string = hash_jam (sy_hash, S_GET_NAME (symbolP), (PTR) symbolP)))
52933965Sjdp    {
53089857Sobrien      as_fatal (_("inserting \"%s\" into symbol table failed: %s"),
53133965Sjdp		S_GET_NAME (symbolP), error_string);
53277298Sobrien    }				/* on error  */
53377298Sobrien}
53433965Sjdp
53577298Sobrien/* If a symbol name does not exist, create it as undefined, and insert
53677298Sobrien   it into the symbol table.  Return a pointer to it.  */
53777298Sobrien
53833965SjdpsymbolS *
53933965Sjdpsymbol_find_or_make (name)
54033965Sjdp     const char *name;
54133965Sjdp{
54233965Sjdp  register symbolS *symbolP;
54333965Sjdp
54433965Sjdp  symbolP = symbol_find (name);
54533965Sjdp
54633965Sjdp  if (symbolP == NULL)
54733965Sjdp    {
54860484Sobrien#ifdef BFD_ASSEMBLER
54960484Sobrien      if (! flag_keep_locals && bfd_is_local_label_name (stdoutput, name))
55060484Sobrien	{
55160484Sobrien	  symbolP = md_undefined_symbol ((char *) name);
55260484Sobrien	  if (symbolP != NULL)
55360484Sobrien	    return symbolP;
55460484Sobrien
55560484Sobrien	  symbolP = (symbolS *) local_symbol_make (name, undefined_section,
55660484Sobrien						   (valueT) 0,
55760484Sobrien						   &zero_address_frag);
55860484Sobrien	  return symbolP;
55960484Sobrien	}
56060484Sobrien#endif
56160484Sobrien
56233965Sjdp      symbolP = symbol_make (name);
56333965Sjdp
56433965Sjdp      symbol_table_insert (symbolP);
56533965Sjdp    }				/* if symbol wasn't found */
56633965Sjdp
56733965Sjdp  return (symbolP);
56877298Sobrien}
56933965Sjdp
57033965SjdpsymbolS *
57133965Sjdpsymbol_make (name)
572104834Sobrien     const char *name;
57333965Sjdp{
57433965Sjdp  symbolS *symbolP;
57533965Sjdp
57677298Sobrien  /* Let the machine description default it, e.g. for register names.  */
57733965Sjdp  symbolP = md_undefined_symbol ((char *) name);
57833965Sjdp
57933965Sjdp  if (!symbolP)
58033965Sjdp    symbolP = symbol_new (name, undefined_section, (valueT) 0, &zero_address_frag);
58133965Sjdp
58233965Sjdp  return (symbolP);
58377298Sobrien}
58433965Sjdp
58577298Sobrien/* Implement symbol table lookup.
58677298Sobrien   In:	A symbol's name as a string: '\0' can't be part of a symbol name.
58777298Sobrien   Out:	NULL if the name was not in the symbol table, else the address
58877298Sobrien   of a struct symbol associated with that name.  */
58933965Sjdp
59033965SjdpsymbolS *
59133965Sjdpsymbol_find (name)
592104834Sobrien     const char *name;
59333965Sjdp{
59433965Sjdp#ifdef STRIP_UNDERSCORE
59533965Sjdp  return (symbol_find_base (name, 1));
59633965Sjdp#else /* STRIP_UNDERSCORE */
59733965Sjdp  return (symbol_find_base (name, 0));
59833965Sjdp#endif /* STRIP_UNDERSCORE */
59977298Sobrien}
60033965Sjdp
60133965SjdpsymbolS *
602104834Sobriensymbol_find_exact (name)
603104834Sobrien     const char *name;
604104834Sobrien{
605104834Sobrien#ifdef BFD_ASSEMBLER
606104834Sobrien  {
607104834Sobrien    struct local_symbol *locsym;
608104834Sobrien
609104834Sobrien    locsym = (struct local_symbol *) hash_find (local_hash, name);
610104834Sobrien    if (locsym != NULL)
611104834Sobrien      return (symbolS *) locsym;
612104834Sobrien  }
613104834Sobrien#endif
614104834Sobrien
615104834Sobrien  return ((symbolS *) hash_find (sy_hash, name));
616104834Sobrien}
617104834Sobrien
618104834SobriensymbolS *
61933965Sjdpsymbol_find_base (name, strip_underscore)
620104834Sobrien     const char *name;
62133965Sjdp     int strip_underscore;
62233965Sjdp{
62333965Sjdp  if (strip_underscore && *name == '_')
62433965Sjdp    name++;
62533965Sjdp
62633965Sjdp#ifdef tc_canonicalize_symbol_name
62733965Sjdp  {
62833965Sjdp    char *copy;
62960484Sobrien    size_t len = strlen (name) + 1;
63033965Sjdp
63160484Sobrien    copy = (char *) alloca (len);
63260484Sobrien    memcpy (copy, name, len);
63333965Sjdp    name = tc_canonicalize_symbol_name (copy);
63433965Sjdp  }
63533965Sjdp#endif
63633965Sjdp
63733965Sjdp  if (! symbols_case_sensitive)
63833965Sjdp    {
63960484Sobrien      char *copy;
64060484Sobrien      const char *orig;
64160484Sobrien      unsigned char c;
64233965Sjdp
64360484Sobrien      orig = name;
64460484Sobrien      name = copy = (char *) alloca (strlen (name) + 1);
64560484Sobrien
64660484Sobrien      while ((c = *orig++) != '\0')
64760484Sobrien	{
64889857Sobrien	  *copy++ = TOUPPER (c);
64960484Sobrien	}
65060484Sobrien      *copy = '\0';
65133965Sjdp    }
65233965Sjdp
653104834Sobrien  return symbol_find_exact (name);
65433965Sjdp}
65533965Sjdp
65677298Sobrien/* Once upon a time, symbols were kept in a singly linked list.  At
65777298Sobrien   least coff needs to be able to rearrange them from time to time, for
65877298Sobrien   which a doubly linked list is much more convenient.  Loic did these
65977298Sobrien   as macros which seemed dangerous to me so they're now functions.
66077298Sobrien   xoxorich.  */
66133965Sjdp
66277298Sobrien/* Link symbol ADDME after symbol TARGET in the chain.  */
66377298Sobrien
66477298Sobrienvoid
66533965Sjdpsymbol_append (addme, target, rootPP, lastPP)
66633965Sjdp     symbolS *addme;
66733965Sjdp     symbolS *target;
66833965Sjdp     symbolS **rootPP;
66933965Sjdp     symbolS **lastPP;
67033965Sjdp{
67160484Sobrien  if (LOCAL_SYMBOL_CHECK (addme))
67260484Sobrien    abort ();
67360484Sobrien  if (target != NULL && LOCAL_SYMBOL_CHECK (target))
67460484Sobrien    abort ();
67560484Sobrien
67633965Sjdp  if (target == NULL)
67733965Sjdp    {
67833965Sjdp      know (*rootPP == NULL);
67933965Sjdp      know (*lastPP == NULL);
68033965Sjdp      addme->sy_next = NULL;
68133965Sjdp#ifdef SYMBOLS_NEED_BACKPOINTERS
68233965Sjdp      addme->sy_previous = NULL;
68333965Sjdp#endif
68433965Sjdp      *rootPP = addme;
68533965Sjdp      *lastPP = addme;
68633965Sjdp      return;
68777298Sobrien    }				/* if the list is empty  */
68833965Sjdp
68933965Sjdp  if (target->sy_next != NULL)
69033965Sjdp    {
69133965Sjdp#ifdef SYMBOLS_NEED_BACKPOINTERS
69233965Sjdp      target->sy_next->sy_previous = addme;
69333965Sjdp#endif /* SYMBOLS_NEED_BACKPOINTERS */
69433965Sjdp    }
69533965Sjdp  else
69633965Sjdp    {
69733965Sjdp      know (*lastPP == target);
69833965Sjdp      *lastPP = addme;
69977298Sobrien    }				/* if we have a next  */
70033965Sjdp
70133965Sjdp  addme->sy_next = target->sy_next;
70233965Sjdp  target->sy_next = addme;
70333965Sjdp
70433965Sjdp#ifdef SYMBOLS_NEED_BACKPOINTERS
70533965Sjdp  addme->sy_previous = target;
70633965Sjdp#endif /* SYMBOLS_NEED_BACKPOINTERS */
70733965Sjdp
70833965Sjdp  debug_verify_symchain (symbol_rootP, symbol_lastP);
70933965Sjdp}
71033965Sjdp
71177298Sobrien/* Set the chain pointers of SYMBOL to null.  */
71277298Sobrien
71377298Sobrienvoid
71433965Sjdpsymbol_clear_list_pointers (symbolP)
71533965Sjdp     symbolS *symbolP;
71633965Sjdp{
71760484Sobrien  if (LOCAL_SYMBOL_CHECK (symbolP))
71860484Sobrien    abort ();
71933965Sjdp  symbolP->sy_next = NULL;
72033965Sjdp#ifdef SYMBOLS_NEED_BACKPOINTERS
72133965Sjdp  symbolP->sy_previous = NULL;
72233965Sjdp#endif
72333965Sjdp}
72433965Sjdp
72533965Sjdp#ifdef SYMBOLS_NEED_BACKPOINTERS
72677298Sobrien/* Remove SYMBOLP from the list.  */
72777298Sobrien
72877298Sobrienvoid
72933965Sjdpsymbol_remove (symbolP, rootPP, lastPP)
73033965Sjdp     symbolS *symbolP;
73133965Sjdp     symbolS **rootPP;
73233965Sjdp     symbolS **lastPP;
73333965Sjdp{
73460484Sobrien  if (LOCAL_SYMBOL_CHECK (symbolP))
73560484Sobrien    abort ();
73660484Sobrien
73733965Sjdp  if (symbolP == *rootPP)
73833965Sjdp    {
73933965Sjdp      *rootPP = symbolP->sy_next;
74077298Sobrien    }				/* if it was the root  */
74133965Sjdp
74233965Sjdp  if (symbolP == *lastPP)
74333965Sjdp    {
74433965Sjdp      *lastPP = symbolP->sy_previous;
74577298Sobrien    }				/* if it was the tail  */
74633965Sjdp
74733965Sjdp  if (symbolP->sy_next != NULL)
74833965Sjdp    {
74933965Sjdp      symbolP->sy_next->sy_previous = symbolP->sy_previous;
75077298Sobrien    }				/* if not last  */
75133965Sjdp
75233965Sjdp  if (symbolP->sy_previous != NULL)
75333965Sjdp    {
75433965Sjdp      symbolP->sy_previous->sy_next = symbolP->sy_next;
75577298Sobrien    }				/* if not first  */
75633965Sjdp
75733965Sjdp  debug_verify_symchain (*rootPP, *lastPP);
75833965Sjdp}
75933965Sjdp
76077298Sobrien/* Link symbol ADDME before symbol TARGET in the chain.  */
76177298Sobrien
76277298Sobrienvoid
76333965Sjdpsymbol_insert (addme, target, rootPP, lastPP)
76433965Sjdp     symbolS *addme;
76533965Sjdp     symbolS *target;
76633965Sjdp     symbolS **rootPP;
76760484Sobrien     symbolS **lastPP ATTRIBUTE_UNUSED;
76833965Sjdp{
76960484Sobrien  if (LOCAL_SYMBOL_CHECK (addme))
77060484Sobrien    abort ();
77160484Sobrien  if (LOCAL_SYMBOL_CHECK (target))
77260484Sobrien    abort ();
77360484Sobrien
77433965Sjdp  if (target->sy_previous != NULL)
77533965Sjdp    {
77633965Sjdp      target->sy_previous->sy_next = addme;
77733965Sjdp    }
77833965Sjdp  else
77933965Sjdp    {
78033965Sjdp      know (*rootPP == target);
78133965Sjdp      *rootPP = addme;
78277298Sobrien    }				/* if not first  */
78333965Sjdp
78433965Sjdp  addme->sy_previous = target->sy_previous;
78533965Sjdp  target->sy_previous = addme;
78633965Sjdp  addme->sy_next = target;
78733965Sjdp
78833965Sjdp  debug_verify_symchain (*rootPP, *lastPP);
78933965Sjdp}
79033965Sjdp
79133965Sjdp#endif /* SYMBOLS_NEED_BACKPOINTERS */
79233965Sjdp
79377298Sobrienvoid
79433965Sjdpverify_symbol_chain (rootP, lastP)
79533965Sjdp     symbolS *rootP;
79633965Sjdp     symbolS *lastP;
79733965Sjdp{
79833965Sjdp  symbolS *symbolP = rootP;
79933965Sjdp
80033965Sjdp  if (symbolP == NULL)
80133965Sjdp    return;
80233965Sjdp
80333965Sjdp  for (; symbol_next (symbolP) != NULL; symbolP = symbol_next (symbolP))
80433965Sjdp    {
80560484Sobrien#ifdef BFD_ASSEMBLER
80660484Sobrien      assert (symbolP->bsym != NULL);
80760484Sobrien#endif
80833965Sjdp#ifdef SYMBOLS_NEED_BACKPOINTERS
80933965Sjdp      assert (symbolP->sy_next->sy_previous == symbolP);
81033965Sjdp#else
81133965Sjdp      /* Walk the list anyways, to make sure pointers are still good.  */
81233965Sjdp      ;
81333965Sjdp#endif /* SYMBOLS_NEED_BACKPOINTERS */
81433965Sjdp    }
81533965Sjdp
81633965Sjdp  assert (lastP == symbolP);
81733965Sjdp}
81833965Sjdp
81933965Sjdpvoid
82033965Sjdpverify_symbol_chain_2 (sym)
82133965Sjdp     symbolS *sym;
82233965Sjdp{
82333965Sjdp  symbolS *p = sym, *n = sym;
82433965Sjdp#ifdef SYMBOLS_NEED_BACKPOINTERS
82533965Sjdp  while (symbol_previous (p))
82633965Sjdp    p = symbol_previous (p);
82733965Sjdp#endif
82833965Sjdp  while (symbol_next (n))
82933965Sjdp    n = symbol_next (n);
83033965Sjdp  verify_symbol_chain (p, n);
83133965Sjdp}
83233965Sjdp
83333965Sjdp/* Resolve the value of a symbol.  This is called during the final
83433965Sjdp   pass over the symbol table to resolve any symbols with complex
83533965Sjdp   values.  */
83633965Sjdp
83738889SjdpvalueT
83889857Sobrienresolve_symbol_value (symp)
83933965Sjdp     symbolS *symp;
84033965Sjdp{
84133965Sjdp  int resolved;
842104834Sobrien  valueT final_val = 0;
84338889Sjdp  segT final_seg;
84433965Sjdp
84560484Sobrien#ifdef BFD_ASSEMBLER
84660484Sobrien  if (LOCAL_SYMBOL_CHECK (symp))
84760484Sobrien    {
84860484Sobrien      struct local_symbol *locsym = (struct local_symbol *) symp;
84960484Sobrien
85089857Sobrien      final_val = locsym->lsy_value;
85160484Sobrien      if (local_symbol_resolved_p (locsym))
85289857Sobrien	return final_val;
85360484Sobrien
85489857Sobrien      final_val += local_symbol_get_frag (locsym)->fr_address / OCTETS_PER_BYTE;
85560484Sobrien
85689857Sobrien      if (finalize_syms)
85760484Sobrien	{
85889857Sobrien	  locsym->lsy_value = final_val;
85960484Sobrien	  local_symbol_mark_resolved (locsym);
86060484Sobrien	}
86160484Sobrien
86260484Sobrien      return final_val;
86360484Sobrien    }
86460484Sobrien#endif
86560484Sobrien
86633965Sjdp  if (symp->sy_resolved)
86738889Sjdp    {
86838889Sjdp      if (symp->sy_value.X_op == O_constant)
86938889Sjdp	return (valueT) symp->sy_value.X_add_number;
87038889Sjdp      else
87138889Sjdp	return 0;
87238889Sjdp    }
87333965Sjdp
87433965Sjdp  resolved = 0;
87538889Sjdp  final_seg = S_GET_SEGMENT (symp);
87633965Sjdp
87733965Sjdp  if (symp->sy_resolving)
87833965Sjdp    {
87989857Sobrien      if (finalize_syms)
88089857Sobrien	as_bad (_("symbol definition loop encountered at `%s'"),
88177298Sobrien		S_GET_NAME (symp));
88238889Sjdp      final_val = 0;
88333965Sjdp      resolved = 1;
88433965Sjdp    }
88533965Sjdp  else
88633965Sjdp    {
88738889Sjdp      symbolS *add_symbol, *op_symbol;
88838889Sjdp      offsetT left, right;
88933965Sjdp      segT seg_left, seg_right;
89038889Sjdp      operatorT op;
89133965Sjdp
89233965Sjdp      symp->sy_resolving = 1;
89333965Sjdp
89438889Sjdp      /* Help out with CSE.  */
89538889Sjdp      add_symbol = symp->sy_value.X_add_symbol;
89638889Sjdp      op_symbol = symp->sy_value.X_op_symbol;
89738889Sjdp      final_val = symp->sy_value.X_add_number;
89838889Sjdp      op = symp->sy_value.X_op;
89938889Sjdp
90038889Sjdp      switch (op)
90133965Sjdp	{
90238889Sjdp	default:
90338889Sjdp	  BAD_CASE (op);
90438889Sjdp	  break;
90533965Sjdp
90633965Sjdp	case O_absent:
90738889Sjdp	  final_val = 0;
90833965Sjdp	  /* Fall through.  */
90938889Sjdp
91033965Sjdp	case O_constant:
91160484Sobrien	  final_val += symp->sy_frag->fr_address / OCTETS_PER_BYTE;
91238889Sjdp	  if (final_seg == expr_section)
91338889Sjdp	    final_seg = absolute_section;
91433965Sjdp	  resolved = 1;
91533965Sjdp	  break;
91633965Sjdp
91733965Sjdp	case O_symbol:
91838889Sjdp	case O_symbol_rva:
91989857Sobrien	  left = resolve_symbol_value (add_symbol);
92089857Sobrien	  seg_left = S_GET_SEGMENT (add_symbol);
92189857Sobrien	  if (finalize_syms)
92289857Sobrien	    symp->sy_value.X_op_symbol = NULL;
92389857Sobrien
92438889Sjdp	do_symbol:
92533965Sjdp	  if (symp->sy_mri_common)
92633965Sjdp	    {
92733965Sjdp	      /* This is a symbol inside an MRI common section.  The
92889857Sobrien		 relocation routines are going to handle it specially.
92989857Sobrien		 Don't change the value.  */
93060484Sobrien	      resolved = symbol_resolved_p (add_symbol);
93133965Sjdp	      break;
93233965Sjdp	    }
93333965Sjdp
93489857Sobrien	  if (finalize_syms && final_val == 0)
93560484Sobrien	    {
93660484Sobrien	      if (LOCAL_SYMBOL_CHECK (add_symbol))
93760484Sobrien		add_symbol = local_symbol_convert ((struct local_symbol *)
93860484Sobrien						   add_symbol);
93960484Sobrien	      copy_symbol_attributes (symp, add_symbol);
94060484Sobrien	    }
94133965Sjdp
94289857Sobrien	  /* If we have equated this symbol to an undefined or common
94389857Sobrien	     symbol, keep X_op set to O_symbol, and don't change
94489857Sobrien	     X_add_number.  This permits the routine which writes out
94589857Sobrien	     relocation to detect this case, and convert the
94689857Sobrien	     relocation to be against the symbol to which this symbol
94789857Sobrien	     is equated.  */
94838889Sjdp	  if (! S_IS_DEFINED (add_symbol) || S_IS_COMMON (add_symbol))
94933965Sjdp	    {
95089857Sobrien	      if (finalize_syms)
95138889Sjdp		{
95238889Sjdp		  symp->sy_value.X_op = O_symbol;
95360484Sobrien		  symp->sy_value.X_add_symbol = add_symbol;
95438889Sjdp		  symp->sy_value.X_add_number = final_val;
95589857Sobrien		  /* Use X_op_symbol as a flag.  */
95689857Sobrien		  symp->sy_value.X_op_symbol = add_symbol;
95789857Sobrien		  final_seg = seg_left;
95838889Sjdp		}
95938889Sjdp	      final_val = 0;
96060484Sobrien	      resolved = symbol_resolved_p (add_symbol);
96189857Sobrien	      symp->sy_resolving = 0;
96238889Sjdp	      goto exit_dont_set_value;
96333965Sjdp	    }
96489857Sobrien	  else if (finalize_syms && final_seg == expr_section
96589857Sobrien		   && seg_left != expr_section)
96689857Sobrien	    {
96789857Sobrien	      /* If the symbol is an expression symbol, do similarly
96889857Sobrien		 as for undefined and common syms above.  Handles
96989857Sobrien		 "sym +/- expr" where "expr" cannot be evaluated
97089857Sobrien		 immediately, and we want relocations to be against
97189857Sobrien		 "sym", eg. because it is weak.  */
97289857Sobrien	      symp->sy_value.X_op = O_symbol;
97389857Sobrien	      symp->sy_value.X_add_symbol = add_symbol;
97489857Sobrien	      symp->sy_value.X_add_number = final_val;
97589857Sobrien	      symp->sy_value.X_op_symbol = add_symbol;
97689857Sobrien	      final_seg = seg_left;
97789857Sobrien	      final_val += symp->sy_frag->fr_address + left;
97889857Sobrien	      resolved = symbol_resolved_p (add_symbol);
97989857Sobrien	      symp->sy_resolving = 0;
98089857Sobrien	      goto exit_dont_set_value;
98189857Sobrien	    }
98233965Sjdp	  else
98333965Sjdp	    {
98438889Sjdp	      final_val += symp->sy_frag->fr_address + left;
98538889Sjdp	      if (final_seg == expr_section || final_seg == undefined_section)
98689857Sobrien		final_seg = seg_left;
98733965Sjdp	    }
98833965Sjdp
98960484Sobrien	  resolved = symbol_resolved_p (add_symbol);
99033965Sjdp	  break;
99133965Sjdp
99233965Sjdp	case O_uminus:
99333965Sjdp	case O_bit_not:
99433965Sjdp	case O_logical_not:
99589857Sobrien	  left = resolve_symbol_value (add_symbol);
99699461Sobrien	  seg_left = S_GET_SEGMENT (add_symbol);
99738889Sjdp
99838889Sjdp	  if (op == O_uminus)
99938889Sjdp	    left = -left;
100038889Sjdp	  else if (op == O_logical_not)
100138889Sjdp	    left = !left;
100233965Sjdp	  else
100338889Sjdp	    left = ~left;
100438889Sjdp
100538889Sjdp	  final_val += left + symp->sy_frag->fr_address;
100638889Sjdp	  if (final_seg == expr_section || final_seg == undefined_section)
100799461Sobrien	    final_seg = seg_left;
100838889Sjdp
100960484Sobrien	  resolved = symbol_resolved_p (add_symbol);
101033965Sjdp	  break;
101133965Sjdp
101233965Sjdp	case O_multiply:
101333965Sjdp	case O_divide:
101433965Sjdp	case O_modulus:
101533965Sjdp	case O_left_shift:
101633965Sjdp	case O_right_shift:
101733965Sjdp	case O_bit_inclusive_or:
101833965Sjdp	case O_bit_or_not:
101933965Sjdp	case O_bit_exclusive_or:
102033965Sjdp	case O_bit_and:
102133965Sjdp	case O_add:
102233965Sjdp	case O_subtract:
102333965Sjdp	case O_eq:
102433965Sjdp	case O_ne:
102533965Sjdp	case O_lt:
102633965Sjdp	case O_le:
102733965Sjdp	case O_ge:
102833965Sjdp	case O_gt:
102933965Sjdp	case O_logical_and:
103033965Sjdp	case O_logical_or:
103189857Sobrien	  left = resolve_symbol_value (add_symbol);
103289857Sobrien	  right = resolve_symbol_value (op_symbol);
103338889Sjdp	  seg_left = S_GET_SEGMENT (add_symbol);
103438889Sjdp	  seg_right = S_GET_SEGMENT (op_symbol);
103533965Sjdp
103638889Sjdp	  /* Simplify addition or subtraction of a constant by folding the
103738889Sjdp	     constant into X_add_number.  */
103889857Sobrien	  if (op == O_add)
103938889Sjdp	    {
104038889Sjdp	      if (seg_right == absolute_section)
104138889Sjdp		{
104289857Sobrien		  final_val += right;
104338889Sjdp		  goto do_symbol;
104438889Sjdp		}
104589857Sobrien	      else if (seg_left == absolute_section)
104638889Sjdp		{
104738889Sjdp		  final_val += left;
104838889Sjdp		  add_symbol = op_symbol;
104938889Sjdp		  left = right;
105089857Sobrien		  seg_left = seg_right;
105138889Sjdp		  goto do_symbol;
105238889Sjdp		}
105338889Sjdp	    }
105489857Sobrien	  else if (op == O_subtract)
105589857Sobrien	    {
105689857Sobrien	      if (seg_right == absolute_section)
105789857Sobrien		{
105889857Sobrien		  final_val -= right;
105989857Sobrien		  goto do_symbol;
106089857Sobrien		}
106189857Sobrien	    }
106238889Sjdp
106389857Sobrien	  /* Equality and non-equality tests are permitted on anything.
106489857Sobrien	     Subtraction, and other comparison operators are permitted if
106589857Sobrien	     both operands are in the same section.  Otherwise, both
106689857Sobrien	     operands must be absolute.  We already handled the case of
106789857Sobrien	     addition or subtraction of a constant above.  This will
106889857Sobrien	     probably need to be changed for an object file format which
106989857Sobrien	     supports arbitrary expressions, such as IEEE-695.
107089857Sobrien
107189857Sobrien	     Don't emit messages unless we're finalizing the symbol value,
107238889Sjdp	     otherwise we may get the same message multiple times.  */
107399461Sobrien	  if ((op == O_eq || op == O_ne)
107499461Sobrien	      || ((op == O_subtract
107599461Sobrien		   || op == O_lt || op == O_le || op == O_ge || op == O_gt)
107699461Sobrien		  && seg_left == seg_right
107799461Sobrien		  && (seg_left != undefined_section
107899461Sobrien		      || add_symbol == op_symbol))
107999461Sobrien	      || (seg_left == absolute_section
108099461Sobrien		  && seg_right == absolute_section))
108133965Sjdp	    {
108299461Sobrien	      if (final_seg == expr_section || final_seg == undefined_section)
108399461Sobrien		final_seg = absolute_section;
108499461Sobrien	    }
108599461Sobrien	  else if (finalize_syms)
108699461Sobrien	    {
108733965Sjdp	      char *file;
108833965Sjdp	      unsigned int line;
108933965Sjdp
109033965Sjdp	      if (expr_symbol_where (symp, &file, &line))
109133965Sjdp		{
109233965Sjdp		  if (seg_left == undefined_section)
109333965Sjdp		    as_bad_where (file, line,
109489857Sobrien				  _("undefined symbol `%s' in operation"),
109533965Sjdp				  S_GET_NAME (symp->sy_value.X_add_symbol));
109633965Sjdp		  if (seg_right == undefined_section)
109733965Sjdp		    as_bad_where (file, line,
109889857Sobrien				  _("undefined symbol `%s' in operation"),
109933965Sjdp				  S_GET_NAME (symp->sy_value.X_op_symbol));
110033965Sjdp		  if (seg_left != undefined_section
110133965Sjdp		      && seg_right != undefined_section)
110277298Sobrien		    as_bad_where (file, line,
110377298Sobrien				  _("invalid section for operation"));
110433965Sjdp		}
110533965Sjdp	      else
110633965Sjdp		{
110733965Sjdp		  if (seg_left == undefined_section)
110889857Sobrien		    as_bad (_("undefined symbol `%s' in operation setting `%s'"),
110933965Sjdp			    S_GET_NAME (symp->sy_value.X_add_symbol),
111033965Sjdp			    S_GET_NAME (symp));
111133965Sjdp		  if (seg_right == undefined_section)
111289857Sobrien		    as_bad (_("undefined symbol `%s' in operation setting `%s'"),
111333965Sjdp			    S_GET_NAME (symp->sy_value.X_op_symbol),
111433965Sjdp			    S_GET_NAME (symp));
111533965Sjdp		  if (seg_left != undefined_section
111633965Sjdp		      && seg_right != undefined_section)
111789857Sobrien		    as_bad (_("invalid section for operation setting `%s'"),
111833965Sjdp			    S_GET_NAME (symp));
111933965Sjdp		}
112099461Sobrien	      /* Prevent the error propagating.  */
112199461Sobrien	      if (final_seg == expr_section || final_seg == undefined_section)
112299461Sobrien		final_seg = absolute_section;
112333965Sjdp	    }
112433965Sjdp
112538889Sjdp	  /* Check for division by zero.  */
112638889Sjdp	  if ((op == O_divide || op == O_modulus) && right == 0)
112738889Sjdp	    {
112838889Sjdp	      /* If seg_right is not absolute_section, then we've
112989857Sobrien		 already issued a warning about using a bad symbol.  */
113089857Sobrien	      if (seg_right == absolute_section && finalize_syms)
113138889Sjdp		{
113238889Sjdp		  char *file;
113338889Sjdp		  unsigned int line;
113438889Sjdp
113538889Sjdp		  if (expr_symbol_where (symp, &file, &line))
113660484Sobrien		    as_bad_where (file, line, _("division by zero"));
113738889Sjdp		  else
113889857Sobrien		    as_bad (_("division by zero when setting `%s'"),
113938889Sjdp			    S_GET_NAME (symp));
114038889Sjdp		}
114138889Sjdp
114238889Sjdp	      right = 1;
114338889Sjdp	    }
114438889Sjdp
114533965Sjdp	  switch (symp->sy_value.X_op)
114633965Sjdp	    {
114738889Sjdp	    case O_multiply:		left *= right; break;
114838889Sjdp	    case O_divide:		left /= right; break;
114938889Sjdp	    case O_modulus:		left %= right; break;
115038889Sjdp	    case O_left_shift:		left <<= right; break;
115138889Sjdp	    case O_right_shift:		left >>= right; break;
115238889Sjdp	    case O_bit_inclusive_or:	left |= right; break;
115338889Sjdp	    case O_bit_or_not:		left |= ~right; break;
115438889Sjdp	    case O_bit_exclusive_or:	left ^= right; break;
115538889Sjdp	    case O_bit_and:		left &= right; break;
115638889Sjdp	    case O_add:			left += right; break;
115738889Sjdp	    case O_subtract:		left -= right; break;
115889857Sobrien	    case O_eq:
115989857Sobrien	    case O_ne:
116089857Sobrien	      left = (left == right && seg_left == seg_right
116189857Sobrien		      && (seg_left != undefined_section
116289857Sobrien			  || add_symbol == op_symbol)
116389857Sobrien		      ? ~ (offsetT) 0 : 0);
116489857Sobrien	      if (symp->sy_value.X_op == O_ne)
116589857Sobrien		left = ~left;
116689857Sobrien	      break;
116738889Sjdp	    case O_lt:	left = left <  right ? ~ (offsetT) 0 : 0; break;
116838889Sjdp	    case O_le:	left = left <= right ? ~ (offsetT) 0 : 0; break;
116938889Sjdp	    case O_ge:	left = left >= right ? ~ (offsetT) 0 : 0; break;
117038889Sjdp	    case O_gt:	left = left >  right ? ~ (offsetT) 0 : 0; break;
117138889Sjdp	    case O_logical_and:	left = left && right; break;
117238889Sjdp	    case O_logical_or:	left = left || right; break;
117338889Sjdp	    default:		abort ();
117433965Sjdp	    }
117538889Sjdp
117638889Sjdp	  final_val += symp->sy_frag->fr_address + left;
117738889Sjdp	  if (final_seg == expr_section || final_seg == undefined_section)
117899461Sobrien	    {
117999461Sobrien	      if (seg_left == undefined_section
118099461Sobrien		  || seg_right == undefined_section)
118199461Sobrien		final_seg = undefined_section;
118299461Sobrien	      else if (seg_left == absolute_section)
118399461Sobrien		final_seg = seg_right;
118499461Sobrien	      else
118599461Sobrien		final_seg = seg_left;
118699461Sobrien	    }
118760484Sobrien	  resolved = (symbol_resolved_p (add_symbol)
118860484Sobrien		      && symbol_resolved_p (op_symbol));
118977298Sobrien	  break;
119033965Sjdp
119133965Sjdp	case O_register:
119233965Sjdp	case O_big:
119333965Sjdp	case O_illegal:
119433965Sjdp	  /* Give an error (below) if not in expr_section.  We don't
119533965Sjdp	     want to worry about expr_section symbols, because they
119633965Sjdp	     are fictional (they are created as part of expression
119733965Sjdp	     resolution), and any problems may not actually mean
119833965Sjdp	     anything.  */
119933965Sjdp	  break;
120033965Sjdp	}
120138889Sjdp
120238889Sjdp      symp->sy_resolving = 0;
120333965Sjdp    }
120433965Sjdp
120589857Sobrien  if (finalize_syms)
120689857Sobrien    S_SET_VALUE (symp, final_val);
120738889Sjdp
120889857Sobrienexit_dont_set_value:
120989857Sobrien  /* Always set the segment, even if not finalizing the value.
121089857Sobrien     The segment is used to determine whether a symbol is defined.  */
121138889Sjdp#if defined (OBJ_AOUT) && ! defined (BFD_ASSEMBLER)
121289857Sobrien  /* The old a.out backend does not handle S_SET_SEGMENT correctly
121389857Sobrien     for a stab symbol, so we use this bad hack.  */
121489857Sobrien  if (final_seg != S_GET_SEGMENT (symp))
121538889Sjdp#endif
121689857Sobrien    S_SET_SEGMENT (symp, final_seg);
121738889Sjdp
121833965Sjdp  /* Don't worry if we can't resolve an expr_section symbol.  */
121989857Sobrien  if (finalize_syms)
122033965Sjdp    {
122138889Sjdp      if (resolved)
122238889Sjdp	symp->sy_resolved = 1;
122338889Sjdp      else if (S_GET_SEGMENT (symp) != expr_section)
122438889Sjdp	{
122589857Sobrien	  as_bad (_("can't resolve value for symbol `%s'"),
122677298Sobrien		  S_GET_NAME (symp));
122738889Sjdp	  symp->sy_resolved = 1;
122838889Sjdp	}
122933965Sjdp    }
123038889Sjdp
123138889Sjdp  return final_val;
123233965Sjdp}
123333965Sjdp
123460484Sobrien#ifdef BFD_ASSEMBLER
123560484Sobrien
123660484Sobrienstatic void resolve_local_symbol PARAMS ((const char *, PTR));
123760484Sobrien
123860484Sobrien/* A static function passed to hash_traverse.  */
123960484Sobrien
124060484Sobrienstatic void
124160484Sobrienresolve_local_symbol (key, value)
124260484Sobrien     const char *key ATTRIBUTE_UNUSED;
124360484Sobrien     PTR value;
124460484Sobrien{
124560484Sobrien  if (value != NULL)
124689857Sobrien    resolve_symbol_value (value);
124760484Sobrien}
124860484Sobrien
124960484Sobrien#endif
125060484Sobrien
125160484Sobrien/* Resolve all local symbols.  */
125260484Sobrien
125360484Sobrienvoid
125460484Sobrienresolve_local_symbol_values ()
125560484Sobrien{
125660484Sobrien#ifdef BFD_ASSEMBLER
125760484Sobrien  hash_traverse (local_hash, resolve_local_symbol);
125860484Sobrien#endif
125960484Sobrien}
126060484Sobrien
126133965Sjdp/* Dollar labels look like a number followed by a dollar sign.  Eg, "42$".
126233965Sjdp   They are *really* local.  That is, they go out of scope whenever we see a
126333965Sjdp   label that isn't local.  Also, like fb labels, there can be multiple
126433965Sjdp   instances of a dollar label.  Therefor, we name encode each instance with
126533965Sjdp   the instance number, keep a list of defined symbols separate from the real
126633965Sjdp   symbol table, and we treat these buggers as a sparse array.  */
126733965Sjdp
126833965Sjdpstatic long *dollar_labels;
126933965Sjdpstatic long *dollar_label_instances;
127033965Sjdpstatic char *dollar_label_defines;
127138889Sjdpstatic unsigned long dollar_label_count;
127233965Sjdpstatic unsigned long dollar_label_max;
127333965Sjdp
127477298Sobrienint
127533965Sjdpdollar_label_defined (label)
127633965Sjdp     long label;
127733965Sjdp{
127833965Sjdp  long *i;
127933965Sjdp
128033965Sjdp  know ((dollar_labels != NULL) || (dollar_label_count == 0));
128133965Sjdp
128233965Sjdp  for (i = dollar_labels; i < dollar_labels + dollar_label_count; ++i)
128333965Sjdp    if (*i == label)
128433965Sjdp      return dollar_label_defines[i - dollar_labels];
128533965Sjdp
128677298Sobrien  /* If we get here, label isn't defined.  */
128733965Sjdp  return 0;
128877298Sobrien}
128933965Sjdp
129033965Sjdpstatic long
129133965Sjdpdollar_label_instance (label)
129233965Sjdp     long label;
129333965Sjdp{
129433965Sjdp  long *i;
129533965Sjdp
129633965Sjdp  know ((dollar_labels != NULL) || (dollar_label_count == 0));
129733965Sjdp
129833965Sjdp  for (i = dollar_labels; i < dollar_labels + dollar_label_count; ++i)
129933965Sjdp    if (*i == label)
130033965Sjdp      return (dollar_label_instances[i - dollar_labels]);
130133965Sjdp
130277298Sobrien  /* If we get here, we haven't seen the label before.
130377298Sobrien     Therefore its instance count is zero.  */
130433965Sjdp  return 0;
130533965Sjdp}
130633965Sjdp
130777298Sobrienvoid
130833965Sjdpdollar_label_clear ()
130933965Sjdp{
131033965Sjdp  memset (dollar_label_defines, '\0', (unsigned int) dollar_label_count);
131133965Sjdp}
131233965Sjdp
131333965Sjdp#define DOLLAR_LABEL_BUMP_BY 10
131433965Sjdp
131577298Sobrienvoid
131633965Sjdpdefine_dollar_label (label)
131733965Sjdp     long label;
131833965Sjdp{
131933965Sjdp  long *i;
132033965Sjdp
132133965Sjdp  for (i = dollar_labels; i < dollar_labels + dollar_label_count; ++i)
132233965Sjdp    if (*i == label)
132333965Sjdp      {
132433965Sjdp	++dollar_label_instances[i - dollar_labels];
132533965Sjdp	dollar_label_defines[i - dollar_labels] = 1;
132633965Sjdp	return;
132733965Sjdp      }
132833965Sjdp
132977298Sobrien  /* If we get to here, we don't have label listed yet.  */
133033965Sjdp
133133965Sjdp  if (dollar_labels == NULL)
133233965Sjdp    {
133333965Sjdp      dollar_labels = (long *) xmalloc (DOLLAR_LABEL_BUMP_BY * sizeof (long));
133433965Sjdp      dollar_label_instances = (long *) xmalloc (DOLLAR_LABEL_BUMP_BY * sizeof (long));
133533965Sjdp      dollar_label_defines = xmalloc (DOLLAR_LABEL_BUMP_BY);
133633965Sjdp      dollar_label_max = DOLLAR_LABEL_BUMP_BY;
133733965Sjdp      dollar_label_count = 0;
133833965Sjdp    }
133933965Sjdp  else if (dollar_label_count == dollar_label_max)
134033965Sjdp    {
134133965Sjdp      dollar_label_max += DOLLAR_LABEL_BUMP_BY;
134233965Sjdp      dollar_labels = (long *) xrealloc ((char *) dollar_labels,
134333965Sjdp					 dollar_label_max * sizeof (long));
134433965Sjdp      dollar_label_instances = (long *) xrealloc ((char *) dollar_label_instances,
134533965Sjdp					  dollar_label_max * sizeof (long));
134633965Sjdp      dollar_label_defines = xrealloc (dollar_label_defines, dollar_label_max);
134777298Sobrien    }				/* if we needed to grow  */
134833965Sjdp
134933965Sjdp  dollar_labels[dollar_label_count] = label;
135033965Sjdp  dollar_label_instances[dollar_label_count] = 1;
135133965Sjdp  dollar_label_defines[dollar_label_count] = 1;
135233965Sjdp  ++dollar_label_count;
135333965Sjdp}
135433965Sjdp
135577298Sobrien/* Caller must copy returned name: we re-use the area for the next name.
135633965Sjdp
135777298Sobrien   The mth occurence of label n: is turned into the symbol "Ln^Am"
135877298Sobrien   where n is the label number and m is the instance number. "L" makes
135977298Sobrien   it a label discarded unless debugging and "^A"('\1') ensures no
136077298Sobrien   ordinary symbol SHOULD get the same name as a local label
136177298Sobrien   symbol. The first "4:" is "L4^A1" - the m numbers begin at 1.
136277298Sobrien
136377298Sobrien   fb labels get the same treatment, except that ^B is used in place
136477298Sobrien   of ^A.  */
136577298Sobrien
136677298Sobrienchar *				/* Return local label name.  */
136733965Sjdpdollar_label_name (n, augend)
136877298Sobrien     register long n;		/* we just saw "n$:" : n a number.  */
136977298Sobrien     register int augend;	/* 0 for current instance, 1 for new instance.  */
137033965Sjdp{
137133965Sjdp  long i;
137277298Sobrien  /* Returned to caller, then copied.  Used for created names ("4f").  */
137333965Sjdp  static char symbol_name_build[24];
137433965Sjdp  register char *p;
137533965Sjdp  register char *q;
137677298Sobrien  char symbol_name_temporary[20];	/* Build up a number, BACKWARDS.  */
137733965Sjdp
137833965Sjdp  know (n >= 0);
137933965Sjdp  know (augend == 0 || augend == 1);
138033965Sjdp  p = symbol_name_build;
138160484Sobrien#ifdef LOCAL_LABEL_PREFIX
138260484Sobrien  *p++ = LOCAL_LABEL_PREFIX;
138360484Sobrien#endif
138433965Sjdp  *p++ = 'L';
138533965Sjdp
138677298Sobrien  /* Next code just does sprintf( {}, "%d", n);  */
138777298Sobrien  /* Label number.  */
138833965Sjdp  q = symbol_name_temporary;
138933965Sjdp  for (*q++ = 0, i = n; i; ++q)
139033965Sjdp    {
139133965Sjdp      *q = i % 10 + '0';
139233965Sjdp      i /= 10;
139333965Sjdp    }
139433965Sjdp  while ((*p = *--q) != '\0')
139533965Sjdp    ++p;
139633965Sjdp
139777298Sobrien  *p++ = DOLLAR_LABEL_CHAR;		/* ^A  */
139833965Sjdp
139977298Sobrien  /* Instance number.  */
140033965Sjdp  q = symbol_name_temporary;
140133965Sjdp  for (*q++ = 0, i = dollar_label_instance (n) + augend; i; ++q)
140233965Sjdp    {
140333965Sjdp      *q = i % 10 + '0';
140433965Sjdp      i /= 10;
140533965Sjdp    }
140633965Sjdp  while ((*p++ = *--q) != '\0');;
140733965Sjdp
140877298Sobrien  /* The label, as a '\0' ended string, starts at symbol_name_build.  */
140933965Sjdp  return symbol_name_build;
141033965Sjdp}
141133965Sjdp
141277298Sobrien/* Sombody else's idea of local labels. They are made by "n:" where n
141377298Sobrien   is any decimal digit. Refer to them with
141477298Sobrien    "nb" for previous (backward) n:
141577298Sobrien   or "nf" for next (forward) n:.
141633965Sjdp
141777298Sobrien   We do a little better and let n be any number, not just a single digit, but
141877298Sobrien   since the other guy's assembler only does ten, we treat the first ten
141977298Sobrien   specially.
142077298Sobrien
142177298Sobrien   Like someone else's assembler, we have one set of local label counters for
142277298Sobrien   entire assembly, not one set per (sub)segment like in most assemblers. This
142377298Sobrien   implies that one can refer to a label in another segment, and indeed some
142477298Sobrien   crufty compilers have done just that.
142577298Sobrien
142677298Sobrien   Since there could be a LOT of these things, treat them as a sparse
142777298Sobrien   array.  */
142877298Sobrien
142933965Sjdp#define FB_LABEL_SPECIAL (10)
143033965Sjdp
143133965Sjdpstatic long fb_low_counter[FB_LABEL_SPECIAL];
143233965Sjdpstatic long *fb_labels;
143333965Sjdpstatic long *fb_label_instances;
143433965Sjdpstatic long fb_label_count;
143533965Sjdpstatic long fb_label_max;
143633965Sjdp
143777298Sobrien/* This must be more than FB_LABEL_SPECIAL.  */
143833965Sjdp#define FB_LABEL_BUMP_BY (FB_LABEL_SPECIAL + 6)
143933965Sjdp
144077298Sobrienstatic void
144133965Sjdpfb_label_init ()
144233965Sjdp{
144333965Sjdp  memset ((void *) fb_low_counter, '\0', sizeof (fb_low_counter));
144477298Sobrien}
144533965Sjdp
144677298Sobrien/* Add one to the instance number of this fb label.  */
144777298Sobrien
144877298Sobrienvoid
144933965Sjdpfb_label_instance_inc (label)
145033965Sjdp     long label;
145133965Sjdp{
145233965Sjdp  long *i;
145333965Sjdp
145433965Sjdp  if (label < FB_LABEL_SPECIAL)
145533965Sjdp    {
145633965Sjdp      ++fb_low_counter[label];
145733965Sjdp      return;
145833965Sjdp    }
145933965Sjdp
146033965Sjdp  if (fb_labels != NULL)
146133965Sjdp    {
146233965Sjdp      for (i = fb_labels + FB_LABEL_SPECIAL;
146333965Sjdp	   i < fb_labels + fb_label_count; ++i)
146433965Sjdp	{
146533965Sjdp	  if (*i == label)
146633965Sjdp	    {
146733965Sjdp	      ++fb_label_instances[i - fb_labels];
146833965Sjdp	      return;
146977298Sobrien	    }			/* if we find it  */
147077298Sobrien	}			/* for each existing label  */
147133965Sjdp    }
147233965Sjdp
147377298Sobrien  /* If we get to here, we don't have label listed yet.  */
147433965Sjdp
147533965Sjdp  if (fb_labels == NULL)
147633965Sjdp    {
147733965Sjdp      fb_labels = (long *) xmalloc (FB_LABEL_BUMP_BY * sizeof (long));
147833965Sjdp      fb_label_instances = (long *) xmalloc (FB_LABEL_BUMP_BY * sizeof (long));
147933965Sjdp      fb_label_max = FB_LABEL_BUMP_BY;
148033965Sjdp      fb_label_count = FB_LABEL_SPECIAL;
148133965Sjdp
148233965Sjdp    }
148333965Sjdp  else if (fb_label_count == fb_label_max)
148433965Sjdp    {
148533965Sjdp      fb_label_max += FB_LABEL_BUMP_BY;
148633965Sjdp      fb_labels = (long *) xrealloc ((char *) fb_labels,
148733965Sjdp				     fb_label_max * sizeof (long));
148833965Sjdp      fb_label_instances = (long *) xrealloc ((char *) fb_label_instances,
148933965Sjdp					      fb_label_max * sizeof (long));
149077298Sobrien    }				/* if we needed to grow  */
149133965Sjdp
149233965Sjdp  fb_labels[fb_label_count] = label;
149333965Sjdp  fb_label_instances[fb_label_count] = 1;
149433965Sjdp  ++fb_label_count;
149533965Sjdp}
149633965Sjdp
149777298Sobrienstatic long
149833965Sjdpfb_label_instance (label)
149933965Sjdp     long label;
150033965Sjdp{
150133965Sjdp  long *i;
150233965Sjdp
150333965Sjdp  if (label < FB_LABEL_SPECIAL)
150433965Sjdp    {
150533965Sjdp      return (fb_low_counter[label]);
150633965Sjdp    }
150733965Sjdp
150833965Sjdp  if (fb_labels != NULL)
150933965Sjdp    {
151033965Sjdp      for (i = fb_labels + FB_LABEL_SPECIAL;
151133965Sjdp	   i < fb_labels + fb_label_count; ++i)
151233965Sjdp	{
151333965Sjdp	  if (*i == label)
151433965Sjdp	    {
151533965Sjdp	      return (fb_label_instances[i - fb_labels]);
151677298Sobrien	    }			/* if we find it  */
151777298Sobrien	}			/* for each existing label  */
151833965Sjdp    }
151933965Sjdp
152033965Sjdp  /* We didn't find the label, so this must be a reference to the
152133965Sjdp     first instance.  */
152233965Sjdp  return 0;
152333965Sjdp}
152433965Sjdp
152577298Sobrien/* Caller must copy returned name: we re-use the area for the next name.
152633965Sjdp
152777298Sobrien   The mth occurence of label n: is turned into the symbol "Ln^Bm"
152877298Sobrien   where n is the label number and m is the instance number. "L" makes
152977298Sobrien   it a label discarded unless debugging and "^B"('\2') ensures no
153077298Sobrien   ordinary symbol SHOULD get the same name as a local label
153177298Sobrien   symbol. The first "4:" is "L4^B1" - the m numbers begin at 1.
153277298Sobrien
153377298Sobrien   dollar labels get the same treatment, except that ^A is used in
153477298Sobrien   place of ^B.  */
153577298Sobrien
153677298Sobrienchar *				/* Return local label name.  */
153733965Sjdpfb_label_name (n, augend)
153877298Sobrien     long n;			/* We just saw "n:", "nf" or "nb" : n a number.  */
153977298Sobrien     long augend;		/* 0 for nb, 1 for n:, nf.  */
154033965Sjdp{
154133965Sjdp  long i;
154277298Sobrien  /* Returned to caller, then copied.  Used for created names ("4f").  */
154333965Sjdp  static char symbol_name_build[24];
154433965Sjdp  register char *p;
154533965Sjdp  register char *q;
154677298Sobrien  char symbol_name_temporary[20];	/* Build up a number, BACKWARDS.  */
154733965Sjdp
154833965Sjdp  know (n >= 0);
154933965Sjdp  know (augend == 0 || augend == 1);
155033965Sjdp  p = symbol_name_build;
155177298Sobrien#ifdef LOCAL_LABEL_PREFIX
155277298Sobrien  *p++ = LOCAL_LABEL_PREFIX;
155377298Sobrien#endif
155433965Sjdp  *p++ = 'L';
155533965Sjdp
155677298Sobrien  /* Next code just does sprintf( {}, "%d", n);  */
155777298Sobrien  /* Label number.  */
155833965Sjdp  q = symbol_name_temporary;
155933965Sjdp  for (*q++ = 0, i = n; i; ++q)
156033965Sjdp    {
156133965Sjdp      *q = i % 10 + '0';
156233965Sjdp      i /= 10;
156333965Sjdp    }
156433965Sjdp  while ((*p = *--q) != '\0')
156533965Sjdp    ++p;
156633965Sjdp
156777298Sobrien  *p++ = LOCAL_LABEL_CHAR;		/* ^B  */
156833965Sjdp
156977298Sobrien  /* Instance number.  */
157033965Sjdp  q = symbol_name_temporary;
157133965Sjdp  for (*q++ = 0, i = fb_label_instance (n) + augend; i; ++q)
157233965Sjdp    {
157333965Sjdp      *q = i % 10 + '0';
157433965Sjdp      i /= 10;
157533965Sjdp    }
157633965Sjdp  while ((*p++ = *--q) != '\0');;
157733965Sjdp
157877298Sobrien  /* The label, as a '\0' ended string, starts at symbol_name_build.  */
157933965Sjdp  return (symbol_name_build);
158077298Sobrien}
158133965Sjdp
158277298Sobrien/* Decode name that may have been generated by foo_label_name() above.
158377298Sobrien   If the name wasn't generated by foo_label_name(), then return it
158477298Sobrien   unaltered.  This is used for error messages.  */
158533965Sjdp
158633965Sjdpchar *
158733965Sjdpdecode_local_label_name (s)
158833965Sjdp     char *s;
158933965Sjdp{
159033965Sjdp  char *p;
159133965Sjdp  char *symbol_decode;
159233965Sjdp  int label_number;
159333965Sjdp  int instance_number;
159433965Sjdp  char *type;
159578828Sobrien  const char *message_format;
159677298Sobrien  int index = 0;
159733965Sjdp
159877298Sobrien#ifdef LOCAL_LABEL_PREFIX
159977298Sobrien  if (s[index] == LOCAL_LABEL_PREFIX)
160077298Sobrien    ++index;
160177298Sobrien#endif
160277298Sobrien
160377298Sobrien  if (s[index] != 'L')
160433965Sjdp    return s;
160533965Sjdp
160689857Sobrien  for (label_number = 0, p = s + index + 1; ISDIGIT (*p); ++p)
160733965Sjdp    label_number = (10 * label_number) + *p - '0';
160833965Sjdp
160977298Sobrien  if (*p == DOLLAR_LABEL_CHAR)
161033965Sjdp    type = "dollar";
161177298Sobrien  else if (*p == LOCAL_LABEL_CHAR)
161233965Sjdp    type = "fb";
161333965Sjdp  else
161433965Sjdp    return s;
161533965Sjdp
161689857Sobrien  for (instance_number = 0, p++; ISDIGIT (*p); ++p)
161733965Sjdp    instance_number = (10 * instance_number) + *p - '0';
161833965Sjdp
161978828Sobrien  message_format = _("\"%d\" (instance number %d of a %s label)");
162033965Sjdp  symbol_decode = obstack_alloc (&notes, strlen (message_format) + 30);
162133965Sjdp  sprintf (symbol_decode, message_format, label_number, instance_number, type);
162233965Sjdp
162333965Sjdp  return symbol_decode;
162433965Sjdp}
162533965Sjdp
162633965Sjdp/* Get the value of a symbol.  */
162733965Sjdp
162833965SjdpvalueT
162933965SjdpS_GET_VALUE (s)
163033965Sjdp     symbolS *s;
163133965Sjdp{
163260484Sobrien#ifdef BFD_ASSEMBLER
163360484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
163489857Sobrien    return resolve_symbol_value (s);
163560484Sobrien#endif
163660484Sobrien
163789857Sobrien  if (!s->sy_resolved)
163889857Sobrien    {
163989857Sobrien      valueT val = resolve_symbol_value (s);
164089857Sobrien      if (!finalize_syms)
164189857Sobrien	return val;
164289857Sobrien    }
164333965Sjdp  if (s->sy_value.X_op != O_constant)
164433965Sjdp    {
164533965Sjdp      static symbolS *recur;
164633965Sjdp
164733965Sjdp      /* FIXME: In non BFD assemblers, S_IS_DEFINED and S_IS_COMMON
164833965Sjdp         may call S_GET_VALUE.  We use a static symbol to avoid the
164933965Sjdp         immediate recursion.  */
165033965Sjdp      if (recur == s)
165133965Sjdp	return (valueT) s->sy_value.X_add_number;
165233965Sjdp      recur = s;
165333965Sjdp      if (! s->sy_resolved
165433965Sjdp	  || s->sy_value.X_op != O_symbol
165533965Sjdp	  || (S_IS_DEFINED (s) && ! S_IS_COMMON (s)))
165689857Sobrien	as_bad (_("attempt to get value of unresolved symbol `%s'"),
165733965Sjdp		S_GET_NAME (s));
165833965Sjdp      recur = NULL;
165933965Sjdp    }
166033965Sjdp  return (valueT) s->sy_value.X_add_number;
166133965Sjdp}
166233965Sjdp
166333965Sjdp/* Set the value of a symbol.  */
166433965Sjdp
166533965Sjdpvoid
166633965SjdpS_SET_VALUE (s, val)
166733965Sjdp     symbolS *s;
166833965Sjdp     valueT val;
166933965Sjdp{
167060484Sobrien#ifdef BFD_ASSEMBLER
167160484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
167260484Sobrien    {
167389857Sobrien      ((struct local_symbol *) s)->lsy_value = val;
167460484Sobrien      return;
167560484Sobrien    }
167660484Sobrien#endif
167760484Sobrien
167833965Sjdp  s->sy_value.X_op = O_constant;
167933965Sjdp  s->sy_value.X_add_number = (offsetT) val;
168033965Sjdp  s->sy_value.X_unsigned = 0;
168133965Sjdp}
168233965Sjdp
168333965Sjdpvoid
168433965Sjdpcopy_symbol_attributes (dest, src)
168533965Sjdp     symbolS *dest, *src;
168633965Sjdp{
168760484Sobrien  if (LOCAL_SYMBOL_CHECK (dest))
168860484Sobrien    dest = local_symbol_convert ((struct local_symbol *) dest);
168960484Sobrien  if (LOCAL_SYMBOL_CHECK (src))
169060484Sobrien    src = local_symbol_convert ((struct local_symbol *) src);
169160484Sobrien
169233965Sjdp#ifdef BFD_ASSEMBLER
169333965Sjdp  /* In an expression, transfer the settings of these flags.
169433965Sjdp     The user can override later, of course.  */
169538889Sjdp#define COPIED_SYMFLAGS	(BSF_FUNCTION | BSF_OBJECT)
169633965Sjdp  dest->bsym->flags |= src->bsym->flags & COPIED_SYMFLAGS;
169733965Sjdp#endif
169833965Sjdp
169933965Sjdp#ifdef OBJ_COPY_SYMBOL_ATTRIBUTES
170033965Sjdp  OBJ_COPY_SYMBOL_ATTRIBUTES (dest, src);
170133965Sjdp#endif
170233965Sjdp}
170333965Sjdp
170433965Sjdp#ifdef BFD_ASSEMBLER
170533965Sjdp
170633965Sjdpint
170760484SobrienS_IS_FUNCTION (s)
170860484Sobrien     symbolS *s;
170960484Sobrien{
171060484Sobrien  flagword flags;
171160484Sobrien
171260484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
171360484Sobrien    return 0;
171460484Sobrien
171560484Sobrien  flags = s->bsym->flags;
171660484Sobrien
171760484Sobrien  return (flags & BSF_FUNCTION) != 0;
171860484Sobrien}
171960484Sobrien
172060484Sobrienint
172133965SjdpS_IS_EXTERNAL (s)
172233965Sjdp     symbolS *s;
172333965Sjdp{
172460484Sobrien  flagword flags;
172533965Sjdp
172660484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
172760484Sobrien    return 0;
172860484Sobrien
172960484Sobrien  flags = s->bsym->flags;
173060484Sobrien
173177298Sobrien  /* Sanity check.  */
173238889Sjdp  if ((flags & BSF_LOCAL) && (flags & BSF_GLOBAL))
173333965Sjdp    abort ();
173433965Sjdp
173533965Sjdp  return (flags & BSF_GLOBAL) != 0;
173633965Sjdp}
173733965Sjdp
173833965Sjdpint
173933965SjdpS_IS_WEAK (s)
174033965Sjdp     symbolS *s;
174133965Sjdp{
174260484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
174360484Sobrien    return 0;
174433965Sjdp  return (s->bsym->flags & BSF_WEAK) != 0;
174533965Sjdp}
174633965Sjdp
174733965Sjdpint
174833965SjdpS_IS_COMMON (s)
174933965Sjdp     symbolS *s;
175033965Sjdp{
175160484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
175260484Sobrien    return 0;
175333965Sjdp  return bfd_is_com_section (s->bsym->section);
175433965Sjdp}
175533965Sjdp
175633965Sjdpint
175733965SjdpS_IS_DEFINED (s)
175833965Sjdp     symbolS *s;
175933965Sjdp{
176060484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
176160484Sobrien    return ((struct local_symbol *) s)->lsy_section != undefined_section;
176233965Sjdp  return s->bsym->section != undefined_section;
176333965Sjdp}
176433965Sjdp
176533965Sjdpint
176633965SjdpS_IS_DEBUG (s)
176733965Sjdp     symbolS *s;
176833965Sjdp{
176960484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
177060484Sobrien    return 0;
177133965Sjdp  if (s->bsym->flags & BSF_DEBUGGING)
177233965Sjdp    return 1;
177333965Sjdp  return 0;
177433965Sjdp}
177533965Sjdp
177633965Sjdpint
177733965SjdpS_IS_LOCAL (s)
177833965Sjdp     symbolS *s;
177933965Sjdp{
178060484Sobrien  flagword flags;
178133965Sjdp  const char *name;
178233965Sjdp
178360484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
178460484Sobrien    return 1;
178560484Sobrien
178660484Sobrien  flags = s->bsym->flags;
178760484Sobrien
178877298Sobrien  /* Sanity check.  */
178938889Sjdp  if ((flags & BSF_LOCAL) && (flags & BSF_GLOBAL))
179033965Sjdp    abort ();
179133965Sjdp
179233965Sjdp  if (bfd_get_section (s->bsym) == reg_section)
179333965Sjdp    return 1;
179433965Sjdp
179538889Sjdp  if (flag_strip_local_absolute
179638889Sjdp      && (flags & BSF_GLOBAL) == 0
179738889Sjdp      && bfd_get_section (s->bsym) == absolute_section)
179838889Sjdp    return 1;
179938889Sjdp
180033965Sjdp  name = S_GET_NAME (s);
180133965Sjdp  return (name != NULL
180233965Sjdp	  && ! S_IS_DEBUG (s)
180377298Sobrien	  && (strchr (name, DOLLAR_LABEL_CHAR)
180477298Sobrien	      || strchr (name, LOCAL_LABEL_CHAR)
180533965Sjdp	      || (! flag_keep_locals
180633965Sjdp		  && (bfd_is_local_label (stdoutput, s->bsym)
180733965Sjdp		      || (flag_mri
180833965Sjdp			  && name[0] == '?'
180933965Sjdp			  && name[1] == '?')))));
181033965Sjdp}
181133965Sjdp
181233965Sjdpint
181333965SjdpS_IS_EXTERN (s)
181433965Sjdp     symbolS *s;
181533965Sjdp{
181633965Sjdp  return S_IS_EXTERNAL (s);
181733965Sjdp}
181833965Sjdp
181933965Sjdpint
182033965SjdpS_IS_STABD (s)
182133965Sjdp     symbolS *s;
182233965Sjdp{
182333965Sjdp  return S_GET_NAME (s) == 0;
182433965Sjdp}
182533965Sjdp
1826104834Sobrienconst char *
182733965SjdpS_GET_NAME (s)
182833965Sjdp     symbolS *s;
182933965Sjdp{
183060484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
183160484Sobrien    return ((struct local_symbol *) s)->lsy_name;
183233965Sjdp  return s->bsym->name;
183333965Sjdp}
183433965Sjdp
183533965SjdpsegT
183633965SjdpS_GET_SEGMENT (s)
183733965Sjdp     symbolS *s;
183833965Sjdp{
183960484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
184060484Sobrien    return ((struct local_symbol *) s)->lsy_section;
184133965Sjdp  return s->bsym->section;
184233965Sjdp}
184333965Sjdp
184433965Sjdpvoid
184533965SjdpS_SET_SEGMENT (s, seg)
184633965Sjdp     symbolS *s;
184733965Sjdp     segT seg;
184833965Sjdp{
184938889Sjdp  /* Don't reassign section symbols.  The direct reason is to prevent seg
185038889Sjdp     faults assigning back to const global symbols such as *ABS*, but it
185138889Sjdp     shouldn't happen anyway.  */
185238889Sjdp
185360484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
185460484Sobrien    {
185560484Sobrien      if (seg == reg_section)
185660484Sobrien	s = local_symbol_convert ((struct local_symbol *) s);
185760484Sobrien      else
185860484Sobrien	{
185960484Sobrien	  ((struct local_symbol *) s)->lsy_section = seg;
186060484Sobrien	  return;
186160484Sobrien	}
186260484Sobrien    }
186360484Sobrien
186438889Sjdp  if (s->bsym->flags & BSF_SECTION_SYM)
186538889Sjdp    {
186638889Sjdp      if (s->bsym->section != seg)
186777298Sobrien	abort ();
186838889Sjdp    }
186938889Sjdp  else
187038889Sjdp    s->bsym->section = seg;
187133965Sjdp}
187233965Sjdp
187333965Sjdpvoid
187433965SjdpS_SET_EXTERNAL (s)
187533965Sjdp     symbolS *s;
187633965Sjdp{
187760484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
187860484Sobrien    s = local_symbol_convert ((struct local_symbol *) s);
187933965Sjdp  if ((s->bsym->flags & BSF_WEAK) != 0)
188033965Sjdp    {
188133965Sjdp      /* Let .weak override .global.  */
188233965Sjdp      return;
188333965Sjdp    }
188478828Sobrien  if (s->bsym->flags & BSF_SECTION_SYM)
188578828Sobrien    {
188678828Sobrien      char * file;
188778828Sobrien      unsigned int line;
1888104834Sobrien
188978828Sobrien      /* Do not reassign section symbols.  */
189078828Sobrien      as_where (& file, & line);
189178828Sobrien      as_warn_where (file, line,
189289857Sobrien		     _("section symbols are already global"));
189378828Sobrien      return;
189478828Sobrien    }
189533965Sjdp  s->bsym->flags |= BSF_GLOBAL;
189677298Sobrien  s->bsym->flags &= ~(BSF_LOCAL | BSF_WEAK);
189733965Sjdp}
189833965Sjdp
189933965Sjdpvoid
190033965SjdpS_CLEAR_EXTERNAL (s)
190133965Sjdp     symbolS *s;
190233965Sjdp{
190360484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
190460484Sobrien    return;
190533965Sjdp  if ((s->bsym->flags & BSF_WEAK) != 0)
190633965Sjdp    {
190733965Sjdp      /* Let .weak override.  */
190833965Sjdp      return;
190933965Sjdp    }
191033965Sjdp  s->bsym->flags |= BSF_LOCAL;
191177298Sobrien  s->bsym->flags &= ~(BSF_GLOBAL | BSF_WEAK);
191233965Sjdp}
191333965Sjdp
191433965Sjdpvoid
191533965SjdpS_SET_WEAK (s)
191633965Sjdp     symbolS *s;
191733965Sjdp{
191860484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
191960484Sobrien    s = local_symbol_convert ((struct local_symbol *) s);
192033965Sjdp  s->bsym->flags |= BSF_WEAK;
192177298Sobrien  s->bsym->flags &= ~(BSF_GLOBAL | BSF_LOCAL);
192233965Sjdp}
192333965Sjdp
192433965Sjdpvoid
192533965SjdpS_SET_NAME (s, name)
192633965Sjdp     symbolS *s;
192733965Sjdp     char *name;
192833965Sjdp{
192960484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
193060484Sobrien    {
193160484Sobrien      ((struct local_symbol *) s)->lsy_name = name;
193260484Sobrien      return;
193360484Sobrien    }
193433965Sjdp  s->bsym->name = name;
193533965Sjdp}
193633965Sjdp#endif /* BFD_ASSEMBLER */
193733965Sjdp
193860484Sobrien#ifdef SYMBOLS_NEED_BACKPOINTERS
193960484Sobrien
194060484Sobrien/* Return the previous symbol in a chain.  */
194160484Sobrien
194260484SobriensymbolS *
194360484Sobriensymbol_previous (s)
194460484Sobrien     symbolS *s;
194560484Sobrien{
194660484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
194760484Sobrien    abort ();
194860484Sobrien  return s->sy_previous;
194960484Sobrien}
195060484Sobrien
195160484Sobrien#endif /* SYMBOLS_NEED_BACKPOINTERS */
195260484Sobrien
195360484Sobrien/* Return the next symbol in a chain.  */
195460484Sobrien
195560484SobriensymbolS *
195660484Sobriensymbol_next (s)
195760484Sobrien     symbolS *s;
195860484Sobrien{
195960484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
196060484Sobrien    abort ();
196160484Sobrien  return s->sy_next;
196260484Sobrien}
196360484Sobrien
196460484Sobrien/* Return a pointer to the value of a symbol as an expression.  */
196560484Sobrien
196660484SobrienexpressionS *
196760484Sobriensymbol_get_value_expression (s)
196860484Sobrien     symbolS *s;
196960484Sobrien{
197060484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
197160484Sobrien    s = local_symbol_convert ((struct local_symbol *) s);
197260484Sobrien  return &s->sy_value;
197360484Sobrien}
197460484Sobrien
197560484Sobrien/* Set the value of a symbol to an expression.  */
197660484Sobrien
197733965Sjdpvoid
197860484Sobriensymbol_set_value_expression (s, exp)
197960484Sobrien     symbolS *s;
198060484Sobrien     const expressionS *exp;
198160484Sobrien{
198260484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
198360484Sobrien    s = local_symbol_convert ((struct local_symbol *) s);
198460484Sobrien  s->sy_value = *exp;
198560484Sobrien}
198660484Sobrien
198760484Sobrien/* Set the frag of a symbol.  */
198860484Sobrien
198960484Sobrienvoid
199060484Sobriensymbol_set_frag (s, f)
199160484Sobrien     symbolS *s;
199260484Sobrien     fragS *f;
199360484Sobrien{
199460484Sobrien#ifdef BFD_ASSEMBLER
199560484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
199660484Sobrien    {
199760484Sobrien      local_symbol_set_frag ((struct local_symbol *) s, f);
199860484Sobrien      return;
199960484Sobrien    }
200060484Sobrien#endif
200160484Sobrien  s->sy_frag = f;
200260484Sobrien}
200360484Sobrien
200460484Sobrien/* Return the frag of a symbol.  */
200560484Sobrien
200660484SobrienfragS *
200760484Sobriensymbol_get_frag (s)
200860484Sobrien     symbolS *s;
200960484Sobrien{
201060484Sobrien#ifdef BFD_ASSEMBLER
201160484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
201260484Sobrien    return local_symbol_get_frag ((struct local_symbol *) s);
201360484Sobrien#endif
201460484Sobrien  return s->sy_frag;
201560484Sobrien}
201660484Sobrien
201760484Sobrien/* Mark a symbol as having been used.  */
201860484Sobrien
201960484Sobrienvoid
202060484Sobriensymbol_mark_used (s)
202160484Sobrien     symbolS *s;
202260484Sobrien{
202360484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
202460484Sobrien    return;
202560484Sobrien  s->sy_used = 1;
202660484Sobrien}
202760484Sobrien
202860484Sobrien/* Clear the mark of whether a symbol has been used.  */
202960484Sobrien
203060484Sobrienvoid
203160484Sobriensymbol_clear_used (s)
203260484Sobrien     symbolS *s;
203360484Sobrien{
203460484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
203560484Sobrien    s = local_symbol_convert ((struct local_symbol *) s);
203660484Sobrien  s->sy_used = 0;
203760484Sobrien}
203860484Sobrien
203960484Sobrien/* Return whether a symbol has been used.  */
204060484Sobrien
204160484Sobrienint
204260484Sobriensymbol_used_p (s)
204360484Sobrien     symbolS *s;
204460484Sobrien{
204560484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
204660484Sobrien    return 1;
204760484Sobrien  return s->sy_used;
204860484Sobrien}
204960484Sobrien
205060484Sobrien/* Mark a symbol as having been used in a reloc.  */
205160484Sobrien
205260484Sobrienvoid
205360484Sobriensymbol_mark_used_in_reloc (s)
205460484Sobrien     symbolS *s;
205560484Sobrien{
205660484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
205760484Sobrien    s = local_symbol_convert ((struct local_symbol *) s);
205860484Sobrien  s->sy_used_in_reloc = 1;
205960484Sobrien}
206060484Sobrien
206160484Sobrien/* Clear the mark of whether a symbol has been used in a reloc.  */
206260484Sobrien
206360484Sobrienvoid
206460484Sobriensymbol_clear_used_in_reloc (s)
206560484Sobrien     symbolS *s;
206660484Sobrien{
206760484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
206860484Sobrien    return;
206960484Sobrien  s->sy_used_in_reloc = 0;
207060484Sobrien}
207160484Sobrien
207260484Sobrien/* Return whether a symbol has been used in a reloc.  */
207360484Sobrien
207460484Sobrienint
207560484Sobriensymbol_used_in_reloc_p (s)
207660484Sobrien     symbolS *s;
207760484Sobrien{
207860484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
207960484Sobrien    return 0;
208060484Sobrien  return s->sy_used_in_reloc;
208160484Sobrien}
208260484Sobrien
208360484Sobrien/* Mark a symbol as an MRI common symbol.  */
208460484Sobrien
208560484Sobrienvoid
208660484Sobriensymbol_mark_mri_common (s)
208760484Sobrien     symbolS *s;
208860484Sobrien{
208960484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
209060484Sobrien    s = local_symbol_convert ((struct local_symbol *) s);
209160484Sobrien  s->sy_mri_common = 1;
209260484Sobrien}
209360484Sobrien
209460484Sobrien/* Clear the mark of whether a symbol is an MRI common symbol.  */
209560484Sobrien
209660484Sobrienvoid
209760484Sobriensymbol_clear_mri_common (s)
209860484Sobrien     symbolS *s;
209960484Sobrien{
210060484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
210160484Sobrien    return;
210260484Sobrien  s->sy_mri_common = 0;
210360484Sobrien}
210460484Sobrien
210560484Sobrien/* Return whether a symbol is an MRI common symbol.  */
210660484Sobrien
210760484Sobrienint
210860484Sobriensymbol_mri_common_p (s)
210960484Sobrien     symbolS *s;
211060484Sobrien{
211160484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
211260484Sobrien    return 0;
211360484Sobrien  return s->sy_mri_common;
211460484Sobrien}
211560484Sobrien
211660484Sobrien/* Mark a symbol as having been written.  */
211760484Sobrien
211860484Sobrienvoid
211960484Sobriensymbol_mark_written (s)
212060484Sobrien     symbolS *s;
212160484Sobrien{
212260484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
212360484Sobrien    return;
212460484Sobrien  s->written = 1;
212560484Sobrien}
212660484Sobrien
212760484Sobrien/* Clear the mark of whether a symbol has been written.  */
212860484Sobrien
212960484Sobrienvoid
213060484Sobriensymbol_clear_written (s)
213160484Sobrien     symbolS *s;
213260484Sobrien{
213360484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
213460484Sobrien    return;
213560484Sobrien  s->written = 0;
213660484Sobrien}
213760484Sobrien
213860484Sobrien/* Return whether a symbol has been written.  */
213960484Sobrien
214060484Sobrienint
214160484Sobriensymbol_written_p (s)
214260484Sobrien     symbolS *s;
214360484Sobrien{
214460484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
214560484Sobrien    return 0;
214660484Sobrien  return s->written;
214760484Sobrien}
214860484Sobrien
214960484Sobrien/* Mark a symbol has having been resolved.  */
215060484Sobrien
215160484Sobrienvoid
215260484Sobriensymbol_mark_resolved (s)
215360484Sobrien     symbolS *s;
215460484Sobrien{
215560484Sobrien#ifdef BFD_ASSEMBLER
215660484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
215760484Sobrien    {
215860484Sobrien      local_symbol_mark_resolved ((struct local_symbol *) s);
215960484Sobrien      return;
216060484Sobrien    }
216160484Sobrien#endif
216260484Sobrien  s->sy_resolved = 1;
216360484Sobrien}
216460484Sobrien
216560484Sobrien/* Return whether a symbol has been resolved.  */
216660484Sobrien
216760484Sobrienint
216860484Sobriensymbol_resolved_p (s)
216960484Sobrien     symbolS *s;
217060484Sobrien{
217160484Sobrien#ifdef BFD_ASSEMBLER
217260484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
217360484Sobrien    return local_symbol_resolved_p ((struct local_symbol *) s);
217460484Sobrien#endif
217560484Sobrien  return s->sy_resolved;
217660484Sobrien}
217760484Sobrien
217860484Sobrien/* Return whether a symbol is a section symbol.  */
217960484Sobrien
218060484Sobrienint
218160484Sobriensymbol_section_p (s)
218260484Sobrien     symbolS *s ATTRIBUTE_UNUSED;
218360484Sobrien{
218460484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
218560484Sobrien    return 0;
218660484Sobrien#ifdef BFD_ASSEMBLER
218760484Sobrien  return (s->bsym->flags & BSF_SECTION_SYM) != 0;
218860484Sobrien#else
218977298Sobrien  /* FIXME.  */
219060484Sobrien  return 0;
219160484Sobrien#endif
219260484Sobrien}
219360484Sobrien
219460484Sobrien/* Return whether a symbol is equated to another symbol.  */
219560484Sobrien
219660484Sobrienint
219760484Sobriensymbol_equated_p (s)
219860484Sobrien     symbolS *s;
219960484Sobrien{
220060484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
220160484Sobrien    return 0;
220260484Sobrien  return s->sy_value.X_op == O_symbol;
220360484Sobrien}
220460484Sobrien
220589857Sobrien/* Return whether a symbol is equated to another symbol, and should be
220689857Sobrien   treated specially when writing out relocs.  */
220789857Sobrien
220889857Sobrienint
220989857Sobriensymbol_equated_reloc_p (s)
221089857Sobrien     symbolS *s;
221189857Sobrien{
221289857Sobrien  if (LOCAL_SYMBOL_CHECK (s))
221389857Sobrien    return 0;
221489857Sobrien  /* X_op_symbol, normally not used for O_symbol, is set by
221589857Sobrien     resolve_symbol_value to flag expression syms that have been
221689857Sobrien     equated.  */
221789857Sobrien  return (s->sy_value.X_op == O_symbol
221889857Sobrien	  && ((s->sy_resolved && s->sy_value.X_op_symbol != NULL)
221989857Sobrien	      || ! S_IS_DEFINED (s)
222089857Sobrien	      || S_IS_COMMON (s)));
222189857Sobrien}
222289857Sobrien
222360484Sobrien/* Return whether a symbol has a constant value.  */
222460484Sobrien
222560484Sobrienint
222660484Sobriensymbol_constant_p (s)
222760484Sobrien     symbolS *s;
222860484Sobrien{
222960484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
223060484Sobrien    return 1;
223160484Sobrien  return s->sy_value.X_op == O_constant;
223260484Sobrien}
223360484Sobrien
223460484Sobrien#ifdef BFD_ASSEMBLER
223560484Sobrien
223660484Sobrien/* Return the BFD symbol for a symbol.  */
223760484Sobrien
223860484Sobrienasymbol *
223960484Sobriensymbol_get_bfdsym (s)
224060484Sobrien     symbolS *s;
224160484Sobrien{
224260484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
224360484Sobrien    s = local_symbol_convert ((struct local_symbol *) s);
224460484Sobrien  return s->bsym;
224560484Sobrien}
224660484Sobrien
224760484Sobrien/* Set the BFD symbol for a symbol.  */
224860484Sobrien
224960484Sobrienvoid
225060484Sobriensymbol_set_bfdsym (s, bsym)
225160484Sobrien     symbolS *s;
225260484Sobrien     asymbol *bsym;
225360484Sobrien{
225460484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
225560484Sobrien    s = local_symbol_convert ((struct local_symbol *) s);
225660484Sobrien  s->bsym = bsym;
225760484Sobrien}
225860484Sobrien
225960484Sobrien#endif /* BFD_ASSEMBLER */
226060484Sobrien
226160484Sobrien#ifdef OBJ_SYMFIELD_TYPE
226260484Sobrien
226360484Sobrien/* Get a pointer to the object format information for a symbol.  */
226460484Sobrien
226560484SobrienOBJ_SYMFIELD_TYPE *
226660484Sobriensymbol_get_obj (s)
226760484Sobrien     symbolS *s;
226860484Sobrien{
226960484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
227060484Sobrien    s = local_symbol_convert ((struct local_symbol *) s);
227160484Sobrien  return &s->sy_obj;
227260484Sobrien}
227360484Sobrien
227460484Sobrien/* Set the object format information for a symbol.  */
227560484Sobrien
227660484Sobrienvoid
227760484Sobriensymbol_set_obj (s, o)
227860484Sobrien     symbolS *s;
227960484Sobrien     OBJ_SYMFIELD_TYPE *o;
228060484Sobrien{
228160484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
228260484Sobrien    s = local_symbol_convert ((struct local_symbol *) s);
228360484Sobrien  s->sy_obj = *o;
228460484Sobrien}
228560484Sobrien
228660484Sobrien#endif /* OBJ_SYMFIELD_TYPE */
228760484Sobrien
228860484Sobrien#ifdef TC_SYMFIELD_TYPE
228960484Sobrien
229060484Sobrien/* Get a pointer to the processor information for a symbol.  */
229160484Sobrien
229260484SobrienTC_SYMFIELD_TYPE *
229360484Sobriensymbol_get_tc (s)
229460484Sobrien     symbolS *s;
229560484Sobrien{
229660484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
229760484Sobrien    s = local_symbol_convert ((struct local_symbol *) s);
229860484Sobrien  return &s->sy_tc;
229960484Sobrien}
230060484Sobrien
230160484Sobrien/* Set the processor information for a symbol.  */
230260484Sobrien
230360484Sobrienvoid
230460484Sobriensymbol_set_tc (s, o)
230560484Sobrien     symbolS *s;
230660484Sobrien     TC_SYMFIELD_TYPE *o;
230760484Sobrien{
230860484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
230960484Sobrien    s = local_symbol_convert ((struct local_symbol *) s);
231060484Sobrien  s->sy_tc = *o;
231160484Sobrien}
231260484Sobrien
231360484Sobrien#endif /* TC_SYMFIELD_TYPE */
231460484Sobrien
231560484Sobrienvoid
231633965Sjdpsymbol_begin ()
231733965Sjdp{
231833965Sjdp  symbol_lastP = NULL;
231977298Sobrien  symbol_rootP = NULL;		/* In case we have 0 symbols (!!)  */
232033965Sjdp  sy_hash = hash_new ();
232160484Sobrien#ifdef BFD_ASSEMBLER
232260484Sobrien  local_hash = hash_new ();
232360484Sobrien#endif
232433965Sjdp
232533965Sjdp  memset ((char *) (&abs_symbol), '\0', sizeof (abs_symbol));
232633965Sjdp#ifdef BFD_ASSEMBLER
232733965Sjdp#if defined (EMIT_SECTION_SYMBOLS) || !defined (RELOC_REQUIRES_SYMBOL)
232833965Sjdp  abs_symbol.bsym = bfd_abs_section.symbol;
232933965Sjdp#endif
233033965Sjdp#else
233177298Sobrien  /* Can't initialise a union. Sigh.  */
233233965Sjdp  S_SET_SEGMENT (&abs_symbol, absolute_section);
233333965Sjdp#endif
233433965Sjdp  abs_symbol.sy_value.X_op = O_constant;
233533965Sjdp  abs_symbol.sy_frag = &zero_address_frag;
233633965Sjdp
233733965Sjdp  if (LOCAL_LABELS_FB)
233833965Sjdp    fb_label_init ();
233933965Sjdp}
234033965Sjdp
234133965Sjdpint indent_level;
234233965Sjdp
234360484Sobrien/* Maximum indent level.
234460484Sobrien   Available for modification inside a gdb session.  */
234560484Sobrienint max_indent_level = 8;
234660484Sobrien
234733965Sjdp#if 0
234833965Sjdp
234933965Sjdpstatic void
235033965Sjdpindent ()
235133965Sjdp{
235233965Sjdp  printf ("%*s", indent_level * 4, "");
235333965Sjdp}
235433965Sjdp
235533965Sjdp#endif
235633965Sjdp
235733965Sjdpvoid
235833965Sjdpprint_symbol_value_1 (file, sym)
235933965Sjdp     FILE *file;
236033965Sjdp     symbolS *sym;
236133965Sjdp{
236233965Sjdp  const char *name = S_GET_NAME (sym);
236333965Sjdp  if (!name || !name[0])
236433965Sjdp    name = "(unnamed)";
236533965Sjdp  fprintf (file, "sym %lx %s", (unsigned long) sym, name);
236660484Sobrien
236760484Sobrien  if (LOCAL_SYMBOL_CHECK (sym))
236860484Sobrien    {
236960484Sobrien#ifdef BFD_ASSEMBLER
237060484Sobrien      struct local_symbol *locsym = (struct local_symbol *) sym;
237160484Sobrien      if (local_symbol_get_frag (locsym) != &zero_address_frag
237260484Sobrien	  && local_symbol_get_frag (locsym) != NULL)
237360484Sobrien	fprintf (file, " frag %lx", (long) local_symbol_get_frag (locsym));
237460484Sobrien      if (local_symbol_resolved_p (locsym))
237560484Sobrien	fprintf (file, " resolved");
237660484Sobrien      fprintf (file, " local");
237760484Sobrien#endif
237860484Sobrien    }
237960484Sobrien  else
238060484Sobrien    {
238160484Sobrien      if (sym->sy_frag != &zero_address_frag)
238260484Sobrien	fprintf (file, " frag %lx", (long) sym->sy_frag);
238360484Sobrien      if (sym->written)
238460484Sobrien	fprintf (file, " written");
238560484Sobrien      if (sym->sy_resolved)
238660484Sobrien	fprintf (file, " resolved");
238760484Sobrien      else if (sym->sy_resolving)
238860484Sobrien	fprintf (file, " resolving");
238960484Sobrien      if (sym->sy_used_in_reloc)
239060484Sobrien	fprintf (file, " used-in-reloc");
239160484Sobrien      if (sym->sy_used)
239260484Sobrien	fprintf (file, " used");
239360484Sobrien      if (S_IS_LOCAL (sym))
239460484Sobrien	fprintf (file, " local");
239560484Sobrien      if (S_IS_EXTERN (sym))
239660484Sobrien	fprintf (file, " extern");
239760484Sobrien      if (S_IS_DEBUG (sym))
239860484Sobrien	fprintf (file, " debug");
239960484Sobrien      if (S_IS_DEFINED (sym))
240060484Sobrien	fprintf (file, " defined");
240160484Sobrien    }
240233965Sjdp  fprintf (file, " %s", segment_name (S_GET_SEGMENT (sym)));
240360484Sobrien  if (symbol_resolved_p (sym))
240433965Sjdp    {
240533965Sjdp      segT s = S_GET_SEGMENT (sym);
240633965Sjdp
240733965Sjdp      if (s != undefined_section
2408104834Sobrien	  && s != expr_section)
240933965Sjdp	fprintf (file, " %lx", (long) S_GET_VALUE (sym));
241033965Sjdp    }
241160484Sobrien  else if (indent_level < max_indent_level
241260484Sobrien	   && S_GET_SEGMENT (sym) != undefined_section)
241333965Sjdp    {
241433965Sjdp      indent_level++;
241533965Sjdp      fprintf (file, "\n%*s<", indent_level * 4, "");
241660484Sobrien#ifdef BFD_ASSEMBLER
241760484Sobrien      if (LOCAL_SYMBOL_CHECK (sym))
241860484Sobrien	fprintf (file, "constant %lx",
241989857Sobrien		 (long) ((struct local_symbol *) sym)->lsy_value);
242060484Sobrien      else
242160484Sobrien#endif
242260484Sobrien	print_expr_1 (file, &sym->sy_value);
242333965Sjdp      fprintf (file, ">");
242433965Sjdp      indent_level--;
242533965Sjdp    }
242633965Sjdp  fflush (file);
242733965Sjdp}
242833965Sjdp
242933965Sjdpvoid
243033965Sjdpprint_symbol_value (sym)
243133965Sjdp     symbolS *sym;
243233965Sjdp{
243333965Sjdp  indent_level = 0;
243433965Sjdp  print_symbol_value_1 (stderr, sym);
243533965Sjdp  fprintf (stderr, "\n");
243633965Sjdp}
243733965Sjdp
243860484Sobrienstatic void
243960484Sobrienprint_binary (file, name, exp)
244060484Sobrien     FILE *file;
244177298Sobrien     const char *name;
244260484Sobrien     expressionS *exp;
244360484Sobrien{
244460484Sobrien  indent_level++;
244560484Sobrien  fprintf (file, "%s\n%*s<", name, indent_level * 4, "");
244660484Sobrien  print_symbol_value_1 (file, exp->X_add_symbol);
244760484Sobrien  fprintf (file, ">\n%*s<", indent_level * 4, "");
244860484Sobrien  print_symbol_value_1 (file, exp->X_op_symbol);
244960484Sobrien  fprintf (file, ">");
245060484Sobrien  indent_level--;
245160484Sobrien}
245260484Sobrien
245333965Sjdpvoid
245433965Sjdpprint_expr_1 (file, exp)
245533965Sjdp     FILE *file;
245633965Sjdp     expressionS *exp;
245733965Sjdp{
245833965Sjdp  fprintf (file, "expr %lx ", (long) exp);
245933965Sjdp  switch (exp->X_op)
246033965Sjdp    {
246133965Sjdp    case O_illegal:
246233965Sjdp      fprintf (file, "illegal");
246333965Sjdp      break;
246433965Sjdp    case O_absent:
246533965Sjdp      fprintf (file, "absent");
246633965Sjdp      break;
246733965Sjdp    case O_constant:
246833965Sjdp      fprintf (file, "constant %lx", (long) exp->X_add_number);
246933965Sjdp      break;
247033965Sjdp    case O_symbol:
247133965Sjdp      indent_level++;
247233965Sjdp      fprintf (file, "symbol\n%*s<", indent_level * 4, "");
247333965Sjdp      print_symbol_value_1 (file, exp->X_add_symbol);
247433965Sjdp      fprintf (file, ">");
247533965Sjdp    maybe_print_addnum:
247633965Sjdp      if (exp->X_add_number)
247733965Sjdp	fprintf (file, "\n%*s%lx", indent_level * 4, "",
247833965Sjdp		 (long) exp->X_add_number);
247933965Sjdp      indent_level--;
248033965Sjdp      break;
248133965Sjdp    case O_register:
248233965Sjdp      fprintf (file, "register #%d", (int) exp->X_add_number);
248333965Sjdp      break;
248433965Sjdp    case O_big:
248533965Sjdp      fprintf (file, "big");
248633965Sjdp      break;
248733965Sjdp    case O_uminus:
248833965Sjdp      fprintf (file, "uminus -<");
248933965Sjdp      indent_level++;
249033965Sjdp      print_symbol_value_1 (file, exp->X_add_symbol);
249133965Sjdp      fprintf (file, ">");
249233965Sjdp      goto maybe_print_addnum;
249333965Sjdp    case O_bit_not:
249433965Sjdp      fprintf (file, "bit_not");
249533965Sjdp      break;
249633965Sjdp    case O_multiply:
249760484Sobrien      print_binary (file, "multiply", exp);
249833965Sjdp      break;
249933965Sjdp    case O_divide:
250060484Sobrien      print_binary (file, "divide", exp);
250133965Sjdp      break;
250233965Sjdp    case O_modulus:
250360484Sobrien      print_binary (file, "modulus", exp);
250433965Sjdp      break;
250533965Sjdp    case O_left_shift:
250660484Sobrien      print_binary (file, "lshift", exp);
250733965Sjdp      break;
250833965Sjdp    case O_right_shift:
250960484Sobrien      print_binary (file, "rshift", exp);
251033965Sjdp      break;
251133965Sjdp    case O_bit_inclusive_or:
251260484Sobrien      print_binary (file, "bit_ior", exp);
251333965Sjdp      break;
251433965Sjdp    case O_bit_exclusive_or:
251560484Sobrien      print_binary (file, "bit_xor", exp);
251633965Sjdp      break;
251733965Sjdp    case O_bit_and:
251860484Sobrien      print_binary (file, "bit_and", exp);
251933965Sjdp      break;
252033965Sjdp    case O_eq:
252160484Sobrien      print_binary (file, "eq", exp);
252233965Sjdp      break;
252333965Sjdp    case O_ne:
252460484Sobrien      print_binary (file, "ne", exp);
252533965Sjdp      break;
252633965Sjdp    case O_lt:
252760484Sobrien      print_binary (file, "lt", exp);
252833965Sjdp      break;
252933965Sjdp    case O_le:
253060484Sobrien      print_binary (file, "le", exp);
253133965Sjdp      break;
253233965Sjdp    case O_ge:
253360484Sobrien      print_binary (file, "ge", exp);
253433965Sjdp      break;
253533965Sjdp    case O_gt:
253660484Sobrien      print_binary (file, "gt", exp);
253733965Sjdp      break;
253833965Sjdp    case O_logical_and:
253960484Sobrien      print_binary (file, "logical_and", exp);
254033965Sjdp      break;
254133965Sjdp    case O_logical_or:
254260484Sobrien      print_binary (file, "logical_or", exp);
254333965Sjdp      break;
254433965Sjdp    case O_add:
254533965Sjdp      indent_level++;
254633965Sjdp      fprintf (file, "add\n%*s<", indent_level * 4, "");
254733965Sjdp      print_symbol_value_1 (file, exp->X_add_symbol);
254833965Sjdp      fprintf (file, ">\n%*s<", indent_level * 4, "");
254933965Sjdp      print_symbol_value_1 (file, exp->X_op_symbol);
255033965Sjdp      fprintf (file, ">");
255133965Sjdp      goto maybe_print_addnum;
255233965Sjdp    case O_subtract:
255333965Sjdp      indent_level++;
255433965Sjdp      fprintf (file, "subtract\n%*s<", indent_level * 4, "");
255533965Sjdp      print_symbol_value_1 (file, exp->X_add_symbol);
255633965Sjdp      fprintf (file, ">\n%*s<", indent_level * 4, "");
255733965Sjdp      print_symbol_value_1 (file, exp->X_op_symbol);
255833965Sjdp      fprintf (file, ">");
255933965Sjdp      goto maybe_print_addnum;
256033965Sjdp    default:
256133965Sjdp      fprintf (file, "{unknown opcode %d}", (int) exp->X_op);
256233965Sjdp      break;
256333965Sjdp    }
256433965Sjdp  fflush (stdout);
256533965Sjdp}
256633965Sjdp
256733965Sjdpvoid
256833965Sjdpprint_expr (exp)
256933965Sjdp     expressionS *exp;
257033965Sjdp{
257133965Sjdp  print_expr_1 (stderr, exp);
257233965Sjdp  fprintf (stderr, "\n");
257333965Sjdp}
257433965Sjdp
257533965Sjdpvoid
257633965Sjdpsymbol_print_statistics (file)
257733965Sjdp     FILE *file;
257833965Sjdp{
257933965Sjdp  hash_print_statistics (file, "symbol table", sy_hash);
258060484Sobrien#ifdef BFD_ASSEMBLER
258160484Sobrien  hash_print_statistics (file, "mini local symbol table", local_hash);
258260484Sobrien  fprintf (file, "%lu mini local symbols created, %lu converted\n",
258360484Sobrien	   local_symbol_count, local_symbol_conversion_count);
258460484Sobrien#endif
258533965Sjdp}
2586