symbols.c revision 218822
133965Sjdp/* symbols.c -symbol table-
278828Sobrien   Copyright 1987, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
3218822Sdim   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
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
20218822Sdim   Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
21218822Sdim   02110-1301, 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;
62218822Sdim#ifdef USE_UNIQUE
63218822Sdim/* The name of an external symbol which is
64218822Sdim   used to make weak PE symbol names unique.  */
65218822Sdimconst char * an_external_name;
66218822Sdim#endif
6733965Sjdp
68130561Sobrienstatic char *save_symbol_name (const char *);
69130561Sobrienstatic void fb_label_init (void);
70130561Sobrienstatic long dollar_label_instance (long);
71130561Sobrienstatic long fb_label_instance (long);
7233965Sjdp
73130561Sobrienstatic void print_binary (FILE *, const char *, expressionS *);
74130561Sobrienstatic void report_op_error (symbolS *, symbolS *, symbolS *);
7560484Sobrien
7677298Sobrien/* Return a pointer to a new symbol.  Die if we can't make a new
7733965Sjdp   symbol.  Fill in the symbol's values.  Add symbol to end of symbol
7833965Sjdp   chain.
7977298Sobrien
8033965Sjdp   This function should be called in the general case of creating a
8133965Sjdp   symbol.  However, if the output file symbol table has already been
8233965Sjdp   set, and you are certain that this symbol won't be wanted in the
8333965Sjdp   output file, you can call symbol_create.  */
8433965Sjdp
8533965SjdpsymbolS *
86130561Sobriensymbol_new (const char *name, segT segment, valueT valu, fragS *frag)
8733965Sjdp{
8833965Sjdp  symbolS *symbolP = symbol_create (name, segment, valu, frag);
8933965Sjdp
9077298Sobrien  /* Link to end of symbol chain.  */
9133965Sjdp  {
9233965Sjdp    extern int symbol_table_frozen;
9333965Sjdp    if (symbol_table_frozen)
9433965Sjdp      abort ();
9533965Sjdp  }
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 *
105130561Sobriensave_symbol_name (const char *name)
10633965Sjdp{
10733965Sjdp  unsigned int name_length;
10860484Sobrien  char *ret;
10933965Sjdp
11077298Sobrien  name_length = strlen (name) + 1;	/* +1 for \0.  */
11133965Sjdp  obstack_grow (&notes, name, name_length);
11260484Sobrien  ret = obstack_finish (&notes);
11360484Sobrien
11433965Sjdp#ifdef tc_canonicalize_symbol_name
11560484Sobrien  ret = tc_canonicalize_symbol_name (ret);
11633965Sjdp#endif
11733965Sjdp
11833965Sjdp  if (! symbols_case_sensitive)
11933965Sjdp    {
12089857Sobrien      char *s;
12133965Sjdp
12289857Sobrien      for (s = ret; *s != '\0'; s++)
12389857Sobrien	*s = TOUPPER (*s);
12433965Sjdp    }
12533965Sjdp
12660484Sobrien  return ret;
12760484Sobrien}
12860484Sobrien
12960484SobriensymbolS *
130130561Sobriensymbol_create (const char *name, /* It is copied, the caller can destroy/modify.  */
131130561Sobrien	       segT segment,	/* Segment identifier (SEG_<something>).  */
132130561Sobrien	       valueT valu,	/* Symbol value.  */
133130561Sobrien	       fragS *frag	/* Associated fragment.  */)
13460484Sobrien{
13560484Sobrien  char *preserved_copy_of_name;
13660484Sobrien  symbolS *symbolP;
13760484Sobrien
13860484Sobrien  preserved_copy_of_name = save_symbol_name (name);
13960484Sobrien
14033965Sjdp  symbolP = (symbolS *) obstack_alloc (&notes, sizeof (symbolS));
14133965Sjdp
14277298Sobrien  /* symbol must be born in some fixed state.  This seems as good as any.  */
14333965Sjdp  memset (symbolP, 0, sizeof (symbolS));
14433965Sjdp
14533965Sjdp  symbolP->bsym = bfd_make_empty_symbol (stdoutput);
14633965Sjdp  if (symbolP->bsym == NULL)
147218822Sdim    as_fatal ("bfd_make_empty_symbol: %s", bfd_errmsg (bfd_get_error ()));
14833965Sjdp  S_SET_NAME (symbolP, preserved_copy_of_name);
14933965Sjdp
15033965Sjdp  S_SET_SEGMENT (symbolP, segment);
15133965Sjdp  S_SET_VALUE (symbolP, valu);
15233965Sjdp  symbol_clear_list_pointers (symbolP);
15333965Sjdp
15433965Sjdp  symbolP->sy_frag = frag;
15533965Sjdp
15633965Sjdp  obj_symbol_new_hook (symbolP);
15733965Sjdp
15833965Sjdp#ifdef tc_symbol_new_hook
15933965Sjdp  tc_symbol_new_hook (symbolP);
16033965Sjdp#endif
16133965Sjdp
16233965Sjdp  return symbolP;
16333965Sjdp}
16433965Sjdp
16533965Sjdp
16660484Sobrien/* Local symbol support.  If we can get away with it, we keep only a
16760484Sobrien   small amount of information for local symbols.  */
16860484Sobrien
169130561Sobrienstatic symbolS *local_symbol_convert (struct local_symbol *);
17060484Sobrien
17160484Sobrien/* Used for statistics.  */
17260484Sobrien
17360484Sobrienstatic unsigned long local_symbol_count;
17460484Sobrienstatic unsigned long local_symbol_conversion_count;
17560484Sobrien
17660484Sobrien/* This macro is called with a symbol argument passed by reference.
17760484Sobrien   It returns whether this is a local symbol.  If necessary, it
17860484Sobrien   changes its argument to the real symbol.  */
17960484Sobrien
18060484Sobrien#define LOCAL_SYMBOL_CHECK(s)						\
18160484Sobrien  (s->bsym == NULL							\
18260484Sobrien   ? (local_symbol_converted_p ((struct local_symbol *) s)		\
18360484Sobrien      ? (s = local_symbol_get_real_symbol ((struct local_symbol *) s),	\
18460484Sobrien	 0)								\
18560484Sobrien      : 1)								\
18660484Sobrien   : 0)
18760484Sobrien
18860484Sobrien/* Create a local symbol and insert it into the local hash table.  */
18960484Sobrien
190218822Sdimstatic struct local_symbol *
191130561Sobrienlocal_symbol_make (const char *name, segT section, valueT value, fragS *frag)
19260484Sobrien{
19360484Sobrien  char *name_copy;
19460484Sobrien  struct local_symbol *ret;
19560484Sobrien
19660484Sobrien  ++local_symbol_count;
19760484Sobrien
19860484Sobrien  name_copy = save_symbol_name (name);
19960484Sobrien
20060484Sobrien  ret = (struct local_symbol *) obstack_alloc (&notes, sizeof *ret);
20160484Sobrien  ret->lsy_marker = NULL;
20260484Sobrien  ret->lsy_name = name_copy;
20360484Sobrien  ret->lsy_section = section;
20460484Sobrien  local_symbol_set_frag (ret, frag);
20589857Sobrien  ret->lsy_value = value;
20660484Sobrien
20760484Sobrien  hash_jam (local_hash, name_copy, (PTR) ret);
20860484Sobrien
20960484Sobrien  return ret;
21060484Sobrien}
21160484Sobrien
21260484Sobrien/* Convert a local symbol into a real symbol.  Note that we do not
21360484Sobrien   reclaim the space used by the local symbol.  */
21460484Sobrien
21560484Sobrienstatic symbolS *
216130561Sobrienlocal_symbol_convert (struct local_symbol *locsym)
21760484Sobrien{
21860484Sobrien  symbolS *ret;
21960484Sobrien
22060484Sobrien  assert (locsym->lsy_marker == NULL);
22160484Sobrien  if (local_symbol_converted_p (locsym))
22260484Sobrien    return local_symbol_get_real_symbol (locsym);
22360484Sobrien
22460484Sobrien  ++local_symbol_conversion_count;
22560484Sobrien
22689857Sobrien  ret = symbol_new (locsym->lsy_name, locsym->lsy_section, locsym->lsy_value,
22760484Sobrien		    local_symbol_get_frag (locsym));
22860484Sobrien
22960484Sobrien  if (local_symbol_resolved_p (locsym))
23060484Sobrien    ret->sy_resolved = 1;
23160484Sobrien
23260484Sobrien  /* Local symbols are always either defined or used.  */
23360484Sobrien  ret->sy_used = 1;
23460484Sobrien
23589857Sobrien#ifdef TC_LOCAL_SYMFIELD_CONVERT
23689857Sobrien  TC_LOCAL_SYMFIELD_CONVERT (locsym, ret);
23789857Sobrien#endif
23889857Sobrien
23960484Sobrien  symbol_table_insert (ret);
24060484Sobrien
24160484Sobrien  local_symbol_mark_converted (locsym);
24260484Sobrien  local_symbol_set_real_symbol (locsym, ret);
24360484Sobrien
24460484Sobrien  hash_jam (local_hash, locsym->lsy_name, NULL);
24560484Sobrien
24660484Sobrien  return ret;
24760484Sobrien}
24860484Sobrien
24977298Sobrien/* We have just seen "<name>:".
25077298Sobrien   Creates a struct symbol unless it already exists.
25160484Sobrien
25277298Sobrien   Gripes if we are redefining a symbol incompatibly (and ignores it).  */
25377298Sobrien
25433965SjdpsymbolS *
255130561Sobriencolon (/* Just seen "x:" - rattle symbols & frags.  */
256130561Sobrien       const char *sym_name	/* Symbol name, as a cannonical string.  */
257130561Sobrien       /* We copy this string: OK to alter later.  */)
25833965Sjdp{
25977298Sobrien  register symbolS *symbolP;	/* Symbol we are working with.  */
26033965Sjdp
26133965Sjdp  /* Sun local labels go out of scope whenever a non-local symbol is
26233965Sjdp     defined.  */
263218822Sdim  if (LOCAL_LABELS_DOLLAR
264218822Sdim      && !bfd_is_local_label_name (stdoutput, sym_name))
265218822Sdim    dollar_label_clear ();
26633965Sjdp
26733965Sjdp#ifndef WORKING_DOT_WORD
26833965Sjdp  if (new_broken_words)
26933965Sjdp    {
27033965Sjdp      struct broken_word *a;
27133965Sjdp      int possible_bytes;
27233965Sjdp      fragS *frag_tmp;
27333965Sjdp      char *frag_opcode;
27433965Sjdp
275130561Sobrien      if (now_seg == absolute_section)
276130561Sobrien	{
277130561Sobrien	  as_bad (_("cannot define symbol `%s' in absolute section"), sym_name);
278130561Sobrien	  return NULL;
279130561Sobrien	}
280130561Sobrien
28133965Sjdp      possible_bytes = (md_short_jump_size
28233965Sjdp			+ new_broken_words * md_long_jump_size);
28333965Sjdp
28433965Sjdp      frag_tmp = frag_now;
28533965Sjdp      frag_opcode = frag_var (rs_broken_word,
28633965Sjdp			      possible_bytes,
28733965Sjdp			      possible_bytes,
28833965Sjdp			      (relax_substateT) 0,
28933965Sjdp			      (symbolS *) broken_words,
29033965Sjdp			      (offsetT) 0,
29133965Sjdp			      NULL);
29233965Sjdp
29377298Sobrien      /* We want to store the pointer to where to insert the jump
29477298Sobrien	 table in the fr_opcode of the rs_broken_word frag.  This
29577298Sobrien	 requires a little hackery.  */
29633965Sjdp      while (frag_tmp
29733965Sjdp	     && (frag_tmp->fr_type != rs_broken_word
29833965Sjdp		 || frag_tmp->fr_opcode))
29933965Sjdp	frag_tmp = frag_tmp->fr_next;
30033965Sjdp      know (frag_tmp);
30133965Sjdp      frag_tmp->fr_opcode = frag_opcode;
30233965Sjdp      new_broken_words = 0;
30333965Sjdp
30433965Sjdp      for (a = broken_words; a && a->dispfrag == 0; a = a->next_broken_word)
30533965Sjdp	a->dispfrag = frag_tmp;
30633965Sjdp    }
30733965Sjdp#endif /* WORKING_DOT_WORD */
30833965Sjdp
30933965Sjdp  if ((symbolP = symbol_find (sym_name)) != 0)
31033965Sjdp    {
311218822Sdim      S_CLEAR_WEAKREFR (symbolP);
31233965Sjdp#ifdef RESOLVE_SYMBOL_REDEFINITION
31333965Sjdp      if (RESOLVE_SYMBOL_REDEFINITION (symbolP))
31433965Sjdp	return symbolP;
31533965Sjdp#endif
31677298Sobrien      /* Now check for undefined symbols.  */
31760484Sobrien      if (LOCAL_SYMBOL_CHECK (symbolP))
31833965Sjdp	{
31960484Sobrien	  struct local_symbol *locsym = (struct local_symbol *) symbolP;
32060484Sobrien
32160484Sobrien	  if (locsym->lsy_section != undefined_section
32260484Sobrien	      && (local_symbol_get_frag (locsym) != frag_now
32360484Sobrien		  || locsym->lsy_section != now_seg
32489857Sobrien		  || locsym->lsy_value != frag_now_fix ()))
32560484Sobrien	    {
32689857Sobrien	      as_bad (_("symbol `%s' is already defined"), sym_name);
32760484Sobrien	      return symbolP;
32860484Sobrien	    }
32960484Sobrien
33060484Sobrien	  locsym->lsy_section = now_seg;
33160484Sobrien	  local_symbol_set_frag (locsym, frag_now);
33289857Sobrien	  locsym->lsy_value = frag_now_fix ();
33360484Sobrien	}
334218822Sdim      else if (!(S_IS_DEFINED (symbolP) || symbol_equated_p (symbolP))
335218822Sdim	       || S_IS_COMMON (symbolP)
336218822Sdim	       || S_IS_VOLATILE (symbolP))
33760484Sobrien	{
338218822Sdim	  if (S_IS_VOLATILE (symbolP))
339218822Sdim	    {
340218822Sdim	      symbolP = symbol_clone (symbolP, 1);
341218822Sdim	      S_SET_VALUE (symbolP, 0);
342218822Sdim	      S_CLEAR_VOLATILE (symbolP);
343218822Sdim	    }
34433965Sjdp	  if (S_GET_VALUE (symbolP) == 0)
34533965Sjdp	    {
34633965Sjdp	      symbolP->sy_frag = frag_now;
34733965Sjdp#ifdef OBJ_VMS
34877298Sobrien	      S_SET_OTHER (symbolP, const_flag);
34933965Sjdp#endif
35033965Sjdp	      S_SET_VALUE (symbolP, (valueT) frag_now_fix ());
35133965Sjdp	      S_SET_SEGMENT (symbolP, now_seg);
35233965Sjdp#ifdef N_UNDF
35333965Sjdp	      know (N_UNDF == 0);
35477298Sobrien#endif /* if we have one, it better be zero.  */
35533965Sjdp
35633965Sjdp	    }
35733965Sjdp	  else
35833965Sjdp	    {
35977298Sobrien	      /* There are still several cases to check:
36033965Sjdp
36177298Sobrien		 A .comm/.lcomm symbol being redefined as initialized
36277298Sobrien		 data is OK
36377298Sobrien
36477298Sobrien		 A .comm/.lcomm symbol being redefined with a larger
36577298Sobrien		 size is also OK
36677298Sobrien
36777298Sobrien		 This only used to be allowed on VMS gas, but Sun cc
36877298Sobrien		 on the sparc also depends on it.  */
36977298Sobrien
37033965Sjdp	      if (((!S_IS_DEBUG (symbolP)
37133965Sjdp		    && (!S_IS_DEFINED (symbolP) || S_IS_COMMON (symbolP))
37233965Sjdp		    && S_IS_EXTERNAL (symbolP))
37333965Sjdp		   || S_GET_SEGMENT (symbolP) == bss_section)
37433965Sjdp		  && (now_seg == data_section
375218822Sdim		      || now_seg == bss_section
37633965Sjdp		      || now_seg == S_GET_SEGMENT (symbolP)))
37733965Sjdp		{
37877298Sobrien		  /* Select which of the 2 cases this is.  */
37933965Sjdp		  if (now_seg != data_section)
38033965Sjdp		    {
38177298Sobrien		      /* New .comm for prev .comm symbol.
38277298Sobrien
38377298Sobrien			 If the new size is larger we just change its
38477298Sobrien			 value.  If the new size is smaller, we ignore
38577298Sobrien			 this symbol.  */
38633965Sjdp		      if (S_GET_VALUE (symbolP)
38733965Sjdp			  < ((unsigned) frag_now_fix ()))
38833965Sjdp			{
38933965Sjdp			  S_SET_VALUE (symbolP, (valueT) frag_now_fix ());
39033965Sjdp			}
39133965Sjdp		    }
39233965Sjdp		  else
39333965Sjdp		    {
39433965Sjdp		      /* It is a .comm/.lcomm being converted to initialized
39533965Sjdp			 data.  */
39633965Sjdp		      symbolP->sy_frag = frag_now;
39733965Sjdp#ifdef OBJ_VMS
39877298Sobrien		      S_SET_OTHER (symbolP, const_flag);
39933965Sjdp#endif
40033965Sjdp		      S_SET_VALUE (symbolP, (valueT) frag_now_fix ());
40177298Sobrien		      S_SET_SEGMENT (symbolP, now_seg);	/* Keep N_EXT bit.  */
40233965Sjdp		    }
40333965Sjdp		}
40433965Sjdp	      else
40533965Sjdp		{
40660484Sobrien#if (!defined (OBJ_AOUT) && !defined (OBJ_MAYBE_AOUT) \
40760484Sobrien     && !defined (OBJ_BOUT) && !defined (OBJ_MAYBE_BOUT))
40860484Sobrien		  static const char *od_buf = "";
40933965Sjdp#else
41060484Sobrien		  char od_buf[100];
41160484Sobrien		  od_buf[0] = '\0';
41260484Sobrien		  if (OUTPUT_FLAVOR == bfd_target_aout_flavour)
413104834Sobrien		    sprintf (od_buf, "%d.%d.",
414104834Sobrien			     S_GET_OTHER (symbolP),
415104834Sobrien			     S_GET_DESC (symbolP));
41660484Sobrien#endif
41789857Sobrien		  as_bad (_("symbol `%s' is already defined as \"%s\"/%s%ld"),
41833965Sjdp			    sym_name,
41933965Sjdp			    segment_name (S_GET_SEGMENT (symbolP)),
42060484Sobrien			    od_buf,
42133965Sjdp			    (long) S_GET_VALUE (symbolP));
42233965Sjdp		}
42377298Sobrien	    }			/* if the undefined symbol has no value  */
42433965Sjdp	}
42533965Sjdp      else
42633965Sjdp	{
42777298Sobrien	  /* Don't blow up if the definition is the same.  */
42833965Sjdp	  if (!(frag_now == symbolP->sy_frag
42933965Sjdp		&& S_GET_VALUE (symbolP) == frag_now_fix ()
43033965Sjdp		&& S_GET_SEGMENT (symbolP) == now_seg))
431218822Sdim	    {
432218822Sdim	      as_bad (_("symbol `%s' is already defined"), sym_name);
433218822Sdim	      symbolP = symbol_clone (symbolP, 0);
434218822Sdim	    }
43577298Sobrien	}
43633965Sjdp
43733965Sjdp    }
43860484Sobrien  else if (! flag_keep_locals && bfd_is_local_label_name (stdoutput, sym_name))
43960484Sobrien    {
44060484Sobrien      symbolP = (symbolS *) local_symbol_make (sym_name, now_seg,
44160484Sobrien					       (valueT) frag_now_fix (),
44260484Sobrien					       frag_now);
44360484Sobrien    }
44433965Sjdp  else
44533965Sjdp    {
44633965Sjdp      symbolP = symbol_new (sym_name, now_seg, (valueT) frag_now_fix (),
44733965Sjdp			    frag_now);
44833965Sjdp#ifdef OBJ_VMS
44933965Sjdp      S_SET_OTHER (symbolP, const_flag);
45033965Sjdp#endif /* OBJ_VMS */
45133965Sjdp
45233965Sjdp      symbol_table_insert (symbolP);
45377298Sobrien    }
45433965Sjdp
45533965Sjdp  if (mri_common_symbol != NULL)
45633965Sjdp    {
45733965Sjdp      /* This symbol is actually being defined within an MRI common
458130561Sobrien	 section.  This requires special handling.  */
45960484Sobrien      if (LOCAL_SYMBOL_CHECK (symbolP))
46060484Sobrien	symbolP = local_symbol_convert ((struct local_symbol *) symbolP);
46133965Sjdp      symbolP->sy_value.X_op = O_symbol;
46233965Sjdp      symbolP->sy_value.X_add_symbol = mri_common_symbol;
46333965Sjdp      symbolP->sy_value.X_add_number = S_GET_VALUE (mri_common_symbol);
46433965Sjdp      symbolP->sy_frag = &zero_address_frag;
46533965Sjdp      S_SET_SEGMENT (symbolP, expr_section);
46633965Sjdp      symbolP->sy_mri_common = 1;
46733965Sjdp    }
46833965Sjdp
46933965Sjdp#ifdef tc_frob_label
47033965Sjdp  tc_frob_label (symbolP);
47133965Sjdp#endif
47233965Sjdp#ifdef obj_frob_label
47333965Sjdp  obj_frob_label (symbolP);
47433965Sjdp#endif
47533965Sjdp
47633965Sjdp  return symbolP;
47733965Sjdp}
47833965Sjdp
47977298Sobrien/* Die if we can't insert the symbol.  */
48033965Sjdp
48177298Sobrienvoid
482130561Sobriensymbol_table_insert (symbolS *symbolP)
48333965Sjdp{
48433965Sjdp  register const char *error_string;
48533965Sjdp
48633965Sjdp  know (symbolP);
48733965Sjdp  know (S_GET_NAME (symbolP));
48833965Sjdp
48960484Sobrien  if (LOCAL_SYMBOL_CHECK (symbolP))
49060484Sobrien    {
49160484Sobrien      error_string = hash_jam (local_hash, S_GET_NAME (symbolP),
49260484Sobrien			       (PTR) symbolP);
49360484Sobrien      if (error_string != NULL)
49489857Sobrien	as_fatal (_("inserting \"%s\" into symbol table failed: %s"),
49560484Sobrien		  S_GET_NAME (symbolP), error_string);
49660484Sobrien      return;
49760484Sobrien    }
49860484Sobrien
49933965Sjdp  if ((error_string = hash_jam (sy_hash, S_GET_NAME (symbolP), (PTR) symbolP)))
50033965Sjdp    {
50189857Sobrien      as_fatal (_("inserting \"%s\" into symbol table failed: %s"),
50233965Sjdp		S_GET_NAME (symbolP), error_string);
50377298Sobrien    }				/* on error  */
50477298Sobrien}
50533965Sjdp
50677298Sobrien/* If a symbol name does not exist, create it as undefined, and insert
50777298Sobrien   it into the symbol table.  Return a pointer to it.  */
50877298Sobrien
50933965SjdpsymbolS *
510130561Sobriensymbol_find_or_make (const char *name)
51133965Sjdp{
51233965Sjdp  register symbolS *symbolP;
51333965Sjdp
51433965Sjdp  symbolP = symbol_find (name);
51533965Sjdp
51633965Sjdp  if (symbolP == NULL)
51733965Sjdp    {
51860484Sobrien      if (! flag_keep_locals && bfd_is_local_label_name (stdoutput, name))
51960484Sobrien	{
52060484Sobrien	  symbolP = md_undefined_symbol ((char *) name);
52160484Sobrien	  if (symbolP != NULL)
52260484Sobrien	    return symbolP;
52360484Sobrien
52460484Sobrien	  symbolP = (symbolS *) local_symbol_make (name, undefined_section,
52560484Sobrien						   (valueT) 0,
52660484Sobrien						   &zero_address_frag);
52760484Sobrien	  return symbolP;
52860484Sobrien	}
52960484Sobrien
53033965Sjdp      symbolP = symbol_make (name);
53133965Sjdp
53233965Sjdp      symbol_table_insert (symbolP);
53333965Sjdp    }				/* if symbol wasn't found */
53433965Sjdp
53533965Sjdp  return (symbolP);
53677298Sobrien}
53733965Sjdp
53833965SjdpsymbolS *
539130561Sobriensymbol_make (const char *name)
54033965Sjdp{
54133965Sjdp  symbolS *symbolP;
54233965Sjdp
54377298Sobrien  /* Let the machine description default it, e.g. for register names.  */
54433965Sjdp  symbolP = md_undefined_symbol ((char *) name);
54533965Sjdp
54633965Sjdp  if (!symbolP)
54733965Sjdp    symbolP = symbol_new (name, undefined_section, (valueT) 0, &zero_address_frag);
54833965Sjdp
54933965Sjdp  return (symbolP);
55077298Sobrien}
55133965Sjdp
552130561SobriensymbolS *
553218822Sdimsymbol_clone (symbolS *orgsymP, int replace)
554218822Sdim{
555218822Sdim  symbolS *newsymP;
556218822Sdim  asymbol *bsymorg, *bsymnew;
557218822Sdim
558218822Sdim  /* Running local_symbol_convert on a clone that's not the one currently
559218822Sdim     in local_hash would incorrectly replace the hash entry.  Thus the
560218822Sdim     symbol must be converted here.  Note that the rest of the function
561218822Sdim     depends on not encountering an unconverted symbol.  */
562218822Sdim  if (LOCAL_SYMBOL_CHECK (orgsymP))
563218822Sdim    orgsymP = local_symbol_convert ((struct local_symbol *) orgsymP);
564218822Sdim  bsymorg = orgsymP->bsym;
565218822Sdim
566218822Sdim  newsymP = obstack_alloc (&notes, sizeof (*newsymP));
567218822Sdim  *newsymP = *orgsymP;
568218822Sdim  bsymnew = bfd_make_empty_symbol (bfd_asymbol_bfd (bsymorg));
569218822Sdim  if (bsymnew == NULL)
570218822Sdim    as_fatal ("bfd_make_empty_symbol: %s", bfd_errmsg (bfd_get_error ()));
571218822Sdim  newsymP->bsym = bsymnew;
572218822Sdim  bsymnew->name = bsymorg->name;
573218822Sdim  bsymnew->flags =  bsymorg->flags;
574218822Sdim  bsymnew->section =  bsymorg->section;
575218822Sdim  bfd_copy_private_symbol_data (bfd_asymbol_bfd (bsymorg), bsymorg,
576218822Sdim				bfd_asymbol_bfd (bsymnew), bsymnew);
577218822Sdim
578218822Sdim#ifdef obj_symbol_clone_hook
579218822Sdim  obj_symbol_clone_hook (newsymP, orgsymP);
580218822Sdim#endif
581218822Sdim
582218822Sdim#ifdef tc_symbol_clone_hook
583218822Sdim  tc_symbol_clone_hook (newsymP, orgsymP);
584218822Sdim#endif
585218822Sdim
586218822Sdim  if (replace)
587218822Sdim    {
588218822Sdim      if (symbol_rootP == orgsymP)
589218822Sdim	symbol_rootP = newsymP;
590218822Sdim      else if (orgsymP->sy_previous)
591218822Sdim	{
592218822Sdim	  orgsymP->sy_previous->sy_next = newsymP;
593218822Sdim	  orgsymP->sy_previous = NULL;
594218822Sdim	}
595218822Sdim      if (symbol_lastP == orgsymP)
596218822Sdim	symbol_lastP = newsymP;
597218822Sdim      else if (orgsymP->sy_next)
598218822Sdim	orgsymP->sy_next->sy_previous = newsymP;
599218822Sdim      orgsymP->sy_previous = orgsymP->sy_next = orgsymP;
600218822Sdim      debug_verify_symchain (symbol_rootP, symbol_lastP);
601218822Sdim
602218822Sdim      symbol_table_insert (newsymP);
603218822Sdim    }
604218822Sdim  else
605218822Sdim    newsymP->sy_previous = newsymP->sy_next = newsymP;
606218822Sdim
607218822Sdim  return newsymP;
608218822Sdim}
609218822Sdim
610218822Sdim/* Referenced symbols, if they are forward references, need to be cloned
611218822Sdim   (without replacing the original) so that the value of the referenced
612218822Sdim   symbols at the point of use .  */
613218822Sdim
614218822Sdim#undef symbol_clone_if_forward_ref
615218822SdimsymbolS *
616218822Sdimsymbol_clone_if_forward_ref (symbolS *symbolP, int is_forward)
617218822Sdim{
618218822Sdim  if (symbolP && !LOCAL_SYMBOL_CHECK (symbolP))
619218822Sdim    {
620218822Sdim      symbolS *add_symbol = symbolP->sy_value.X_add_symbol;
621218822Sdim      symbolS *op_symbol = symbolP->sy_value.X_op_symbol;
622218822Sdim
623218822Sdim      if (symbolP->sy_forward_ref)
624218822Sdim	is_forward = 1;
625218822Sdim
626218822Sdim      if (is_forward)
627218822Sdim	{
628218822Sdim	  /* assign_symbol() clones volatile symbols; pre-existing expressions
629218822Sdim	     hold references to the original instance, but want the current
630218822Sdim	     value.  Just repeat the lookup.  */
631218822Sdim	  if (add_symbol && S_IS_VOLATILE (add_symbol))
632218822Sdim	    add_symbol = symbol_find_exact (S_GET_NAME (add_symbol));
633218822Sdim	  if (op_symbol && S_IS_VOLATILE (op_symbol))
634218822Sdim	    op_symbol = symbol_find_exact (S_GET_NAME (op_symbol));
635218822Sdim	}
636218822Sdim
637218822Sdim      /* Re-using sy_resolving here, as this routine cannot get called from
638218822Sdim	 symbol resolution code.  */
639218822Sdim      if (symbolP->bsym->section == expr_section && !symbolP->sy_resolving)
640218822Sdim	{
641218822Sdim	  symbolP->sy_resolving = 1;
642218822Sdim	  add_symbol = symbol_clone_if_forward_ref (add_symbol, is_forward);
643218822Sdim	  op_symbol = symbol_clone_if_forward_ref (op_symbol, is_forward);
644218822Sdim	  symbolP->sy_resolving = 0;
645218822Sdim	}
646218822Sdim
647218822Sdim      if (symbolP->sy_forward_ref
648218822Sdim	  || add_symbol != symbolP->sy_value.X_add_symbol
649218822Sdim	  || op_symbol != symbolP->sy_value.X_op_symbol)
650218822Sdim	symbolP = symbol_clone (symbolP, 0);
651218822Sdim
652218822Sdim      symbolP->sy_value.X_add_symbol = add_symbol;
653218822Sdim      symbolP->sy_value.X_op_symbol = op_symbol;
654218822Sdim    }
655218822Sdim
656218822Sdim  return symbolP;
657218822Sdim}
658218822Sdim
659218822SdimsymbolS *
660130561Sobriensymbol_temp_new (segT seg, valueT ofs, fragS *frag)
661130561Sobrien{
662130561Sobrien  return symbol_new (FAKE_LABEL_NAME, seg, ofs, frag);
663130561Sobrien}
664130561Sobrien
665130561SobriensymbolS *
666130561Sobriensymbol_temp_new_now (void)
667130561Sobrien{
668130561Sobrien  return symbol_temp_new (now_seg, frag_now_fix (), frag_now);
669130561Sobrien}
670130561Sobrien
671130561SobriensymbolS *
672130561Sobriensymbol_temp_make (void)
673130561Sobrien{
674130561Sobrien  return symbol_make (FAKE_LABEL_NAME);
675130561Sobrien}
676130561Sobrien
67777298Sobrien/* Implement symbol table lookup.
67877298Sobrien   In:	A symbol's name as a string: '\0' can't be part of a symbol name.
67977298Sobrien   Out:	NULL if the name was not in the symbol table, else the address
68077298Sobrien   of a struct symbol associated with that name.  */
68133965Sjdp
68233965SjdpsymbolS *
683218822Sdimsymbol_find_exact (const char *name)
68433965Sjdp{
685218822Sdim  return symbol_find_exact_noref (name, 0);
68677298Sobrien}
68733965Sjdp
68833965SjdpsymbolS *
689218822Sdimsymbol_find_exact_noref (const char *name, int noref)
690104834Sobrien{
691218822Sdim  struct local_symbol *locsym;
692218822Sdim  symbolS* sym;
693104834Sobrien
694218822Sdim  locsym = (struct local_symbol *) hash_find (local_hash, name);
695218822Sdim  if (locsym != NULL)
696218822Sdim    return (symbolS *) locsym;
697104834Sobrien
698218822Sdim  sym = ((symbolS *) hash_find (sy_hash, name));
699218822Sdim
700218822Sdim  /* Any references to the symbol, except for the reference in
701218822Sdim     .weakref, must clear this flag, such that the symbol does not
702218822Sdim     turn into a weak symbol.  Note that we don't have to handle the
703218822Sdim     local_symbol case, since a weakrefd is always promoted out of the
704218822Sdim     local_symbol table when it is turned into a weak symbol.  */
705218822Sdim  if (sym && ! noref)
706218822Sdim    S_CLEAR_WEAKREFD (sym);
707218822Sdim
708218822Sdim  return sym;
709104834Sobrien}
710104834Sobrien
711104834SobriensymbolS *
712218822Sdimsymbol_find (const char *name)
71333965Sjdp{
714218822Sdim  return symbol_find_noref (name, 0);
715218822Sdim}
71633965Sjdp
717218822SdimsymbolS *
718218822Sdimsymbol_find_noref (const char *name, int noref)
719218822Sdim{
72033965Sjdp#ifdef tc_canonicalize_symbol_name
72133965Sjdp  {
72233965Sjdp    char *copy;
72360484Sobrien    size_t len = strlen (name) + 1;
72433965Sjdp
72560484Sobrien    copy = (char *) alloca (len);
72660484Sobrien    memcpy (copy, name, len);
72733965Sjdp    name = tc_canonicalize_symbol_name (copy);
72833965Sjdp  }
72933965Sjdp#endif
73033965Sjdp
73133965Sjdp  if (! symbols_case_sensitive)
73233965Sjdp    {
73360484Sobrien      char *copy;
73460484Sobrien      const char *orig;
73560484Sobrien      unsigned char c;
73633965Sjdp
73760484Sobrien      orig = name;
73860484Sobrien      name = copy = (char *) alloca (strlen (name) + 1);
73960484Sobrien
74060484Sobrien      while ((c = *orig++) != '\0')
74160484Sobrien	{
74289857Sobrien	  *copy++ = TOUPPER (c);
74360484Sobrien	}
74460484Sobrien      *copy = '\0';
74533965Sjdp    }
74633965Sjdp
747218822Sdim  return symbol_find_exact_noref (name, noref);
74833965Sjdp}
74933965Sjdp
75077298Sobrien/* Once upon a time, symbols were kept in a singly linked list.  At
75177298Sobrien   least coff needs to be able to rearrange them from time to time, for
75277298Sobrien   which a doubly linked list is much more convenient.  Loic did these
75377298Sobrien   as macros which seemed dangerous to me so they're now functions.
75477298Sobrien   xoxorich.  */
75533965Sjdp
75677298Sobrien/* Link symbol ADDME after symbol TARGET in the chain.  */
75777298Sobrien
75877298Sobrienvoid
759130561Sobriensymbol_append (symbolS *addme, symbolS *target,
760130561Sobrien	       symbolS **rootPP, symbolS **lastPP)
76133965Sjdp{
76260484Sobrien  if (LOCAL_SYMBOL_CHECK (addme))
76360484Sobrien    abort ();
76460484Sobrien  if (target != NULL && LOCAL_SYMBOL_CHECK (target))
76560484Sobrien    abort ();
76660484Sobrien
76733965Sjdp  if (target == NULL)
76833965Sjdp    {
76933965Sjdp      know (*rootPP == NULL);
77033965Sjdp      know (*lastPP == NULL);
77133965Sjdp      addme->sy_next = NULL;
77233965Sjdp      addme->sy_previous = NULL;
77333965Sjdp      *rootPP = addme;
77433965Sjdp      *lastPP = addme;
77533965Sjdp      return;
77677298Sobrien    }				/* if the list is empty  */
77733965Sjdp
77833965Sjdp  if (target->sy_next != NULL)
77933965Sjdp    {
78033965Sjdp      target->sy_next->sy_previous = addme;
78133965Sjdp    }
78233965Sjdp  else
78333965Sjdp    {
78433965Sjdp      know (*lastPP == target);
78533965Sjdp      *lastPP = addme;
78677298Sobrien    }				/* if we have a next  */
78733965Sjdp
78833965Sjdp  addme->sy_next = target->sy_next;
78933965Sjdp  target->sy_next = addme;
79033965Sjdp  addme->sy_previous = target;
79133965Sjdp
79233965Sjdp  debug_verify_symchain (symbol_rootP, symbol_lastP);
79333965Sjdp}
79433965Sjdp
79577298Sobrien/* Set the chain pointers of SYMBOL to null.  */
79677298Sobrien
79777298Sobrienvoid
798130561Sobriensymbol_clear_list_pointers (symbolS *symbolP)
79933965Sjdp{
80060484Sobrien  if (LOCAL_SYMBOL_CHECK (symbolP))
80160484Sobrien    abort ();
80233965Sjdp  symbolP->sy_next = NULL;
80333965Sjdp  symbolP->sy_previous = NULL;
80433965Sjdp}
80533965Sjdp
80677298Sobrien/* Remove SYMBOLP from the list.  */
80777298Sobrien
80877298Sobrienvoid
809130561Sobriensymbol_remove (symbolS *symbolP, symbolS **rootPP, symbolS **lastPP)
81033965Sjdp{
81160484Sobrien  if (LOCAL_SYMBOL_CHECK (symbolP))
81260484Sobrien    abort ();
81360484Sobrien
81433965Sjdp  if (symbolP == *rootPP)
81533965Sjdp    {
81633965Sjdp      *rootPP = symbolP->sy_next;
81777298Sobrien    }				/* if it was the root  */
81833965Sjdp
81933965Sjdp  if (symbolP == *lastPP)
82033965Sjdp    {
82133965Sjdp      *lastPP = symbolP->sy_previous;
82277298Sobrien    }				/* if it was the tail  */
82333965Sjdp
82433965Sjdp  if (symbolP->sy_next != NULL)
82533965Sjdp    {
82633965Sjdp      symbolP->sy_next->sy_previous = symbolP->sy_previous;
82777298Sobrien    }				/* if not last  */
82833965Sjdp
82933965Sjdp  if (symbolP->sy_previous != NULL)
83033965Sjdp    {
83133965Sjdp      symbolP->sy_previous->sy_next = symbolP->sy_next;
83277298Sobrien    }				/* if not first  */
83333965Sjdp
83433965Sjdp  debug_verify_symchain (*rootPP, *lastPP);
83533965Sjdp}
83633965Sjdp
83777298Sobrien/* Link symbol ADDME before symbol TARGET in the chain.  */
83877298Sobrien
83977298Sobrienvoid
840130561Sobriensymbol_insert (symbolS *addme, symbolS *target,
841130561Sobrien	       symbolS **rootPP, symbolS **lastPP ATTRIBUTE_UNUSED)
84233965Sjdp{
84360484Sobrien  if (LOCAL_SYMBOL_CHECK (addme))
84460484Sobrien    abort ();
84560484Sobrien  if (LOCAL_SYMBOL_CHECK (target))
84660484Sobrien    abort ();
84760484Sobrien
84833965Sjdp  if (target->sy_previous != NULL)
84933965Sjdp    {
85033965Sjdp      target->sy_previous->sy_next = addme;
85133965Sjdp    }
85233965Sjdp  else
85333965Sjdp    {
85433965Sjdp      know (*rootPP == target);
85533965Sjdp      *rootPP = addme;
85677298Sobrien    }				/* if not first  */
85733965Sjdp
85833965Sjdp  addme->sy_previous = target->sy_previous;
85933965Sjdp  target->sy_previous = addme;
86033965Sjdp  addme->sy_next = target;
86133965Sjdp
86233965Sjdp  debug_verify_symchain (*rootPP, *lastPP);
86333965Sjdp}
86433965Sjdp
86577298Sobrienvoid
866130561Sobrienverify_symbol_chain (symbolS *rootP, symbolS *lastP)
86733965Sjdp{
86833965Sjdp  symbolS *symbolP = rootP;
86933965Sjdp
87033965Sjdp  if (symbolP == NULL)
87133965Sjdp    return;
87233965Sjdp
87333965Sjdp  for (; symbol_next (symbolP) != NULL; symbolP = symbol_next (symbolP))
87433965Sjdp    {
87560484Sobrien      assert (symbolP->bsym != NULL);
87633965Sjdp      assert (symbolP->sy_next->sy_previous == symbolP);
87733965Sjdp    }
87833965Sjdp
87933965Sjdp  assert (lastP == symbolP);
88033965Sjdp}
88133965Sjdp
882218822Sdim#ifdef OBJ_COMPLEX_RELC
883218822Sdim
884218822Sdimstatic int
885218822Sdimuse_complex_relocs_for (symbolS * symp)
88633965Sjdp{
887218822Sdim  switch (symp->sy_value.X_op)
888218822Sdim    {
889218822Sdim    case O_constant:
890218822Sdim      return 0;
891218822Sdim
892218822Sdim    case O_symbol:
893218822Sdim    case O_symbol_rva:
894218822Sdim    case O_uminus:
895218822Sdim    case O_bit_not:
896218822Sdim    case O_logical_not:
897218822Sdim      if (  (S_IS_COMMON (symp->sy_value.X_add_symbol)
898218822Sdim	   || S_IS_LOCAL (symp->sy_value.X_add_symbol))
899218822Sdim	  &&
900218822Sdim	      (S_IS_DEFINED (symp->sy_value.X_add_symbol)
901218822Sdim	   && S_GET_SEGMENT (symp->sy_value.X_add_symbol) != expr_section))
902218822Sdim	return 0;
903218822Sdim      break;
904218822Sdim
905218822Sdim    case O_multiply:
906218822Sdim    case O_divide:
907218822Sdim    case O_modulus:
908218822Sdim    case O_left_shift:
909218822Sdim    case O_right_shift:
910218822Sdim    case O_bit_inclusive_or:
911218822Sdim    case O_bit_or_not:
912218822Sdim    case O_bit_exclusive_or:
913218822Sdim    case O_bit_and:
914218822Sdim    case O_add:
915218822Sdim    case O_subtract:
916218822Sdim    case O_eq:
917218822Sdim    case O_ne:
918218822Sdim    case O_lt:
919218822Sdim    case O_le:
920218822Sdim    case O_ge:
921218822Sdim    case O_gt:
922218822Sdim    case O_logical_and:
923218822Sdim    case O_logical_or:
924218822Sdim
925218822Sdim      if (  (S_IS_COMMON (symp->sy_value.X_add_symbol)
926218822Sdim	   || S_IS_LOCAL (symp->sy_value.X_add_symbol))
927218822Sdim	  &&
928218822Sdim	    (S_IS_COMMON (symp->sy_value.X_op_symbol)
929218822Sdim	   || S_IS_LOCAL (symp->sy_value.X_op_symbol))
930218822Sdim
931218822Sdim	  && S_IS_DEFINED (symp->sy_value.X_add_symbol)
932218822Sdim	  && S_IS_DEFINED (symp->sy_value.X_op_symbol)
933218822Sdim	  && S_GET_SEGMENT (symp->sy_value.X_add_symbol) != expr_section
934218822Sdim	  && S_GET_SEGMENT (symp->sy_value.X_op_symbol) != expr_section)
935218822Sdim	return 0;
936218822Sdim      break;
937218822Sdim
938218822Sdim    default:
939218822Sdim      break;
940218822Sdim    }
941218822Sdim  return 1;
942218822Sdim}
94333965Sjdp#endif
94433965Sjdp
945130561Sobrienstatic void
946130561Sobrienreport_op_error (symbolS *symp, symbolS *left, symbolS *right)
947130561Sobrien{
948130561Sobrien  char *file;
949130561Sobrien  unsigned int line;
950130561Sobrien  segT seg_left = S_GET_SEGMENT (left);
951130561Sobrien  segT seg_right = right ? S_GET_SEGMENT (right) : 0;
952130561Sobrien
953130561Sobrien  if (expr_symbol_where (symp, &file, &line))
954130561Sobrien    {
955130561Sobrien      if (seg_left == undefined_section)
956130561Sobrien	as_bad_where (file, line,
957130561Sobrien		      _("undefined symbol `%s' in operation"),
958130561Sobrien		      S_GET_NAME (left));
959130561Sobrien      if (seg_right == undefined_section)
960130561Sobrien	as_bad_where (file, line,
961130561Sobrien		      _("undefined symbol `%s' in operation"),
962130561Sobrien		      S_GET_NAME (right));
963130561Sobrien      if (seg_left != undefined_section
964130561Sobrien	  && seg_right != undefined_section)
965130561Sobrien	{
966130561Sobrien	  if (right)
967130561Sobrien	    as_bad_where (file, line,
968130561Sobrien			  _("invalid sections for operation on `%s' and `%s'"),
969130561Sobrien			  S_GET_NAME (left), S_GET_NAME (right));
970130561Sobrien	  else
971130561Sobrien	    as_bad_where (file, line,
972130561Sobrien			  _("invalid section for operation on `%s'"),
973130561Sobrien			  S_GET_NAME (left));
974130561Sobrien	}
975130561Sobrien
976130561Sobrien    }
977130561Sobrien  else
978130561Sobrien    {
979130561Sobrien      if (seg_left == undefined_section)
980130561Sobrien	as_bad (_("undefined symbol `%s' in operation setting `%s'"),
981130561Sobrien		S_GET_NAME (left), S_GET_NAME (symp));
982130561Sobrien      if (seg_right == undefined_section)
983130561Sobrien	as_bad (_("undefined symbol `%s' in operation setting `%s'"),
984130561Sobrien		S_GET_NAME (right), S_GET_NAME (symp));
985130561Sobrien      if (seg_left != undefined_section
986130561Sobrien	  && seg_right != undefined_section)
987130561Sobrien	{
988130561Sobrien	  if (right)
989218822Sdim	    as_bad (_("invalid sections for operation on `%s' and `%s' setting `%s'"),
990218822Sdim		    S_GET_NAME (left), S_GET_NAME (right), S_GET_NAME (symp));
991130561Sobrien	  else
992218822Sdim	    as_bad (_("invalid section for operation on `%s' setting `%s'"),
993218822Sdim		    S_GET_NAME (left), S_GET_NAME (symp));
994130561Sobrien	}
995130561Sobrien    }
996130561Sobrien}
997130561Sobrien
99833965Sjdp/* Resolve the value of a symbol.  This is called during the final
99933965Sjdp   pass over the symbol table to resolve any symbols with complex
100033965Sjdp   values.  */
100133965Sjdp
100238889SjdpvalueT
1003130561Sobrienresolve_symbol_value (symbolS *symp)
100433965Sjdp{
100533965Sjdp  int resolved;
1006104834Sobrien  valueT final_val = 0;
100738889Sjdp  segT final_seg;
100833965Sjdp
100960484Sobrien  if (LOCAL_SYMBOL_CHECK (symp))
101060484Sobrien    {
101160484Sobrien      struct local_symbol *locsym = (struct local_symbol *) symp;
101260484Sobrien
101389857Sobrien      final_val = locsym->lsy_value;
101460484Sobrien      if (local_symbol_resolved_p (locsym))
101589857Sobrien	return final_val;
101660484Sobrien
101789857Sobrien      final_val += local_symbol_get_frag (locsym)->fr_address / OCTETS_PER_BYTE;
101860484Sobrien
101989857Sobrien      if (finalize_syms)
102060484Sobrien	{
102189857Sobrien	  locsym->lsy_value = final_val;
102260484Sobrien	  local_symbol_mark_resolved (locsym);
102360484Sobrien	}
102460484Sobrien
102560484Sobrien      return final_val;
102660484Sobrien    }
102760484Sobrien
102833965Sjdp  if (symp->sy_resolved)
102938889Sjdp    {
103038889Sjdp      if (symp->sy_value.X_op == O_constant)
103138889Sjdp	return (valueT) symp->sy_value.X_add_number;
103238889Sjdp      else
103338889Sjdp	return 0;
103438889Sjdp    }
103533965Sjdp
103633965Sjdp  resolved = 0;
103738889Sjdp  final_seg = S_GET_SEGMENT (symp);
103833965Sjdp
103933965Sjdp  if (symp->sy_resolving)
104033965Sjdp    {
104189857Sobrien      if (finalize_syms)
104289857Sobrien	as_bad (_("symbol definition loop encountered at `%s'"),
104377298Sobrien		S_GET_NAME (symp));
104438889Sjdp      final_val = 0;
104533965Sjdp      resolved = 1;
104633965Sjdp    }
1047218822Sdim#ifdef OBJ_COMPLEX_RELC
1048218822Sdim  else if (final_seg == expr_section
1049218822Sdim	   && use_complex_relocs_for (symp))
1050218822Sdim    {
1051218822Sdim      symbolS * relc_symbol = NULL;
1052218822Sdim      char * relc_symbol_name = NULL;
1053218822Sdim
1054218822Sdim      relc_symbol_name = symbol_relc_make_expr (& symp->sy_value);
1055218822Sdim
1056218822Sdim      /* For debugging, print out conversion input & output.  */
1057218822Sdim#ifdef DEBUG_SYMS
1058218822Sdim      print_expr (& symp->sy_value);
1059218822Sdim      if (relc_symbol_name)
1060218822Sdim	fprintf (stderr, "-> relc symbol: %s\n", relc_symbol_name);
1061218822Sdim#endif
1062218822Sdim
1063218822Sdim      if (relc_symbol_name != NULL)
1064218822Sdim	relc_symbol = symbol_new (relc_symbol_name, undefined_section,
1065218822Sdim				  0, & zero_address_frag);
1066218822Sdim
1067218822Sdim      if (relc_symbol == NULL)
1068218822Sdim	{
1069218822Sdim	  as_bad (_("cannot convert expression symbol %s to complex relocation"),
1070218822Sdim		  S_GET_NAME (symp));
1071218822Sdim	  resolved = 0;
1072218822Sdim	}
1073218822Sdim      else
1074218822Sdim	{
1075218822Sdim	  symbol_table_insert (relc_symbol);
1076218822Sdim
1077218822Sdim 	  /* S_CLEAR_EXTERNAL (relc_symbol); */
1078218822Sdim	  if (symp->bsym->flags & BSF_SRELC)
1079218822Sdim	    relc_symbol->bsym->flags |= BSF_SRELC;
1080218822Sdim	  else
1081218822Sdim	    relc_symbol->bsym->flags |= BSF_RELC;
1082218822Sdim	  /* symp->bsym->flags |= BSF_RELC; */
1083218822Sdim	  copy_symbol_attributes (symp, relc_symbol);
1084218822Sdim	  symp->sy_value.X_op = O_symbol;
1085218822Sdim	  symp->sy_value.X_add_symbol = relc_symbol;
1086218822Sdim	  symp->sy_value.X_add_number = 0;
1087218822Sdim	  resolved = 1;
1088218822Sdim	}
1089218822Sdim
1090218822Sdim      final_seg = undefined_section;
1091218822Sdim      goto exit_dont_set_value;
1092218822Sdim    }
1093218822Sdim#endif
109433965Sjdp  else
109533965Sjdp    {
109638889Sjdp      symbolS *add_symbol, *op_symbol;
109738889Sjdp      offsetT left, right;
109833965Sjdp      segT seg_left, seg_right;
109938889Sjdp      operatorT op;
1100218822Sdim      int move_seg_ok;
110133965Sjdp
110233965Sjdp      symp->sy_resolving = 1;
110333965Sjdp
110438889Sjdp      /* Help out with CSE.  */
110538889Sjdp      add_symbol = symp->sy_value.X_add_symbol;
110638889Sjdp      op_symbol = symp->sy_value.X_op_symbol;
110738889Sjdp      final_val = symp->sy_value.X_add_number;
110838889Sjdp      op = symp->sy_value.X_op;
110938889Sjdp
111038889Sjdp      switch (op)
111133965Sjdp	{
111238889Sjdp	default:
111338889Sjdp	  BAD_CASE (op);
111438889Sjdp	  break;
111533965Sjdp
111633965Sjdp	case O_absent:
111738889Sjdp	  final_val = 0;
111833965Sjdp	  /* Fall through.  */
111938889Sjdp
112033965Sjdp	case O_constant:
112160484Sobrien	  final_val += symp->sy_frag->fr_address / OCTETS_PER_BYTE;
112238889Sjdp	  if (final_seg == expr_section)
112338889Sjdp	    final_seg = absolute_section;
1124218822Sdim	  /* Fall through.  */
1125218822Sdim
1126218822Sdim	case O_register:
112733965Sjdp	  resolved = 1;
112833965Sjdp	  break;
112933965Sjdp
113033965Sjdp	case O_symbol:
113138889Sjdp	case O_symbol_rva:
113289857Sobrien	  left = resolve_symbol_value (add_symbol);
113389857Sobrien	  seg_left = S_GET_SEGMENT (add_symbol);
113489857Sobrien	  if (finalize_syms)
113589857Sobrien	    symp->sy_value.X_op_symbol = NULL;
113689857Sobrien
113738889Sjdp	do_symbol:
1138218822Sdim	  if (S_IS_WEAKREFR (symp))
1139218822Sdim	    {
1140218822Sdim	      assert (final_val == 0);
1141218822Sdim	      if (S_IS_WEAKREFR (add_symbol))
1142218822Sdim		{
1143218822Sdim		  assert (add_symbol->sy_value.X_op == O_symbol
1144218822Sdim			  && add_symbol->sy_value.X_add_number == 0);
1145218822Sdim		  add_symbol = add_symbol->sy_value.X_add_symbol;
1146218822Sdim		  assert (! S_IS_WEAKREFR (add_symbol));
1147218822Sdim		  symp->sy_value.X_add_symbol = add_symbol;
1148218822Sdim		}
1149218822Sdim	    }
1150218822Sdim
115133965Sjdp	  if (symp->sy_mri_common)
115233965Sjdp	    {
115333965Sjdp	      /* This is a symbol inside an MRI common section.  The
115489857Sobrien		 relocation routines are going to handle it specially.
115589857Sobrien		 Don't change the value.  */
115660484Sobrien	      resolved = symbol_resolved_p (add_symbol);
115733965Sjdp	      break;
115833965Sjdp	    }
115933965Sjdp
116089857Sobrien	  if (finalize_syms && final_val == 0)
116160484Sobrien	    {
116260484Sobrien	      if (LOCAL_SYMBOL_CHECK (add_symbol))
116360484Sobrien		add_symbol = local_symbol_convert ((struct local_symbol *)
116460484Sobrien						   add_symbol);
116560484Sobrien	      copy_symbol_attributes (symp, add_symbol);
116660484Sobrien	    }
116733965Sjdp
116889857Sobrien	  /* If we have equated this symbol to an undefined or common
116989857Sobrien	     symbol, keep X_op set to O_symbol, and don't change
117089857Sobrien	     X_add_number.  This permits the routine which writes out
117189857Sobrien	     relocation to detect this case, and convert the
117289857Sobrien	     relocation to be against the symbol to which this symbol
117389857Sobrien	     is equated.  */
1174218822Sdim	  if (! S_IS_DEFINED (add_symbol)
1175218822Sdim#if defined (OBJ_COFF) && defined (TE_PE)
1176218822Sdim	      || S_IS_WEAK (add_symbol)
1177218822Sdim#endif
1178218822Sdim	      || S_IS_COMMON (add_symbol))
117933965Sjdp	    {
118089857Sobrien	      if (finalize_syms)
118138889Sjdp		{
118238889Sjdp		  symp->sy_value.X_op = O_symbol;
118360484Sobrien		  symp->sy_value.X_add_symbol = add_symbol;
118438889Sjdp		  symp->sy_value.X_add_number = final_val;
118589857Sobrien		  /* Use X_op_symbol as a flag.  */
118689857Sobrien		  symp->sy_value.X_op_symbol = add_symbol;
118789857Sobrien		  final_seg = seg_left;
118838889Sjdp		}
118938889Sjdp	      final_val = 0;
119060484Sobrien	      resolved = symbol_resolved_p (add_symbol);
119189857Sobrien	      symp->sy_resolving = 0;
119238889Sjdp	      goto exit_dont_set_value;
119333965Sjdp	    }
1194218822Sdim	  else if (finalize_syms
1195218822Sdim		   && ((final_seg == expr_section && seg_left != expr_section)
1196218822Sdim		       || symbol_shadow_p (symp)))
119789857Sobrien	    {
119889857Sobrien	      /* If the symbol is an expression symbol, do similarly
119989857Sobrien		 as for undefined and common syms above.  Handles
120089857Sobrien		 "sym +/- expr" where "expr" cannot be evaluated
120189857Sobrien		 immediately, and we want relocations to be against
120289857Sobrien		 "sym", eg. because it is weak.  */
120389857Sobrien	      symp->sy_value.X_op = O_symbol;
120489857Sobrien	      symp->sy_value.X_add_symbol = add_symbol;
120589857Sobrien	      symp->sy_value.X_add_number = final_val;
120689857Sobrien	      symp->sy_value.X_op_symbol = add_symbol;
120789857Sobrien	      final_seg = seg_left;
120889857Sobrien	      final_val += symp->sy_frag->fr_address + left;
120989857Sobrien	      resolved = symbol_resolved_p (add_symbol);
121089857Sobrien	      symp->sy_resolving = 0;
121189857Sobrien	      goto exit_dont_set_value;
121289857Sobrien	    }
121333965Sjdp	  else
121433965Sjdp	    {
121538889Sjdp	      final_val += symp->sy_frag->fr_address + left;
121638889Sjdp	      if (final_seg == expr_section || final_seg == undefined_section)
121789857Sobrien		final_seg = seg_left;
121833965Sjdp	    }
121933965Sjdp
122060484Sobrien	  resolved = symbol_resolved_p (add_symbol);
1221218822Sdim	  if (S_IS_WEAKREFR (symp))
1222218822Sdim	    goto exit_dont_set_value;
122333965Sjdp	  break;
122433965Sjdp
122533965Sjdp	case O_uminus:
122633965Sjdp	case O_bit_not:
122733965Sjdp	case O_logical_not:
122889857Sobrien	  left = resolve_symbol_value (add_symbol);
122999461Sobrien	  seg_left = S_GET_SEGMENT (add_symbol);
123038889Sjdp
1231130561Sobrien	  /* By reducing these to the relevant dyadic operator, we get
1232130561Sobrien	     	!S -> S == 0 	permitted on anything,
1233130561Sobrien		-S -> 0 - S 	only permitted on absolute
1234130561Sobrien		~S -> S ^ ~0 	only permitted on absolute  */
1235130561Sobrien	  if (op != O_logical_not && seg_left != absolute_section
1236130561Sobrien	      && finalize_syms)
1237130561Sobrien	    report_op_error (symp, add_symbol, NULL);
1238130561Sobrien
1239130561Sobrien	  if (final_seg == expr_section || final_seg == undefined_section)
1240130561Sobrien	    final_seg = absolute_section;
1241130561Sobrien
124238889Sjdp	  if (op == O_uminus)
124338889Sjdp	    left = -left;
124438889Sjdp	  else if (op == O_logical_not)
124538889Sjdp	    left = !left;
124633965Sjdp	  else
124738889Sjdp	    left = ~left;
124838889Sjdp
124938889Sjdp	  final_val += left + symp->sy_frag->fr_address;
125038889Sjdp
125160484Sobrien	  resolved = symbol_resolved_p (add_symbol);
125233965Sjdp	  break;
125333965Sjdp
125433965Sjdp	case O_multiply:
125533965Sjdp	case O_divide:
125633965Sjdp	case O_modulus:
125733965Sjdp	case O_left_shift:
125833965Sjdp	case O_right_shift:
125933965Sjdp	case O_bit_inclusive_or:
126033965Sjdp	case O_bit_or_not:
126133965Sjdp	case O_bit_exclusive_or:
126233965Sjdp	case O_bit_and:
126333965Sjdp	case O_add:
126433965Sjdp	case O_subtract:
126533965Sjdp	case O_eq:
126633965Sjdp	case O_ne:
126733965Sjdp	case O_lt:
126833965Sjdp	case O_le:
126933965Sjdp	case O_ge:
127033965Sjdp	case O_gt:
127133965Sjdp	case O_logical_and:
127233965Sjdp	case O_logical_or:
127389857Sobrien	  left = resolve_symbol_value (add_symbol);
127489857Sobrien	  right = resolve_symbol_value (op_symbol);
127538889Sjdp	  seg_left = S_GET_SEGMENT (add_symbol);
127638889Sjdp	  seg_right = S_GET_SEGMENT (op_symbol);
127733965Sjdp
127838889Sjdp	  /* Simplify addition or subtraction of a constant by folding the
127938889Sjdp	     constant into X_add_number.  */
128089857Sobrien	  if (op == O_add)
128138889Sjdp	    {
128238889Sjdp	      if (seg_right == absolute_section)
128338889Sjdp		{
128489857Sobrien		  final_val += right;
128538889Sjdp		  goto do_symbol;
128638889Sjdp		}
128789857Sobrien	      else if (seg_left == absolute_section)
128838889Sjdp		{
128938889Sjdp		  final_val += left;
129038889Sjdp		  add_symbol = op_symbol;
129138889Sjdp		  left = right;
129289857Sobrien		  seg_left = seg_right;
129338889Sjdp		  goto do_symbol;
129438889Sjdp		}
129538889Sjdp	    }
129689857Sobrien	  else if (op == O_subtract)
129789857Sobrien	    {
129889857Sobrien	      if (seg_right == absolute_section)
129989857Sobrien		{
130089857Sobrien		  final_val -= right;
130189857Sobrien		  goto do_symbol;
130289857Sobrien		}
130389857Sobrien	    }
130438889Sjdp
1305218822Sdim	  move_seg_ok = 1;
130689857Sobrien	  /* Equality and non-equality tests are permitted on anything.
130789857Sobrien	     Subtraction, and other comparison operators are permitted if
130889857Sobrien	     both operands are in the same section.  Otherwise, both
130989857Sobrien	     operands must be absolute.  We already handled the case of
131089857Sobrien	     addition or subtraction of a constant above.  This will
131189857Sobrien	     probably need to be changed for an object file format which
1312218822Sdim	     supports arbitrary expressions, such as IEEE-695.  */
1313218822Sdim	  if (!(seg_left == absolute_section
1314130561Sobrien		   && seg_right == absolute_section)
1315130561Sobrien	      && !(op == O_eq || op == O_ne)
1316130561Sobrien	      && !((op == O_subtract
1317130561Sobrien		    || op == O_lt || op == O_le || op == O_ge || op == O_gt)
1318130561Sobrien		   && seg_left == seg_right
1319130561Sobrien		   && (seg_left != undefined_section
1320130561Sobrien		       || add_symbol == op_symbol)))
1321218822Sdim	    {
1322218822Sdim	      /* Don't emit messages unless we're finalizing the symbol value,
1323218822Sdim		 otherwise we may get the same message multiple times.  */
1324218822Sdim	      if (finalize_syms)
1325218822Sdim		report_op_error (symp, add_symbol, op_symbol);
1326218822Sdim	      /* However do not move the symbol into the absolute section
1327218822Sdim		 if it cannot currently be resolved - this would confuse
1328218822Sdim		 other parts of the assembler into believing that the
1329218822Sdim		 expression had been evaluated to zero.  */
1330218822Sdim	      else
1331218822Sdim		move_seg_ok = 0;
1332218822Sdim	    }
133333965Sjdp
1334218822Sdim	  if (move_seg_ok
1335218822Sdim	      && (final_seg == expr_section || final_seg == undefined_section))
1336130561Sobrien	    final_seg = absolute_section;
133733965Sjdp
133838889Sjdp	  /* Check for division by zero.  */
133938889Sjdp	  if ((op == O_divide || op == O_modulus) && right == 0)
134038889Sjdp	    {
134138889Sjdp	      /* If seg_right is not absolute_section, then we've
134289857Sobrien		 already issued a warning about using a bad symbol.  */
134389857Sobrien	      if (seg_right == absolute_section && finalize_syms)
134438889Sjdp		{
134538889Sjdp		  char *file;
134638889Sjdp		  unsigned int line;
134738889Sjdp
134838889Sjdp		  if (expr_symbol_where (symp, &file, &line))
134960484Sobrien		    as_bad_where (file, line, _("division by zero"));
135038889Sjdp		  else
135189857Sobrien		    as_bad (_("division by zero when setting `%s'"),
135238889Sjdp			    S_GET_NAME (symp));
135338889Sjdp		}
135438889Sjdp
135538889Sjdp	      right = 1;
135638889Sjdp	    }
135738889Sjdp
135833965Sjdp	  switch (symp->sy_value.X_op)
135933965Sjdp	    {
136038889Sjdp	    case O_multiply:		left *= right; break;
136138889Sjdp	    case O_divide:		left /= right; break;
136238889Sjdp	    case O_modulus:		left %= right; break;
136338889Sjdp	    case O_left_shift:		left <<= right; break;
136438889Sjdp	    case O_right_shift:		left >>= right; break;
136538889Sjdp	    case O_bit_inclusive_or:	left |= right; break;
136638889Sjdp	    case O_bit_or_not:		left |= ~right; break;
136738889Sjdp	    case O_bit_exclusive_or:	left ^= right; break;
136838889Sjdp	    case O_bit_and:		left &= right; break;
136938889Sjdp	    case O_add:			left += right; break;
137038889Sjdp	    case O_subtract:		left -= right; break;
137189857Sobrien	    case O_eq:
137289857Sobrien	    case O_ne:
137389857Sobrien	      left = (left == right && seg_left == seg_right
137489857Sobrien		      && (seg_left != undefined_section
137589857Sobrien			  || add_symbol == op_symbol)
137689857Sobrien		      ? ~ (offsetT) 0 : 0);
137789857Sobrien	      if (symp->sy_value.X_op == O_ne)
137889857Sobrien		left = ~left;
137989857Sobrien	      break;
138038889Sjdp	    case O_lt:	left = left <  right ? ~ (offsetT) 0 : 0; break;
138138889Sjdp	    case O_le:	left = left <= right ? ~ (offsetT) 0 : 0; break;
138238889Sjdp	    case O_ge:	left = left >= right ? ~ (offsetT) 0 : 0; break;
138338889Sjdp	    case O_gt:	left = left >  right ? ~ (offsetT) 0 : 0; break;
138438889Sjdp	    case O_logical_and:	left = left && right; break;
138538889Sjdp	    case O_logical_or:	left = left || right; break;
138638889Sjdp	    default:		abort ();
138733965Sjdp	    }
138838889Sjdp
138938889Sjdp	  final_val += symp->sy_frag->fr_address + left;
139038889Sjdp	  if (final_seg == expr_section || final_seg == undefined_section)
139199461Sobrien	    {
139299461Sobrien	      if (seg_left == undefined_section
139399461Sobrien		  || seg_right == undefined_section)
139499461Sobrien		final_seg = undefined_section;
139599461Sobrien	      else if (seg_left == absolute_section)
139699461Sobrien		final_seg = seg_right;
139799461Sobrien	      else
139899461Sobrien		final_seg = seg_left;
139999461Sobrien	    }
140060484Sobrien	  resolved = (symbol_resolved_p (add_symbol)
140160484Sobrien		      && symbol_resolved_p (op_symbol));
140277298Sobrien	  break;
140333965Sjdp
140433965Sjdp	case O_big:
140533965Sjdp	case O_illegal:
140633965Sjdp	  /* Give an error (below) if not in expr_section.  We don't
140733965Sjdp	     want to worry about expr_section symbols, because they
140833965Sjdp	     are fictional (they are created as part of expression
140933965Sjdp	     resolution), and any problems may not actually mean
141033965Sjdp	     anything.  */
141133965Sjdp	  break;
141233965Sjdp	}
141338889Sjdp
141438889Sjdp      symp->sy_resolving = 0;
141533965Sjdp    }
141633965Sjdp
141789857Sobrien  if (finalize_syms)
141889857Sobrien    S_SET_VALUE (symp, final_val);
141938889Sjdp
142089857Sobrienexit_dont_set_value:
142189857Sobrien  /* Always set the segment, even if not finalizing the value.
142289857Sobrien     The segment is used to determine whether a symbol is defined.  */
142389857Sobrien    S_SET_SEGMENT (symp, final_seg);
142438889Sjdp
142533965Sjdp  /* Don't worry if we can't resolve an expr_section symbol.  */
142689857Sobrien  if (finalize_syms)
142733965Sjdp    {
142838889Sjdp      if (resolved)
142938889Sjdp	symp->sy_resolved = 1;
143038889Sjdp      else if (S_GET_SEGMENT (symp) != expr_section)
143138889Sjdp	{
143289857Sobrien	  as_bad (_("can't resolve value for symbol `%s'"),
143377298Sobrien		  S_GET_NAME (symp));
143438889Sjdp	  symp->sy_resolved = 1;
143538889Sjdp	}
143633965Sjdp    }
143738889Sjdp
143838889Sjdp  return final_val;
143933965Sjdp}
144033965Sjdp
1441130561Sobrienstatic void resolve_local_symbol (const char *, PTR);
144260484Sobrien
144360484Sobrien/* A static function passed to hash_traverse.  */
144460484Sobrien
144560484Sobrienstatic void
1446130561Sobrienresolve_local_symbol (const char *key ATTRIBUTE_UNUSED, PTR value)
144760484Sobrien{
144860484Sobrien  if (value != NULL)
144989857Sobrien    resolve_symbol_value (value);
145060484Sobrien}
145160484Sobrien
145260484Sobrien/* Resolve all local symbols.  */
145360484Sobrien
145460484Sobrienvoid
1455130561Sobrienresolve_local_symbol_values (void)
145660484Sobrien{
145760484Sobrien  hash_traverse (local_hash, resolve_local_symbol);
145860484Sobrien}
145960484Sobrien
1460218822Sdim/* Obtain the current value of a symbol without changing any
1461218822Sdim   sub-expressions used.  */
1462218822Sdim
1463218822Sdimint
1464218822Sdimsnapshot_symbol (symbolS **symbolPP, valueT *valueP, segT *segP, fragS **fragPP)
1465218822Sdim{
1466218822Sdim  symbolS *symbolP = *symbolPP;
1467218822Sdim
1468218822Sdim  if (LOCAL_SYMBOL_CHECK (symbolP))
1469218822Sdim    {
1470218822Sdim      struct local_symbol *locsym = (struct local_symbol *) symbolP;
1471218822Sdim
1472218822Sdim      *valueP = locsym->lsy_value;
1473218822Sdim      *segP = locsym->lsy_section;
1474218822Sdim      *fragPP = local_symbol_get_frag (locsym);
1475218822Sdim    }
1476218822Sdim  else
1477218822Sdim    {
1478218822Sdim      expressionS expr = symbolP->sy_value;
1479218822Sdim
1480218822Sdim      if (!symbolP->sy_resolved && expr.X_op != O_illegal)
1481218822Sdim	{
1482218822Sdim	  int resolved;
1483218822Sdim
1484218822Sdim	  if (symbolP->sy_resolving)
1485218822Sdim	    return 0;
1486218822Sdim	  symbolP->sy_resolving = 1;
1487218822Sdim	  resolved = resolve_expression (&expr);
1488218822Sdim	  symbolP->sy_resolving = 0;
1489218822Sdim	  if (!resolved)
1490218822Sdim	    return 0;
1491218822Sdim
1492218822Sdim	  switch (expr.X_op)
1493218822Sdim	    {
1494218822Sdim	    case O_constant:
1495218822Sdim	    case O_register:
1496218822Sdim	      if (!symbol_equated_p (symbolP))
1497218822Sdim		break;
1498218822Sdim	      /* Fall thru.  */
1499218822Sdim	    case O_symbol:
1500218822Sdim	    case O_symbol_rva:
1501218822Sdim	      symbolP = expr.X_add_symbol;
1502218822Sdim	      break;
1503218822Sdim	    default:
1504218822Sdim	      return 0;
1505218822Sdim	    }
1506218822Sdim	}
1507218822Sdim
1508218822Sdim      /* Never change a defined symbol.  */
1509218822Sdim      if (symbolP->bsym->section == undefined_section
1510218822Sdim	  || symbolP->bsym->section == expr_section)
1511218822Sdim	*symbolPP = symbolP;
1512218822Sdim      *valueP = expr.X_add_number;
1513218822Sdim      *segP = symbolP->bsym->section;
1514218822Sdim      *fragPP = symbolP->sy_frag;
1515218822Sdim
1516218822Sdim      if (*segP == expr_section)
1517218822Sdim	switch (expr.X_op)
1518218822Sdim	  {
1519218822Sdim	  case O_constant: *segP = absolute_section; break;
1520218822Sdim	  case O_register: *segP = reg_section; break;
1521218822Sdim	  default: break;
1522218822Sdim	  }
1523218822Sdim    }
1524218822Sdim
1525218822Sdim  return 1;
1526218822Sdim}
1527218822Sdim
152833965Sjdp/* Dollar labels look like a number followed by a dollar sign.  Eg, "42$".
152933965Sjdp   They are *really* local.  That is, they go out of scope whenever we see a
153033965Sjdp   label that isn't local.  Also, like fb labels, there can be multiple
153133965Sjdp   instances of a dollar label.  Therefor, we name encode each instance with
153233965Sjdp   the instance number, keep a list of defined symbols separate from the real
153333965Sjdp   symbol table, and we treat these buggers as a sparse array.  */
153433965Sjdp
153533965Sjdpstatic long *dollar_labels;
153633965Sjdpstatic long *dollar_label_instances;
153733965Sjdpstatic char *dollar_label_defines;
153838889Sjdpstatic unsigned long dollar_label_count;
153933965Sjdpstatic unsigned long dollar_label_max;
154033965Sjdp
154177298Sobrienint
1542130561Sobriendollar_label_defined (long label)
154333965Sjdp{
154433965Sjdp  long *i;
154533965Sjdp
154633965Sjdp  know ((dollar_labels != NULL) || (dollar_label_count == 0));
154733965Sjdp
154833965Sjdp  for (i = dollar_labels; i < dollar_labels + dollar_label_count; ++i)
154933965Sjdp    if (*i == label)
155033965Sjdp      return dollar_label_defines[i - dollar_labels];
155133965Sjdp
155277298Sobrien  /* If we get here, label isn't defined.  */
155333965Sjdp  return 0;
155477298Sobrien}
155533965Sjdp
155633965Sjdpstatic long
1557130561Sobriendollar_label_instance (long label)
155833965Sjdp{
155933965Sjdp  long *i;
156033965Sjdp
156133965Sjdp  know ((dollar_labels != NULL) || (dollar_label_count == 0));
156233965Sjdp
156333965Sjdp  for (i = dollar_labels; i < dollar_labels + dollar_label_count; ++i)
156433965Sjdp    if (*i == label)
156533965Sjdp      return (dollar_label_instances[i - dollar_labels]);
156633965Sjdp
156777298Sobrien  /* If we get here, we haven't seen the label before.
156877298Sobrien     Therefore its instance count is zero.  */
156933965Sjdp  return 0;
157033965Sjdp}
157133965Sjdp
157277298Sobrienvoid
1573130561Sobriendollar_label_clear (void)
157433965Sjdp{
157533965Sjdp  memset (dollar_label_defines, '\0', (unsigned int) dollar_label_count);
157633965Sjdp}
157733965Sjdp
157833965Sjdp#define DOLLAR_LABEL_BUMP_BY 10
157933965Sjdp
158077298Sobrienvoid
1581130561Sobriendefine_dollar_label (long label)
158233965Sjdp{
158333965Sjdp  long *i;
158433965Sjdp
158533965Sjdp  for (i = dollar_labels; i < dollar_labels + dollar_label_count; ++i)
158633965Sjdp    if (*i == label)
158733965Sjdp      {
158833965Sjdp	++dollar_label_instances[i - dollar_labels];
158933965Sjdp	dollar_label_defines[i - dollar_labels] = 1;
159033965Sjdp	return;
159133965Sjdp      }
159233965Sjdp
159377298Sobrien  /* If we get to here, we don't have label listed yet.  */
159433965Sjdp
159533965Sjdp  if (dollar_labels == NULL)
159633965Sjdp    {
159733965Sjdp      dollar_labels = (long *) xmalloc (DOLLAR_LABEL_BUMP_BY * sizeof (long));
159833965Sjdp      dollar_label_instances = (long *) xmalloc (DOLLAR_LABEL_BUMP_BY * sizeof (long));
159933965Sjdp      dollar_label_defines = xmalloc (DOLLAR_LABEL_BUMP_BY);
160033965Sjdp      dollar_label_max = DOLLAR_LABEL_BUMP_BY;
160133965Sjdp      dollar_label_count = 0;
160233965Sjdp    }
160333965Sjdp  else if (dollar_label_count == dollar_label_max)
160433965Sjdp    {
160533965Sjdp      dollar_label_max += DOLLAR_LABEL_BUMP_BY;
160633965Sjdp      dollar_labels = (long *) xrealloc ((char *) dollar_labels,
160733965Sjdp					 dollar_label_max * sizeof (long));
160833965Sjdp      dollar_label_instances = (long *) xrealloc ((char *) dollar_label_instances,
160933965Sjdp					  dollar_label_max * sizeof (long));
161033965Sjdp      dollar_label_defines = xrealloc (dollar_label_defines, dollar_label_max);
161177298Sobrien    }				/* if we needed to grow  */
161233965Sjdp
161333965Sjdp  dollar_labels[dollar_label_count] = label;
161433965Sjdp  dollar_label_instances[dollar_label_count] = 1;
161533965Sjdp  dollar_label_defines[dollar_label_count] = 1;
161633965Sjdp  ++dollar_label_count;
161733965Sjdp}
161833965Sjdp
161977298Sobrien/* Caller must copy returned name: we re-use the area for the next name.
162033965Sjdp
162177298Sobrien   The mth occurence of label n: is turned into the symbol "Ln^Am"
162277298Sobrien   where n is the label number and m is the instance number. "L" makes
162377298Sobrien   it a label discarded unless debugging and "^A"('\1') ensures no
162477298Sobrien   ordinary symbol SHOULD get the same name as a local label
162577298Sobrien   symbol. The first "4:" is "L4^A1" - the m numbers begin at 1.
162677298Sobrien
162777298Sobrien   fb labels get the same treatment, except that ^B is used in place
162877298Sobrien   of ^A.  */
162977298Sobrien
163077298Sobrienchar *				/* Return local label name.  */
1631130561Sobriendollar_label_name (register long n,	/* we just saw "n$:" : n a number.  */
1632130561Sobrien		   register int augend	/* 0 for current instance, 1 for new instance.  */)
163333965Sjdp{
163433965Sjdp  long i;
163577298Sobrien  /* Returned to caller, then copied.  Used for created names ("4f").  */
163633965Sjdp  static char symbol_name_build[24];
163733965Sjdp  register char *p;
163833965Sjdp  register char *q;
163977298Sobrien  char symbol_name_temporary[20];	/* Build up a number, BACKWARDS.  */
164033965Sjdp
164133965Sjdp  know (n >= 0);
164233965Sjdp  know (augend == 0 || augend == 1);
164333965Sjdp  p = symbol_name_build;
164460484Sobrien#ifdef LOCAL_LABEL_PREFIX
164560484Sobrien  *p++ = LOCAL_LABEL_PREFIX;
164660484Sobrien#endif
164733965Sjdp  *p++ = 'L';
164833965Sjdp
164977298Sobrien  /* Next code just does sprintf( {}, "%d", n);  */
165077298Sobrien  /* Label number.  */
165133965Sjdp  q = symbol_name_temporary;
165233965Sjdp  for (*q++ = 0, i = n; i; ++q)
165333965Sjdp    {
165433965Sjdp      *q = i % 10 + '0';
165533965Sjdp      i /= 10;
165633965Sjdp    }
165733965Sjdp  while ((*p = *--q) != '\0')
165833965Sjdp    ++p;
165933965Sjdp
166077298Sobrien  *p++ = DOLLAR_LABEL_CHAR;		/* ^A  */
166133965Sjdp
166277298Sobrien  /* Instance number.  */
166333965Sjdp  q = symbol_name_temporary;
166433965Sjdp  for (*q++ = 0, i = dollar_label_instance (n) + augend; i; ++q)
166533965Sjdp    {
166633965Sjdp      *q = i % 10 + '0';
166733965Sjdp      i /= 10;
166833965Sjdp    }
166933965Sjdp  while ((*p++ = *--q) != '\0');;
167033965Sjdp
167177298Sobrien  /* The label, as a '\0' ended string, starts at symbol_name_build.  */
167233965Sjdp  return symbol_name_build;
167333965Sjdp}
167433965Sjdp
1675130561Sobrien/* Somebody else's idea of local labels. They are made by "n:" where n
167677298Sobrien   is any decimal digit. Refer to them with
167777298Sobrien    "nb" for previous (backward) n:
167877298Sobrien   or "nf" for next (forward) n:.
167933965Sjdp
168077298Sobrien   We do a little better and let n be any number, not just a single digit, but
168177298Sobrien   since the other guy's assembler only does ten, we treat the first ten
168277298Sobrien   specially.
168377298Sobrien
168477298Sobrien   Like someone else's assembler, we have one set of local label counters for
168577298Sobrien   entire assembly, not one set per (sub)segment like in most assemblers. This
168677298Sobrien   implies that one can refer to a label in another segment, and indeed some
168777298Sobrien   crufty compilers have done just that.
168877298Sobrien
168977298Sobrien   Since there could be a LOT of these things, treat them as a sparse
169077298Sobrien   array.  */
169177298Sobrien
169233965Sjdp#define FB_LABEL_SPECIAL (10)
169333965Sjdp
169433965Sjdpstatic long fb_low_counter[FB_LABEL_SPECIAL];
169533965Sjdpstatic long *fb_labels;
169633965Sjdpstatic long *fb_label_instances;
169733965Sjdpstatic long fb_label_count;
169833965Sjdpstatic long fb_label_max;
169933965Sjdp
170077298Sobrien/* This must be more than FB_LABEL_SPECIAL.  */
170133965Sjdp#define FB_LABEL_BUMP_BY (FB_LABEL_SPECIAL + 6)
170233965Sjdp
170377298Sobrienstatic void
1704130561Sobrienfb_label_init (void)
170533965Sjdp{
170633965Sjdp  memset ((void *) fb_low_counter, '\0', sizeof (fb_low_counter));
170777298Sobrien}
170833965Sjdp
170977298Sobrien/* Add one to the instance number of this fb label.  */
171077298Sobrien
171177298Sobrienvoid
1712130561Sobrienfb_label_instance_inc (long label)
171333965Sjdp{
171433965Sjdp  long *i;
171533965Sjdp
171633965Sjdp  if (label < FB_LABEL_SPECIAL)
171733965Sjdp    {
171833965Sjdp      ++fb_low_counter[label];
171933965Sjdp      return;
172033965Sjdp    }
172133965Sjdp
172233965Sjdp  if (fb_labels != NULL)
172333965Sjdp    {
172433965Sjdp      for (i = fb_labels + FB_LABEL_SPECIAL;
172533965Sjdp	   i < fb_labels + fb_label_count; ++i)
172633965Sjdp	{
172733965Sjdp	  if (*i == label)
172833965Sjdp	    {
172933965Sjdp	      ++fb_label_instances[i - fb_labels];
173033965Sjdp	      return;
173177298Sobrien	    }			/* if we find it  */
173277298Sobrien	}			/* for each existing label  */
173333965Sjdp    }
173433965Sjdp
173577298Sobrien  /* If we get to here, we don't have label listed yet.  */
173633965Sjdp
173733965Sjdp  if (fb_labels == NULL)
173833965Sjdp    {
173933965Sjdp      fb_labels = (long *) xmalloc (FB_LABEL_BUMP_BY * sizeof (long));
174033965Sjdp      fb_label_instances = (long *) xmalloc (FB_LABEL_BUMP_BY * sizeof (long));
174133965Sjdp      fb_label_max = FB_LABEL_BUMP_BY;
174233965Sjdp      fb_label_count = FB_LABEL_SPECIAL;
174333965Sjdp
174433965Sjdp    }
174533965Sjdp  else if (fb_label_count == fb_label_max)
174633965Sjdp    {
174733965Sjdp      fb_label_max += FB_LABEL_BUMP_BY;
174833965Sjdp      fb_labels = (long *) xrealloc ((char *) fb_labels,
174933965Sjdp				     fb_label_max * sizeof (long));
175033965Sjdp      fb_label_instances = (long *) xrealloc ((char *) fb_label_instances,
175133965Sjdp					      fb_label_max * sizeof (long));
175277298Sobrien    }				/* if we needed to grow  */
175333965Sjdp
175433965Sjdp  fb_labels[fb_label_count] = label;
175533965Sjdp  fb_label_instances[fb_label_count] = 1;
175633965Sjdp  ++fb_label_count;
175733965Sjdp}
175833965Sjdp
175977298Sobrienstatic long
1760130561Sobrienfb_label_instance (long label)
176133965Sjdp{
176233965Sjdp  long *i;
176333965Sjdp
176433965Sjdp  if (label < FB_LABEL_SPECIAL)
176533965Sjdp    {
176633965Sjdp      return (fb_low_counter[label]);
176733965Sjdp    }
176833965Sjdp
176933965Sjdp  if (fb_labels != NULL)
177033965Sjdp    {
177133965Sjdp      for (i = fb_labels + FB_LABEL_SPECIAL;
177233965Sjdp	   i < fb_labels + fb_label_count; ++i)
177333965Sjdp	{
177433965Sjdp	  if (*i == label)
177533965Sjdp	    {
177633965Sjdp	      return (fb_label_instances[i - fb_labels]);
177777298Sobrien	    }			/* if we find it  */
177877298Sobrien	}			/* for each existing label  */
177933965Sjdp    }
178033965Sjdp
178133965Sjdp  /* We didn't find the label, so this must be a reference to the
178233965Sjdp     first instance.  */
178333965Sjdp  return 0;
178433965Sjdp}
178533965Sjdp
178677298Sobrien/* Caller must copy returned name: we re-use the area for the next name.
178733965Sjdp
178877298Sobrien   The mth occurence of label n: is turned into the symbol "Ln^Bm"
178977298Sobrien   where n is the label number and m is the instance number. "L" makes
179077298Sobrien   it a label discarded unless debugging and "^B"('\2') ensures no
179177298Sobrien   ordinary symbol SHOULD get the same name as a local label
179277298Sobrien   symbol. The first "4:" is "L4^B1" - the m numbers begin at 1.
179377298Sobrien
179477298Sobrien   dollar labels get the same treatment, except that ^A is used in
179577298Sobrien   place of ^B.  */
179677298Sobrien
179777298Sobrienchar *				/* Return local label name.  */
1798130561Sobrienfb_label_name (long n,	/* We just saw "n:", "nf" or "nb" : n a number.  */
1799130561Sobrien	       long augend	/* 0 for nb, 1 for n:, nf.  */)
180033965Sjdp{
180133965Sjdp  long i;
180277298Sobrien  /* Returned to caller, then copied.  Used for created names ("4f").  */
180333965Sjdp  static char symbol_name_build[24];
180433965Sjdp  register char *p;
180533965Sjdp  register char *q;
180677298Sobrien  char symbol_name_temporary[20];	/* Build up a number, BACKWARDS.  */
180733965Sjdp
180833965Sjdp  know (n >= 0);
1809218822Sdim#ifdef TC_MMIX
1810218822Sdim  know ((unsigned long) augend <= 2 /* See mmix_fb_label.  */);
1811218822Sdim#else
1812218822Sdim  know ((unsigned long) augend <= 1);
1813218822Sdim#endif
181433965Sjdp  p = symbol_name_build;
181577298Sobrien#ifdef LOCAL_LABEL_PREFIX
181677298Sobrien  *p++ = LOCAL_LABEL_PREFIX;
181777298Sobrien#endif
181833965Sjdp  *p++ = 'L';
181933965Sjdp
182077298Sobrien  /* Next code just does sprintf( {}, "%d", n);  */
182177298Sobrien  /* Label number.  */
182233965Sjdp  q = symbol_name_temporary;
182333965Sjdp  for (*q++ = 0, i = n; i; ++q)
182433965Sjdp    {
182533965Sjdp      *q = i % 10 + '0';
182633965Sjdp      i /= 10;
182733965Sjdp    }
182833965Sjdp  while ((*p = *--q) != '\0')
182933965Sjdp    ++p;
183033965Sjdp
183177298Sobrien  *p++ = LOCAL_LABEL_CHAR;		/* ^B  */
183233965Sjdp
183377298Sobrien  /* Instance number.  */
183433965Sjdp  q = symbol_name_temporary;
183533965Sjdp  for (*q++ = 0, i = fb_label_instance (n) + augend; i; ++q)
183633965Sjdp    {
183733965Sjdp      *q = i % 10 + '0';
183833965Sjdp      i /= 10;
183933965Sjdp    }
184033965Sjdp  while ((*p++ = *--q) != '\0');;
184133965Sjdp
184277298Sobrien  /* The label, as a '\0' ended string, starts at symbol_name_build.  */
184333965Sjdp  return (symbol_name_build);
184477298Sobrien}
184533965Sjdp
184677298Sobrien/* Decode name that may have been generated by foo_label_name() above.
184777298Sobrien   If the name wasn't generated by foo_label_name(), then return it
184877298Sobrien   unaltered.  This is used for error messages.  */
184933965Sjdp
185033965Sjdpchar *
1851130561Sobriendecode_local_label_name (char *s)
185233965Sjdp{
185333965Sjdp  char *p;
185433965Sjdp  char *symbol_decode;
185533965Sjdp  int label_number;
185633965Sjdp  int instance_number;
185733965Sjdp  char *type;
185878828Sobrien  const char *message_format;
185977298Sobrien  int index = 0;
186033965Sjdp
186177298Sobrien#ifdef LOCAL_LABEL_PREFIX
186277298Sobrien  if (s[index] == LOCAL_LABEL_PREFIX)
186377298Sobrien    ++index;
186477298Sobrien#endif
186577298Sobrien
186677298Sobrien  if (s[index] != 'L')
186733965Sjdp    return s;
186833965Sjdp
186989857Sobrien  for (label_number = 0, p = s + index + 1; ISDIGIT (*p); ++p)
187033965Sjdp    label_number = (10 * label_number) + *p - '0';
187133965Sjdp
187277298Sobrien  if (*p == DOLLAR_LABEL_CHAR)
187333965Sjdp    type = "dollar";
187477298Sobrien  else if (*p == LOCAL_LABEL_CHAR)
187533965Sjdp    type = "fb";
187633965Sjdp  else
187733965Sjdp    return s;
187833965Sjdp
187989857Sobrien  for (instance_number = 0, p++; ISDIGIT (*p); ++p)
188033965Sjdp    instance_number = (10 * instance_number) + *p - '0';
188133965Sjdp
188278828Sobrien  message_format = _("\"%d\" (instance number %d of a %s label)");
188333965Sjdp  symbol_decode = obstack_alloc (&notes, strlen (message_format) + 30);
188433965Sjdp  sprintf (symbol_decode, message_format, label_number, instance_number, type);
188533965Sjdp
188633965Sjdp  return symbol_decode;
188733965Sjdp}
188833965Sjdp
188933965Sjdp/* Get the value of a symbol.  */
189033965Sjdp
189133965SjdpvalueT
1892130561SobrienS_GET_VALUE (symbolS *s)
189333965Sjdp{
189460484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
189589857Sobrien    return resolve_symbol_value (s);
189660484Sobrien
189789857Sobrien  if (!s->sy_resolved)
189889857Sobrien    {
189989857Sobrien      valueT val = resolve_symbol_value (s);
190089857Sobrien      if (!finalize_syms)
190189857Sobrien	return val;
190289857Sobrien    }
1903218822Sdim  if (S_IS_WEAKREFR (s))
1904218822Sdim    return S_GET_VALUE (s->sy_value.X_add_symbol);
1905218822Sdim
190633965Sjdp  if (s->sy_value.X_op != O_constant)
190733965Sjdp    {
190833965Sjdp      if (! s->sy_resolved
190933965Sjdp	  || s->sy_value.X_op != O_symbol
191033965Sjdp	  || (S_IS_DEFINED (s) && ! S_IS_COMMON (s)))
191189857Sobrien	as_bad (_("attempt to get value of unresolved symbol `%s'"),
191233965Sjdp		S_GET_NAME (s));
191333965Sjdp    }
191433965Sjdp  return (valueT) s->sy_value.X_add_number;
191533965Sjdp}
191633965Sjdp
191733965Sjdp/* Set the value of a symbol.  */
191833965Sjdp
191933965Sjdpvoid
1920130561SobrienS_SET_VALUE (symbolS *s, valueT val)
192133965Sjdp{
192260484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
192360484Sobrien    {
192489857Sobrien      ((struct local_symbol *) s)->lsy_value = val;
192560484Sobrien      return;
192660484Sobrien    }
192760484Sobrien
192833965Sjdp  s->sy_value.X_op = O_constant;
192933965Sjdp  s->sy_value.X_add_number = (offsetT) val;
193033965Sjdp  s->sy_value.X_unsigned = 0;
1931218822Sdim  S_CLEAR_WEAKREFR (s);
193233965Sjdp}
193333965Sjdp
193433965Sjdpvoid
1935130561Sobriencopy_symbol_attributes (symbolS *dest, symbolS *src)
193633965Sjdp{
193760484Sobrien  if (LOCAL_SYMBOL_CHECK (dest))
193860484Sobrien    dest = local_symbol_convert ((struct local_symbol *) dest);
193960484Sobrien  if (LOCAL_SYMBOL_CHECK (src))
194060484Sobrien    src = local_symbol_convert ((struct local_symbol *) src);
194160484Sobrien
194233965Sjdp  /* In an expression, transfer the settings of these flags.
194333965Sjdp     The user can override later, of course.  */
194438889Sjdp#define COPIED_SYMFLAGS	(BSF_FUNCTION | BSF_OBJECT)
194533965Sjdp  dest->bsym->flags |= src->bsym->flags & COPIED_SYMFLAGS;
194633965Sjdp
194733965Sjdp#ifdef OBJ_COPY_SYMBOL_ATTRIBUTES
194833965Sjdp  OBJ_COPY_SYMBOL_ATTRIBUTES (dest, src);
194933965Sjdp#endif
1950218822Sdim
1951218822Sdim#ifdef TC_COPY_SYMBOL_ATTRIBUTES
1952218822Sdim  TC_COPY_SYMBOL_ATTRIBUTES (dest, src);
1953218822Sdim#endif
195433965Sjdp}
195533965Sjdp
195633965Sjdpint
1957130561SobrienS_IS_FUNCTION (symbolS *s)
195860484Sobrien{
195960484Sobrien  flagword flags;
196060484Sobrien
196160484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
196260484Sobrien    return 0;
196360484Sobrien
196460484Sobrien  flags = s->bsym->flags;
196560484Sobrien
196660484Sobrien  return (flags & BSF_FUNCTION) != 0;
196760484Sobrien}
196860484Sobrien
196960484Sobrienint
1970130561SobrienS_IS_EXTERNAL (symbolS *s)
197133965Sjdp{
197260484Sobrien  flagword flags;
197333965Sjdp
197460484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
197560484Sobrien    return 0;
197660484Sobrien
197760484Sobrien  flags = s->bsym->flags;
197860484Sobrien
197977298Sobrien  /* Sanity check.  */
198038889Sjdp  if ((flags & BSF_LOCAL) && (flags & BSF_GLOBAL))
198133965Sjdp    abort ();
198233965Sjdp
198333965Sjdp  return (flags & BSF_GLOBAL) != 0;
198433965Sjdp}
198533965Sjdp
198633965Sjdpint
1987130561SobrienS_IS_WEAK (symbolS *s)
198833965Sjdp{
198960484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
199060484Sobrien    return 0;
1991218822Sdim  /* Conceptually, a weakrefr is weak if the referenced symbol is.  We
1992218822Sdim     could probably handle a WEAKREFR as always weak though.  E.g., if
1993218822Sdim     the referenced symbol has lost its weak status, there's no reason
1994218822Sdim     to keep handling the weakrefr as if it was weak.  */
1995218822Sdim  if (S_IS_WEAKREFR (s))
1996218822Sdim    return S_IS_WEAK (s->sy_value.X_add_symbol);
199733965Sjdp  return (s->bsym->flags & BSF_WEAK) != 0;
199833965Sjdp}
199933965Sjdp
200033965Sjdpint
2001218822SdimS_IS_WEAKREFR (symbolS *s)
2002218822Sdim{
2003218822Sdim  if (LOCAL_SYMBOL_CHECK (s))
2004218822Sdim    return 0;
2005218822Sdim  return s->sy_weakrefr != 0;
2006218822Sdim}
2007218822Sdim
2008218822Sdimint
2009218822SdimS_IS_WEAKREFD (symbolS *s)
2010218822Sdim{
2011218822Sdim  if (LOCAL_SYMBOL_CHECK (s))
2012218822Sdim    return 0;
2013218822Sdim  return s->sy_weakrefd != 0;
2014218822Sdim}
2015218822Sdim
2016218822Sdimint
2017130561SobrienS_IS_COMMON (symbolS *s)
201833965Sjdp{
201960484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
202060484Sobrien    return 0;
202133965Sjdp  return bfd_is_com_section (s->bsym->section);
202233965Sjdp}
202333965Sjdp
202433965Sjdpint
2025130561SobrienS_IS_DEFINED (symbolS *s)
202633965Sjdp{
202760484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
202860484Sobrien    return ((struct local_symbol *) s)->lsy_section != undefined_section;
202933965Sjdp  return s->bsym->section != undefined_section;
203033965Sjdp}
203133965Sjdp
2032130561Sobrien
2033130561Sobrien#ifndef EXTERN_FORCE_RELOC
2034130561Sobrien#define EXTERN_FORCE_RELOC IS_ELF
2035130561Sobrien#endif
2036130561Sobrien
2037130561Sobrien/* Return true for symbols that should not be reduced to section
2038130561Sobrien   symbols or eliminated from expressions, because they may be
2039130561Sobrien   overridden by the linker.  */
204033965Sjdpint
2041130561SobrienS_FORCE_RELOC (symbolS *s, int strict)
204233965Sjdp{
204360484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
2044130561Sobrien    return ((struct local_symbol *) s)->lsy_section == undefined_section;
2045130561Sobrien
2046130561Sobrien  return ((strict
2047130561Sobrien	   && ((s->bsym->flags & BSF_WEAK) != 0
2048130561Sobrien	       || (EXTERN_FORCE_RELOC
2049130561Sobrien		   && (s->bsym->flags & BSF_GLOBAL) != 0)))
2050130561Sobrien	  || s->bsym->section == undefined_section
2051130561Sobrien	  || bfd_is_com_section (s->bsym->section));
2052130561Sobrien}
2053130561Sobrien
2054130561Sobrienint
2055130561SobrienS_IS_DEBUG (symbolS *s)
2056130561Sobrien{
2057130561Sobrien  if (LOCAL_SYMBOL_CHECK (s))
205860484Sobrien    return 0;
205933965Sjdp  if (s->bsym->flags & BSF_DEBUGGING)
206033965Sjdp    return 1;
206133965Sjdp  return 0;
206233965Sjdp}
206333965Sjdp
206433965Sjdpint
2065130561SobrienS_IS_LOCAL (symbolS *s)
206633965Sjdp{
206760484Sobrien  flagword flags;
206833965Sjdp  const char *name;
206933965Sjdp
207060484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
207160484Sobrien    return 1;
207260484Sobrien
207360484Sobrien  flags = s->bsym->flags;
207460484Sobrien
207577298Sobrien  /* Sanity check.  */
207638889Sjdp  if ((flags & BSF_LOCAL) && (flags & BSF_GLOBAL))
207733965Sjdp    abort ();
207833965Sjdp
207933965Sjdp  if (bfd_get_section (s->bsym) == reg_section)
208033965Sjdp    return 1;
208133965Sjdp
208238889Sjdp  if (flag_strip_local_absolute
2083218822Sdim      /* Keep BSF_FILE symbols in order to allow debuggers to identify
2084218822Sdim	 the source file even when the object file is stripped.  */
2085218822Sdim      && (flags & (BSF_GLOBAL | BSF_FILE)) == 0
208638889Sjdp      && bfd_get_section (s->bsym) == absolute_section)
208738889Sjdp    return 1;
208838889Sjdp
208933965Sjdp  name = S_GET_NAME (s);
209033965Sjdp  return (name != NULL
209133965Sjdp	  && ! S_IS_DEBUG (s)
209277298Sobrien	  && (strchr (name, DOLLAR_LABEL_CHAR)
209377298Sobrien	      || strchr (name, LOCAL_LABEL_CHAR)
209433965Sjdp	      || (! flag_keep_locals
209533965Sjdp		  && (bfd_is_local_label (stdoutput, s->bsym)
209633965Sjdp		      || (flag_mri
209733965Sjdp			  && name[0] == '?'
209833965Sjdp			  && name[1] == '?')))));
209933965Sjdp}
210033965Sjdp
210133965Sjdpint
2102218822SdimS_IS_STABD (symbolS *s)
210333965Sjdp{
2104218822Sdim  return S_GET_NAME (s) == 0;
210533965Sjdp}
210633965Sjdp
210733965Sjdpint
2108218822SdimS_IS_VOLATILE (const symbolS *s)
210933965Sjdp{
2110218822Sdim  if (LOCAL_SYMBOL_CHECK (s))
2111218822Sdim    return 0;
2112218822Sdim  return s->sy_volatile;
211333965Sjdp}
211433965Sjdp
2115218822Sdimint
2116218822SdimS_IS_FORWARD_REF (const symbolS *s)
2117218822Sdim{
2118218822Sdim  if (LOCAL_SYMBOL_CHECK (s))
2119218822Sdim    return 0;
2120218822Sdim  return s->sy_forward_ref;
2121218822Sdim}
2122218822Sdim
2123104834Sobrienconst char *
2124130561SobrienS_GET_NAME (symbolS *s)
212533965Sjdp{
212660484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
212760484Sobrien    return ((struct local_symbol *) s)->lsy_name;
212833965Sjdp  return s->bsym->name;
212933965Sjdp}
213033965Sjdp
213133965SjdpsegT
2132130561SobrienS_GET_SEGMENT (symbolS *s)
213333965Sjdp{
213460484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
213560484Sobrien    return ((struct local_symbol *) s)->lsy_section;
213633965Sjdp  return s->bsym->section;
213733965Sjdp}
213833965Sjdp
213933965Sjdpvoid
2140130561SobrienS_SET_SEGMENT (symbolS *s, segT seg)
214133965Sjdp{
214238889Sjdp  /* Don't reassign section symbols.  The direct reason is to prevent seg
214338889Sjdp     faults assigning back to const global symbols such as *ABS*, but it
214438889Sjdp     shouldn't happen anyway.  */
214538889Sjdp
214660484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
214760484Sobrien    {
214860484Sobrien      if (seg == reg_section)
214960484Sobrien	s = local_symbol_convert ((struct local_symbol *) s);
215060484Sobrien      else
215160484Sobrien	{
215260484Sobrien	  ((struct local_symbol *) s)->lsy_section = seg;
215360484Sobrien	  return;
215460484Sobrien	}
215560484Sobrien    }
215660484Sobrien
215738889Sjdp  if (s->bsym->flags & BSF_SECTION_SYM)
215838889Sjdp    {
215938889Sjdp      if (s->bsym->section != seg)
216077298Sobrien	abort ();
216138889Sjdp    }
216238889Sjdp  else
216338889Sjdp    s->bsym->section = seg;
216433965Sjdp}
216533965Sjdp
216633965Sjdpvoid
2167130561SobrienS_SET_EXTERNAL (symbolS *s)
216833965Sjdp{
216960484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
217060484Sobrien    s = local_symbol_convert ((struct local_symbol *) s);
217133965Sjdp  if ((s->bsym->flags & BSF_WEAK) != 0)
217233965Sjdp    {
217333965Sjdp      /* Let .weak override .global.  */
217433965Sjdp      return;
217533965Sjdp    }
217678828Sobrien  if (s->bsym->flags & BSF_SECTION_SYM)
217778828Sobrien    {
217878828Sobrien      char * file;
217978828Sobrien      unsigned int line;
2180104834Sobrien
218178828Sobrien      /* Do not reassign section symbols.  */
218278828Sobrien      as_where (& file, & line);
218378828Sobrien      as_warn_where (file, line,
218489857Sobrien		     _("section symbols are already global"));
218578828Sobrien      return;
218678828Sobrien    }
218733965Sjdp  s->bsym->flags |= BSF_GLOBAL;
218877298Sobrien  s->bsym->flags &= ~(BSF_LOCAL | BSF_WEAK);
2189218822Sdim
2190218822Sdim#ifdef USE_UNIQUE
2191218822Sdim  if (! an_external_name && S_GET_NAME(s)[0] != '.')
2192218822Sdim    an_external_name = S_GET_NAME (s);
2193218822Sdim#endif
219433965Sjdp}
219533965Sjdp
219633965Sjdpvoid
2197130561SobrienS_CLEAR_EXTERNAL (symbolS *s)
219833965Sjdp{
219960484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
220060484Sobrien    return;
220133965Sjdp  if ((s->bsym->flags & BSF_WEAK) != 0)
220233965Sjdp    {
220333965Sjdp      /* Let .weak override.  */
220433965Sjdp      return;
220533965Sjdp    }
220633965Sjdp  s->bsym->flags |= BSF_LOCAL;
220777298Sobrien  s->bsym->flags &= ~(BSF_GLOBAL | BSF_WEAK);
220833965Sjdp}
220933965Sjdp
221033965Sjdpvoid
2211130561SobrienS_SET_WEAK (symbolS *s)
221233965Sjdp{
221360484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
221460484Sobrien    s = local_symbol_convert ((struct local_symbol *) s);
2215218822Sdim#ifdef obj_set_weak_hook
2216218822Sdim  obj_set_weak_hook (s);
2217218822Sdim#endif
221833965Sjdp  s->bsym->flags |= BSF_WEAK;
221977298Sobrien  s->bsym->flags &= ~(BSF_GLOBAL | BSF_LOCAL);
222033965Sjdp}
222133965Sjdp
222233965Sjdpvoid
2223218822SdimS_SET_WEAKREFR (symbolS *s)
2224218822Sdim{
2225218822Sdim  if (LOCAL_SYMBOL_CHECK (s))
2226218822Sdim    s = local_symbol_convert ((struct local_symbol *) s);
2227218822Sdim  s->sy_weakrefr = 1;
2228218822Sdim  /* If the alias was already used, make sure we mark the target as
2229218822Sdim     used as well, otherwise it might be dropped from the symbol
2230218822Sdim     table.  This may have unintended side effects if the alias is
2231218822Sdim     later redirected to another symbol, such as keeping the unused
2232218822Sdim     previous target in the symbol table.  Since it will be weak, it's
2233218822Sdim     not a big deal.  */
2234218822Sdim  if (s->sy_used)
2235218822Sdim    symbol_mark_used (s->sy_value.X_add_symbol);
2236218822Sdim}
2237218822Sdim
2238218822Sdimvoid
2239218822SdimS_CLEAR_WEAKREFR (symbolS *s)
2240218822Sdim{
2241218822Sdim  if (LOCAL_SYMBOL_CHECK (s))
2242218822Sdim    return;
2243218822Sdim  s->sy_weakrefr = 0;
2244218822Sdim}
2245218822Sdim
2246218822Sdimvoid
2247218822SdimS_SET_WEAKREFD (symbolS *s)
2248218822Sdim{
2249218822Sdim  if (LOCAL_SYMBOL_CHECK (s))
2250218822Sdim    s = local_symbol_convert ((struct local_symbol *) s);
2251218822Sdim  s->sy_weakrefd = 1;
2252218822Sdim  S_SET_WEAK (s);
2253218822Sdim}
2254218822Sdim
2255218822Sdimvoid
2256218822SdimS_CLEAR_WEAKREFD (symbolS *s)
2257218822Sdim{
2258218822Sdim  if (LOCAL_SYMBOL_CHECK (s))
2259218822Sdim    return;
2260218822Sdim  if (s->sy_weakrefd)
2261218822Sdim    {
2262218822Sdim      s->sy_weakrefd = 0;
2263218822Sdim      /* If a weakref target symbol is weak, then it was never
2264218822Sdim	 referenced directly before, not even in a .global directive,
2265218822Sdim	 so decay it to local.  If it remains undefined, it will be
2266218822Sdim	 later turned into a global, like any other undefined
2267218822Sdim	 symbol.  */
2268218822Sdim      if (s->bsym->flags & BSF_WEAK)
2269218822Sdim	{
2270218822Sdim#ifdef obj_clear_weak_hook
2271218822Sdim	  obj_clear_weak_hook (s);
2272218822Sdim#endif
2273218822Sdim	  s->bsym->flags &= ~BSF_WEAK;
2274218822Sdim	  s->bsym->flags |= BSF_LOCAL;
2275218822Sdim	}
2276218822Sdim    }
2277218822Sdim}
2278218822Sdim
2279218822Sdimvoid
2280130561SobrienS_SET_THREAD_LOCAL (symbolS *s)
228133965Sjdp{
228260484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
2283130561Sobrien    s = local_symbol_convert ((struct local_symbol *) s);
2284130561Sobrien  if (bfd_is_com_section (s->bsym->section)
2285130561Sobrien      && (s->bsym->flags & BSF_THREAD_LOCAL) != 0)
2286130561Sobrien    return;
2287130561Sobrien  s->bsym->flags |= BSF_THREAD_LOCAL;
2288130561Sobrien  if ((s->bsym->flags & BSF_FUNCTION) != 0)
2289130561Sobrien    as_bad (_("Accessing function `%s' as thread-local object"),
2290130561Sobrien	    S_GET_NAME (s));
2291130561Sobrien  else if (! bfd_is_und_section (s->bsym->section)
2292130561Sobrien	   && (s->bsym->section->flags & SEC_THREAD_LOCAL) == 0)
2293130561Sobrien    as_bad (_("Accessing `%s' as thread-local object"),
2294130561Sobrien	    S_GET_NAME (s));
2295130561Sobrien}
2296130561Sobrien
2297130561Sobrienvoid
2298218822SdimS_SET_NAME (symbolS *s, const char *name)
2299130561Sobrien{
2300130561Sobrien  if (LOCAL_SYMBOL_CHECK (s))
230160484Sobrien    {
230260484Sobrien      ((struct local_symbol *) s)->lsy_name = name;
230360484Sobrien      return;
230460484Sobrien    }
230533965Sjdp  s->bsym->name = name;
230633965Sjdp}
230733965Sjdp
2308218822Sdimvoid
2309218822SdimS_SET_VOLATILE (symbolS *s)
2310218822Sdim{
2311218822Sdim  if (LOCAL_SYMBOL_CHECK (s))
2312218822Sdim    s = local_symbol_convert ((struct local_symbol *) s);
2313218822Sdim  s->sy_volatile = 1;
2314218822Sdim}
231560484Sobrien
2316218822Sdimvoid
2317218822SdimS_CLEAR_VOLATILE (symbolS *s)
2318218822Sdim{
2319218822Sdim  if (!LOCAL_SYMBOL_CHECK (s))
2320218822Sdim    s->sy_volatile = 0;
2321218822Sdim}
2322218822Sdim
2323218822Sdimvoid
2324218822SdimS_SET_FORWARD_REF (symbolS *s)
2325218822Sdim{
2326218822Sdim  if (LOCAL_SYMBOL_CHECK (s))
2327218822Sdim    s = local_symbol_convert ((struct local_symbol *) s);
2328218822Sdim  s->sy_forward_ref = 1;
2329218822Sdim}
2330218822Sdim
233160484Sobrien/* Return the previous symbol in a chain.  */
233260484Sobrien
233360484SobriensymbolS *
2334130561Sobriensymbol_previous (symbolS *s)
233560484Sobrien{
233660484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
233760484Sobrien    abort ();
233860484Sobrien  return s->sy_previous;
233960484Sobrien}
234060484Sobrien
234160484Sobrien/* Return the next symbol in a chain.  */
234260484Sobrien
234360484SobriensymbolS *
2344130561Sobriensymbol_next (symbolS *s)
234560484Sobrien{
234660484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
234760484Sobrien    abort ();
234860484Sobrien  return s->sy_next;
234960484Sobrien}
235060484Sobrien
235160484Sobrien/* Return a pointer to the value of a symbol as an expression.  */
235260484Sobrien
235360484SobrienexpressionS *
2354130561Sobriensymbol_get_value_expression (symbolS *s)
235560484Sobrien{
235660484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
235760484Sobrien    s = local_symbol_convert ((struct local_symbol *) s);
235860484Sobrien  return &s->sy_value;
235960484Sobrien}
236060484Sobrien
236160484Sobrien/* Set the value of a symbol to an expression.  */
236260484Sobrien
236333965Sjdpvoid
2364130561Sobriensymbol_set_value_expression (symbolS *s, const expressionS *exp)
236560484Sobrien{
236660484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
236760484Sobrien    s = local_symbol_convert ((struct local_symbol *) s);
236860484Sobrien  s->sy_value = *exp;
2369218822Sdim  S_CLEAR_WEAKREFR (s);
237060484Sobrien}
237160484Sobrien
2372218822Sdim/* Return a pointer to the X_add_number component of a symbol.  */
2373218822Sdim
2374218822SdimoffsetT *
2375218822Sdimsymbol_X_add_number (symbolS *s)
2376218822Sdim{
2377218822Sdim  if (LOCAL_SYMBOL_CHECK (s))
2378218822Sdim    return (offsetT *) &((struct local_symbol *) s)->lsy_value;
2379218822Sdim
2380218822Sdim  return &s->sy_value.X_add_number;
2381218822Sdim}
2382218822Sdim
2383130561Sobrien/* Set the value of SYM to the current position in the current segment.  */
2384130561Sobrien
2385130561Sobrienvoid
2386130561Sobriensymbol_set_value_now (symbolS *sym)
2387130561Sobrien{
2388130561Sobrien  S_SET_SEGMENT (sym, now_seg);
2389130561Sobrien  S_SET_VALUE (sym, frag_now_fix ());
2390130561Sobrien  symbol_set_frag (sym, frag_now);
2391130561Sobrien}
2392130561Sobrien
239360484Sobrien/* Set the frag of a symbol.  */
239460484Sobrien
239560484Sobrienvoid
2396130561Sobriensymbol_set_frag (symbolS *s, fragS *f)
239760484Sobrien{
239860484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
239960484Sobrien    {
240060484Sobrien      local_symbol_set_frag ((struct local_symbol *) s, f);
240160484Sobrien      return;
240260484Sobrien    }
240360484Sobrien  s->sy_frag = f;
2404218822Sdim  S_CLEAR_WEAKREFR (s);
240560484Sobrien}
240660484Sobrien
240760484Sobrien/* Return the frag of a symbol.  */
240860484Sobrien
240960484SobrienfragS *
2410130561Sobriensymbol_get_frag (symbolS *s)
241160484Sobrien{
241260484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
241360484Sobrien    return local_symbol_get_frag ((struct local_symbol *) s);
241460484Sobrien  return s->sy_frag;
241560484Sobrien}
241660484Sobrien
241760484Sobrien/* Mark a symbol as having been used.  */
241860484Sobrien
241960484Sobrienvoid
2420130561Sobriensymbol_mark_used (symbolS *s)
242160484Sobrien{
242260484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
242360484Sobrien    return;
242460484Sobrien  s->sy_used = 1;
2425218822Sdim  if (S_IS_WEAKREFR (s))
2426218822Sdim    symbol_mark_used (s->sy_value.X_add_symbol);
242760484Sobrien}
242860484Sobrien
242960484Sobrien/* Clear the mark of whether a symbol has been used.  */
243060484Sobrien
243160484Sobrienvoid
2432130561Sobriensymbol_clear_used (symbolS *s)
243360484Sobrien{
243460484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
243560484Sobrien    s = local_symbol_convert ((struct local_symbol *) s);
243660484Sobrien  s->sy_used = 0;
243760484Sobrien}
243860484Sobrien
243960484Sobrien/* Return whether a symbol has been used.  */
244060484Sobrien
244160484Sobrienint
2442130561Sobriensymbol_used_p (symbolS *s)
244360484Sobrien{
244460484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
244560484Sobrien    return 1;
244660484Sobrien  return s->sy_used;
244760484Sobrien}
244860484Sobrien
244960484Sobrien/* Mark a symbol as having been used in a reloc.  */
245060484Sobrien
245160484Sobrienvoid
2452130561Sobriensymbol_mark_used_in_reloc (symbolS *s)
245360484Sobrien{
245460484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
245560484Sobrien    s = local_symbol_convert ((struct local_symbol *) s);
245660484Sobrien  s->sy_used_in_reloc = 1;
245760484Sobrien}
245860484Sobrien
245960484Sobrien/* Clear the mark of whether a symbol has been used in a reloc.  */
246060484Sobrien
246160484Sobrienvoid
2462130561Sobriensymbol_clear_used_in_reloc (symbolS *s)
246360484Sobrien{
246460484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
246560484Sobrien    return;
246660484Sobrien  s->sy_used_in_reloc = 0;
246760484Sobrien}
246860484Sobrien
246960484Sobrien/* Return whether a symbol has been used in a reloc.  */
247060484Sobrien
247160484Sobrienint
2472130561Sobriensymbol_used_in_reloc_p (symbolS *s)
247360484Sobrien{
247460484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
247560484Sobrien    return 0;
247660484Sobrien  return s->sy_used_in_reloc;
247760484Sobrien}
247860484Sobrien
247960484Sobrien/* Mark a symbol as an MRI common symbol.  */
248060484Sobrien
248160484Sobrienvoid
2482130561Sobriensymbol_mark_mri_common (symbolS *s)
248360484Sobrien{
248460484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
248560484Sobrien    s = local_symbol_convert ((struct local_symbol *) s);
248660484Sobrien  s->sy_mri_common = 1;
248760484Sobrien}
248860484Sobrien
248960484Sobrien/* Clear the mark of whether a symbol is an MRI common symbol.  */
249060484Sobrien
249160484Sobrienvoid
2492130561Sobriensymbol_clear_mri_common (symbolS *s)
249360484Sobrien{
249460484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
249560484Sobrien    return;
249660484Sobrien  s->sy_mri_common = 0;
249760484Sobrien}
249860484Sobrien
249960484Sobrien/* Return whether a symbol is an MRI common symbol.  */
250060484Sobrien
250160484Sobrienint
2502130561Sobriensymbol_mri_common_p (symbolS *s)
250360484Sobrien{
250460484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
250560484Sobrien    return 0;
250660484Sobrien  return s->sy_mri_common;
250760484Sobrien}
250860484Sobrien
250960484Sobrien/* Mark a symbol as having been written.  */
251060484Sobrien
251160484Sobrienvoid
2512130561Sobriensymbol_mark_written (symbolS *s)
251360484Sobrien{
251460484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
251560484Sobrien    return;
251660484Sobrien  s->written = 1;
251760484Sobrien}
251860484Sobrien
251960484Sobrien/* Clear the mark of whether a symbol has been written.  */
252060484Sobrien
252160484Sobrienvoid
2522130561Sobriensymbol_clear_written (symbolS *s)
252360484Sobrien{
252460484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
252560484Sobrien    return;
252660484Sobrien  s->written = 0;
252760484Sobrien}
252860484Sobrien
252960484Sobrien/* Return whether a symbol has been written.  */
253060484Sobrien
253160484Sobrienint
2532130561Sobriensymbol_written_p (symbolS *s)
253360484Sobrien{
253460484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
253560484Sobrien    return 0;
253660484Sobrien  return s->written;
253760484Sobrien}
253860484Sobrien
253960484Sobrien/* Mark a symbol has having been resolved.  */
254060484Sobrien
254160484Sobrienvoid
2542130561Sobriensymbol_mark_resolved (symbolS *s)
254360484Sobrien{
254460484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
254560484Sobrien    {
254660484Sobrien      local_symbol_mark_resolved ((struct local_symbol *) s);
254760484Sobrien      return;
254860484Sobrien    }
254960484Sobrien  s->sy_resolved = 1;
255060484Sobrien}
255160484Sobrien
255260484Sobrien/* Return whether a symbol has been resolved.  */
255360484Sobrien
255460484Sobrienint
2555130561Sobriensymbol_resolved_p (symbolS *s)
255660484Sobrien{
255760484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
255860484Sobrien    return local_symbol_resolved_p ((struct local_symbol *) s);
255960484Sobrien  return s->sy_resolved;
256060484Sobrien}
256160484Sobrien
256260484Sobrien/* Return whether a symbol is a section symbol.  */
256360484Sobrien
256460484Sobrienint
2565130561Sobriensymbol_section_p (symbolS *s ATTRIBUTE_UNUSED)
256660484Sobrien{
256760484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
256860484Sobrien    return 0;
256960484Sobrien  return (s->bsym->flags & BSF_SECTION_SYM) != 0;
257060484Sobrien}
257160484Sobrien
257260484Sobrien/* Return whether a symbol is equated to another symbol.  */
257360484Sobrien
257460484Sobrienint
2575130561Sobriensymbol_equated_p (symbolS *s)
257660484Sobrien{
257760484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
257860484Sobrien    return 0;
257960484Sobrien  return s->sy_value.X_op == O_symbol;
258060484Sobrien}
258160484Sobrien
258289857Sobrien/* Return whether a symbol is equated to another symbol, and should be
258389857Sobrien   treated specially when writing out relocs.  */
258489857Sobrien
258589857Sobrienint
2586130561Sobriensymbol_equated_reloc_p (symbolS *s)
258789857Sobrien{
258889857Sobrien  if (LOCAL_SYMBOL_CHECK (s))
258989857Sobrien    return 0;
259089857Sobrien  /* X_op_symbol, normally not used for O_symbol, is set by
259189857Sobrien     resolve_symbol_value to flag expression syms that have been
259289857Sobrien     equated.  */
259389857Sobrien  return (s->sy_value.X_op == O_symbol
2594218822Sdim#if defined (OBJ_COFF) && defined (TE_PE)
2595218822Sdim	  && ! S_IS_WEAK (s)
2596218822Sdim#endif
259789857Sobrien	  && ((s->sy_resolved && s->sy_value.X_op_symbol != NULL)
259889857Sobrien	      || ! S_IS_DEFINED (s)
259989857Sobrien	      || S_IS_COMMON (s)));
260089857Sobrien}
260189857Sobrien
260260484Sobrien/* Return whether a symbol has a constant value.  */
260360484Sobrien
260460484Sobrienint
2605130561Sobriensymbol_constant_p (symbolS *s)
260660484Sobrien{
260760484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
260860484Sobrien    return 1;
260960484Sobrien  return s->sy_value.X_op == O_constant;
261060484Sobrien}
261160484Sobrien
2612218822Sdim/* Return whether a symbol was cloned and thus removed from the global
2613218822Sdim   symbol list.  */
261460484Sobrien
2615218822Sdimint
2616218822Sdimsymbol_shadow_p (symbolS *s)
2617218822Sdim{
2618218822Sdim  if (LOCAL_SYMBOL_CHECK (s))
2619218822Sdim    return 0;
2620218822Sdim  return s->sy_next == s;
2621218822Sdim}
2622218822Sdim
262360484Sobrien/* Return the BFD symbol for a symbol.  */
262460484Sobrien
262560484Sobrienasymbol *
2626130561Sobriensymbol_get_bfdsym (symbolS *s)
262760484Sobrien{
262860484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
262960484Sobrien    s = local_symbol_convert ((struct local_symbol *) s);
263060484Sobrien  return s->bsym;
263160484Sobrien}
263260484Sobrien
263360484Sobrien/* Set the BFD symbol for a symbol.  */
263460484Sobrien
263560484Sobrienvoid
2636130561Sobriensymbol_set_bfdsym (symbolS *s, asymbol *bsym)
263760484Sobrien{
263860484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
263960484Sobrien    s = local_symbol_convert ((struct local_symbol *) s);
2640218822Sdim  /* Usually, it is harmless to reset a symbol to a BFD section
2641218822Sdim     symbol. For example, obj_elf_change_section sets the BFD symbol
2642218822Sdim     of an old symbol with the newly created section symbol. But when
2643218822Sdim     we have multiple sections with the same name, the newly created
2644218822Sdim     section may have the same name as an old section. We check if the
2645218822Sdim     old symbol has been already marked as a section symbol before
2646218822Sdim     resetting it.  */
2647218822Sdim  if ((s->bsym->flags & BSF_SECTION_SYM) == 0)
2648218822Sdim    s->bsym = bsym;
2649218822Sdim  /* else XXX - What do we do now ?  */
265060484Sobrien}
265160484Sobrien
265260484Sobrien#ifdef OBJ_SYMFIELD_TYPE
265360484Sobrien
265460484Sobrien/* Get a pointer to the object format information for a symbol.  */
265560484Sobrien
265660484SobrienOBJ_SYMFIELD_TYPE *
2657130561Sobriensymbol_get_obj (symbolS *s)
265860484Sobrien{
265960484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
266060484Sobrien    s = local_symbol_convert ((struct local_symbol *) s);
266160484Sobrien  return &s->sy_obj;
266260484Sobrien}
266360484Sobrien
266460484Sobrien/* Set the object format information for a symbol.  */
266560484Sobrien
266660484Sobrienvoid
2667130561Sobriensymbol_set_obj (symbolS *s, OBJ_SYMFIELD_TYPE *o)
266860484Sobrien{
266960484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
267060484Sobrien    s = local_symbol_convert ((struct local_symbol *) s);
267160484Sobrien  s->sy_obj = *o;
267260484Sobrien}
267360484Sobrien
267460484Sobrien#endif /* OBJ_SYMFIELD_TYPE */
267560484Sobrien
267660484Sobrien#ifdef TC_SYMFIELD_TYPE
267760484Sobrien
267860484Sobrien/* Get a pointer to the processor information for a symbol.  */
267960484Sobrien
268060484SobrienTC_SYMFIELD_TYPE *
2681130561Sobriensymbol_get_tc (symbolS *s)
268260484Sobrien{
268360484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
268460484Sobrien    s = local_symbol_convert ((struct local_symbol *) s);
268560484Sobrien  return &s->sy_tc;
268660484Sobrien}
268760484Sobrien
268860484Sobrien/* Set the processor information for a symbol.  */
268960484Sobrien
269060484Sobrienvoid
2691130561Sobriensymbol_set_tc (symbolS *s, TC_SYMFIELD_TYPE *o)
269260484Sobrien{
269360484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
269460484Sobrien    s = local_symbol_convert ((struct local_symbol *) s);
269560484Sobrien  s->sy_tc = *o;
269660484Sobrien}
269760484Sobrien
269860484Sobrien#endif /* TC_SYMFIELD_TYPE */
269960484Sobrien
270060484Sobrienvoid
2701130561Sobriensymbol_begin (void)
270233965Sjdp{
270333965Sjdp  symbol_lastP = NULL;
270477298Sobrien  symbol_rootP = NULL;		/* In case we have 0 symbols (!!)  */
270533965Sjdp  sy_hash = hash_new ();
270660484Sobrien  local_hash = hash_new ();
270733965Sjdp
270833965Sjdp  memset ((char *) (&abs_symbol), '\0', sizeof (abs_symbol));
270933965Sjdp#if defined (EMIT_SECTION_SYMBOLS) || !defined (RELOC_REQUIRES_SYMBOL)
271033965Sjdp  abs_symbol.bsym = bfd_abs_section.symbol;
271133965Sjdp#endif
271233965Sjdp  abs_symbol.sy_value.X_op = O_constant;
271333965Sjdp  abs_symbol.sy_frag = &zero_address_frag;
271433965Sjdp
271533965Sjdp  if (LOCAL_LABELS_FB)
271633965Sjdp    fb_label_init ();
271733965Sjdp}
271833965Sjdp
271933965Sjdpint indent_level;
272033965Sjdp
272160484Sobrien/* Maximum indent level.
272260484Sobrien   Available for modification inside a gdb session.  */
2723218822Sdimstatic int max_indent_level = 8;
272460484Sobrien
272533965Sjdpvoid
2726130561Sobrienprint_symbol_value_1 (FILE *file, symbolS *sym)
272733965Sjdp{
272833965Sjdp  const char *name = S_GET_NAME (sym);
272933965Sjdp  if (!name || !name[0])
273033965Sjdp    name = "(unnamed)";
273133965Sjdp  fprintf (file, "sym %lx %s", (unsigned long) sym, name);
273260484Sobrien
273360484Sobrien  if (LOCAL_SYMBOL_CHECK (sym))
273460484Sobrien    {
273560484Sobrien      struct local_symbol *locsym = (struct local_symbol *) sym;
273660484Sobrien      if (local_symbol_get_frag (locsym) != &zero_address_frag
273760484Sobrien	  && local_symbol_get_frag (locsym) != NULL)
273860484Sobrien	fprintf (file, " frag %lx", (long) local_symbol_get_frag (locsym));
273960484Sobrien      if (local_symbol_resolved_p (locsym))
274060484Sobrien	fprintf (file, " resolved");
274160484Sobrien      fprintf (file, " local");
274260484Sobrien    }
274360484Sobrien  else
274460484Sobrien    {
274560484Sobrien      if (sym->sy_frag != &zero_address_frag)
274660484Sobrien	fprintf (file, " frag %lx", (long) sym->sy_frag);
274760484Sobrien      if (sym->written)
274860484Sobrien	fprintf (file, " written");
274960484Sobrien      if (sym->sy_resolved)
275060484Sobrien	fprintf (file, " resolved");
275160484Sobrien      else if (sym->sy_resolving)
275260484Sobrien	fprintf (file, " resolving");
275360484Sobrien      if (sym->sy_used_in_reloc)
275460484Sobrien	fprintf (file, " used-in-reloc");
275560484Sobrien      if (sym->sy_used)
275660484Sobrien	fprintf (file, " used");
275760484Sobrien      if (S_IS_LOCAL (sym))
275860484Sobrien	fprintf (file, " local");
2759218822Sdim      if (S_IS_EXTERNAL (sym))
276060484Sobrien	fprintf (file, " extern");
2761218822Sdim      if (S_IS_WEAK (sym))
2762218822Sdim	fprintf (file, " weak");
276360484Sobrien      if (S_IS_DEBUG (sym))
276460484Sobrien	fprintf (file, " debug");
276560484Sobrien      if (S_IS_DEFINED (sym))
276660484Sobrien	fprintf (file, " defined");
276760484Sobrien    }
2768218822Sdim  if (S_IS_WEAKREFR (sym))
2769218822Sdim    fprintf (file, " weakrefr");
2770218822Sdim  if (S_IS_WEAKREFD (sym))
2771218822Sdim    fprintf (file, " weakrefd");
277233965Sjdp  fprintf (file, " %s", segment_name (S_GET_SEGMENT (sym)));
277360484Sobrien  if (symbol_resolved_p (sym))
277433965Sjdp    {
277533965Sjdp      segT s = S_GET_SEGMENT (sym);
277633965Sjdp
277733965Sjdp      if (s != undefined_section
2778104834Sobrien	  && s != expr_section)
277933965Sjdp	fprintf (file, " %lx", (long) S_GET_VALUE (sym));
278033965Sjdp    }
278160484Sobrien  else if (indent_level < max_indent_level
278260484Sobrien	   && S_GET_SEGMENT (sym) != undefined_section)
278333965Sjdp    {
278433965Sjdp      indent_level++;
278533965Sjdp      fprintf (file, "\n%*s<", indent_level * 4, "");
278660484Sobrien      if (LOCAL_SYMBOL_CHECK (sym))
278760484Sobrien	fprintf (file, "constant %lx",
278889857Sobrien		 (long) ((struct local_symbol *) sym)->lsy_value);
278960484Sobrien      else
279060484Sobrien	print_expr_1 (file, &sym->sy_value);
279133965Sjdp      fprintf (file, ">");
279233965Sjdp      indent_level--;
279333965Sjdp    }
279433965Sjdp  fflush (file);
279533965Sjdp}
279633965Sjdp
279733965Sjdpvoid
2798130561Sobrienprint_symbol_value (symbolS *sym)
279933965Sjdp{
280033965Sjdp  indent_level = 0;
280133965Sjdp  print_symbol_value_1 (stderr, sym);
280233965Sjdp  fprintf (stderr, "\n");
280333965Sjdp}
280433965Sjdp
280560484Sobrienstatic void
2806130561Sobrienprint_binary (FILE *file, const char *name, expressionS *exp)
280760484Sobrien{
280860484Sobrien  indent_level++;
280960484Sobrien  fprintf (file, "%s\n%*s<", name, indent_level * 4, "");
281060484Sobrien  print_symbol_value_1 (file, exp->X_add_symbol);
281160484Sobrien  fprintf (file, ">\n%*s<", indent_level * 4, "");
281260484Sobrien  print_symbol_value_1 (file, exp->X_op_symbol);
281360484Sobrien  fprintf (file, ">");
281460484Sobrien  indent_level--;
281560484Sobrien}
281660484Sobrien
281733965Sjdpvoid
2818130561Sobrienprint_expr_1 (FILE *file, expressionS *exp)
281933965Sjdp{
282033965Sjdp  fprintf (file, "expr %lx ", (long) exp);
282133965Sjdp  switch (exp->X_op)
282233965Sjdp    {
282333965Sjdp    case O_illegal:
282433965Sjdp      fprintf (file, "illegal");
282533965Sjdp      break;
282633965Sjdp    case O_absent:
282733965Sjdp      fprintf (file, "absent");
282833965Sjdp      break;
282933965Sjdp    case O_constant:
283033965Sjdp      fprintf (file, "constant %lx", (long) exp->X_add_number);
283133965Sjdp      break;
283233965Sjdp    case O_symbol:
283333965Sjdp      indent_level++;
283433965Sjdp      fprintf (file, "symbol\n%*s<", indent_level * 4, "");
283533965Sjdp      print_symbol_value_1 (file, exp->X_add_symbol);
283633965Sjdp      fprintf (file, ">");
283733965Sjdp    maybe_print_addnum:
283833965Sjdp      if (exp->X_add_number)
283933965Sjdp	fprintf (file, "\n%*s%lx", indent_level * 4, "",
284033965Sjdp		 (long) exp->X_add_number);
284133965Sjdp      indent_level--;
284233965Sjdp      break;
284333965Sjdp    case O_register:
284433965Sjdp      fprintf (file, "register #%d", (int) exp->X_add_number);
284533965Sjdp      break;
284633965Sjdp    case O_big:
284733965Sjdp      fprintf (file, "big");
284833965Sjdp      break;
284933965Sjdp    case O_uminus:
285033965Sjdp      fprintf (file, "uminus -<");
285133965Sjdp      indent_level++;
285233965Sjdp      print_symbol_value_1 (file, exp->X_add_symbol);
285333965Sjdp      fprintf (file, ">");
285433965Sjdp      goto maybe_print_addnum;
285533965Sjdp    case O_bit_not:
285633965Sjdp      fprintf (file, "bit_not");
285733965Sjdp      break;
285833965Sjdp    case O_multiply:
285960484Sobrien      print_binary (file, "multiply", exp);
286033965Sjdp      break;
286133965Sjdp    case O_divide:
286260484Sobrien      print_binary (file, "divide", exp);
286333965Sjdp      break;
286433965Sjdp    case O_modulus:
286560484Sobrien      print_binary (file, "modulus", exp);
286633965Sjdp      break;
286733965Sjdp    case O_left_shift:
286860484Sobrien      print_binary (file, "lshift", exp);
286933965Sjdp      break;
287033965Sjdp    case O_right_shift:
287160484Sobrien      print_binary (file, "rshift", exp);
287233965Sjdp      break;
287333965Sjdp    case O_bit_inclusive_or:
287460484Sobrien      print_binary (file, "bit_ior", exp);
287533965Sjdp      break;
287633965Sjdp    case O_bit_exclusive_or:
287760484Sobrien      print_binary (file, "bit_xor", exp);
287833965Sjdp      break;
287933965Sjdp    case O_bit_and:
288060484Sobrien      print_binary (file, "bit_and", exp);
288133965Sjdp      break;
288233965Sjdp    case O_eq:
288360484Sobrien      print_binary (file, "eq", exp);
288433965Sjdp      break;
288533965Sjdp    case O_ne:
288660484Sobrien      print_binary (file, "ne", exp);
288733965Sjdp      break;
288833965Sjdp    case O_lt:
288960484Sobrien      print_binary (file, "lt", exp);
289033965Sjdp      break;
289133965Sjdp    case O_le:
289260484Sobrien      print_binary (file, "le", exp);
289333965Sjdp      break;
289433965Sjdp    case O_ge:
289560484Sobrien      print_binary (file, "ge", exp);
289633965Sjdp      break;
289733965Sjdp    case O_gt:
289860484Sobrien      print_binary (file, "gt", exp);
289933965Sjdp      break;
290033965Sjdp    case O_logical_and:
290160484Sobrien      print_binary (file, "logical_and", exp);
290233965Sjdp      break;
290333965Sjdp    case O_logical_or:
290460484Sobrien      print_binary (file, "logical_or", exp);
290533965Sjdp      break;
290633965Sjdp    case O_add:
290733965Sjdp      indent_level++;
290833965Sjdp      fprintf (file, "add\n%*s<", indent_level * 4, "");
290933965Sjdp      print_symbol_value_1 (file, exp->X_add_symbol);
291033965Sjdp      fprintf (file, ">\n%*s<", indent_level * 4, "");
291133965Sjdp      print_symbol_value_1 (file, exp->X_op_symbol);
291233965Sjdp      fprintf (file, ">");
291333965Sjdp      goto maybe_print_addnum;
291433965Sjdp    case O_subtract:
291533965Sjdp      indent_level++;
291633965Sjdp      fprintf (file, "subtract\n%*s<", indent_level * 4, "");
291733965Sjdp      print_symbol_value_1 (file, exp->X_add_symbol);
291833965Sjdp      fprintf (file, ">\n%*s<", indent_level * 4, "");
291933965Sjdp      print_symbol_value_1 (file, exp->X_op_symbol);
292033965Sjdp      fprintf (file, ">");
292133965Sjdp      goto maybe_print_addnum;
292233965Sjdp    default:
292333965Sjdp      fprintf (file, "{unknown opcode %d}", (int) exp->X_op);
292433965Sjdp      break;
292533965Sjdp    }
292633965Sjdp  fflush (stdout);
292733965Sjdp}
292833965Sjdp
292933965Sjdpvoid
2930130561Sobrienprint_expr (expressionS *exp)
293133965Sjdp{
293233965Sjdp  print_expr_1 (stderr, exp);
293333965Sjdp  fprintf (stderr, "\n");
293433965Sjdp}
293533965Sjdp
293633965Sjdpvoid
2937130561Sobriensymbol_print_statistics (FILE *file)
293833965Sjdp{
293933965Sjdp  hash_print_statistics (file, "symbol table", sy_hash);
294060484Sobrien  hash_print_statistics (file, "mini local symbol table", local_hash);
294160484Sobrien  fprintf (file, "%lu mini local symbols created, %lu converted\n",
294260484Sobrien	   local_symbol_count, local_symbol_conversion_count);
2943218822Sdim}
2944218822Sdim
2945218822Sdim#ifdef OBJ_COMPLEX_RELC
2946218822Sdim
2947218822Sdim/* Convert given symbol to a new complex-relocation symbol name.  This
2948218822Sdim   may be a recursive function, since it might be called for non-leaf
2949218822Sdim   nodes (plain symbols) in the expression tree.  The caller owns the
2950218822Sdim   returning string, so should free it eventually.  Errors are
2951218822Sdim   indicated via as_bad and a NULL return value.  The given symbol
2952218822Sdim   is marked with sy_used_in_reloc.  */
2953218822Sdim
2954218822Sdimchar *
2955218822Sdimsymbol_relc_make_sym (symbolS * sym)
2956218822Sdim{
2957218822Sdim  char * terminal = NULL;
2958218822Sdim  const char * sname;
2959218822Sdim  char typetag;
2960218822Sdim  int sname_len;
2961218822Sdim
2962218822Sdim  assert (sym != NULL);
2963218822Sdim
2964218822Sdim  /* Recurse to symbol_relc_make_expr if this symbol
2965218822Sdim     is defined as an expression or a plain value.  */
2966218822Sdim  if (   S_GET_SEGMENT (sym) == expr_section
2967218822Sdim      || S_GET_SEGMENT (sym) == absolute_section)
2968218822Sdim    return symbol_relc_make_expr (& sym->sy_value);
2969218822Sdim
2970218822Sdim  /* This may be a "fake symbol" L0\001, referring to ".".
2971218822Sdim     Write out a special null symbol to refer to this position.  */
2972218822Sdim  if (! strcmp (S_GET_NAME (sym), FAKE_LABEL_NAME))
2973218822Sdim    return xstrdup (".");
2974218822Sdim
2975218822Sdim  /* We hope this is a plain leaf symbol.  Construct the encoding
2976218822Sdim     as {S,s}II...:CCCCCCC....
2977218822Sdim     where 'S'/'s' means section symbol / plain symbol
2978218822Sdim     III is decimal for the symbol name length
2979218822Sdim     CCC is the symbol name itself.  */
2980218822Sdim  symbol_mark_used_in_reloc (sym);
2981218822Sdim
2982218822Sdim  sname = S_GET_NAME (sym);
2983218822Sdim  sname_len = strlen (sname);
2984218822Sdim  typetag = symbol_section_p (sym) ? 'S' : 's';
2985218822Sdim
2986218822Sdim  terminal = xmalloc (1 /* S or s */
2987218822Sdim		      + 8 /* sname_len in decimal */
2988218822Sdim		      + 1 /* _ spacer */
2989218822Sdim		      + sname_len /* name itself */
2990218822Sdim		      + 1 /* \0 */ );
2991218822Sdim
2992218822Sdim  sprintf (terminal, "%c%d:%s", typetag, sname_len, sname);
2993218822Sdim  return terminal;
2994218822Sdim}
2995218822Sdim
2996218822Sdim/* Convert given value to a new complex-relocation symbol name.  This
2997218822Sdim   is a non-recursive function, since it is be called for leaf nodes
2998218822Sdim   (plain values) in the expression tree.  The caller owns the
2999218822Sdim   returning string, so should free() it eventually.  No errors.  */
3000218822Sdim
3001218822Sdimchar *
3002218822Sdimsymbol_relc_make_value (offsetT val)
3003218822Sdim{
3004218822Sdim  char * terminal = xmalloc (28);  /* Enough for long long.  */
3005218822Sdim
3006218822Sdim  terminal[0] = '#';
3007218822Sdim  sprintf_vma (& terminal[1], val);
3008218822Sdim  return terminal;
3009218822Sdim}
3010218822Sdim
3011218822Sdim/* Convert given expression to a new complex-relocation symbol name.
3012218822Sdim   This is a recursive function, since it traverses the entire given
3013218822Sdim   expression tree.  The caller owns the returning string, so should
3014218822Sdim   free() it eventually.  Errors are indicated via as_bad() and a NULL
3015218822Sdim   return value.  */
3016218822Sdim
3017218822Sdimchar *
3018218822Sdimsymbol_relc_make_expr (expressionS * exp)
3019218822Sdim{
3020218822Sdim  char * opstr = NULL; /* Operator prefix string.  */
3021218822Sdim  int    arity = 0;    /* Arity of this operator.  */
3022218822Sdim  char * operands[3];  /* Up to three operands.  */
3023218822Sdim  char * concat_string = NULL;
3024218822Sdim
3025218822Sdim  operands[0] = operands[1] = operands[2] = NULL;
3026218822Sdim
3027218822Sdim  assert (exp != NULL);
3028218822Sdim
3029218822Sdim  /* Match known operators -> fill in opstr, arity, operands[] and fall
3030218822Sdim     through to construct subexpression fragments; may instead return
3031218822Sdim     string directly for leaf nodes.  */
3032218822Sdim
3033218822Sdim  /* See expr.h for the meaning of all these enums.  Many operators
3034218822Sdim     have an unnatural arity (X_add_number implicitly added).  The
3035218822Sdim     conversion logic expands them to explicit "+" subexpressions.   */
3036218822Sdim
3037218822Sdim  switch (exp->X_op)
3038218822Sdim    {
3039218822Sdim    default:
3040218822Sdim      as_bad ("Unknown expression operator (enum %d)", exp->X_op);
3041218822Sdim      break;
3042218822Sdim
3043218822Sdim      /* Leaf nodes.  */
3044218822Sdim    case O_constant:
3045218822Sdim      return symbol_relc_make_value (exp->X_add_number);
3046218822Sdim
3047218822Sdim    case O_symbol:
3048218822Sdim      if (exp->X_add_number)
3049218822Sdim	{
3050218822Sdim	  arity = 2;
3051218822Sdim	  opstr = "+";
3052218822Sdim	  operands[0] = symbol_relc_make_sym (exp->X_add_symbol);
3053218822Sdim	  operands[1] = symbol_relc_make_value (exp->X_add_number);
3054218822Sdim	  break;
3055218822Sdim	}
3056218822Sdim      else
3057218822Sdim	return symbol_relc_make_sym (exp->X_add_symbol);
3058218822Sdim
3059218822Sdim      /* Helper macros for nesting nodes.  */
3060218822Sdim
3061218822Sdim#define HANDLE_XADD_OPT1(str_) 						\
3062218822Sdim      if (exp->X_add_number)						\
3063218822Sdim        {								\
3064218822Sdim          arity = 2;							\
3065218822Sdim          opstr = "+:" str_;						\
3066218822Sdim          operands[0] = symbol_relc_make_sym (exp->X_add_symbol);	\
3067218822Sdim          operands[1] = symbol_relc_make_value (exp->X_add_number);	\
3068218822Sdim          break;							\
3069218822Sdim        }								\
3070218822Sdim      else								\
3071218822Sdim        {								\
3072218822Sdim          arity = 1;							\
3073218822Sdim          opstr = str_;							\
3074218822Sdim          operands[0] = symbol_relc_make_sym (exp->X_add_symbol);	\
3075218822Sdim        }								\
3076218822Sdim      break
3077218822Sdim
3078218822Sdim#define HANDLE_XADD_OPT2(str_) 						\
3079218822Sdim      if (exp->X_add_number)						\
3080218822Sdim        {								\
3081218822Sdim          arity = 3;							\
3082218822Sdim          opstr = "+:" str_;						\
3083218822Sdim          operands[0] = symbol_relc_make_sym (exp->X_add_symbol);	\
3084218822Sdim          operands[1] = symbol_relc_make_sym (exp->X_op_symbol);	\
3085218822Sdim          operands[2] = symbol_relc_make_value (exp->X_add_number);	\
3086218822Sdim        }								\
3087218822Sdim      else								\
3088218822Sdim        {								\
3089218822Sdim          arity = 2;							\
3090218822Sdim          opstr = str_;							\
3091218822Sdim          operands[0] = symbol_relc_make_sym (exp->X_add_symbol);	\
3092218822Sdim          operands[1] = symbol_relc_make_sym (exp->X_op_symbol);	\
3093218822Sdim        } 								\
3094218822Sdim      break
3095218822Sdim
3096218822Sdim      /* Nesting nodes.  */
3097218822Sdim
3098218822Sdim    case O_uminus:       	HANDLE_XADD_OPT1 ("0-");
3099218822Sdim    case O_bit_not:      	HANDLE_XADD_OPT1 ("~");
3100218822Sdim    case O_logical_not:  	HANDLE_XADD_OPT1 ("!");
3101218822Sdim    case O_multiply:     	HANDLE_XADD_OPT2 ("*");
3102218822Sdim    case O_divide:       	HANDLE_XADD_OPT2 ("/");
3103218822Sdim    case O_modulus:      	HANDLE_XADD_OPT2 ("%");
3104218822Sdim    case O_left_shift:   	HANDLE_XADD_OPT2 ("<<");
3105218822Sdim    case O_right_shift:  	HANDLE_XADD_OPT2 (">>");
3106218822Sdim    case O_bit_inclusive_or:	HANDLE_XADD_OPT2 ("|");
3107218822Sdim    case O_bit_exclusive_or:	HANDLE_XADD_OPT2 ("^");
3108218822Sdim    case O_bit_and:      	HANDLE_XADD_OPT2 ("&");
3109218822Sdim    case O_add:          	HANDLE_XADD_OPT2 ("+");
3110218822Sdim    case O_subtract:     	HANDLE_XADD_OPT2 ("-");
3111218822Sdim    case O_eq:           	HANDLE_XADD_OPT2 ("==");
3112218822Sdim    case O_ne:           	HANDLE_XADD_OPT2 ("!=");
3113218822Sdim    case O_lt:           	HANDLE_XADD_OPT2 ("<");
3114218822Sdim    case O_le:           	HANDLE_XADD_OPT2 ("<=");
3115218822Sdim    case O_ge:           	HANDLE_XADD_OPT2 (">=");
3116218822Sdim    case O_gt:           	HANDLE_XADD_OPT2 (">");
3117218822Sdim    case O_logical_and:  	HANDLE_XADD_OPT2 ("&&");
3118218822Sdim    case O_logical_or:   	HANDLE_XADD_OPT2 ("||");
3119218822Sdim    }
3120218822Sdim
3121218822Sdim  /* Validate & reject early.  */
3122218822Sdim  if (arity >= 1 && ((operands[0] == NULL) || (strlen (operands[0]) == 0)))
3123218822Sdim    opstr = NULL;
3124218822Sdim  if (arity >= 2 && ((operands[1] == NULL) || (strlen (operands[1]) == 0)))
3125218822Sdim    opstr = NULL;
3126218822Sdim  if (arity >= 3 && ((operands[2] == NULL) || (strlen (operands[2]) == 0)))
3127218822Sdim    opstr = NULL;
3128218822Sdim
3129218822Sdim  if (opstr == NULL)
3130218822Sdim    concat_string = NULL;
3131218822Sdim  else
3132218822Sdim    {
3133218822Sdim      /* Allocate new string; include inter-operand padding gaps etc.  */
3134218822Sdim      concat_string = xmalloc (strlen (opstr)
3135218822Sdim			       + 1
3136218822Sdim			       + (arity >= 1 ? (strlen (operands[0]) + 1 ) : 0)
3137218822Sdim			       + (arity >= 2 ? (strlen (operands[1]) + 1 ) : 0)
3138218822Sdim			       + (arity >= 3 ? (strlen (operands[2]) + 0 ) : 0)
3139218822Sdim			       + 1);
3140218822Sdim      assert (concat_string != NULL);
3141218822Sdim
3142218822Sdim      /* Format the thing.  */
3143218822Sdim      sprintf (concat_string,
3144218822Sdim	       (arity == 0 ? "%s" :
3145218822Sdim		arity == 1 ? "%s:%s" :
3146218822Sdim		arity == 2 ? "%s:%s:%s" :
3147218822Sdim		/* arity == 3 */ "%s:%s:%s:%s"),
3148218822Sdim	       opstr, operands[0], operands[1], operands[2]);
3149218822Sdim    }
3150218822Sdim
3151218822Sdim  /* Free operand strings (not opstr).  */
3152218822Sdim  if (arity >= 1) xfree (operands[0]);
3153218822Sdim  if (arity >= 2) xfree (operands[1]);
3154218822Sdim  if (arity >= 3) xfree (operands[2]);
3155218822Sdim
3156218822Sdim  return concat_string;
3157218822Sdim}
3158218822Sdim
315960484Sobrien#endif
3160