obj-elf.c revision 94536
133965Sjdp/* ELF object file format
289857Sobrien   Copyright 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
360484Sobrien   Free Software Foundation, Inc.
433965Sjdp
533965Sjdp   This file is part of GAS, the GNU Assembler.
633965Sjdp
733965Sjdp   GAS is free software; you can redistribute it and/or modify
833965Sjdp   it under the terms of the GNU General Public License as
933965Sjdp   published by the Free Software Foundation; either version 2,
1033965Sjdp   or (at your option) any later version.
1133965Sjdp
1233965Sjdp   GAS is distributed in the hope that it will be useful, but
1333965Sjdp   WITHOUT ANY WARRANTY; without even the implied warranty of
1433965Sjdp   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
1533965Sjdp   the GNU General Public License for more details.
1633965Sjdp
1733965Sjdp   You should have received a copy of the GNU General Public License
1833965Sjdp   along with GAS; see the file COPYING.  If not, write to the Free
1933965Sjdp   Software Foundation, 59 Temple Place - Suite 330, Boston, MA
2077298Sobrien   02111-1307, USA.  */
2133965Sjdp
2233965Sjdp#define OBJ_HEADER "obj-elf.h"
2333965Sjdp#include "as.h"
2489857Sobrien#include "safe-ctype.h"
2533965Sjdp#include "subsegs.h"
2633965Sjdp#include "obstack.h"
2733965Sjdp
2833965Sjdp#ifndef ECOFF_DEBUGGING
2933965Sjdp#define ECOFF_DEBUGGING 0
3033965Sjdp#else
3133965Sjdp#define NEED_ECOFF_DEBUG
3233965Sjdp#endif
3333965Sjdp
3433965Sjdp#ifdef NEED_ECOFF_DEBUG
3533965Sjdp#include "ecoff.h"
3633965Sjdp#endif
3733965Sjdp
3838889Sjdp#ifdef TC_ALPHA
3938889Sjdp#include "elf/alpha.h"
4038889Sjdp#endif
4138889Sjdp
4233965Sjdp#ifdef TC_MIPS
4333965Sjdp#include "elf/mips.h"
4433965Sjdp#endif
4533965Sjdp
4633965Sjdp#ifdef TC_PPC
4733965Sjdp#include "elf/ppc.h"
4833965Sjdp#endif
4933965Sjdp
5060484Sobrien#ifdef TC_I370
5160484Sobrien#include "elf/i370.h"
5260484Sobrien#endif
5360484Sobrien
5433965Sjdpstatic bfd_vma elf_s_get_size PARAMS ((symbolS *));
5533965Sjdpstatic void elf_s_set_size PARAMS ((symbolS *, bfd_vma));
5633965Sjdpstatic bfd_vma elf_s_get_align PARAMS ((symbolS *));
5733965Sjdpstatic void elf_s_set_align PARAMS ((symbolS *, bfd_vma));
5877298Sobrienstatic void elf_s_set_other PARAMS ((symbolS *, int));
5933965Sjdpstatic int elf_sec_sym_ok_for_reloc PARAMS ((asection *));
6033965Sjdpstatic void adjust_stab_sections PARAMS ((bfd *, asection *, PTR));
6189857Sobrienstatic void build_group_lists PARAMS ((bfd *, asection *, PTR));
6277298Sobrienstatic int elf_separate_stab_sections PARAMS ((void));
6377298Sobrienstatic void elf_init_stab_section PARAMS ((segT));
6433965Sjdp
6533965Sjdp#ifdef NEED_ECOFF_DEBUG
6633965Sjdpstatic boolean elf_get_extr PARAMS ((asymbol *, EXTR *));
6733965Sjdpstatic void elf_set_index PARAMS ((asymbol *, bfd_size_type));
6833965Sjdp#endif
6933965Sjdp
7033965Sjdpstatic void obj_elf_line PARAMS ((int));
7133965Sjdpvoid obj_elf_version PARAMS ((int));
7233965Sjdpstatic void obj_elf_size PARAMS ((int));
7333965Sjdpstatic void obj_elf_type PARAMS ((int));
7433965Sjdpstatic void obj_elf_ident PARAMS ((int));
7533965Sjdpstatic void obj_elf_weak PARAMS ((int));
7633965Sjdpstatic void obj_elf_local PARAMS ((int));
7760484Sobrienstatic void obj_elf_visibility PARAMS ((int));
7889857Sobrienstatic void obj_elf_change_section
7989857Sobrien  PARAMS ((const char *, int, int, int, const char *, int));
8089857Sobrienstatic int obj_elf_parse_section_letters PARAMS ((char *, size_t));
8189857Sobrienstatic int obj_elf_section_word PARAMS ((char *, size_t));
8289857Sobrienstatic char *obj_elf_section_name PARAMS ((void));
8389857Sobrienstatic int obj_elf_section_type PARAMS ((char *, size_t));
8433965Sjdpstatic void obj_elf_symver PARAMS ((int));
8538889Sjdpstatic void obj_elf_subsection PARAMS ((int));
8660484Sobrienstatic void obj_elf_popsection PARAMS ((int));
8733965Sjdp
8833965Sjdpstatic const pseudo_typeS elf_pseudo_table[] =
8933965Sjdp{
9033965Sjdp  {"comm", obj_elf_common, 0},
9160484Sobrien  {"common", obj_elf_common, 1},
9233965Sjdp  {"ident", obj_elf_ident, 0},
9333965Sjdp  {"local", obj_elf_local, 0},
9433965Sjdp  {"previous", obj_elf_previous, 0},
9533965Sjdp  {"section", obj_elf_section, 0},
9633965Sjdp  {"section.s", obj_elf_section, 0},
9733965Sjdp  {"sect", obj_elf_section, 0},
9833965Sjdp  {"sect.s", obj_elf_section, 0},
9960484Sobrien  {"pushsection", obj_elf_section, 1},
10060484Sobrien  {"popsection", obj_elf_popsection, 0},
10133965Sjdp  {"size", obj_elf_size, 0},
10233965Sjdp  {"type", obj_elf_type, 0},
10333965Sjdp  {"version", obj_elf_version, 0},
10433965Sjdp  {"weak", obj_elf_weak, 0},
10533965Sjdp
10677298Sobrien  /* These define symbol visibility.  */
10760484Sobrien  {"internal", obj_elf_visibility, STV_INTERNAL},
10860484Sobrien  {"hidden", obj_elf_visibility, STV_HIDDEN},
10960484Sobrien  {"protected", obj_elf_visibility, STV_PROTECTED},
11060484Sobrien
11133965Sjdp  /* These are used for stabs-in-elf configurations.  */
11233965Sjdp  {"line", obj_elf_line, 0},
11333965Sjdp
11433965Sjdp  /* This is a GNU extension to handle symbol versions.  */
11533965Sjdp  {"symver", obj_elf_symver, 0},
11633965Sjdp
11738889Sjdp  /* A GNU extension to change subsection only.  */
11838889Sjdp  {"subsection", obj_elf_subsection, 0},
11938889Sjdp
12060484Sobrien  /* These are GNU extensions to aid in garbage collecting C++ vtables.  */
12177298Sobrien  {"vtable_inherit", (void (*) PARAMS ((int))) &obj_elf_vtable_inherit, 0},
12277298Sobrien  {"vtable_entry", (void (*) PARAMS ((int))) &obj_elf_vtable_entry, 0},
12360484Sobrien
12477298Sobrien  /* These are used for dwarf.  */
12533965Sjdp  {"2byte", cons, 2},
12633965Sjdp  {"4byte", cons, 4},
12733965Sjdp  {"8byte", cons, 8},
12833965Sjdp
12933965Sjdp  /* We need to trap the section changing calls to handle .previous.  */
13033965Sjdp  {"data", obj_elf_data, 0},
13133965Sjdp  {"text", obj_elf_text, 0},
13233965Sjdp
13333965Sjdp  /* End sentinel.  */
13460484Sobrien  {NULL, NULL, 0},
13533965Sjdp};
13633965Sjdp
13733965Sjdpstatic const pseudo_typeS ecoff_debug_pseudo_table[] =
13833965Sjdp{
13933965Sjdp#ifdef NEED_ECOFF_DEBUG
14033965Sjdp  /* COFF style debugging information for ECOFF. .ln is not used; .loc
14133965Sjdp     is used instead.  */
14233965Sjdp  { "def",	ecoff_directive_def,	0 },
14333965Sjdp  { "dim",	ecoff_directive_dim,	0 },
14433965Sjdp  { "endef",	ecoff_directive_endef,	0 },
14533965Sjdp  { "file",	ecoff_directive_file,	0 },
14633965Sjdp  { "scl",	ecoff_directive_scl,	0 },
14733965Sjdp  { "tag",	ecoff_directive_tag,	0 },
14833965Sjdp  { "val",	ecoff_directive_val,	0 },
14933965Sjdp
15033965Sjdp  /* COFF debugging requires pseudo-ops .size and .type, but ELF
15133965Sjdp     already has meanings for those.  We use .esize and .etype
15233965Sjdp     instead.  These are only generated by gcc anyhow.  */
15333965Sjdp  { "esize",	ecoff_directive_size,	0 },
15433965Sjdp  { "etype",	ecoff_directive_type,	0 },
15533965Sjdp
15633965Sjdp  /* ECOFF specific debugging information.  */
15733965Sjdp  { "begin",	ecoff_directive_begin,	0 },
15833965Sjdp  { "bend",	ecoff_directive_bend,	0 },
15933965Sjdp  { "end",	ecoff_directive_end,	0 },
16033965Sjdp  { "ent",	ecoff_directive_ent,	0 },
16133965Sjdp  { "fmask",	ecoff_directive_fmask,	0 },
16233965Sjdp  { "frame",	ecoff_directive_frame,	0 },
16333965Sjdp  { "loc",	ecoff_directive_loc,	0 },
16433965Sjdp  { "mask",	ecoff_directive_mask,	0 },
16533965Sjdp
16633965Sjdp  /* Other ECOFF directives.  */
16733965Sjdp  { "extern",	ecoff_directive_extern,	0 },
16833965Sjdp
16933965Sjdp  /* These are used on Irix.  I don't know how to implement them.  */
17033965Sjdp  { "alias",	s_ignore,		0 },
17133965Sjdp  { "bgnb",	s_ignore,		0 },
17233965Sjdp  { "endb",	s_ignore,		0 },
17333965Sjdp  { "lab",	s_ignore,		0 },
17433965Sjdp  { "noalias",	s_ignore,		0 },
17533965Sjdp  { "verstamp",	s_ignore,		0 },
17633965Sjdp  { "vreg",	s_ignore,		0 },
17733965Sjdp#endif
17833965Sjdp
17960484Sobrien  {NULL, NULL, 0}			/* end sentinel */
18033965Sjdp};
18133965Sjdp
18233965Sjdp#undef NO_RELOC
18333965Sjdp#include "aout/aout64.h"
18433965Sjdp
18533965Sjdp/* This is called when the assembler starts.  */
18633965Sjdp
18733965Sjdpvoid
18833965Sjdpelf_begin ()
18933965Sjdp{
19033965Sjdp  /* Add symbols for the known sections to the symbol table.  */
19133965Sjdp  symbol_table_insert (section_symbol (bfd_get_section_by_name (stdoutput,
19238889Sjdp								TEXT_SECTION_NAME)));
19333965Sjdp  symbol_table_insert (section_symbol (bfd_get_section_by_name (stdoutput,
19438889Sjdp								DATA_SECTION_NAME)));
19533965Sjdp  symbol_table_insert (section_symbol (bfd_get_section_by_name (stdoutput,
19638889Sjdp								BSS_SECTION_NAME)));
19733965Sjdp}
19833965Sjdp
19933965Sjdpvoid
20033965Sjdpelf_pop_insert ()
20133965Sjdp{
20233965Sjdp  pop_insert (elf_pseudo_table);
20333965Sjdp  if (ECOFF_DEBUGGING)
20433965Sjdp    pop_insert (ecoff_debug_pseudo_table);
20533965Sjdp}
20633965Sjdp
20733965Sjdpstatic bfd_vma
20833965Sjdpelf_s_get_size (sym)
20933965Sjdp     symbolS *sym;
21033965Sjdp{
21133965Sjdp  return S_GET_SIZE (sym);
21233965Sjdp}
21333965Sjdp
21433965Sjdpstatic void
21533965Sjdpelf_s_set_size (sym, sz)
21633965Sjdp     symbolS *sym;
21733965Sjdp     bfd_vma sz;
21833965Sjdp{
21933965Sjdp  S_SET_SIZE (sym, sz);
22033965Sjdp}
22133965Sjdp
22233965Sjdpstatic bfd_vma
22333965Sjdpelf_s_get_align (sym)
22433965Sjdp     symbolS *sym;
22533965Sjdp{
22633965Sjdp  return S_GET_ALIGN (sym);
22733965Sjdp}
22833965Sjdp
22933965Sjdpstatic void
23033965Sjdpelf_s_set_align (sym, align)
23133965Sjdp     symbolS *sym;
23233965Sjdp     bfd_vma align;
23333965Sjdp{
23433965Sjdp  S_SET_ALIGN (sym, align);
23533965Sjdp}
23633965Sjdp
23760484Sobrienint
23860484Sobrienelf_s_get_other (sym)
23960484Sobrien     symbolS *sym;
24060484Sobrien{
24160484Sobrien  return elf_symbol (symbol_get_bfdsym (sym))->internal_elf_sym.st_other;
24260484Sobrien}
24360484Sobrien
24433965Sjdpstatic void
24577298Sobrienelf_s_set_other (sym, other)
24677298Sobrien     symbolS *sym;
24777298Sobrien     int other;
24877298Sobrien{
24977298Sobrien  S_SET_OTHER (sym, other);
25077298Sobrien}
25177298Sobrien
25233965Sjdpstatic int
25333965Sjdpelf_sec_sym_ok_for_reloc (sec)
25433965Sjdp     asection *sec;
25533965Sjdp{
25633965Sjdp  return obj_sec_sym_ok_for_reloc (sec);
25733965Sjdp}
25833965Sjdp
25933965Sjdpvoid
26033965Sjdpelf_file_symbol (s)
26177298Sobrien     const char *s;
26233965Sjdp{
26333965Sjdp  symbolS *sym;
26433965Sjdp
26533965Sjdp  sym = symbol_new (s, absolute_section, (valueT) 0, (struct frag *) 0);
26660484Sobrien  symbol_set_frag (sym, &zero_address_frag);
26760484Sobrien  symbol_get_bfdsym (sym)->flags |= BSF_FILE;
26833965Sjdp
26933965Sjdp  if (symbol_rootP != sym)
27033965Sjdp    {
27133965Sjdp      symbol_remove (sym, &symbol_rootP, &symbol_lastP);
27233965Sjdp      symbol_insert (sym, symbol_rootP, &symbol_rootP, &symbol_lastP);
27333965Sjdp#ifdef DEBUG
27433965Sjdp      verify_symbol_chain (symbol_rootP, symbol_lastP);
27533965Sjdp#endif
27633965Sjdp    }
27733965Sjdp
27833965Sjdp#ifdef NEED_ECOFF_DEBUG
27933965Sjdp  ecoff_new_file (s);
28033965Sjdp#endif
28133965Sjdp}
28233965Sjdp
28360484Sobrienvoid
28460484Sobrienobj_elf_common (is_common)
28560484Sobrien     int is_common;
28633965Sjdp{
28733965Sjdp  char *name;
28833965Sjdp  char c;
28933965Sjdp  char *p;
29033965Sjdp  int temp, size;
29133965Sjdp  symbolS *symbolP;
29233965Sjdp  int have_align;
29333965Sjdp
29460484Sobrien  if (flag_mri && is_common)
29560484Sobrien    {
29660484Sobrien      s_mri_common (0);
29760484Sobrien      return;
29860484Sobrien    }
29960484Sobrien
30033965Sjdp  name = input_line_pointer;
30133965Sjdp  c = get_symbol_end ();
30233965Sjdp  /* just after name is now '\0' */
30333965Sjdp  p = input_line_pointer;
30433965Sjdp  *p = c;
30533965Sjdp  SKIP_WHITESPACE ();
30633965Sjdp  if (*input_line_pointer != ',')
30733965Sjdp    {
30889857Sobrien      as_bad (_("expected comma after symbol-name"));
30933965Sjdp      ignore_rest_of_line ();
31033965Sjdp      return;
31133965Sjdp    }
31233965Sjdp  input_line_pointer++;		/* skip ',' */
31333965Sjdp  if ((temp = get_absolute_expression ()) < 0)
31433965Sjdp    {
31560484Sobrien      as_bad (_(".COMMon length (%d.) <0! Ignored."), temp);
31633965Sjdp      ignore_rest_of_line ();
31733965Sjdp      return;
31833965Sjdp    }
31933965Sjdp  size = temp;
32033965Sjdp  *p = 0;
32133965Sjdp  symbolP = symbol_find_or_make (name);
32233965Sjdp  *p = c;
32333965Sjdp  if (S_IS_DEFINED (symbolP) && ! S_IS_COMMON (symbolP))
32433965Sjdp    {
32589857Sobrien      as_bad (_("symbol `%s' is already defined"), S_GET_NAME (symbolP));
32633965Sjdp      ignore_rest_of_line ();
32733965Sjdp      return;
32833965Sjdp    }
32933965Sjdp  if (S_GET_VALUE (symbolP) != 0)
33033965Sjdp    {
33160484Sobrien      if (S_GET_VALUE (symbolP) != (valueT) size)
33233965Sjdp	{
33389857Sobrien	  as_warn (_("length of .comm \"%s\" is already %ld; not changed to %d"),
33433965Sjdp		   S_GET_NAME (symbolP), (long) S_GET_VALUE (symbolP), size);
33533965Sjdp	}
33633965Sjdp    }
33733965Sjdp  know (symbolP->sy_frag == &zero_address_frag);
33833965Sjdp  if (*input_line_pointer != ',')
33933965Sjdp    have_align = 0;
34033965Sjdp  else
34133965Sjdp    {
34233965Sjdp      have_align = 1;
34333965Sjdp      input_line_pointer++;
34433965Sjdp      SKIP_WHITESPACE ();
34533965Sjdp    }
34633965Sjdp  if (! have_align || *input_line_pointer != '"')
34733965Sjdp    {
34833965Sjdp      if (! have_align)
34933965Sjdp	temp = 0;
35033965Sjdp      else
35133965Sjdp	{
35233965Sjdp	  temp = get_absolute_expression ();
35333965Sjdp	  if (temp < 0)
35433965Sjdp	    {
35533965Sjdp	      temp = 0;
35689857Sobrien	      as_warn (_("common alignment negative; 0 assumed"));
35733965Sjdp	    }
35833965Sjdp	}
35960484Sobrien      if (symbol_get_obj (symbolP)->local)
36033965Sjdp	{
36133965Sjdp	  segT old_sec;
36233965Sjdp	  int old_subsec;
36333965Sjdp	  char *pfrag;
36433965Sjdp	  int align;
36533965Sjdp
36633965Sjdp	/* allocate_bss: */
36733965Sjdp	  old_sec = now_seg;
36833965Sjdp	  old_subsec = now_subseg;
36933965Sjdp	  if (temp)
37033965Sjdp	    {
37133965Sjdp	      /* convert to a power of 2 alignment */
37233965Sjdp	      for (align = 0; (temp & 1) == 0; temp >>= 1, ++align);
37333965Sjdp	      if (temp != 1)
37433965Sjdp		{
37589857Sobrien		  as_bad (_("common alignment not a power of 2"));
37633965Sjdp		  ignore_rest_of_line ();
37733965Sjdp		  return;
37833965Sjdp		}
37933965Sjdp	    }
38033965Sjdp	  else
38133965Sjdp	    align = 0;
38233965Sjdp	  record_alignment (bss_section, align);
38333965Sjdp	  subseg_set (bss_section, 0);
38433965Sjdp	  if (align)
38533965Sjdp	    frag_align (align, 0, 0);
38633965Sjdp	  if (S_GET_SEGMENT (symbolP) == bss_section)
38760484Sobrien	    symbol_get_frag (symbolP)->fr_symbol = 0;
38860484Sobrien	  symbol_set_frag (symbolP, frag_now);
38933965Sjdp	  pfrag = frag_var (rs_org, 1, 1, (relax_substateT) 0, symbolP,
39033965Sjdp			    (offsetT) size, (char *) 0);
39133965Sjdp	  *pfrag = 0;
39233965Sjdp	  S_SET_SIZE (symbolP, size);
39333965Sjdp	  S_SET_SEGMENT (symbolP, bss_section);
39433965Sjdp	  S_CLEAR_EXTERNAL (symbolP);
39533965Sjdp	  subseg_set (old_sec, old_subsec);
39633965Sjdp	}
39733965Sjdp      else
39833965Sjdp	{
39933965Sjdp	allocate_common:
40033965Sjdp	  S_SET_VALUE (symbolP, (valueT) size);
40133965Sjdp	  S_SET_ALIGN (symbolP, temp);
40233965Sjdp	  S_SET_EXTERNAL (symbolP);
40333965Sjdp	  S_SET_SEGMENT (symbolP, bfd_com_section_ptr);
40433965Sjdp	}
40533965Sjdp    }
40633965Sjdp  else
40733965Sjdp    {
40833965Sjdp      input_line_pointer++;
40933965Sjdp      /* @@ Some use the dot, some don't.  Can we get some consistency??  */
41033965Sjdp      if (*input_line_pointer == '.')
41133965Sjdp	input_line_pointer++;
41233965Sjdp      /* @@ Some say data, some say bss.  */
41333965Sjdp      if (strncmp (input_line_pointer, "bss\"", 4)
41433965Sjdp	  && strncmp (input_line_pointer, "data\"", 5))
41533965Sjdp	{
41633965Sjdp	  while (*--input_line_pointer != '"')
41733965Sjdp	    ;
41833965Sjdp	  input_line_pointer--;
41933965Sjdp	  goto bad_common_segment;
42033965Sjdp	}
42133965Sjdp      while (*input_line_pointer++ != '"')
42233965Sjdp	;
42333965Sjdp      goto allocate_common;
42433965Sjdp    }
42533965Sjdp
42660484Sobrien  symbol_get_bfdsym (symbolP)->flags |= BSF_OBJECT;
42733965Sjdp
42833965Sjdp  demand_empty_rest_of_line ();
42933965Sjdp  return;
43033965Sjdp
43133965Sjdp  {
43233965Sjdp  bad_common_segment:
43333965Sjdp    p = input_line_pointer;
43433965Sjdp    while (*p && *p != '\n')
43533965Sjdp      p++;
43633965Sjdp    c = *p;
43733965Sjdp    *p = '\0';
43860484Sobrien    as_bad (_("bad .common segment %s"), input_line_pointer + 1);
43933965Sjdp    *p = c;
44033965Sjdp    input_line_pointer = p;
44133965Sjdp    ignore_rest_of_line ();
44233965Sjdp    return;
44333965Sjdp  }
44433965Sjdp}
44533965Sjdp
44633965Sjdpstatic void
44733965Sjdpobj_elf_local (ignore)
44860484Sobrien     int ignore ATTRIBUTE_UNUSED;
44933965Sjdp{
45033965Sjdp  char *name;
45133965Sjdp  int c;
45233965Sjdp  symbolS *symbolP;
45333965Sjdp
45433965Sjdp  do
45533965Sjdp    {
45633965Sjdp      name = input_line_pointer;
45733965Sjdp      c = get_symbol_end ();
45833965Sjdp      symbolP = symbol_find_or_make (name);
45933965Sjdp      *input_line_pointer = c;
46033965Sjdp      SKIP_WHITESPACE ();
46133965Sjdp      S_CLEAR_EXTERNAL (symbolP);
46260484Sobrien      symbol_get_obj (symbolP)->local = 1;
46333965Sjdp      if (c == ',')
46433965Sjdp	{
46533965Sjdp	  input_line_pointer++;
46633965Sjdp	  SKIP_WHITESPACE ();
46733965Sjdp	  if (*input_line_pointer == '\n')
46833965Sjdp	    c = '\n';
46933965Sjdp	}
47033965Sjdp    }
47133965Sjdp  while (c == ',');
47233965Sjdp  demand_empty_rest_of_line ();
47333965Sjdp}
47433965Sjdp
47533965Sjdpstatic void
47633965Sjdpobj_elf_weak (ignore)
47760484Sobrien     int ignore ATTRIBUTE_UNUSED;
47833965Sjdp{
47933965Sjdp  char *name;
48033965Sjdp  int c;
48133965Sjdp  symbolS *symbolP;
48233965Sjdp
48333965Sjdp  do
48433965Sjdp    {
48533965Sjdp      name = input_line_pointer;
48633965Sjdp      c = get_symbol_end ();
48733965Sjdp      symbolP = symbol_find_or_make (name);
48833965Sjdp      *input_line_pointer = c;
48933965Sjdp      SKIP_WHITESPACE ();
49033965Sjdp      S_SET_WEAK (symbolP);
49160484Sobrien      symbol_get_obj (symbolP)->local = 1;
49233965Sjdp      if (c == ',')
49333965Sjdp	{
49433965Sjdp	  input_line_pointer++;
49533965Sjdp	  SKIP_WHITESPACE ();
49633965Sjdp	  if (*input_line_pointer == '\n')
49733965Sjdp	    c = '\n';
49833965Sjdp	}
49933965Sjdp    }
50033965Sjdp  while (c == ',');
50133965Sjdp  demand_empty_rest_of_line ();
50233965Sjdp}
50333965Sjdp
50460484Sobrienstatic void
50560484Sobrienobj_elf_visibility (visibility)
50660484Sobrien     int visibility;
50760484Sobrien{
50860484Sobrien  char *name;
50960484Sobrien  int c;
51060484Sobrien  symbolS *symbolP;
51160484Sobrien  asymbol *bfdsym;
51260484Sobrien  elf_symbol_type *elfsym;
51360484Sobrien
51460484Sobrien  do
51560484Sobrien    {
51660484Sobrien      name = input_line_pointer;
51760484Sobrien      c = get_symbol_end ();
51860484Sobrien      symbolP = symbol_find_or_make (name);
51960484Sobrien      *input_line_pointer = c;
52060484Sobrien
52160484Sobrien      SKIP_WHITESPACE ();
52260484Sobrien
52360484Sobrien      bfdsym = symbol_get_bfdsym (symbolP);
52460484Sobrien      elfsym = elf_symbol_from (bfd_asymbol_bfd (bfdsym), bfdsym);
52560484Sobrien
52660484Sobrien      assert (elfsym);
52760484Sobrien
52860484Sobrien      elfsym->internal_elf_sym.st_other = visibility;
52960484Sobrien
53060484Sobrien      if (c == ',')
53160484Sobrien	{
53260484Sobrien	  input_line_pointer ++;
53360484Sobrien
53460484Sobrien	  SKIP_WHITESPACE ();
53560484Sobrien
53660484Sobrien	  if (*input_line_pointer == '\n')
53760484Sobrien	    c = '\n';
53860484Sobrien	}
53960484Sobrien    }
54060484Sobrien  while (c == ',');
54160484Sobrien
54260484Sobrien  demand_empty_rest_of_line ();
54360484Sobrien}
54460484Sobrien
54533965Sjdpstatic segT previous_section;
54633965Sjdpstatic int previous_subsection;
54733965Sjdp
54860484Sobrienstruct section_stack
54960484Sobrien{
55060484Sobrien  struct section_stack *next;
55160484Sobrien  segT seg, prev_seg;
55260484Sobrien  int subseg, prev_subseg;
55360484Sobrien};
55460484Sobrien
55560484Sobrienstatic struct section_stack *section_stack;
55660484Sobrien
55733965Sjdp/* Handle the .section pseudo-op.  This code supports two different
55833965Sjdp   syntaxes.
55933965Sjdp
56033965Sjdp   The first is found on Solaris, and looks like
56133965Sjdp       .section ".sec1",#alloc,#execinstr,#write
56233965Sjdp   Here the names after '#' are the SHF_* flags to turn on for the
56333965Sjdp   section.  I'm not sure how it determines the SHT_* type (BFD
56433965Sjdp   doesn't really give us control over the type, anyhow).
56533965Sjdp
56633965Sjdp   The second format is found on UnixWare, and probably most SVR4
56733965Sjdp   machines, and looks like
56833965Sjdp       .section .sec1,"a",@progbits
56933965Sjdp   The quoted string may contain any combination of a, w, x, and
57033965Sjdp   represents the SHF_* flags to turn on for the section.  The string
57133965Sjdp   beginning with '@' can be progbits or nobits.  There should be
57233965Sjdp   other possibilities, but I don't know what they are.  In any case,
57333965Sjdp   BFD doesn't really let us set the section type.  */
57433965Sjdp
57533965Sjdp/* Certain named sections have particular defined types, listed on p.
57633965Sjdp   4-19 of the ABI.  */
57733965Sjdpstruct special_section
57833965Sjdp{
57933965Sjdp  const char *name;
58033965Sjdp  int type;
58133965Sjdp  int attributes;
58233965Sjdp};
58333965Sjdp
58460484Sobrienstatic struct special_section const special_sections[] =
58533965Sjdp{
58633965Sjdp  { ".bss",	SHT_NOBITS,	SHF_ALLOC + SHF_WRITE		},
58733965Sjdp  { ".comment",	SHT_PROGBITS,	0				},
58833965Sjdp  { ".data",	SHT_PROGBITS,	SHF_ALLOC + SHF_WRITE		},
58933965Sjdp  { ".data1",	SHT_PROGBITS,	SHF_ALLOC + SHF_WRITE		},
59033965Sjdp  { ".debug",	SHT_PROGBITS,	0				},
59133965Sjdp  { ".fini",	SHT_PROGBITS,	SHF_ALLOC + SHF_EXECINSTR	},
59233965Sjdp  { ".init",	SHT_PROGBITS,	SHF_ALLOC + SHF_EXECINSTR	},
59333965Sjdp  { ".line",	SHT_PROGBITS,	0				},
59433965Sjdp  { ".note",	SHT_NOTE,	0				},
59533965Sjdp  { ".rodata",	SHT_PROGBITS,	SHF_ALLOC			},
59633965Sjdp  { ".rodata1",	SHT_PROGBITS,	SHF_ALLOC			},
59733965Sjdp  { ".text",	SHT_PROGBITS,	SHF_ALLOC + SHF_EXECINSTR	},
59894536Sobrien#if 0
59994536Sobrien  /* FIXME: The current gcc, as of 2002-03-03, will emit
60033965Sjdp
60194536Sobrien	.section .init_array,"aw",@progbits
60294536Sobrien
60394536Sobrien     for __attribute__ ((section (".init_array"))). "@progbits" marks
60494536Sobrien     the incorrect section type. For now, we make them with
60594536Sobrien     SHT_PROGBITS. BFD will fix the section type. Gcc should be changed
60694536Sobrien     to emit
60794536Sobrien
60894536Sobrien	.section .init_array
60994536Sobrien
61094536Sobrien   */
61194536Sobrien  { ".init_array",SHT_INIT_ARRAY, SHF_ALLOC + SHF_WRITE         },
61294536Sobrien  { ".fini_array",SHT_FINI_ARRAY, SHF_ALLOC + SHF_WRITE         },
61394536Sobrien  { ".preinit_array",SHT_PREINIT_ARRAY, SHF_ALLOC + SHF_WRITE   },
61494536Sobrien#else
61594536Sobrien  { ".init_array",SHT_PROGBITS, SHF_ALLOC + SHF_WRITE         },
61694536Sobrien  { ".fini_array",SHT_PROGBITS, SHF_ALLOC + SHF_WRITE         },
61794536Sobrien  { ".preinit_array",SHT_PROGBITS, SHF_ALLOC + SHF_WRITE   },
61894536Sobrien#endif
61994536Sobrien
62033965Sjdp#ifdef ELF_TC_SPECIAL_SECTIONS
62133965Sjdp  ELF_TC_SPECIAL_SECTIONS
62233965Sjdp#endif
62333965Sjdp
62433965Sjdp#if 0
62533965Sjdp  /* The following section names are special, but they can not
62633965Sjdp     reasonably appear in assembler code.  Some of the attributes are
62733965Sjdp     processor dependent.  */
62833965Sjdp  { ".dynamic",	SHT_DYNAMIC,	SHF_ALLOC /* + SHF_WRITE */ 	},
62933965Sjdp  { ".dynstr",	SHT_STRTAB,	SHF_ALLOC			},
63033965Sjdp  { ".dynsym",	SHT_DYNSYM,	SHF_ALLOC			},
63133965Sjdp  { ".got",	SHT_PROGBITS,	0				},
63233965Sjdp  { ".hash",	SHT_HASH,	SHF_ALLOC			},
63333965Sjdp  { ".interp",	SHT_PROGBITS,	/* SHF_ALLOC */			},
63433965Sjdp  { ".plt",	SHT_PROGBITS,	0				},
63533965Sjdp  { ".shstrtab",SHT_STRTAB,	0				},
63633965Sjdp  { ".strtab",	SHT_STRTAB,	/* SHF_ALLOC */			},
63733965Sjdp  { ".symtab",	SHT_SYMTAB,	/* SHF_ALLOC */			},
63833965Sjdp#endif
63933965Sjdp
64033965Sjdp  { NULL,	0,		0				}
64133965Sjdp};
64233965Sjdp
64389857Sobrienstatic void
64489857Sobrienobj_elf_change_section (name, type, attr, entsize, group_name, push)
64589857Sobrien     const char *name;
64689857Sobrien     int type;
64789857Sobrien     int attr;
64889857Sobrien     int entsize;
64989857Sobrien     const char *group_name;
65089857Sobrien     int push;
65133965Sjdp{
65277298Sobrien  asection *old_sec;
65333965Sjdp  segT sec;
65477298Sobrien  flagword flags;
65577298Sobrien  int i;
65633965Sjdp
65733965Sjdp#ifdef md_flush_pending_output
65833965Sjdp  md_flush_pending_output ();
65933965Sjdp#endif
66033965Sjdp
66160484Sobrien  /* Switch to the section, creating it if necessary.  */
66260484Sobrien  if (push)
66360484Sobrien    {
66460484Sobrien      struct section_stack *elt;
66560484Sobrien      elt = xmalloc (sizeof (struct section_stack));
66660484Sobrien      elt->next = section_stack;
66760484Sobrien      elt->seg = now_seg;
66860484Sobrien      elt->prev_seg = previous_section;
66960484Sobrien      elt->subseg = now_subseg;
67060484Sobrien      elt->prev_subseg = previous_subsection;
67160484Sobrien      section_stack = elt;
67260484Sobrien    }
67360484Sobrien  previous_section = now_seg;
67460484Sobrien  previous_subsection = now_subseg;
67560484Sobrien
67677298Sobrien  old_sec = bfd_get_section_by_name (stdoutput, name);
67760484Sobrien  sec = subseg_new (name, 0);
67860484Sobrien
67977298Sobrien  /* See if this is one of the special sections.  */
68077298Sobrien  for (i = 0; special_sections[i].name != NULL; i++)
68177298Sobrien    if (strcmp (name, special_sections[i].name) == 0)
68277298Sobrien      {
68377298Sobrien	if (type == SHT_NULL)
68477298Sobrien	  type = special_sections[i].type;
68577298Sobrien	else if (type != special_sections[i].type)
68677298Sobrien	  {
68777298Sobrien	    if (old_sec == NULL)
68860484Sobrien	      {
68989857Sobrien		as_warn (_("setting incorrect section type for %s"), name);
69060484Sobrien	      }
69177298Sobrien	    else
69277298Sobrien	      {
69389857Sobrien		as_warn (_("ignoring incorrect section type for %s"), name);
69477298Sobrien		type = special_sections[i].type;
69577298Sobrien	      }
69660484Sobrien	  }
69777298Sobrien	if ((attr &~ special_sections[i].attributes) != 0
69877298Sobrien	    && old_sec == NULL)
69977298Sobrien	  {
70077298Sobrien	    /* As a GNU extension, we permit a .note section to be
70177298Sobrien	       allocatable.  If the linker sees an allocateable .note
70277298Sobrien	       section, it will create a PT_NOTE segment in the output
70377298Sobrien	       file.  */
70477298Sobrien	    if (strcmp (name, ".note") != 0
70577298Sobrien		|| attr != SHF_ALLOC)
70689857Sobrien	      as_warn (_("setting incorrect section attributes for %s"),
70777298Sobrien		       name);
70877298Sobrien	  }
70977298Sobrien	attr |= special_sections[i].attributes;
71077298Sobrien	break;
71177298Sobrien      }
71260484Sobrien
71377298Sobrien  /* Convert ELF type and flags to BFD flags.  */
71477298Sobrien  flags = (SEC_RELOC
71577298Sobrien	   | ((attr & SHF_WRITE) ? 0 : SEC_READONLY)
71677298Sobrien	   | ((attr & SHF_ALLOC) ? SEC_ALLOC : 0)
71777298Sobrien	   | (((attr & SHF_ALLOC) && type != SHT_NOBITS) ? SEC_LOAD : 0)
71889857Sobrien	   | ((attr & SHF_EXECINSTR) ? SEC_CODE : 0)
71989857Sobrien	   | ((attr & SHF_MERGE) ? SEC_MERGE : 0)
72089857Sobrien	   | ((attr & SHF_STRINGS) ? SEC_STRINGS : 0));
72160484Sobrien#ifdef md_elf_section_flags
72277298Sobrien  flags = md_elf_section_flags (flags, attr, type);
72360484Sobrien#endif
72460484Sobrien
72577298Sobrien  if (old_sec == NULL)
72677298Sobrien    {
72777298Sobrien      symbolS *secsym;
72877298Sobrien
72960484Sobrien      /* Prevent SEC_HAS_CONTENTS from being inadvertently set.  */
73060484Sobrien      if (type == SHT_NOBITS)
73160484Sobrien        seg_info (sec)->bss = 1;
73260484Sobrien
73360484Sobrien      bfd_set_section_flags (stdoutput, sec, flags);
73489857Sobrien      if (flags & SEC_MERGE)
73589857Sobrien	sec->entsize = entsize;
73689857Sobrien      elf_group_name (sec) = group_name;
73760484Sobrien
73860484Sobrien      /* Add a symbol for this section to the symbol table.  */
73960484Sobrien      secsym = symbol_find (name);
74060484Sobrien      if (secsym != NULL)
74160484Sobrien	symbol_set_bfdsym (secsym, sec->symbol);
74260484Sobrien      else
74360484Sobrien        symbol_table_insert (section_symbol (sec));
74460484Sobrien    }
74577298Sobrien  else if (attr != 0)
74677298Sobrien    {
74777298Sobrien      /* If section attributes are specified the second time we see a
74877298Sobrien	 particular section, then check that they are the same as we
74977298Sobrien	 saw the first time.  */
75077298Sobrien      if ((old_sec->flags ^ flags)
75177298Sobrien	  & (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_CODE
75289857Sobrien	     | SEC_EXCLUDE | SEC_SORT_ENTRIES | SEC_MERGE | SEC_STRINGS))
75389857Sobrien	as_warn (_("ignoring changed section attributes for %s"), name);
75489857Sobrien      else if ((flags & SEC_MERGE) && old_sec->entsize != (unsigned) entsize)
75589857Sobrien	as_warn (_("ignoring changed section entity size for %s"), name);
75689857Sobrien      else if ((attr & SHF_GROUP) != 0
75789857Sobrien	       && strcmp (elf_group_name (old_sec), group_name) != 0)
75889857Sobrien	as_warn (_("ignoring new section group for %s"), name);
75977298Sobrien    }
76060484Sobrien
76160484Sobrien#ifdef md_elf_section_change_hook
76277298Sobrien  md_elf_section_change_hook ();
76360484Sobrien#endif
76460484Sobrien}
76560484Sobrien
76689857Sobrienstatic int
76760484Sobrienobj_elf_parse_section_letters (str, len)
76860484Sobrien     char *str;
76960484Sobrien     size_t len;
77060484Sobrien{
77160484Sobrien  int attr = 0;
77260484Sobrien
77360484Sobrien  while (len > 0)
77460484Sobrien    {
77560484Sobrien      switch (*str)
77660484Sobrien	{
77760484Sobrien	case 'a':
77860484Sobrien	  attr |= SHF_ALLOC;
77960484Sobrien	  break;
78060484Sobrien	case 'w':
78160484Sobrien	  attr |= SHF_WRITE;
78260484Sobrien	  break;
78360484Sobrien	case 'x':
78460484Sobrien	  attr |= SHF_EXECINSTR;
78560484Sobrien	  break;
78689857Sobrien	case 'M':
78789857Sobrien	  attr |= SHF_MERGE;
78889857Sobrien	  break;
78989857Sobrien	case 'S':
79089857Sobrien	  attr |= SHF_STRINGS;
79189857Sobrien	  break;
79289857Sobrien	case 'G':
79389857Sobrien	  attr |= SHF_GROUP;
79489857Sobrien	  break;
79589857Sobrien	/* Compatibility.  */
79689857Sobrien	case 'm':
79789857Sobrien	  if (*(str - 1) == 'a')
79889857Sobrien	    {
79989857Sobrien	      attr |= SHF_MERGE;
80089857Sobrien	      if (len > 1 && str[1] == 's')
80189857Sobrien		{
80289857Sobrien		  attr |= SHF_STRINGS;
80389857Sobrien		  str++, len--;
80489857Sobrien		}
80589857Sobrien	      break;
80689857Sobrien	    }
80760484Sobrien	default:
80860484Sobrien	  {
80989857Sobrien	    char *bad_msg = _("unrecognized .section attribute: want a,w,x,M,S,G");
81060484Sobrien#ifdef md_elf_section_letter
81160484Sobrien	    int md_attr = md_elf_section_letter (*str, &bad_msg);
81260484Sobrien	    if (md_attr >= 0)
81360484Sobrien	      attr |= md_attr;
81460484Sobrien	    else
81560484Sobrien#endif
81660484Sobrien	      {
81760484Sobrien		as_warn ("%s", bad_msg);
81860484Sobrien		attr = -1;
81960484Sobrien	      }
82060484Sobrien	  }
82160484Sobrien	  break;
82260484Sobrien	}
82360484Sobrien      str++, len--;
82460484Sobrien    }
82560484Sobrien
82660484Sobrien  return attr;
82760484Sobrien}
82860484Sobrien
82989857Sobrienstatic int
83060484Sobrienobj_elf_section_word (str, len)
83160484Sobrien     char *str;
83260484Sobrien     size_t len;
83360484Sobrien{
83460484Sobrien  if (len == 5 && strncmp (str, "write", 5) == 0)
83560484Sobrien    return SHF_WRITE;
83660484Sobrien  if (len == 5 && strncmp (str, "alloc", 5) == 0)
83760484Sobrien    return SHF_ALLOC;
83860484Sobrien  if (len == 9 && strncmp (str, "execinstr", 9) == 0)
83960484Sobrien    return SHF_EXECINSTR;
84060484Sobrien
84160484Sobrien#ifdef md_elf_section_word
84260484Sobrien  {
84360484Sobrien    int md_attr = md_elf_section_word (str, len);
84460484Sobrien    if (md_attr >= 0)
84560484Sobrien      return md_attr;
84660484Sobrien  }
84760484Sobrien#endif
84860484Sobrien
84989857Sobrien  as_warn (_("unrecognized section attribute"));
85060484Sobrien  return 0;
85160484Sobrien}
85260484Sobrien
85389857Sobrienstatic int
85460484Sobrienobj_elf_section_type (str, len)
85560484Sobrien     char *str;
85660484Sobrien     size_t len;
85760484Sobrien{
85860484Sobrien  if (len == 8 && strncmp (str, "progbits", 8) == 0)
85960484Sobrien    return SHT_PROGBITS;
86060484Sobrien  if (len == 6 && strncmp (str, "nobits", 6) == 0)
86160484Sobrien    return SHT_NOBITS;
86260484Sobrien
86360484Sobrien#ifdef md_elf_section_type
86460484Sobrien  {
86560484Sobrien    int md_type = md_elf_section_type (str, len);
86660484Sobrien    if (md_type >= 0)
86760484Sobrien      return md_type;
86860484Sobrien  }
86960484Sobrien#endif
87060484Sobrien
87189857Sobrien  as_warn (_("unrecognized section type"));
87260484Sobrien  return 0;
87360484Sobrien}
87460484Sobrien
87589857Sobrien/* Get name of section.  */
87689857Sobrienstatic char *
87789857Sobrienobj_elf_section_name ()
87889857Sobrien{
87989857Sobrien  char *name;
88089857Sobrien
88189857Sobrien  SKIP_WHITESPACE ();
88289857Sobrien  if (*input_line_pointer == '"')
88389857Sobrien    {
88489857Sobrien      int dummy;
88589857Sobrien
88689857Sobrien      name = demand_copy_C_string (&dummy);
88789857Sobrien      if (name == NULL)
88889857Sobrien	{
88989857Sobrien	  ignore_rest_of_line ();
89089857Sobrien	  return NULL;
89189857Sobrien	}
89289857Sobrien    }
89389857Sobrien  else
89489857Sobrien    {
89589857Sobrien      char *end = input_line_pointer;
89689857Sobrien
89789857Sobrien      while (0 == strchr ("\n\t,; ", *end))
89889857Sobrien	end++;
89989857Sobrien      if (end == input_line_pointer)
90089857Sobrien	{
90189857Sobrien	  as_warn (_("missing name"));
90289857Sobrien	  ignore_rest_of_line ();
90389857Sobrien	  return NULL;
90489857Sobrien	}
90589857Sobrien
90689857Sobrien      name = xmalloc (end - input_line_pointer + 1);
90789857Sobrien      memcpy (name, input_line_pointer, end - input_line_pointer);
90889857Sobrien      name[end - input_line_pointer] = '\0';
90989857Sobrien      input_line_pointer = end;
91089857Sobrien    }
91189857Sobrien  SKIP_WHITESPACE ();
91289857Sobrien  return name;
91389857Sobrien}
91489857Sobrien
91560484Sobrienvoid
91660484Sobrienobj_elf_section (push)
91760484Sobrien     int push;
91860484Sobrien{
91989857Sobrien  char *name, *group_name, *beg;
92060484Sobrien  int type, attr, dummy;
92189857Sobrien  int entsize;
92260484Sobrien
92360484Sobrien#ifndef TC_I370
92433965Sjdp  if (flag_mri)
92533965Sjdp    {
92633965Sjdp      char mri_type;
92733965Sjdp
92860484Sobrien#ifdef md_flush_pending_output
92977298Sobrien      md_flush_pending_output ();
93060484Sobrien#endif
93160484Sobrien
93233965Sjdp      previous_section = now_seg;
93333965Sjdp      previous_subsection = now_subseg;
93433965Sjdp
93533965Sjdp      s_mri_sect (&mri_type);
93633965Sjdp
93733965Sjdp#ifdef md_elf_section_change_hook
93833965Sjdp      md_elf_section_change_hook ();
93933965Sjdp#endif
94033965Sjdp
94133965Sjdp      return;
94233965Sjdp    }
94360484Sobrien#endif /* ! defined (TC_I370) */
94433965Sjdp
94589857Sobrien  name = obj_elf_section_name ();
94689857Sobrien  if (name == NULL)
94789857Sobrien    return;
94833965Sjdp  type = SHT_NULL;
94933965Sjdp  attr = 0;
95089857Sobrien  group_name = NULL;
95189857Sobrien  entsize = 0;
95233965Sjdp
95333965Sjdp  if (*input_line_pointer == ',')
95433965Sjdp    {
95533965Sjdp      /* Skip the comma.  */
95633965Sjdp      ++input_line_pointer;
95733965Sjdp      SKIP_WHITESPACE ();
95838889Sjdp
95933965Sjdp      if (*input_line_pointer == '"')
96033965Sjdp	{
96160484Sobrien	  beg = demand_copy_C_string (&dummy);
96260484Sobrien	  if (beg == NULL)
96333965Sjdp	    {
96460484Sobrien	      ignore_rest_of_line ();
96560484Sobrien	      return;
96633965Sjdp	    }
96760484Sobrien	  attr |= obj_elf_parse_section_letters (beg, strlen (beg));
96833965Sjdp
96933965Sjdp	  SKIP_WHITESPACE ();
97033965Sjdp	  if (*input_line_pointer == ',')
97133965Sjdp	    {
97260484Sobrien	      char c;
97389857Sobrien	      char *save = input_line_pointer;
97489857Sobrien
97533965Sjdp	      ++input_line_pointer;
97633965Sjdp	      SKIP_WHITESPACE ();
97760484Sobrien	      c = *input_line_pointer;
97860484Sobrien	      if (c == '"')
97933965Sjdp		{
98060484Sobrien		  beg = demand_copy_C_string (&dummy);
98160484Sobrien		  if (beg == NULL)
98233965Sjdp		    {
98360484Sobrien		      ignore_rest_of_line ();
98460484Sobrien		      return;
98533965Sjdp		    }
98660484Sobrien		  type = obj_elf_section_type (beg, strlen (beg));
98733965Sjdp		}
98860484Sobrien	      else if (c == '@' || c == '%')
98960484Sobrien		{
99060484Sobrien		  beg = ++input_line_pointer;
99160484Sobrien		  c = get_symbol_end ();
99260484Sobrien		  *input_line_pointer = c;
99360484Sobrien		  type = obj_elf_section_type (beg, input_line_pointer - beg);
99460484Sobrien		}
99589857Sobrien	      else
99689857Sobrien		input_line_pointer = save;
99733965Sjdp	    }
99889857Sobrien
99989857Sobrien	  SKIP_WHITESPACE ();
100089857Sobrien	  if ((attr & SHF_MERGE) != 0 && *input_line_pointer == ',')
100189857Sobrien	    {
100289857Sobrien	      ++input_line_pointer;
100389857Sobrien	      SKIP_WHITESPACE ();
100489857Sobrien	      entsize = get_absolute_expression ();
100589857Sobrien	      SKIP_WHITESPACE ();
100689857Sobrien	      if (entsize < 0)
100789857Sobrien		{
100889857Sobrien		  as_warn (_("invalid merge entity size"));
100989857Sobrien		  attr &= ~SHF_MERGE;
101089857Sobrien		  entsize = 0;
101189857Sobrien		}
101289857Sobrien	    }
101389857Sobrien	  else if ((attr & SHF_MERGE) != 0)
101489857Sobrien	    {
101589857Sobrien	      as_warn (_("entity size for SHF_MERGE not specified"));
101689857Sobrien	      attr &= ~SHF_MERGE;
101789857Sobrien	    }
101889857Sobrien
101989857Sobrien	  if ((attr & SHF_GROUP) != 0 && *input_line_pointer == ',')
102089857Sobrien	    {
102189857Sobrien	      ++input_line_pointer;
102289857Sobrien	      group_name = obj_elf_section_name ();
102389857Sobrien	      if (group_name == NULL)
102489857Sobrien		attr &= ~SHF_GROUP;
102589857Sobrien	    }
102689857Sobrien	  else if ((attr & SHF_GROUP) != 0)
102789857Sobrien	    {
102889857Sobrien	      as_warn (_("group name for SHF_GROUP not specified"));
102989857Sobrien	      attr &= ~SHF_GROUP;
103089857Sobrien	    }
103133965Sjdp	}
103233965Sjdp      else
103333965Sjdp	{
103433965Sjdp	  do
103533965Sjdp	    {
103660484Sobrien	      char c;
103760484Sobrien
103833965Sjdp	      SKIP_WHITESPACE ();
103933965Sjdp	      if (*input_line_pointer != '#')
104033965Sjdp		{
104189857Sobrien		  as_warn (_("character following name is not '#'"));
104233965Sjdp		  ignore_rest_of_line ();
104333965Sjdp		  return;
104433965Sjdp		}
104560484Sobrien	      beg = ++input_line_pointer;
104660484Sobrien	      c = get_symbol_end ();
104760484Sobrien	      *input_line_pointer = c;
104860484Sobrien
104960484Sobrien	      attr |= obj_elf_section_word (beg, input_line_pointer - beg);
105060484Sobrien
105133965Sjdp	      SKIP_WHITESPACE ();
105233965Sjdp	    }
105333965Sjdp	  while (*input_line_pointer++ == ',');
105433965Sjdp	  --input_line_pointer;
105533965Sjdp	}
105633965Sjdp    }
105733965Sjdp
105860484Sobrien  demand_empty_rest_of_line ();
105933965Sjdp
106089857Sobrien  obj_elf_change_section (name, type, attr, entsize, group_name, push);
106133965Sjdp}
106233965Sjdp
106333965Sjdp/* Change to the .data section.  */
106433965Sjdp
106560484Sobrienvoid
106633965Sjdpobj_elf_data (i)
106733965Sjdp     int i;
106833965Sjdp{
106933965Sjdp#ifdef md_flush_pending_output
107033965Sjdp  md_flush_pending_output ();
107133965Sjdp#endif
107233965Sjdp
107333965Sjdp  previous_section = now_seg;
107433965Sjdp  previous_subsection = now_subseg;
107533965Sjdp  s_data (i);
107633965Sjdp
107733965Sjdp#ifdef md_elf_section_change_hook
107833965Sjdp  md_elf_section_change_hook ();
107933965Sjdp#endif
108033965Sjdp}
108133965Sjdp
108233965Sjdp/* Change to the .text section.  */
108333965Sjdp
108460484Sobrienvoid
108533965Sjdpobj_elf_text (i)
108633965Sjdp     int i;
108733965Sjdp{
108833965Sjdp#ifdef md_flush_pending_output
108933965Sjdp  md_flush_pending_output ();
109033965Sjdp#endif
109133965Sjdp
109233965Sjdp  previous_section = now_seg;
109333965Sjdp  previous_subsection = now_subseg;
109433965Sjdp  s_text (i);
109533965Sjdp
109633965Sjdp#ifdef md_elf_section_change_hook
109733965Sjdp  md_elf_section_change_hook ();
109833965Sjdp#endif
109933965Sjdp}
110033965Sjdp
110138889Sjdpstatic void
110238889Sjdpobj_elf_subsection (ignore)
110360484Sobrien     int ignore ATTRIBUTE_UNUSED;
110438889Sjdp{
110538889Sjdp  register int temp;
110638889Sjdp
110738889Sjdp#ifdef md_flush_pending_output
110838889Sjdp  md_flush_pending_output ();
110938889Sjdp#endif
111038889Sjdp
111138889Sjdp  previous_section = now_seg;
111238889Sjdp  previous_subsection = now_subseg;
111338889Sjdp
111438889Sjdp  temp = get_absolute_expression ();
111538889Sjdp  subseg_set (now_seg, (subsegT) temp);
111638889Sjdp  demand_empty_rest_of_line ();
111738889Sjdp
111838889Sjdp#ifdef md_elf_section_change_hook
111938889Sjdp  md_elf_section_change_hook ();
112038889Sjdp#endif
112138889Sjdp}
112238889Sjdp
112333965Sjdp/* This can be called from the processor backends if they change
112433965Sjdp   sections.  */
112533965Sjdp
112633965Sjdpvoid
112733965Sjdpobj_elf_section_change_hook ()
112833965Sjdp{
112933965Sjdp  previous_section = now_seg;
113033965Sjdp  previous_subsection = now_subseg;
113133965Sjdp}
113233965Sjdp
113333965Sjdpvoid
113433965Sjdpobj_elf_previous (ignore)
113560484Sobrien     int ignore ATTRIBUTE_UNUSED;
113633965Sjdp{
113760484Sobrien  segT new_section;
113860484Sobrien  int new_subsection;
113960484Sobrien
114033965Sjdp  if (previous_section == 0)
114133965Sjdp    {
114289857Sobrien      as_warn (_(".previous without corresponding .section; ignored"));
114333965Sjdp      return;
114433965Sjdp    }
114533965Sjdp
114633965Sjdp#ifdef md_flush_pending_output
114733965Sjdp  md_flush_pending_output ();
114833965Sjdp#endif
114933965Sjdp
115060484Sobrien  new_section = previous_section;
115160484Sobrien  new_subsection = previous_subsection;
115260484Sobrien  previous_section = now_seg;
115360484Sobrien  previous_subsection = now_subseg;
115460484Sobrien  subseg_set (new_section, new_subsection);
115533965Sjdp
115633965Sjdp#ifdef md_elf_section_change_hook
115733965Sjdp  md_elf_section_change_hook ();
115833965Sjdp#endif
115933965Sjdp}
116033965Sjdp
116133965Sjdpstatic void
116260484Sobrienobj_elf_popsection (xxx)
116360484Sobrien     int xxx ATTRIBUTE_UNUSED;
116460484Sobrien{
116560484Sobrien  struct section_stack *top = section_stack;
116660484Sobrien
116760484Sobrien  if (top == NULL)
116860484Sobrien    {
116989857Sobrien      as_warn (_(".popsection without corresponding .pushsection; ignored"));
117060484Sobrien      return;
117160484Sobrien    }
117260484Sobrien
117360484Sobrien#ifdef md_flush_pending_output
117460484Sobrien  md_flush_pending_output ();
117560484Sobrien#endif
117660484Sobrien
117760484Sobrien  section_stack = top->next;
117860484Sobrien  previous_section = top->prev_seg;
117960484Sobrien  previous_subsection = top->prev_subseg;
118060484Sobrien  subseg_set (top->seg, top->subseg);
118160484Sobrien  free (top);
118260484Sobrien
118360484Sobrien#ifdef md_elf_section_change_hook
118460484Sobrien  md_elf_section_change_hook ();
118560484Sobrien#endif
118660484Sobrien}
118760484Sobrien
118860484Sobrienstatic void
118933965Sjdpobj_elf_line (ignore)
119060484Sobrien     int ignore ATTRIBUTE_UNUSED;
119133965Sjdp{
119233965Sjdp  /* Assume delimiter is part of expression.  BSD4.2 as fails with
119377298Sobrien     delightful bug, so we are not being incompatible here.  */
119433965Sjdp  new_logical_line ((char *) NULL, (int) (get_absolute_expression ()));
119533965Sjdp  demand_empty_rest_of_line ();
119633965Sjdp}
119733965Sjdp
119860484Sobrien/* This handles the .symver pseudo-op, which is used to specify a
119933965Sjdp   symbol version.  The syntax is ``.symver NAME,SYMVERNAME''.
120033965Sjdp   SYMVERNAME may contain ELF_VER_CHR ('@') characters.  This
120133965Sjdp   pseudo-op causes the assembler to emit a symbol named SYMVERNAME
120233965Sjdp   with the same value as the symbol NAME.  */
120333965Sjdp
120433965Sjdpstatic void
120533965Sjdpobj_elf_symver (ignore)
120660484Sobrien     int ignore ATTRIBUTE_UNUSED;
120733965Sjdp{
120833965Sjdp  char *name;
120933965Sjdp  char c;
121089857Sobrien  char old_lexat;
121133965Sjdp  symbolS *sym;
121233965Sjdp
121333965Sjdp  name = input_line_pointer;
121433965Sjdp  c = get_symbol_end ();
121533965Sjdp
121633965Sjdp  sym = symbol_find_or_make (name);
121733965Sjdp
121833965Sjdp  *input_line_pointer = c;
121933965Sjdp
122033965Sjdp  SKIP_WHITESPACE ();
122133965Sjdp  if (*input_line_pointer != ',')
122233965Sjdp    {
122360484Sobrien      as_bad (_("expected comma after name in .symver"));
122433965Sjdp      ignore_rest_of_line ();
122533965Sjdp      return;
122633965Sjdp    }
122733965Sjdp
122833965Sjdp  ++input_line_pointer;
122933965Sjdp  name = input_line_pointer;
123033965Sjdp
123189857Sobrien  /* Temporarily include '@' in symbol names.  */
123289857Sobrien  old_lexat = lex_type[(unsigned char) '@'];
123389857Sobrien  lex_type[(unsigned char) '@'] |= LEX_NAME;
123489857Sobrien  c = get_symbol_end ();
123589857Sobrien  lex_type[(unsigned char) '@'] = old_lexat;
123689857Sobrien
123777298Sobrien  if (symbol_get_obj (sym)->versioned_name == NULL)
123877298Sobrien    {
123977298Sobrien      symbol_get_obj (sym)->versioned_name = xstrdup (name);
124033965Sjdp
124177298Sobrien      *input_line_pointer = c;
124233965Sjdp
124377298Sobrien      if (strchr (symbol_get_obj (sym)->versioned_name,
124477298Sobrien		  ELF_VER_CHR) == NULL)
124577298Sobrien	{
124677298Sobrien	  as_bad (_("missing version name in `%s' for symbol `%s'"),
124777298Sobrien		  symbol_get_obj (sym)->versioned_name,
124877298Sobrien		  S_GET_NAME (sym));
124977298Sobrien	  ignore_rest_of_line ();
125077298Sobrien	  return;
125177298Sobrien	}
125277298Sobrien    }
125377298Sobrien  else
125433965Sjdp    {
125577298Sobrien      if (strcmp (symbol_get_obj (sym)->versioned_name, name))
125677298Sobrien	{
125777298Sobrien	  as_bad (_("multiple versions [`%s'|`%s'] for symbol `%s'"),
125877298Sobrien		  name, symbol_get_obj (sym)->versioned_name,
125977298Sobrien		  S_GET_NAME (sym));
126077298Sobrien	  ignore_rest_of_line ();
126177298Sobrien	  return;
126277298Sobrien	}
126377298Sobrien
126477298Sobrien      *input_line_pointer = c;
126533965Sjdp    }
126633965Sjdp
126733965Sjdp  demand_empty_rest_of_line ();
126833965Sjdp}
126933965Sjdp
127060484Sobrien/* This handles the .vtable_inherit pseudo-op, which is used to indicate
127160484Sobrien   to the linker the hierarchy in which a particular table resides.  The
127260484Sobrien   syntax is ".vtable_inherit CHILDNAME, PARENTNAME".  */
127360484Sobrien
127477298Sobrienstruct fix *
127560484Sobrienobj_elf_vtable_inherit (ignore)
127660484Sobrien     int ignore ATTRIBUTE_UNUSED;
127760484Sobrien{
127860484Sobrien  char *cname, *pname;
127960484Sobrien  symbolS *csym, *psym;
128060484Sobrien  char c, bad = 0;
128160484Sobrien
128260484Sobrien  if (*input_line_pointer == '#')
128360484Sobrien    ++input_line_pointer;
128460484Sobrien
128560484Sobrien  cname = input_line_pointer;
128660484Sobrien  c = get_symbol_end ();
128760484Sobrien  csym = symbol_find (cname);
128860484Sobrien
128960484Sobrien  /* GCFIXME: should check that we don't have two .vtable_inherits for
129060484Sobrien     the same child symbol.  Also, we can currently only do this if the
129160484Sobrien     child symbol is already exists and is placed in a fragment.  */
129260484Sobrien
129360484Sobrien  if (csym == NULL || symbol_get_frag (csym) == NULL)
129460484Sobrien    {
129560484Sobrien      as_bad ("expected `%s' to have already been set for .vtable_inherit",
129660484Sobrien	      cname);
129760484Sobrien      bad = 1;
129860484Sobrien    }
129960484Sobrien
130060484Sobrien  *input_line_pointer = c;
130160484Sobrien
130260484Sobrien  SKIP_WHITESPACE ();
130360484Sobrien  if (*input_line_pointer != ',')
130460484Sobrien    {
130560484Sobrien      as_bad ("expected comma after name in .vtable_inherit");
130660484Sobrien      ignore_rest_of_line ();
130777298Sobrien      return NULL;
130860484Sobrien    }
130960484Sobrien
131060484Sobrien  ++input_line_pointer;
131160484Sobrien  SKIP_WHITESPACE ();
131260484Sobrien
131360484Sobrien  if (*input_line_pointer == '#')
131460484Sobrien    ++input_line_pointer;
131560484Sobrien
131660484Sobrien  if (input_line_pointer[0] == '0'
131760484Sobrien      && (input_line_pointer[1] == '\0'
131889857Sobrien	  || ISSPACE (input_line_pointer[1])))
131960484Sobrien    {
132060484Sobrien      psym = section_symbol (absolute_section);
132160484Sobrien      ++input_line_pointer;
132260484Sobrien    }
132360484Sobrien  else
132460484Sobrien    {
132560484Sobrien      pname = input_line_pointer;
132660484Sobrien      c = get_symbol_end ();
132760484Sobrien      psym = symbol_find_or_make (pname);
132860484Sobrien      *input_line_pointer = c;
132960484Sobrien    }
133060484Sobrien
133160484Sobrien  demand_empty_rest_of_line ();
133260484Sobrien
133360484Sobrien  if (bad)
133477298Sobrien    return NULL;
133560484Sobrien
133660484Sobrien  assert (symbol_get_value_expression (csym)->X_op == O_constant);
133777298Sobrien  return fix_new (symbol_get_frag (csym),
133877298Sobrien		  symbol_get_value_expression (csym)->X_add_number,
133977298Sobrien		  0, psym, 0, 0, BFD_RELOC_VTABLE_INHERIT);
134060484Sobrien}
134160484Sobrien
134260484Sobrien/* This handles the .vtable_entry pseudo-op, which is used to indicate
134360484Sobrien   to the linker that a vtable slot was used.  The syntax is
134460484Sobrien   ".vtable_entry tablename, offset".  */
134560484Sobrien
134677298Sobrienstruct fix *
134760484Sobrienobj_elf_vtable_entry (ignore)
134860484Sobrien     int ignore ATTRIBUTE_UNUSED;
134960484Sobrien{
135060484Sobrien  char *name;
135160484Sobrien  symbolS *sym;
135260484Sobrien  offsetT offset;
135360484Sobrien  char c;
135460484Sobrien
135560484Sobrien  if (*input_line_pointer == '#')
135660484Sobrien    ++input_line_pointer;
135760484Sobrien
135860484Sobrien  name = input_line_pointer;
135960484Sobrien  c = get_symbol_end ();
136060484Sobrien  sym = symbol_find_or_make (name);
136160484Sobrien  *input_line_pointer = c;
136260484Sobrien
136360484Sobrien  SKIP_WHITESPACE ();
136460484Sobrien  if (*input_line_pointer != ',')
136560484Sobrien    {
136660484Sobrien      as_bad ("expected comma after name in .vtable_entry");
136760484Sobrien      ignore_rest_of_line ();
136877298Sobrien      return NULL;
136960484Sobrien    }
137060484Sobrien
137160484Sobrien  ++input_line_pointer;
137260484Sobrien  if (*input_line_pointer == '#')
137360484Sobrien    ++input_line_pointer;
137460484Sobrien
137560484Sobrien  offset = get_absolute_expression ();
137660484Sobrien
137777298Sobrien  demand_empty_rest_of_line ();
137860484Sobrien
137977298Sobrien  return fix_new (frag_now, frag_now_fix (), 0, sym, offset, 0,
138077298Sobrien		  BFD_RELOC_VTABLE_ENTRY);
138160484Sobrien}
138260484Sobrien
138333965Sjdpvoid
138460484Sobrienelf_obj_read_begin_hook ()
138533965Sjdp{
138633965Sjdp#ifdef NEED_ECOFF_DEBUG
138733965Sjdp  if (ECOFF_DEBUGGING)
138833965Sjdp    ecoff_read_begin_hook ();
138933965Sjdp#endif
139033965Sjdp}
139133965Sjdp
139233965Sjdpvoid
139360484Sobrienelf_obj_symbol_new_hook (symbolP)
139433965Sjdp     symbolS *symbolP;
139533965Sjdp{
139660484Sobrien  struct elf_obj_sy *sy_obj;
139733965Sjdp
139860484Sobrien  sy_obj = symbol_get_obj (symbolP);
139960484Sobrien  sy_obj->size = NULL;
140060484Sobrien  sy_obj->versioned_name = NULL;
140160484Sobrien
140233965Sjdp#ifdef NEED_ECOFF_DEBUG
140333965Sjdp  if (ECOFF_DEBUGGING)
140433965Sjdp    ecoff_symbol_new_hook (symbolP);
140533965Sjdp#endif
140633965Sjdp}
140733965Sjdp
140889857Sobrien/* When setting one symbol equal to another, by default we probably
140989857Sobrien   want them to have the same "size", whatever it means in the current
141089857Sobrien   context.  */
141189857Sobrien
141233965Sjdpvoid
141389857Sobrienelf_copy_symbol_attributes (dest, src)
141489857Sobrien     symbolS *dest, *src;
141589857Sobrien{
141689857Sobrien  struct elf_obj_sy *srcelf = symbol_get_obj (src);
141789857Sobrien  struct elf_obj_sy *destelf = symbol_get_obj (dest);
141889857Sobrien  if (srcelf->size)
141989857Sobrien    {
142089857Sobrien      if (destelf->size == NULL)
142189857Sobrien	destelf->size =
142289857Sobrien	  (expressionS *) xmalloc (sizeof (expressionS));
142389857Sobrien      *destelf->size = *srcelf->size;
142489857Sobrien    }
142589857Sobrien  else
142689857Sobrien    {
142789857Sobrien      if (destelf->size != NULL)
142889857Sobrien	free (destelf->size);
142989857Sobrien      destelf->size = NULL;
143089857Sobrien    }
143189857Sobrien  S_SET_SIZE (dest, S_GET_SIZE (src));
143294536Sobrien  /* Don't copy visibility.  */
143394536Sobrien  S_SET_OTHER (dest, (ELF_ST_VISIBILITY (S_GET_OTHER (dest))
143494536Sobrien		      | (S_GET_OTHER (src) & ~ELF_ST_VISIBILITY (-1))));
143589857Sobrien}
143689857Sobrien
143789857Sobrienvoid
143833965Sjdpobj_elf_version (ignore)
143960484Sobrien     int ignore ATTRIBUTE_UNUSED;
144033965Sjdp{
144133965Sjdp  char *name;
144233965Sjdp  unsigned int c;
144333965Sjdp  char *p;
144433965Sjdp  asection *seg = now_seg;
144533965Sjdp  subsegT subseg = now_subseg;
144633965Sjdp  Elf_Internal_Note i_note;
144733965Sjdp  Elf_External_Note e_note;
144833965Sjdp  asection *note_secp = (asection *) NULL;
144989857Sobrien  int len;
145033965Sjdp
145133965Sjdp  SKIP_WHITESPACE ();
145233965Sjdp  if (*input_line_pointer == '\"')
145333965Sjdp    {
145477298Sobrien      ++input_line_pointer;	/* -> 1st char of string.  */
145533965Sjdp      name = input_line_pointer;
145633965Sjdp
145733965Sjdp      while (is_a_char (c = next_char_of_string ()))
145833965Sjdp	;
145933965Sjdp      c = *input_line_pointer;
146033965Sjdp      *input_line_pointer = '\0';
146133965Sjdp      *(input_line_pointer - 1) = '\0';
146233965Sjdp      *input_line_pointer = c;
146333965Sjdp
146433965Sjdp      /* create the .note section */
146533965Sjdp
146633965Sjdp      note_secp = subseg_new (".note", 0);
146733965Sjdp      bfd_set_section_flags (stdoutput,
146833965Sjdp			     note_secp,
146933965Sjdp			     SEC_HAS_CONTENTS | SEC_READONLY);
147033965Sjdp
147133965Sjdp      /* process the version string */
147233965Sjdp
147333965Sjdp      len = strlen (name);
147433965Sjdp
147533965Sjdp      i_note.namesz = ((len + 1) + 3) & ~3; /* round this to word boundary */
147633965Sjdp      i_note.descsz = 0;	/* no description */
147733965Sjdp      i_note.type = NT_VERSION;
147833965Sjdp      p = frag_more (sizeof (e_note.namesz));
147989857Sobrien      md_number_to_chars (p, (valueT) i_note.namesz, sizeof (e_note.namesz));
148033965Sjdp      p = frag_more (sizeof (e_note.descsz));
148189857Sobrien      md_number_to_chars (p, (valueT) i_note.descsz, sizeof (e_note.descsz));
148233965Sjdp      p = frag_more (sizeof (e_note.type));
148389857Sobrien      md_number_to_chars (p, (valueT) i_note.type, sizeof (e_note.type));
148489857Sobrien      p = frag_more (len + 1);
148589857Sobrien      strcpy (p, name);
148633965Sjdp
148733965Sjdp      frag_align (2, 0, 0);
148833965Sjdp
148933965Sjdp      subseg_set (seg, subseg);
149033965Sjdp    }
149133965Sjdp  else
149233965Sjdp    {
149389857Sobrien      as_bad (_("expected quoted string"));
149433965Sjdp    }
149533965Sjdp  demand_empty_rest_of_line ();
149633965Sjdp}
149733965Sjdp
149833965Sjdpstatic void
149933965Sjdpobj_elf_size (ignore)
150060484Sobrien     int ignore ATTRIBUTE_UNUSED;
150133965Sjdp{
150233965Sjdp  char *name = input_line_pointer;
150333965Sjdp  char c = get_symbol_end ();
150433965Sjdp  char *p;
150533965Sjdp  expressionS exp;
150633965Sjdp  symbolS *sym;
150733965Sjdp
150833965Sjdp  p = input_line_pointer;
150933965Sjdp  *p = c;
151033965Sjdp  SKIP_WHITESPACE ();
151133965Sjdp  if (*input_line_pointer != ',')
151233965Sjdp    {
151333965Sjdp      *p = 0;
151460484Sobrien      as_bad (_("expected comma after name `%s' in .size directive"), name);
151533965Sjdp      *p = c;
151633965Sjdp      ignore_rest_of_line ();
151733965Sjdp      return;
151833965Sjdp    }
151933965Sjdp  input_line_pointer++;
152033965Sjdp  expression (&exp);
152133965Sjdp  if (exp.X_op == O_absent)
152233965Sjdp    {
152360484Sobrien      as_bad (_("missing expression in .size directive"));
152433965Sjdp      exp.X_op = O_constant;
152533965Sjdp      exp.X_add_number = 0;
152633965Sjdp    }
152733965Sjdp  *p = 0;
152833965Sjdp  sym = symbol_find_or_make (name);
152933965Sjdp  *p = c;
153033965Sjdp  if (exp.X_op == O_constant)
153189857Sobrien    {
153289857Sobrien      S_SET_SIZE (sym, exp.X_add_number);
153389857Sobrien      if (symbol_get_obj (sym)->size)
153489857Sobrien	{
153589857Sobrien	  xfree (symbol_get_obj (sym)->size);
153689857Sobrien	  symbol_get_obj (sym)->size = NULL;
153789857Sobrien	}
153889857Sobrien    }
153933965Sjdp  else
154033965Sjdp    {
154160484Sobrien      symbol_get_obj (sym)->size =
154260484Sobrien	(expressionS *) xmalloc (sizeof (expressionS));
154360484Sobrien      *symbol_get_obj (sym)->size = exp;
154433965Sjdp    }
154533965Sjdp  demand_empty_rest_of_line ();
154633965Sjdp}
154733965Sjdp
154833965Sjdp/* Handle the ELF .type pseudo-op.  This sets the type of a symbol.
154977298Sobrien   There are five syntaxes:
155060484Sobrien
155160484Sobrien   The first (used on Solaris) is
155233965Sjdp       .type SYM,#function
155333965Sjdp   The second (used on UnixWare) is
155433965Sjdp       .type SYM,@function
155533965Sjdp   The third (reportedly to be used on Irix 6.0) is
155633965Sjdp       .type SYM STT_FUNC
155760484Sobrien   The fourth (used on NetBSD/Arm and Linux/ARM) is
155860484Sobrien       .type SYM,%function
155977298Sobrien   The fifth (used on SVR4/860) is
156077298Sobrien       .type SYM,"function"
156133965Sjdp   */
156233965Sjdp
156333965Sjdpstatic void
156433965Sjdpobj_elf_type (ignore)
156560484Sobrien     int ignore ATTRIBUTE_UNUSED;
156633965Sjdp{
156733965Sjdp  char *name;
156833965Sjdp  char c;
156933965Sjdp  int type;
157033965Sjdp  const char *typename;
157133965Sjdp  symbolS *sym;
157277298Sobrien  elf_symbol_type *elfsym;
157333965Sjdp
157433965Sjdp  name = input_line_pointer;
157533965Sjdp  c = get_symbol_end ();
157633965Sjdp  sym = symbol_find_or_make (name);
157777298Sobrien  elfsym = (elf_symbol_type *) symbol_get_bfdsym (sym);
157833965Sjdp  *input_line_pointer = c;
157933965Sjdp
158033965Sjdp  SKIP_WHITESPACE ();
158133965Sjdp  if (*input_line_pointer == ',')
158233965Sjdp    ++input_line_pointer;
158333965Sjdp
158433965Sjdp  SKIP_WHITESPACE ();
158560484Sobrien  if (   *input_line_pointer == '#'
158660484Sobrien      || *input_line_pointer == '@'
158777298Sobrien      || *input_line_pointer == '"'
158860484Sobrien      || *input_line_pointer == '%')
158933965Sjdp    ++input_line_pointer;
159033965Sjdp
159133965Sjdp  typename = input_line_pointer;
159233965Sjdp  c = get_symbol_end ();
159333965Sjdp
159433965Sjdp  type = 0;
159533965Sjdp  if (strcmp (typename, "function") == 0
159633965Sjdp      || strcmp (typename, "STT_FUNC") == 0)
159733965Sjdp    type = BSF_FUNCTION;
159833965Sjdp  else if (strcmp (typename, "object") == 0
159933965Sjdp	   || strcmp (typename, "STT_OBJECT") == 0)
160033965Sjdp    type = BSF_OBJECT;
160177298Sobrien#ifdef md_elf_symbol_type
160277298Sobrien  else if ((type = md_elf_symbol_type (typename, sym, elfsym)) != -1)
160377298Sobrien    ;
160477298Sobrien#endif
160533965Sjdp  else
160689857Sobrien    as_bad (_("unrecognized symbol type \"%s\""), typename);
160733965Sjdp
160833965Sjdp  *input_line_pointer = c;
160933965Sjdp
161077298Sobrien  if (*input_line_pointer == '"')
161177298Sobrien    ++input_line_pointer;
161233965Sjdp
161377298Sobrien  elfsym->symbol.flags |= type;
161477298Sobrien
161533965Sjdp  demand_empty_rest_of_line ();
161633965Sjdp}
161733965Sjdp
161833965Sjdpstatic void
161933965Sjdpobj_elf_ident (ignore)
162060484Sobrien     int ignore ATTRIBUTE_UNUSED;
162133965Sjdp{
162233965Sjdp  static segT comment_section;
162333965Sjdp  segT old_section = now_seg;
162433965Sjdp  int old_subsection = now_subseg;
162533965Sjdp
162660484Sobrien#ifdef md_flush_pending_output
162760484Sobrien  md_flush_pending_output ();
162860484Sobrien#endif
162960484Sobrien
163033965Sjdp  if (!comment_section)
163133965Sjdp    {
163233965Sjdp      char *p;
163333965Sjdp      comment_section = subseg_new (".comment", 0);
163433965Sjdp      bfd_set_section_flags (stdoutput, comment_section,
163533965Sjdp			     SEC_READONLY | SEC_HAS_CONTENTS);
163633965Sjdp      p = frag_more (1);
163733965Sjdp      *p = 0;
163833965Sjdp    }
163933965Sjdp  else
164033965Sjdp    subseg_set (comment_section, 0);
164133965Sjdp  stringer (1);
164233965Sjdp  subseg_set (old_section, old_subsection);
164333965Sjdp}
164433965Sjdp
164533965Sjdp#ifdef INIT_STAB_SECTION
164633965Sjdp
164733965Sjdp/* The first entry in a .stabs section is special.  */
164833965Sjdp
164933965Sjdpvoid
165033965Sjdpobj_elf_init_stab_section (seg)
165133965Sjdp     segT seg;
165233965Sjdp{
165333965Sjdp  char *file;
165433965Sjdp  char *p;
165533965Sjdp  char *stabstr_name;
165633965Sjdp  unsigned int stroff;
165733965Sjdp
165833965Sjdp  /* Force the section to align to a longword boundary.  Without this,
165933965Sjdp     UnixWare ar crashes.  */
166033965Sjdp  bfd_set_section_alignment (stdoutput, seg, 2);
166133965Sjdp
166277298Sobrien  /* Make space for this first symbol.  */
166333965Sjdp  p = frag_more (12);
166477298Sobrien  /* Zero it out.  */
166533965Sjdp  memset (p, 0, 12);
166633965Sjdp  as_where (&file, (unsigned int *) NULL);
166789857Sobrien  stabstr_name = (char *) xmalloc (strlen (segment_name (seg)) + 4);
166833965Sjdp  strcpy (stabstr_name, segment_name (seg));
166933965Sjdp  strcat (stabstr_name, "str");
167033965Sjdp  stroff = get_stab_string_offset (file, stabstr_name);
167133965Sjdp  know (stroff == 1);
167233965Sjdp  md_number_to_chars (p, stroff, 4);
167333965Sjdp  seg_info (seg)->stabu.p = p;
167433965Sjdp}
167533965Sjdp
167633965Sjdp#endif
167733965Sjdp
167833965Sjdp/* Fill in the counts in the first entry in a .stabs section.  */
167933965Sjdp
168033965Sjdpstatic void
168133965Sjdpadjust_stab_sections (abfd, sec, xxx)
168233965Sjdp     bfd *abfd;
168333965Sjdp     asection *sec;
168460484Sobrien     PTR xxx ATTRIBUTE_UNUSED;
168533965Sjdp{
168633965Sjdp  char *name;
168733965Sjdp  asection *strsec;
168833965Sjdp  char *p;
168933965Sjdp  int strsz, nsyms;
169033965Sjdp
169133965Sjdp  if (strncmp (".stab", sec->name, 5))
169233965Sjdp    return;
169333965Sjdp  if (!strcmp ("str", sec->name + strlen (sec->name) - 3))
169433965Sjdp    return;
169533965Sjdp
169633965Sjdp  name = (char *) alloca (strlen (sec->name) + 4);
169733965Sjdp  strcpy (name, sec->name);
169833965Sjdp  strcat (name, "str");
169933965Sjdp  strsec = bfd_get_section_by_name (abfd, name);
170033965Sjdp  if (strsec)
170133965Sjdp    strsz = bfd_section_size (abfd, strsec);
170233965Sjdp  else
170333965Sjdp    strsz = 0;
170433965Sjdp  nsyms = bfd_section_size (abfd, sec) / 12 - 1;
170533965Sjdp
170633965Sjdp  p = seg_info (sec)->stabu.p;
170733965Sjdp  assert (p != 0);
170833965Sjdp
170933965Sjdp  bfd_h_put_16 (abfd, (bfd_vma) nsyms, (bfd_byte *) p + 6);
171033965Sjdp  bfd_h_put_32 (abfd, (bfd_vma) strsz, (bfd_byte *) p + 8);
171133965Sjdp}
171233965Sjdp
171333965Sjdp#ifdef NEED_ECOFF_DEBUG
171433965Sjdp
171533965Sjdp/* This function is called by the ECOFF code.  It is supposed to
171633965Sjdp   record the external symbol information so that the backend can
171733965Sjdp   write it out correctly.  The ELF backend doesn't actually handle
171833965Sjdp   this at the moment, so we do it ourselves.  We save the information
171933965Sjdp   in the symbol.  */
172033965Sjdp
172133965Sjdpvoid
172233965Sjdpelf_ecoff_set_ext (sym, ext)
172333965Sjdp     symbolS *sym;
172433965Sjdp     struct ecoff_extr *ext;
172533965Sjdp{
172660484Sobrien  symbol_get_bfdsym (sym)->udata.p = (PTR) ext;
172733965Sjdp}
172833965Sjdp
172933965Sjdp/* This function is called by bfd_ecoff_debug_externals.  It is
173033965Sjdp   supposed to *EXT to the external symbol information, and return
173133965Sjdp   whether the symbol should be used at all.  */
173233965Sjdp
173333965Sjdpstatic boolean
173433965Sjdpelf_get_extr (sym, ext)
173533965Sjdp     asymbol *sym;
173633965Sjdp     EXTR *ext;
173733965Sjdp{
173833965Sjdp  if (sym->udata.p == NULL)
173933965Sjdp    return false;
174033965Sjdp  *ext = *(EXTR *) sym->udata.p;
174133965Sjdp  return true;
174233965Sjdp}
174333965Sjdp
174433965Sjdp/* This function is called by bfd_ecoff_debug_externals.  It has
174533965Sjdp   nothing to do for ELF.  */
174633965Sjdp
174733965Sjdp/*ARGSUSED*/
174833965Sjdpstatic void
174933965Sjdpelf_set_index (sym, indx)
175060484Sobrien     asymbol *sym ATTRIBUTE_UNUSED;
175160484Sobrien     bfd_size_type indx ATTRIBUTE_UNUSED;
175233965Sjdp{
175333965Sjdp}
175433965Sjdp
175533965Sjdp#endif /* NEED_ECOFF_DEBUG */
175633965Sjdp
175733965Sjdpvoid
175833965Sjdpelf_frob_symbol (symp, puntp)
175933965Sjdp     symbolS *symp;
176033965Sjdp     int *puntp;
176133965Sjdp{
176260484Sobrien  struct elf_obj_sy *sy_obj;
176360484Sobrien
176433965Sjdp#ifdef NEED_ECOFF_DEBUG
176533965Sjdp  if (ECOFF_DEBUGGING)
176633965Sjdp    ecoff_frob_symbol (symp);
176733965Sjdp#endif
176833965Sjdp
176960484Sobrien  sy_obj = symbol_get_obj (symp);
177060484Sobrien
177160484Sobrien  if (sy_obj->size != NULL)
177233965Sjdp    {
177360484Sobrien      switch (sy_obj->size->X_op)
177433965Sjdp	{
177533965Sjdp	case O_subtract:
177633965Sjdp	  S_SET_SIZE (symp,
177760484Sobrien		      (S_GET_VALUE (sy_obj->size->X_add_symbol)
177860484Sobrien		       + sy_obj->size->X_add_number
177960484Sobrien		       - S_GET_VALUE (sy_obj->size->X_op_symbol)));
178033965Sjdp	  break;
178133965Sjdp	case O_constant:
178233965Sjdp	  S_SET_SIZE (symp,
178360484Sobrien		      (S_GET_VALUE (sy_obj->size->X_add_symbol)
178460484Sobrien		       + sy_obj->size->X_add_number));
178533965Sjdp	  break;
178633965Sjdp	default:
178760484Sobrien	  as_bad (_(".size expression too complicated to fix up"));
178833965Sjdp	  break;
178933965Sjdp	}
179060484Sobrien      free (sy_obj->size);
179160484Sobrien      sy_obj->size = NULL;
179233965Sjdp    }
179333965Sjdp
179460484Sobrien  if (sy_obj->versioned_name != NULL)
179533965Sjdp    {
179677298Sobrien      char *p;
179777298Sobrien
179877298Sobrien      p = strchr (sy_obj->versioned_name, ELF_VER_CHR);
179977298Sobrien      know (p != NULL);
180077298Sobrien
180133965Sjdp      /* This symbol was given a new name with the .symver directive.
180233965Sjdp
180333965Sjdp         If this is an external reference, just rename the symbol to
180433965Sjdp         include the version string.  This will make the relocs be
180533965Sjdp         against the correct versioned symbol.
180633965Sjdp
180733965Sjdp	 If this is a definition, add an alias.  FIXME: Using an alias
180833965Sjdp	 will permit the debugging information to refer to the right
180933965Sjdp	 symbol.  However, it's not clear whether it is the best
181033965Sjdp	 approach.  */
181133965Sjdp
181233965Sjdp      if (! S_IS_DEFINED (symp))
181333965Sjdp	{
181433965Sjdp	  /* Verify that the name isn't using the @@ syntax--this is
181533965Sjdp             reserved for definitions of the default version to link
181633965Sjdp             against.  */
181733965Sjdp	  if (p[1] == ELF_VER_CHR)
181833965Sjdp	    {
181960484Sobrien	      as_bad (_("invalid attempt to declare external version name as default in symbol `%s'"),
182060484Sobrien		      sy_obj->versioned_name);
182133965Sjdp	      *puntp = true;
182233965Sjdp	    }
182360484Sobrien	  S_SET_NAME (symp, sy_obj->versioned_name);
182433965Sjdp	}
182533965Sjdp      else
182633965Sjdp	{
182777298Sobrien	  if (p [1] == ELF_VER_CHR && p [2] == ELF_VER_CHR)
182877298Sobrien	    {
182977298Sobrien	      size_t l;
183033965Sjdp
183177298Sobrien	      /* The @@@ syntax is a special case. It renames the
183277298Sobrien		 symbol name to versioned_name with one `@' removed.  */
183377298Sobrien	      l = strlen (&p[3]) + 1;
183477298Sobrien	      memmove (&p [2], &p[3], l);
183577298Sobrien	      S_SET_NAME (symp, sy_obj->versioned_name);
183677298Sobrien	    }
183777298Sobrien	  else
183877298Sobrien	    {
183977298Sobrien	      symbolS *symp2;
184033965Sjdp
184177298Sobrien	      /* FIXME: Creating a new symbol here is risky.  We're
184277298Sobrien		 in the final loop over the symbol table.  We can
184377298Sobrien		 get away with it only because the symbol goes to
184477298Sobrien		 the end of the list, where the loop will still see
184577298Sobrien		 it.  It would probably be better to do this in
184677298Sobrien		 obj_frob_file_before_adjust.  */
184733965Sjdp
184877298Sobrien	      symp2 = symbol_find_or_make (sy_obj->versioned_name);
184933965Sjdp
185077298Sobrien	      /* Now we act as though we saw symp2 = sym.  */
185133965Sjdp
185277298Sobrien	      S_SET_SEGMENT (symp2, S_GET_SEGMENT (symp));
185333965Sjdp
185477298Sobrien	      /* Subtracting out the frag address here is a hack
185577298Sobrien		 because we are in the middle of the final loop.  */
185677298Sobrien	      S_SET_VALUE (symp2,
185777298Sobrien			   (S_GET_VALUE (symp)
185877298Sobrien			    - symbol_get_frag (symp)->fr_address));
185933965Sjdp
186077298Sobrien	      symbol_set_frag (symp2, symbol_get_frag (symp));
186133965Sjdp
186277298Sobrien	      /* This will copy over the size information.  */
186377298Sobrien	      copy_symbol_attributes (symp2, symp);
186433965Sjdp
186594536Sobrien	      S_SET_OTHER (symp2, S_GET_OTHER (symp));
186694536Sobrien
186777298Sobrien	      if (S_IS_WEAK (symp))
186877298Sobrien		S_SET_WEAK (symp2);
186977298Sobrien
187077298Sobrien	      if (S_IS_EXTERNAL (symp))
187177298Sobrien		S_SET_EXTERNAL (symp2);
187277298Sobrien	    }
187333965Sjdp	}
187433965Sjdp    }
187533965Sjdp
187633965Sjdp  /* Double check weak symbols.  */
187760484Sobrien  if (S_IS_WEAK (symp))
187833965Sjdp    {
187933965Sjdp      if (S_IS_COMMON (symp))
188089857Sobrien	as_bad (_("symbol `%s' can not be both weak and common"),
188133965Sjdp		S_GET_NAME (symp));
188233965Sjdp    }
188333965Sjdp
188433965Sjdp#ifdef TC_MIPS
188533965Sjdp  /* The Irix 5 and 6 assemblers set the type of any common symbol and
188638889Sjdp     any undefined non-function symbol to STT_OBJECT.  We try to be
188738889Sjdp     compatible, since newer Irix 5 and 6 linkers care.  However, we
188838889Sjdp     only set undefined symbols to be STT_OBJECT if we are on Irix,
188938889Sjdp     because that is the only time gcc will generate the necessary
189038889Sjdp     .global directives to mark functions.  */
189138889Sjdp
189238889Sjdp  if (S_IS_COMMON (symp))
189360484Sobrien    symbol_get_bfdsym (symp)->flags |= BSF_OBJECT;
189438889Sjdp
189538889Sjdp  if (strstr (TARGET_OS, "irix") != NULL
189660484Sobrien      && ! S_IS_DEFINED (symp)
189760484Sobrien      && (symbol_get_bfdsym (symp)->flags & BSF_FUNCTION) == 0)
189860484Sobrien    symbol_get_bfdsym (symp)->flags |= BSF_OBJECT;
189933965Sjdp#endif
190033965Sjdp
190160484Sobrien#if 0 /* TC_PPC */
190260484Sobrien  /* If TC_PPC is defined, we used to force the type of a symbol to be
190360484Sobrien     BSF_OBJECT if it was otherwise unset.  This was required by some
190460484Sobrien     version of VxWorks.  Thomas de Lellis <tdel@windriver.com> says
190560484Sobrien     that this is no longer needed, so it is now commented out.  */
190660484Sobrien  if ((symbol_get_bfdsym (symp)->flags
190760484Sobrien       & (BSF_FUNCTION | BSF_FILE | BSF_SECTION_SYM)) == 0
190833965Sjdp      && S_IS_DEFINED (symp))
190960484Sobrien    symbol_get_bfdsym (symp)->flags |= BSF_OBJECT;
191033965Sjdp#endif
191133965Sjdp}
191233965Sjdp
191389857Sobrienstruct group_list
191489857Sobrien{
191589857Sobrien  asection **head;		/* Section lists.  */
191689857Sobrien  unsigned int *elt_count;	/* Number of sections in each list.  */
191789857Sobrien  unsigned int num_group;	/* Number of lists.  */
191889857Sobrien};
191989857Sobrien
192089857Sobrien/* Called via bfd_map_over_sections.  If SEC is a member of a group,
192189857Sobrien   add it to a list of sections belonging to the group.  INF is a
192289857Sobrien   pointer to a struct group_list, which is where we store the head of
192389857Sobrien   each list.  */
192489857Sobrien
192589857Sobrienstatic void
192689857Sobrienbuild_group_lists (abfd, sec, inf)
192789857Sobrien     bfd *abfd ATTRIBUTE_UNUSED;
192889857Sobrien     asection *sec;
192989857Sobrien     PTR inf;
193089857Sobrien{
193189857Sobrien  struct group_list *list = (struct group_list *) inf;
193289857Sobrien  const char *group_name = elf_group_name (sec);
193389857Sobrien  unsigned int i;
193489857Sobrien
193589857Sobrien  if (group_name == NULL)
193689857Sobrien    return;
193789857Sobrien
193889857Sobrien  /* If this group already has a list, add the section to the head of
193989857Sobrien     the list.  */
194089857Sobrien  for (i = 0; i < list->num_group; i++)
194189857Sobrien    {
194289857Sobrien      if (strcmp (group_name, elf_group_name (list->head[i])) == 0)
194389857Sobrien	{
194489857Sobrien	  elf_next_in_group (sec) = list->head[i];
194589857Sobrien	  list->head[i] = sec;
194689857Sobrien	  list->elt_count[i] += 1;
194789857Sobrien	  return;
194889857Sobrien	}
194989857Sobrien    }
195089857Sobrien
195189857Sobrien  /* New group.  Make the arrays bigger in chunks to minimize calls to
195289857Sobrien     realloc.  */
195389857Sobrien  i = list->num_group;
195489857Sobrien  if ((i & 127) == 0)
195589857Sobrien    {
195689857Sobrien      unsigned int newsize = i + 128;
195789857Sobrien      list->head = xrealloc (list->head, newsize * sizeof (*list->head));
195889857Sobrien      list->elt_count = xrealloc (list->elt_count,
195989857Sobrien				  newsize * sizeof (*list->elt_count));
196089857Sobrien    }
196189857Sobrien  list->head[i] = sec;
196289857Sobrien  list->elt_count[i] = 1;
196389857Sobrien  list->num_group += 1;
196489857Sobrien}
196589857Sobrien
196633965Sjdpvoid
196733965Sjdpelf_frob_file ()
196833965Sjdp{
196989857Sobrien  struct group_list list;
197089857Sobrien  unsigned int i;
197189857Sobrien
197233965Sjdp  bfd_map_over_sections (stdoutput, adjust_stab_sections, (PTR) 0);
197333965Sjdp
197489857Sobrien  /* Go find section groups.  */
197589857Sobrien  list.num_group = 0;
197689857Sobrien  list.head = NULL;
197789857Sobrien  list.elt_count = NULL;
197889857Sobrien  bfd_map_over_sections (stdoutput, build_group_lists, (PTR) &list);
197989857Sobrien
198089857Sobrien  /* Make the SHT_GROUP sections that describe each section group.  We
198189857Sobrien     can't set up the section contents here yet, because elf section
198289857Sobrien     indices have yet to be calculated.  elf.c:set_group_contents does
198389857Sobrien     the rest of the work.  */
198489857Sobrien  for (i = 0; i < list.num_group; i++)
198589857Sobrien    {
198689857Sobrien      const char *group_name = elf_group_name (list.head[i]);
198789857Sobrien      asection *s;
198889857Sobrien      flagword flags;
198989857Sobrien
199089857Sobrien      s = subseg_force_new (group_name, 0);
199189857Sobrien      flags = SEC_READONLY | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_GROUP;
199289857Sobrien      if (s == NULL
199389857Sobrien	  || !bfd_set_section_flags (stdoutput, s, flags)
199489857Sobrien	  || !bfd_set_section_alignment (stdoutput, s, 2))
199589857Sobrien	{
199689857Sobrien	  as_fatal (_("can't create group: %s"),
199789857Sobrien		    bfd_errmsg (bfd_get_error ()));
199889857Sobrien	}
199989857Sobrien
200089857Sobrien      /* Pass a pointer to the first section in this group.  */
200189857Sobrien      elf_next_in_group (s) = list.head[i];
200289857Sobrien
200389857Sobrien      s->_raw_size = 4 * (list.elt_count[i] + 1);
200489857Sobrien      s->contents = frag_more (s->_raw_size);
200589857Sobrien      frag_now->fr_fix = frag_now_fix_octets ();
200689857Sobrien    }
200789857Sobrien
200833965Sjdp#ifdef elf_tc_final_processing
200933965Sjdp  elf_tc_final_processing ();
201033965Sjdp#endif
201133965Sjdp}
201233965Sjdp
201377298Sobrien/* It removes any unneeded versioned symbols from the symbol table.  */
201477298Sobrien
201577298Sobrienvoid
201677298Sobrienelf_frob_file_before_adjust ()
201777298Sobrien{
201877298Sobrien  if (symbol_rootP)
201977298Sobrien    {
202077298Sobrien      symbolS *symp;
202177298Sobrien
202277298Sobrien      for (symp = symbol_rootP; symp; symp = symbol_next (symp))
202391041Sobrien	if (!S_IS_DEFINED (symp))
202477298Sobrien	  {
202591041Sobrien	    if (symbol_get_obj (symp)->versioned_name)
202677298Sobrien	      {
202777298Sobrien		char *p;
202877298Sobrien
202977298Sobrien		/* The @@@ syntax is a special case. If the symbol is
203077298Sobrien		   not defined, 2 `@'s will be removed from the
203177298Sobrien		   versioned_name.  */
203277298Sobrien
203377298Sobrien		p = strchr (symbol_get_obj (symp)->versioned_name,
203477298Sobrien			    ELF_VER_CHR);
203577298Sobrien		know (p != NULL);
203677298Sobrien		if (p [1] == ELF_VER_CHR && p [2] == ELF_VER_CHR)
203777298Sobrien		  {
203877298Sobrien		    size_t l = strlen (&p[3]) + 1;
203977298Sobrien		    memmove (&p [1], &p[3], l);
204077298Sobrien		  }
204177298Sobrien		if (symbol_used_p (symp) == 0
204277298Sobrien		    && symbol_used_in_reloc_p (symp) == 0)
204377298Sobrien		  symbol_remove (symp, &symbol_rootP, &symbol_lastP);
204477298Sobrien	      }
204591041Sobrien
204691041Sobrien	    /* If there was .weak foo, but foo was neither defined nor
204791041Sobrien	       used anywhere, remove it.  */
204891041Sobrien
204991041Sobrien	    else if (S_IS_WEAK (symp)
205091041Sobrien		     && symbol_used_p (symp) == 0
205191041Sobrien		     && symbol_used_in_reloc_p (symp) == 0)
205291041Sobrien	      symbol_remove (symp, &symbol_rootP, &symbol_lastP);
205377298Sobrien	  }
205477298Sobrien    }
205577298Sobrien}
205677298Sobrien
205733965Sjdp/* It is required that we let write_relocs have the opportunity to
205833965Sjdp   optimize away fixups before output has begun, since it is possible
205933965Sjdp   to eliminate all fixups for a section and thus we never should
206033965Sjdp   have generated the relocation section.  */
206133965Sjdp
206233965Sjdpvoid
206333965Sjdpelf_frob_file_after_relocs ()
206433965Sjdp{
206533965Sjdp#ifdef NEED_ECOFF_DEBUG
206633965Sjdp  if (ECOFF_DEBUGGING)
206733965Sjdp    /* Generate the ECOFF debugging information.  */
206833965Sjdp    {
206933965Sjdp      const struct ecoff_debug_swap *debug_swap;
207033965Sjdp      struct ecoff_debug_info debug;
207133965Sjdp      char *buf;
207233965Sjdp      asection *sec;
207333965Sjdp
207433965Sjdp      debug_swap
207533965Sjdp	= get_elf_backend_data (stdoutput)->elf_backend_ecoff_debug_swap;
207633965Sjdp      know (debug_swap != (const struct ecoff_debug_swap *) NULL);
207733965Sjdp      ecoff_build_debug (&debug.symbolic_header, &buf, debug_swap);
207833965Sjdp
207933965Sjdp      /* Set up the pointers in debug.  */
208033965Sjdp#define SET(ptr, offset, type) \
208133965Sjdp    debug.ptr = (type) (buf + debug.symbolic_header.offset)
208233965Sjdp
208333965Sjdp      SET (line, cbLineOffset, unsigned char *);
208433965Sjdp      SET (external_dnr, cbDnOffset, PTR);
208533965Sjdp      SET (external_pdr, cbPdOffset, PTR);
208633965Sjdp      SET (external_sym, cbSymOffset, PTR);
208733965Sjdp      SET (external_opt, cbOptOffset, PTR);
208833965Sjdp      SET (external_aux, cbAuxOffset, union aux_ext *);
208933965Sjdp      SET (ss, cbSsOffset, char *);
209033965Sjdp      SET (external_fdr, cbFdOffset, PTR);
209133965Sjdp      SET (external_rfd, cbRfdOffset, PTR);
209233965Sjdp      /* ssext and external_ext are set up just below.  */
209333965Sjdp
209433965Sjdp#undef SET
209533965Sjdp
209633965Sjdp      /* Set up the external symbols.  */
209733965Sjdp      debug.ssext = debug.ssext_end = NULL;
209833965Sjdp      debug.external_ext = debug.external_ext_end = NULL;
209933965Sjdp      if (! bfd_ecoff_debug_externals (stdoutput, &debug, debug_swap, true,
210033965Sjdp				       elf_get_extr, elf_set_index))
210189857Sobrien	as_fatal (_("failed to set up debugging information: %s"),
210233965Sjdp		  bfd_errmsg (bfd_get_error ()));
210333965Sjdp
210433965Sjdp      sec = bfd_get_section_by_name (stdoutput, ".mdebug");
210533965Sjdp      assert (sec != NULL);
210633965Sjdp
210733965Sjdp      know (stdoutput->output_has_begun == false);
210833965Sjdp
210933965Sjdp      /* We set the size of the section, call bfd_set_section_contents
211033965Sjdp	 to force the ELF backend to allocate a file position, and then
211133965Sjdp	 write out the data.  FIXME: Is this really the best way to do
211233965Sjdp	 this?  */
211333965Sjdp      sec->_raw_size = bfd_ecoff_debug_size (stdoutput, &debug, debug_swap);
211433965Sjdp
211560484Sobrien      /* Pass BUF to bfd_set_section_contents because this will
211660484Sobrien         eventually become a call to fwrite, and ISO C prohibits
211760484Sobrien         passing a NULL pointer to a stdio function even if the
211860484Sobrien         pointer will not be used.  */
211960484Sobrien      if (! bfd_set_section_contents (stdoutput, sec, (PTR) buf,
212033965Sjdp				      (file_ptr) 0, (bfd_size_type) 0))
212189857Sobrien	as_fatal (_("can't start writing .mdebug section: %s"),
212233965Sjdp		  bfd_errmsg (bfd_get_error ()));
212333965Sjdp
212433965Sjdp      know (stdoutput->output_has_begun == true);
212533965Sjdp      know (sec->filepos != 0);
212633965Sjdp
212733965Sjdp      if (! bfd_ecoff_write_debug (stdoutput, &debug, debug_swap,
212833965Sjdp				   sec->filepos))
212989857Sobrien	as_fatal (_("could not write .mdebug section: %s"),
213033965Sjdp		  bfd_errmsg (bfd_get_error ()));
213133965Sjdp    }
213233965Sjdp#endif /* NEED_ECOFF_DEBUG */
213333965Sjdp}
213433965Sjdp
213533965Sjdp#ifdef SCO_ELF
213633965Sjdp
213733965Sjdp/* Heavily plagarized from obj_elf_version.  The idea is to emit the
213833965Sjdp   SCO specific identifier in the .notes section to satisfy the SCO
213933965Sjdp   linker.
214033965Sjdp
214133965Sjdp   This looks more complicated than it really is.  As opposed to the
214233965Sjdp   "obvious" solution, this should handle the cross dev cases
214333965Sjdp   correctly.  (i.e, hosting on a 64 bit big endian processor, but
214433965Sjdp   generating SCO Elf code) Efficiency isn't a concern, as there
214533965Sjdp   should be exactly one of these sections per object module.
214633965Sjdp
214733965Sjdp   SCO OpenServer 5 identifies it's ELF modules with a standard ELF
214833965Sjdp   .note section.
214933965Sjdp
215060484Sobrien   int_32 namesz  = 4 ;  Name size
215160484Sobrien   int_32 descsz  = 12 ; Descriptive information
215260484Sobrien   int_32 type    = 1 ;
215360484Sobrien   char   name[4] = "SCO" ; Originator name ALWAYS SCO + NULL
215433965Sjdp   int_32 version = (major ver # << 16)  | version of tools ;
215533965Sjdp   int_32 source  = (tool_id << 16 ) | 1 ;
215633965Sjdp   int_32 info    = 0 ;    These are set by the SCO tools, but we
215760484Sobrien                           don't know enough about the source
215833965Sjdp			   environment to set them.  SCO ld currently
215933965Sjdp			   ignores them, and recommends we set them
216033965Sjdp			   to zero.  */
216133965Sjdp
216233965Sjdp#define SCO_MAJOR_VERSION 0x1
216333965Sjdp#define SCO_MINOR_VERSION 0x1
216433965Sjdp
216533965Sjdpvoid
216633965Sjdpsco_id ()
216733965Sjdp{
216833965Sjdp
216933965Sjdp  char *name;
217033965Sjdp  unsigned int c;
217133965Sjdp  char ch;
217233965Sjdp  char *p;
217333965Sjdp  asection *seg = now_seg;
217433965Sjdp  subsegT subseg = now_subseg;
217533965Sjdp  Elf_Internal_Note i_note;
217633965Sjdp  Elf_External_Note e_note;
217733965Sjdp  asection *note_secp = (asection *) NULL;
217833965Sjdp  int i, len;
217933965Sjdp
218033965Sjdp  /* create the .note section */
218133965Sjdp
218233965Sjdp  note_secp = subseg_new (".note", 0);
218333965Sjdp  bfd_set_section_flags (stdoutput,
218433965Sjdp			 note_secp,
218533965Sjdp			 SEC_HAS_CONTENTS | SEC_READONLY);
218633965Sjdp
218733965Sjdp  /* process the version string */
218833965Sjdp
218960484Sobrien  i_note.namesz = 4;
219033965Sjdp  i_note.descsz = 12;		/* 12 descriptive bytes */
219133965Sjdp  i_note.type = NT_VERSION;	/* Contains a version string */
219233965Sjdp
219333965Sjdp  p = frag_more (sizeof (i_note.namesz));
219433965Sjdp  md_number_to_chars (p, (valueT) i_note.namesz, 4);
219533965Sjdp
219633965Sjdp  p = frag_more (sizeof (i_note.descsz));
219733965Sjdp  md_number_to_chars (p, (valueT) i_note.descsz, 4);
219833965Sjdp
219933965Sjdp  p = frag_more (sizeof (i_note.type));
220033965Sjdp  md_number_to_chars (p, (valueT) i_note.type, 4);
220133965Sjdp
220233965Sjdp  p = frag_more (4);
220360484Sobrien  strcpy (p, "SCO");
220433965Sjdp
220533965Sjdp  /* Note: this is the version number of the ELF we're representing */
220633965Sjdp  p = frag_more (4);
220733965Sjdp  md_number_to_chars (p, (SCO_MAJOR_VERSION << 16) | (SCO_MINOR_VERSION), 4);
220833965Sjdp
220933965Sjdp  /* Here, we pick a magic number for ourselves (yes, I "registered"
221033965Sjdp     it with SCO.  The bottom bit shows that we are compat with the
221133965Sjdp     SCO ABI.  */
221233965Sjdp  p = frag_more (4);
221333965Sjdp  md_number_to_chars (p, 0x4c520000 | 0x0001, 4);
221433965Sjdp
221533965Sjdp  /* If we knew (or cared) what the source language options were, we'd
221633965Sjdp     fill them in here.  SCO has given us permission to ignore these
221733965Sjdp     and just set them to zero.  */
221833965Sjdp  p = frag_more (4);
221933965Sjdp  md_number_to_chars (p, 0x0000, 4);
222060484Sobrien
222133965Sjdp  frag_align (2, 0, 0);
222233965Sjdp
222333965Sjdp  /* We probably can't restore the current segment, for there likely
222433965Sjdp     isn't one yet...  */
222533965Sjdp  if (seg && subseg)
222633965Sjdp    subseg_set (seg, subseg);
222733965Sjdp
222833965Sjdp}
222933965Sjdp
223033965Sjdp#endif /* SCO_ELF */
223133965Sjdp
223277298Sobrienstatic int
223377298Sobrienelf_separate_stab_sections ()
223477298Sobrien{
223577298Sobrien#ifdef NEED_ECOFF_DEBUG
223677298Sobrien  return (!ECOFF_DEBUGGING);
223777298Sobrien#else
223877298Sobrien  return 1;
223977298Sobrien#endif
224077298Sobrien}
224177298Sobrien
224277298Sobrienstatic void
224377298Sobrienelf_init_stab_section (seg)
224477298Sobrien     segT seg;
224577298Sobrien{
224677298Sobrien#ifdef NEED_ECOFF_DEBUG
224777298Sobrien  if (!ECOFF_DEBUGGING)
224877298Sobrien#endif
224977298Sobrien    obj_elf_init_stab_section (seg);
225077298Sobrien}
225177298Sobrien
225233965Sjdpconst struct format_ops elf_format_ops =
225333965Sjdp{
225433965Sjdp  bfd_target_elf_flavour,
225560484Sobrien  0,	/* dfl_leading_underscore */
225660484Sobrien  1,	/* emit_section_symbols */
225777298Sobrien  elf_begin,
225877298Sobrien  elf_file_symbol,
225933965Sjdp  elf_frob_symbol,
226033965Sjdp  elf_frob_file,
226177298Sobrien  elf_frob_file_before_adjust,
226233965Sjdp  elf_frob_file_after_relocs,
226333965Sjdp  elf_s_get_size, elf_s_set_size,
226433965Sjdp  elf_s_get_align, elf_s_set_align,
226560484Sobrien  elf_s_get_other,
226677298Sobrien  elf_s_set_other,
226760484Sobrien  0,	/* s_get_desc */
226877298Sobrien  0,	/* s_set_desc */
226977298Sobrien  0,	/* s_get_type */
227077298Sobrien  0,	/* s_set_type */
227133965Sjdp  elf_copy_symbol_attributes,
227233965Sjdp#ifdef NEED_ECOFF_DEBUG
227333965Sjdp  ecoff_generate_asm_lineno,
227433965Sjdp  ecoff_stab,
227533965Sjdp#else
227660484Sobrien  0,	/* generate_asm_lineno */
227760484Sobrien  0,	/* process_stab */
227833965Sjdp#endif
227977298Sobrien  elf_separate_stab_sections,
228077298Sobrien  elf_init_stab_section,
228133965Sjdp  elf_sec_sym_ok_for_reloc,
228233965Sjdp  elf_pop_insert,
228333965Sjdp#ifdef NEED_ECOFF_DEBUG
228433965Sjdp  elf_ecoff_set_ext,
228533965Sjdp#else
228660484Sobrien  0,	/* ecoff_set_ext */
228733965Sjdp#endif
228860484Sobrien  elf_obj_read_begin_hook,
228977298Sobrien  elf_obj_symbol_new_hook
229033965Sjdp};
2291