133965Sjdp/* coff object file format
278828Sobrien   Copyright 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
3218822Sdim   1999, 2000, 2001, 2002, 2003, 2004, 2005
433965Sjdp   Free Software Foundation, Inc.
533965Sjdp
633965Sjdp   This file is part of GAS.
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
2333965Sjdp#define OBJ_HEADER "obj-coff.h"
2433965Sjdp
2533965Sjdp#include "as.h"
2633965Sjdp#include "obstack.h"
2733965Sjdp#include "subsegs.h"
2833965Sjdp
29218822Sdim#ifdef TE_PE
30218822Sdim#include "coff/pe.h"
31218822Sdim#endif
32218822Sdim
33218822Sdim#define streq(a,b)     (strcmp ((a), (b)) == 0)
34218822Sdim#define strneq(a,b,n)  (strncmp ((a), (b), (n)) == 0)
35218822Sdim
3633965Sjdp/* I think this is probably always correct.  */
3733965Sjdp#ifndef KEEP_RELOC_INFO
3833965Sjdp#define KEEP_RELOC_INFO
3933965Sjdp#endif
4033965Sjdp
41218822Sdim/* obj_coff_section will use this macro to set a new section's
42218822Sdim   attributes when a directive has no valid flags or the "w" flag is
43218822Sdim   used.  This default should be appropriate for most.  */
4477298Sobrien#ifndef TC_COFF_SECTION_DEFAULT_ATTRIBUTES
4577298Sobrien#define TC_COFF_SECTION_DEFAULT_ATTRIBUTES (SEC_LOAD | SEC_DATA)
4677298Sobrien#endif
4777298Sobrien
4889857Sobrien/* This is used to hold the symbol built by a sequence of pseudo-ops
4989857Sobrien   from .def and .endef.  */
5089857Sobrienstatic symbolS *def_symbol_in_progress;
51218822Sdim#ifdef TE_PE
52218822Sdim/* PE weak alternate symbols begin with this string.  */
53218822Sdimstatic const char weak_altprefix[] = ".weak.";
54218822Sdim#endif /* TE_PE */
5589857Sobrien
5689857Sobrientypedef struct
5789857Sobrien  {
5889857Sobrien    unsigned long chunk_size;
5989857Sobrien    unsigned long element_size;
6089857Sobrien    unsigned long size;
6189857Sobrien    char *data;
6289857Sobrien    unsigned long pointer;
6389857Sobrien  }
6489857Sobrienstack;
6589857Sobrien
6633965Sjdp
67218822Sdim/* Stack stuff.  */
6833965Sjdp
6933965Sjdpstatic stack *
70218822Sdimstack_init (unsigned long chunk_size,
71218822Sdim	    unsigned long element_size)
7233965Sjdp{
7333965Sjdp  stack *st;
7433965Sjdp
75218822Sdim  st = malloc (sizeof (* st));
7633965Sjdp  if (!st)
77218822Sdim    return NULL;
7833965Sjdp  st->data = malloc (chunk_size);
7933965Sjdp  if (!st->data)
8033965Sjdp    {
8133965Sjdp      free (st);
82218822Sdim      return NULL;
8333965Sjdp    }
8433965Sjdp  st->pointer = 0;
8533965Sjdp  st->size = chunk_size;
8633965Sjdp  st->chunk_size = chunk_size;
8733965Sjdp  st->element_size = element_size;
8833965Sjdp  return st;
8933965Sjdp}
9033965Sjdp
9133965Sjdpstatic char *
92218822Sdimstack_push (stack *st, char *element)
9333965Sjdp{
9433965Sjdp  if (st->pointer + st->element_size >= st->size)
9533965Sjdp    {
9633965Sjdp      st->size += st->chunk_size;
97218822Sdim      if ((st->data = xrealloc (st->data, st->size)) == NULL)
98218822Sdim	return NULL;
9933965Sjdp    }
10033965Sjdp  memcpy (st->data + st->pointer, element, st->element_size);
10133965Sjdp  st->pointer += st->element_size;
10233965Sjdp  return st->data + st->pointer;
10333965Sjdp}
10433965Sjdp
10533965Sjdpstatic char *
106218822Sdimstack_pop (stack *st)
10733965Sjdp{
10833965Sjdp  if (st->pointer < st->element_size)
10933965Sjdp    {
11033965Sjdp      st->pointer = 0;
111218822Sdim      return NULL;
11233965Sjdp    }
11333965Sjdp  st->pointer -= st->element_size;
11433965Sjdp  return st->data + st->pointer;
11533965Sjdp}
11633965Sjdp
117218822Sdim/* Maintain a list of the tagnames of the structures.  */
11833965Sjdp
11933965Sjdpstatic struct hash_control *tag_hash;
12033965Sjdp
12133965Sjdpstatic void
122218822Sdimtag_init (void)
12333965Sjdp{
12433965Sjdp  tag_hash = hash_new ();
12533965Sjdp}
12633965Sjdp
12733965Sjdpstatic void
128218822Sdimtag_insert (const char *name, symbolS *symbolP)
12933965Sjdp{
13033965Sjdp  const char *error_string;
13133965Sjdp
13233965Sjdp  if ((error_string = hash_jam (tag_hash, name, (char *) symbolP)))
133218822Sdim    as_fatal (_("Inserting \"%s\" into structure table failed: %s"),
134218822Sdim	      name, error_string);
13533965Sjdp}
13633965Sjdp
13733965Sjdpstatic symbolS *
138218822Sdimtag_find (char *name)
13933965Sjdp{
14033965Sjdp  return (symbolS *) hash_find (tag_hash, name);
14133965Sjdp}
14233965Sjdp
14333965Sjdpstatic symbolS *
144218822Sdimtag_find_or_make (char *name)
14533965Sjdp{
14633965Sjdp  symbolS *symbolP;
14733965Sjdp
14833965Sjdp  if ((symbolP = tag_find (name)) == NULL)
14933965Sjdp    {
15033965Sjdp      symbolP = symbol_new (name, undefined_section,
15133965Sjdp			    0, &zero_address_frag);
15233965Sjdp
15333965Sjdp      tag_insert (S_GET_NAME (symbolP), symbolP);
15433965Sjdp      symbol_table_insert (symbolP);
155218822Sdim    }
15633965Sjdp
15733965Sjdp  return symbolP;
15833965Sjdp}
15933965Sjdp
16038889Sjdp/* We accept the .bss directive to set the section for backward
16138889Sjdp   compatibility with earlier versions of gas.  */
16233965Sjdp
16338889Sjdpstatic void
164218822Sdimobj_coff_bss (int ignore ATTRIBUTE_UNUSED)
16538889Sjdp{
16638889Sjdp  if (*input_line_pointer == '\n')
16738889Sjdp    subseg_new (".bss", get_absolute_expression ());
16838889Sjdp  else
16938889Sjdp    s_lcomm (0);
17038889Sjdp}
17133965Sjdp
17233965Sjdp#define GET_FILENAME_STRING(X) \
173218822Sdim  ((char *) (&((X)->sy_symbol.ost_auxent->x_file.x_n.x_offset))[1])
17433965Sjdp
17533965Sjdp/* @@ Ick.  */
17633965Sjdpstatic segT
177218822Sdimfetch_coff_debug_section (void)
17833965Sjdp{
17933965Sjdp  static segT debug_section;
180218822Sdim
18133965Sjdp  if (!debug_section)
18233965Sjdp    {
183104834Sobrien      const asymbol *s;
184218822Sdim
185218822Sdim      s = bfd_make_debug_symbol (stdoutput, NULL, 0);
18633965Sjdp      assert (s != 0);
18733965Sjdp      debug_section = s->section;
18833965Sjdp    }
18933965Sjdp  return debug_section;
19033965Sjdp}
19133965Sjdp
19233965Sjdpvoid
193218822SdimSA_SET_SYM_ENDNDX (symbolS *sym, symbolS *val)
19433965Sjdp{
19533965Sjdp  combined_entry_type *entry, *p;
19633965Sjdp
19760484Sobrien  entry = &coffsymbol (symbol_get_bfdsym (sym))->native[1];
19860484Sobrien  p = coffsymbol (symbol_get_bfdsym (val))->native;
19933965Sjdp  entry->u.auxent.x_sym.x_fcnary.x_fcn.x_endndx.p = p;
20033965Sjdp  entry->fix_end = 1;
20133965Sjdp}
20233965Sjdp
20333965Sjdpstatic void
204218822SdimSA_SET_SYM_TAGNDX (symbolS *sym, symbolS *val)
20533965Sjdp{
20633965Sjdp  combined_entry_type *entry, *p;
20733965Sjdp
20860484Sobrien  entry = &coffsymbol (symbol_get_bfdsym (sym))->native[1];
20960484Sobrien  p = coffsymbol (symbol_get_bfdsym (val))->native;
21033965Sjdp  entry->u.auxent.x_sym.x_tagndx.p = p;
21133965Sjdp  entry->fix_tag = 1;
21233965Sjdp}
21333965Sjdp
21433965Sjdpstatic int
215218822SdimS_GET_DATA_TYPE (symbolS *sym)
21633965Sjdp{
21760484Sobrien  return coffsymbol (symbol_get_bfdsym (sym))->native->u.syment.n_type;
21833965Sjdp}
21933965Sjdp
22033965Sjdpint
221218822SdimS_SET_DATA_TYPE (symbolS *sym, int val)
22233965Sjdp{
22360484Sobrien  coffsymbol (symbol_get_bfdsym (sym))->native->u.syment.n_type = val;
22433965Sjdp  return val;
22533965Sjdp}
22633965Sjdp
22733965Sjdpint
228218822SdimS_GET_STORAGE_CLASS (symbolS *sym)
22933965Sjdp{
23060484Sobrien  return coffsymbol (symbol_get_bfdsym (sym))->native->u.syment.n_sclass;
23133965Sjdp}
23233965Sjdp
23333965Sjdpint
234218822SdimS_SET_STORAGE_CLASS (symbolS *sym, int val)
23533965Sjdp{
23660484Sobrien  coffsymbol (symbol_get_bfdsym (sym))->native->u.syment.n_sclass = val;
23733965Sjdp  return val;
23833965Sjdp}
23933965Sjdp
24077298Sobrien/* Merge a debug symbol containing debug information into a normal symbol.  */
24133965Sjdp
242218822Sdimstatic void
243218822Sdimc_symbol_merge (symbolS *debug, symbolS *normal)
24433965Sjdp{
24533965Sjdp  S_SET_DATA_TYPE (normal, S_GET_DATA_TYPE (debug));
24633965Sjdp  S_SET_STORAGE_CLASS (normal, S_GET_STORAGE_CLASS (debug));
24733965Sjdp
24833965Sjdp  if (S_GET_NUMBER_AUXILIARY (debug) > S_GET_NUMBER_AUXILIARY (normal))
249218822Sdim    /* Take the most we have.  */
250218822Sdim    S_SET_NUMBER_AUXILIARY (normal, S_GET_NUMBER_AUXILIARY (debug));
25133965Sjdp
25233965Sjdp  if (S_GET_NUMBER_AUXILIARY (debug) > 0)
253218822Sdim    /* Move all the auxiliary information.  */
254218822Sdim    memcpy (SYM_AUXINFO (normal), SYM_AUXINFO (debug),
255218822Sdim	    (S_GET_NUMBER_AUXILIARY (debug)
256218822Sdim	     * sizeof (*SYM_AUXINFO (debug))));
25733965Sjdp
25877298Sobrien  /* Move the debug flags.  */
25933965Sjdp  SF_SET_DEBUG_FIELD (normal, SF_GET_DEBUG_FIELD (debug));
26033965Sjdp}
26133965Sjdp
26233965Sjdpvoid
263218822Sdimc_dot_file_symbol (const char *filename, int appfile ATTRIBUTE_UNUSED)
26433965Sjdp{
26533965Sjdp  symbolS *symbolP;
26633965Sjdp
26760484Sobrien  /* BFD converts filename to a .file symbol with an aux entry.  It
26860484Sobrien     also handles chaining.  */
26933965Sjdp  symbolP = symbol_new (filename, bfd_abs_section_ptr, 0, &zero_address_frag);
27033965Sjdp
27133965Sjdp  S_SET_STORAGE_CLASS (symbolP, C_FILE);
27233965Sjdp  S_SET_NUMBER_AUXILIARY (symbolP, 1);
27333965Sjdp
27460484Sobrien  symbol_get_bfdsym (symbolP)->flags = BSF_DEBUGGING;
27533965Sjdp
27633965Sjdp#ifndef NO_LISTING
27733965Sjdp  {
27833965Sjdp    extern int listing;
279218822Sdim
28033965Sjdp    if (listing)
281218822Sdim      listing_source_file (filename);
28233965Sjdp  }
28333965Sjdp#endif
28433965Sjdp
285218822Sdim  /* Make sure that the symbol is first on the symbol chain.  */
28633965Sjdp  if (symbol_rootP != symbolP)
28733965Sjdp    {
28833965Sjdp      symbol_remove (symbolP, &symbol_rootP, &symbol_lastP);
28933965Sjdp      symbol_insert (symbolP, symbol_rootP, &symbol_rootP, &symbol_lastP);
290218822Sdim    }
29133965Sjdp}
29233965Sjdp
293218822Sdim/* Line number handling.  */
29433965Sjdp
295218822Sdimstruct line_no
296218822Sdim{
29733965Sjdp  struct line_no *next;
29833965Sjdp  fragS *frag;
29933965Sjdp  alent l;
30033965Sjdp};
30133965Sjdp
30233965Sjdpint coff_line_base;
30333965Sjdp
30433965Sjdp/* Symbol of last function, which we should hang line#s off of.  */
30533965Sjdpstatic symbolS *line_fsym;
30633965Sjdp
30733965Sjdp#define in_function()		(line_fsym != 0)
30833965Sjdp#define clear_function()	(line_fsym = 0)
30933965Sjdp#define set_function(F)		(line_fsym = (F), coff_add_linesym (F))
31033965Sjdp
31133965Sjdp
31233965Sjdpvoid
313218822Sdimcoff_obj_symbol_new_hook (symbolS *symbolP)
31433965Sjdp{
31560484Sobrien  long   sz = (OBJ_COFF_MAX_AUXENTRIES + 1) * sizeof (combined_entry_type);
316218822Sdim  char * s  = xmalloc (sz);
31777298Sobrien
31860484Sobrien  memset (s, 0, sz);
31960484Sobrien  coffsymbol (symbol_get_bfdsym (symbolP))->native = (combined_entry_type *) s;
32033965Sjdp
32133965Sjdp  S_SET_DATA_TYPE (symbolP, T_NULL);
32233965Sjdp  S_SET_STORAGE_CLASS (symbolP, 0);
32333965Sjdp  S_SET_NUMBER_AUXILIARY (symbolP, 0);
32433965Sjdp
32533965Sjdp  if (S_IS_STRING (symbolP))
32633965Sjdp    SF_SET_STRING (symbolP);
32777298Sobrien
32860484Sobrien  if (S_IS_LOCAL (symbolP))
32933965Sjdp    SF_SET_LOCAL (symbolP);
33033965Sjdp}
33133965Sjdp
332218822Sdimvoid
333218822Sdimcoff_obj_symbol_clone_hook (symbolS *newsymP, symbolS *orgsymP)
334218822Sdim{
335218822Sdim  long sz = (OBJ_COFF_MAX_AUXENTRIES + 1) * sizeof (combined_entry_type);
336218822Sdim  combined_entry_type * s = xmalloc (sz);
337218822Sdim
338218822Sdim  memcpy (s, coffsymbol (symbol_get_bfdsym (orgsymP))->native, sz);
339218822Sdim  coffsymbol (symbol_get_bfdsym (newsymP))->native = s;
340218822Sdim
341218822Sdim  SF_SET (newsymP, SF_GET (orgsymP));
342218822Sdim}
343218822Sdim
34433965Sjdp
345218822Sdim/* Handle .ln directives.  */
34633965Sjdp
34733965Sjdpstatic symbolS *current_lineno_sym;
34833965Sjdpstatic struct line_no *line_nos;
349218822Sdim/* FIXME:  Blindly assume all .ln directives will be in the .text section.  */
35033965Sjdpint coff_n_line_nos;
35133965Sjdp
35233965Sjdpstatic void
353218822Sdimadd_lineno (fragS * frag, addressT offset, int num)
35433965Sjdp{
355218822Sdim  struct line_no * new_line = xmalloc (sizeof (* new_line));
356218822Sdim
35733965Sjdp  if (!current_lineno_sym)
358218822Sdim    abort ();
35978828Sobrien
36078828Sobrien#ifndef OBJ_XCOFF
361218822Sdim  /* The native aix assembler accepts negative line number.  */
36278828Sobrien
36377298Sobrien  if (num <= 0)
36460484Sobrien    {
36560484Sobrien      /* Zero is used as an end marker in the file.  */
36660484Sobrien      as_warn (_("Line numbers must be positive integers\n"));
36760484Sobrien      num = 1;
36860484Sobrien    }
36978828Sobrien#endif /* OBJ_XCOFF */
37033965Sjdp  new_line->next = line_nos;
37133965Sjdp  new_line->frag = frag;
37233965Sjdp  new_line->l.line_number = num;
37333965Sjdp  new_line->l.u.offset = offset;
37433965Sjdp  line_nos = new_line;
37533965Sjdp  coff_n_line_nos++;
37633965Sjdp}
37733965Sjdp
37833965Sjdpvoid
379218822Sdimcoff_add_linesym (symbolS *sym)
38033965Sjdp{
38133965Sjdp  if (line_nos)
38233965Sjdp    {
38360484Sobrien      coffsymbol (symbol_get_bfdsym (current_lineno_sym))->lineno =
38460484Sobrien	(alent *) line_nos;
38533965Sjdp      coff_n_line_nos++;
38633965Sjdp      line_nos = 0;
38733965Sjdp    }
38833965Sjdp  current_lineno_sym = sym;
38933965Sjdp}
39033965Sjdp
39133965Sjdpstatic void
392218822Sdimobj_coff_ln (int appline)
39333965Sjdp{
39433965Sjdp  int l;
39533965Sjdp
39633965Sjdp  if (! appline && def_symbol_in_progress != NULL)
39733965Sjdp    {
39860484Sobrien      as_warn (_(".ln pseudo-op inside .def/.endef: ignored."));
39933965Sjdp      demand_empty_rest_of_line ();
40033965Sjdp      return;
40133965Sjdp    }
40233965Sjdp
40333965Sjdp  l = get_absolute_expression ();
40433965Sjdp
40589857Sobrien  /* If there is no lineno symbol, treat a .ln
40689857Sobrien     directive as if it were a .appline directive.  */
40789857Sobrien  if (appline || current_lineno_sym == NULL)
40833965Sjdp    new_logical_line ((char *) NULL, l - 1);
40989857Sobrien  else
41089857Sobrien    add_lineno (frag_now, frag_now_fix (), l);
41133965Sjdp
41233965Sjdp#ifndef NO_LISTING
41333965Sjdp  {
41433965Sjdp    extern int listing;
41533965Sjdp
41633965Sjdp    if (listing)
41733965Sjdp      {
41833965Sjdp	if (! appline)
41933965Sjdp	  l += coff_line_base - 1;
42033965Sjdp	listing_source_line (l);
42133965Sjdp      }
42233965Sjdp  }
42333965Sjdp#endif
42433965Sjdp
42533965Sjdp  demand_empty_rest_of_line ();
42633965Sjdp}
42733965Sjdp
42860484Sobrien/* .loc is essentially the same as .ln; parse it for assembler
42960484Sobrien   compatibility.  */
43060484Sobrien
43160484Sobrienstatic void
432218822Sdimobj_coff_loc (int ignore ATTRIBUTE_UNUSED)
43360484Sobrien{
43460484Sobrien  int lineno;
43560484Sobrien
43660484Sobrien  /* FIXME: Why do we need this check?  We need it for ECOFF, but why
43760484Sobrien     do we need it for COFF?  */
43860484Sobrien  if (now_seg != text_section)
43960484Sobrien    {
44060484Sobrien      as_warn (_(".loc outside of .text"));
44160484Sobrien      demand_empty_rest_of_line ();
44260484Sobrien      return;
44360484Sobrien    }
44460484Sobrien
44560484Sobrien  if (def_symbol_in_progress != NULL)
44660484Sobrien    {
44760484Sobrien      as_warn (_(".loc pseudo-op inside .def/.endef: ignored."));
44860484Sobrien      demand_empty_rest_of_line ();
44960484Sobrien      return;
45060484Sobrien    }
45160484Sobrien
45260484Sobrien  /* Skip the file number.  */
45360484Sobrien  SKIP_WHITESPACE ();
45460484Sobrien  get_absolute_expression ();
45560484Sobrien  SKIP_WHITESPACE ();
45660484Sobrien
45760484Sobrien  lineno = get_absolute_expression ();
45860484Sobrien
45960484Sobrien#ifndef NO_LISTING
46060484Sobrien  {
46160484Sobrien    extern int listing;
46260484Sobrien
46360484Sobrien    if (listing)
46460484Sobrien      {
465104834Sobrien	lineno += coff_line_base - 1;
46660484Sobrien	listing_source_line (lineno);
46760484Sobrien      }
46860484Sobrien  }
46960484Sobrien#endif
47060484Sobrien
47160484Sobrien  demand_empty_rest_of_line ();
47260484Sobrien
47360484Sobrien  add_lineno (frag_now, frag_now_fix (), lineno);
47460484Sobrien}
47560484Sobrien
47660484Sobrien/* Handle the .ident pseudo-op.  */
47760484Sobrien
47860484Sobrienstatic void
479218822Sdimobj_coff_ident (int ignore ATTRIBUTE_UNUSED)
48060484Sobrien{
48160484Sobrien  segT current_seg = now_seg;
48260484Sobrien  subsegT current_subseg = now_subseg;
48360484Sobrien
48460484Sobrien#ifdef TE_PE
48560484Sobrien  {
48660484Sobrien    segT sec;
48760484Sobrien
48860484Sobrien    /* We could put it in .comment, but that creates an extra section
48960484Sobrien       that shouldn't be loaded into memory, which requires linker
49060484Sobrien       changes...  For now, until proven otherwise, use .rdata.  */
49160484Sobrien    sec = subseg_new (".rdata$zzz", 0);
49260484Sobrien    bfd_set_section_flags (stdoutput, sec,
49360484Sobrien			   ((SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_DATA)
49460484Sobrien			    & bfd_applicable_section_flags (stdoutput)));
49560484Sobrien  }
49660484Sobrien#else
49760484Sobrien  subseg_new (".comment", 0);
49860484Sobrien#endif
49960484Sobrien
50060484Sobrien  stringer (1);
50160484Sobrien  subseg_set (current_seg, current_subseg);
50260484Sobrien}
50360484Sobrien
504218822Sdim/* Handle .def directives.
50533965Sjdp
506218822Sdim   One might ask : why can't we symbol_new if the symbol does not
507218822Sdim   already exist and fill it with debug information.  Because of
508218822Sdim   the C_EFCN special symbol. It would clobber the value of the
509218822Sdim   function symbol before we have a chance to notice that it is
510218822Sdim   a C_EFCN. And a second reason is that the code is more clear this
511218822Sdim   way. (at least I think it is :-).  */
512218822Sdim
51333965Sjdp#define SKIP_SEMI_COLON()	while (*input_line_pointer++ != ';')
51433965Sjdp#define SKIP_WHITESPACES()	while (*input_line_pointer == ' ' || \
515218822Sdim				       *input_line_pointer == '\t')  \
516218822Sdim                                  input_line_pointer++;
51733965Sjdp
51833965Sjdpstatic void
519218822Sdimobj_coff_def (int what ATTRIBUTE_UNUSED)
52033965Sjdp{
521218822Sdim  char name_end;		/* Char after the end of name.  */
522218822Sdim  char *symbol_name;		/* Name of the debug symbol.  */
523218822Sdim  char *symbol_name_copy;	/* Temporary copy of the name.  */
52433965Sjdp  unsigned int symbol_name_length;
52533965Sjdp
52633965Sjdp  if (def_symbol_in_progress != NULL)
52733965Sjdp    {
52860484Sobrien      as_warn (_(".def pseudo-op used inside of .def/.endef: ignored."));
52933965Sjdp      demand_empty_rest_of_line ();
53033965Sjdp      return;
531218822Sdim    }
53233965Sjdp
53333965Sjdp  SKIP_WHITESPACES ();
53433965Sjdp
53533965Sjdp  symbol_name = input_line_pointer;
53633965Sjdp  name_end = get_symbol_end ();
53733965Sjdp  symbol_name_length = strlen (symbol_name);
53833965Sjdp  symbol_name_copy = xmalloc (symbol_name_length + 1);
53933965Sjdp  strcpy (symbol_name_copy, symbol_name);
54033965Sjdp#ifdef tc_canonicalize_symbol_name
54133965Sjdp  symbol_name_copy = tc_canonicalize_symbol_name (symbol_name_copy);
54233965Sjdp#endif
54333965Sjdp
544218822Sdim  /* Initialize the new symbol.  */
54533965Sjdp  def_symbol_in_progress = symbol_make (symbol_name_copy);
54660484Sobrien  symbol_set_frag (def_symbol_in_progress, &zero_address_frag);
54733965Sjdp  S_SET_VALUE (def_symbol_in_progress, 0);
54833965Sjdp
54933965Sjdp  if (S_IS_STRING (def_symbol_in_progress))
55033965Sjdp    SF_SET_STRING (def_symbol_in_progress);
55133965Sjdp
55233965Sjdp  *input_line_pointer = name_end;
55333965Sjdp
55433965Sjdp  demand_empty_rest_of_line ();
55533965Sjdp}
55633965Sjdp
55733965Sjdpunsigned int dim_index;
55833965Sjdp
55933965Sjdpstatic void
560218822Sdimobj_coff_endef (int ignore ATTRIBUTE_UNUSED)
56133965Sjdp{
56277298Sobrien  symbolS *symbolP = NULL;
56360484Sobrien
56433965Sjdp  dim_index = 0;
56533965Sjdp  if (def_symbol_in_progress == NULL)
56633965Sjdp    {
56760484Sobrien      as_warn (_(".endef pseudo-op used outside of .def/.endef: ignored."));
56833965Sjdp      demand_empty_rest_of_line ();
56933965Sjdp      return;
570218822Sdim    }
57133965Sjdp
57277298Sobrien  /* Set the section number according to storage class.  */
57333965Sjdp  switch (S_GET_STORAGE_CLASS (def_symbol_in_progress))
57433965Sjdp    {
57533965Sjdp    case C_STRTAG:
57633965Sjdp    case C_ENTAG:
57733965Sjdp    case C_UNTAG:
57833965Sjdp      SF_SET_TAG (def_symbol_in_progress);
579218822Sdim      /* Fall through.  */
58033965Sjdp    case C_FILE:
58133965Sjdp    case C_TPDEF:
58233965Sjdp      SF_SET_DEBUG (def_symbol_in_progress);
58333965Sjdp      S_SET_SEGMENT (def_symbol_in_progress, fetch_coff_debug_section ());
58433965Sjdp      break;
58533965Sjdp
58633965Sjdp    case C_EFCN:
58777298Sobrien      SF_SET_LOCAL (def_symbol_in_progress);	/* Do not emit this symbol.  */
588218822Sdim      /* Fall through.  */
58933965Sjdp    case C_BLOCK:
590218822Sdim      SF_SET_PROCESS (def_symbol_in_progress);	/* Will need processing before writing.  */
591218822Sdim      /* Fall through.  */
59233965Sjdp    case C_FCN:
59333965Sjdp      {
594104834Sobrien	const char *name;
595218822Sdim
59633965Sjdp	S_SET_SEGMENT (def_symbol_in_progress, text_section);
59733965Sjdp
59860484Sobrien	name = S_GET_NAME (def_symbol_in_progress);
59960484Sobrien	if (name[0] == '.' && name[2] == 'f' && name[3] == '\0')
600104834Sobrien	  {
60160484Sobrien	    switch (name[1])
60260484Sobrien	      {
60377298Sobrien	      case 'b':
60460484Sobrien		/* .bf */
60560484Sobrien		if (! in_function ())
60660484Sobrien		  as_warn (_("`%s' symbol without preceding function"), name);
60760484Sobrien		/* Will need relocating.  */
60860484Sobrien		SF_SET_PROCESS (def_symbol_in_progress);
60960484Sobrien		clear_function ();
61060484Sobrien		break;
61160484Sobrien#ifdef TE_PE
61277298Sobrien	      case 'e':
61360484Sobrien		/* .ef */
61460484Sobrien		/* The MS compilers output the actual endline, not the
61560484Sobrien		   function-relative one... we want to match without
61660484Sobrien		   changing the assembler input.  */
61777298Sobrien		SA_SET_SYM_LNNO (def_symbol_in_progress,
61860484Sobrien				 (SA_GET_SYM_LNNO (def_symbol_in_progress)
61960484Sobrien				  + coff_line_base));
62060484Sobrien		break;
62160484Sobrien#endif
62260484Sobrien	      }
62333965Sjdp	  }
62433965Sjdp      }
62533965Sjdp      break;
62633965Sjdp
62733965Sjdp#ifdef C_AUTOARG
62833965Sjdp    case C_AUTOARG:
62933965Sjdp#endif /* C_AUTOARG */
63033965Sjdp    case C_AUTO:
63133965Sjdp    case C_REG:
63233965Sjdp    case C_ARG:
63333965Sjdp    case C_REGPARM:
63433965Sjdp    case C_FIELD:
63577298Sobrien
63677298Sobrien    /* According to the COFF documentation:
63777298Sobrien
63877298Sobrien       http://osr5doc.sco.com:1996/topics/COFF_SectNumFld.html
63977298Sobrien
64077298Sobrien       A special section number (-2) marks symbolic debugging symbols,
64177298Sobrien       including structure/union/enumeration tag names, typedefs, and
64277298Sobrien       the name of the file. A section number of -1 indicates that the
64377298Sobrien       symbol has a value but is not relocatable. Examples of
64477298Sobrien       absolute-valued symbols include automatic and register variables,
64577298Sobrien       function arguments, and .eos symbols.
64677298Sobrien
64777298Sobrien       But from Ian Lance Taylor:
64877298Sobrien
64977298Sobrien       http://sources.redhat.com/ml/binutils/2000-08/msg00202.html
65077298Sobrien
65177298Sobrien       the actual tools all marked them as section -1. So the GNU COFF
65277298Sobrien       assembler follows historical COFF assemblers.
65377298Sobrien
65477298Sobrien       However, it causes problems for djgpp
65577298Sobrien
65677298Sobrien       http://sources.redhat.com/ml/binutils/2000-08/msg00210.html
65777298Sobrien
65877298Sobrien       By defining STRICTCOFF, a COFF port can make the assembler to
65977298Sobrien       follow the documented behavior.  */
66077298Sobrien#ifdef STRICTCOFF
66177298Sobrien    case C_MOS:
66277298Sobrien    case C_MOE:
66377298Sobrien    case C_MOU:
66477298Sobrien    case C_EOS:
66577298Sobrien#endif
66633965Sjdp      SF_SET_DEBUG (def_symbol_in_progress);
66733965Sjdp      S_SET_SEGMENT (def_symbol_in_progress, absolute_section);
66833965Sjdp      break;
66933965Sjdp
67077298Sobrien#ifndef STRICTCOFF
67133965Sjdp    case C_MOS:
67233965Sjdp    case C_MOE:
67333965Sjdp    case C_MOU:
67433965Sjdp    case C_EOS:
67533965Sjdp      S_SET_SEGMENT (def_symbol_in_progress, absolute_section);
67633965Sjdp      break;
67777298Sobrien#endif
67833965Sjdp
67933965Sjdp    case C_EXT:
68060484Sobrien    case C_WEAKEXT:
68160484Sobrien#ifdef TE_PE
68260484Sobrien    case C_NT_WEAK:
68360484Sobrien#endif
68433965Sjdp    case C_STAT:
68533965Sjdp    case C_LABEL:
686218822Sdim      /* Valid but set somewhere else (s_comm, s_lcomm, colon).  */
68733965Sjdp      break;
68833965Sjdp
68960484Sobrien    default:
69033965Sjdp    case C_USTATIC:
69133965Sjdp    case C_EXTDEF:
69233965Sjdp    case C_ULABEL:
69360484Sobrien      as_warn (_("unexpected storage class %d"),
69433965Sjdp	       S_GET_STORAGE_CLASS (def_symbol_in_progress));
69533965Sjdp      break;
696218822Sdim    }
69733965Sjdp
69833965Sjdp  /* Now that we have built a debug symbol, try to find if we should
69933965Sjdp     merge with an existing symbol or not.  If a symbol is C_EFCN or
70060484Sobrien     absolute_section or untagged SEG_DEBUG it never merges.  We also
70160484Sobrien     don't merge labels, which are in a different namespace, nor
70260484Sobrien     symbols which have not yet been defined since they are typically
70360484Sobrien     unique, nor do we merge tags with non-tags.  */
70433965Sjdp
70533965Sjdp  /* Two cases for functions.  Either debug followed by definition or
70633965Sjdp     definition followed by debug.  For definition first, we will
70733965Sjdp     merge the debug symbol into the definition.  For debug first, the
70833965Sjdp     lineno entry MUST point to the definition function or else it
70933965Sjdp     will point off into space when obj_crawl_symbol_chain() merges
71033965Sjdp     the debug symbol into the real symbol.  Therefor, let's presume
71177298Sobrien     the debug symbol is a real function reference.  */
71233965Sjdp
71333965Sjdp  /* FIXME-SOON If for some reason the definition label/symbol is
71433965Sjdp     never seen, this will probably leave an undefined symbol at link
71577298Sobrien     time.  */
71633965Sjdp
71733965Sjdp  if (S_GET_STORAGE_CLASS (def_symbol_in_progress) == C_EFCN
71860484Sobrien      || S_GET_STORAGE_CLASS (def_symbol_in_progress) == C_LABEL
719218822Sdim      || (streq (bfd_get_section_name (stdoutput,
720218822Sdim				       S_GET_SEGMENT (def_symbol_in_progress)),
721218822Sdim		 "*DEBUG*")
72233965Sjdp	  && !SF_GET_TAG (def_symbol_in_progress))
72333965Sjdp      || S_GET_SEGMENT (def_symbol_in_progress) == absolute_section
72460484Sobrien      || ! symbol_constant_p (def_symbol_in_progress)
725218822Sdim      || (symbolP = symbol_find (S_GET_NAME (def_symbol_in_progress))) == NULL
72660484Sobrien      || SF_GET_TAG (def_symbol_in_progress) != SF_GET_TAG (symbolP))
72733965Sjdp    {
72860484Sobrien      /* If it already is at the end of the symbol list, do nothing */
72933965Sjdp      if (def_symbol_in_progress != symbol_lastP)
730104834Sobrien	{
73160484Sobrien	  symbol_remove (def_symbol_in_progress, &symbol_rootP, &symbol_lastP);
73260484Sobrien	  symbol_append (def_symbol_in_progress, symbol_lastP, &symbol_rootP,
73360484Sobrien			 &symbol_lastP);
734104834Sobrien	}
73533965Sjdp    }
73633965Sjdp  else
73733965Sjdp    {
73833965Sjdp      /* This symbol already exists, merge the newly created symbol
73933965Sjdp	 into the old one.  This is not mandatory. The linker can
74033965Sjdp	 handle duplicate symbols correctly. But I guess that it save
74133965Sjdp	 a *lot* of space if the assembly file defines a lot of
742218822Sdim	 symbols. [loic]  */
74333965Sjdp
74433965Sjdp      /* The debug entry (def_symbol_in_progress) is merged into the
74577298Sobrien	 previous definition.  */
74633965Sjdp
74733965Sjdp      c_symbol_merge (def_symbol_in_progress, symbolP);
74833965Sjdp      symbol_remove (def_symbol_in_progress, &symbol_rootP, &symbol_lastP);
74933965Sjdp
75033965Sjdp      def_symbol_in_progress = symbolP;
75133965Sjdp
75233965Sjdp      if (SF_GET_FUNCTION (def_symbol_in_progress)
75333965Sjdp	  || SF_GET_TAG (def_symbol_in_progress)
75433965Sjdp	  || S_GET_STORAGE_CLASS (def_symbol_in_progress) == C_STAT)
75533965Sjdp	{
75633965Sjdp	  /* For functions, and tags, and static symbols, the symbol
75733965Sjdp	     *must* be where the debug symbol appears.  Move the
75877298Sobrien	     existing symbol to the current place.  */
759218822Sdim	  /* If it already is at the end of the symbol list, do nothing.  */
76033965Sjdp	  if (def_symbol_in_progress != symbol_lastP)
76133965Sjdp	    {
76233965Sjdp	      symbol_remove (def_symbol_in_progress, &symbol_rootP, &symbol_lastP);
76333965Sjdp	      symbol_append (def_symbol_in_progress, symbol_lastP, &symbol_rootP, &symbol_lastP);
76433965Sjdp	    }
76533965Sjdp	}
76633965Sjdp    }
76733965Sjdp
76833965Sjdp  if (SF_GET_TAG (def_symbol_in_progress))
76933965Sjdp    {
77033965Sjdp      symbolS *oldtag;
77133965Sjdp
772218822Sdim      oldtag = symbol_find (S_GET_NAME (def_symbol_in_progress));
77333965Sjdp      if (oldtag == NULL || ! SF_GET_TAG (oldtag))
77433965Sjdp	tag_insert (S_GET_NAME (def_symbol_in_progress),
77533965Sjdp		    def_symbol_in_progress);
77633965Sjdp    }
77733965Sjdp
77833965Sjdp  if (SF_GET_FUNCTION (def_symbol_in_progress))
77933965Sjdp    {
78033965Sjdp      know (sizeof (def_symbol_in_progress) <= sizeof (long));
78133965Sjdp      set_function (def_symbol_in_progress);
78233965Sjdp      SF_SET_PROCESS (def_symbol_in_progress);
78333965Sjdp
78433965Sjdp      if (symbolP == NULL)
785218822Sdim	/* That is, if this is the first time we've seen the
786218822Sdim	   function.  */
787218822Sdim	symbol_table_insert (def_symbol_in_progress);
78833965Sjdp
789218822Sdim    }
790218822Sdim
79133965Sjdp  def_symbol_in_progress = NULL;
79233965Sjdp  demand_empty_rest_of_line ();
79333965Sjdp}
79433965Sjdp
79533965Sjdpstatic void
796218822Sdimobj_coff_dim (int ignore ATTRIBUTE_UNUSED)
79733965Sjdp{
79833965Sjdp  int dim_index;
79933965Sjdp
80033965Sjdp  if (def_symbol_in_progress == NULL)
80133965Sjdp    {
80260484Sobrien      as_warn (_(".dim pseudo-op used outside of .def/.endef: ignored."));
80333965Sjdp      demand_empty_rest_of_line ();
80433965Sjdp      return;
805218822Sdim    }
80633965Sjdp
80733965Sjdp  S_SET_NUMBER_AUXILIARY (def_symbol_in_progress, 1);
80833965Sjdp
80933965Sjdp  for (dim_index = 0; dim_index < DIMNUM; dim_index++)
81033965Sjdp    {
81133965Sjdp      SKIP_WHITESPACES ();
81233965Sjdp      SA_SET_SYM_DIMEN (def_symbol_in_progress, dim_index,
81333965Sjdp			get_absolute_expression ());
81433965Sjdp
81533965Sjdp      switch (*input_line_pointer)
81633965Sjdp	{
81733965Sjdp	case ',':
81833965Sjdp	  input_line_pointer++;
81933965Sjdp	  break;
82033965Sjdp
82133965Sjdp	default:
82260484Sobrien	  as_warn (_("badly formed .dim directive ignored"));
823218822Sdim	  /* Fall through.  */
82433965Sjdp	case '\n':
82533965Sjdp	case ';':
82633965Sjdp	  dim_index = DIMNUM;
82733965Sjdp	  break;
82833965Sjdp	}
82933965Sjdp    }
83033965Sjdp
83133965Sjdp  demand_empty_rest_of_line ();
83233965Sjdp}
83333965Sjdp
83433965Sjdpstatic void
835218822Sdimobj_coff_line (int ignore ATTRIBUTE_UNUSED)
83633965Sjdp{
83733965Sjdp  int this_base;
83833965Sjdp
83933965Sjdp  if (def_symbol_in_progress == NULL)
84033965Sjdp    {
84133965Sjdp      /* Probably stabs-style line?  */
84233965Sjdp      obj_coff_ln (0);
84333965Sjdp      return;
84433965Sjdp    }
84533965Sjdp
84633965Sjdp  this_base = get_absolute_expression ();
847218822Sdim  if (streq (".bf", S_GET_NAME (def_symbol_in_progress)))
84833965Sjdp    coff_line_base = this_base;
84933965Sjdp
85033965Sjdp  S_SET_NUMBER_AUXILIARY (def_symbol_in_progress, 1);
85160484Sobrien  SA_SET_SYM_LNNO (def_symbol_in_progress, this_base);
85233965Sjdp
85333965Sjdp  demand_empty_rest_of_line ();
85433965Sjdp
85533965Sjdp#ifndef NO_LISTING
856218822Sdim  if (streq (".bf", S_GET_NAME (def_symbol_in_progress)))
85733965Sjdp    {
85833965Sjdp      extern int listing;
85933965Sjdp
86033965Sjdp      if (listing)
86160484Sobrien	listing_source_line ((unsigned int) this_base);
86233965Sjdp    }
86333965Sjdp#endif
86433965Sjdp}
86533965Sjdp
86633965Sjdpstatic void
867218822Sdimobj_coff_size (int ignore ATTRIBUTE_UNUSED)
86833965Sjdp{
86933965Sjdp  if (def_symbol_in_progress == NULL)
87033965Sjdp    {
87160484Sobrien      as_warn (_(".size pseudo-op used outside of .def/.endef ignored."));
87233965Sjdp      demand_empty_rest_of_line ();
87333965Sjdp      return;
874218822Sdim    }
87533965Sjdp
87633965Sjdp  S_SET_NUMBER_AUXILIARY (def_symbol_in_progress, 1);
87733965Sjdp  SA_SET_SYM_SIZE (def_symbol_in_progress, get_absolute_expression ());
87833965Sjdp  demand_empty_rest_of_line ();
87933965Sjdp}
88033965Sjdp
88133965Sjdpstatic void
882218822Sdimobj_coff_scl (int ignore ATTRIBUTE_UNUSED)
88333965Sjdp{
88433965Sjdp  if (def_symbol_in_progress == NULL)
88533965Sjdp    {
88660484Sobrien      as_warn (_(".scl pseudo-op used outside of .def/.endef ignored."));
88733965Sjdp      demand_empty_rest_of_line ();
88833965Sjdp      return;
889218822Sdim    }
89033965Sjdp
89133965Sjdp  S_SET_STORAGE_CLASS (def_symbol_in_progress, get_absolute_expression ());
89233965Sjdp  demand_empty_rest_of_line ();
89333965Sjdp}
89433965Sjdp
89533965Sjdpstatic void
896218822Sdimobj_coff_tag (int ignore ATTRIBUTE_UNUSED)
89733965Sjdp{
89833965Sjdp  char *symbol_name;
89933965Sjdp  char name_end;
90033965Sjdp
90133965Sjdp  if (def_symbol_in_progress == NULL)
90233965Sjdp    {
90360484Sobrien      as_warn (_(".tag pseudo-op used outside of .def/.endef ignored."));
90433965Sjdp      demand_empty_rest_of_line ();
90533965Sjdp      return;
90633965Sjdp    }
90733965Sjdp
90833965Sjdp  S_SET_NUMBER_AUXILIARY (def_symbol_in_progress, 1);
90933965Sjdp  symbol_name = input_line_pointer;
91033965Sjdp  name_end = get_symbol_end ();
91133965Sjdp
91233965Sjdp#ifdef tc_canonicalize_symbol_name
91333965Sjdp  symbol_name = tc_canonicalize_symbol_name (symbol_name);
91433965Sjdp#endif
91533965Sjdp
91633965Sjdp  /* Assume that the symbol referred to by .tag is always defined.
91777298Sobrien     This was a bad assumption.  I've added find_or_make. xoxorich.  */
91833965Sjdp  SA_SET_SYM_TAGNDX (def_symbol_in_progress,
91933965Sjdp		     tag_find_or_make (symbol_name));
92033965Sjdp  if (SA_GET_SYM_TAGNDX (def_symbol_in_progress) == 0L)
921218822Sdim    as_warn (_("tag not found for .tag %s"), symbol_name);
92233965Sjdp
92333965Sjdp  SF_SET_TAGGED (def_symbol_in_progress);
92433965Sjdp  *input_line_pointer = name_end;
92533965Sjdp
92633965Sjdp  demand_empty_rest_of_line ();
92733965Sjdp}
92833965Sjdp
92933965Sjdpstatic void
930218822Sdimobj_coff_type (int ignore ATTRIBUTE_UNUSED)
93133965Sjdp{
93233965Sjdp  if (def_symbol_in_progress == NULL)
93333965Sjdp    {
93460484Sobrien      as_warn (_(".type pseudo-op used outside of .def/.endef ignored."));
93533965Sjdp      demand_empty_rest_of_line ();
93633965Sjdp      return;
937218822Sdim    }
93833965Sjdp
93933965Sjdp  S_SET_DATA_TYPE (def_symbol_in_progress, get_absolute_expression ());
94033965Sjdp
94133965Sjdp  if (ISFCN (S_GET_DATA_TYPE (def_symbol_in_progress)) &&
94233965Sjdp      S_GET_STORAGE_CLASS (def_symbol_in_progress) != C_TPDEF)
943218822Sdim    SF_SET_FUNCTION (def_symbol_in_progress);
94433965Sjdp
94533965Sjdp  demand_empty_rest_of_line ();
94633965Sjdp}
94733965Sjdp
94833965Sjdpstatic void
949218822Sdimobj_coff_val (int ignore ATTRIBUTE_UNUSED)
95033965Sjdp{
95133965Sjdp  if (def_symbol_in_progress == NULL)
95233965Sjdp    {
95360484Sobrien      as_warn (_(".val pseudo-op used outside of .def/.endef ignored."));
95433965Sjdp      demand_empty_rest_of_line ();
95533965Sjdp      return;
956218822Sdim    }
95733965Sjdp
95833965Sjdp  if (is_name_beginner (*input_line_pointer))
95933965Sjdp    {
96033965Sjdp      char *symbol_name = input_line_pointer;
96133965Sjdp      char name_end = get_symbol_end ();
96233965Sjdp
96333965Sjdp#ifdef tc_canonicalize_symbol_name
96433965Sjdp  symbol_name = tc_canonicalize_symbol_name (symbol_name);
96533965Sjdp#endif
966218822Sdim      if (streq (symbol_name, "."))
96733965Sjdp	{
968218822Sdim	  /* If the .val is != from the .def (e.g. statics).  */
96960484Sobrien	  symbol_set_frag (def_symbol_in_progress, frag_now);
97033965Sjdp	  S_SET_VALUE (def_symbol_in_progress, (valueT) frag_now_fix ());
97133965Sjdp	}
972218822Sdim      else if (! streq (S_GET_NAME (def_symbol_in_progress), symbol_name))
97333965Sjdp	{
97460484Sobrien	  expressionS exp;
97533965Sjdp
97660484Sobrien	  exp.X_op = O_symbol;
97760484Sobrien	  exp.X_add_symbol = symbol_find_or_make (symbol_name);
97860484Sobrien	  exp.X_op_symbol = NULL;
97960484Sobrien	  exp.X_add_number = 0;
98060484Sobrien	  symbol_set_value_expression (def_symbol_in_progress, &exp);
98160484Sobrien
98233965Sjdp	  /* If the segment is undefined when the forward reference is
98333965Sjdp	     resolved, then copy the segment id from the forward
98433965Sjdp	     symbol.  */
98533965Sjdp	  SF_SET_GET_SEGMENT (def_symbol_in_progress);
98660484Sobrien
98760484Sobrien	  /* FIXME: gcc can generate address expressions here in
98860484Sobrien	     unusual cases (search for "obscure" in sdbout.c).  We
98960484Sobrien	     just ignore the offset here, thus generating incorrect
99060484Sobrien	     debugging information.  We ignore the rest of the line
99160484Sobrien	     just below.  */
99233965Sjdp	}
99360484Sobrien      /* Otherwise, it is the name of a non debug symbol and its value
99477298Sobrien         will be calculated later.  */
99533965Sjdp      *input_line_pointer = name_end;
99633965Sjdp    }
99733965Sjdp  else
99833965Sjdp    {
99933965Sjdp      S_SET_VALUE (def_symbol_in_progress, get_absolute_expression ());
1000218822Sdim    }
100133965Sjdp
100233965Sjdp  demand_empty_rest_of_line ();
100333965Sjdp}
100433965Sjdp
1005218822Sdim#ifdef TE_PE
1006218822Sdim
1007218822Sdim/* Return nonzero if name begins with weak alternate symbol prefix.  */
1008218822Sdim
1009218822Sdimstatic int
1010218822Sdimweak_is_altname (const char * name)
1011218822Sdim{
1012218822Sdim  return strneq (name, weak_altprefix, sizeof (weak_altprefix) - 1);
1013218822Sdim}
1014218822Sdim
1015218822Sdim/* Return the name of the alternate symbol
1016218822Sdim   name corresponding to a weak symbol's name.  */
1017218822Sdim
1018218822Sdimstatic const char *
1019218822Sdimweak_name2altname (const char * name)
1020218822Sdim{
1021218822Sdim  char *alt_name;
1022218822Sdim
1023218822Sdim  alt_name = xmalloc (sizeof (weak_altprefix) + strlen (name));
1024218822Sdim  strcpy (alt_name, weak_altprefix);
1025218822Sdim  return strcat (alt_name, name);
1026218822Sdim}
1027218822Sdim
1028218822Sdim/* Return the name of the weak symbol corresponding to an
1029218822Sdim   alternate symbol.  */
1030218822Sdim
1031218822Sdimstatic const char *
1032218822Sdimweak_altname2name (const char * name)
1033218822Sdim{
1034218822Sdim  char * weak_name;
1035218822Sdim  char * dot;
1036218822Sdim
1037218822Sdim  assert (weak_is_altname (name));
1038218822Sdim
1039218822Sdim  weak_name = xstrdup (name + 6);
1040218822Sdim  if ((dot = strchr (weak_name, '.')))
1041218822Sdim    *dot = 0;
1042218822Sdim  return weak_name;
1043218822Sdim}
1044218822Sdim
1045218822Sdim/* Make a weak symbol name unique by
1046218822Sdim   appending the name of an external symbol.  */
1047218822Sdim
1048218822Sdimstatic const char *
1049218822Sdimweak_uniquify (const char * name)
1050218822Sdim{
1051218822Sdim  char *ret;
1052218822Sdim  const char * unique = "";
1053218822Sdim
1054218822Sdim#ifdef USE_UNIQUE
1055218822Sdim  if (an_external_name != NULL)
1056218822Sdim    unique = an_external_name;
1057218822Sdim#endif
1058218822Sdim  assert (weak_is_altname (name));
1059218822Sdim
1060218822Sdim  if (strchr (name + sizeof (weak_altprefix), '.'))
1061218822Sdim    return name;
1062218822Sdim
1063218822Sdim  ret = xmalloc (strlen (name) + strlen (unique) + 2);
1064218822Sdim  strcpy (ret, name);
1065218822Sdim  strcat (ret, ".");
1066218822Sdim  strcat (ret, unique);
1067218822Sdim  return ret;
1068218822Sdim}
1069218822Sdim
107033965Sjdpvoid
1071218822Sdimpecoff_obj_set_weak_hook (symbolS *symbolP)
107233965Sjdp{
1073218822Sdim  symbolS *alternateP;
1074218822Sdim
1075218822Sdim  /* See _Microsoft Portable Executable and Common Object
1076218822Sdim     File Format Specification_, section 5.5.3.
1077218822Sdim     Create a symbol representing the alternate value.
1078218822Sdim     coff_frob_symbol will set the value of this symbol from
1079218822Sdim     the value of the weak symbol itself.  */
1080218822Sdim  S_SET_STORAGE_CLASS (symbolP, C_NT_WEAK);
1081218822Sdim  S_SET_NUMBER_AUXILIARY (symbolP, 1);
1082218822Sdim  SA_SET_SYM_FSIZE (symbolP, IMAGE_WEAK_EXTERN_SEARCH_NOLIBRARY);
1083218822Sdim
1084218822Sdim  alternateP = symbol_find_or_make (weak_name2altname (S_GET_NAME (symbolP)));
1085218822Sdim  S_SET_EXTERNAL (alternateP);
1086218822Sdim  S_SET_STORAGE_CLASS (alternateP, C_NT_WEAK);
1087218822Sdim
1088218822Sdim  SA_SET_SYM_TAGNDX (symbolP, alternateP);
1089218822Sdim}
1090218822Sdim
1091218822Sdimvoid
1092218822Sdimpecoff_obj_clear_weak_hook (symbolS *symbolP)
1093218822Sdim{
1094218822Sdim  symbolS *alternateP;
1095218822Sdim
1096218822Sdim  S_SET_STORAGE_CLASS (symbolP, 0);
1097218822Sdim  SA_SET_SYM_FSIZE (symbolP, 0);
1098218822Sdim
1099218822Sdim  alternateP = symbol_find (weak_name2altname (S_GET_NAME (symbolP)));
1100218822Sdim  S_CLEAR_EXTERNAL (alternateP);
1101218822Sdim}
1102218822Sdim
1103218822Sdim#endif  /* TE_PE */
1104218822Sdim
1105218822Sdim/* Handle .weak.  This is a GNU extension in formats other than PE. */
1106218822Sdim
1107218822Sdimstatic void
1108218822Sdimobj_coff_weak (int ignore ATTRIBUTE_UNUSED)
1109218822Sdim{
1110218822Sdim  char *name;
1111218822Sdim  int c;
1112218822Sdim  symbolS *symbolP;
1113218822Sdim
1114218822Sdim  do
1115218822Sdim    {
1116218822Sdim      name = input_line_pointer;
1117218822Sdim      c = get_symbol_end ();
1118218822Sdim      if (*name == 0)
1119218822Sdim	{
1120218822Sdim	  as_warn (_("badly formed .weak directive ignored"));
1121218822Sdim	  ignore_rest_of_line ();
1122218822Sdim	  return;
1123218822Sdim	}
1124218822Sdim      c = 0;
1125218822Sdim      symbolP = symbol_find_or_make (name);
1126218822Sdim      *input_line_pointer = c;
1127218822Sdim      SKIP_WHITESPACE ();
1128218822Sdim      S_SET_WEAK (symbolP);
1129218822Sdim
1130218822Sdim      if (c == ',')
1131218822Sdim	{
1132218822Sdim	  input_line_pointer++;
1133218822Sdim	  SKIP_WHITESPACE ();
1134218822Sdim	  if (*input_line_pointer == '\n')
1135218822Sdim	    c = '\n';
1136218822Sdim	}
1137218822Sdim
1138218822Sdim    }
1139218822Sdim  while (c == ',');
1140218822Sdim
1141218822Sdim  demand_empty_rest_of_line ();
1142218822Sdim}
1143218822Sdim
1144218822Sdimvoid
1145218822Sdimcoff_obj_read_begin_hook (void)
1146218822Sdim{
114777298Sobrien  /* These had better be the same.  Usually 18 bytes.  */
114833965Sjdp  know (sizeof (SYMENT) == sizeof (AUXENT));
114933965Sjdp  know (SYMESZ == AUXESZ);
115033965Sjdp  tag_init ();
115133965Sjdp}
115233965Sjdp
115333965SjdpsymbolS *coff_last_function;
1154130561Sobrien#ifndef OBJ_XCOFF
115533965Sjdpstatic symbolS *coff_last_bf;
1156130561Sobrien#endif
115733965Sjdp
115833965Sjdpvoid
1159218822Sdimcoff_frob_symbol (symbolS *symp, int *punt)
116033965Sjdp{
116133965Sjdp  static symbolS *last_tagP;
116233965Sjdp  static stack *block_stack;
116333965Sjdp  static symbolS *set_end;
116433965Sjdp  symbolS *next_set_end = NULL;
116533965Sjdp
116633965Sjdp  if (symp == &abs_symbol)
116733965Sjdp    {
116833965Sjdp      *punt = 1;
116933965Sjdp      return;
117033965Sjdp    }
117133965Sjdp
117233965Sjdp  if (current_lineno_sym)
1173218822Sdim    coff_add_linesym (NULL);
117433965Sjdp
117533965Sjdp  if (!block_stack)
117633965Sjdp    block_stack = stack_init (512, sizeof (symbolS*));
117733965Sjdp
1178218822Sdim#ifdef TE_PE
1179218822Sdim  if (S_GET_STORAGE_CLASS (symp) == C_NT_WEAK
1180218822Sdim      && ! S_IS_WEAK (symp)
1181218822Sdim      && weak_is_altname (S_GET_NAME (symp)))
118260484Sobrien    {
1183218822Sdim      /* This is a weak alternate symbol.  All processing of
1184218822Sdim	 PECOFFweak symbols is done here, through the alternate.  */
1185218822Sdim      symbolS *weakp = symbol_find_noref (weak_altname2name
1186218822Sdim					  (S_GET_NAME (symp)), 1);
1187218822Sdim
1188218822Sdim      assert (weakp);
1189218822Sdim      assert (S_GET_NUMBER_AUXILIARY (weakp) == 1);
1190218822Sdim
1191218822Sdim      if (! S_IS_WEAK (weakp))
1192218822Sdim	{
1193218822Sdim	  /* The symbol was turned from weak to strong.  Discard altname.  */
1194218822Sdim	  *punt = 1;
1195218822Sdim	  return;
1196218822Sdim	}
1197218822Sdim      else if (symbol_equated_p (weakp))
1198218822Sdim	{
1199218822Sdim	  /* The weak symbol has an alternate specified; symp is unneeded.  */
1200218822Sdim	  S_SET_STORAGE_CLASS (weakp, C_NT_WEAK);
1201218822Sdim	  SA_SET_SYM_TAGNDX (weakp,
1202218822Sdim	    symbol_get_value_expression (weakp)->X_add_symbol);
1203218822Sdim
1204218822Sdim	  S_CLEAR_EXTERNAL (symp);
1205218822Sdim	  *punt = 1;
1206218822Sdim	  return;
1207218822Sdim	}
1208218822Sdim      else
1209218822Sdim	{
1210218822Sdim	  /* The weak symbol has been assigned an alternate value.
1211218822Sdim             Copy this value to symp, and set symp as weakp's alternate.  */
1212218822Sdim	  if (S_GET_STORAGE_CLASS (weakp) != C_NT_WEAK)
1213218822Sdim	    {
1214218822Sdim	      S_SET_STORAGE_CLASS (symp, S_GET_STORAGE_CLASS (weakp));
1215218822Sdim	      S_SET_STORAGE_CLASS (weakp, C_NT_WEAK);
1216218822Sdim	    }
1217218822Sdim
1218218822Sdim	  if (S_IS_DEFINED (weakp))
1219218822Sdim	    {
1220218822Sdim	      /* This is a defined weak symbol.  Copy value information
1221218822Sdim	         from the weak symbol itself to the alternate symbol.  */
1222218822Sdim	      symbol_set_value_expression (symp,
1223218822Sdim					   symbol_get_value_expression (weakp));
1224218822Sdim	      symbol_set_frag (symp, symbol_get_frag (weakp));
1225218822Sdim	      S_SET_SEGMENT (symp, S_GET_SEGMENT (weakp));
1226218822Sdim	    }
1227218822Sdim	  else
1228218822Sdim	    {
1229218822Sdim	      /* This is an undefined weak symbol.
1230218822Sdim		 Define the alternate symbol to zero.  */
1231218822Sdim	      S_SET_VALUE (symp, 0);
1232218822Sdim	      S_SET_SEGMENT (symp, absolute_section);
1233218822Sdim	    }
1234218822Sdim
1235218822Sdim	  S_SET_NAME (symp, weak_uniquify (S_GET_NAME (symp)));
1236218822Sdim	  S_SET_STORAGE_CLASS (symp, C_EXT);
1237218822Sdim
1238218822Sdim	  S_SET_VALUE (weakp, 0);
1239218822Sdim	  S_SET_SEGMENT (weakp, undefined_section);
1240218822Sdim	}
124160484Sobrien    }
1242218822Sdim#else /* TE_PE */
1243218822Sdim  if (S_IS_WEAK (symp))
1244218822Sdim    S_SET_STORAGE_CLASS (symp, C_WEAKEXT);
1245218822Sdim#endif /* TE_PE */
124660484Sobrien
124760484Sobrien  if (!S_IS_DEFINED (symp)
124860484Sobrien      && !S_IS_WEAK (symp)
124960484Sobrien      && S_GET_STORAGE_CLASS (symp) != C_STAT)
125033965Sjdp    S_SET_STORAGE_CLASS (symp, C_EXT);
125133965Sjdp
125233965Sjdp  if (!SF_GET_DEBUG (symp))
125333965Sjdp    {
125489857Sobrien      symbolS * real;
125589857Sobrien
125633965Sjdp      if (!SF_GET_LOCAL (symp)
125733965Sjdp	  && !SF_GET_STATICS (symp)
125877298Sobrien	  && S_GET_STORAGE_CLASS (symp) != C_LABEL
1259218822Sdim	  && symbol_constant_p (symp)
1260218822Sdim	  && (real = symbol_find_noref (S_GET_NAME (symp), 1))
126189857Sobrien	  && S_GET_STORAGE_CLASS (real) == C_NULL
126233965Sjdp	  && real != symp)
126333965Sjdp	{
126433965Sjdp	  c_symbol_merge (symp, real);
126533965Sjdp	  *punt = 1;
126677298Sobrien	  return;
126733965Sjdp	}
126889857Sobrien
126933965Sjdp      if (!S_IS_DEFINED (symp) && !SF_GET_LOCAL (symp))
127033965Sjdp	{
127133965Sjdp	  assert (S_GET_VALUE (symp) == 0);
1272218822Sdim	  if (S_IS_WEAKREFD (symp))
1273218822Sdim	    *punt = 1;
1274218822Sdim	  else
1275218822Sdim	    S_SET_EXTERNAL (symp);
127633965Sjdp	}
127733965Sjdp      else if (S_GET_STORAGE_CLASS (symp) == C_NULL)
127833965Sjdp	{
127933965Sjdp	  if (S_GET_SEGMENT (symp) == text_section
128033965Sjdp	      && symp != seg_info (text_section)->sym)
128133965Sjdp	    S_SET_STORAGE_CLASS (symp, C_LABEL);
128233965Sjdp	  else
128333965Sjdp	    S_SET_STORAGE_CLASS (symp, C_STAT);
128433965Sjdp	}
128589857Sobrien
128633965Sjdp      if (SF_GET_PROCESS (symp))
128733965Sjdp	{
128833965Sjdp	  if (S_GET_STORAGE_CLASS (symp) == C_BLOCK)
128933965Sjdp	    {
1290218822Sdim	      if (streq (S_GET_NAME (symp), ".bb"))
129133965Sjdp		stack_push (block_stack, (char *) &symp);
129233965Sjdp	      else
129333965Sjdp		{
129433965Sjdp		  symbolS *begin;
129589857Sobrien
129633965Sjdp		  begin = *(symbolS **) stack_pop (block_stack);
129733965Sjdp		  if (begin == 0)
129860484Sobrien		    as_warn (_("mismatched .eb"));
129933965Sjdp		  else
130033965Sjdp		    next_set_end = begin;
130133965Sjdp		}
130233965Sjdp	    }
130389857Sobrien
130433965Sjdp	  if (coff_last_function == 0 && SF_GET_FUNCTION (symp))
130533965Sjdp	    {
130633965Sjdp	      union internal_auxent *auxp;
130789857Sobrien
130833965Sjdp	      coff_last_function = symp;
130933965Sjdp	      if (S_GET_NUMBER_AUXILIARY (symp) < 1)
131033965Sjdp		S_SET_NUMBER_AUXILIARY (symp, 1);
131160484Sobrien	      auxp = SYM_AUXENT (symp);
131233965Sjdp	      memset (auxp->x_sym.x_fcnary.x_ary.x_dimen, 0,
131333965Sjdp		      sizeof (auxp->x_sym.x_fcnary.x_ary.x_dimen));
131433965Sjdp	    }
131589857Sobrien
131633965Sjdp	  if (S_GET_STORAGE_CLASS (symp) == C_EFCN)
131733965Sjdp	    {
131833965Sjdp	      if (coff_last_function == 0)
1319218822Sdim		as_fatal (_("C_EFCN symbol for %s out of scope"),
1320218822Sdim			  S_GET_NAME (symp));
132133965Sjdp	      SA_SET_SYM_FSIZE (coff_last_function,
132233965Sjdp				(long) (S_GET_VALUE (symp)
132333965Sjdp					- S_GET_VALUE (coff_last_function)));
132433965Sjdp	      next_set_end = coff_last_function;
132533965Sjdp	      coff_last_function = 0;
132633965Sjdp	    }
132733965Sjdp	}
132889857Sobrien
132933965Sjdp      if (S_IS_EXTERNAL (symp))
133033965Sjdp	S_SET_STORAGE_CLASS (symp, C_EXT);
133133965Sjdp      else if (SF_GET_LOCAL (symp))
133233965Sjdp	*punt = 1;
133333965Sjdp
133433965Sjdp      if (SF_GET_FUNCTION (symp))
133560484Sobrien	symbol_get_bfdsym (symp)->flags |= BSF_FUNCTION;
133633965Sjdp    }
133733965Sjdp
133860484Sobrien  /* Double check weak symbols.  */
133960484Sobrien  if (S_IS_WEAK (symp) && S_IS_COMMON (symp))
134060484Sobrien    as_bad (_("Symbol `%s' can not be both weak and common"),
134160484Sobrien	    S_GET_NAME (symp));
134260484Sobrien
134333965Sjdp  if (SF_GET_TAG (symp))
134433965Sjdp    last_tagP = symp;
134533965Sjdp  else if (S_GET_STORAGE_CLASS (symp) == C_EOS)
134633965Sjdp    next_set_end = last_tagP;
134733965Sjdp
134833965Sjdp#ifdef OBJ_XCOFF
134933965Sjdp  /* This is pretty horrible, but we have to set *punt correctly in
135033965Sjdp     order to call SA_SET_SYM_ENDNDX correctly.  */
135160484Sobrien  if (! symbol_used_in_reloc_p (symp)
135260484Sobrien      && ((symbol_get_bfdsym (symp)->flags & BSF_SECTION_SYM) != 0
1353218822Sdim	  || (! (S_IS_EXTERNAL (symp) || S_IS_WEAK (symp))
135460484Sobrien	      && ! symbol_get_tc (symp)->output
135533965Sjdp	      && S_GET_STORAGE_CLASS (symp) != C_FILE)))
135633965Sjdp    *punt = 1;
135733965Sjdp#endif
135833965Sjdp
135933965Sjdp  if (set_end != (symbolS *) NULL
136033965Sjdp      && ! *punt
136160484Sobrien      && ((symbol_get_bfdsym (symp)->flags & BSF_NOT_AT_END) != 0
136233965Sjdp	  || (S_IS_DEFINED (symp)
136333965Sjdp	      && ! S_IS_COMMON (symp)
136433965Sjdp	      && (! S_IS_EXTERNAL (symp) || SF_GET_FUNCTION (symp)))))
136533965Sjdp    {
136633965Sjdp      SA_SET_SYM_ENDNDX (set_end, symp);
136733965Sjdp      set_end = NULL;
136833965Sjdp    }
136933965Sjdp
137060484Sobrien  if (next_set_end != NULL)
137160484Sobrien    {
137260484Sobrien      if (set_end != NULL)
137360484Sobrien	as_warn ("Warning: internal error: forgetting to set endndx of %s",
137460484Sobrien		 S_GET_NAME (set_end));
137560484Sobrien      set_end = next_set_end;
137660484Sobrien    }
137733965Sjdp
137889857Sobrien#ifndef OBJ_XCOFF
137933965Sjdp  if (! *punt
138033965Sjdp      && S_GET_STORAGE_CLASS (symp) == C_FCN
1381218822Sdim      && streq (S_GET_NAME (symp), ".bf"))
138233965Sjdp    {
138333965Sjdp      if (coff_last_bf != NULL)
138433965Sjdp	SA_SET_SYM_ENDNDX (coff_last_bf, symp);
138533965Sjdp      coff_last_bf = symp;
138633965Sjdp    }
138789857Sobrien#endif
138860484Sobrien  if (coffsymbol (symbol_get_bfdsym (symp))->lineno)
138933965Sjdp    {
139033965Sjdp      int i;
139133965Sjdp      struct line_no *lptr;
139233965Sjdp      alent *l;
139333965Sjdp
139460484Sobrien      lptr = (struct line_no *) coffsymbol (symbol_get_bfdsym (symp))->lineno;
139533965Sjdp      for (i = 0; lptr; lptr = lptr->next)
139633965Sjdp	i++;
139760484Sobrien      lptr = (struct line_no *) coffsymbol (symbol_get_bfdsym (symp))->lineno;
139833965Sjdp
139933965Sjdp      /* We need i entries for line numbers, plus 1 for the first
140033965Sjdp	 entry which BFD will override, plus 1 for the last zero
140133965Sjdp	 entry (a marker for BFD).  */
1402218822Sdim      l = xmalloc ((i + 2) * sizeof (* l));
140360484Sobrien      coffsymbol (symbol_get_bfdsym (symp))->lineno = l;
140433965Sjdp      l[i + 1].line_number = 0;
140533965Sjdp      l[i + 1].u.sym = NULL;
140633965Sjdp      for (; i > 0; i--)
140733965Sjdp	{
140833965Sjdp	  if (lptr->frag)
140960484Sobrien	    lptr->l.u.offset += lptr->frag->fr_address / OCTETS_PER_BYTE;
141033965Sjdp	  l[i] = lptr->l;
141133965Sjdp	  lptr = lptr->next;
141233965Sjdp	}
141333965Sjdp    }
141433965Sjdp}
141533965Sjdp
141633965Sjdpvoid
1417218822Sdimcoff_adjust_section_syms (bfd *abfd ATTRIBUTE_UNUSED,
1418218822Sdim			  asection *sec,
1419218822Sdim			  void * x ATTRIBUTE_UNUSED)
142033965Sjdp{
142133965Sjdp  symbolS *secsym;
142233965Sjdp  segment_info_type *seginfo = seg_info (sec);
142333965Sjdp  int nlnno, nrelocs = 0;
142433965Sjdp
142533965Sjdp  /* RS/6000 gas creates a .debug section manually in ppc_frob_file in
142633965Sjdp     tc-ppc.c.  Do not get confused by it.  */
142733965Sjdp  if (seginfo == NULL)
142833965Sjdp    return;
142933965Sjdp
1430218822Sdim  if (streq (sec->name, ".text"))
143133965Sjdp    nlnno = coff_n_line_nos;
143233965Sjdp  else
143333965Sjdp    nlnno = 0;
143433965Sjdp  {
143533965Sjdp    /* @@ Hope that none of the fixups expand to more than one reloc
143633965Sjdp       entry...  */
143733965Sjdp    fixS *fixp = seginfo->fix_root;
143833965Sjdp    while (fixp)
143933965Sjdp      {
144038889Sjdp	if (! fixp->fx_done)
144138889Sjdp	  nrelocs++;
144233965Sjdp	fixp = fixp->fx_next;
144333965Sjdp      }
144433965Sjdp  }
1445218822Sdim  if (bfd_get_section_size (sec) == 0
144633965Sjdp      && nrelocs == 0
144733965Sjdp      && nlnno == 0
144833965Sjdp      && sec != text_section
144933965Sjdp      && sec != data_section
145033965Sjdp      && sec != bss_section)
145133965Sjdp    return;
1452218822Sdim
145333965Sjdp  secsym = section_symbol (sec);
145460484Sobrien  /* This is an estimate; we'll plug in the real value using
145560484Sobrien     SET_SECTION_RELOCS later */
145633965Sjdp  SA_SET_SCN_NRELOC (secsym, nrelocs);
145733965Sjdp  SA_SET_SCN_NLINNO (secsym, nlnno);
145833965Sjdp}
145933965Sjdp
146033965Sjdpvoid
1461218822Sdimcoff_frob_file_after_relocs (void)
146233965Sjdp{
1463218822Sdim  bfd_map_over_sections (stdoutput, coff_adjust_section_syms, NULL);
146433965Sjdp}
146533965Sjdp
1466104834Sobrien/* Implement the .section pseudo op:
1467104834Sobrien  	.section name {, "flags"}
1468104834Sobrien                  ^         ^
1469104834Sobrien                  |         +--- optional flags: 'b' for bss
1470104834Sobrien                  |                              'i' for info
1471104834Sobrien                  +-- section name               'l' for lib
1472104834Sobrien                                                 'n' for noload
1473104834Sobrien                                                 'o' for over
1474104834Sobrien                                                 'w' for data
1475104834Sobrien  						 'd' (apparently m88k for data)
1476104834Sobrien                                                 'x' for text
1477104834Sobrien  						 'r' for read-only data
1478104834Sobrien  						 's' for shared data (PE)
1479104834Sobrien   But if the argument is not a quoted string, treat it as a
1480104834Sobrien   subsegment number.
148133965Sjdp
1482104834Sobrien   Note the 'a' flag is silently ignored.  This allows the same
1483104834Sobrien   .section directive to be parsed in both ELF and COFF formats.  */
1484104834Sobrien
148533965Sjdpvoid
1486218822Sdimobj_coff_section (int ignore ATTRIBUTE_UNUSED)
148733965Sjdp{
1488218822Sdim  /* Strip out the section name.  */
148933965Sjdp  char *section_name;
149033965Sjdp  char c;
149133965Sjdp  char *name;
149233965Sjdp  unsigned int exp;
149377298Sobrien  flagword flags, oldflags;
149433965Sjdp  asection *sec;
149533965Sjdp
149633965Sjdp  if (flag_mri)
149733965Sjdp    {
149833965Sjdp      char type;
149933965Sjdp
150033965Sjdp      s_mri_sect (&type);
150133965Sjdp      return;
150233965Sjdp    }
150333965Sjdp
150433965Sjdp  section_name = input_line_pointer;
150533965Sjdp  c = get_symbol_end ();
150633965Sjdp
150733965Sjdp  name = xmalloc (input_line_pointer - section_name + 1);
150833965Sjdp  strcpy (name, section_name);
150933965Sjdp
151033965Sjdp  *input_line_pointer = c;
151133965Sjdp
151233965Sjdp  SKIP_WHITESPACE ();
151333965Sjdp
151433965Sjdp  exp = 0;
151577298Sobrien  flags = SEC_NO_FLAGS;
151633965Sjdp
151733965Sjdp  if (*input_line_pointer == ',')
151833965Sjdp    {
151933965Sjdp      ++input_line_pointer;
152033965Sjdp      SKIP_WHITESPACE ();
152133965Sjdp      if (*input_line_pointer != '"')
152233965Sjdp	exp = get_absolute_expression ();
152333965Sjdp      else
152433965Sjdp	{
1525218822Sdim	  unsigned char attr;
1526218822Sdim	  int readonly_removed = 0;
1527218822Sdim	  int load_removed = 0;
1528218822Sdim
1529218822Sdim	  while (attr = *++input_line_pointer,
1530218822Sdim		 attr != '"'
1531218822Sdim		 && ! is_end_of_line[attr])
153233965Sjdp	    {
1533218822Sdim	      switch (attr)
153433965Sjdp		{
1535218822Sdim		case 'b':
1536218822Sdim		  /* Uninitialised data section.  */
1537218822Sdim		  flags |= SEC_ALLOC;
1538218822Sdim		  flags &=~ SEC_LOAD;
1539218822Sdim		  break;
1540130561Sobrien
1541218822Sdim		case 'n':
1542218822Sdim		  /* Section not loaded.  */
1543218822Sdim		  flags &=~ SEC_LOAD;
1544218822Sdim		  flags |= SEC_NEVER_LOAD;
1545218822Sdim		  load_removed = 1;
1546218822Sdim		  break;
1547130561Sobrien
1548218822Sdim		case 's':
1549218822Sdim		  /* Shared section.  */
1550218822Sdim		  flags |= SEC_COFF_SHARED;
1551218822Sdim		  /* Fall through.  */
1552218822Sdim		case 'd':
1553218822Sdim		  /* Data section.  */
1554218822Sdim		  flags |= SEC_DATA;
1555218822Sdim		  if (! load_removed)
1556218822Sdim		    flags |= SEC_LOAD;
1557218822Sdim		  flags &=~ SEC_READONLY;
1558218822Sdim		  break;
155933965Sjdp
1560218822Sdim		case 'w':
1561218822Sdim		  /* Writable section.  */
1562218822Sdim		  flags &=~ SEC_READONLY;
1563218822Sdim		  readonly_removed = 1;
1564218822Sdim		  break;
1565218822Sdim
1566218822Sdim		case 'a':
1567218822Sdim		  /* Ignore.  Here for compatibility with ELF.  */
1568218822Sdim		  break;
1569218822Sdim
1570218822Sdim		case 'r': /* Read-only section.  Implies a data section.  */
1571218822Sdim		  readonly_removed = 0;
1572218822Sdim		  /* Fall through.  */
1573218822Sdim		case 'x': /* Executable section.  */
1574218822Sdim		  /* If we are setting the 'x' attribute or if the 'r'
1575218822Sdim		     attribute is being used to restore the readonly status
1576218822Sdim		     of a code section (eg "wxr") then set the SEC_CODE flag,
1577218822Sdim		     otherwise set the SEC_DATA flag.  */
1578218822Sdim		  flags |= (attr == 'x' || (flags & SEC_CODE) ? SEC_CODE : SEC_DATA);
1579218822Sdim		  if (! load_removed)
1580218822Sdim		    flags |= SEC_LOAD;
1581218822Sdim		  /* Note - the READONLY flag is set here, even for the 'x'
1582218822Sdim		     attribute in order to be compatible with the MSVC
1583218822Sdim		     linker.  */
1584218822Sdim		  if (! readonly_removed)
1585218822Sdim		    flags |= SEC_READONLY;
1586218822Sdim		  break;
1587218822Sdim
158833965Sjdp		case 'i': /* STYP_INFO */
158933965Sjdp		case 'l': /* STYP_LIB */
159033965Sjdp		case 'o': /* STYP_OVER */
1591218822Sdim		  as_warn (_("unsupported section attribute '%c'"), attr);
159233965Sjdp		  break;
159333965Sjdp
159433965Sjdp		default:
1595218822Sdim		  as_warn (_("unknown section attribute '%c'"), attr);
159633965Sjdp		  break;
159733965Sjdp		}
159833965Sjdp	    }
1599218822Sdim	  if (attr == '"')
160033965Sjdp	    ++input_line_pointer;
160133965Sjdp	}
160233965Sjdp    }
160333965Sjdp
160433965Sjdp  sec = subseg_new (name, (subsegT) exp);
160533965Sjdp
160677298Sobrien  oldflags = bfd_get_section_flags (stdoutput, sec);
160777298Sobrien  if (oldflags == SEC_NO_FLAGS)
160833965Sjdp    {
160977298Sobrien      /* Set section flags for a new section just created by subseg_new.
161077298Sobrien         Provide a default if no flags were parsed.  */
161177298Sobrien      if (flags == SEC_NO_FLAGS)
161277298Sobrien	flags = TC_COFF_SECTION_DEFAULT_ATTRIBUTES;
161360484Sobrien
161477298Sobrien#ifdef COFF_LONG_SECTION_NAMES
161577298Sobrien      /* Add SEC_LINK_ONCE and SEC_LINK_DUPLICATES_DISCARD to .gnu.linkonce
161677298Sobrien         sections so adjust_reloc_syms in write.c will correctly handle
161777298Sobrien         relocs which refer to non-local symbols in these sections.  */
1618218822Sdim      if (strneq (name, ".gnu.linkonce", sizeof (".gnu.linkonce") - 1))
1619104834Sobrien	flags |= SEC_LINK_ONCE | SEC_LINK_DUPLICATES_DISCARD;
162077298Sobrien#endif
162160484Sobrien
162233965Sjdp      if (! bfd_set_section_flags (stdoutput, sec, flags))
1623104834Sobrien	as_warn (_("error setting flags for \"%s\": %s"),
1624104834Sobrien		 bfd_section_name (stdoutput, sec),
1625104834Sobrien		 bfd_errmsg (bfd_get_error ()));
162633965Sjdp    }
162777298Sobrien  else if (flags != SEC_NO_FLAGS)
162877298Sobrien    {
1629218822Sdim      /* This section's attributes have already been set.  Warn if the
163077298Sobrien         attributes don't match.  */
163178828Sobrien      flagword matchflags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_CODE
1632218822Sdim			     | SEC_DATA | SEC_COFF_SHARED | SEC_NEVER_LOAD);
163377298Sobrien      if ((flags ^ oldflags) & matchflags)
163477298Sobrien	as_warn (_("Ignoring changed section attributes for %s"), name);
163577298Sobrien    }
163633965Sjdp
163733965Sjdp  demand_empty_rest_of_line ();
163833965Sjdp}
163933965Sjdp
164033965Sjdpvoid
1641218822Sdimcoff_adjust_symtab (void)
164233965Sjdp{
164333965Sjdp  if (symbol_rootP == NULL
164433965Sjdp      || S_GET_STORAGE_CLASS (symbol_rootP) != C_FILE)
1645218822Sdim    c_dot_file_symbol ("fake", 0);
164633965Sjdp}
164733965Sjdp
164833965Sjdpvoid
1649218822Sdimcoff_frob_section (segT sec)
165033965Sjdp{
165133965Sjdp  segT strsec;
165233965Sjdp  char *p;
165333965Sjdp  fragS *fragp;
165433965Sjdp  bfd_vma size, n_entries, mask;
165560484Sobrien  bfd_vma align_power = (bfd_vma)sec->alignment_power + OCTETS_PER_BYTE_POWER;
165633965Sjdp
165733965Sjdp  /* The COFF back end in BFD requires that all section sizes be
165860484Sobrien     rounded up to multiples of the corresponding section alignments,
165960484Sobrien     supposedly because standard COFF has no other way of encoding alignment
166060484Sobrien     for sections.  If your COFF flavor has a different way of encoding
166177298Sobrien     section alignment, then skip this step, as TICOFF does.  */
1662218822Sdim  size = bfd_get_section_size (sec);
166360484Sobrien  mask = ((bfd_vma) 1 << align_power) - 1;
166460484Sobrien#if !defined(TICOFF)
166533965Sjdp  if (size & mask)
166633965Sjdp    {
166777298Sobrien      bfd_vma new_size;
166877298Sobrien      fragS *last;
166977298Sobrien
167077298Sobrien      new_size = (size + mask) & ~mask;
167177298Sobrien      bfd_set_section_size (stdoutput, sec, new_size);
167277298Sobrien
167377298Sobrien      /* If the size had to be rounded up, add some padding in
167477298Sobrien         the last non-empty frag.  */
167577298Sobrien      fragp = seg_info (sec)->frchainP->frch_root;
167677298Sobrien      last = seg_info (sec)->frchainP->frch_last;
167777298Sobrien      while (fragp->fr_next != last)
1678104834Sobrien	fragp = fragp->fr_next;
167977298Sobrien      last->fr_address = size;
168077298Sobrien      fragp->fr_offset += new_size - size;
168133965Sjdp    }
168260484Sobrien#endif
168333965Sjdp
168433965Sjdp  /* If the section size is non-zero, the section symbol needs an aux
168533965Sjdp     entry associated with it, indicating the size.  We don't know
168633965Sjdp     all the values yet; coff_frob_symbol will fill them in later.  */
168760484Sobrien#ifndef TICOFF
168833965Sjdp  if (size != 0
168933965Sjdp      || sec == text_section
169033965Sjdp      || sec == data_section
169133965Sjdp      || sec == bss_section)
169260484Sobrien#endif
169333965Sjdp    {
169433965Sjdp      symbolS *secsym = section_symbol (sec);
169533965Sjdp
169633965Sjdp      S_SET_STORAGE_CLASS (secsym, C_STAT);
169733965Sjdp      S_SET_NUMBER_AUXILIARY (secsym, 1);
169833965Sjdp      SF_SET_STATICS (secsym);
169933965Sjdp      SA_SET_SCN_SCNLEN (secsym, size);
170033965Sjdp    }
170133965Sjdp
1702218822Sdim  /* FIXME: These should be in a "stabs.h" file, or maybe as.h.  */
170333965Sjdp#ifndef STAB_SECTION_NAME
170433965Sjdp#define STAB_SECTION_NAME ".stab"
170533965Sjdp#endif
170633965Sjdp#ifndef STAB_STRING_SECTION_NAME
170733965Sjdp#define STAB_STRING_SECTION_NAME ".stabstr"
170833965Sjdp#endif
1709218822Sdim  if (! streq (STAB_STRING_SECTION_NAME, sec->name))
171033965Sjdp    return;
171133965Sjdp
171233965Sjdp  strsec = sec;
171333965Sjdp  sec = subseg_get (STAB_SECTION_NAME, 0);
171433965Sjdp  /* size is already rounded up, since other section will be listed first */
1715218822Sdim  size = bfd_get_section_size (strsec);
171633965Sjdp
1717218822Sdim  n_entries = bfd_get_section_size (sec) / 12 - 1;
171833965Sjdp
171933965Sjdp  /* Find first non-empty frag.  It should be large enough.  */
172033965Sjdp  fragp = seg_info (sec)->frchainP->frch_root;
172133965Sjdp  while (fragp && fragp->fr_fix == 0)
172233965Sjdp    fragp = fragp->fr_next;
172333965Sjdp  assert (fragp != 0 && fragp->fr_fix >= 12);
172433965Sjdp
172533965Sjdp  /* Store the values.  */
172633965Sjdp  p = fragp->fr_literal;
172733965Sjdp  bfd_h_put_16 (stdoutput, n_entries, (bfd_byte *) p + 6);
172833965Sjdp  bfd_h_put_32 (stdoutput, size, (bfd_byte *) p + 8);
172933965Sjdp}
173033965Sjdp
173133965Sjdpvoid
1732218822Sdimobj_coff_init_stab_section (segT seg)
173333965Sjdp{
173433965Sjdp  char *file;
173533965Sjdp  char *p;
173633965Sjdp  char *stabstr_name;
173733965Sjdp  unsigned int stroff;
173833965Sjdp
173977298Sobrien  /* Make space for this first symbol.  */
174033965Sjdp  p = frag_more (12);
174177298Sobrien  /* Zero it out.  */
174233965Sjdp  memset (p, 0, 12);
174333965Sjdp  as_where (&file, (unsigned int *) NULL);
1744218822Sdim  stabstr_name = xmalloc (strlen (seg->name) + 4);
174533965Sjdp  strcpy (stabstr_name, seg->name);
174633965Sjdp  strcat (stabstr_name, "str");
174733965Sjdp  stroff = get_stab_string_offset (file, stabstr_name);
174833965Sjdp  know (stroff == 1);
174933965Sjdp  md_number_to_chars (p, stroff, 4);
175033965Sjdp}
175133965Sjdp
175233965Sjdp#ifdef DEBUG
175333965Sjdpconst char *
1754218822Sdims_get_name (symbolS *s)
175533965Sjdp{
175633965Sjdp  return ((s == NULL) ? "(NULL)" : S_GET_NAME (s));
175733965Sjdp}
175833965Sjdp
175933965Sjdpvoid
1760218822Sdimsymbol_dump (void)
176133965Sjdp{
176233965Sjdp  symbolS *symbolP;
176333965Sjdp
176433965Sjdp  for (symbolP = symbol_rootP; symbolP; symbolP = symbol_next (symbolP))
1765218822Sdim    printf (_("0x%lx: \"%s\" type = %ld, class = %d, segment = %d\n"),
1766218822Sdim	    (unsigned long) symbolP,
1767218822Sdim	    S_GET_NAME (symbolP),
1768218822Sdim	    (long) S_GET_DATA_TYPE (symbolP),
1769218822Sdim	    S_GET_STORAGE_CLASS (symbolP),
1770218822Sdim	    (int) S_GET_SEGMENT (symbolP));
177133965Sjdp}
177233965Sjdp
177333965Sjdp#endif /* DEBUG */
177433965Sjdp
177560484Sobrienconst pseudo_typeS coff_pseudo_table[] =
177633965Sjdp{
1777218822Sdim  {"ABORT", s_abort, 0},
1778218822Sdim  {"appline", obj_coff_ln, 1},
1779218822Sdim  /* We accept the .bss directive for backward compatibility with
1780218822Sdim     earlier versions of gas.  */
1781218822Sdim  {"bss", obj_coff_bss, 0},
178233965Sjdp  {"def", obj_coff_def, 0},
178333965Sjdp  {"dim", obj_coff_dim, 0},
178433965Sjdp  {"endef", obj_coff_endef, 0},
1785218822Sdim  {"ident", obj_coff_ident, 0},
178633965Sjdp  {"line", obj_coff_line, 0},
178733965Sjdp  {"ln", obj_coff_ln, 0},
178833965Sjdp  {"scl", obj_coff_scl, 0},
1789218822Sdim  {"sect", obj_coff_section, 0},
1790218822Sdim  {"sect.s", obj_coff_section, 0},
1791218822Sdim  {"section", obj_coff_section, 0},
1792218822Sdim  {"section.s", obj_coff_section, 0},
1793218822Sdim  /* FIXME: We ignore the MRI short attribute.  */
179433965Sjdp  {"size", obj_coff_size, 0},
179533965Sjdp  {"tag", obj_coff_tag, 0},
179633965Sjdp  {"type", obj_coff_type, 0},
179733965Sjdp  {"val", obj_coff_val, 0},
1798218822Sdim  {"version", s_ignore, 0},
1799218822Sdim  {"loc", obj_coff_loc, 0},
1800218822Sdim  {"optim", s_ignore, 0},	/* For sun386i cc (?) */
180160484Sobrien  {"weak", obj_coff_weak, 0},
1802218822Sdim#if defined TC_TIC4X
1803218822Sdim  /* The tic4x uses sdef instead of def.  */
180433965Sjdp  {"sdef", obj_coff_def, 0},
180533965Sjdp#endif
1806218822Sdim  {NULL, NULL, 0}
1807218822Sdim};
180833965Sjdp
180933965Sjdp
181033965Sjdp/* Support for a COFF emulation.  */
181133965Sjdp
181233965Sjdpstatic void
1813218822Sdimcoff_pop_insert (void)
181433965Sjdp{
181560484Sobrien  pop_insert (coff_pseudo_table);
181633965Sjdp}
181733965Sjdp
181877298Sobrienstatic int
1819218822Sdimcoff_separate_stab_sections (void)
182077298Sobrien{
182177298Sobrien  return 1;
182277298Sobrien}
182377298Sobrien
182433965Sjdpconst struct format_ops coff_format_ops =
182533965Sjdp{
182633965Sjdp  bfd_target_coff_flavour,
182760484Sobrien  0,	/* dfl_leading_underscore */
182860484Sobrien  1,	/* emit_section_symbols */
182977298Sobrien  0,    /* begin */
183077298Sobrien  c_dot_file_symbol,
183133965Sjdp  coff_frob_symbol,
183260484Sobrien  0,	/* frob_file */
183377298Sobrien  0,	/* frob_file_before_adjust */
1834130561Sobrien  0,	/* frob_file_before_fix */
183538889Sjdp  coff_frob_file_after_relocs,
183660484Sobrien  0,	/* s_get_size */
183760484Sobrien  0,	/* s_set_size */
183860484Sobrien  0,	/* s_get_align */
183960484Sobrien  0,	/* s_set_align */
184060484Sobrien  0,	/* s_get_other */
184177298Sobrien  0,	/* s_set_other */
184260484Sobrien  0,	/* s_get_desc */
184377298Sobrien  0,	/* s_set_desc */
184477298Sobrien  0,	/* s_get_type */
184577298Sobrien  0,	/* s_set_type */
184660484Sobrien  0,	/* copy_symbol_attributes */
184760484Sobrien  0,	/* generate_asm_lineno */
184860484Sobrien  0,	/* process_stab */
184977298Sobrien  coff_separate_stab_sections,
185077298Sobrien  obj_coff_init_stab_section,
185160484Sobrien  0,	/* sec_sym_ok_for_reloc */
185233965Sjdp  coff_pop_insert,
185360484Sobrien  0,	/* ecoff_set_ext */
185433965Sjdp  coff_obj_read_begin_hook,
185560484Sobrien  coff_obj_symbol_new_hook
185633965Sjdp};
1857