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    }
1669257360Ssbruno  while ((*p++ = *--q) != '\0')
1670257360Ssbruno	;;
167133965Sjdp
167277298Sobrien  /* The label, as a '\0' ended string, starts at symbol_name_build.  */
167333965Sjdp  return symbol_name_build;
167433965Sjdp}
167533965Sjdp
1676130561Sobrien/* Somebody else's idea of local labels. They are made by "n:" where n
167777298Sobrien   is any decimal digit. Refer to them with
167877298Sobrien    "nb" for previous (backward) n:
167977298Sobrien   or "nf" for next (forward) n:.
168033965Sjdp
168177298Sobrien   We do a little better and let n be any number, not just a single digit, but
168277298Sobrien   since the other guy's assembler only does ten, we treat the first ten
168377298Sobrien   specially.
168477298Sobrien
168577298Sobrien   Like someone else's assembler, we have one set of local label counters for
168677298Sobrien   entire assembly, not one set per (sub)segment like in most assemblers. This
168777298Sobrien   implies that one can refer to a label in another segment, and indeed some
168877298Sobrien   crufty compilers have done just that.
168977298Sobrien
169077298Sobrien   Since there could be a LOT of these things, treat them as a sparse
169177298Sobrien   array.  */
169277298Sobrien
169333965Sjdp#define FB_LABEL_SPECIAL (10)
169433965Sjdp
169533965Sjdpstatic long fb_low_counter[FB_LABEL_SPECIAL];
169633965Sjdpstatic long *fb_labels;
169733965Sjdpstatic long *fb_label_instances;
169833965Sjdpstatic long fb_label_count;
169933965Sjdpstatic long fb_label_max;
170033965Sjdp
170177298Sobrien/* This must be more than FB_LABEL_SPECIAL.  */
170233965Sjdp#define FB_LABEL_BUMP_BY (FB_LABEL_SPECIAL + 6)
170333965Sjdp
170477298Sobrienstatic void
1705130561Sobrienfb_label_init (void)
170633965Sjdp{
170733965Sjdp  memset ((void *) fb_low_counter, '\0', sizeof (fb_low_counter));
170877298Sobrien}
170933965Sjdp
171077298Sobrien/* Add one to the instance number of this fb label.  */
171177298Sobrien
171277298Sobrienvoid
1713130561Sobrienfb_label_instance_inc (long label)
171433965Sjdp{
171533965Sjdp  long *i;
171633965Sjdp
171733965Sjdp  if (label < FB_LABEL_SPECIAL)
171833965Sjdp    {
171933965Sjdp      ++fb_low_counter[label];
172033965Sjdp      return;
172133965Sjdp    }
172233965Sjdp
172333965Sjdp  if (fb_labels != NULL)
172433965Sjdp    {
172533965Sjdp      for (i = fb_labels + FB_LABEL_SPECIAL;
172633965Sjdp	   i < fb_labels + fb_label_count; ++i)
172733965Sjdp	{
172833965Sjdp	  if (*i == label)
172933965Sjdp	    {
173033965Sjdp	      ++fb_label_instances[i - fb_labels];
173133965Sjdp	      return;
173277298Sobrien	    }			/* if we find it  */
173377298Sobrien	}			/* for each existing label  */
173433965Sjdp    }
173533965Sjdp
173677298Sobrien  /* If we get to here, we don't have label listed yet.  */
173733965Sjdp
173833965Sjdp  if (fb_labels == NULL)
173933965Sjdp    {
174033965Sjdp      fb_labels = (long *) xmalloc (FB_LABEL_BUMP_BY * sizeof (long));
174133965Sjdp      fb_label_instances = (long *) xmalloc (FB_LABEL_BUMP_BY * sizeof (long));
174233965Sjdp      fb_label_max = FB_LABEL_BUMP_BY;
174333965Sjdp      fb_label_count = FB_LABEL_SPECIAL;
174433965Sjdp
174533965Sjdp    }
174633965Sjdp  else if (fb_label_count == fb_label_max)
174733965Sjdp    {
174833965Sjdp      fb_label_max += FB_LABEL_BUMP_BY;
174933965Sjdp      fb_labels = (long *) xrealloc ((char *) fb_labels,
175033965Sjdp				     fb_label_max * sizeof (long));
175133965Sjdp      fb_label_instances = (long *) xrealloc ((char *) fb_label_instances,
175233965Sjdp					      fb_label_max * sizeof (long));
175377298Sobrien    }				/* if we needed to grow  */
175433965Sjdp
175533965Sjdp  fb_labels[fb_label_count] = label;
175633965Sjdp  fb_label_instances[fb_label_count] = 1;
175733965Sjdp  ++fb_label_count;
175833965Sjdp}
175933965Sjdp
176077298Sobrienstatic long
1761130561Sobrienfb_label_instance (long label)
176233965Sjdp{
176333965Sjdp  long *i;
176433965Sjdp
176533965Sjdp  if (label < FB_LABEL_SPECIAL)
176633965Sjdp    {
176733965Sjdp      return (fb_low_counter[label]);
176833965Sjdp    }
176933965Sjdp
177033965Sjdp  if (fb_labels != NULL)
177133965Sjdp    {
177233965Sjdp      for (i = fb_labels + FB_LABEL_SPECIAL;
177333965Sjdp	   i < fb_labels + fb_label_count; ++i)
177433965Sjdp	{
177533965Sjdp	  if (*i == label)
177633965Sjdp	    {
177733965Sjdp	      return (fb_label_instances[i - fb_labels]);
177877298Sobrien	    }			/* if we find it  */
177977298Sobrien	}			/* for each existing label  */
178033965Sjdp    }
178133965Sjdp
178233965Sjdp  /* We didn't find the label, so this must be a reference to the
178333965Sjdp     first instance.  */
178433965Sjdp  return 0;
178533965Sjdp}
178633965Sjdp
178777298Sobrien/* Caller must copy returned name: we re-use the area for the next name.
178833965Sjdp
178977298Sobrien   The mth occurence of label n: is turned into the symbol "Ln^Bm"
179077298Sobrien   where n is the label number and m is the instance number. "L" makes
179177298Sobrien   it a label discarded unless debugging and "^B"('\2') ensures no
179277298Sobrien   ordinary symbol SHOULD get the same name as a local label
179377298Sobrien   symbol. The first "4:" is "L4^B1" - the m numbers begin at 1.
179477298Sobrien
179577298Sobrien   dollar labels get the same treatment, except that ^A is used in
179677298Sobrien   place of ^B.  */
179777298Sobrien
179877298Sobrienchar *				/* Return local label name.  */
1799130561Sobrienfb_label_name (long n,	/* We just saw "n:", "nf" or "nb" : n a number.  */
1800130561Sobrien	       long augend	/* 0 for nb, 1 for n:, nf.  */)
180133965Sjdp{
180233965Sjdp  long i;
180377298Sobrien  /* Returned to caller, then copied.  Used for created names ("4f").  */
180433965Sjdp  static char symbol_name_build[24];
180533965Sjdp  register char *p;
180633965Sjdp  register char *q;
180777298Sobrien  char symbol_name_temporary[20];	/* Build up a number, BACKWARDS.  */
180833965Sjdp
180933965Sjdp  know (n >= 0);
1810218822Sdim#ifdef TC_MMIX
1811218822Sdim  know ((unsigned long) augend <= 2 /* See mmix_fb_label.  */);
1812218822Sdim#else
1813218822Sdim  know ((unsigned long) augend <= 1);
1814218822Sdim#endif
181533965Sjdp  p = symbol_name_build;
181677298Sobrien#ifdef LOCAL_LABEL_PREFIX
181777298Sobrien  *p++ = LOCAL_LABEL_PREFIX;
181877298Sobrien#endif
181933965Sjdp  *p++ = 'L';
182033965Sjdp
182177298Sobrien  /* Next code just does sprintf( {}, "%d", n);  */
182277298Sobrien  /* Label number.  */
182333965Sjdp  q = symbol_name_temporary;
182433965Sjdp  for (*q++ = 0, i = n; i; ++q)
182533965Sjdp    {
182633965Sjdp      *q = i % 10 + '0';
182733965Sjdp      i /= 10;
182833965Sjdp    }
182933965Sjdp  while ((*p = *--q) != '\0')
183033965Sjdp    ++p;
183133965Sjdp
183277298Sobrien  *p++ = LOCAL_LABEL_CHAR;		/* ^B  */
183333965Sjdp
183477298Sobrien  /* Instance number.  */
183533965Sjdp  q = symbol_name_temporary;
183633965Sjdp  for (*q++ = 0, i = fb_label_instance (n) + augend; i; ++q)
183733965Sjdp    {
183833965Sjdp      *q = i % 10 + '0';
183933965Sjdp      i /= 10;
184033965Sjdp    }
1841257360Ssbruno  while ((*p++ = *--q) != '\0')
1842257360Ssbruno	;;
184333965Sjdp
184477298Sobrien  /* The label, as a '\0' ended string, starts at symbol_name_build.  */
184533965Sjdp  return (symbol_name_build);
184677298Sobrien}
184733965Sjdp
184877298Sobrien/* Decode name that may have been generated by foo_label_name() above.
184977298Sobrien   If the name wasn't generated by foo_label_name(), then return it
185077298Sobrien   unaltered.  This is used for error messages.  */
185133965Sjdp
185233965Sjdpchar *
1853130561Sobriendecode_local_label_name (char *s)
185433965Sjdp{
185533965Sjdp  char *p;
185633965Sjdp  char *symbol_decode;
185733965Sjdp  int label_number;
185833965Sjdp  int instance_number;
185933965Sjdp  char *type;
186078828Sobrien  const char *message_format;
186177298Sobrien  int index = 0;
186233965Sjdp
186377298Sobrien#ifdef LOCAL_LABEL_PREFIX
186477298Sobrien  if (s[index] == LOCAL_LABEL_PREFIX)
186577298Sobrien    ++index;
186677298Sobrien#endif
186777298Sobrien
186877298Sobrien  if (s[index] != 'L')
186933965Sjdp    return s;
187033965Sjdp
187189857Sobrien  for (label_number = 0, p = s + index + 1; ISDIGIT (*p); ++p)
187233965Sjdp    label_number = (10 * label_number) + *p - '0';
187333965Sjdp
187477298Sobrien  if (*p == DOLLAR_LABEL_CHAR)
187533965Sjdp    type = "dollar";
187677298Sobrien  else if (*p == LOCAL_LABEL_CHAR)
187733965Sjdp    type = "fb";
187833965Sjdp  else
187933965Sjdp    return s;
188033965Sjdp
188189857Sobrien  for (instance_number = 0, p++; ISDIGIT (*p); ++p)
188233965Sjdp    instance_number = (10 * instance_number) + *p - '0';
188333965Sjdp
188478828Sobrien  message_format = _("\"%d\" (instance number %d of a %s label)");
188533965Sjdp  symbol_decode = obstack_alloc (&notes, strlen (message_format) + 30);
188633965Sjdp  sprintf (symbol_decode, message_format, label_number, instance_number, type);
188733965Sjdp
188833965Sjdp  return symbol_decode;
188933965Sjdp}
189033965Sjdp
189133965Sjdp/* Get the value of a symbol.  */
189233965Sjdp
189333965SjdpvalueT
1894130561SobrienS_GET_VALUE (symbolS *s)
189533965Sjdp{
189660484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
189789857Sobrien    return resolve_symbol_value (s);
189860484Sobrien
189989857Sobrien  if (!s->sy_resolved)
190089857Sobrien    {
190189857Sobrien      valueT val = resolve_symbol_value (s);
190289857Sobrien      if (!finalize_syms)
190389857Sobrien	return val;
190489857Sobrien    }
1905218822Sdim  if (S_IS_WEAKREFR (s))
1906218822Sdim    return S_GET_VALUE (s->sy_value.X_add_symbol);
1907218822Sdim
190833965Sjdp  if (s->sy_value.X_op != O_constant)
190933965Sjdp    {
191033965Sjdp      if (! s->sy_resolved
191133965Sjdp	  || s->sy_value.X_op != O_symbol
191233965Sjdp	  || (S_IS_DEFINED (s) && ! S_IS_COMMON (s)))
191389857Sobrien	as_bad (_("attempt to get value of unresolved symbol `%s'"),
191433965Sjdp		S_GET_NAME (s));
191533965Sjdp    }
191633965Sjdp  return (valueT) s->sy_value.X_add_number;
191733965Sjdp}
191833965Sjdp
191933965Sjdp/* Set the value of a symbol.  */
192033965Sjdp
192133965Sjdpvoid
1922130561SobrienS_SET_VALUE (symbolS *s, valueT val)
192333965Sjdp{
192460484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
192560484Sobrien    {
192689857Sobrien      ((struct local_symbol *) s)->lsy_value = val;
192760484Sobrien      return;
192860484Sobrien    }
192960484Sobrien
193033965Sjdp  s->sy_value.X_op = O_constant;
193133965Sjdp  s->sy_value.X_add_number = (offsetT) val;
193233965Sjdp  s->sy_value.X_unsigned = 0;
1933218822Sdim  S_CLEAR_WEAKREFR (s);
193433965Sjdp}
193533965Sjdp
193633965Sjdpvoid
1937130561Sobriencopy_symbol_attributes (symbolS *dest, symbolS *src)
193833965Sjdp{
193960484Sobrien  if (LOCAL_SYMBOL_CHECK (dest))
194060484Sobrien    dest = local_symbol_convert ((struct local_symbol *) dest);
194160484Sobrien  if (LOCAL_SYMBOL_CHECK (src))
194260484Sobrien    src = local_symbol_convert ((struct local_symbol *) src);
194360484Sobrien
194433965Sjdp  /* In an expression, transfer the settings of these flags.
194533965Sjdp     The user can override later, of course.  */
194638889Sjdp#define COPIED_SYMFLAGS	(BSF_FUNCTION | BSF_OBJECT)
194733965Sjdp  dest->bsym->flags |= src->bsym->flags & COPIED_SYMFLAGS;
194833965Sjdp
194933965Sjdp#ifdef OBJ_COPY_SYMBOL_ATTRIBUTES
195033965Sjdp  OBJ_COPY_SYMBOL_ATTRIBUTES (dest, src);
195133965Sjdp#endif
1952218822Sdim
1953218822Sdim#ifdef TC_COPY_SYMBOL_ATTRIBUTES
1954218822Sdim  TC_COPY_SYMBOL_ATTRIBUTES (dest, src);
1955218822Sdim#endif
195633965Sjdp}
195733965Sjdp
195833965Sjdpint
1959130561SobrienS_IS_FUNCTION (symbolS *s)
196060484Sobrien{
196160484Sobrien  flagword flags;
196260484Sobrien
196360484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
196460484Sobrien    return 0;
196560484Sobrien
196660484Sobrien  flags = s->bsym->flags;
196760484Sobrien
196860484Sobrien  return (flags & BSF_FUNCTION) != 0;
196960484Sobrien}
197060484Sobrien
197160484Sobrienint
1972130561SobrienS_IS_EXTERNAL (symbolS *s)
197333965Sjdp{
197460484Sobrien  flagword flags;
197533965Sjdp
197660484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
197760484Sobrien    return 0;
197860484Sobrien
197960484Sobrien  flags = s->bsym->flags;
198060484Sobrien
198177298Sobrien  /* Sanity check.  */
198238889Sjdp  if ((flags & BSF_LOCAL) && (flags & BSF_GLOBAL))
198333965Sjdp    abort ();
198433965Sjdp
198533965Sjdp  return (flags & BSF_GLOBAL) != 0;
198633965Sjdp}
198733965Sjdp
198833965Sjdpint
1989130561SobrienS_IS_WEAK (symbolS *s)
199033965Sjdp{
199160484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
199260484Sobrien    return 0;
1993218822Sdim  /* Conceptually, a weakrefr is weak if the referenced symbol is.  We
1994218822Sdim     could probably handle a WEAKREFR as always weak though.  E.g., if
1995218822Sdim     the referenced symbol has lost its weak status, there's no reason
1996218822Sdim     to keep handling the weakrefr as if it was weak.  */
1997218822Sdim  if (S_IS_WEAKREFR (s))
1998218822Sdim    return S_IS_WEAK (s->sy_value.X_add_symbol);
199933965Sjdp  return (s->bsym->flags & BSF_WEAK) != 0;
200033965Sjdp}
200133965Sjdp
200233965Sjdpint
2003218822SdimS_IS_WEAKREFR (symbolS *s)
2004218822Sdim{
2005218822Sdim  if (LOCAL_SYMBOL_CHECK (s))
2006218822Sdim    return 0;
2007218822Sdim  return s->sy_weakrefr != 0;
2008218822Sdim}
2009218822Sdim
2010218822Sdimint
2011218822SdimS_IS_WEAKREFD (symbolS *s)
2012218822Sdim{
2013218822Sdim  if (LOCAL_SYMBOL_CHECK (s))
2014218822Sdim    return 0;
2015218822Sdim  return s->sy_weakrefd != 0;
2016218822Sdim}
2017218822Sdim
2018218822Sdimint
2019130561SobrienS_IS_COMMON (symbolS *s)
202033965Sjdp{
202160484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
202260484Sobrien    return 0;
202333965Sjdp  return bfd_is_com_section (s->bsym->section);
202433965Sjdp}
202533965Sjdp
202633965Sjdpint
2027130561SobrienS_IS_DEFINED (symbolS *s)
202833965Sjdp{
202960484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
203060484Sobrien    return ((struct local_symbol *) s)->lsy_section != undefined_section;
203133965Sjdp  return s->bsym->section != undefined_section;
203233965Sjdp}
203333965Sjdp
2034130561Sobrien
2035130561Sobrien#ifndef EXTERN_FORCE_RELOC
2036130561Sobrien#define EXTERN_FORCE_RELOC IS_ELF
2037130561Sobrien#endif
2038130561Sobrien
2039130561Sobrien/* Return true for symbols that should not be reduced to section
2040130561Sobrien   symbols or eliminated from expressions, because they may be
2041130561Sobrien   overridden by the linker.  */
204233965Sjdpint
2043130561SobrienS_FORCE_RELOC (symbolS *s, int strict)
204433965Sjdp{
204560484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
2046130561Sobrien    return ((struct local_symbol *) s)->lsy_section == undefined_section;
2047130561Sobrien
2048130561Sobrien  return ((strict
2049130561Sobrien	   && ((s->bsym->flags & BSF_WEAK) != 0
2050130561Sobrien	       || (EXTERN_FORCE_RELOC
2051130561Sobrien		   && (s->bsym->flags & BSF_GLOBAL) != 0)))
2052130561Sobrien	  || s->bsym->section == undefined_section
2053130561Sobrien	  || bfd_is_com_section (s->bsym->section));
2054130561Sobrien}
2055130561Sobrien
2056130561Sobrienint
2057130561SobrienS_IS_DEBUG (symbolS *s)
2058130561Sobrien{
2059130561Sobrien  if (LOCAL_SYMBOL_CHECK (s))
206060484Sobrien    return 0;
206133965Sjdp  if (s->bsym->flags & BSF_DEBUGGING)
206233965Sjdp    return 1;
206333965Sjdp  return 0;
206433965Sjdp}
206533965Sjdp
206633965Sjdpint
2067130561SobrienS_IS_LOCAL (symbolS *s)
206833965Sjdp{
206960484Sobrien  flagword flags;
207033965Sjdp  const char *name;
207133965Sjdp
207260484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
207360484Sobrien    return 1;
207460484Sobrien
207560484Sobrien  flags = s->bsym->flags;
207660484Sobrien
207777298Sobrien  /* Sanity check.  */
207838889Sjdp  if ((flags & BSF_LOCAL) && (flags & BSF_GLOBAL))
207933965Sjdp    abort ();
208033965Sjdp
208133965Sjdp  if (bfd_get_section (s->bsym) == reg_section)
208233965Sjdp    return 1;
208333965Sjdp
208438889Sjdp  if (flag_strip_local_absolute
2085218822Sdim      /* Keep BSF_FILE symbols in order to allow debuggers to identify
2086218822Sdim	 the source file even when the object file is stripped.  */
2087218822Sdim      && (flags & (BSF_GLOBAL | BSF_FILE)) == 0
208838889Sjdp      && bfd_get_section (s->bsym) == absolute_section)
208938889Sjdp    return 1;
209038889Sjdp
209133965Sjdp  name = S_GET_NAME (s);
209233965Sjdp  return (name != NULL
209333965Sjdp	  && ! S_IS_DEBUG (s)
209477298Sobrien	  && (strchr (name, DOLLAR_LABEL_CHAR)
209577298Sobrien	      || strchr (name, LOCAL_LABEL_CHAR)
209633965Sjdp	      || (! flag_keep_locals
209733965Sjdp		  && (bfd_is_local_label (stdoutput, s->bsym)
209833965Sjdp		      || (flag_mri
209933965Sjdp			  && name[0] == '?'
210033965Sjdp			  && name[1] == '?')))));
210133965Sjdp}
210233965Sjdp
210333965Sjdpint
2104218822SdimS_IS_STABD (symbolS *s)
210533965Sjdp{
2106218822Sdim  return S_GET_NAME (s) == 0;
210733965Sjdp}
210833965Sjdp
210933965Sjdpint
2110218822SdimS_IS_VOLATILE (const symbolS *s)
211133965Sjdp{
2112218822Sdim  if (LOCAL_SYMBOL_CHECK (s))
2113218822Sdim    return 0;
2114218822Sdim  return s->sy_volatile;
211533965Sjdp}
211633965Sjdp
2117218822Sdimint
2118218822SdimS_IS_FORWARD_REF (const symbolS *s)
2119218822Sdim{
2120218822Sdim  if (LOCAL_SYMBOL_CHECK (s))
2121218822Sdim    return 0;
2122218822Sdim  return s->sy_forward_ref;
2123218822Sdim}
2124218822Sdim
2125104834Sobrienconst char *
2126130561SobrienS_GET_NAME (symbolS *s)
212733965Sjdp{
212860484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
212960484Sobrien    return ((struct local_symbol *) s)->lsy_name;
213033965Sjdp  return s->bsym->name;
213133965Sjdp}
213233965Sjdp
213333965SjdpsegT
2134130561SobrienS_GET_SEGMENT (symbolS *s)
213533965Sjdp{
213660484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
213760484Sobrien    return ((struct local_symbol *) s)->lsy_section;
213833965Sjdp  return s->bsym->section;
213933965Sjdp}
214033965Sjdp
214133965Sjdpvoid
2142130561SobrienS_SET_SEGMENT (symbolS *s, segT seg)
214333965Sjdp{
214438889Sjdp  /* Don't reassign section symbols.  The direct reason is to prevent seg
214538889Sjdp     faults assigning back to const global symbols such as *ABS*, but it
214638889Sjdp     shouldn't happen anyway.  */
214738889Sjdp
214860484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
214960484Sobrien    {
215060484Sobrien      if (seg == reg_section)
215160484Sobrien	s = local_symbol_convert ((struct local_symbol *) s);
215260484Sobrien      else
215360484Sobrien	{
215460484Sobrien	  ((struct local_symbol *) s)->lsy_section = seg;
215560484Sobrien	  return;
215660484Sobrien	}
215760484Sobrien    }
215860484Sobrien
215938889Sjdp  if (s->bsym->flags & BSF_SECTION_SYM)
216038889Sjdp    {
216138889Sjdp      if (s->bsym->section != seg)
216277298Sobrien	abort ();
216338889Sjdp    }
216438889Sjdp  else
216538889Sjdp    s->bsym->section = seg;
216633965Sjdp}
216733965Sjdp
216833965Sjdpvoid
2169130561SobrienS_SET_EXTERNAL (symbolS *s)
217033965Sjdp{
217160484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
217260484Sobrien    s = local_symbol_convert ((struct local_symbol *) s);
217333965Sjdp  if ((s->bsym->flags & BSF_WEAK) != 0)
217433965Sjdp    {
217533965Sjdp      /* Let .weak override .global.  */
217633965Sjdp      return;
217733965Sjdp    }
217878828Sobrien  if (s->bsym->flags & BSF_SECTION_SYM)
217978828Sobrien    {
218078828Sobrien      char * file;
218178828Sobrien      unsigned int line;
2182104834Sobrien
218378828Sobrien      /* Do not reassign section symbols.  */
218478828Sobrien      as_where (& file, & line);
218578828Sobrien      as_warn_where (file, line,
218689857Sobrien		     _("section symbols are already global"));
218778828Sobrien      return;
218878828Sobrien    }
218933965Sjdp  s->bsym->flags |= BSF_GLOBAL;
219077298Sobrien  s->bsym->flags &= ~(BSF_LOCAL | BSF_WEAK);
2191218822Sdim
2192218822Sdim#ifdef USE_UNIQUE
2193218822Sdim  if (! an_external_name && S_GET_NAME(s)[0] != '.')
2194218822Sdim    an_external_name = S_GET_NAME (s);
2195218822Sdim#endif
219633965Sjdp}
219733965Sjdp
219833965Sjdpvoid
2199130561SobrienS_CLEAR_EXTERNAL (symbolS *s)
220033965Sjdp{
220160484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
220260484Sobrien    return;
220333965Sjdp  if ((s->bsym->flags & BSF_WEAK) != 0)
220433965Sjdp    {
220533965Sjdp      /* Let .weak override.  */
220633965Sjdp      return;
220733965Sjdp    }
220833965Sjdp  s->bsym->flags |= BSF_LOCAL;
220977298Sobrien  s->bsym->flags &= ~(BSF_GLOBAL | BSF_WEAK);
221033965Sjdp}
221133965Sjdp
221233965Sjdpvoid
2213130561SobrienS_SET_WEAK (symbolS *s)
221433965Sjdp{
221560484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
221660484Sobrien    s = local_symbol_convert ((struct local_symbol *) s);
2217218822Sdim#ifdef obj_set_weak_hook
2218218822Sdim  obj_set_weak_hook (s);
2219218822Sdim#endif
222033965Sjdp  s->bsym->flags |= BSF_WEAK;
222177298Sobrien  s->bsym->flags &= ~(BSF_GLOBAL | BSF_LOCAL);
222233965Sjdp}
222333965Sjdp
222433965Sjdpvoid
2225218822SdimS_SET_WEAKREFR (symbolS *s)
2226218822Sdim{
2227218822Sdim  if (LOCAL_SYMBOL_CHECK (s))
2228218822Sdim    s = local_symbol_convert ((struct local_symbol *) s);
2229218822Sdim  s->sy_weakrefr = 1;
2230218822Sdim  /* If the alias was already used, make sure we mark the target as
2231218822Sdim     used as well, otherwise it might be dropped from the symbol
2232218822Sdim     table.  This may have unintended side effects if the alias is
2233218822Sdim     later redirected to another symbol, such as keeping the unused
2234218822Sdim     previous target in the symbol table.  Since it will be weak, it's
2235218822Sdim     not a big deal.  */
2236218822Sdim  if (s->sy_used)
2237218822Sdim    symbol_mark_used (s->sy_value.X_add_symbol);
2238218822Sdim}
2239218822Sdim
2240218822Sdimvoid
2241218822SdimS_CLEAR_WEAKREFR (symbolS *s)
2242218822Sdim{
2243218822Sdim  if (LOCAL_SYMBOL_CHECK (s))
2244218822Sdim    return;
2245218822Sdim  s->sy_weakrefr = 0;
2246218822Sdim}
2247218822Sdim
2248218822Sdimvoid
2249218822SdimS_SET_WEAKREFD (symbolS *s)
2250218822Sdim{
2251218822Sdim  if (LOCAL_SYMBOL_CHECK (s))
2252218822Sdim    s = local_symbol_convert ((struct local_symbol *) s);
2253218822Sdim  s->sy_weakrefd = 1;
2254218822Sdim  S_SET_WEAK (s);
2255218822Sdim}
2256218822Sdim
2257218822Sdimvoid
2258218822SdimS_CLEAR_WEAKREFD (symbolS *s)
2259218822Sdim{
2260218822Sdim  if (LOCAL_SYMBOL_CHECK (s))
2261218822Sdim    return;
2262218822Sdim  if (s->sy_weakrefd)
2263218822Sdim    {
2264218822Sdim      s->sy_weakrefd = 0;
2265218822Sdim      /* If a weakref target symbol is weak, then it was never
2266218822Sdim	 referenced directly before, not even in a .global directive,
2267218822Sdim	 so decay it to local.  If it remains undefined, it will be
2268218822Sdim	 later turned into a global, like any other undefined
2269218822Sdim	 symbol.  */
2270218822Sdim      if (s->bsym->flags & BSF_WEAK)
2271218822Sdim	{
2272218822Sdim#ifdef obj_clear_weak_hook
2273218822Sdim	  obj_clear_weak_hook (s);
2274218822Sdim#endif
2275218822Sdim	  s->bsym->flags &= ~BSF_WEAK;
2276218822Sdim	  s->bsym->flags |= BSF_LOCAL;
2277218822Sdim	}
2278218822Sdim    }
2279218822Sdim}
2280218822Sdim
2281218822Sdimvoid
2282130561SobrienS_SET_THREAD_LOCAL (symbolS *s)
228333965Sjdp{
228460484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
2285130561Sobrien    s = local_symbol_convert ((struct local_symbol *) s);
2286130561Sobrien  if (bfd_is_com_section (s->bsym->section)
2287130561Sobrien      && (s->bsym->flags & BSF_THREAD_LOCAL) != 0)
2288130561Sobrien    return;
2289130561Sobrien  s->bsym->flags |= BSF_THREAD_LOCAL;
2290130561Sobrien  if ((s->bsym->flags & BSF_FUNCTION) != 0)
2291130561Sobrien    as_bad (_("Accessing function `%s' as thread-local object"),
2292130561Sobrien	    S_GET_NAME (s));
2293130561Sobrien  else if (! bfd_is_und_section (s->bsym->section)
2294130561Sobrien	   && (s->bsym->section->flags & SEC_THREAD_LOCAL) == 0)
2295130561Sobrien    as_bad (_("Accessing `%s' as thread-local object"),
2296130561Sobrien	    S_GET_NAME (s));
2297130561Sobrien}
2298130561Sobrien
2299130561Sobrienvoid
2300218822SdimS_SET_NAME (symbolS *s, const char *name)
2301130561Sobrien{
2302130561Sobrien  if (LOCAL_SYMBOL_CHECK (s))
230360484Sobrien    {
230460484Sobrien      ((struct local_symbol *) s)->lsy_name = name;
230560484Sobrien      return;
230660484Sobrien    }
230733965Sjdp  s->bsym->name = name;
230833965Sjdp}
230933965Sjdp
2310218822Sdimvoid
2311218822SdimS_SET_VOLATILE (symbolS *s)
2312218822Sdim{
2313218822Sdim  if (LOCAL_SYMBOL_CHECK (s))
2314218822Sdim    s = local_symbol_convert ((struct local_symbol *) s);
2315218822Sdim  s->sy_volatile = 1;
2316218822Sdim}
231760484Sobrien
2318218822Sdimvoid
2319218822SdimS_CLEAR_VOLATILE (symbolS *s)
2320218822Sdim{
2321218822Sdim  if (!LOCAL_SYMBOL_CHECK (s))
2322218822Sdim    s->sy_volatile = 0;
2323218822Sdim}
2324218822Sdim
2325218822Sdimvoid
2326218822SdimS_SET_FORWARD_REF (symbolS *s)
2327218822Sdim{
2328218822Sdim  if (LOCAL_SYMBOL_CHECK (s))
2329218822Sdim    s = local_symbol_convert ((struct local_symbol *) s);
2330218822Sdim  s->sy_forward_ref = 1;
2331218822Sdim}
2332218822Sdim
233360484Sobrien/* Return the previous symbol in a chain.  */
233460484Sobrien
233560484SobriensymbolS *
2336130561Sobriensymbol_previous (symbolS *s)
233760484Sobrien{
233860484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
233960484Sobrien    abort ();
234060484Sobrien  return s->sy_previous;
234160484Sobrien}
234260484Sobrien
234360484Sobrien/* Return the next symbol in a chain.  */
234460484Sobrien
234560484SobriensymbolS *
2346130561Sobriensymbol_next (symbolS *s)
234760484Sobrien{
234860484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
234960484Sobrien    abort ();
235060484Sobrien  return s->sy_next;
235160484Sobrien}
235260484Sobrien
235360484Sobrien/* Return a pointer to the value of a symbol as an expression.  */
235460484Sobrien
235560484SobrienexpressionS *
2356130561Sobriensymbol_get_value_expression (symbolS *s)
235760484Sobrien{
235860484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
235960484Sobrien    s = local_symbol_convert ((struct local_symbol *) s);
236060484Sobrien  return &s->sy_value;
236160484Sobrien}
236260484Sobrien
236360484Sobrien/* Set the value of a symbol to an expression.  */
236460484Sobrien
236533965Sjdpvoid
2366130561Sobriensymbol_set_value_expression (symbolS *s, const expressionS *exp)
236760484Sobrien{
236860484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
236960484Sobrien    s = local_symbol_convert ((struct local_symbol *) s);
237060484Sobrien  s->sy_value = *exp;
2371218822Sdim  S_CLEAR_WEAKREFR (s);
237260484Sobrien}
237360484Sobrien
2374218822Sdim/* Return a pointer to the X_add_number component of a symbol.  */
2375218822Sdim
2376218822SdimoffsetT *
2377218822Sdimsymbol_X_add_number (symbolS *s)
2378218822Sdim{
2379218822Sdim  if (LOCAL_SYMBOL_CHECK (s))
2380218822Sdim    return (offsetT *) &((struct local_symbol *) s)->lsy_value;
2381218822Sdim
2382218822Sdim  return &s->sy_value.X_add_number;
2383218822Sdim}
2384218822Sdim
2385130561Sobrien/* Set the value of SYM to the current position in the current segment.  */
2386130561Sobrien
2387130561Sobrienvoid
2388130561Sobriensymbol_set_value_now (symbolS *sym)
2389130561Sobrien{
2390130561Sobrien  S_SET_SEGMENT (sym, now_seg);
2391130561Sobrien  S_SET_VALUE (sym, frag_now_fix ());
2392130561Sobrien  symbol_set_frag (sym, frag_now);
2393130561Sobrien}
2394130561Sobrien
239560484Sobrien/* Set the frag of a symbol.  */
239660484Sobrien
239760484Sobrienvoid
2398130561Sobriensymbol_set_frag (symbolS *s, fragS *f)
239960484Sobrien{
240060484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
240160484Sobrien    {
240260484Sobrien      local_symbol_set_frag ((struct local_symbol *) s, f);
240360484Sobrien      return;
240460484Sobrien    }
240560484Sobrien  s->sy_frag = f;
2406218822Sdim  S_CLEAR_WEAKREFR (s);
240760484Sobrien}
240860484Sobrien
240960484Sobrien/* Return the frag of a symbol.  */
241060484Sobrien
241160484SobrienfragS *
2412130561Sobriensymbol_get_frag (symbolS *s)
241360484Sobrien{
241460484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
241560484Sobrien    return local_symbol_get_frag ((struct local_symbol *) s);
241660484Sobrien  return s->sy_frag;
241760484Sobrien}
241860484Sobrien
241960484Sobrien/* Mark a symbol as having been used.  */
242060484Sobrien
242160484Sobrienvoid
2422130561Sobriensymbol_mark_used (symbolS *s)
242360484Sobrien{
242460484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
242560484Sobrien    return;
242660484Sobrien  s->sy_used = 1;
2427218822Sdim  if (S_IS_WEAKREFR (s))
2428218822Sdim    symbol_mark_used (s->sy_value.X_add_symbol);
242960484Sobrien}
243060484Sobrien
243160484Sobrien/* Clear the mark of whether a symbol has been used.  */
243260484Sobrien
243360484Sobrienvoid
2434130561Sobriensymbol_clear_used (symbolS *s)
243560484Sobrien{
243660484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
243760484Sobrien    s = local_symbol_convert ((struct local_symbol *) s);
243860484Sobrien  s->sy_used = 0;
243960484Sobrien}
244060484Sobrien
244160484Sobrien/* Return whether a symbol has been used.  */
244260484Sobrien
244360484Sobrienint
2444130561Sobriensymbol_used_p (symbolS *s)
244560484Sobrien{
244660484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
244760484Sobrien    return 1;
244860484Sobrien  return s->sy_used;
244960484Sobrien}
245060484Sobrien
245160484Sobrien/* Mark a symbol as having been used in a reloc.  */
245260484Sobrien
245360484Sobrienvoid
2454130561Sobriensymbol_mark_used_in_reloc (symbolS *s)
245560484Sobrien{
245660484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
245760484Sobrien    s = local_symbol_convert ((struct local_symbol *) s);
245860484Sobrien  s->sy_used_in_reloc = 1;
245960484Sobrien}
246060484Sobrien
246160484Sobrien/* Clear the mark of whether a symbol has been used in a reloc.  */
246260484Sobrien
246360484Sobrienvoid
2464130561Sobriensymbol_clear_used_in_reloc (symbolS *s)
246560484Sobrien{
246660484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
246760484Sobrien    return;
246860484Sobrien  s->sy_used_in_reloc = 0;
246960484Sobrien}
247060484Sobrien
247160484Sobrien/* Return whether a symbol has been used in a reloc.  */
247260484Sobrien
247360484Sobrienint
2474130561Sobriensymbol_used_in_reloc_p (symbolS *s)
247560484Sobrien{
247660484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
247760484Sobrien    return 0;
247860484Sobrien  return s->sy_used_in_reloc;
247960484Sobrien}
248060484Sobrien
248160484Sobrien/* Mark a symbol as an MRI common symbol.  */
248260484Sobrien
248360484Sobrienvoid
2484130561Sobriensymbol_mark_mri_common (symbolS *s)
248560484Sobrien{
248660484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
248760484Sobrien    s = local_symbol_convert ((struct local_symbol *) s);
248860484Sobrien  s->sy_mri_common = 1;
248960484Sobrien}
249060484Sobrien
249160484Sobrien/* Clear the mark of whether a symbol is an MRI common symbol.  */
249260484Sobrien
249360484Sobrienvoid
2494130561Sobriensymbol_clear_mri_common (symbolS *s)
249560484Sobrien{
249660484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
249760484Sobrien    return;
249860484Sobrien  s->sy_mri_common = 0;
249960484Sobrien}
250060484Sobrien
250160484Sobrien/* Return whether a symbol is an MRI common symbol.  */
250260484Sobrien
250360484Sobrienint
2504130561Sobriensymbol_mri_common_p (symbolS *s)
250560484Sobrien{
250660484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
250760484Sobrien    return 0;
250860484Sobrien  return s->sy_mri_common;
250960484Sobrien}
251060484Sobrien
251160484Sobrien/* Mark a symbol as having been written.  */
251260484Sobrien
251360484Sobrienvoid
2514130561Sobriensymbol_mark_written (symbolS *s)
251560484Sobrien{
251660484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
251760484Sobrien    return;
251860484Sobrien  s->written = 1;
251960484Sobrien}
252060484Sobrien
252160484Sobrien/* Clear the mark of whether a symbol has been written.  */
252260484Sobrien
252360484Sobrienvoid
2524130561Sobriensymbol_clear_written (symbolS *s)
252560484Sobrien{
252660484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
252760484Sobrien    return;
252860484Sobrien  s->written = 0;
252960484Sobrien}
253060484Sobrien
253160484Sobrien/* Return whether a symbol has been written.  */
253260484Sobrien
253360484Sobrienint
2534130561Sobriensymbol_written_p (symbolS *s)
253560484Sobrien{
253660484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
253760484Sobrien    return 0;
253860484Sobrien  return s->written;
253960484Sobrien}
254060484Sobrien
254160484Sobrien/* Mark a symbol has having been resolved.  */
254260484Sobrien
254360484Sobrienvoid
2544130561Sobriensymbol_mark_resolved (symbolS *s)
254560484Sobrien{
254660484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
254760484Sobrien    {
254860484Sobrien      local_symbol_mark_resolved ((struct local_symbol *) s);
254960484Sobrien      return;
255060484Sobrien    }
255160484Sobrien  s->sy_resolved = 1;
255260484Sobrien}
255360484Sobrien
255460484Sobrien/* Return whether a symbol has been resolved.  */
255560484Sobrien
255660484Sobrienint
2557130561Sobriensymbol_resolved_p (symbolS *s)
255860484Sobrien{
255960484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
256060484Sobrien    return local_symbol_resolved_p ((struct local_symbol *) s);
256160484Sobrien  return s->sy_resolved;
256260484Sobrien}
256360484Sobrien
256460484Sobrien/* Return whether a symbol is a section symbol.  */
256560484Sobrien
256660484Sobrienint
2567130561Sobriensymbol_section_p (symbolS *s ATTRIBUTE_UNUSED)
256860484Sobrien{
256960484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
257060484Sobrien    return 0;
257160484Sobrien  return (s->bsym->flags & BSF_SECTION_SYM) != 0;
257260484Sobrien}
257360484Sobrien
257460484Sobrien/* Return whether a symbol is equated to another symbol.  */
257560484Sobrien
257660484Sobrienint
2577130561Sobriensymbol_equated_p (symbolS *s)
257860484Sobrien{
257960484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
258060484Sobrien    return 0;
258160484Sobrien  return s->sy_value.X_op == O_symbol;
258260484Sobrien}
258360484Sobrien
258489857Sobrien/* Return whether a symbol is equated to another symbol, and should be
258589857Sobrien   treated specially when writing out relocs.  */
258689857Sobrien
258789857Sobrienint
2588130561Sobriensymbol_equated_reloc_p (symbolS *s)
258989857Sobrien{
259089857Sobrien  if (LOCAL_SYMBOL_CHECK (s))
259189857Sobrien    return 0;
259289857Sobrien  /* X_op_symbol, normally not used for O_symbol, is set by
259389857Sobrien     resolve_symbol_value to flag expression syms that have been
259489857Sobrien     equated.  */
259589857Sobrien  return (s->sy_value.X_op == O_symbol
2596218822Sdim#if defined (OBJ_COFF) && defined (TE_PE)
2597218822Sdim	  && ! S_IS_WEAK (s)
2598218822Sdim#endif
259989857Sobrien	  && ((s->sy_resolved && s->sy_value.X_op_symbol != NULL)
260089857Sobrien	      || ! S_IS_DEFINED (s)
260189857Sobrien	      || S_IS_COMMON (s)));
260289857Sobrien}
260389857Sobrien
260460484Sobrien/* Return whether a symbol has a constant value.  */
260560484Sobrien
260660484Sobrienint
2607130561Sobriensymbol_constant_p (symbolS *s)
260860484Sobrien{
260960484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
261060484Sobrien    return 1;
261160484Sobrien  return s->sy_value.X_op == O_constant;
261260484Sobrien}
261360484Sobrien
2614218822Sdim/* Return whether a symbol was cloned and thus removed from the global
2615218822Sdim   symbol list.  */
261660484Sobrien
2617218822Sdimint
2618218822Sdimsymbol_shadow_p (symbolS *s)
2619218822Sdim{
2620218822Sdim  if (LOCAL_SYMBOL_CHECK (s))
2621218822Sdim    return 0;
2622218822Sdim  return s->sy_next == s;
2623218822Sdim}
2624218822Sdim
262560484Sobrien/* Return the BFD symbol for a symbol.  */
262660484Sobrien
262760484Sobrienasymbol *
2628130561Sobriensymbol_get_bfdsym (symbolS *s)
262960484Sobrien{
263060484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
263160484Sobrien    s = local_symbol_convert ((struct local_symbol *) s);
263260484Sobrien  return s->bsym;
263360484Sobrien}
263460484Sobrien
263560484Sobrien/* Set the BFD symbol for a symbol.  */
263660484Sobrien
263760484Sobrienvoid
2638130561Sobriensymbol_set_bfdsym (symbolS *s, asymbol *bsym)
263960484Sobrien{
264060484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
264160484Sobrien    s = local_symbol_convert ((struct local_symbol *) s);
2642218822Sdim  /* Usually, it is harmless to reset a symbol to a BFD section
2643218822Sdim     symbol. For example, obj_elf_change_section sets the BFD symbol
2644218822Sdim     of an old symbol with the newly created section symbol. But when
2645218822Sdim     we have multiple sections with the same name, the newly created
2646218822Sdim     section may have the same name as an old section. We check if the
2647218822Sdim     old symbol has been already marked as a section symbol before
2648218822Sdim     resetting it.  */
2649218822Sdim  if ((s->bsym->flags & BSF_SECTION_SYM) == 0)
2650218822Sdim    s->bsym = bsym;
2651218822Sdim  /* else XXX - What do we do now ?  */
265260484Sobrien}
265360484Sobrien
265460484Sobrien#ifdef OBJ_SYMFIELD_TYPE
265560484Sobrien
265660484Sobrien/* Get a pointer to the object format information for a symbol.  */
265760484Sobrien
265860484SobrienOBJ_SYMFIELD_TYPE *
2659130561Sobriensymbol_get_obj (symbolS *s)
266060484Sobrien{
266160484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
266260484Sobrien    s = local_symbol_convert ((struct local_symbol *) s);
266360484Sobrien  return &s->sy_obj;
266460484Sobrien}
266560484Sobrien
266660484Sobrien/* Set the object format information for a symbol.  */
266760484Sobrien
266860484Sobrienvoid
2669130561Sobriensymbol_set_obj (symbolS *s, OBJ_SYMFIELD_TYPE *o)
267060484Sobrien{
267160484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
267260484Sobrien    s = local_symbol_convert ((struct local_symbol *) s);
267360484Sobrien  s->sy_obj = *o;
267460484Sobrien}
267560484Sobrien
267660484Sobrien#endif /* OBJ_SYMFIELD_TYPE */
267760484Sobrien
267860484Sobrien#ifdef TC_SYMFIELD_TYPE
267960484Sobrien
268060484Sobrien/* Get a pointer to the processor information for a symbol.  */
268160484Sobrien
268260484SobrienTC_SYMFIELD_TYPE *
2683130561Sobriensymbol_get_tc (symbolS *s)
268460484Sobrien{
268560484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
268660484Sobrien    s = local_symbol_convert ((struct local_symbol *) s);
268760484Sobrien  return &s->sy_tc;
268860484Sobrien}
268960484Sobrien
269060484Sobrien/* Set the processor information for a symbol.  */
269160484Sobrien
269260484Sobrienvoid
2693130561Sobriensymbol_set_tc (symbolS *s, TC_SYMFIELD_TYPE *o)
269460484Sobrien{
269560484Sobrien  if (LOCAL_SYMBOL_CHECK (s))
269660484Sobrien    s = local_symbol_convert ((struct local_symbol *) s);
269760484Sobrien  s->sy_tc = *o;
269860484Sobrien}
269960484Sobrien
270060484Sobrien#endif /* TC_SYMFIELD_TYPE */
270160484Sobrien
270260484Sobrienvoid
2703130561Sobriensymbol_begin (void)
270433965Sjdp{
270533965Sjdp  symbol_lastP = NULL;
270677298Sobrien  symbol_rootP = NULL;		/* In case we have 0 symbols (!!)  */
270733965Sjdp  sy_hash = hash_new ();
270860484Sobrien  local_hash = hash_new ();
270933965Sjdp
271033965Sjdp  memset ((char *) (&abs_symbol), '\0', sizeof (abs_symbol));
271133965Sjdp#if defined (EMIT_SECTION_SYMBOLS) || !defined (RELOC_REQUIRES_SYMBOL)
271233965Sjdp  abs_symbol.bsym = bfd_abs_section.symbol;
271333965Sjdp#endif
271433965Sjdp  abs_symbol.sy_value.X_op = O_constant;
271533965Sjdp  abs_symbol.sy_frag = &zero_address_frag;
271633965Sjdp
271733965Sjdp  if (LOCAL_LABELS_FB)
271833965Sjdp    fb_label_init ();
271933965Sjdp}
272033965Sjdp
272133965Sjdpint indent_level;
272233965Sjdp
272360484Sobrien/* Maximum indent level.
272460484Sobrien   Available for modification inside a gdb session.  */
2725218822Sdimstatic int max_indent_level = 8;
272660484Sobrien
272733965Sjdpvoid
2728130561Sobrienprint_symbol_value_1 (FILE *file, symbolS *sym)
272933965Sjdp{
273033965Sjdp  const char *name = S_GET_NAME (sym);
273133965Sjdp  if (!name || !name[0])
273233965Sjdp    name = "(unnamed)";
273333965Sjdp  fprintf (file, "sym %lx %s", (unsigned long) sym, name);
273460484Sobrien
273560484Sobrien  if (LOCAL_SYMBOL_CHECK (sym))
273660484Sobrien    {
273760484Sobrien      struct local_symbol *locsym = (struct local_symbol *) sym;
273860484Sobrien      if (local_symbol_get_frag (locsym) != &zero_address_frag
273960484Sobrien	  && local_symbol_get_frag (locsym) != NULL)
274060484Sobrien	fprintf (file, " frag %lx", (long) local_symbol_get_frag (locsym));
274160484Sobrien      if (local_symbol_resolved_p (locsym))
274260484Sobrien	fprintf (file, " resolved");
274360484Sobrien      fprintf (file, " local");
274460484Sobrien    }
274560484Sobrien  else
274660484Sobrien    {
274760484Sobrien      if (sym->sy_frag != &zero_address_frag)
274860484Sobrien	fprintf (file, " frag %lx", (long) sym->sy_frag);
274960484Sobrien      if (sym->written)
275060484Sobrien	fprintf (file, " written");
275160484Sobrien      if (sym->sy_resolved)
275260484Sobrien	fprintf (file, " resolved");
275360484Sobrien      else if (sym->sy_resolving)
275460484Sobrien	fprintf (file, " resolving");
275560484Sobrien      if (sym->sy_used_in_reloc)
275660484Sobrien	fprintf (file, " used-in-reloc");
275760484Sobrien      if (sym->sy_used)
275860484Sobrien	fprintf (file, " used");
275960484Sobrien      if (S_IS_LOCAL (sym))
276060484Sobrien	fprintf (file, " local");
2761218822Sdim      if (S_IS_EXTERNAL (sym))
276260484Sobrien	fprintf (file, " extern");
2763218822Sdim      if (S_IS_WEAK (sym))
2764218822Sdim	fprintf (file, " weak");
276560484Sobrien      if (S_IS_DEBUG (sym))
276660484Sobrien	fprintf (file, " debug");
276760484Sobrien      if (S_IS_DEFINED (sym))
276860484Sobrien	fprintf (file, " defined");
276960484Sobrien    }
2770218822Sdim  if (S_IS_WEAKREFR (sym))
2771218822Sdim    fprintf (file, " weakrefr");
2772218822Sdim  if (S_IS_WEAKREFD (sym))
2773218822Sdim    fprintf (file, " weakrefd");
277433965Sjdp  fprintf (file, " %s", segment_name (S_GET_SEGMENT (sym)));
277560484Sobrien  if (symbol_resolved_p (sym))
277633965Sjdp    {
277733965Sjdp      segT s = S_GET_SEGMENT (sym);
277833965Sjdp
277933965Sjdp      if (s != undefined_section
2780104834Sobrien	  && s != expr_section)
278133965Sjdp	fprintf (file, " %lx", (long) S_GET_VALUE (sym));
278233965Sjdp    }
278360484Sobrien  else if (indent_level < max_indent_level
278460484Sobrien	   && S_GET_SEGMENT (sym) != undefined_section)
278533965Sjdp    {
278633965Sjdp      indent_level++;
278733965Sjdp      fprintf (file, "\n%*s<", indent_level * 4, "");
278860484Sobrien      if (LOCAL_SYMBOL_CHECK (sym))
278960484Sobrien	fprintf (file, "constant %lx",
279089857Sobrien		 (long) ((struct local_symbol *) sym)->lsy_value);
279160484Sobrien      else
279260484Sobrien	print_expr_1 (file, &sym->sy_value);
279333965Sjdp      fprintf (file, ">");
279433965Sjdp      indent_level--;
279533965Sjdp    }
279633965Sjdp  fflush (file);
279733965Sjdp}
279833965Sjdp
279933965Sjdpvoid
2800130561Sobrienprint_symbol_value (symbolS *sym)
280133965Sjdp{
280233965Sjdp  indent_level = 0;
280333965Sjdp  print_symbol_value_1 (stderr, sym);
280433965Sjdp  fprintf (stderr, "\n");
280533965Sjdp}
280633965Sjdp
280760484Sobrienstatic void
2808130561Sobrienprint_binary (FILE *file, const char *name, expressionS *exp)
280960484Sobrien{
281060484Sobrien  indent_level++;
281160484Sobrien  fprintf (file, "%s\n%*s<", name, indent_level * 4, "");
281260484Sobrien  print_symbol_value_1 (file, exp->X_add_symbol);
281360484Sobrien  fprintf (file, ">\n%*s<", indent_level * 4, "");
281460484Sobrien  print_symbol_value_1 (file, exp->X_op_symbol);
281560484Sobrien  fprintf (file, ">");
281660484Sobrien  indent_level--;
281760484Sobrien}
281860484Sobrien
281933965Sjdpvoid
2820130561Sobrienprint_expr_1 (FILE *file, expressionS *exp)
282133965Sjdp{
282233965Sjdp  fprintf (file, "expr %lx ", (long) exp);
282333965Sjdp  switch (exp->X_op)
282433965Sjdp    {
282533965Sjdp    case O_illegal:
282633965Sjdp      fprintf (file, "illegal");
282733965Sjdp      break;
282833965Sjdp    case O_absent:
282933965Sjdp      fprintf (file, "absent");
283033965Sjdp      break;
283133965Sjdp    case O_constant:
283233965Sjdp      fprintf (file, "constant %lx", (long) exp->X_add_number);
283333965Sjdp      break;
283433965Sjdp    case O_symbol:
283533965Sjdp      indent_level++;
283633965Sjdp      fprintf (file, "symbol\n%*s<", indent_level * 4, "");
283733965Sjdp      print_symbol_value_1 (file, exp->X_add_symbol);
283833965Sjdp      fprintf (file, ">");
283933965Sjdp    maybe_print_addnum:
284033965Sjdp      if (exp->X_add_number)
284133965Sjdp	fprintf (file, "\n%*s%lx", indent_level * 4, "",
284233965Sjdp		 (long) exp->X_add_number);
284333965Sjdp      indent_level--;
284433965Sjdp      break;
284533965Sjdp    case O_register:
284633965Sjdp      fprintf (file, "register #%d", (int) exp->X_add_number);
284733965Sjdp      break;
284833965Sjdp    case O_big:
284933965Sjdp      fprintf (file, "big");
285033965Sjdp      break;
285133965Sjdp    case O_uminus:
285233965Sjdp      fprintf (file, "uminus -<");
285333965Sjdp      indent_level++;
285433965Sjdp      print_symbol_value_1 (file, exp->X_add_symbol);
285533965Sjdp      fprintf (file, ">");
285633965Sjdp      goto maybe_print_addnum;
285733965Sjdp    case O_bit_not:
285833965Sjdp      fprintf (file, "bit_not");
285933965Sjdp      break;
286033965Sjdp    case O_multiply:
286160484Sobrien      print_binary (file, "multiply", exp);
286233965Sjdp      break;
286333965Sjdp    case O_divide:
286460484Sobrien      print_binary (file, "divide", exp);
286533965Sjdp      break;
286633965Sjdp    case O_modulus:
286760484Sobrien      print_binary (file, "modulus", exp);
286833965Sjdp      break;
286933965Sjdp    case O_left_shift:
287060484Sobrien      print_binary (file, "lshift", exp);
287133965Sjdp      break;
287233965Sjdp    case O_right_shift:
287360484Sobrien      print_binary (file, "rshift", exp);
287433965Sjdp      break;
287533965Sjdp    case O_bit_inclusive_or:
287660484Sobrien      print_binary (file, "bit_ior", exp);
287733965Sjdp      break;
287833965Sjdp    case O_bit_exclusive_or:
287960484Sobrien      print_binary (file, "bit_xor", exp);
288033965Sjdp      break;
288133965Sjdp    case O_bit_and:
288260484Sobrien      print_binary (file, "bit_and", exp);
288333965Sjdp      break;
288433965Sjdp    case O_eq:
288560484Sobrien      print_binary (file, "eq", exp);
288633965Sjdp      break;
288733965Sjdp    case O_ne:
288860484Sobrien      print_binary (file, "ne", exp);
288933965Sjdp      break;
289033965Sjdp    case O_lt:
289160484Sobrien      print_binary (file, "lt", exp);
289233965Sjdp      break;
289333965Sjdp    case O_le:
289460484Sobrien      print_binary (file, "le", exp);
289533965Sjdp      break;
289633965Sjdp    case O_ge:
289760484Sobrien      print_binary (file, "ge", exp);
289833965Sjdp      break;
289933965Sjdp    case O_gt:
290060484Sobrien      print_binary (file, "gt", exp);
290133965Sjdp      break;
290233965Sjdp    case O_logical_and:
290360484Sobrien      print_binary (file, "logical_and", exp);
290433965Sjdp      break;
290533965Sjdp    case O_logical_or:
290660484Sobrien      print_binary (file, "logical_or", exp);
290733965Sjdp      break;
290833965Sjdp    case O_add:
290933965Sjdp      indent_level++;
291033965Sjdp      fprintf (file, "add\n%*s<", indent_level * 4, "");
291133965Sjdp      print_symbol_value_1 (file, exp->X_add_symbol);
291233965Sjdp      fprintf (file, ">\n%*s<", indent_level * 4, "");
291333965Sjdp      print_symbol_value_1 (file, exp->X_op_symbol);
291433965Sjdp      fprintf (file, ">");
291533965Sjdp      goto maybe_print_addnum;
291633965Sjdp    case O_subtract:
291733965Sjdp      indent_level++;
291833965Sjdp      fprintf (file, "subtract\n%*s<", indent_level * 4, "");
291933965Sjdp      print_symbol_value_1 (file, exp->X_add_symbol);
292033965Sjdp      fprintf (file, ">\n%*s<", indent_level * 4, "");
292133965Sjdp      print_symbol_value_1 (file, exp->X_op_symbol);
292233965Sjdp      fprintf (file, ">");
292333965Sjdp      goto maybe_print_addnum;
292433965Sjdp    default:
292533965Sjdp      fprintf (file, "{unknown opcode %d}", (int) exp->X_op);
292633965Sjdp      break;
292733965Sjdp    }
292833965Sjdp  fflush (stdout);
292933965Sjdp}
293033965Sjdp
293133965Sjdpvoid
2932130561Sobrienprint_expr (expressionS *exp)
293333965Sjdp{
293433965Sjdp  print_expr_1 (stderr, exp);
293533965Sjdp  fprintf (stderr, "\n");
293633965Sjdp}
293733965Sjdp
293833965Sjdpvoid
2939130561Sobriensymbol_print_statistics (FILE *file)
294033965Sjdp{
294133965Sjdp  hash_print_statistics (file, "symbol table", sy_hash);
294260484Sobrien  hash_print_statistics (file, "mini local symbol table", local_hash);
294360484Sobrien  fprintf (file, "%lu mini local symbols created, %lu converted\n",
294460484Sobrien	   local_symbol_count, local_symbol_conversion_count);
2945218822Sdim}
2946218822Sdim
2947218822Sdim#ifdef OBJ_COMPLEX_RELC
2948218822Sdim
2949218822Sdim/* Convert given symbol to a new complex-relocation symbol name.  This
2950218822Sdim   may be a recursive function, since it might be called for non-leaf
2951218822Sdim   nodes (plain symbols) in the expression tree.  The caller owns the
2952218822Sdim   returning string, so should free it eventually.  Errors are
2953218822Sdim   indicated via as_bad and a NULL return value.  The given symbol
2954218822Sdim   is marked with sy_used_in_reloc.  */
2955218822Sdim
2956218822Sdimchar *
2957218822Sdimsymbol_relc_make_sym (symbolS * sym)
2958218822Sdim{
2959218822Sdim  char * terminal = NULL;
2960218822Sdim  const char * sname;
2961218822Sdim  char typetag;
2962218822Sdim  int sname_len;
2963218822Sdim
2964218822Sdim  assert (sym != NULL);
2965218822Sdim
2966218822Sdim  /* Recurse to symbol_relc_make_expr if this symbol
2967218822Sdim     is defined as an expression or a plain value.  */
2968218822Sdim  if (   S_GET_SEGMENT (sym) == expr_section
2969218822Sdim      || S_GET_SEGMENT (sym) == absolute_section)
2970218822Sdim    return symbol_relc_make_expr (& sym->sy_value);
2971218822Sdim
2972218822Sdim  /* This may be a "fake symbol" L0\001, referring to ".".
2973218822Sdim     Write out a special null symbol to refer to this position.  */
2974218822Sdim  if (! strcmp (S_GET_NAME (sym), FAKE_LABEL_NAME))
2975218822Sdim    return xstrdup (".");
2976218822Sdim
2977218822Sdim  /* We hope this is a plain leaf symbol.  Construct the encoding
2978218822Sdim     as {S,s}II...:CCCCCCC....
2979218822Sdim     where 'S'/'s' means section symbol / plain symbol
2980218822Sdim     III is decimal for the symbol name length
2981218822Sdim     CCC is the symbol name itself.  */
2982218822Sdim  symbol_mark_used_in_reloc (sym);
2983218822Sdim
2984218822Sdim  sname = S_GET_NAME (sym);
2985218822Sdim  sname_len = strlen (sname);
2986218822Sdim  typetag = symbol_section_p (sym) ? 'S' : 's';
2987218822Sdim
2988218822Sdim  terminal = xmalloc (1 /* S or s */
2989218822Sdim		      + 8 /* sname_len in decimal */
2990218822Sdim		      + 1 /* _ spacer */
2991218822Sdim		      + sname_len /* name itself */
2992218822Sdim		      + 1 /* \0 */ );
2993218822Sdim
2994218822Sdim  sprintf (terminal, "%c%d:%s", typetag, sname_len, sname);
2995218822Sdim  return terminal;
2996218822Sdim}
2997218822Sdim
2998218822Sdim/* Convert given value to a new complex-relocation symbol name.  This
2999218822Sdim   is a non-recursive function, since it is be called for leaf nodes
3000218822Sdim   (plain values) in the expression tree.  The caller owns the
3001218822Sdim   returning string, so should free() it eventually.  No errors.  */
3002218822Sdim
3003218822Sdimchar *
3004218822Sdimsymbol_relc_make_value (offsetT val)
3005218822Sdim{
3006218822Sdim  char * terminal = xmalloc (28);  /* Enough for long long.  */
3007218822Sdim
3008218822Sdim  terminal[0] = '#';
3009218822Sdim  sprintf_vma (& terminal[1], val);
3010218822Sdim  return terminal;
3011218822Sdim}
3012218822Sdim
3013218822Sdim/* Convert given expression to a new complex-relocation symbol name.
3014218822Sdim   This is a recursive function, since it traverses the entire given
3015218822Sdim   expression tree.  The caller owns the returning string, so should
3016218822Sdim   free() it eventually.  Errors are indicated via as_bad() and a NULL
3017218822Sdim   return value.  */
3018218822Sdim
3019218822Sdimchar *
3020218822Sdimsymbol_relc_make_expr (expressionS * exp)
3021218822Sdim{
3022218822Sdim  char * opstr = NULL; /* Operator prefix string.  */
3023218822Sdim  int    arity = 0;    /* Arity of this operator.  */
3024218822Sdim  char * operands[3];  /* Up to three operands.  */
3025218822Sdim  char * concat_string = NULL;
3026218822Sdim
3027218822Sdim  operands[0] = operands[1] = operands[2] = NULL;
3028218822Sdim
3029218822Sdim  assert (exp != NULL);
3030218822Sdim
3031218822Sdim  /* Match known operators -> fill in opstr, arity, operands[] and fall
3032218822Sdim     through to construct subexpression fragments; may instead return
3033218822Sdim     string directly for leaf nodes.  */
3034218822Sdim
3035218822Sdim  /* See expr.h for the meaning of all these enums.  Many operators
3036218822Sdim     have an unnatural arity (X_add_number implicitly added).  The
3037218822Sdim     conversion logic expands them to explicit "+" subexpressions.   */
3038218822Sdim
3039218822Sdim  switch (exp->X_op)
3040218822Sdim    {
3041218822Sdim    default:
3042218822Sdim      as_bad ("Unknown expression operator (enum %d)", exp->X_op);
3043218822Sdim      break;
3044218822Sdim
3045218822Sdim      /* Leaf nodes.  */
3046218822Sdim    case O_constant:
3047218822Sdim      return symbol_relc_make_value (exp->X_add_number);
3048218822Sdim
3049218822Sdim    case O_symbol:
3050218822Sdim      if (exp->X_add_number)
3051218822Sdim	{
3052218822Sdim	  arity = 2;
3053218822Sdim	  opstr = "+";
3054218822Sdim	  operands[0] = symbol_relc_make_sym (exp->X_add_symbol);
3055218822Sdim	  operands[1] = symbol_relc_make_value (exp->X_add_number);
3056218822Sdim	  break;
3057218822Sdim	}
3058218822Sdim      else
3059218822Sdim	return symbol_relc_make_sym (exp->X_add_symbol);
3060218822Sdim
3061218822Sdim      /* Helper macros for nesting nodes.  */
3062218822Sdim
3063218822Sdim#define HANDLE_XADD_OPT1(str_) 						\
3064218822Sdim      if (exp->X_add_number)						\
3065218822Sdim        {								\
3066218822Sdim          arity = 2;							\
3067218822Sdim          opstr = "+:" str_;						\
3068218822Sdim          operands[0] = symbol_relc_make_sym (exp->X_add_symbol);	\
3069218822Sdim          operands[1] = symbol_relc_make_value (exp->X_add_number);	\
3070218822Sdim          break;							\
3071218822Sdim        }								\
3072218822Sdim      else								\
3073218822Sdim        {								\
3074218822Sdim          arity = 1;							\
3075218822Sdim          opstr = str_;							\
3076218822Sdim          operands[0] = symbol_relc_make_sym (exp->X_add_symbol);	\
3077218822Sdim        }								\
3078218822Sdim      break
3079218822Sdim
3080218822Sdim#define HANDLE_XADD_OPT2(str_) 						\
3081218822Sdim      if (exp->X_add_number)						\
3082218822Sdim        {								\
3083218822Sdim          arity = 3;							\
3084218822Sdim          opstr = "+:" str_;						\
3085218822Sdim          operands[0] = symbol_relc_make_sym (exp->X_add_symbol);	\
3086218822Sdim          operands[1] = symbol_relc_make_sym (exp->X_op_symbol);	\
3087218822Sdim          operands[2] = symbol_relc_make_value (exp->X_add_number);	\
3088218822Sdim        }								\
3089218822Sdim      else								\
3090218822Sdim        {								\
3091218822Sdim          arity = 2;							\
3092218822Sdim          opstr = str_;							\
3093218822Sdim          operands[0] = symbol_relc_make_sym (exp->X_add_symbol);	\
3094218822Sdim          operands[1] = symbol_relc_make_sym (exp->X_op_symbol);	\
3095218822Sdim        } 								\
3096218822Sdim      break
3097218822Sdim
3098218822Sdim      /* Nesting nodes.  */
3099218822Sdim
3100218822Sdim    case O_uminus:       	HANDLE_XADD_OPT1 ("0-");
3101218822Sdim    case O_bit_not:      	HANDLE_XADD_OPT1 ("~");
3102218822Sdim    case O_logical_not:  	HANDLE_XADD_OPT1 ("!");
3103218822Sdim    case O_multiply:     	HANDLE_XADD_OPT2 ("*");
3104218822Sdim    case O_divide:       	HANDLE_XADD_OPT2 ("/");
3105218822Sdim    case O_modulus:      	HANDLE_XADD_OPT2 ("%");
3106218822Sdim    case O_left_shift:   	HANDLE_XADD_OPT2 ("<<");
3107218822Sdim    case O_right_shift:  	HANDLE_XADD_OPT2 (">>");
3108218822Sdim    case O_bit_inclusive_or:	HANDLE_XADD_OPT2 ("|");
3109218822Sdim    case O_bit_exclusive_or:	HANDLE_XADD_OPT2 ("^");
3110218822Sdim    case O_bit_and:      	HANDLE_XADD_OPT2 ("&");
3111218822Sdim    case O_add:          	HANDLE_XADD_OPT2 ("+");
3112218822Sdim    case O_subtract:     	HANDLE_XADD_OPT2 ("-");
3113218822Sdim    case O_eq:           	HANDLE_XADD_OPT2 ("==");
3114218822Sdim    case O_ne:           	HANDLE_XADD_OPT2 ("!=");
3115218822Sdim    case O_lt:           	HANDLE_XADD_OPT2 ("<");
3116218822Sdim    case O_le:           	HANDLE_XADD_OPT2 ("<=");
3117218822Sdim    case O_ge:           	HANDLE_XADD_OPT2 (">=");
3118218822Sdim    case O_gt:           	HANDLE_XADD_OPT2 (">");
3119218822Sdim    case O_logical_and:  	HANDLE_XADD_OPT2 ("&&");
3120218822Sdim    case O_logical_or:   	HANDLE_XADD_OPT2 ("||");
3121218822Sdim    }
3122218822Sdim
3123218822Sdim  /* Validate & reject early.  */
3124218822Sdim  if (arity >= 1 && ((operands[0] == NULL) || (strlen (operands[0]) == 0)))
3125218822Sdim    opstr = NULL;
3126218822Sdim  if (arity >= 2 && ((operands[1] == NULL) || (strlen (operands[1]) == 0)))
3127218822Sdim    opstr = NULL;
3128218822Sdim  if (arity >= 3 && ((operands[2] == NULL) || (strlen (operands[2]) == 0)))
3129218822Sdim    opstr = NULL;
3130218822Sdim
3131218822Sdim  if (opstr == NULL)
3132218822Sdim    concat_string = NULL;
3133218822Sdim  else
3134218822Sdim    {
3135218822Sdim      /* Allocate new string; include inter-operand padding gaps etc.  */
3136218822Sdim      concat_string = xmalloc (strlen (opstr)
3137218822Sdim			       + 1
3138218822Sdim			       + (arity >= 1 ? (strlen (operands[0]) + 1 ) : 0)
3139218822Sdim			       + (arity >= 2 ? (strlen (operands[1]) + 1 ) : 0)
3140218822Sdim			       + (arity >= 3 ? (strlen (operands[2]) + 0 ) : 0)
3141218822Sdim			       + 1);
3142218822Sdim      assert (concat_string != NULL);
3143218822Sdim
3144218822Sdim      /* Format the thing.  */
3145218822Sdim      sprintf (concat_string,
3146218822Sdim	       (arity == 0 ? "%s" :
3147218822Sdim		arity == 1 ? "%s:%s" :
3148218822Sdim		arity == 2 ? "%s:%s:%s" :
3149218822Sdim		/* arity == 3 */ "%s:%s:%s:%s"),
3150218822Sdim	       opstr, operands[0], operands[1], operands[2]);
3151218822Sdim    }
3152218822Sdim
3153218822Sdim  /* Free operand strings (not opstr).  */
3154218822Sdim  if (arity >= 1) xfree (operands[0]);
3155218822Sdim  if (arity >= 2) xfree (operands[1]);
3156218822Sdim  if (arity >= 3) xfree (operands[2]);
3157218822Sdim
3158218822Sdim  return concat_string;
3159218822Sdim}
3160218822Sdim
316160484Sobrien#endif
3162