133965Sjdp/* ELF object file format
2104834Sobrien   Copyright 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
3218822Sdim   2001, 2002, 2003, 2004, 2005, 2006, 2007
4218822Sdim   Free Software Foundation, Inc.
533965Sjdp
633965Sjdp   This file is part of GAS, the GNU Assembler.
733965Sjdp
833965Sjdp   GAS is free software; you can redistribute it and/or modify
933965Sjdp   it under the terms of the GNU General Public License as
1033965Sjdp   published by the Free Software Foundation; either version 2,
1133965Sjdp   or (at your option) any later version.
1233965Sjdp
1333965Sjdp   GAS is distributed in the hope that it will be useful, but
1433965Sjdp   WITHOUT ANY WARRANTY; without even the implied warranty of
1533965Sjdp   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
1633965Sjdp   the 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-elf.h"
2433965Sjdp#include "as.h"
2589857Sobrien#include "safe-ctype.h"
2633965Sjdp#include "subsegs.h"
2733965Sjdp#include "obstack.h"
28104834Sobrien#include "struc-symbol.h"
29130561Sobrien#include "dwarf2dbg.h"
3033965Sjdp
3133965Sjdp#ifndef ECOFF_DEBUGGING
3233965Sjdp#define ECOFF_DEBUGGING 0
3333965Sjdp#else
3433965Sjdp#define NEED_ECOFF_DEBUG
3533965Sjdp#endif
3633965Sjdp
3733965Sjdp#ifdef NEED_ECOFF_DEBUG
3833965Sjdp#include "ecoff.h"
3933965Sjdp#endif
4033965Sjdp
4138889Sjdp#ifdef TC_ALPHA
4238889Sjdp#include "elf/alpha.h"
4338889Sjdp#endif
4438889Sjdp
4533965Sjdp#ifdef TC_MIPS
4633965Sjdp#include "elf/mips.h"
4733965Sjdp#endif
4833965Sjdp
4933965Sjdp#ifdef TC_PPC
5033965Sjdp#include "elf/ppc.h"
5133965Sjdp#endif
5233965Sjdp
5360484Sobrien#ifdef TC_I370
5460484Sobrien#include "elf/i370.h"
5560484Sobrien#endif
5660484Sobrien
57218822Sdim#ifdef TC_I386
58218822Sdim#include "elf/x86-64.h"
59218822Sdim#endif
60218822Sdim
61218822Sdim#ifdef TC_MEP
62218822Sdim#include "elf/mep.h"
63218822Sdim#endif
64218822Sdim
65130561Sobrienstatic void obj_elf_line (int);
66130561Sobrienstatic void obj_elf_size (int);
67130561Sobrienstatic void obj_elf_type (int);
68130561Sobrienstatic void obj_elf_ident (int);
69130561Sobrienstatic void obj_elf_weak (int);
70130561Sobrienstatic void obj_elf_local (int);
71130561Sobrienstatic void obj_elf_visibility (int);
72130561Sobrienstatic void obj_elf_symver (int);
73130561Sobrienstatic void obj_elf_subsection (int);
74130561Sobrienstatic void obj_elf_popsection (int);
75130561Sobrienstatic void obj_elf_tls_common (int);
76130561Sobrienstatic void obj_elf_lcomm (int);
77218822Sdimstatic void obj_elf_struct (int);
7833965Sjdp
7933965Sjdpstatic const pseudo_typeS elf_pseudo_table[] =
8033965Sjdp{
8133965Sjdp  {"comm", obj_elf_common, 0},
8260484Sobrien  {"common", obj_elf_common, 1},
8333965Sjdp  {"ident", obj_elf_ident, 0},
84130561Sobrien  {"lcomm", obj_elf_lcomm, 0},
8533965Sjdp  {"local", obj_elf_local, 0},
8633965Sjdp  {"previous", obj_elf_previous, 0},
8733965Sjdp  {"section", obj_elf_section, 0},
8833965Sjdp  {"section.s", obj_elf_section, 0},
8933965Sjdp  {"sect", obj_elf_section, 0},
9033965Sjdp  {"sect.s", obj_elf_section, 0},
9160484Sobrien  {"pushsection", obj_elf_section, 1},
9260484Sobrien  {"popsection", obj_elf_popsection, 0},
9333965Sjdp  {"size", obj_elf_size, 0},
9433965Sjdp  {"type", obj_elf_type, 0},
9533965Sjdp  {"version", obj_elf_version, 0},
9633965Sjdp  {"weak", obj_elf_weak, 0},
9733965Sjdp
9877298Sobrien  /* These define symbol visibility.  */
9960484Sobrien  {"internal", obj_elf_visibility, STV_INTERNAL},
10060484Sobrien  {"hidden", obj_elf_visibility, STV_HIDDEN},
10160484Sobrien  {"protected", obj_elf_visibility, STV_PROTECTED},
10260484Sobrien
10333965Sjdp  /* These are used for stabs-in-elf configurations.  */
10433965Sjdp  {"line", obj_elf_line, 0},
10533965Sjdp
10633965Sjdp  /* This is a GNU extension to handle symbol versions.  */
10733965Sjdp  {"symver", obj_elf_symver, 0},
10833965Sjdp
10938889Sjdp  /* A GNU extension to change subsection only.  */
11038889Sjdp  {"subsection", obj_elf_subsection, 0},
11138889Sjdp
11260484Sobrien  /* These are GNU extensions to aid in garbage collecting C++ vtables.  */
113130561Sobrien  {"vtable_inherit", (void (*) (int)) &obj_elf_vtable_inherit, 0},
114130561Sobrien  {"vtable_entry", (void (*) (int)) &obj_elf_vtable_entry, 0},
11560484Sobrien
11677298Sobrien  /* These are used for dwarf.  */
11733965Sjdp  {"2byte", cons, 2},
11833965Sjdp  {"4byte", cons, 4},
11933965Sjdp  {"8byte", cons, 8},
120130561Sobrien  /* These are used for dwarf2.  */
121130561Sobrien  { "file", (void (*) (int)) dwarf2_directive_file, 0 },
122130561Sobrien  { "loc",  dwarf2_directive_loc,  0 },
123218822Sdim  { "loc_mark_labels", dwarf2_directive_loc_mark_labels, 0 },
12433965Sjdp
12533965Sjdp  /* We need to trap the section changing calls to handle .previous.  */
12633965Sjdp  {"data", obj_elf_data, 0},
127218822Sdim  {"offset", obj_elf_struct, 0},
128218822Sdim  {"struct", obj_elf_struct, 0},
12933965Sjdp  {"text", obj_elf_text, 0},
13033965Sjdp
131104834Sobrien  {"tls_common", obj_elf_tls_common, 0},
132104834Sobrien
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
187218822Sdimasection *elf_com_section_ptr;
188218822Sdim
18933965Sjdpvoid
190130561Sobrienelf_begin (void)
19133965Sjdp{
192130561Sobrien  asection *s;
193130561Sobrien
19433965Sjdp  /* Add symbols for the known sections to the symbol table.  */
195130561Sobrien  s = bfd_get_section_by_name (stdoutput, TEXT_SECTION_NAME);
196130561Sobrien  symbol_table_insert (section_symbol (s));
197130561Sobrien  s = bfd_get_section_by_name (stdoutput, DATA_SECTION_NAME);
198130561Sobrien  symbol_table_insert (section_symbol (s));
199130561Sobrien  s = bfd_get_section_by_name (stdoutput, BSS_SECTION_NAME);
200130561Sobrien  symbol_table_insert (section_symbol (s));
201218822Sdim  elf_com_section_ptr = bfd_com_section_ptr;
20233965Sjdp}
20333965Sjdp
20433965Sjdpvoid
205130561Sobrienelf_pop_insert (void)
20633965Sjdp{
20733965Sjdp  pop_insert (elf_pseudo_table);
20833965Sjdp  if (ECOFF_DEBUGGING)
20933965Sjdp    pop_insert (ecoff_debug_pseudo_table);
21033965Sjdp}
21133965Sjdp
21233965Sjdpstatic bfd_vma
213130561Sobrienelf_s_get_size (symbolS *sym)
21433965Sjdp{
21533965Sjdp  return S_GET_SIZE (sym);
21633965Sjdp}
21733965Sjdp
21833965Sjdpstatic void
219130561Sobrienelf_s_set_size (symbolS *sym, bfd_vma sz)
22033965Sjdp{
22133965Sjdp  S_SET_SIZE (sym, sz);
22233965Sjdp}
22333965Sjdp
22433965Sjdpstatic bfd_vma
225130561Sobrienelf_s_get_align (symbolS *sym)
22633965Sjdp{
22733965Sjdp  return S_GET_ALIGN (sym);
22833965Sjdp}
22933965Sjdp
23033965Sjdpstatic void
231130561Sobrienelf_s_set_align (symbolS *sym, bfd_vma align)
23233965Sjdp{
23333965Sjdp  S_SET_ALIGN (sym, align);
23433965Sjdp}
23533965Sjdp
23660484Sobrienint
237130561Sobrienelf_s_get_other (symbolS *sym)
23860484Sobrien{
23960484Sobrien  return elf_symbol (symbol_get_bfdsym (sym))->internal_elf_sym.st_other;
24060484Sobrien}
24160484Sobrien
24233965Sjdpstatic void
243130561Sobrienelf_s_set_other (symbolS *sym, int other)
24477298Sobrien{
24577298Sobrien  S_SET_OTHER (sym, other);
24677298Sobrien}
24777298Sobrien
24833965Sjdpstatic int
249130561Sobrienelf_sec_sym_ok_for_reloc (asection *sec)
25033965Sjdp{
25133965Sjdp  return obj_sec_sym_ok_for_reloc (sec);
25233965Sjdp}
25333965Sjdp
25433965Sjdpvoid
255218822Sdimelf_file_symbol (const char *s, int appfile)
25633965Sjdp{
257218822Sdim  if (!appfile
258218822Sdim      || symbol_rootP == NULL
259218822Sdim      || symbol_rootP->bsym == NULL
260218822Sdim      || (symbol_rootP->bsym->flags & BSF_FILE) == 0)
261218822Sdim    {
262218822Sdim      symbolS *sym;
26333965Sjdp
264218822Sdim      sym = symbol_new (s, absolute_section, 0, NULL);
265218822Sdim      symbol_set_frag (sym, &zero_address_frag);
266218822Sdim      symbol_get_bfdsym (sym)->flags |= BSF_FILE;
26733965Sjdp
268218822Sdim      if (symbol_rootP != sym)
269218822Sdim	{
270218822Sdim	  symbol_remove (sym, &symbol_rootP, &symbol_lastP);
271218822Sdim	  symbol_insert (sym, symbol_rootP, &symbol_rootP, &symbol_lastP);
27233965Sjdp#ifdef DEBUG
273218822Sdim	  verify_symbol_chain (symbol_rootP, symbol_lastP);
27433965Sjdp#endif
275218822Sdim	}
27633965Sjdp    }
27733965Sjdp
27833965Sjdp#ifdef NEED_ECOFF_DEBUG
279218822Sdim  ecoff_new_file (s, appfile);
28033965Sjdp#endif
28133965Sjdp}
28233965Sjdp
283130561Sobrien/* Called from read.c:s_comm after we've parsed .comm symbol, size.
284130561Sobrien   Parse a possible alignment value.  */
285130561Sobrien
286218822SdimsymbolS *
287130561Sobrienelf_common_parse (int ignore ATTRIBUTE_UNUSED, symbolS *symbolP, addressT size)
28833965Sjdp{
289130561Sobrien  addressT align = 0;
290130561Sobrien  int is_local = symbol_get_obj (symbolP)->local;
29133965Sjdp
292130561Sobrien  if (*input_line_pointer == ',')
29360484Sobrien    {
294130561Sobrien      char *save = input_line_pointer;
29560484Sobrien
29633965Sjdp      input_line_pointer++;
29733965Sjdp      SKIP_WHITESPACE ();
298130561Sobrien
299130561Sobrien      if (*input_line_pointer == '"')
30033965Sjdp	{
301130561Sobrien	  /* For sparc.  Accept .common symbol, length, "bss"  */
302130561Sobrien	  input_line_pointer++;
303130561Sobrien	  /* Some use the dot, some don't.  */
304130561Sobrien	  if (*input_line_pointer == '.')
305130561Sobrien	    input_line_pointer++;
306130561Sobrien	  /* Some say data, some say bss.  */
307130561Sobrien	  if (strncmp (input_line_pointer, "bss\"", 4) == 0)
308130561Sobrien	    input_line_pointer += 4;
309130561Sobrien	  else if (strncmp (input_line_pointer, "data\"", 5) == 0)
310130561Sobrien	    input_line_pointer += 5;
311130561Sobrien	  else
31233965Sjdp	    {
313130561Sobrien	      char *p = input_line_pointer;
314130561Sobrien	      char c;
31533965Sjdp
316130561Sobrien	      while (*--p != '"')
317130561Sobrien		;
318130561Sobrien	      while (!is_end_of_line[(unsigned char) *input_line_pointer])
319130561Sobrien		if (*input_line_pointer++ == '"')
320130561Sobrien		  break;
321130561Sobrien	      c = *input_line_pointer;
322130561Sobrien	      *input_line_pointer = '\0';
323130561Sobrien	      as_bad (_("bad .common segment %s"), p);
324130561Sobrien	      *input_line_pointer = c;
325130561Sobrien	      ignore_rest_of_line ();
326130561Sobrien	      return NULL;
32733965Sjdp	    }
328130561Sobrien	  /* ??? Don't ask me why these are always global.  */
329130561Sobrien	  is_local = 0;
33033965Sjdp	}
33133965Sjdp      else
33233965Sjdp	{
333130561Sobrien	  input_line_pointer = save;
334130561Sobrien	  align = parse_align (is_local);
335130561Sobrien	  if (align == (addressT) -1)
336130561Sobrien	    return NULL;
33733965Sjdp	}
33833965Sjdp    }
339130561Sobrien
340130561Sobrien  if (is_local)
341130561Sobrien    {
342130561Sobrien      bss_alloc (symbolP, size, align);
343130561Sobrien      S_CLEAR_EXTERNAL (symbolP);
344130561Sobrien    }
34533965Sjdp  else
34633965Sjdp    {
347130561Sobrien      S_SET_VALUE (symbolP, size);
348130561Sobrien      S_SET_ALIGN (symbolP, align);
349130561Sobrien      S_SET_EXTERNAL (symbolP);
350218822Sdim      S_SET_SEGMENT (symbolP, elf_com_section_ptr);
35133965Sjdp    }
35233965Sjdp
35360484Sobrien  symbol_get_bfdsym (symbolP)->flags |= BSF_OBJECT;
35433965Sjdp
355104834Sobrien  return symbolP;
35633965Sjdp}
35733965Sjdp
358104834Sobrienvoid
359130561Sobrienobj_elf_common (int is_common)
360104834Sobrien{
361130561Sobrien  if (flag_mri && is_common)
362130561Sobrien    s_mri_common (0);
363130561Sobrien  else
364130561Sobrien    s_comm_internal (0, elf_common_parse);
365104834Sobrien}
366104834Sobrien
36733965Sjdpstatic void
368130561Sobrienobj_elf_tls_common (int ignore ATTRIBUTE_UNUSED)
369104834Sobrien{
370130561Sobrien  symbolS *symbolP = s_comm_internal (0, elf_common_parse);
371104834Sobrien
372104834Sobrien  if (symbolP)
373104834Sobrien    symbol_get_bfdsym (symbolP)->flags |= BSF_THREAD_LOCAL;
374104834Sobrien}
375104834Sobrien
376104834Sobrienstatic void
377130561Sobrienobj_elf_lcomm (int ignore ATTRIBUTE_UNUSED)
37833965Sjdp{
379130561Sobrien  symbolS *symbolP = s_comm_internal (0, s_lcomm_internal);
380130561Sobrien
381130561Sobrien  if (symbolP)
382130561Sobrien    symbol_get_bfdsym (symbolP)->flags |= BSF_OBJECT;
383130561Sobrien}
384130561Sobrien
385130561Sobrienstatic void
386130561Sobrienobj_elf_local (int ignore ATTRIBUTE_UNUSED)
387130561Sobrien{
38833965Sjdp  char *name;
38933965Sjdp  int c;
39033965Sjdp  symbolS *symbolP;
39133965Sjdp
39233965Sjdp  do
39333965Sjdp    {
39433965Sjdp      name = input_line_pointer;
39533965Sjdp      c = get_symbol_end ();
39633965Sjdp      symbolP = symbol_find_or_make (name);
39733965Sjdp      *input_line_pointer = c;
39833965Sjdp      SKIP_WHITESPACE ();
39933965Sjdp      S_CLEAR_EXTERNAL (symbolP);
40060484Sobrien      symbol_get_obj (symbolP)->local = 1;
40133965Sjdp      if (c == ',')
40233965Sjdp	{
40333965Sjdp	  input_line_pointer++;
40433965Sjdp	  SKIP_WHITESPACE ();
40533965Sjdp	  if (*input_line_pointer == '\n')
40633965Sjdp	    c = '\n';
40733965Sjdp	}
40833965Sjdp    }
40933965Sjdp  while (c == ',');
41033965Sjdp  demand_empty_rest_of_line ();
41133965Sjdp}
41233965Sjdp
41333965Sjdpstatic void
414130561Sobrienobj_elf_weak (int ignore ATTRIBUTE_UNUSED)
41533965Sjdp{
41633965Sjdp  char *name;
41733965Sjdp  int c;
41833965Sjdp  symbolS *symbolP;
41933965Sjdp
42033965Sjdp  do
42133965Sjdp    {
42233965Sjdp      name = input_line_pointer;
42333965Sjdp      c = get_symbol_end ();
42433965Sjdp      symbolP = symbol_find_or_make (name);
42533965Sjdp      *input_line_pointer = c;
42633965Sjdp      SKIP_WHITESPACE ();
42733965Sjdp      S_SET_WEAK (symbolP);
42860484Sobrien      symbol_get_obj (symbolP)->local = 1;
42933965Sjdp      if (c == ',')
43033965Sjdp	{
43133965Sjdp	  input_line_pointer++;
43233965Sjdp	  SKIP_WHITESPACE ();
43333965Sjdp	  if (*input_line_pointer == '\n')
43433965Sjdp	    c = '\n';
43533965Sjdp	}
43633965Sjdp    }
43733965Sjdp  while (c == ',');
43833965Sjdp  demand_empty_rest_of_line ();
43933965Sjdp}
44033965Sjdp
44160484Sobrienstatic void
442130561Sobrienobj_elf_visibility (int visibility)
44360484Sobrien{
44460484Sobrien  char *name;
44560484Sobrien  int c;
44660484Sobrien  symbolS *symbolP;
44760484Sobrien  asymbol *bfdsym;
44860484Sobrien  elf_symbol_type *elfsym;
44960484Sobrien
45060484Sobrien  do
45160484Sobrien    {
45260484Sobrien      name = input_line_pointer;
45360484Sobrien      c = get_symbol_end ();
45460484Sobrien      symbolP = symbol_find_or_make (name);
45560484Sobrien      *input_line_pointer = c;
45660484Sobrien
45760484Sobrien      SKIP_WHITESPACE ();
45860484Sobrien
45960484Sobrien      bfdsym = symbol_get_bfdsym (symbolP);
46060484Sobrien      elfsym = elf_symbol_from (bfd_asymbol_bfd (bfdsym), bfdsym);
46160484Sobrien
46260484Sobrien      assert (elfsym);
46360484Sobrien
464107492Sobrien      elfsym->internal_elf_sym.st_other &= ~3;
465107492Sobrien      elfsym->internal_elf_sym.st_other |= visibility;
46660484Sobrien
46760484Sobrien      if (c == ',')
46860484Sobrien	{
46960484Sobrien	  input_line_pointer ++;
47060484Sobrien
47160484Sobrien	  SKIP_WHITESPACE ();
47260484Sobrien
47360484Sobrien	  if (*input_line_pointer == '\n')
47460484Sobrien	    c = '\n';
47560484Sobrien	}
47660484Sobrien    }
47760484Sobrien  while (c == ',');
47860484Sobrien
47960484Sobrien  demand_empty_rest_of_line ();
48060484Sobrien}
48160484Sobrien
48233965Sjdpstatic segT previous_section;
48333965Sjdpstatic int previous_subsection;
48433965Sjdp
48560484Sobrienstruct section_stack
48660484Sobrien{
48760484Sobrien  struct section_stack *next;
48860484Sobrien  segT seg, prev_seg;
48960484Sobrien  int subseg, prev_subseg;
49060484Sobrien};
49160484Sobrien
49260484Sobrienstatic struct section_stack *section_stack;
49360484Sobrien
494218822Sdimstatic bfd_boolean
495218822Sdimget_section (bfd *abfd ATTRIBUTE_UNUSED, asection *sec, void *inf)
496218822Sdim{
497218822Sdim  const char *gname = inf;
498218822Sdim  const char *group_name = elf_group_name (sec);
499218822Sdim
500218822Sdim  return (group_name == gname
501218822Sdim	  || (group_name != NULL
502218822Sdim	      && gname != NULL
503218822Sdim	      && strcmp (group_name, gname) == 0));
504218822Sdim}
505218822Sdim
50633965Sjdp/* Handle the .section pseudo-op.  This code supports two different
50733965Sjdp   syntaxes.
50833965Sjdp
50933965Sjdp   The first is found on Solaris, and looks like
51033965Sjdp       .section ".sec1",#alloc,#execinstr,#write
51133965Sjdp   Here the names after '#' are the SHF_* flags to turn on for the
51233965Sjdp   section.  I'm not sure how it determines the SHT_* type (BFD
51333965Sjdp   doesn't really give us control over the type, anyhow).
51433965Sjdp
51533965Sjdp   The second format is found on UnixWare, and probably most SVR4
51633965Sjdp   machines, and looks like
51733965Sjdp       .section .sec1,"a",@progbits
51833965Sjdp   The quoted string may contain any combination of a, w, x, and
51933965Sjdp   represents the SHF_* flags to turn on for the section.  The string
52033965Sjdp   beginning with '@' can be progbits or nobits.  There should be
52133965Sjdp   other possibilities, but I don't know what they are.  In any case,
52233965Sjdp   BFD doesn't really let us set the section type.  */
52333965Sjdp
524130561Sobrienvoid
525130561Sobrienobj_elf_change_section (const char *name,
526130561Sobrien			int type,
527130561Sobrien			int attr,
528130561Sobrien			int entsize,
529130561Sobrien			const char *group_name,
530130561Sobrien			int linkonce,
531130561Sobrien			int push)
53233965Sjdp{
53377298Sobrien  asection *old_sec;
53433965Sjdp  segT sec;
53577298Sobrien  flagword flags;
536218822Sdim  const struct elf_backend_data *bed;
537130561Sobrien  const struct bfd_elf_special_section *ssect;
53833965Sjdp
53933965Sjdp#ifdef md_flush_pending_output
54033965Sjdp  md_flush_pending_output ();
54133965Sjdp#endif
54233965Sjdp
54360484Sobrien  /* Switch to the section, creating it if necessary.  */
54460484Sobrien  if (push)
54560484Sobrien    {
54660484Sobrien      struct section_stack *elt;
54760484Sobrien      elt = xmalloc (sizeof (struct section_stack));
54860484Sobrien      elt->next = section_stack;
54960484Sobrien      elt->seg = now_seg;
55060484Sobrien      elt->prev_seg = previous_section;
55160484Sobrien      elt->subseg = now_subseg;
55260484Sobrien      elt->prev_subseg = previous_subsection;
55360484Sobrien      section_stack = elt;
55460484Sobrien    }
55560484Sobrien  previous_section = now_seg;
55660484Sobrien  previous_subsection = now_subseg;
55760484Sobrien
558218822Sdim  old_sec = bfd_get_section_by_name_if (stdoutput, name, get_section,
559218822Sdim					(void *) group_name);
560218822Sdim  if (old_sec)
561218822Sdim    {
562218822Sdim      sec = old_sec;
563218822Sdim      subseg_set (sec, 0);
564218822Sdim    }
565218822Sdim  else
566218822Sdim    sec = subseg_force_new (name, 0);
56760484Sobrien
568218822Sdim  bed = get_elf_backend_data (stdoutput);
569218822Sdim  ssect = (*bed->get_sec_type_attr) (stdoutput, sec);
570218822Sdim
571130561Sobrien  if (ssect != NULL)
572130561Sobrien    {
573130561Sobrien      bfd_boolean override = FALSE;
574130561Sobrien
575130561Sobrien      if (type == SHT_NULL)
576130561Sobrien	type = ssect->type;
577130561Sobrien      else if (type != ssect->type)
578130561Sobrien	{
579130561Sobrien	  if (old_sec == NULL
580130561Sobrien	      /* FIXME: gcc, as of 2002-10-22, will emit
581130561Sobrien
582130561Sobrien		 .section .init_array,"aw",@progbits
583130561Sobrien
584130561Sobrien		 for __attribute__ ((section (".init_array"))).
585218822Sdim		 "@progbits" is incorrect.  Also for x86-64 large bss
586218822Sdim		 sections, gcc, as of 2005-07-06, will emit
587218822Sdim
588218822Sdim		 .section .lbss,"aw",@progbits
589218822Sdim
590130561Sobrien		 "@progbits" is incorrect.  */
591218822Sdim#ifdef TC_I386
592218822Sdim	      && (bed->s->arch_size != 64
593218822Sdim		  || !(ssect->attr & SHF_X86_64_LARGE))
594218822Sdim#endif
595130561Sobrien	      && ssect->type != SHT_INIT_ARRAY
596130561Sobrien	      && ssect->type != SHT_FINI_ARRAY
597130561Sobrien	      && ssect->type != SHT_PREINIT_ARRAY)
598130561Sobrien	    {
599130561Sobrien	      /* We allow to specify any type for a .note section.  */
600130561Sobrien	      if (ssect->type != SHT_NOTE)
601130561Sobrien		as_warn (_("setting incorrect section type for %s"),
602130561Sobrien			 name);
603130561Sobrien	    }
604130561Sobrien	  else
605130561Sobrien	    {
606130561Sobrien	      as_warn (_("ignoring incorrect section type for %s"),
607130561Sobrien		       name);
608130561Sobrien	      type = ssect->type;
609130561Sobrien	    }
610130561Sobrien	}
611130561Sobrien
612130561Sobrien      if (old_sec == NULL && (attr & ~ssect->attr) != 0)
613130561Sobrien	{
614130561Sobrien	  /* As a GNU extension, we permit a .note section to be
615130561Sobrien	     allocatable.  If the linker sees an allocatable .note
616130561Sobrien	     section, it will create a PT_NOTE segment in the output
617130561Sobrien	     file.  We also allow "x" for .note.GNU-stack.  */
618130561Sobrien	  if (ssect->type == SHT_NOTE
619130561Sobrien	      && (attr == SHF_ALLOC || attr == SHF_EXECINSTR))
620130561Sobrien	    ;
621130561Sobrien	  /* Allow different SHF_MERGE and SHF_STRINGS if we have
622130561Sobrien	     something like .rodata.str.  */
623130561Sobrien	  else if (ssect->suffix_length == -2
624130561Sobrien		   && name[ssect->prefix_length] == '.'
625130561Sobrien		   && (attr
626130561Sobrien		       & ~ssect->attr
627130561Sobrien		       & ~SHF_MERGE
628130561Sobrien		       & ~SHF_STRINGS) == 0)
629130561Sobrien	    ;
630130561Sobrien	  /* .interp, .strtab and .symtab can have SHF_ALLOC.  */
631130561Sobrien	  else if (attr == SHF_ALLOC
632130561Sobrien		   && (strcmp (name, ".interp") == 0
633130561Sobrien		       || strcmp (name, ".strtab") == 0
634130561Sobrien		       || strcmp (name, ".symtab") == 0))
635130561Sobrien	    override = TRUE;
636218822Sdim	  /* .note.GNU-stack can have SHF_EXECINSTR.  */
637218822Sdim	  else if (attr == SHF_EXECINSTR
638218822Sdim		   && strcmp (name, ".note.GNU-stack") == 0)
639218822Sdim	    override = TRUE;
640218822Sdim#ifdef TC_ALPHA
641218822Sdim	  /* A section on Alpha may have SHF_ALPHA_GPREL.  */
642218822Sdim	  else if ((attr & ~ssect->attr) == SHF_ALPHA_GPREL)
643218822Sdim	    override = TRUE;
644218822Sdim#endif
645130561Sobrien	  else
646130561Sobrien	    {
647218822Sdim	      if (group_name == NULL)
648218822Sdim		as_warn (_("setting incorrect section attributes for %s"),
649218822Sdim			 name);
650130561Sobrien	      override = TRUE;
651130561Sobrien	    }
652130561Sobrien	}
653130561Sobrien      if (!override && old_sec == NULL)
654130561Sobrien	attr |= ssect->attr;
655130561Sobrien    }
65660484Sobrien
65777298Sobrien  /* Convert ELF type and flags to BFD flags.  */
65877298Sobrien  flags = (SEC_RELOC
65977298Sobrien	   | ((attr & SHF_WRITE) ? 0 : SEC_READONLY)
66077298Sobrien	   | ((attr & SHF_ALLOC) ? SEC_ALLOC : 0)
66177298Sobrien	   | (((attr & SHF_ALLOC) && type != SHT_NOBITS) ? SEC_LOAD : 0)
66289857Sobrien	   | ((attr & SHF_EXECINSTR) ? SEC_CODE : 0)
66389857Sobrien	   | ((attr & SHF_MERGE) ? SEC_MERGE : 0)
664104834Sobrien	   | ((attr & SHF_STRINGS) ? SEC_STRINGS : 0)
665104834Sobrien	   | ((attr & SHF_TLS) ? SEC_THREAD_LOCAL : 0));
66660484Sobrien#ifdef md_elf_section_flags
66777298Sobrien  flags = md_elf_section_flags (flags, attr, type);
66860484Sobrien#endif
66960484Sobrien
670218822Sdim  if (linkonce)
671218822Sdim    flags |= SEC_LINK_ONCE | SEC_LINK_DUPLICATES_DISCARD;
672218822Sdim
67377298Sobrien  if (old_sec == NULL)
67477298Sobrien    {
67577298Sobrien      symbolS *secsym;
67677298Sobrien
677218822Sdim      elf_section_type (sec) = type;
678218822Sdim      elf_section_flags (sec) = attr;
679218822Sdim
68060484Sobrien      /* Prevent SEC_HAS_CONTENTS from being inadvertently set.  */
68160484Sobrien      if (type == SHT_NOBITS)
682130561Sobrien	seg_info (sec)->bss = 1;
68360484Sobrien
68460484Sobrien      bfd_set_section_flags (stdoutput, sec, flags);
68589857Sobrien      if (flags & SEC_MERGE)
68689857Sobrien	sec->entsize = entsize;
68789857Sobrien      elf_group_name (sec) = group_name;
68860484Sobrien
68960484Sobrien      /* Add a symbol for this section to the symbol table.  */
69060484Sobrien      secsym = symbol_find (name);
69160484Sobrien      if (secsym != NULL)
69260484Sobrien	symbol_set_bfdsym (secsym, sec->symbol);
69360484Sobrien      else
694130561Sobrien	symbol_table_insert (section_symbol (sec));
69560484Sobrien    }
696218822Sdim  else
69777298Sobrien    {
698218822Sdim      if (type != SHT_NULL
699218822Sdim	  && (unsigned) type != elf_section_type (old_sec))
700218822Sdim	as_warn (_("ignoring changed section type for %s"), name);
701218822Sdim
702218822Sdim      if (attr != 0)
703218822Sdim	{
704218822Sdim	  /* If section attributes are specified the second time we see a
705218822Sdim	     particular section, then check that they are the same as we
706218822Sdim	     saw the first time.  */
707218822Sdim	  if (((old_sec->flags ^ flags)
708218822Sdim	       & (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_CODE
709218822Sdim		  | SEC_EXCLUDE | SEC_SORT_ENTRIES | SEC_MERGE | SEC_STRINGS
710218822Sdim		  | SEC_LINK_ONCE | SEC_LINK_DUPLICATES_DISCARD
711218822Sdim		  | SEC_THREAD_LOCAL)))
712218822Sdim	    as_warn (_("ignoring changed section attributes for %s"), name);
713218822Sdim	  if ((flags & SEC_MERGE) && old_sec->entsize != (unsigned) entsize)
714218822Sdim	    as_warn (_("ignoring changed section entity size for %s"), name);
715218822Sdim	}
71677298Sobrien    }
71760484Sobrien
71860484Sobrien#ifdef md_elf_section_change_hook
71977298Sobrien  md_elf_section_change_hook ();
72060484Sobrien#endif
72160484Sobrien}
72260484Sobrien
72389857Sobrienstatic int
724130561Sobrienobj_elf_parse_section_letters (char *str, size_t len)
72560484Sobrien{
72660484Sobrien  int attr = 0;
72760484Sobrien
72860484Sobrien  while (len > 0)
72960484Sobrien    {
73060484Sobrien      switch (*str)
73160484Sobrien	{
73260484Sobrien	case 'a':
73360484Sobrien	  attr |= SHF_ALLOC;
73460484Sobrien	  break;
73560484Sobrien	case 'w':
73660484Sobrien	  attr |= SHF_WRITE;
73760484Sobrien	  break;
73860484Sobrien	case 'x':
73960484Sobrien	  attr |= SHF_EXECINSTR;
74060484Sobrien	  break;
74189857Sobrien	case 'M':
74289857Sobrien	  attr |= SHF_MERGE;
74389857Sobrien	  break;
74489857Sobrien	case 'S':
74589857Sobrien	  attr |= SHF_STRINGS;
74689857Sobrien	  break;
74789857Sobrien	case 'G':
74889857Sobrien	  attr |= SHF_GROUP;
74989857Sobrien	  break;
750104834Sobrien	case 'T':
751104834Sobrien	  attr |= SHF_TLS;
752104834Sobrien	  break;
75389857Sobrien	/* Compatibility.  */
75489857Sobrien	case 'm':
75589857Sobrien	  if (*(str - 1) == 'a')
75689857Sobrien	    {
75789857Sobrien	      attr |= SHF_MERGE;
75889857Sobrien	      if (len > 1 && str[1] == 's')
75989857Sobrien		{
76089857Sobrien		  attr |= SHF_STRINGS;
76189857Sobrien		  str++, len--;
76289857Sobrien		}
76389857Sobrien	      break;
76489857Sobrien	    }
76560484Sobrien	default:
76660484Sobrien	  {
767104834Sobrien	    char *bad_msg = _("unrecognized .section attribute: want a,w,x,M,S,G,T");
76860484Sobrien#ifdef md_elf_section_letter
76960484Sobrien	    int md_attr = md_elf_section_letter (*str, &bad_msg);
77060484Sobrien	    if (md_attr >= 0)
77160484Sobrien	      attr |= md_attr;
77260484Sobrien	    else
77360484Sobrien#endif
774130561Sobrien	      as_fatal ("%s", bad_msg);
77560484Sobrien	  }
77660484Sobrien	  break;
77760484Sobrien	}
77860484Sobrien      str++, len--;
77960484Sobrien    }
78060484Sobrien
78160484Sobrien  return attr;
78260484Sobrien}
78360484Sobrien
78489857Sobrienstatic int
785130561Sobrienobj_elf_section_word (char *str, size_t len)
78660484Sobrien{
78760484Sobrien  if (len == 5 && strncmp (str, "write", 5) == 0)
78860484Sobrien    return SHF_WRITE;
78960484Sobrien  if (len == 5 && strncmp (str, "alloc", 5) == 0)
79060484Sobrien    return SHF_ALLOC;
79160484Sobrien  if (len == 9 && strncmp (str, "execinstr", 9) == 0)
79260484Sobrien    return SHF_EXECINSTR;
793130561Sobrien  if (len == 3 && strncmp (str, "tls", 3) == 0)
794130561Sobrien    return SHF_TLS;
79560484Sobrien
79660484Sobrien#ifdef md_elf_section_word
79760484Sobrien  {
79860484Sobrien    int md_attr = md_elf_section_word (str, len);
79960484Sobrien    if (md_attr >= 0)
80060484Sobrien      return md_attr;
80160484Sobrien  }
80260484Sobrien#endif
80360484Sobrien
80489857Sobrien  as_warn (_("unrecognized section attribute"));
80560484Sobrien  return 0;
80660484Sobrien}
80760484Sobrien
80889857Sobrienstatic int
809130561Sobrienobj_elf_section_type (char *str, size_t len)
81060484Sobrien{
81160484Sobrien  if (len == 8 && strncmp (str, "progbits", 8) == 0)
81260484Sobrien    return SHT_PROGBITS;
81360484Sobrien  if (len == 6 && strncmp (str, "nobits", 6) == 0)
81460484Sobrien    return SHT_NOBITS;
815130561Sobrien  if (len == 4 && strncmp (str, "note", 4) == 0)
816130561Sobrien    return SHT_NOTE;
817218822Sdim  if (len == 10 && strncmp (str, "init_array", 10) == 0)
818218822Sdim    return SHT_INIT_ARRAY;
819218822Sdim  if (len == 10 && strncmp (str, "fini_array", 10) == 0)
820218822Sdim    return SHT_FINI_ARRAY;
821218822Sdim  if (len == 13 && strncmp (str, "preinit_array", 13) == 0)
822218822Sdim    return SHT_PREINIT_ARRAY;
82360484Sobrien
82460484Sobrien#ifdef md_elf_section_type
82560484Sobrien  {
82660484Sobrien    int md_type = md_elf_section_type (str, len);
82760484Sobrien    if (md_type >= 0)
82860484Sobrien      return md_type;
82960484Sobrien  }
83060484Sobrien#endif
83160484Sobrien
83289857Sobrien  as_warn (_("unrecognized section type"));
83360484Sobrien  return 0;
83460484Sobrien}
83560484Sobrien
83689857Sobrien/* Get name of section.  */
83789857Sobrienstatic char *
838130561Sobrienobj_elf_section_name (void)
83989857Sobrien{
84089857Sobrien  char *name;
84189857Sobrien
84289857Sobrien  SKIP_WHITESPACE ();
84389857Sobrien  if (*input_line_pointer == '"')
84489857Sobrien    {
84589857Sobrien      int dummy;
84689857Sobrien
84789857Sobrien      name = demand_copy_C_string (&dummy);
84889857Sobrien      if (name == NULL)
84989857Sobrien	{
85089857Sobrien	  ignore_rest_of_line ();
85189857Sobrien	  return NULL;
85289857Sobrien	}
85389857Sobrien    }
85489857Sobrien  else
85589857Sobrien    {
85689857Sobrien      char *end = input_line_pointer;
85789857Sobrien
85889857Sobrien      while (0 == strchr ("\n\t,; ", *end))
85989857Sobrien	end++;
86089857Sobrien      if (end == input_line_pointer)
86189857Sobrien	{
862130561Sobrien	  as_bad (_("missing name"));
86389857Sobrien	  ignore_rest_of_line ();
86489857Sobrien	  return NULL;
86589857Sobrien	}
86689857Sobrien
86789857Sobrien      name = xmalloc (end - input_line_pointer + 1);
86889857Sobrien      memcpy (name, input_line_pointer, end - input_line_pointer);
86989857Sobrien      name[end - input_line_pointer] = '\0';
870130561Sobrien#ifdef tc_canonicalize_section_name
871130561Sobrien      name = tc_canonicalize_section_name (name);
872130561Sobrien#endif
87389857Sobrien      input_line_pointer = end;
87489857Sobrien    }
87589857Sobrien  SKIP_WHITESPACE ();
87689857Sobrien  return name;
87789857Sobrien}
87889857Sobrien
87960484Sobrienvoid
880130561Sobrienobj_elf_section (int push)
88160484Sobrien{
88289857Sobrien  char *name, *group_name, *beg;
88360484Sobrien  int type, attr, dummy;
88489857Sobrien  int entsize;
885104834Sobrien  int linkonce;
88660484Sobrien
88760484Sobrien#ifndef TC_I370
88833965Sjdp  if (flag_mri)
88933965Sjdp    {
89033965Sjdp      char mri_type;
89133965Sjdp
89260484Sobrien#ifdef md_flush_pending_output
89377298Sobrien      md_flush_pending_output ();
89460484Sobrien#endif
89560484Sobrien
89633965Sjdp      previous_section = now_seg;
89733965Sjdp      previous_subsection = now_subseg;
89833965Sjdp
89933965Sjdp      s_mri_sect (&mri_type);
90033965Sjdp
90133965Sjdp#ifdef md_elf_section_change_hook
90233965Sjdp      md_elf_section_change_hook ();
90333965Sjdp#endif
90433965Sjdp
90533965Sjdp      return;
90633965Sjdp    }
90760484Sobrien#endif /* ! defined (TC_I370) */
90833965Sjdp
90989857Sobrien  name = obj_elf_section_name ();
91089857Sobrien  if (name == NULL)
91189857Sobrien    return;
91233965Sjdp  type = SHT_NULL;
91333965Sjdp  attr = 0;
91489857Sobrien  group_name = NULL;
91589857Sobrien  entsize = 0;
916104834Sobrien  linkonce = 0;
91733965Sjdp
91833965Sjdp  if (*input_line_pointer == ',')
91933965Sjdp    {
92033965Sjdp      /* Skip the comma.  */
92133965Sjdp      ++input_line_pointer;
92233965Sjdp      SKIP_WHITESPACE ();
92338889Sjdp
92433965Sjdp      if (*input_line_pointer == '"')
92533965Sjdp	{
92660484Sobrien	  beg = demand_copy_C_string (&dummy);
92760484Sobrien	  if (beg == NULL)
92833965Sjdp	    {
92960484Sobrien	      ignore_rest_of_line ();
93060484Sobrien	      return;
93133965Sjdp	    }
93260484Sobrien	  attr |= obj_elf_parse_section_letters (beg, strlen (beg));
93333965Sjdp
93433965Sjdp	  SKIP_WHITESPACE ();
93533965Sjdp	  if (*input_line_pointer == ',')
93633965Sjdp	    {
93760484Sobrien	      char c;
93889857Sobrien	      char *save = input_line_pointer;
93989857Sobrien
94033965Sjdp	      ++input_line_pointer;
94133965Sjdp	      SKIP_WHITESPACE ();
94260484Sobrien	      c = *input_line_pointer;
94360484Sobrien	      if (c == '"')
94433965Sjdp		{
94560484Sobrien		  beg = demand_copy_C_string (&dummy);
94660484Sobrien		  if (beg == NULL)
94733965Sjdp		    {
94860484Sobrien		      ignore_rest_of_line ();
94960484Sobrien		      return;
95033965Sjdp		    }
95160484Sobrien		  type = obj_elf_section_type (beg, strlen (beg));
95233965Sjdp		}
95360484Sobrien	      else if (c == '@' || c == '%')
95460484Sobrien		{
95560484Sobrien		  beg = ++input_line_pointer;
95660484Sobrien		  c = get_symbol_end ();
95760484Sobrien		  *input_line_pointer = c;
95860484Sobrien		  type = obj_elf_section_type (beg, input_line_pointer - beg);
95960484Sobrien		}
96089857Sobrien	      else
96189857Sobrien		input_line_pointer = save;
96233965Sjdp	    }
96389857Sobrien
96489857Sobrien	  SKIP_WHITESPACE ();
96589857Sobrien	  if ((attr & SHF_MERGE) != 0 && *input_line_pointer == ',')
96689857Sobrien	    {
96789857Sobrien	      ++input_line_pointer;
96889857Sobrien	      SKIP_WHITESPACE ();
96989857Sobrien	      entsize = get_absolute_expression ();
97089857Sobrien	      SKIP_WHITESPACE ();
97189857Sobrien	      if (entsize < 0)
97289857Sobrien		{
97389857Sobrien		  as_warn (_("invalid merge entity size"));
97489857Sobrien		  attr &= ~SHF_MERGE;
97589857Sobrien		  entsize = 0;
97689857Sobrien		}
97789857Sobrien	    }
97889857Sobrien	  else if ((attr & SHF_MERGE) != 0)
97989857Sobrien	    {
98089857Sobrien	      as_warn (_("entity size for SHF_MERGE not specified"));
98189857Sobrien	      attr &= ~SHF_MERGE;
98289857Sobrien	    }
98389857Sobrien
98489857Sobrien	  if ((attr & SHF_GROUP) != 0 && *input_line_pointer == ',')
98589857Sobrien	    {
98689857Sobrien	      ++input_line_pointer;
98789857Sobrien	      group_name = obj_elf_section_name ();
98889857Sobrien	      if (group_name == NULL)
98989857Sobrien		attr &= ~SHF_GROUP;
990104834Sobrien	      else if (strncmp (input_line_pointer, ",comdat", 7) == 0)
991104834Sobrien		{
992104834Sobrien		  input_line_pointer += 7;
993104834Sobrien		  linkonce = 1;
994104834Sobrien		}
995104834Sobrien	      else if (strncmp (name, ".gnu.linkonce", 13) == 0)
996104834Sobrien		linkonce = 1;
99789857Sobrien	    }
99889857Sobrien	  else if ((attr & SHF_GROUP) != 0)
99989857Sobrien	    {
100089857Sobrien	      as_warn (_("group name for SHF_GROUP not specified"));
100189857Sobrien	      attr &= ~SHF_GROUP;
100289857Sobrien	    }
100333965Sjdp	}
100433965Sjdp      else
100533965Sjdp	{
100633965Sjdp	  do
100733965Sjdp	    {
100860484Sobrien	      char c;
100960484Sobrien
101033965Sjdp	      SKIP_WHITESPACE ();
101133965Sjdp	      if (*input_line_pointer != '#')
101233965Sjdp		{
1013130561Sobrien		  as_bad (_("character following name is not '#'"));
101433965Sjdp		  ignore_rest_of_line ();
101533965Sjdp		  return;
101633965Sjdp		}
101760484Sobrien	      beg = ++input_line_pointer;
101860484Sobrien	      c = get_symbol_end ();
101960484Sobrien	      *input_line_pointer = c;
102060484Sobrien
102160484Sobrien	      attr |= obj_elf_section_word (beg, input_line_pointer - beg);
102260484Sobrien
102333965Sjdp	      SKIP_WHITESPACE ();
102433965Sjdp	    }
102533965Sjdp	  while (*input_line_pointer++ == ',');
102633965Sjdp	  --input_line_pointer;
102733965Sjdp	}
102833965Sjdp    }
102933965Sjdp
103060484Sobrien  demand_empty_rest_of_line ();
103133965Sjdp
1032104834Sobrien  obj_elf_change_section (name, type, attr, entsize, group_name, linkonce, push);
103333965Sjdp}
103433965Sjdp
103533965Sjdp/* Change to the .data section.  */
103633965Sjdp
103760484Sobrienvoid
1038130561Sobrienobj_elf_data (int i)
103933965Sjdp{
104033965Sjdp#ifdef md_flush_pending_output
104133965Sjdp  md_flush_pending_output ();
104233965Sjdp#endif
104333965Sjdp
104433965Sjdp  previous_section = now_seg;
104533965Sjdp  previous_subsection = now_subseg;
104633965Sjdp  s_data (i);
104733965Sjdp
104833965Sjdp#ifdef md_elf_section_change_hook
104933965Sjdp  md_elf_section_change_hook ();
105033965Sjdp#endif
105133965Sjdp}
105233965Sjdp
105333965Sjdp/* Change to the .text section.  */
105433965Sjdp
105560484Sobrienvoid
1056130561Sobrienobj_elf_text (int i)
105733965Sjdp{
105833965Sjdp#ifdef md_flush_pending_output
105933965Sjdp  md_flush_pending_output ();
106033965Sjdp#endif
106133965Sjdp
106233965Sjdp  previous_section = now_seg;
106333965Sjdp  previous_subsection = now_subseg;
106433965Sjdp  s_text (i);
106533965Sjdp
106633965Sjdp#ifdef md_elf_section_change_hook
106733965Sjdp  md_elf_section_change_hook ();
106833965Sjdp#endif
106933965Sjdp}
107033965Sjdp
1071218822Sdim/* Change to the *ABS* section.  */
1072218822Sdim
1073218822Sdimvoid
1074218822Sdimobj_elf_struct (int i)
1075218822Sdim{
1076218822Sdim#ifdef md_flush_pending_output
1077218822Sdim  md_flush_pending_output ();
1078218822Sdim#endif
1079218822Sdim
1080218822Sdim  previous_section = now_seg;
1081218822Sdim  previous_subsection = now_subseg;
1082218822Sdim  s_struct (i);
1083218822Sdim
1084218822Sdim#ifdef md_elf_section_change_hook
1085218822Sdim  md_elf_section_change_hook ();
1086218822Sdim#endif
1087218822Sdim}
1088218822Sdim
108938889Sjdpstatic void
1090130561Sobrienobj_elf_subsection (int ignore ATTRIBUTE_UNUSED)
109138889Sjdp{
109238889Sjdp  register int temp;
109338889Sjdp
109438889Sjdp#ifdef md_flush_pending_output
109538889Sjdp  md_flush_pending_output ();
109638889Sjdp#endif
109738889Sjdp
109838889Sjdp  previous_section = now_seg;
109938889Sjdp  previous_subsection = now_subseg;
110038889Sjdp
110138889Sjdp  temp = get_absolute_expression ();
110238889Sjdp  subseg_set (now_seg, (subsegT) temp);
110338889Sjdp  demand_empty_rest_of_line ();
110438889Sjdp
110538889Sjdp#ifdef md_elf_section_change_hook
110638889Sjdp  md_elf_section_change_hook ();
110738889Sjdp#endif
110838889Sjdp}
110938889Sjdp
111033965Sjdp/* This can be called from the processor backends if they change
111133965Sjdp   sections.  */
111233965Sjdp
111333965Sjdpvoid
1114130561Sobrienobj_elf_section_change_hook (void)
111533965Sjdp{
111633965Sjdp  previous_section = now_seg;
111733965Sjdp  previous_subsection = now_subseg;
111833965Sjdp}
111933965Sjdp
112033965Sjdpvoid
1121130561Sobrienobj_elf_previous (int ignore ATTRIBUTE_UNUSED)
112233965Sjdp{
112360484Sobrien  segT new_section;
112460484Sobrien  int new_subsection;
112560484Sobrien
112633965Sjdp  if (previous_section == 0)
112733965Sjdp    {
112889857Sobrien      as_warn (_(".previous without corresponding .section; ignored"));
112933965Sjdp      return;
113033965Sjdp    }
113133965Sjdp
113233965Sjdp#ifdef md_flush_pending_output
113333965Sjdp  md_flush_pending_output ();
113433965Sjdp#endif
113533965Sjdp
113660484Sobrien  new_section = previous_section;
113760484Sobrien  new_subsection = previous_subsection;
113860484Sobrien  previous_section = now_seg;
113960484Sobrien  previous_subsection = now_subseg;
114060484Sobrien  subseg_set (new_section, new_subsection);
114133965Sjdp
114233965Sjdp#ifdef md_elf_section_change_hook
114333965Sjdp  md_elf_section_change_hook ();
114433965Sjdp#endif
114533965Sjdp}
114633965Sjdp
114733965Sjdpstatic void
1148130561Sobrienobj_elf_popsection (int xxx ATTRIBUTE_UNUSED)
114960484Sobrien{
115060484Sobrien  struct section_stack *top = section_stack;
115160484Sobrien
115260484Sobrien  if (top == NULL)
115360484Sobrien    {
115489857Sobrien      as_warn (_(".popsection without corresponding .pushsection; ignored"));
115560484Sobrien      return;
115660484Sobrien    }
115760484Sobrien
115860484Sobrien#ifdef md_flush_pending_output
115960484Sobrien  md_flush_pending_output ();
116060484Sobrien#endif
116160484Sobrien
116260484Sobrien  section_stack = top->next;
116360484Sobrien  previous_section = top->prev_seg;
116460484Sobrien  previous_subsection = top->prev_subseg;
116560484Sobrien  subseg_set (top->seg, top->subseg);
116660484Sobrien  free (top);
116760484Sobrien
116860484Sobrien#ifdef md_elf_section_change_hook
116960484Sobrien  md_elf_section_change_hook ();
117060484Sobrien#endif
117160484Sobrien}
117260484Sobrien
117360484Sobrienstatic void
1174130561Sobrienobj_elf_line (int ignore ATTRIBUTE_UNUSED)
117533965Sjdp{
117633965Sjdp  /* Assume delimiter is part of expression.  BSD4.2 as fails with
117777298Sobrien     delightful bug, so we are not being incompatible here.  */
1178130561Sobrien  new_logical_line (NULL, get_absolute_expression ());
117933965Sjdp  demand_empty_rest_of_line ();
118033965Sjdp}
118133965Sjdp
118260484Sobrien/* This handles the .symver pseudo-op, which is used to specify a
118333965Sjdp   symbol version.  The syntax is ``.symver NAME,SYMVERNAME''.
118433965Sjdp   SYMVERNAME may contain ELF_VER_CHR ('@') characters.  This
118533965Sjdp   pseudo-op causes the assembler to emit a symbol named SYMVERNAME
118633965Sjdp   with the same value as the symbol NAME.  */
118733965Sjdp
118833965Sjdpstatic void
1189130561Sobrienobj_elf_symver (int ignore ATTRIBUTE_UNUSED)
119033965Sjdp{
119133965Sjdp  char *name;
119233965Sjdp  char c;
119389857Sobrien  char old_lexat;
119433965Sjdp  symbolS *sym;
119533965Sjdp
119633965Sjdp  name = input_line_pointer;
119733965Sjdp  c = get_symbol_end ();
119833965Sjdp
119933965Sjdp  sym = symbol_find_or_make (name);
120033965Sjdp
120133965Sjdp  *input_line_pointer = c;
120233965Sjdp
120333965Sjdp  SKIP_WHITESPACE ();
120433965Sjdp  if (*input_line_pointer != ',')
120533965Sjdp    {
120660484Sobrien      as_bad (_("expected comma after name in .symver"));
120733965Sjdp      ignore_rest_of_line ();
120833965Sjdp      return;
120933965Sjdp    }
121033965Sjdp
121133965Sjdp  ++input_line_pointer;
1212130561Sobrien  SKIP_WHITESPACE ();
121333965Sjdp  name = input_line_pointer;
121433965Sjdp
121589857Sobrien  /* Temporarily include '@' in symbol names.  */
121689857Sobrien  old_lexat = lex_type[(unsigned char) '@'];
121789857Sobrien  lex_type[(unsigned char) '@'] |= LEX_NAME;
121889857Sobrien  c = get_symbol_end ();
121989857Sobrien  lex_type[(unsigned char) '@'] = old_lexat;
122089857Sobrien
122177298Sobrien  if (symbol_get_obj (sym)->versioned_name == NULL)
122277298Sobrien    {
122377298Sobrien      symbol_get_obj (sym)->versioned_name = xstrdup (name);
122433965Sjdp
122577298Sobrien      *input_line_pointer = c;
122633965Sjdp
122777298Sobrien      if (strchr (symbol_get_obj (sym)->versioned_name,
122877298Sobrien		  ELF_VER_CHR) == NULL)
122977298Sobrien	{
123077298Sobrien	  as_bad (_("missing version name in `%s' for symbol `%s'"),
123177298Sobrien		  symbol_get_obj (sym)->versioned_name,
123277298Sobrien		  S_GET_NAME (sym));
123377298Sobrien	  ignore_rest_of_line ();
123477298Sobrien	  return;
123577298Sobrien	}
123677298Sobrien    }
123777298Sobrien  else
123833965Sjdp    {
123977298Sobrien      if (strcmp (symbol_get_obj (sym)->versioned_name, name))
124077298Sobrien	{
124177298Sobrien	  as_bad (_("multiple versions [`%s'|`%s'] for symbol `%s'"),
124277298Sobrien		  name, symbol_get_obj (sym)->versioned_name,
124377298Sobrien		  S_GET_NAME (sym));
124477298Sobrien	  ignore_rest_of_line ();
124577298Sobrien	  return;
124677298Sobrien	}
124777298Sobrien
124877298Sobrien      *input_line_pointer = c;
124933965Sjdp    }
125033965Sjdp
125133965Sjdp  demand_empty_rest_of_line ();
125233965Sjdp}
125333965Sjdp
125460484Sobrien/* This handles the .vtable_inherit pseudo-op, which is used to indicate
125560484Sobrien   to the linker the hierarchy in which a particular table resides.  The
125660484Sobrien   syntax is ".vtable_inherit CHILDNAME, PARENTNAME".  */
125760484Sobrien
125877298Sobrienstruct fix *
1259130561Sobrienobj_elf_vtable_inherit (int ignore ATTRIBUTE_UNUSED)
126060484Sobrien{
126160484Sobrien  char *cname, *pname;
126260484Sobrien  symbolS *csym, *psym;
126360484Sobrien  char c, bad = 0;
126460484Sobrien
126560484Sobrien  if (*input_line_pointer == '#')
126660484Sobrien    ++input_line_pointer;
126760484Sobrien
126860484Sobrien  cname = input_line_pointer;
126960484Sobrien  c = get_symbol_end ();
127060484Sobrien  csym = symbol_find (cname);
127160484Sobrien
127260484Sobrien  /* GCFIXME: should check that we don't have two .vtable_inherits for
127360484Sobrien     the same child symbol.  Also, we can currently only do this if the
127460484Sobrien     child symbol is already exists and is placed in a fragment.  */
127560484Sobrien
127660484Sobrien  if (csym == NULL || symbol_get_frag (csym) == NULL)
127760484Sobrien    {
127860484Sobrien      as_bad ("expected `%s' to have already been set for .vtable_inherit",
127960484Sobrien	      cname);
128060484Sobrien      bad = 1;
128160484Sobrien    }
128260484Sobrien
128360484Sobrien  *input_line_pointer = c;
128460484Sobrien
128560484Sobrien  SKIP_WHITESPACE ();
128660484Sobrien  if (*input_line_pointer != ',')
128760484Sobrien    {
128860484Sobrien      as_bad ("expected comma after name in .vtable_inherit");
128960484Sobrien      ignore_rest_of_line ();
129077298Sobrien      return NULL;
129160484Sobrien    }
129260484Sobrien
129360484Sobrien  ++input_line_pointer;
129460484Sobrien  SKIP_WHITESPACE ();
129560484Sobrien
129660484Sobrien  if (*input_line_pointer == '#')
129760484Sobrien    ++input_line_pointer;
129860484Sobrien
129960484Sobrien  if (input_line_pointer[0] == '0'
130060484Sobrien      && (input_line_pointer[1] == '\0'
130189857Sobrien	  || ISSPACE (input_line_pointer[1])))
130260484Sobrien    {
130360484Sobrien      psym = section_symbol (absolute_section);
130460484Sobrien      ++input_line_pointer;
130560484Sobrien    }
130660484Sobrien  else
130760484Sobrien    {
130860484Sobrien      pname = input_line_pointer;
130960484Sobrien      c = get_symbol_end ();
131060484Sobrien      psym = symbol_find_or_make (pname);
131160484Sobrien      *input_line_pointer = c;
131260484Sobrien    }
131360484Sobrien
131460484Sobrien  demand_empty_rest_of_line ();
131560484Sobrien
131660484Sobrien  if (bad)
131777298Sobrien    return NULL;
131860484Sobrien
131960484Sobrien  assert (symbol_get_value_expression (csym)->X_op == O_constant);
132077298Sobrien  return fix_new (symbol_get_frag (csym),
132177298Sobrien		  symbol_get_value_expression (csym)->X_add_number,
132277298Sobrien		  0, psym, 0, 0, BFD_RELOC_VTABLE_INHERIT);
132360484Sobrien}
132460484Sobrien
132560484Sobrien/* This handles the .vtable_entry pseudo-op, which is used to indicate
132660484Sobrien   to the linker that a vtable slot was used.  The syntax is
132760484Sobrien   ".vtable_entry tablename, offset".  */
132860484Sobrien
132977298Sobrienstruct fix *
1330130561Sobrienobj_elf_vtable_entry (int ignore ATTRIBUTE_UNUSED)
133160484Sobrien{
133260484Sobrien  char *name;
133360484Sobrien  symbolS *sym;
133460484Sobrien  offsetT offset;
133560484Sobrien  char c;
133660484Sobrien
133760484Sobrien  if (*input_line_pointer == '#')
133860484Sobrien    ++input_line_pointer;
133960484Sobrien
134060484Sobrien  name = input_line_pointer;
134160484Sobrien  c = get_symbol_end ();
134260484Sobrien  sym = symbol_find_or_make (name);
134360484Sobrien  *input_line_pointer = c;
134460484Sobrien
134560484Sobrien  SKIP_WHITESPACE ();
134660484Sobrien  if (*input_line_pointer != ',')
134760484Sobrien    {
134860484Sobrien      as_bad ("expected comma after name in .vtable_entry");
134960484Sobrien      ignore_rest_of_line ();
135077298Sobrien      return NULL;
135160484Sobrien    }
135260484Sobrien
135360484Sobrien  ++input_line_pointer;
135460484Sobrien  if (*input_line_pointer == '#')
135560484Sobrien    ++input_line_pointer;
135660484Sobrien
135760484Sobrien  offset = get_absolute_expression ();
135860484Sobrien
135977298Sobrien  demand_empty_rest_of_line ();
136060484Sobrien
136177298Sobrien  return fix_new (frag_now, frag_now_fix (), 0, sym, offset, 0,
136277298Sobrien		  BFD_RELOC_VTABLE_ENTRY);
136360484Sobrien}
136460484Sobrien
136533965Sjdpvoid
1366130561Sobrienelf_obj_read_begin_hook (void)
136733965Sjdp{
136833965Sjdp#ifdef NEED_ECOFF_DEBUG
136933965Sjdp  if (ECOFF_DEBUGGING)
137033965Sjdp    ecoff_read_begin_hook ();
137133965Sjdp#endif
137233965Sjdp}
137333965Sjdp
137433965Sjdpvoid
1375130561Sobrienelf_obj_symbol_new_hook (symbolS *symbolP)
137633965Sjdp{
137760484Sobrien  struct elf_obj_sy *sy_obj;
137833965Sjdp
137960484Sobrien  sy_obj = symbol_get_obj (symbolP);
138060484Sobrien  sy_obj->size = NULL;
138160484Sobrien  sy_obj->versioned_name = NULL;
138260484Sobrien
138333965Sjdp#ifdef NEED_ECOFF_DEBUG
138433965Sjdp  if (ECOFF_DEBUGGING)
138533965Sjdp    ecoff_symbol_new_hook (symbolP);
138633965Sjdp#endif
138733965Sjdp}
138833965Sjdp
138989857Sobrien/* When setting one symbol equal to another, by default we probably
139089857Sobrien   want them to have the same "size", whatever it means in the current
139189857Sobrien   context.  */
139289857Sobrien
139333965Sjdpvoid
1394130561Sobrienelf_copy_symbol_attributes (symbolS *dest, symbolS *src)
139589857Sobrien{
139689857Sobrien  struct elf_obj_sy *srcelf = symbol_get_obj (src);
139789857Sobrien  struct elf_obj_sy *destelf = symbol_get_obj (dest);
139889857Sobrien  if (srcelf->size)
139989857Sobrien    {
140089857Sobrien      if (destelf->size == NULL)
1401130561Sobrien	destelf->size = xmalloc (sizeof (expressionS));
140289857Sobrien      *destelf->size = *srcelf->size;
140389857Sobrien    }
140489857Sobrien  else
140589857Sobrien    {
140689857Sobrien      if (destelf->size != NULL)
140789857Sobrien	free (destelf->size);
140889857Sobrien      destelf->size = NULL;
140989857Sobrien    }
141089857Sobrien  S_SET_SIZE (dest, S_GET_SIZE (src));
141194536Sobrien  /* Don't copy visibility.  */
141294536Sobrien  S_SET_OTHER (dest, (ELF_ST_VISIBILITY (S_GET_OTHER (dest))
141394536Sobrien		      | (S_GET_OTHER (src) & ~ELF_ST_VISIBILITY (-1))));
141489857Sobrien}
141589857Sobrien
141689857Sobrienvoid
1417130561Sobrienobj_elf_version (int ignore ATTRIBUTE_UNUSED)
141833965Sjdp{
141933965Sjdp  char *name;
142033965Sjdp  unsigned int c;
142133965Sjdp  char *p;
142233965Sjdp  asection *seg = now_seg;
142333965Sjdp  subsegT subseg = now_subseg;
142433965Sjdp  Elf_Internal_Note i_note;
142533965Sjdp  Elf_External_Note e_note;
1426130561Sobrien  asection *note_secp = NULL;
142733965Sjdp
142833965Sjdp  SKIP_WHITESPACE ();
142933965Sjdp  if (*input_line_pointer == '\"')
143033965Sjdp    {
1431218822Sdim      unsigned int len;
1432218822Sdim
143377298Sobrien      ++input_line_pointer;	/* -> 1st char of string.  */
143433965Sjdp      name = input_line_pointer;
143533965Sjdp
143633965Sjdp      while (is_a_char (c = next_char_of_string ()))
143733965Sjdp	;
143833965Sjdp      c = *input_line_pointer;
143933965Sjdp      *input_line_pointer = '\0';
144033965Sjdp      *(input_line_pointer - 1) = '\0';
144133965Sjdp      *input_line_pointer = c;
144233965Sjdp
1443218822Sdim      /* Create the .note section.  */
144433965Sjdp      note_secp = subseg_new (".note", 0);
144533965Sjdp      bfd_set_section_flags (stdoutput,
144633965Sjdp			     note_secp,
144733965Sjdp			     SEC_HAS_CONTENTS | SEC_READONLY);
144833965Sjdp
1449218822Sdim      /* Process the version string.  */
1450218822Sdim      len = strlen (name) + 1;
145133965Sjdp
1452218822Sdim      /* PR 3456: Although the name field is padded out to an 4-byte
1453218822Sdim	 boundary, the namesz field should not be adjusted.  */
1454218822Sdim      i_note.namesz = len;
1455218822Sdim      i_note.descsz = 0;	/* No description.  */
145633965Sjdp      i_note.type = NT_VERSION;
145733965Sjdp      p = frag_more (sizeof (e_note.namesz));
1458130561Sobrien      md_number_to_chars (p, i_note.namesz, sizeof (e_note.namesz));
145933965Sjdp      p = frag_more (sizeof (e_note.descsz));
1460130561Sobrien      md_number_to_chars (p, i_note.descsz, sizeof (e_note.descsz));
146133965Sjdp      p = frag_more (sizeof (e_note.type));
1462130561Sobrien      md_number_to_chars (p, i_note.type, sizeof (e_note.type));
1463218822Sdim      p = frag_more (len);
1464218822Sdim      memcpy (p, name, len);
146533965Sjdp
146633965Sjdp      frag_align (2, 0, 0);
146733965Sjdp
146833965Sjdp      subseg_set (seg, subseg);
146933965Sjdp    }
147033965Sjdp  else
1471218822Sdim    as_bad (_("expected quoted string"));
1472218822Sdim
147333965Sjdp  demand_empty_rest_of_line ();
147433965Sjdp}
147533965Sjdp
147633965Sjdpstatic void
1477130561Sobrienobj_elf_size (int ignore ATTRIBUTE_UNUSED)
147833965Sjdp{
147933965Sjdp  char *name = input_line_pointer;
148033965Sjdp  char c = get_symbol_end ();
148133965Sjdp  char *p;
148233965Sjdp  expressionS exp;
148333965Sjdp  symbolS *sym;
148433965Sjdp
148533965Sjdp  p = input_line_pointer;
148633965Sjdp  *p = c;
148733965Sjdp  SKIP_WHITESPACE ();
148833965Sjdp  if (*input_line_pointer != ',')
148933965Sjdp    {
149033965Sjdp      *p = 0;
149160484Sobrien      as_bad (_("expected comma after name `%s' in .size directive"), name);
149233965Sjdp      *p = c;
149333965Sjdp      ignore_rest_of_line ();
149433965Sjdp      return;
149533965Sjdp    }
149633965Sjdp  input_line_pointer++;
149733965Sjdp  expression (&exp);
149833965Sjdp  if (exp.X_op == O_absent)
149933965Sjdp    {
150060484Sobrien      as_bad (_("missing expression in .size directive"));
150133965Sjdp      exp.X_op = O_constant;
150233965Sjdp      exp.X_add_number = 0;
150333965Sjdp    }
150433965Sjdp  *p = 0;
150533965Sjdp  sym = symbol_find_or_make (name);
150633965Sjdp  *p = c;
150733965Sjdp  if (exp.X_op == O_constant)
150889857Sobrien    {
150989857Sobrien      S_SET_SIZE (sym, exp.X_add_number);
151089857Sobrien      if (symbol_get_obj (sym)->size)
151189857Sobrien	{
151289857Sobrien	  xfree (symbol_get_obj (sym)->size);
151389857Sobrien	  symbol_get_obj (sym)->size = NULL;
151489857Sobrien	}
151589857Sobrien    }
151633965Sjdp  else
151733965Sjdp    {
1518130561Sobrien      symbol_get_obj (sym)->size = xmalloc (sizeof (expressionS));
151960484Sobrien      *symbol_get_obj (sym)->size = exp;
152033965Sjdp    }
152133965Sjdp  demand_empty_rest_of_line ();
152233965Sjdp}
152333965Sjdp
152433965Sjdp/* Handle the ELF .type pseudo-op.  This sets the type of a symbol.
152577298Sobrien   There are five syntaxes:
152660484Sobrien
152760484Sobrien   The first (used on Solaris) is
152833965Sjdp       .type SYM,#function
152933965Sjdp   The second (used on UnixWare) is
153033965Sjdp       .type SYM,@function
153133965Sjdp   The third (reportedly to be used on Irix 6.0) is
153233965Sjdp       .type SYM STT_FUNC
153360484Sobrien   The fourth (used on NetBSD/Arm and Linux/ARM) is
153460484Sobrien       .type SYM,%function
153577298Sobrien   The fifth (used on SVR4/860) is
153677298Sobrien       .type SYM,"function"
153733965Sjdp   */
153833965Sjdp
153933965Sjdpstatic void
1540130561Sobrienobj_elf_type (int ignore ATTRIBUTE_UNUSED)
154133965Sjdp{
154233965Sjdp  char *name;
154333965Sjdp  char c;
154433965Sjdp  int type;
154533965Sjdp  const char *typename;
154633965Sjdp  symbolS *sym;
154777298Sobrien  elf_symbol_type *elfsym;
154833965Sjdp
154933965Sjdp  name = input_line_pointer;
155033965Sjdp  c = get_symbol_end ();
155133965Sjdp  sym = symbol_find_or_make (name);
155277298Sobrien  elfsym = (elf_symbol_type *) symbol_get_bfdsym (sym);
155333965Sjdp  *input_line_pointer = c;
155433965Sjdp
155533965Sjdp  SKIP_WHITESPACE ();
155633965Sjdp  if (*input_line_pointer == ',')
155733965Sjdp    ++input_line_pointer;
155833965Sjdp
155933965Sjdp  SKIP_WHITESPACE ();
156060484Sobrien  if (   *input_line_pointer == '#'
156160484Sobrien      || *input_line_pointer == '@'
156277298Sobrien      || *input_line_pointer == '"'
156360484Sobrien      || *input_line_pointer == '%')
156433965Sjdp    ++input_line_pointer;
156533965Sjdp
156633965Sjdp  typename = input_line_pointer;
156733965Sjdp  c = get_symbol_end ();
156833965Sjdp
156933965Sjdp  type = 0;
157033965Sjdp  if (strcmp (typename, "function") == 0
157133965Sjdp      || strcmp (typename, "STT_FUNC") == 0)
157233965Sjdp    type = BSF_FUNCTION;
157333965Sjdp  else if (strcmp (typename, "object") == 0
157433965Sjdp	   || strcmp (typename, "STT_OBJECT") == 0)
157533965Sjdp    type = BSF_OBJECT;
1576130561Sobrien  else if (strcmp (typename, "tls_object") == 0
1577130561Sobrien	   || strcmp (typename, "STT_TLS") == 0)
1578130561Sobrien    type = BSF_OBJECT | BSF_THREAD_LOCAL;
1579130561Sobrien  else if (strcmp (typename, "notype") == 0
1580130561Sobrien	   || strcmp (typename, "STT_NOTYPE") == 0)
1581130561Sobrien    ;
158277298Sobrien#ifdef md_elf_symbol_type
158377298Sobrien  else if ((type = md_elf_symbol_type (typename, sym, elfsym)) != -1)
158477298Sobrien    ;
158577298Sobrien#endif
158633965Sjdp  else
158789857Sobrien    as_bad (_("unrecognized symbol type \"%s\""), typename);
158833965Sjdp
158933965Sjdp  *input_line_pointer = c;
159033965Sjdp
159177298Sobrien  if (*input_line_pointer == '"')
159277298Sobrien    ++input_line_pointer;
159333965Sjdp
159477298Sobrien  elfsym->symbol.flags |= type;
159577298Sobrien
159633965Sjdp  demand_empty_rest_of_line ();
159733965Sjdp}
159833965Sjdp
159933965Sjdpstatic void
1600130561Sobrienobj_elf_ident (int ignore ATTRIBUTE_UNUSED)
160133965Sjdp{
160233965Sjdp  static segT comment_section;
160333965Sjdp  segT old_section = now_seg;
160433965Sjdp  int old_subsection = now_subseg;
160533965Sjdp
160660484Sobrien#ifdef md_flush_pending_output
160760484Sobrien  md_flush_pending_output ();
160860484Sobrien#endif
160960484Sobrien
161033965Sjdp  if (!comment_section)
161133965Sjdp    {
161233965Sjdp      char *p;
161333965Sjdp      comment_section = subseg_new (".comment", 0);
161433965Sjdp      bfd_set_section_flags (stdoutput, comment_section,
161533965Sjdp			     SEC_READONLY | SEC_HAS_CONTENTS);
161633965Sjdp      p = frag_more (1);
161733965Sjdp      *p = 0;
161833965Sjdp    }
161933965Sjdp  else
162033965Sjdp    subseg_set (comment_section, 0);
162133965Sjdp  stringer (1);
162233965Sjdp  subseg_set (old_section, old_subsection);
162333965Sjdp}
162433965Sjdp
162533965Sjdp#ifdef INIT_STAB_SECTION
162633965Sjdp
162733965Sjdp/* The first entry in a .stabs section is special.  */
162833965Sjdp
162933965Sjdpvoid
1630130561Sobrienobj_elf_init_stab_section (segT seg)
163133965Sjdp{
163233965Sjdp  char *file;
163333965Sjdp  char *p;
163433965Sjdp  char *stabstr_name;
163533965Sjdp  unsigned int stroff;
163633965Sjdp
163733965Sjdp  /* Force the section to align to a longword boundary.  Without this,
163833965Sjdp     UnixWare ar crashes.  */
1639223262Sbenl  (void) bfd_set_section_alignment (stdoutput, seg, 2);
164033965Sjdp
164177298Sobrien  /* Make space for this first symbol.  */
164233965Sjdp  p = frag_more (12);
164377298Sobrien  /* Zero it out.  */
164433965Sjdp  memset (p, 0, 12);
1645130561Sobrien  as_where (&file, NULL);
1646130561Sobrien  stabstr_name = xmalloc (strlen (segment_name (seg)) + 4);
164733965Sjdp  strcpy (stabstr_name, segment_name (seg));
164833965Sjdp  strcat (stabstr_name, "str");
164933965Sjdp  stroff = get_stab_string_offset (file, stabstr_name);
165033965Sjdp  know (stroff == 1);
165133965Sjdp  md_number_to_chars (p, stroff, 4);
165233965Sjdp  seg_info (seg)->stabu.p = p;
165333965Sjdp}
165433965Sjdp
165533965Sjdp#endif
165633965Sjdp
165733965Sjdp/* Fill in the counts in the first entry in a .stabs section.  */
165833965Sjdp
165933965Sjdpstatic void
1660130561Sobrienadjust_stab_sections (bfd *abfd, asection *sec, void *xxx ATTRIBUTE_UNUSED)
166133965Sjdp{
166233965Sjdp  char *name;
166333965Sjdp  asection *strsec;
166433965Sjdp  char *p;
166533965Sjdp  int strsz, nsyms;
166633965Sjdp
166733965Sjdp  if (strncmp (".stab", sec->name, 5))
166833965Sjdp    return;
166933965Sjdp  if (!strcmp ("str", sec->name + strlen (sec->name) - 3))
167033965Sjdp    return;
167133965Sjdp
1672130561Sobrien  name = alloca (strlen (sec->name) + 4);
167333965Sjdp  strcpy (name, sec->name);
167433965Sjdp  strcat (name, "str");
167533965Sjdp  strsec = bfd_get_section_by_name (abfd, name);
167633965Sjdp  if (strsec)
167733965Sjdp    strsz = bfd_section_size (abfd, strsec);
167833965Sjdp  else
167933965Sjdp    strsz = 0;
168033965Sjdp  nsyms = bfd_section_size (abfd, sec) / 12 - 1;
168133965Sjdp
168233965Sjdp  p = seg_info (sec)->stabu.p;
168333965Sjdp  assert (p != 0);
168433965Sjdp
1685130561Sobrien  bfd_h_put_16 (abfd, nsyms, p + 6);
1686130561Sobrien  bfd_h_put_32 (abfd, strsz, p + 8);
168733965Sjdp}
168833965Sjdp
168933965Sjdp#ifdef NEED_ECOFF_DEBUG
169033965Sjdp
169133965Sjdp/* This function is called by the ECOFF code.  It is supposed to
169233965Sjdp   record the external symbol information so that the backend can
169333965Sjdp   write it out correctly.  The ELF backend doesn't actually handle
169433965Sjdp   this at the moment, so we do it ourselves.  We save the information
169533965Sjdp   in the symbol.  */
169633965Sjdp
1697218822Sdim#ifdef OBJ_MAYBE_ELF
1698218822Sdimstatic
1699218822Sdim#endif
170033965Sjdpvoid
1701130561Sobrienelf_ecoff_set_ext (symbolS *sym, struct ecoff_extr *ext)
170233965Sjdp{
1703130561Sobrien  symbol_get_bfdsym (sym)->udata.p = ext;
170433965Sjdp}
170533965Sjdp
170633965Sjdp/* This function is called by bfd_ecoff_debug_externals.  It is
170733965Sjdp   supposed to *EXT to the external symbol information, and return
170833965Sjdp   whether the symbol should be used at all.  */
170933965Sjdp
1710130561Sobrienstatic bfd_boolean
1711130561Sobrienelf_get_extr (asymbol *sym, EXTR *ext)
171233965Sjdp{
171333965Sjdp  if (sym->udata.p == NULL)
1714130561Sobrien    return FALSE;
171533965Sjdp  *ext = *(EXTR *) sym->udata.p;
1716130561Sobrien  return TRUE;
171733965Sjdp}
171833965Sjdp
171933965Sjdp/* This function is called by bfd_ecoff_debug_externals.  It has
172033965Sjdp   nothing to do for ELF.  */
172133965Sjdp
172233965Sjdpstatic void
1723130561Sobrienelf_set_index (asymbol *sym ATTRIBUTE_UNUSED,
1724130561Sobrien	       bfd_size_type indx ATTRIBUTE_UNUSED)
172533965Sjdp{
172633965Sjdp}
172733965Sjdp
172833965Sjdp#endif /* NEED_ECOFF_DEBUG */
172933965Sjdp
173033965Sjdpvoid
1731130561Sobrienelf_frob_symbol (symbolS *symp, int *puntp)
173233965Sjdp{
173360484Sobrien  struct elf_obj_sy *sy_obj;
173460484Sobrien
173533965Sjdp#ifdef NEED_ECOFF_DEBUG
173633965Sjdp  if (ECOFF_DEBUGGING)
173733965Sjdp    ecoff_frob_symbol (symp);
173833965Sjdp#endif
173933965Sjdp
174060484Sobrien  sy_obj = symbol_get_obj (symp);
174160484Sobrien
174260484Sobrien  if (sy_obj->size != NULL)
174333965Sjdp    {
174460484Sobrien      switch (sy_obj->size->X_op)
174533965Sjdp	{
174633965Sjdp	case O_subtract:
174733965Sjdp	  S_SET_SIZE (symp,
174860484Sobrien		      (S_GET_VALUE (sy_obj->size->X_add_symbol)
174960484Sobrien		       + sy_obj->size->X_add_number
175060484Sobrien		       - S_GET_VALUE (sy_obj->size->X_op_symbol)));
175133965Sjdp	  break;
175233965Sjdp	case O_constant:
175333965Sjdp	  S_SET_SIZE (symp,
175460484Sobrien		      (S_GET_VALUE (sy_obj->size->X_add_symbol)
175560484Sobrien		       + sy_obj->size->X_add_number));
175633965Sjdp	  break;
175733965Sjdp	default:
175860484Sobrien	  as_bad (_(".size expression too complicated to fix up"));
175933965Sjdp	  break;
176033965Sjdp	}
176160484Sobrien      free (sy_obj->size);
176260484Sobrien      sy_obj->size = NULL;
176333965Sjdp    }
176433965Sjdp
176560484Sobrien  if (sy_obj->versioned_name != NULL)
176633965Sjdp    {
176777298Sobrien      char *p;
176877298Sobrien
176977298Sobrien      p = strchr (sy_obj->versioned_name, ELF_VER_CHR);
177077298Sobrien      know (p != NULL);
177177298Sobrien
177233965Sjdp      /* This symbol was given a new name with the .symver directive.
177333965Sjdp
1774130561Sobrien	 If this is an external reference, just rename the symbol to
1775130561Sobrien	 include the version string.  This will make the relocs be
1776130561Sobrien	 against the correct versioned symbol.
177733965Sjdp
177833965Sjdp	 If this is a definition, add an alias.  FIXME: Using an alias
177933965Sjdp	 will permit the debugging information to refer to the right
178033965Sjdp	 symbol.  However, it's not clear whether it is the best
178133965Sjdp	 approach.  */
178233965Sjdp
178333965Sjdp      if (! S_IS_DEFINED (symp))
178433965Sjdp	{
178533965Sjdp	  /* Verify that the name isn't using the @@ syntax--this is
1786130561Sobrien	     reserved for definitions of the default version to link
1787130561Sobrien	     against.  */
178833965Sjdp	  if (p[1] == ELF_VER_CHR)
178933965Sjdp	    {
179060484Sobrien	      as_bad (_("invalid attempt to declare external version name as default in symbol `%s'"),
179160484Sobrien		      sy_obj->versioned_name);
1792130561Sobrien	      *puntp = TRUE;
179333965Sjdp	    }
179460484Sobrien	  S_SET_NAME (symp, sy_obj->versioned_name);
179533965Sjdp	}
179633965Sjdp      else
179733965Sjdp	{
1798130561Sobrien	  if (p[1] == ELF_VER_CHR && p[2] == ELF_VER_CHR)
179977298Sobrien	    {
180077298Sobrien	      size_t l;
180133965Sjdp
180277298Sobrien	      /* The @@@ syntax is a special case. It renames the
180377298Sobrien		 symbol name to versioned_name with one `@' removed.  */
180477298Sobrien	      l = strlen (&p[3]) + 1;
1805130561Sobrien	      memmove (&p[2], &p[3], l);
180677298Sobrien	      S_SET_NAME (symp, sy_obj->versioned_name);
180777298Sobrien	    }
180877298Sobrien	  else
180977298Sobrien	    {
181077298Sobrien	      symbolS *symp2;
181133965Sjdp
181277298Sobrien	      /* FIXME: Creating a new symbol here is risky.  We're
181377298Sobrien		 in the final loop over the symbol table.  We can
181477298Sobrien		 get away with it only because the symbol goes to
181577298Sobrien		 the end of the list, where the loop will still see
181677298Sobrien		 it.  It would probably be better to do this in
181777298Sobrien		 obj_frob_file_before_adjust.  */
181833965Sjdp
181977298Sobrien	      symp2 = symbol_find_or_make (sy_obj->versioned_name);
182033965Sjdp
182177298Sobrien	      /* Now we act as though we saw symp2 = sym.  */
182233965Sjdp
182377298Sobrien	      S_SET_SEGMENT (symp2, S_GET_SEGMENT (symp));
182433965Sjdp
182577298Sobrien	      /* Subtracting out the frag address here is a hack
182677298Sobrien		 because we are in the middle of the final loop.  */
182777298Sobrien	      S_SET_VALUE (symp2,
182877298Sobrien			   (S_GET_VALUE (symp)
182977298Sobrien			    - symbol_get_frag (symp)->fr_address));
183033965Sjdp
183177298Sobrien	      symbol_set_frag (symp2, symbol_get_frag (symp));
183233965Sjdp
183377298Sobrien	      /* This will copy over the size information.  */
183477298Sobrien	      copy_symbol_attributes (symp2, symp);
183533965Sjdp
183694536Sobrien	      S_SET_OTHER (symp2, S_GET_OTHER (symp));
183794536Sobrien
183877298Sobrien	      if (S_IS_WEAK (symp))
183977298Sobrien		S_SET_WEAK (symp2);
184077298Sobrien
184177298Sobrien	      if (S_IS_EXTERNAL (symp))
184277298Sobrien		S_SET_EXTERNAL (symp2);
184377298Sobrien	    }
184433965Sjdp	}
184533965Sjdp    }
184633965Sjdp
184733965Sjdp  /* Double check weak symbols.  */
184860484Sobrien  if (S_IS_WEAK (symp))
184933965Sjdp    {
185033965Sjdp      if (S_IS_COMMON (symp))
185189857Sobrien	as_bad (_("symbol `%s' can not be both weak and common"),
185233965Sjdp		S_GET_NAME (symp));
185333965Sjdp    }
185433965Sjdp
185533965Sjdp#ifdef TC_MIPS
185633965Sjdp  /* The Irix 5 and 6 assemblers set the type of any common symbol and
185738889Sjdp     any undefined non-function symbol to STT_OBJECT.  We try to be
185838889Sjdp     compatible, since newer Irix 5 and 6 linkers care.  However, we
185938889Sjdp     only set undefined symbols to be STT_OBJECT if we are on Irix,
186038889Sjdp     because that is the only time gcc will generate the necessary
186138889Sjdp     .global directives to mark functions.  */
186238889Sjdp
186338889Sjdp  if (S_IS_COMMON (symp))
186460484Sobrien    symbol_get_bfdsym (symp)->flags |= BSF_OBJECT;
186538889Sjdp
186638889Sjdp  if (strstr (TARGET_OS, "irix") != NULL
186760484Sobrien      && ! S_IS_DEFINED (symp)
186860484Sobrien      && (symbol_get_bfdsym (symp)->flags & BSF_FUNCTION) == 0)
186960484Sobrien    symbol_get_bfdsym (symp)->flags |= BSF_OBJECT;
187033965Sjdp#endif
187133965Sjdp}
187233965Sjdp
187389857Sobrienstruct group_list
187489857Sobrien{
187589857Sobrien  asection **head;		/* Section lists.  */
187689857Sobrien  unsigned int *elt_count;	/* Number of sections in each list.  */
187789857Sobrien  unsigned int num_group;	/* Number of lists.  */
187889857Sobrien};
187989857Sobrien
188089857Sobrien/* Called via bfd_map_over_sections.  If SEC is a member of a group,
188189857Sobrien   add it to a list of sections belonging to the group.  INF is a
188289857Sobrien   pointer to a struct group_list, which is where we store the head of
188389857Sobrien   each list.  */
188489857Sobrien
188589857Sobrienstatic void
1886130561Sobrienbuild_group_lists (bfd *abfd ATTRIBUTE_UNUSED, asection *sec, void *inf)
188789857Sobrien{
1888130561Sobrien  struct group_list *list = inf;
188989857Sobrien  const char *group_name = elf_group_name (sec);
189089857Sobrien  unsigned int i;
189189857Sobrien
189289857Sobrien  if (group_name == NULL)
189389857Sobrien    return;
189489857Sobrien
189589857Sobrien  /* If this group already has a list, add the section to the head of
189689857Sobrien     the list.  */
189789857Sobrien  for (i = 0; i < list->num_group; i++)
189889857Sobrien    {
189989857Sobrien      if (strcmp (group_name, elf_group_name (list->head[i])) == 0)
190089857Sobrien	{
190189857Sobrien	  elf_next_in_group (sec) = list->head[i];
190289857Sobrien	  list->head[i] = sec;
190389857Sobrien	  list->elt_count[i] += 1;
190489857Sobrien	  return;
190589857Sobrien	}
190689857Sobrien    }
190789857Sobrien
190889857Sobrien  /* New group.  Make the arrays bigger in chunks to minimize calls to
190989857Sobrien     realloc.  */
191089857Sobrien  i = list->num_group;
191189857Sobrien  if ((i & 127) == 0)
191289857Sobrien    {
191389857Sobrien      unsigned int newsize = i + 128;
191489857Sobrien      list->head = xrealloc (list->head, newsize * sizeof (*list->head));
191589857Sobrien      list->elt_count = xrealloc (list->elt_count,
191689857Sobrien				  newsize * sizeof (*list->elt_count));
191789857Sobrien    }
191889857Sobrien  list->head[i] = sec;
191989857Sobrien  list->elt_count[i] = 1;
192089857Sobrien  list->num_group += 1;
192189857Sobrien}
192289857Sobrien
192333965Sjdpvoid
1924130561Sobrienelf_frob_file (void)
192533965Sjdp{
192689857Sobrien  struct group_list list;
192789857Sobrien  unsigned int i;
192889857Sobrien
1929130561Sobrien  bfd_map_over_sections (stdoutput, adjust_stab_sections, NULL);
193033965Sjdp
193189857Sobrien  /* Go find section groups.  */
193289857Sobrien  list.num_group = 0;
193389857Sobrien  list.head = NULL;
193489857Sobrien  list.elt_count = NULL;
1935130561Sobrien  bfd_map_over_sections (stdoutput, build_group_lists, &list);
193689857Sobrien
193789857Sobrien  /* Make the SHT_GROUP sections that describe each section group.  We
193889857Sobrien     can't set up the section contents here yet, because elf section
193989857Sobrien     indices have yet to be calculated.  elf.c:set_group_contents does
194089857Sobrien     the rest of the work.  */
194189857Sobrien  for (i = 0; i < list.num_group; i++)
194289857Sobrien    {
194389857Sobrien      const char *group_name = elf_group_name (list.head[i]);
1944104834Sobrien      const char *sec_name;
194589857Sobrien      asection *s;
194689857Sobrien      flagword flags;
1947104834Sobrien      struct symbol *sy;
1948104834Sobrien      int has_sym;
1949218822Sdim      bfd_size_type size;
195089857Sobrien
195189857Sobrien      flags = SEC_READONLY | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_GROUP;
1952104834Sobrien      for (s = list.head[i]; s != NULL; s = elf_next_in_group (s))
1953130561Sobrien	if ((s->flags ^ flags) & SEC_LINK_ONCE)
1954104834Sobrien	  {
1955104834Sobrien	    flags |= SEC_LINK_ONCE | SEC_LINK_DUPLICATES_DISCARD;
1956104834Sobrien	    if (s != list.head[i])
1957104834Sobrien	      {
1958104834Sobrien		as_warn (_("assuming all members of group `%s' are COMDAT"),
1959104834Sobrien			 group_name);
1960104834Sobrien		break;
1961104834Sobrien	      }
1962104834Sobrien	  }
1963104834Sobrien
1964104834Sobrien      sec_name = group_name;
1965104834Sobrien      sy = symbol_find_exact (group_name);
1966104834Sobrien      has_sym = 0;
1967104834Sobrien      if (sy != NULL
1968104834Sobrien	  && (sy == symbol_lastP
1969104834Sobrien	      || (sy->sy_next != NULL
1970104834Sobrien		  && sy->sy_next->sy_previous == sy)))
1971104834Sobrien	{
1972104834Sobrien	  has_sym = 1;
1973104834Sobrien	  sec_name = ".group";
1974104834Sobrien	}
1975104834Sobrien      s = subseg_force_new (sec_name, 0);
197689857Sobrien      if (s == NULL
197789857Sobrien	  || !bfd_set_section_flags (stdoutput, s, flags)
197889857Sobrien	  || !bfd_set_section_alignment (stdoutput, s, 2))
197989857Sobrien	{
198089857Sobrien	  as_fatal (_("can't create group: %s"),
198189857Sobrien		    bfd_errmsg (bfd_get_error ()));
198289857Sobrien	}
1983130561Sobrien      elf_section_type (s) = SHT_GROUP;
198489857Sobrien
198589857Sobrien      /* Pass a pointer to the first section in this group.  */
198689857Sobrien      elf_next_in_group (s) = list.head[i];
1987104834Sobrien      if (has_sym)
1988104834Sobrien	elf_group_id (s) = sy->bsym;
198989857Sobrien
1990218822Sdim      size = 4 * (list.elt_count[i] + 1);
1991218822Sdim      bfd_set_section_size (stdoutput, s, size);
1992218822Sdim      s->contents = (unsigned char *) frag_more (size);
199389857Sobrien      frag_now->fr_fix = frag_now_fix_octets ();
1994218822Sdim      frag_wane (frag_now);
199589857Sobrien    }
199689857Sobrien
199733965Sjdp#ifdef elf_tc_final_processing
199833965Sjdp  elf_tc_final_processing ();
199933965Sjdp#endif
200033965Sjdp}
200133965Sjdp
200277298Sobrien/* It removes any unneeded versioned symbols from the symbol table.  */
200377298Sobrien
200477298Sobrienvoid
2005130561Sobrienelf_frob_file_before_adjust (void)
200677298Sobrien{
200777298Sobrien  if (symbol_rootP)
200877298Sobrien    {
200977298Sobrien      symbolS *symp;
201077298Sobrien
201177298Sobrien      for (symp = symbol_rootP; symp; symp = symbol_next (symp))
201291041Sobrien	if (!S_IS_DEFINED (symp))
201377298Sobrien	  {
201491041Sobrien	    if (symbol_get_obj (symp)->versioned_name)
201577298Sobrien	      {
201677298Sobrien		char *p;
201777298Sobrien
201877298Sobrien		/* The @@@ syntax is a special case. If the symbol is
201977298Sobrien		   not defined, 2 `@'s will be removed from the
202077298Sobrien		   versioned_name.  */
202177298Sobrien
202277298Sobrien		p = strchr (symbol_get_obj (symp)->versioned_name,
202377298Sobrien			    ELF_VER_CHR);
202477298Sobrien		know (p != NULL);
2025130561Sobrien		if (p[1] == ELF_VER_CHR && p[2] == ELF_VER_CHR)
202677298Sobrien		  {
202777298Sobrien		    size_t l = strlen (&p[3]) + 1;
2028130561Sobrien		    memmove (&p[1], &p[3], l);
202977298Sobrien		  }
203077298Sobrien		if (symbol_used_p (symp) == 0
203177298Sobrien		    && symbol_used_in_reloc_p (symp) == 0)
203277298Sobrien		  symbol_remove (symp, &symbol_rootP, &symbol_lastP);
203377298Sobrien	      }
203491041Sobrien
203591041Sobrien	    /* If there was .weak foo, but foo was neither defined nor
203691041Sobrien	       used anywhere, remove it.  */
203791041Sobrien
203891041Sobrien	    else if (S_IS_WEAK (symp)
203991041Sobrien		     && symbol_used_p (symp) == 0
204091041Sobrien		     && symbol_used_in_reloc_p (symp) == 0)
204191041Sobrien	      symbol_remove (symp, &symbol_rootP, &symbol_lastP);
204277298Sobrien	  }
204377298Sobrien    }
204477298Sobrien}
204577298Sobrien
204633965Sjdp/* It is required that we let write_relocs have the opportunity to
204733965Sjdp   optimize away fixups before output has begun, since it is possible
204833965Sjdp   to eliminate all fixups for a section and thus we never should
204933965Sjdp   have generated the relocation section.  */
205033965Sjdp
205133965Sjdpvoid
2052130561Sobrienelf_frob_file_after_relocs (void)
205333965Sjdp{
205433965Sjdp#ifdef NEED_ECOFF_DEBUG
205533965Sjdp  if (ECOFF_DEBUGGING)
205633965Sjdp    /* Generate the ECOFF debugging information.  */
205733965Sjdp    {
205833965Sjdp      const struct ecoff_debug_swap *debug_swap;
205933965Sjdp      struct ecoff_debug_info debug;
206033965Sjdp      char *buf;
206133965Sjdp      asection *sec;
206233965Sjdp
206333965Sjdp      debug_swap
206433965Sjdp	= get_elf_backend_data (stdoutput)->elf_backend_ecoff_debug_swap;
2065130561Sobrien      know (debug_swap != NULL);
206633965Sjdp      ecoff_build_debug (&debug.symbolic_header, &buf, debug_swap);
206733965Sjdp
206833965Sjdp      /* Set up the pointers in debug.  */
206933965Sjdp#define SET(ptr, offset, type) \
207033965Sjdp    debug.ptr = (type) (buf + debug.symbolic_header.offset)
207133965Sjdp
207233965Sjdp      SET (line, cbLineOffset, unsigned char *);
2073130561Sobrien      SET (external_dnr, cbDnOffset, void *);
2074130561Sobrien      SET (external_pdr, cbPdOffset, void *);
2075130561Sobrien      SET (external_sym, cbSymOffset, void *);
2076130561Sobrien      SET (external_opt, cbOptOffset, void *);
207733965Sjdp      SET (external_aux, cbAuxOffset, union aux_ext *);
207833965Sjdp      SET (ss, cbSsOffset, char *);
2079130561Sobrien      SET (external_fdr, cbFdOffset, void *);
2080130561Sobrien      SET (external_rfd, cbRfdOffset, void *);
208133965Sjdp      /* ssext and external_ext are set up just below.  */
208233965Sjdp
208333965Sjdp#undef SET
208433965Sjdp
208533965Sjdp      /* Set up the external symbols.  */
208633965Sjdp      debug.ssext = debug.ssext_end = NULL;
208733965Sjdp      debug.external_ext = debug.external_ext_end = NULL;
2088130561Sobrien      if (! bfd_ecoff_debug_externals (stdoutput, &debug, debug_swap, TRUE,
208933965Sjdp				       elf_get_extr, elf_set_index))
209089857Sobrien	as_fatal (_("failed to set up debugging information: %s"),
209133965Sjdp		  bfd_errmsg (bfd_get_error ()));
209233965Sjdp
209333965Sjdp      sec = bfd_get_section_by_name (stdoutput, ".mdebug");
209433965Sjdp      assert (sec != NULL);
209533965Sjdp
2096130561Sobrien      know (!stdoutput->output_has_begun);
209733965Sjdp
209833965Sjdp      /* We set the size of the section, call bfd_set_section_contents
209933965Sjdp	 to force the ELF backend to allocate a file position, and then
210033965Sjdp	 write out the data.  FIXME: Is this really the best way to do
210133965Sjdp	 this?  */
2102218822Sdim      bfd_set_section_size
2103218822Sdim	(stdoutput, sec, bfd_ecoff_debug_size (stdoutput, &debug, debug_swap));
210433965Sjdp
210560484Sobrien      /* Pass BUF to bfd_set_section_contents because this will
2106130561Sobrien	 eventually become a call to fwrite, and ISO C prohibits
2107130561Sobrien	 passing a NULL pointer to a stdio function even if the
2108130561Sobrien	 pointer will not be used.  */
2109130561Sobrien      if (! bfd_set_section_contents (stdoutput, sec, buf, 0, 0))
211089857Sobrien	as_fatal (_("can't start writing .mdebug section: %s"),
211133965Sjdp		  bfd_errmsg (bfd_get_error ()));
211233965Sjdp
2113130561Sobrien      know (stdoutput->output_has_begun);
211433965Sjdp      know (sec->filepos != 0);
211533965Sjdp
211633965Sjdp      if (! bfd_ecoff_write_debug (stdoutput, &debug, debug_swap,
211733965Sjdp				   sec->filepos))
211889857Sobrien	as_fatal (_("could not write .mdebug section: %s"),
211933965Sjdp		  bfd_errmsg (bfd_get_error ()));
212033965Sjdp    }
212133965Sjdp#endif /* NEED_ECOFF_DEBUG */
212233965Sjdp}
212333965Sjdp
212433965Sjdp#ifdef SCO_ELF
212533965Sjdp
2126130561Sobrien/* Heavily plagiarized from obj_elf_version.  The idea is to emit the
212733965Sjdp   SCO specific identifier in the .notes section to satisfy the SCO
212833965Sjdp   linker.
212933965Sjdp
213033965Sjdp   This looks more complicated than it really is.  As opposed to the
213133965Sjdp   "obvious" solution, this should handle the cross dev cases
213233965Sjdp   correctly.  (i.e, hosting on a 64 bit big endian processor, but
213333965Sjdp   generating SCO Elf code) Efficiency isn't a concern, as there
213433965Sjdp   should be exactly one of these sections per object module.
213533965Sjdp
213633965Sjdp   SCO OpenServer 5 identifies it's ELF modules with a standard ELF
213733965Sjdp   .note section.
213833965Sjdp
213960484Sobrien   int_32 namesz  = 4 ;  Name size
214060484Sobrien   int_32 descsz  = 12 ; Descriptive information
214160484Sobrien   int_32 type    = 1 ;
214260484Sobrien   char   name[4] = "SCO" ; Originator name ALWAYS SCO + NULL
214333965Sjdp   int_32 version = (major ver # << 16)  | version of tools ;
214433965Sjdp   int_32 source  = (tool_id << 16 ) | 1 ;
214533965Sjdp   int_32 info    = 0 ;    These are set by the SCO tools, but we
2146130561Sobrien			   don't know enough about the source
214733965Sjdp			   environment to set them.  SCO ld currently
214833965Sjdp			   ignores them, and recommends we set them
214933965Sjdp			   to zero.  */
215033965Sjdp
215133965Sjdp#define SCO_MAJOR_VERSION 0x1
215233965Sjdp#define SCO_MINOR_VERSION 0x1
215333965Sjdp
215433965Sjdpvoid
2155130561Sobriensco_id (void)
215633965Sjdp{
215733965Sjdp
215833965Sjdp  char *name;
215933965Sjdp  unsigned int c;
216033965Sjdp  char ch;
216133965Sjdp  char *p;
216233965Sjdp  asection *seg = now_seg;
216333965Sjdp  subsegT subseg = now_subseg;
216433965Sjdp  Elf_Internal_Note i_note;
216533965Sjdp  Elf_External_Note e_note;
2166130561Sobrien  asection *note_secp = NULL;
216733965Sjdp  int i, len;
216833965Sjdp
216933965Sjdp  /* create the .note section */
217033965Sjdp
217133965Sjdp  note_secp = subseg_new (".note", 0);
217233965Sjdp  bfd_set_section_flags (stdoutput,
217333965Sjdp			 note_secp,
217433965Sjdp			 SEC_HAS_CONTENTS | SEC_READONLY);
217533965Sjdp
217633965Sjdp  /* process the version string */
217733965Sjdp
217860484Sobrien  i_note.namesz = 4;
217933965Sjdp  i_note.descsz = 12;		/* 12 descriptive bytes */
218033965Sjdp  i_note.type = NT_VERSION;	/* Contains a version string */
218133965Sjdp
218233965Sjdp  p = frag_more (sizeof (i_note.namesz));
2183130561Sobrien  md_number_to_chars (p, i_note.namesz, 4);
218433965Sjdp
218533965Sjdp  p = frag_more (sizeof (i_note.descsz));
2186130561Sobrien  md_number_to_chars (p, i_note.descsz, 4);
218733965Sjdp
218833965Sjdp  p = frag_more (sizeof (i_note.type));
2189130561Sobrien  md_number_to_chars (p, i_note.type, 4);
219033965Sjdp
219133965Sjdp  p = frag_more (4);
219260484Sobrien  strcpy (p, "SCO");
219333965Sjdp
219433965Sjdp  /* Note: this is the version number of the ELF we're representing */
219533965Sjdp  p = frag_more (4);
219633965Sjdp  md_number_to_chars (p, (SCO_MAJOR_VERSION << 16) | (SCO_MINOR_VERSION), 4);
219733965Sjdp
219833965Sjdp  /* Here, we pick a magic number for ourselves (yes, I "registered"
219933965Sjdp     it with SCO.  The bottom bit shows that we are compat with the
220033965Sjdp     SCO ABI.  */
220133965Sjdp  p = frag_more (4);
220233965Sjdp  md_number_to_chars (p, 0x4c520000 | 0x0001, 4);
220333965Sjdp
220433965Sjdp  /* If we knew (or cared) what the source language options were, we'd
220533965Sjdp     fill them in here.  SCO has given us permission to ignore these
220633965Sjdp     and just set them to zero.  */
220733965Sjdp  p = frag_more (4);
220833965Sjdp  md_number_to_chars (p, 0x0000, 4);
220960484Sobrien
221033965Sjdp  frag_align (2, 0, 0);
221133965Sjdp
221233965Sjdp  /* We probably can't restore the current segment, for there likely
221333965Sjdp     isn't one yet...  */
221433965Sjdp  if (seg && subseg)
221533965Sjdp    subseg_set (seg, subseg);
221633965Sjdp
221733965Sjdp}
221833965Sjdp
221933965Sjdp#endif /* SCO_ELF */
222033965Sjdp
222177298Sobrienstatic int
2222130561Sobrienelf_separate_stab_sections (void)
222377298Sobrien{
222477298Sobrien#ifdef NEED_ECOFF_DEBUG
222577298Sobrien  return (!ECOFF_DEBUGGING);
222677298Sobrien#else
222777298Sobrien  return 1;
222877298Sobrien#endif
222977298Sobrien}
223077298Sobrien
223177298Sobrienstatic void
2232130561Sobrienelf_init_stab_section (segT seg)
223377298Sobrien{
223477298Sobrien#ifdef NEED_ECOFF_DEBUG
223577298Sobrien  if (!ECOFF_DEBUGGING)
223677298Sobrien#endif
223777298Sobrien    obj_elf_init_stab_section (seg);
223877298Sobrien}
223977298Sobrien
224033965Sjdpconst struct format_ops elf_format_ops =
224133965Sjdp{
224233965Sjdp  bfd_target_elf_flavour,
224360484Sobrien  0,	/* dfl_leading_underscore */
224460484Sobrien  1,	/* emit_section_symbols */
224577298Sobrien  elf_begin,
224677298Sobrien  elf_file_symbol,
224733965Sjdp  elf_frob_symbol,
224833965Sjdp  elf_frob_file,
224977298Sobrien  elf_frob_file_before_adjust,
2250130561Sobrien  0,	/* obj_frob_file_before_fix */
225133965Sjdp  elf_frob_file_after_relocs,
225233965Sjdp  elf_s_get_size, elf_s_set_size,
225333965Sjdp  elf_s_get_align, elf_s_set_align,
225460484Sobrien  elf_s_get_other,
225577298Sobrien  elf_s_set_other,
225660484Sobrien  0,	/* s_get_desc */
225777298Sobrien  0,	/* s_set_desc */
225877298Sobrien  0,	/* s_get_type */
225977298Sobrien  0,	/* s_set_type */
226033965Sjdp  elf_copy_symbol_attributes,
226133965Sjdp#ifdef NEED_ECOFF_DEBUG
226233965Sjdp  ecoff_generate_asm_lineno,
226333965Sjdp  ecoff_stab,
226433965Sjdp#else
226560484Sobrien  0,	/* generate_asm_lineno */
226660484Sobrien  0,	/* process_stab */
226733965Sjdp#endif
226877298Sobrien  elf_separate_stab_sections,
226977298Sobrien  elf_init_stab_section,
227033965Sjdp  elf_sec_sym_ok_for_reloc,
227133965Sjdp  elf_pop_insert,
227233965Sjdp#ifdef NEED_ECOFF_DEBUG
227333965Sjdp  elf_ecoff_set_ext,
227433965Sjdp#else
227560484Sobrien  0,	/* ecoff_set_ext */
227633965Sjdp#endif
227760484Sobrien  elf_obj_read_begin_hook,
227877298Sobrien  elf_obj_symbol_new_hook
227933965Sjdp};
2280