sunos.c revision 130561
159024Sobrien/* BFD backend for SunOS binaries.
289857Sobrien   Copyright 1990, 1991, 1992, 1994, 1995, 1996, 1997, 1998, 2000, 2001,
3130561Sobrien   2002, 2003 Free Software Foundation, Inc.
459024Sobrien   Written by Cygnus Support.
559024Sobrien
659024SobrienThis file is part of BFD, the Binary File Descriptor library.
759024Sobrien
859024SobrienThis program is free software; you can redistribute it and/or modify
959024Sobrienit under the terms of the GNU General Public License as published by
1059024Sobrienthe Free Software Foundation; either version 2 of the License, or
1159024Sobrien(at your option) any later version.
1259024Sobrien
1359024SobrienThis program is distributed in the hope that it will be useful,
1459024Sobrienbut WITHOUT ANY WARRANTY; without even the implied warranty of
1559024SobrienMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1659024SobrienGNU General Public License for more details.
1759024Sobrien
1859024SobrienYou should have received a copy of the GNU General Public License
1959024Sobrienalong with this program; if not, write to the Free Software
2059024SobrienFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
2159024Sobrien
2259024Sobrien#define TARGETNAME "a.out-sunos-big"
2359024Sobrien
2489857Sobrien/* Do not "beautify" the CONCAT* macro args.  Traditional C will not
2589857Sobrien   remove whitespace added here, and thus will fail to concatenate
2689857Sobrien   the tokens.  */
2789857Sobrien#define MY(OP) CONCAT2 (sunos_big_,OP)
2889857Sobrien
2959024Sobrien#include "bfd.h"
3059024Sobrien#include "bfdlink.h"
3159024Sobrien#include "libaout.h"
3259024Sobrien
3359024Sobrien/* Static routines defined in this file.  */
3459024Sobrien
35130561Sobrienstatic bfd_boolean sunos_read_dynamic_info PARAMS ((bfd *));
3659024Sobrienstatic long sunos_get_dynamic_symtab_upper_bound PARAMS ((bfd *));
37130561Sobrienstatic bfd_boolean sunos_slurp_dynamic_symtab PARAMS ((bfd *));
3859024Sobrienstatic long sunos_canonicalize_dynamic_symtab PARAMS ((bfd *, asymbol **));
3959024Sobrienstatic long sunos_get_dynamic_reloc_upper_bound PARAMS ((bfd *));
4059024Sobrienstatic long sunos_canonicalize_dynamic_reloc
4159024Sobrien  PARAMS ((bfd *, arelent **, asymbol **));
4259024Sobrienstatic struct bfd_hash_entry *sunos_link_hash_newfunc
4359024Sobrien  PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, const char *));
4459024Sobrienstatic struct bfd_link_hash_table *sunos_link_hash_table_create
4559024Sobrien  PARAMS ((bfd *));
46130561Sobrienstatic bfd_boolean sunos_create_dynamic_sections
47130561Sobrien  PARAMS ((bfd *, struct bfd_link_info *, bfd_boolean));
48130561Sobrienstatic bfd_boolean sunos_add_dynamic_symbols
4959024Sobrien  PARAMS ((bfd *, struct bfd_link_info *, struct external_nlist **,
5059024Sobrien	   bfd_size_type *, char **));
51130561Sobrienstatic bfd_boolean sunos_add_one_symbol
5259024Sobrien  PARAMS ((struct bfd_link_info *, bfd *, const char *, flagword, asection *,
53130561Sobrien	   bfd_vma, const char *, bfd_boolean, bfd_boolean,
5459024Sobrien	   struct bfd_link_hash_entry **));
55130561Sobrienstatic bfd_boolean sunos_scan_relocs
5659024Sobrien  PARAMS ((struct bfd_link_info *, bfd *, asection *, bfd_size_type));
57130561Sobrienstatic bfd_boolean sunos_scan_std_relocs
5859024Sobrien  PARAMS ((struct bfd_link_info *, bfd *, asection *,
5959024Sobrien	   const struct reloc_std_external *, bfd_size_type));
60130561Sobrienstatic bfd_boolean sunos_scan_ext_relocs
6159024Sobrien  PARAMS ((struct bfd_link_info *, bfd *, asection *,
6259024Sobrien	   const struct reloc_ext_external *, bfd_size_type));
63130561Sobrienstatic bfd_boolean sunos_link_dynamic_object
6459024Sobrien  PARAMS ((struct bfd_link_info *, bfd *));
65130561Sobrienstatic bfd_boolean sunos_write_dynamic_symbol
6659024Sobrien  PARAMS ((bfd *, struct bfd_link_info *, struct aout_link_hash_entry *));
67130561Sobrienstatic bfd_boolean sunos_check_dynamic_reloc
6859024Sobrien  PARAMS ((struct bfd_link_info *, bfd *, asection *,
69130561Sobrien	   struct aout_link_hash_entry *, PTR, bfd_byte *, bfd_boolean *,
7059024Sobrien	   bfd_vma *));
71130561Sobrienstatic bfd_boolean sunos_finish_dynamic_link
7259024Sobrien  PARAMS ((bfd *, struct bfd_link_info *));
7359024Sobrien
7459024Sobrien#define MY_get_dynamic_symtab_upper_bound sunos_get_dynamic_symtab_upper_bound
7559024Sobrien#define MY_canonicalize_dynamic_symtab sunos_canonicalize_dynamic_symtab
7659024Sobrien#define MY_get_dynamic_reloc_upper_bound sunos_get_dynamic_reloc_upper_bound
7759024Sobrien#define MY_canonicalize_dynamic_reloc sunos_canonicalize_dynamic_reloc
7859024Sobrien#define MY_bfd_link_hash_table_create sunos_link_hash_table_create
7959024Sobrien#define MY_add_dynamic_symbols sunos_add_dynamic_symbols
8059024Sobrien#define MY_add_one_symbol sunos_add_one_symbol
8159024Sobrien#define MY_link_dynamic_object sunos_link_dynamic_object
8259024Sobrien#define MY_write_dynamic_symbol sunos_write_dynamic_symbol
8359024Sobrien#define MY_check_dynamic_reloc sunos_check_dynamic_reloc
8459024Sobrien#define MY_finish_dynamic_link sunos_finish_dynamic_link
8559024Sobrien
8659024Sobrien/* ??? Where should this go?  */
8759024Sobrien#define MACHTYPE_OK(mtype) \
8859024Sobrien  (((mtype) == M_SPARC && bfd_lookup_arch (bfd_arch_sparc, 0) != NULL) \
8959024Sobrien   || ((mtype) == M_SPARCLET \
9059024Sobrien       && bfd_lookup_arch (bfd_arch_sparc, bfd_mach_sparc_sparclet) != NULL) \
9184865Sobrien   || ((mtype) == M_SPARCLITE_LE \
9284865Sobrien       && bfd_lookup_arch (bfd_arch_sparc, bfd_mach_sparc_sparclet) != NULL) \
9359024Sobrien   || (((mtype) == M_UNKNOWN || (mtype) == M_68010 || (mtype) == M_68020) \
9459024Sobrien       && bfd_lookup_arch (bfd_arch_m68k, 0) != NULL))
9559024Sobrien
9659024Sobrien/* Include the usual a.out support.  */
9759024Sobrien#include "aoutf1.h"
9859024Sobrien
9984865Sobrien/* The SunOS 4.1.4 /usr/include/locale.h defines valid as a macro.  */
10084865Sobrien#undef valid
10184865Sobrien
10259024Sobrien/* SunOS shared library support.  We store a pointer to this structure
10359024Sobrien   in obj_aout_dynamic_info (abfd).  */
10459024Sobrien
10559024Sobrienstruct sunos_dynamic_info
10659024Sobrien{
10759024Sobrien  /* Whether we found any dynamic information.  */
108130561Sobrien  bfd_boolean valid;
10959024Sobrien  /* Dynamic information.  */
11059024Sobrien  struct internal_sun4_dynamic_link dyninfo;
11159024Sobrien  /* Number of dynamic symbols.  */
11259024Sobrien  unsigned long dynsym_count;
11359024Sobrien  /* Read in nlists for dynamic symbols.  */
11459024Sobrien  struct external_nlist *dynsym;
11559024Sobrien  /* asymbol structures for dynamic symbols.  */
11659024Sobrien  aout_symbol_type *canonical_dynsym;
11759024Sobrien  /* Read in dynamic string table.  */
11859024Sobrien  char *dynstr;
11959024Sobrien  /* Number of dynamic relocs.  */
12059024Sobrien  unsigned long dynrel_count;
12159024Sobrien  /* Read in dynamic relocs.  This may be reloc_std_external or
12259024Sobrien     reloc_ext_external.  */
12359024Sobrien  PTR dynrel;
12459024Sobrien  /* arelent structures for dynamic relocs.  */
12559024Sobrien  arelent *canonical_dynrel;
12659024Sobrien};
12759024Sobrien
12859024Sobrien/* The hash table of dynamic symbols is composed of two word entries.
12959024Sobrien   See include/aout/sun4.h for details.  */
13059024Sobrien
13159024Sobrien#define HASH_ENTRY_SIZE (2 * BYTES_IN_WORD)
13259024Sobrien
13359024Sobrien/* Read in the basic dynamic information.  This locates the __DYNAMIC
13459024Sobrien   structure and uses it to find the dynamic_link structure.  It
13559024Sobrien   creates and saves a sunos_dynamic_info structure.  If it can't find
13659024Sobrien   __DYNAMIC, it sets the valid field of the sunos_dynamic_info
137130561Sobrien   structure to FALSE to avoid doing this work again.  */
13859024Sobrien
139130561Sobrienstatic bfd_boolean
14059024Sobriensunos_read_dynamic_info (abfd)
14159024Sobrien     bfd *abfd;
14259024Sobrien{
14359024Sobrien  struct sunos_dynamic_info *info;
14459024Sobrien  asection *dynsec;
14559024Sobrien  bfd_vma dynoff;
14659024Sobrien  struct external_sun4_dynamic dyninfo;
14759024Sobrien  unsigned long dynver;
14859024Sobrien  struct external_sun4_dynamic_link linkinfo;
14989857Sobrien  bfd_size_type amt;
15059024Sobrien
15159024Sobrien  if (obj_aout_dynamic_info (abfd) != (PTR) NULL)
152130561Sobrien    return TRUE;
15359024Sobrien
15459024Sobrien  if ((abfd->flags & DYNAMIC) == 0)
15559024Sobrien    {
15659024Sobrien      bfd_set_error (bfd_error_invalid_operation);
157130561Sobrien      return FALSE;
15859024Sobrien    }
15959024Sobrien
16089857Sobrien  amt = sizeof (struct sunos_dynamic_info);
16189857Sobrien  info = (struct sunos_dynamic_info *) bfd_zalloc (abfd, amt);
16259024Sobrien  if (!info)
163130561Sobrien    return FALSE;
164130561Sobrien  info->valid = FALSE;
16559024Sobrien  info->dynsym = NULL;
16659024Sobrien  info->dynstr = NULL;
16759024Sobrien  info->canonical_dynsym = NULL;
16859024Sobrien  info->dynrel = NULL;
16959024Sobrien  info->canonical_dynrel = NULL;
17059024Sobrien  obj_aout_dynamic_info (abfd) = (PTR) info;
17159024Sobrien
17259024Sobrien  /* This code used to look for the __DYNAMIC symbol to locate the dynamic
17359024Sobrien     linking information.
17459024Sobrien     However this inhibits recovering the dynamic symbols from a
17559024Sobrien     stripped object file, so blindly assume that the dynamic linking
17659024Sobrien     information is located at the start of the data section.
17759024Sobrien     We could verify this assumption later by looking through the dynamic
17859024Sobrien     symbols for the __DYNAMIC symbol.  */
17959024Sobrien  if ((abfd->flags & DYNAMIC) == 0)
180130561Sobrien    return TRUE;
18159024Sobrien  if (! bfd_get_section_contents (abfd, obj_datasec (abfd), (PTR) &dyninfo,
18289857Sobrien				  (file_ptr) 0,
18389857Sobrien				  (bfd_size_type) sizeof dyninfo))
184130561Sobrien    return TRUE;
18559024Sobrien
18659024Sobrien  dynver = GET_WORD (abfd, dyninfo.ld_version);
18759024Sobrien  if (dynver != 2 && dynver != 3)
188130561Sobrien    return TRUE;
18959024Sobrien
19059024Sobrien  dynoff = GET_WORD (abfd, dyninfo.ld);
19159024Sobrien
19259024Sobrien  /* dynoff is a virtual address.  It is probably always in the .data
19359024Sobrien     section, but this code should work even if it moves.  */
19459024Sobrien  if (dynoff < bfd_get_section_vma (abfd, obj_datasec (abfd)))
19559024Sobrien    dynsec = obj_textsec (abfd);
19659024Sobrien  else
19759024Sobrien    dynsec = obj_datasec (abfd);
19859024Sobrien  dynoff -= bfd_get_section_vma (abfd, dynsec);
19959024Sobrien  if (dynoff > bfd_section_size (abfd, dynsec))
200130561Sobrien    return TRUE;
20159024Sobrien
20259024Sobrien  /* This executable appears to be dynamically linked in a way that we
20359024Sobrien     can understand.  */
20489857Sobrien  if (! bfd_get_section_contents (abfd, dynsec, (PTR) &linkinfo,
20589857Sobrien				  (file_ptr) dynoff,
20659024Sobrien				  (bfd_size_type) sizeof linkinfo))
207130561Sobrien    return TRUE;
20859024Sobrien
20959024Sobrien  /* Swap in the dynamic link information.  */
21059024Sobrien  info->dyninfo.ld_loaded = GET_WORD (abfd, linkinfo.ld_loaded);
21159024Sobrien  info->dyninfo.ld_need = GET_WORD (abfd, linkinfo.ld_need);
21259024Sobrien  info->dyninfo.ld_rules = GET_WORD (abfd, linkinfo.ld_rules);
21359024Sobrien  info->dyninfo.ld_got = GET_WORD (abfd, linkinfo.ld_got);
21459024Sobrien  info->dyninfo.ld_plt = GET_WORD (abfd, linkinfo.ld_plt);
21559024Sobrien  info->dyninfo.ld_rel = GET_WORD (abfd, linkinfo.ld_rel);
21659024Sobrien  info->dyninfo.ld_hash = GET_WORD (abfd, linkinfo.ld_hash);
21759024Sobrien  info->dyninfo.ld_stab = GET_WORD (abfd, linkinfo.ld_stab);
21859024Sobrien  info->dyninfo.ld_stab_hash = GET_WORD (abfd, linkinfo.ld_stab_hash);
21959024Sobrien  info->dyninfo.ld_buckets = GET_WORD (abfd, linkinfo.ld_buckets);
22059024Sobrien  info->dyninfo.ld_symbols = GET_WORD (abfd, linkinfo.ld_symbols);
22159024Sobrien  info->dyninfo.ld_symb_size = GET_WORD (abfd, linkinfo.ld_symb_size);
22259024Sobrien  info->dyninfo.ld_text = GET_WORD (abfd, linkinfo.ld_text);
22359024Sobrien  info->dyninfo.ld_plt_sz = GET_WORD (abfd, linkinfo.ld_plt_sz);
22459024Sobrien
22559024Sobrien  /* Reportedly the addresses need to be offset by the size of the
22659024Sobrien     exec header in an NMAGIC file.  */
22759024Sobrien  if (adata (abfd).magic == n_magic)
22859024Sobrien    {
22959024Sobrien      unsigned long exec_bytes_size = adata (abfd).exec_bytes_size;
23059024Sobrien
23159024Sobrien      info->dyninfo.ld_need += exec_bytes_size;
23259024Sobrien      info->dyninfo.ld_rules += exec_bytes_size;
23359024Sobrien      info->dyninfo.ld_rel += exec_bytes_size;
23459024Sobrien      info->dyninfo.ld_hash += exec_bytes_size;
23559024Sobrien      info->dyninfo.ld_stab += exec_bytes_size;
23659024Sobrien      info->dyninfo.ld_symbols += exec_bytes_size;
23759024Sobrien    }
23859024Sobrien
23959024Sobrien  /* The only way to get the size of the symbol information appears to
24059024Sobrien     be to determine the distance between it and the string table.  */
24159024Sobrien  info->dynsym_count = ((info->dyninfo.ld_symbols - info->dyninfo.ld_stab)
24259024Sobrien			/ EXTERNAL_NLIST_SIZE);
24359024Sobrien  BFD_ASSERT (info->dynsym_count * EXTERNAL_NLIST_SIZE
24459024Sobrien	      == (unsigned long) (info->dyninfo.ld_symbols
24559024Sobrien				  - info->dyninfo.ld_stab));
24659024Sobrien
24759024Sobrien  /* Similarly, the relocs end at the hash table.  */
24859024Sobrien  info->dynrel_count = ((info->dyninfo.ld_hash - info->dyninfo.ld_rel)
24959024Sobrien			/ obj_reloc_entry_size (abfd));
25059024Sobrien  BFD_ASSERT (info->dynrel_count * obj_reloc_entry_size (abfd)
25159024Sobrien	      == (unsigned long) (info->dyninfo.ld_hash
25259024Sobrien				  - info->dyninfo.ld_rel));
25359024Sobrien
254130561Sobrien  info->valid = TRUE;
25559024Sobrien
256130561Sobrien  return TRUE;
25759024Sobrien}
25859024Sobrien
25959024Sobrien/* Return the amount of memory required for the dynamic symbols.  */
26059024Sobrien
26159024Sobrienstatic long
26259024Sobriensunos_get_dynamic_symtab_upper_bound (abfd)
26359024Sobrien     bfd *abfd;
26459024Sobrien{
26559024Sobrien  struct sunos_dynamic_info *info;
26659024Sobrien
26759024Sobrien  if (! sunos_read_dynamic_info (abfd))
26859024Sobrien    return -1;
26959024Sobrien
27059024Sobrien  info = (struct sunos_dynamic_info *) obj_aout_dynamic_info (abfd);
27159024Sobrien  if (! info->valid)
27259024Sobrien    {
27359024Sobrien      bfd_set_error (bfd_error_no_symbols);
27459024Sobrien      return -1;
27559024Sobrien    }
27659024Sobrien
27759024Sobrien  return (info->dynsym_count + 1) * sizeof (asymbol *);
27859024Sobrien}
27959024Sobrien
28059024Sobrien/* Read the external dynamic symbols.  */
28159024Sobrien
282130561Sobrienstatic bfd_boolean
28359024Sobriensunos_slurp_dynamic_symtab (abfd)
28459024Sobrien     bfd *abfd;
28559024Sobrien{
28659024Sobrien  struct sunos_dynamic_info *info;
28789857Sobrien  bfd_size_type amt;
28859024Sobrien
28959024Sobrien  /* Get the general dynamic information.  */
29059024Sobrien  if (obj_aout_dynamic_info (abfd) == NULL)
29159024Sobrien    {
29259024Sobrien      if (! sunos_read_dynamic_info (abfd))
293130561Sobrien	  return FALSE;
29459024Sobrien    }
29559024Sobrien
29659024Sobrien  info = (struct sunos_dynamic_info *) obj_aout_dynamic_info (abfd);
29759024Sobrien  if (! info->valid)
29859024Sobrien    {
29959024Sobrien      bfd_set_error (bfd_error_no_symbols);
300130561Sobrien      return FALSE;
30159024Sobrien    }
30259024Sobrien
30359024Sobrien  /* Get the dynamic nlist structures.  */
30459024Sobrien  if (info->dynsym == (struct external_nlist *) NULL)
30559024Sobrien    {
30689857Sobrien      amt = (bfd_size_type) info->dynsym_count * EXTERNAL_NLIST_SIZE;
30789857Sobrien      info->dynsym = (struct external_nlist *) bfd_alloc (abfd, amt);
30859024Sobrien      if (info->dynsym == NULL && info->dynsym_count != 0)
309130561Sobrien	return FALSE;
31089857Sobrien      if (bfd_seek (abfd, (file_ptr) info->dyninfo.ld_stab, SEEK_SET) != 0
31189857Sobrien	  || bfd_bread ((PTR) info->dynsym, amt, abfd) != amt)
31259024Sobrien	{
31359024Sobrien	  if (info->dynsym != NULL)
31459024Sobrien	    {
31559024Sobrien	      bfd_release (abfd, info->dynsym);
31659024Sobrien	      info->dynsym = NULL;
31759024Sobrien	    }
318130561Sobrien	  return FALSE;
31959024Sobrien	}
32059024Sobrien    }
32159024Sobrien
32259024Sobrien  /* Get the dynamic strings.  */
32359024Sobrien  if (info->dynstr == (char *) NULL)
32459024Sobrien    {
32589857Sobrien      amt = info->dyninfo.ld_symb_size;
32689857Sobrien      info->dynstr = (char *) bfd_alloc (abfd, amt);
32759024Sobrien      if (info->dynstr == NULL && info->dyninfo.ld_symb_size != 0)
328130561Sobrien	return FALSE;
32989857Sobrien      if (bfd_seek (abfd, (file_ptr) info->dyninfo.ld_symbols, SEEK_SET) != 0
33089857Sobrien	  || bfd_bread ((PTR) info->dynstr, amt, abfd) != amt)
33159024Sobrien	{
33259024Sobrien	  if (info->dynstr != NULL)
33359024Sobrien	    {
33459024Sobrien	      bfd_release (abfd, info->dynstr);
33559024Sobrien	      info->dynstr = NULL;
33659024Sobrien	    }
337130561Sobrien	  return FALSE;
33859024Sobrien	}
33959024Sobrien    }
34059024Sobrien
341130561Sobrien  return TRUE;
34259024Sobrien}
34359024Sobrien
34459024Sobrien/* Read in the dynamic symbols.  */
34559024Sobrien
34659024Sobrienstatic long
34759024Sobriensunos_canonicalize_dynamic_symtab (abfd, storage)
34859024Sobrien     bfd *abfd;
34959024Sobrien     asymbol **storage;
35059024Sobrien{
35159024Sobrien  struct sunos_dynamic_info *info;
35259024Sobrien  unsigned long i;
35359024Sobrien
35459024Sobrien  if (! sunos_slurp_dynamic_symtab (abfd))
35559024Sobrien    return -1;
35659024Sobrien
35759024Sobrien  info = (struct sunos_dynamic_info *) obj_aout_dynamic_info (abfd);
35859024Sobrien
35959024Sobrien#ifdef CHECK_DYNAMIC_HASH
36059024Sobrien  /* Check my understanding of the dynamic hash table by making sure
36159024Sobrien     that each symbol can be located in the hash table.  */
36259024Sobrien  {
36359024Sobrien    bfd_size_type table_size;
36459024Sobrien    bfd_byte *table;
36559024Sobrien    bfd_size_type i;
36659024Sobrien
36759024Sobrien    if (info->dyninfo.ld_buckets > info->dynsym_count)
36859024Sobrien      abort ();
36959024Sobrien    table_size = info->dyninfo.ld_stab - info->dyninfo.ld_hash;
37059024Sobrien    table = (bfd_byte *) bfd_malloc (table_size);
37159024Sobrien    if (table == NULL && table_size != 0)
37259024Sobrien      abort ();
37389857Sobrien    if (bfd_seek (abfd, (file_ptr) info->dyninfo.ld_hash, SEEK_SET) != 0
37489857Sobrien	|| bfd_bread ((PTR) table, table_size, abfd) != table_size)
37559024Sobrien      abort ();
37659024Sobrien    for (i = 0; i < info->dynsym_count; i++)
37759024Sobrien      {
37859024Sobrien	unsigned char *name;
37959024Sobrien	unsigned long hash;
38059024Sobrien
38159024Sobrien	name = ((unsigned char *) info->dynstr
38259024Sobrien		+ GET_WORD (abfd, info->dynsym[i].e_strx));
38359024Sobrien	hash = 0;
38459024Sobrien	while (*name != '\0')
38559024Sobrien	  hash = (hash << 1) + *name++;
38659024Sobrien	hash &= 0x7fffffff;
38759024Sobrien	hash %= info->dyninfo.ld_buckets;
38859024Sobrien	while (GET_WORD (abfd, table + hash * HASH_ENTRY_SIZE) != i)
38959024Sobrien	  {
39059024Sobrien	    hash = GET_WORD (abfd,
39159024Sobrien			     table + hash * HASH_ENTRY_SIZE + BYTES_IN_WORD);
39259024Sobrien	    if (hash == 0 || hash >= table_size / HASH_ENTRY_SIZE)
39359024Sobrien	      abort ();
39459024Sobrien	  }
39559024Sobrien      }
39659024Sobrien    free (table);
39759024Sobrien  }
39859024Sobrien#endif /* CHECK_DYNAMIC_HASH */
39959024Sobrien
40059024Sobrien  /* Get the asymbol structures corresponding to the dynamic nlist
40159024Sobrien     structures.  */
40259024Sobrien  if (info->canonical_dynsym == (aout_symbol_type *) NULL)
40359024Sobrien    {
40489857Sobrien      bfd_size_type size;
40589857Sobrien      bfd_size_type strsize = info->dyninfo.ld_symb_size;
40689857Sobrien
40789857Sobrien      size = (bfd_size_type) info->dynsym_count * sizeof (aout_symbol_type);
40889857Sobrien      info->canonical_dynsym = (aout_symbol_type *) bfd_alloc (abfd, size);
40959024Sobrien      if (info->canonical_dynsym == NULL && info->dynsym_count != 0)
41059024Sobrien	return -1;
41159024Sobrien
41259024Sobrien      if (! aout_32_translate_symbol_table (abfd, info->canonical_dynsym,
41389857Sobrien					    info->dynsym,
41489857Sobrien					    (bfd_size_type) info->dynsym_count,
415130561Sobrien					    info->dynstr, strsize, TRUE))
41659024Sobrien	{
41759024Sobrien	  if (info->canonical_dynsym != NULL)
41859024Sobrien	    {
41959024Sobrien	      bfd_release (abfd, info->canonical_dynsym);
42059024Sobrien	      info->canonical_dynsym = NULL;
42159024Sobrien	    }
42259024Sobrien	  return -1;
42359024Sobrien	}
42459024Sobrien    }
42559024Sobrien
42659024Sobrien  /* Return pointers to the dynamic asymbol structures.  */
42759024Sobrien  for (i = 0; i < info->dynsym_count; i++)
42859024Sobrien    *storage++ = (asymbol *) (info->canonical_dynsym + i);
42959024Sobrien  *storage = NULL;
43059024Sobrien
43159024Sobrien  return info->dynsym_count;
43259024Sobrien}
43359024Sobrien
43459024Sobrien/* Return the amount of memory required for the dynamic relocs.  */
43559024Sobrien
43659024Sobrienstatic long
43759024Sobriensunos_get_dynamic_reloc_upper_bound (abfd)
43859024Sobrien     bfd *abfd;
43959024Sobrien{
44059024Sobrien  struct sunos_dynamic_info *info;
44159024Sobrien
44259024Sobrien  if (! sunos_read_dynamic_info (abfd))
44359024Sobrien    return -1;
44459024Sobrien
44559024Sobrien  info = (struct sunos_dynamic_info *) obj_aout_dynamic_info (abfd);
44659024Sobrien  if (! info->valid)
44759024Sobrien    {
44859024Sobrien      bfd_set_error (bfd_error_no_symbols);
44959024Sobrien      return -1;
45059024Sobrien    }
45159024Sobrien
45259024Sobrien  return (info->dynrel_count + 1) * sizeof (arelent *);
45359024Sobrien}
45459024Sobrien
45559024Sobrien/* Read in the dynamic relocs.  */
45659024Sobrien
45759024Sobrienstatic long
45859024Sobriensunos_canonicalize_dynamic_reloc (abfd, storage, syms)
45959024Sobrien     bfd *abfd;
46059024Sobrien     arelent **storage;
46159024Sobrien     asymbol **syms;
46259024Sobrien{
46359024Sobrien  struct sunos_dynamic_info *info;
46459024Sobrien  unsigned long i;
46589857Sobrien  bfd_size_type size;
46659024Sobrien
46759024Sobrien  /* Get the general dynamic information.  */
46859024Sobrien  if (obj_aout_dynamic_info (abfd) == (PTR) NULL)
46959024Sobrien    {
47059024Sobrien      if (! sunos_read_dynamic_info (abfd))
47159024Sobrien	return -1;
47259024Sobrien    }
47359024Sobrien
47459024Sobrien  info = (struct sunos_dynamic_info *) obj_aout_dynamic_info (abfd);
47559024Sobrien  if (! info->valid)
47659024Sobrien    {
47759024Sobrien      bfd_set_error (bfd_error_no_symbols);
47859024Sobrien      return -1;
47959024Sobrien    }
48059024Sobrien
48159024Sobrien  /* Get the dynamic reloc information.  */
48259024Sobrien  if (info->dynrel == NULL)
48359024Sobrien    {
48489857Sobrien      size = (bfd_size_type) info->dynrel_count * obj_reloc_entry_size (abfd);
48589857Sobrien      info->dynrel = (PTR) bfd_alloc (abfd, size);
48689857Sobrien      if (info->dynrel == NULL && size != 0)
48759024Sobrien	return -1;
48889857Sobrien      if (bfd_seek (abfd, (file_ptr) info->dyninfo.ld_rel, SEEK_SET) != 0
48989857Sobrien	  || bfd_bread ((PTR) info->dynrel, size, abfd) != size)
49059024Sobrien	{
49159024Sobrien	  if (info->dynrel != NULL)
49259024Sobrien	    {
49359024Sobrien	      bfd_release (abfd, info->dynrel);
49459024Sobrien	      info->dynrel = NULL;
49559024Sobrien	    }
49659024Sobrien	  return -1;
49759024Sobrien	}
49859024Sobrien    }
49959024Sobrien
50059024Sobrien  /* Get the arelent structures corresponding to the dynamic reloc
50159024Sobrien     information.  */
50259024Sobrien  if (info->canonical_dynrel == (arelent *) NULL)
50359024Sobrien    {
50459024Sobrien      arelent *to;
50559024Sobrien
50689857Sobrien      size = (bfd_size_type) info->dynrel_count * sizeof (arelent);
50789857Sobrien      info->canonical_dynrel = (arelent *) bfd_alloc (abfd, size);
50859024Sobrien      if (info->canonical_dynrel == NULL && info->dynrel_count != 0)
50959024Sobrien	return -1;
51084865Sobrien
51159024Sobrien      to = info->canonical_dynrel;
51259024Sobrien
51359024Sobrien      if (obj_reloc_entry_size (abfd) == RELOC_EXT_SIZE)
51459024Sobrien	{
51559024Sobrien	  register struct reloc_ext_external *p;
51659024Sobrien	  struct reloc_ext_external *pend;
51759024Sobrien
51859024Sobrien	  p = (struct reloc_ext_external *) info->dynrel;
51959024Sobrien	  pend = p + info->dynrel_count;
52059024Sobrien	  for (; p < pend; p++, to++)
52159024Sobrien	    NAME(aout,swap_ext_reloc_in) (abfd, p, to, syms,
52289857Sobrien					  (bfd_size_type) info->dynsym_count);
52359024Sobrien	}
52459024Sobrien      else
52559024Sobrien	{
52659024Sobrien	  register struct reloc_std_external *p;
52759024Sobrien	  struct reloc_std_external *pend;
52859024Sobrien
52959024Sobrien	  p = (struct reloc_std_external *) info->dynrel;
53059024Sobrien	  pend = p + info->dynrel_count;
53159024Sobrien	  for (; p < pend; p++, to++)
53259024Sobrien	    NAME(aout,swap_std_reloc_in) (abfd, p, to, syms,
53389857Sobrien					  (bfd_size_type) info->dynsym_count);
53459024Sobrien	}
53559024Sobrien    }
53659024Sobrien
53759024Sobrien  /* Return pointers to the dynamic arelent structures.  */
53859024Sobrien  for (i = 0; i < info->dynrel_count; i++)
53959024Sobrien    *storage++ = info->canonical_dynrel + i;
54059024Sobrien  *storage = NULL;
54159024Sobrien
54259024Sobrien  return info->dynrel_count;
54359024Sobrien}
54459024Sobrien
54559024Sobrien/* Code to handle linking of SunOS shared libraries.  */
54659024Sobrien
54759024Sobrien/* A SPARC procedure linkage table entry is 12 bytes.  The first entry
54859024Sobrien   in the table is a jump which is filled in by the runtime linker.
54959024Sobrien   The remaining entries are branches back to the first entry,
55059024Sobrien   followed by an index into the relocation table encoded to look like
55159024Sobrien   a sethi of %g0.  */
55259024Sobrien
55359024Sobrien#define SPARC_PLT_ENTRY_SIZE (12)
55459024Sobrien
55559024Sobrienstatic const bfd_byte sparc_plt_first_entry[SPARC_PLT_ENTRY_SIZE] =
55659024Sobrien{
55759024Sobrien  /* sethi %hi(0),%g1; address filled in by runtime linker.  */
55859024Sobrien  0x3, 0, 0, 0,
55959024Sobrien  /* jmp %g1; offset filled in by runtime linker.  */
56059024Sobrien  0x81, 0xc0, 0x60, 0,
56159024Sobrien  /* nop */
56259024Sobrien  0x1, 0, 0, 0
56359024Sobrien};
56459024Sobrien
56559024Sobrien/* save %sp, -96, %sp */
56689857Sobrien#define SPARC_PLT_ENTRY_WORD0 ((bfd_vma) 0x9de3bfa0)
56759024Sobrien/* call; address filled in later.  */
56889857Sobrien#define SPARC_PLT_ENTRY_WORD1 ((bfd_vma) 0x40000000)
56959024Sobrien/* sethi; reloc index filled in later.  */
57089857Sobrien#define SPARC_PLT_ENTRY_WORD2 ((bfd_vma) 0x01000000)
57159024Sobrien
57259024Sobrien/* This sequence is used when for the jump table entry to a defined
57359024Sobrien   symbol in a complete executable.  It is used when linking PIC
57459024Sobrien   compiled code which is not being put into a shared library.  */
57559024Sobrien/* sethi <address to be filled in later>, %g1 */
57689857Sobrien#define SPARC_PLT_PIC_WORD0 ((bfd_vma) 0x03000000)
57759024Sobrien/* jmp %g1 + <address to be filled in later> */
57889857Sobrien#define SPARC_PLT_PIC_WORD1 ((bfd_vma) 0x81c06000)
57959024Sobrien/* nop */
58089857Sobrien#define SPARC_PLT_PIC_WORD2 ((bfd_vma) 0x01000000)
58159024Sobrien
58259024Sobrien/* An m68k procedure linkage table entry is 8 bytes.  The first entry
58359024Sobrien   in the table is a jump which is filled in the by the runtime
58459024Sobrien   linker.  The remaining entries are branches back to the first
58559024Sobrien   entry, followed by a two byte index into the relocation table.  */
58659024Sobrien
58759024Sobrien#define M68K_PLT_ENTRY_SIZE (8)
58859024Sobrien
58959024Sobrienstatic const bfd_byte m68k_plt_first_entry[M68K_PLT_ENTRY_SIZE] =
59059024Sobrien{
59159024Sobrien  /* jmps @# */
59259024Sobrien  0x4e, 0xf9,
59359024Sobrien  /* Filled in by runtime linker with a magic address.  */
59459024Sobrien  0, 0, 0, 0,
59559024Sobrien  /* Not used?  */
59659024Sobrien  0, 0
59759024Sobrien};
59859024Sobrien
59959024Sobrien/* bsrl */
60089857Sobrien#define M68K_PLT_ENTRY_WORD0 ((bfd_vma) 0x61ff)
60159024Sobrien/* Remaining words filled in later.  */
60259024Sobrien
60359024Sobrien/* An entry in the SunOS linker hash table.  */
60459024Sobrien
60559024Sobrienstruct sunos_link_hash_entry
60659024Sobrien{
60759024Sobrien  struct aout_link_hash_entry root;
60859024Sobrien
60959024Sobrien  /* If this is a dynamic symbol, this is its index into the dynamic
61059024Sobrien     symbol table.  This is initialized to -1.  As the linker looks at
61159024Sobrien     the input files, it changes this to -2 if it will be added to the
61259024Sobrien     dynamic symbol table.  After all the input files have been seen,
61359024Sobrien     the linker will know whether to build a dynamic symbol table; if
61459024Sobrien     it does build one, this becomes the index into the table.  */
61559024Sobrien  long dynindx;
61659024Sobrien
61759024Sobrien  /* If this is a dynamic symbol, this is the index of the name in the
61859024Sobrien     dynamic symbol string table.  */
61959024Sobrien  long dynstr_index;
62059024Sobrien
62159024Sobrien  /* The offset into the global offset table used for this symbol.  If
62259024Sobrien     the symbol does not require a GOT entry, this is 0.  */
62359024Sobrien  bfd_vma got_offset;
62459024Sobrien
62559024Sobrien  /* The offset into the procedure linkage table used for this symbol.
62659024Sobrien     If the symbol does not require a PLT entry, this is 0.  */
62759024Sobrien  bfd_vma plt_offset;
62859024Sobrien
62959024Sobrien  /* Some linker flags.  */
63059024Sobrien  unsigned char flags;
63159024Sobrien  /* Symbol is referenced by a regular object.  */
63259024Sobrien#define SUNOS_REF_REGULAR 01
63359024Sobrien  /* Symbol is defined by a regular object.  */
63459024Sobrien#define SUNOS_DEF_REGULAR 02
63559024Sobrien  /* Symbol is referenced by a dynamic object.  */
63659024Sobrien#define SUNOS_REF_DYNAMIC 04
63759024Sobrien  /* Symbol is defined by a dynamic object.  */
63859024Sobrien#define SUNOS_DEF_DYNAMIC 010
63959024Sobrien  /* Symbol is a constructor symbol in a regular object.  */
64059024Sobrien#define SUNOS_CONSTRUCTOR 020
64159024Sobrien};
64259024Sobrien
64359024Sobrien/* The SunOS linker hash table.  */
64459024Sobrien
64559024Sobrienstruct sunos_link_hash_table
64659024Sobrien{
64759024Sobrien  struct aout_link_hash_table root;
64859024Sobrien
64959024Sobrien  /* The object which holds the dynamic sections.  */
65059024Sobrien  bfd *dynobj;
65159024Sobrien
65259024Sobrien  /* Whether we have created the dynamic sections.  */
653130561Sobrien  bfd_boolean dynamic_sections_created;
65459024Sobrien
65559024Sobrien  /* Whether we need the dynamic sections.  */
656130561Sobrien  bfd_boolean dynamic_sections_needed;
65759024Sobrien
65859024Sobrien  /* Whether we need the .got table.  */
659130561Sobrien  bfd_boolean got_needed;
66059024Sobrien
66159024Sobrien  /* The number of dynamic symbols.  */
66259024Sobrien  size_t dynsymcount;
66359024Sobrien
66459024Sobrien  /* The number of buckets in the hash table.  */
66559024Sobrien  size_t bucketcount;
66659024Sobrien
66759024Sobrien  /* The list of dynamic objects needed by dynamic objects included in
66859024Sobrien     the link.  */
66959024Sobrien  struct bfd_link_needed_list *needed;
67059024Sobrien
67159024Sobrien  /* The offset of __GLOBAL_OFFSET_TABLE_ into the .got section.  */
67259024Sobrien  bfd_vma got_base;
67359024Sobrien};
67459024Sobrien
67559024Sobrien/* Routine to create an entry in an SunOS link hash table.  */
67659024Sobrien
67759024Sobrienstatic struct bfd_hash_entry *
67859024Sobriensunos_link_hash_newfunc (entry, table, string)
67959024Sobrien     struct bfd_hash_entry *entry;
68059024Sobrien     struct bfd_hash_table *table;
68159024Sobrien     const char *string;
68259024Sobrien{
68359024Sobrien  struct sunos_link_hash_entry *ret = (struct sunos_link_hash_entry *) entry;
68459024Sobrien
68559024Sobrien  /* Allocate the structure if it has not already been allocated by a
68659024Sobrien     subclass.  */
68759024Sobrien  if (ret == (struct sunos_link_hash_entry *) NULL)
68859024Sobrien    ret = ((struct sunos_link_hash_entry *)
68959024Sobrien	   bfd_hash_allocate (table, sizeof (struct sunos_link_hash_entry)));
69059024Sobrien  if (ret == (struct sunos_link_hash_entry *) NULL)
69159024Sobrien    return (struct bfd_hash_entry *) ret;
69259024Sobrien
69359024Sobrien  /* Call the allocation method of the superclass.  */
69459024Sobrien  ret = ((struct sunos_link_hash_entry *)
69559024Sobrien	 NAME(aout,link_hash_newfunc) ((struct bfd_hash_entry *) ret,
69659024Sobrien				       table, string));
69759024Sobrien  if (ret != NULL)
69859024Sobrien    {
69959024Sobrien      /* Set local fields.  */
70059024Sobrien      ret->dynindx = -1;
70159024Sobrien      ret->dynstr_index = -1;
70259024Sobrien      ret->got_offset = 0;
70359024Sobrien      ret->plt_offset = 0;
70459024Sobrien      ret->flags = 0;
70559024Sobrien    }
70659024Sobrien
70759024Sobrien  return (struct bfd_hash_entry *) ret;
70859024Sobrien}
70959024Sobrien
71059024Sobrien/* Create a SunOS link hash table.  */
71159024Sobrien
71259024Sobrienstatic struct bfd_link_hash_table *
71359024Sobriensunos_link_hash_table_create (abfd)
71459024Sobrien     bfd *abfd;
71559024Sobrien{
71659024Sobrien  struct sunos_link_hash_table *ret;
71789857Sobrien  bfd_size_type amt = sizeof (struct sunos_link_hash_table);
71859024Sobrien
719104834Sobrien  ret = (struct sunos_link_hash_table *) bfd_malloc (amt);
72059024Sobrien  if (ret == (struct sunos_link_hash_table *) NULL)
72159024Sobrien    return (struct bfd_link_hash_table *) NULL;
72259024Sobrien  if (! NAME(aout,link_hash_table_init) (&ret->root, abfd,
72359024Sobrien					 sunos_link_hash_newfunc))
72459024Sobrien    {
725104834Sobrien      free (ret);
72659024Sobrien      return (struct bfd_link_hash_table *) NULL;
72759024Sobrien    }
72859024Sobrien
72959024Sobrien  ret->dynobj = NULL;
730130561Sobrien  ret->dynamic_sections_created = FALSE;
731130561Sobrien  ret->dynamic_sections_needed = FALSE;
732130561Sobrien  ret->got_needed = FALSE;
73359024Sobrien  ret->dynsymcount = 0;
73459024Sobrien  ret->bucketcount = 0;
73559024Sobrien  ret->needed = NULL;
73659024Sobrien  ret->got_base = 0;
73759024Sobrien
73859024Sobrien  return &ret->root.root;
73959024Sobrien}
74059024Sobrien
74159024Sobrien/* Look up an entry in an SunOS link hash table.  */
74259024Sobrien
74359024Sobrien#define sunos_link_hash_lookup(table, string, create, copy, follow) \
74459024Sobrien  ((struct sunos_link_hash_entry *) \
74559024Sobrien   aout_link_hash_lookup (&(table)->root, (string), (create), (copy),\
74659024Sobrien			  (follow)))
74759024Sobrien
74859024Sobrien/* Traverse a SunOS link hash table.  */
74959024Sobrien
75059024Sobrien#define sunos_link_hash_traverse(table, func, info)			\
75159024Sobrien  (aout_link_hash_traverse						\
75259024Sobrien   (&(table)->root,							\
753130561Sobrien    (bfd_boolean (*) PARAMS ((struct aout_link_hash_entry *, PTR))) (func), \
75459024Sobrien    (info)))
75559024Sobrien
75659024Sobrien/* Get the SunOS link hash table from the info structure.  This is
75759024Sobrien   just a cast.  */
75859024Sobrien
75959024Sobrien#define sunos_hash_table(p) ((struct sunos_link_hash_table *) ((p)->hash))
76059024Sobrien
761130561Sobrienstatic bfd_boolean sunos_scan_dynamic_symbol
76259024Sobrien  PARAMS ((struct sunos_link_hash_entry *, PTR));
76359024Sobrien
76459024Sobrien/* Create the dynamic sections needed if we are linking against a
76559024Sobrien   dynamic object, or if we are linking PIC compiled code.  ABFD is a
76659024Sobrien   bfd we can attach the dynamic sections to.  The linker script will
76759024Sobrien   look for these special sections names and put them in the right
76859024Sobrien   place in the output file.  See include/aout/sun4.h for more details
76959024Sobrien   of the dynamic linking information.  */
77059024Sobrien
771130561Sobrienstatic bfd_boolean
77259024Sobriensunos_create_dynamic_sections (abfd, info, needed)
77359024Sobrien     bfd *abfd;
77459024Sobrien     struct bfd_link_info *info;
775130561Sobrien     bfd_boolean needed;
77659024Sobrien{
77759024Sobrien  asection *s;
77859024Sobrien
77959024Sobrien  if (! sunos_hash_table (info)->dynamic_sections_created)
78059024Sobrien    {
78159024Sobrien      flagword flags;
78259024Sobrien
78359024Sobrien      sunos_hash_table (info)->dynobj = abfd;
78459024Sobrien
78559024Sobrien      flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY
78659024Sobrien	       | SEC_LINKER_CREATED);
78759024Sobrien
78859024Sobrien      /* The .dynamic section holds the basic dynamic information: the
78959024Sobrien	 sun4_dynamic structure, the dynamic debugger information, and
79059024Sobrien	 the sun4_dynamic_link structure.  */
79159024Sobrien      s = bfd_make_section (abfd, ".dynamic");
79259024Sobrien      if (s == NULL
79359024Sobrien	  || ! bfd_set_section_flags (abfd, s, flags)
79459024Sobrien	  || ! bfd_set_section_alignment (abfd, s, 2))
795130561Sobrien	return FALSE;
79659024Sobrien
79759024Sobrien      /* The .got section holds the global offset table.  The address
79859024Sobrien	 is put in the ld_got field.  */
79959024Sobrien      s = bfd_make_section (abfd, ".got");
80059024Sobrien      if (s == NULL
80159024Sobrien	  || ! bfd_set_section_flags (abfd, s, flags)
80259024Sobrien	  || ! bfd_set_section_alignment (abfd, s, 2))
803130561Sobrien	return FALSE;
80459024Sobrien
80559024Sobrien      /* The .plt section holds the procedure linkage table.  The
80659024Sobrien	 address is put in the ld_plt field.  */
80759024Sobrien      s = bfd_make_section (abfd, ".plt");
80859024Sobrien      if (s == NULL
80959024Sobrien	  || ! bfd_set_section_flags (abfd, s, flags | SEC_CODE)
81059024Sobrien	  || ! bfd_set_section_alignment (abfd, s, 2))
811130561Sobrien	return FALSE;
81259024Sobrien
81359024Sobrien      /* The .dynrel section holds the dynamic relocs.  The address is
81459024Sobrien	 put in the ld_rel field.  */
81559024Sobrien      s = bfd_make_section (abfd, ".dynrel");
81659024Sobrien      if (s == NULL
81759024Sobrien	  || ! bfd_set_section_flags (abfd, s, flags | SEC_READONLY)
81859024Sobrien	  || ! bfd_set_section_alignment (abfd, s, 2))
819130561Sobrien	return FALSE;
82059024Sobrien
82159024Sobrien      /* The .hash section holds the dynamic hash table.  The address
82259024Sobrien	 is put in the ld_hash field.  */
82359024Sobrien      s = bfd_make_section (abfd, ".hash");
82459024Sobrien      if (s == NULL
82559024Sobrien	  || ! bfd_set_section_flags (abfd, s, flags | SEC_READONLY)
82659024Sobrien	  || ! bfd_set_section_alignment (abfd, s, 2))
827130561Sobrien	return FALSE;
82859024Sobrien
82959024Sobrien      /* The .dynsym section holds the dynamic symbols.  The address
83059024Sobrien	 is put in the ld_stab field.  */
83159024Sobrien      s = bfd_make_section (abfd, ".dynsym");
83259024Sobrien      if (s == NULL
83359024Sobrien	  || ! bfd_set_section_flags (abfd, s, flags | SEC_READONLY)
83459024Sobrien	  || ! bfd_set_section_alignment (abfd, s, 2))
835130561Sobrien	return FALSE;
83659024Sobrien
83759024Sobrien      /* The .dynstr section holds the dynamic symbol string table.
83859024Sobrien	 The address is put in the ld_symbols field.  */
83959024Sobrien      s = bfd_make_section (abfd, ".dynstr");
84059024Sobrien      if (s == NULL
84159024Sobrien	  || ! bfd_set_section_flags (abfd, s, flags | SEC_READONLY)
84259024Sobrien	  || ! bfd_set_section_alignment (abfd, s, 2))
843130561Sobrien	return FALSE;
84459024Sobrien
845130561Sobrien      sunos_hash_table (info)->dynamic_sections_created = TRUE;
84659024Sobrien    }
84759024Sobrien
84859024Sobrien  if ((needed && ! sunos_hash_table (info)->dynamic_sections_needed)
84959024Sobrien      || info->shared)
85059024Sobrien    {
85159024Sobrien      bfd *dynobj;
85259024Sobrien
85359024Sobrien      dynobj = sunos_hash_table (info)->dynobj;
85459024Sobrien
85559024Sobrien      s = bfd_get_section_by_name (dynobj, ".got");
85659024Sobrien      if (s->_raw_size == 0)
85759024Sobrien	s->_raw_size = BYTES_IN_WORD;
85859024Sobrien
859130561Sobrien      sunos_hash_table (info)->dynamic_sections_needed = TRUE;
860130561Sobrien      sunos_hash_table (info)->got_needed = TRUE;
86159024Sobrien    }
86259024Sobrien
863130561Sobrien  return TRUE;
86459024Sobrien}
86559024Sobrien
86659024Sobrien/* Add dynamic symbols during a link.  This is called by the a.out
86759024Sobrien   backend linker for each object it encounters.  */
86859024Sobrien
869130561Sobrienstatic bfd_boolean
87059024Sobriensunos_add_dynamic_symbols (abfd, info, symsp, sym_countp, stringsp)
87159024Sobrien     bfd *abfd;
87259024Sobrien     struct bfd_link_info *info;
87359024Sobrien     struct external_nlist **symsp;
87459024Sobrien     bfd_size_type *sym_countp;
87559024Sobrien     char **stringsp;
87659024Sobrien{
87759024Sobrien  bfd *dynobj;
87859024Sobrien  struct sunos_dynamic_info *dinfo;
87959024Sobrien  unsigned long need;
88089857Sobrien  asection **ps;
88159024Sobrien
88259024Sobrien  /* Make sure we have all the required sections.  */
88359024Sobrien  if (info->hash->creator == abfd->xvec)
88459024Sobrien    {
88559024Sobrien      if (! sunos_create_dynamic_sections (abfd, info,
886130561Sobrien					   ((abfd->flags & DYNAMIC) != 0
887130561Sobrien					    && !info->relocatable)))
888130561Sobrien	return FALSE;
88959024Sobrien    }
89059024Sobrien
89159024Sobrien  /* There is nothing else to do for a normal object.  */
89259024Sobrien  if ((abfd->flags & DYNAMIC) == 0)
893130561Sobrien    return TRUE;
89459024Sobrien
89559024Sobrien  dynobj = sunos_hash_table (info)->dynobj;
89659024Sobrien
89759024Sobrien  /* We do not want to include the sections in a dynamic object in the
89859024Sobrien     output file.  We hack by simply clobbering the list of sections
89959024Sobrien     in the BFD.  This could be handled more cleanly by, say, a new
90059024Sobrien     section flag; the existing SEC_NEVER_LOAD flag is not the one we
90159024Sobrien     want, because that one still implies that the section takes up
90259024Sobrien     space in the output file.  If this is the first object we have
90359024Sobrien     seen, we must preserve the dynamic sections we just created.  */
90489857Sobrien  for (ps = &abfd->sections; *ps != NULL; )
90559024Sobrien    {
90689857Sobrien      if (abfd != dynobj || ((*ps)->flags & SEC_LINKER_CREATED) == 0)
90789857Sobrien	bfd_section_list_remove (abfd, ps);
90889857Sobrien      else
90989857Sobrien	ps = &(*ps)->next;
91059024Sobrien    }
91159024Sobrien
91259024Sobrien  /* The native linker seems to just ignore dynamic objects when -r is
91359024Sobrien     used.  */
914130561Sobrien  if (info->relocatable)
915130561Sobrien    return TRUE;
91659024Sobrien
91759024Sobrien  /* There's no hope of using a dynamic object which does not exactly
91859024Sobrien     match the format of the output file.  */
91959024Sobrien  if (info->hash->creator != abfd->xvec)
92059024Sobrien    {
92159024Sobrien      bfd_set_error (bfd_error_invalid_operation);
922130561Sobrien      return FALSE;
92359024Sobrien    }
92459024Sobrien
92559024Sobrien  /* Make sure we have a .need and a .rules sections.  These are only
92659024Sobrien     needed if there really is a dynamic object in the link, so they
92759024Sobrien     are not added by sunos_create_dynamic_sections.  */
92859024Sobrien  if (bfd_get_section_by_name (dynobj, ".need") == NULL)
92959024Sobrien    {
93059024Sobrien      /* The .need section holds the list of names of shared objets
93159024Sobrien	 which must be included at runtime.  The address of this
93259024Sobrien	 section is put in the ld_need field.  */
93389857Sobrien      asection *s = bfd_make_section (dynobj, ".need");
93459024Sobrien      if (s == NULL
93559024Sobrien	  || ! bfd_set_section_flags (dynobj, s,
93659024Sobrien				      (SEC_ALLOC
93759024Sobrien				       | SEC_LOAD
93859024Sobrien				       | SEC_HAS_CONTENTS
93959024Sobrien				       | SEC_IN_MEMORY
94059024Sobrien				       | SEC_READONLY))
94159024Sobrien	  || ! bfd_set_section_alignment (dynobj, s, 2))
942130561Sobrien	return FALSE;
94359024Sobrien    }
94459024Sobrien
94559024Sobrien  if (bfd_get_section_by_name (dynobj, ".rules") == NULL)
94659024Sobrien    {
94759024Sobrien      /* The .rules section holds the path to search for shared
94859024Sobrien	 objects.  The address of this section is put in the ld_rules
94959024Sobrien	 field.  */
95089857Sobrien      asection *s = bfd_make_section (dynobj, ".rules");
95159024Sobrien      if (s == NULL
95259024Sobrien	  || ! bfd_set_section_flags (dynobj, s,
95359024Sobrien				      (SEC_ALLOC
95459024Sobrien				       | SEC_LOAD
95559024Sobrien				       | SEC_HAS_CONTENTS
95659024Sobrien				       | SEC_IN_MEMORY
95759024Sobrien				       | SEC_READONLY))
95859024Sobrien	  || ! bfd_set_section_alignment (dynobj, s, 2))
959130561Sobrien	return FALSE;
96059024Sobrien    }
96159024Sobrien
96259024Sobrien  /* Pick up the dynamic symbols and return them to the caller.  */
96359024Sobrien  if (! sunos_slurp_dynamic_symtab (abfd))
964130561Sobrien    return FALSE;
96559024Sobrien
96659024Sobrien  dinfo = (struct sunos_dynamic_info *) obj_aout_dynamic_info (abfd);
96759024Sobrien  *symsp = dinfo->dynsym;
96859024Sobrien  *sym_countp = dinfo->dynsym_count;
96959024Sobrien  *stringsp = dinfo->dynstr;
97059024Sobrien
97159024Sobrien  /* Record information about any other objects needed by this one.  */
97259024Sobrien  need = dinfo->dyninfo.ld_need;
97359024Sobrien  while (need != 0)
97459024Sobrien    {
97559024Sobrien      bfd_byte buf[16];
97659024Sobrien      unsigned long name, flags;
97759024Sobrien      unsigned short major_vno, minor_vno;
97859024Sobrien      struct bfd_link_needed_list *needed, **pp;
97959024Sobrien      char *namebuf, *p;
98089857Sobrien      bfd_size_type alc;
98159024Sobrien      bfd_byte b;
98259024Sobrien      char *namecopy;
98359024Sobrien
98489857Sobrien      if (bfd_seek (abfd, (file_ptr) need, SEEK_SET) != 0
98589857Sobrien	  || bfd_bread (buf, (bfd_size_type) 16, abfd) != 16)
986130561Sobrien	return FALSE;
98759024Sobrien
98859024Sobrien      /* For the format of an ld_need entry, see aout/sun4.h.  We
989130561Sobrien	 should probably define structs for this manipulation.  */
99059024Sobrien
99159024Sobrien      name = bfd_get_32 (abfd, buf);
99259024Sobrien      flags = bfd_get_32 (abfd, buf + 4);
99389857Sobrien      major_vno = (unsigned short) bfd_get_16 (abfd, buf + 8);
99489857Sobrien      minor_vno = (unsigned short) bfd_get_16 (abfd, buf + 10);
99559024Sobrien      need = bfd_get_32 (abfd, buf + 12);
99659024Sobrien
99789857Sobrien      alc = sizeof (struct bfd_link_needed_list);
99889857Sobrien      needed = (struct bfd_link_needed_list *) bfd_alloc (abfd, alc);
99959024Sobrien      if (needed == NULL)
1000130561Sobrien	return FALSE;
100159024Sobrien      needed->by = abfd;
100259024Sobrien
100359024Sobrien      /* We return the name as [-l]name[.maj][.min].  */
100459024Sobrien      alc = 30;
100559024Sobrien      namebuf = (char *) bfd_malloc (alc + 1);
100659024Sobrien      if (namebuf == NULL)
1007130561Sobrien	return FALSE;
100859024Sobrien      p = namebuf;
100959024Sobrien
101059024Sobrien      if ((flags & 0x80000000) != 0)
101159024Sobrien	{
101259024Sobrien	  *p++ = '-';
101359024Sobrien	  *p++ = 'l';
101459024Sobrien	}
101589857Sobrien      if (bfd_seek (abfd, (file_ptr) name, SEEK_SET) != 0)
101659024Sobrien	{
101759024Sobrien	  free (namebuf);
1018130561Sobrien	  return FALSE;
101959024Sobrien	}
102059024Sobrien
102159024Sobrien      do
102259024Sobrien	{
102389857Sobrien	  if (bfd_bread (&b, (bfd_size_type) 1, abfd) != 1)
102459024Sobrien	    {
102559024Sobrien	      free (namebuf);
1026130561Sobrien	      return FALSE;
102759024Sobrien	    }
102859024Sobrien
102989857Sobrien	  if ((bfd_size_type) (p - namebuf) >= alc)
103059024Sobrien	    {
103159024Sobrien	      char *n;
103259024Sobrien
103359024Sobrien	      alc *= 2;
103459024Sobrien	      n = (char *) bfd_realloc (namebuf, alc + 1);
103559024Sobrien	      if (n == NULL)
103659024Sobrien		{
103759024Sobrien		  free (namebuf);
1038130561Sobrien		  return FALSE;
103959024Sobrien		}
104059024Sobrien	      p = n + (p - namebuf);
104159024Sobrien	      namebuf = n;
104259024Sobrien	    }
104359024Sobrien
104459024Sobrien	  *p++ = b;
104559024Sobrien	}
104659024Sobrien      while (b != '\0');
104759024Sobrien
104859024Sobrien      if (major_vno == 0)
104959024Sobrien	*p = '\0';
105059024Sobrien      else
105159024Sobrien	{
105259024Sobrien	  char majbuf[30];
105359024Sobrien	  char minbuf[30];
105459024Sobrien
105559024Sobrien	  sprintf (majbuf, ".%d", major_vno);
105659024Sobrien	  if (minor_vno == 0)
105759024Sobrien	    minbuf[0] = '\0';
105859024Sobrien	  else
105959024Sobrien	    sprintf (minbuf, ".%d", minor_vno);
106059024Sobrien
106159024Sobrien	  if ((p - namebuf) + strlen (majbuf) + strlen (minbuf) >= alc)
106259024Sobrien	    {
106359024Sobrien	      char *n;
106459024Sobrien
106559024Sobrien	      alc = (p - namebuf) + strlen (majbuf) + strlen (minbuf);
106659024Sobrien	      n = (char *) bfd_realloc (namebuf, alc + 1);
106759024Sobrien	      if (n == NULL)
106859024Sobrien		{
106959024Sobrien		  free (namebuf);
1070130561Sobrien		  return FALSE;
107159024Sobrien		}
107259024Sobrien	      p = n + (p - namebuf);
107359024Sobrien	      namebuf = n;
107459024Sobrien	    }
107559024Sobrien
107659024Sobrien	  strcpy (p, majbuf);
107759024Sobrien	  strcat (p, minbuf);
107859024Sobrien	}
107959024Sobrien
108089857Sobrien      namecopy = bfd_alloc (abfd, (bfd_size_type) strlen (namebuf) + 1);
108159024Sobrien      if (namecopy == NULL)
108259024Sobrien	{
108359024Sobrien	  free (namebuf);
1084130561Sobrien	  return FALSE;
108559024Sobrien	}
108659024Sobrien      strcpy (namecopy, namebuf);
108759024Sobrien      free (namebuf);
108859024Sobrien      needed->name = namecopy;
108959024Sobrien
109059024Sobrien      needed->next = NULL;
109159024Sobrien
109259024Sobrien      for (pp = &sunos_hash_table (info)->needed;
109359024Sobrien	   *pp != NULL;
109459024Sobrien	   pp = &(*pp)->next)
109559024Sobrien	;
109659024Sobrien      *pp = needed;
109759024Sobrien    }
109859024Sobrien
1099130561Sobrien  return TRUE;
110059024Sobrien}
110159024Sobrien
110259024Sobrien/* Function to add a single symbol to the linker hash table.  This is
110359024Sobrien   a wrapper around _bfd_generic_link_add_one_symbol which handles the
110459024Sobrien   tweaking needed for dynamic linking support.  */
110559024Sobrien
1106130561Sobrienstatic bfd_boolean
110759024Sobriensunos_add_one_symbol (info, abfd, name, flags, section, value, string,
110859024Sobrien		      copy, collect, hashp)
110959024Sobrien     struct bfd_link_info *info;
111059024Sobrien     bfd *abfd;
111159024Sobrien     const char *name;
111259024Sobrien     flagword flags;
111359024Sobrien     asection *section;
111459024Sobrien     bfd_vma value;
111559024Sobrien     const char *string;
1116130561Sobrien     bfd_boolean copy;
1117130561Sobrien     bfd_boolean collect;
111859024Sobrien     struct bfd_link_hash_entry **hashp;
111959024Sobrien{
112059024Sobrien  struct sunos_link_hash_entry *h;
112159024Sobrien  int new_flag;
112259024Sobrien
112359024Sobrien  if ((flags & (BSF_INDIRECT | BSF_WARNING | BSF_CONSTRUCTOR)) != 0
112459024Sobrien      || ! bfd_is_und_section (section))
1125130561Sobrien    h = sunos_link_hash_lookup (sunos_hash_table (info), name, TRUE, copy,
1126130561Sobrien				FALSE);
112759024Sobrien  else
112859024Sobrien    h = ((struct sunos_link_hash_entry *)
1129130561Sobrien	 bfd_wrapped_link_hash_lookup (abfd, info, name, TRUE, copy, FALSE));
113059024Sobrien  if (h == NULL)
1131130561Sobrien    return FALSE;
113259024Sobrien
113359024Sobrien  if (hashp != NULL)
113459024Sobrien    *hashp = (struct bfd_link_hash_entry *) h;
113559024Sobrien
113659024Sobrien  /* Treat a common symbol in a dynamic object as defined in the .bss
113759024Sobrien     section of the dynamic object.  We don't want to allocate space
113859024Sobrien     for it in our process image.  */
113959024Sobrien  if ((abfd->flags & DYNAMIC) != 0
114059024Sobrien      && bfd_is_com_section (section))
114159024Sobrien    section = obj_bsssec (abfd);
114259024Sobrien
114359024Sobrien  if (! bfd_is_und_section (section)
114459024Sobrien      && h->root.root.type != bfd_link_hash_new
114559024Sobrien      && h->root.root.type != bfd_link_hash_undefined
114659024Sobrien      && h->root.root.type != bfd_link_hash_defweak)
114759024Sobrien    {
114859024Sobrien      /* We are defining the symbol, and it is already defined.  This
114959024Sobrien	 is a potential multiple definition error.  */
115059024Sobrien      if ((abfd->flags & DYNAMIC) != 0)
115159024Sobrien	{
115259024Sobrien	  /* The definition we are adding is from a dynamic object.
115359024Sobrien	     We do not want this new definition to override the
115459024Sobrien	     existing definition, so we pretend it is just a
115559024Sobrien	     reference.  */
115659024Sobrien	  section = bfd_und_section_ptr;
115759024Sobrien	}
115859024Sobrien      else if (h->root.root.type == bfd_link_hash_defined
115959024Sobrien	       && h->root.root.u.def.section->owner != NULL
116059024Sobrien	       && (h->root.root.u.def.section->owner->flags & DYNAMIC) != 0)
116159024Sobrien	{
116259024Sobrien	  /* The existing definition is from a dynamic object.  We
116359024Sobrien	     want to override it with the definition we just found.
116459024Sobrien	     Clobber the existing definition.  */
116559024Sobrien	  h->root.root.type = bfd_link_hash_undefined;
116659024Sobrien	  h->root.root.u.undef.abfd = h->root.root.u.def.section->owner;
116759024Sobrien	}
116859024Sobrien      else if (h->root.root.type == bfd_link_hash_common
116959024Sobrien	       && (h->root.root.u.c.p->section->owner->flags & DYNAMIC) != 0)
117059024Sobrien	{
117159024Sobrien	  /* The existing definition is from a dynamic object.  We
117259024Sobrien	     want to override it with the definition we just found.
117359024Sobrien	     Clobber the existing definition.  We can't set it to new,
117459024Sobrien	     because it is on the undefined list.  */
117559024Sobrien	  h->root.root.type = bfd_link_hash_undefined;
117659024Sobrien	  h->root.root.u.undef.abfd = h->root.root.u.c.p->section->owner;
117759024Sobrien	}
117859024Sobrien    }
117959024Sobrien
118059024Sobrien  if ((abfd->flags & DYNAMIC) != 0
118159024Sobrien      && abfd->xvec == info->hash->creator
118259024Sobrien      && (h->flags & SUNOS_CONSTRUCTOR) != 0)
118359024Sobrien    {
118459024Sobrien      /* The existing symbol is a constructor symbol, and this symbol
1185130561Sobrien	 is from a dynamic object.  A constructor symbol is actually a
1186130561Sobrien	 definition, although the type will be bfd_link_hash_undefined
1187130561Sobrien	 at this point.  We want to ignore the definition from the
1188130561Sobrien	 dynamic object.  */
118959024Sobrien      section = bfd_und_section_ptr;
119059024Sobrien    }
119159024Sobrien  else if ((flags & BSF_CONSTRUCTOR) != 0
119259024Sobrien	   && (abfd->flags & DYNAMIC) == 0
119359024Sobrien	   && h->root.root.type == bfd_link_hash_defined
119459024Sobrien	   && h->root.root.u.def.section->owner != NULL
119559024Sobrien	   && (h->root.root.u.def.section->owner->flags & DYNAMIC) != 0)
119659024Sobrien    {
119759024Sobrien      /* The existing symbol is defined by a dynamic object, and this
1198130561Sobrien	 is a constructor symbol.  As above, we want to force the use
1199130561Sobrien	 of the constructor symbol from the regular object.  */
120059024Sobrien      h->root.root.type = bfd_link_hash_new;
120159024Sobrien    }
120259024Sobrien
120359024Sobrien  /* Do the usual procedure for adding a symbol.  */
120459024Sobrien  if (! _bfd_generic_link_add_one_symbol (info, abfd, name, flags, section,
120559024Sobrien					  value, string, copy, collect,
120659024Sobrien					  hashp))
1207130561Sobrien    return FALSE;
120859024Sobrien
120959024Sobrien  if (abfd->xvec == info->hash->creator)
121059024Sobrien    {
121159024Sobrien      /* Set a flag in the hash table entry indicating the type of
121259024Sobrien	 reference or definition we just found.  Keep a count of the
121359024Sobrien	 number of dynamic symbols we find.  A dynamic symbol is one
121459024Sobrien	 which is referenced or defined by both a regular object and a
121559024Sobrien	 shared object.  */
121659024Sobrien      if ((abfd->flags & DYNAMIC) == 0)
121759024Sobrien	{
121859024Sobrien	  if (bfd_is_und_section (section))
121959024Sobrien	    new_flag = SUNOS_REF_REGULAR;
122059024Sobrien	  else
122159024Sobrien	    new_flag = SUNOS_DEF_REGULAR;
122259024Sobrien	}
122359024Sobrien      else
122459024Sobrien	{
122559024Sobrien	  if (bfd_is_und_section (section))
122659024Sobrien	    new_flag = SUNOS_REF_DYNAMIC;
122759024Sobrien	  else
122859024Sobrien	    new_flag = SUNOS_DEF_DYNAMIC;
122959024Sobrien	}
123059024Sobrien      h->flags |= new_flag;
123159024Sobrien
123259024Sobrien      if (h->dynindx == -1
123359024Sobrien	  && (h->flags & (SUNOS_DEF_REGULAR | SUNOS_REF_REGULAR)) != 0)
123459024Sobrien	{
123559024Sobrien	  ++sunos_hash_table (info)->dynsymcount;
123659024Sobrien	  h->dynindx = -2;
123759024Sobrien	}
123859024Sobrien
123959024Sobrien      if ((flags & BSF_CONSTRUCTOR) != 0
124059024Sobrien	  && (abfd->flags & DYNAMIC) == 0)
124159024Sobrien	h->flags |= SUNOS_CONSTRUCTOR;
124259024Sobrien    }
124359024Sobrien
1244130561Sobrien  return TRUE;
124559024Sobrien}
124659024Sobrien
124759024Sobrien/* Return the list of objects needed by BFD.  */
124859024Sobrien
124959024Sobrienstruct bfd_link_needed_list *
125059024Sobrienbfd_sunos_get_needed_list (abfd, info)
125184865Sobrien     bfd *abfd ATTRIBUTE_UNUSED;
125259024Sobrien     struct bfd_link_info *info;
125359024Sobrien{
125459024Sobrien  if (info->hash->creator != &MY(vec))
125559024Sobrien    return NULL;
125659024Sobrien  return sunos_hash_table (info)->needed;
125759024Sobrien}
125859024Sobrien
125959024Sobrien/* Record an assignment made to a symbol by a linker script.  We need
126059024Sobrien   this in case some dynamic object refers to this symbol.  */
126159024Sobrien
1262130561Sobrienbfd_boolean
126359024Sobrienbfd_sunos_record_link_assignment (output_bfd, info, name)
126459024Sobrien     bfd *output_bfd;
126559024Sobrien     struct bfd_link_info *info;
126659024Sobrien     const char *name;
126759024Sobrien{
126859024Sobrien  struct sunos_link_hash_entry *h;
126959024Sobrien
127059024Sobrien  if (output_bfd->xvec != &MY(vec))
1271130561Sobrien    return TRUE;
127259024Sobrien
127359024Sobrien  /* This is called after we have examined all the input objects.  If
127459024Sobrien     the symbol does not exist, it merely means that no object refers
127559024Sobrien     to it, and we can just ignore it at this point.  */
127659024Sobrien  h = sunos_link_hash_lookup (sunos_hash_table (info), name,
1277130561Sobrien			      FALSE, FALSE, FALSE);
127859024Sobrien  if (h == NULL)
1279130561Sobrien    return TRUE;
128059024Sobrien
128159024Sobrien  /* In a shared library, the __DYNAMIC symbol does not appear in the
128259024Sobrien     dynamic symbol table.  */
128359024Sobrien  if (! info->shared || strcmp (name, "__DYNAMIC") != 0)
128459024Sobrien    {
128559024Sobrien      h->flags |= SUNOS_DEF_REGULAR;
128659024Sobrien
128759024Sobrien      if (h->dynindx == -1)
128859024Sobrien	{
128959024Sobrien	  ++sunos_hash_table (info)->dynsymcount;
129059024Sobrien	  h->dynindx = -2;
129159024Sobrien	}
129259024Sobrien    }
129359024Sobrien
1294130561Sobrien  return TRUE;
129559024Sobrien}
129659024Sobrien
129759024Sobrien/* Set up the sizes and contents of the dynamic sections created in
129859024Sobrien   sunos_add_dynamic_symbols.  This is called by the SunOS linker
129959024Sobrien   emulation before_allocation routine.  We must set the sizes of the
130059024Sobrien   sections before the linker sets the addresses of the various
130159024Sobrien   sections.  This unfortunately requires reading all the relocs so
130259024Sobrien   that we can work out which ones need to become dynamic relocs.  If
1303130561Sobrien   info->keep_memory is TRUE, we keep the relocs in memory; otherwise,
130459024Sobrien   we discard them, and will read them again later.  */
130559024Sobrien
1306130561Sobrienbfd_boolean
130759024Sobrienbfd_sunos_size_dynamic_sections (output_bfd, info, sdynptr, sneedptr,
130859024Sobrien				 srulesptr)
130959024Sobrien     bfd *output_bfd;
131059024Sobrien     struct bfd_link_info *info;
131159024Sobrien     asection **sdynptr;
131259024Sobrien     asection **sneedptr;
131359024Sobrien     asection **srulesptr;
131459024Sobrien{
131559024Sobrien  bfd *dynobj;
131689857Sobrien  bfd_size_type dynsymcount;
131759024Sobrien  struct sunos_link_hash_entry *h;
131859024Sobrien  asection *s;
131959024Sobrien  size_t bucketcount;
132089857Sobrien  bfd_size_type hashalloc;
132159024Sobrien  size_t i;
132259024Sobrien  bfd *sub;
132359024Sobrien
132459024Sobrien  *sdynptr = NULL;
132559024Sobrien  *sneedptr = NULL;
132659024Sobrien  *srulesptr = NULL;
132759024Sobrien
1328130561Sobrien  if (info->relocatable)
1329130561Sobrien    return TRUE;
133059024Sobrien
133159024Sobrien  if (output_bfd->xvec != &MY(vec))
1332130561Sobrien    return TRUE;
133359024Sobrien
133459024Sobrien  /* Look through all the input BFD's and read their relocs.  It would
133559024Sobrien     be better if we didn't have to do this, but there is no other way
133659024Sobrien     to determine the number of dynamic relocs we need, and, more
133759024Sobrien     importantly, there is no other way to know which symbols should
133859024Sobrien     get an entry in the procedure linkage table.  */
133959024Sobrien  for (sub = info->input_bfds; sub != NULL; sub = sub->link_next)
134059024Sobrien    {
134159024Sobrien      if ((sub->flags & DYNAMIC) == 0
134259024Sobrien	  && sub->xvec == output_bfd->xvec)
134359024Sobrien	{
134459024Sobrien	  if (! sunos_scan_relocs (info, sub, obj_textsec (sub),
134559024Sobrien				   exec_hdr (sub)->a_trsize)
134659024Sobrien	      || ! sunos_scan_relocs (info, sub, obj_datasec (sub),
134759024Sobrien				      exec_hdr (sub)->a_drsize))
1348130561Sobrien	    return FALSE;
134959024Sobrien	}
135059024Sobrien    }
135159024Sobrien
135259024Sobrien  dynobj = sunos_hash_table (info)->dynobj;
135359024Sobrien  dynsymcount = sunos_hash_table (info)->dynsymcount;
135459024Sobrien
135559024Sobrien  /* If there were no dynamic objects in the link, and we don't need
135659024Sobrien     to build a global offset table, there is nothing to do here.  */
135759024Sobrien  if (! sunos_hash_table (info)->dynamic_sections_needed
135859024Sobrien      && ! sunos_hash_table (info)->got_needed)
1359130561Sobrien    return TRUE;
136059024Sobrien
136159024Sobrien  /* If __GLOBAL_OFFSET_TABLE_ was mentioned, define it.  */
136259024Sobrien  h = sunos_link_hash_lookup (sunos_hash_table (info),
1363130561Sobrien			      "__GLOBAL_OFFSET_TABLE_", FALSE, FALSE, FALSE);
136459024Sobrien  if (h != NULL && (h->flags & SUNOS_REF_REGULAR) != 0)
136559024Sobrien    {
136659024Sobrien      h->flags |= SUNOS_DEF_REGULAR;
136759024Sobrien      if (h->dynindx == -1)
136859024Sobrien	{
136959024Sobrien	  ++sunos_hash_table (info)->dynsymcount;
137059024Sobrien	  h->dynindx = -2;
137159024Sobrien	}
137259024Sobrien      h->root.root.type = bfd_link_hash_defined;
137359024Sobrien      h->root.root.u.def.section = bfd_get_section_by_name (dynobj, ".got");
137459024Sobrien
137559024Sobrien      /* If the .got section is more than 0x1000 bytes, we set
1376130561Sobrien	 __GLOBAL_OFFSET_TABLE_ to be 0x1000 bytes into the section,
1377130561Sobrien	 so that 13 bit relocations have a greater chance of working.  */
137859024Sobrien      s = bfd_get_section_by_name (dynobj, ".got");
137959024Sobrien      BFD_ASSERT (s != NULL);
138059024Sobrien      if (s->_raw_size >= 0x1000)
138159024Sobrien	h->root.root.u.def.value = 0x1000;
138259024Sobrien      else
138359024Sobrien	h->root.root.u.def.value = 0;
138459024Sobrien
138559024Sobrien      sunos_hash_table (info)->got_base = h->root.root.u.def.value;
138659024Sobrien    }
138759024Sobrien
138859024Sobrien  /* If there are any shared objects in the link, then we need to set
138959024Sobrien     up the dynamic linking information.  */
139059024Sobrien  if (sunos_hash_table (info)->dynamic_sections_needed)
139159024Sobrien    {
139259024Sobrien      *sdynptr = bfd_get_section_by_name (dynobj, ".dynamic");
139359024Sobrien
139459024Sobrien      /* The .dynamic section is always the same size.  */
139559024Sobrien      s = *sdynptr;
139659024Sobrien      BFD_ASSERT (s != NULL);
139759024Sobrien      s->_raw_size = (sizeof (struct external_sun4_dynamic)
139859024Sobrien		      + EXTERNAL_SUN4_DYNAMIC_DEBUGGER_SIZE
139959024Sobrien		      + sizeof (struct external_sun4_dynamic_link));
140059024Sobrien
140159024Sobrien      /* Set the size of the .dynsym and .hash sections.  We counted
140259024Sobrien	 the number of dynamic symbols as we read the input files.  We
140359024Sobrien	 will build the dynamic symbol table (.dynsym) and the hash
140459024Sobrien	 table (.hash) when we build the final symbol table, because
140559024Sobrien	 until then we do not know the correct value to give the
140659024Sobrien	 symbols.  We build the dynamic symbol string table (.dynstr)
140759024Sobrien	 in a traversal of the symbol table using
140859024Sobrien	 sunos_scan_dynamic_symbol.  */
140959024Sobrien      s = bfd_get_section_by_name (dynobj, ".dynsym");
141059024Sobrien      BFD_ASSERT (s != NULL);
141159024Sobrien      s->_raw_size = dynsymcount * sizeof (struct external_nlist);
141259024Sobrien      s->contents = (bfd_byte *) bfd_alloc (output_bfd, s->_raw_size);
141359024Sobrien      if (s->contents == NULL && s->_raw_size != 0)
1414130561Sobrien	return FALSE;
141584865Sobrien
141659024Sobrien      /* The number of buckets is just the number of symbols divided
141759024Sobrien	 by four.  To compute the final size of the hash table, we
141859024Sobrien	 must actually compute the hash table.  Normally we need
141959024Sobrien	 exactly as many entries in the hash table as there are
142059024Sobrien	 dynamic symbols, but if some of the buckets are not used we
142159024Sobrien	 will need additional entries.  In the worst case, every
142259024Sobrien	 symbol will hash to the same bucket, and we will need
142359024Sobrien	 BUCKETCOUNT - 1 extra entries.  */
142459024Sobrien      if (dynsymcount >= 4)
142559024Sobrien	bucketcount = dynsymcount / 4;
142659024Sobrien      else if (dynsymcount > 0)
142759024Sobrien	bucketcount = dynsymcount;
142859024Sobrien      else
142959024Sobrien	bucketcount = 1;
143059024Sobrien      s = bfd_get_section_by_name (dynobj, ".hash");
143159024Sobrien      BFD_ASSERT (s != NULL);
143259024Sobrien      hashalloc = (dynsymcount + bucketcount - 1) * HASH_ENTRY_SIZE;
1433104834Sobrien      s->contents = (bfd_byte *) bfd_zalloc (dynobj, hashalloc);
143459024Sobrien      if (s->contents == NULL && dynsymcount > 0)
1435130561Sobrien	return FALSE;
143659024Sobrien      for (i = 0; i < bucketcount; i++)
143759024Sobrien	PUT_WORD (output_bfd, (bfd_vma) -1, s->contents + i * HASH_ENTRY_SIZE);
143859024Sobrien      s->_raw_size = bucketcount * HASH_ENTRY_SIZE;
143959024Sobrien
144059024Sobrien      sunos_hash_table (info)->bucketcount = bucketcount;
144159024Sobrien
144259024Sobrien      /* Scan all the symbols, place them in the dynamic symbol table,
144359024Sobrien	 and build the dynamic hash table.  We reuse dynsymcount as a
144459024Sobrien	 counter for the number of symbols we have added so far.  */
144559024Sobrien      sunos_hash_table (info)->dynsymcount = 0;
144659024Sobrien      sunos_link_hash_traverse (sunos_hash_table (info),
144759024Sobrien				sunos_scan_dynamic_symbol,
144859024Sobrien				(PTR) info);
144959024Sobrien      BFD_ASSERT (sunos_hash_table (info)->dynsymcount == dynsymcount);
145059024Sobrien
145159024Sobrien      /* The SunOS native linker seems to align the total size of the
145259024Sobrien	 symbol strings to a multiple of 8.  I don't know if this is
145359024Sobrien	 important, but it can't hurt much.  */
145459024Sobrien      s = bfd_get_section_by_name (dynobj, ".dynstr");
145559024Sobrien      BFD_ASSERT (s != NULL);
145659024Sobrien      if ((s->_raw_size & 7) != 0)
145759024Sobrien	{
145859024Sobrien	  bfd_size_type add;
145959024Sobrien	  bfd_byte *contents;
146059024Sobrien
146159024Sobrien	  add = 8 - (s->_raw_size & 7);
146259024Sobrien	  contents = (bfd_byte *) bfd_realloc (s->contents,
146389857Sobrien					       s->_raw_size + add);
146459024Sobrien	  if (contents == NULL)
1465130561Sobrien	    return FALSE;
146659024Sobrien	  memset (contents + s->_raw_size, 0, (size_t) add);
146759024Sobrien	  s->contents = contents;
146859024Sobrien	  s->_raw_size += add;
146959024Sobrien	}
147059024Sobrien    }
147159024Sobrien
147259024Sobrien  /* Now that we have worked out the sizes of the procedure linkage
147359024Sobrien     table and the dynamic relocs, allocate storage for them.  */
147459024Sobrien  s = bfd_get_section_by_name (dynobj, ".plt");
147559024Sobrien  BFD_ASSERT (s != NULL);
147659024Sobrien  if (s->_raw_size != 0)
147759024Sobrien    {
147859024Sobrien      s->contents = (bfd_byte *) bfd_alloc (dynobj, s->_raw_size);
147959024Sobrien      if (s->contents == NULL)
1480130561Sobrien	return FALSE;
148159024Sobrien
148259024Sobrien      /* Fill in the first entry in the table.  */
148359024Sobrien      switch (bfd_get_arch (dynobj))
148459024Sobrien	{
148559024Sobrien	case bfd_arch_sparc:
148659024Sobrien	  memcpy (s->contents, sparc_plt_first_entry, SPARC_PLT_ENTRY_SIZE);
148759024Sobrien	  break;
148859024Sobrien
148959024Sobrien	case bfd_arch_m68k:
149059024Sobrien	  memcpy (s->contents, m68k_plt_first_entry, M68K_PLT_ENTRY_SIZE);
149159024Sobrien	  break;
149259024Sobrien
149359024Sobrien	default:
149459024Sobrien	  abort ();
149559024Sobrien	}
149659024Sobrien    }
149759024Sobrien
149859024Sobrien  s = bfd_get_section_by_name (dynobj, ".dynrel");
149959024Sobrien  if (s->_raw_size != 0)
150059024Sobrien    {
150159024Sobrien      s->contents = (bfd_byte *) bfd_alloc (dynobj, s->_raw_size);
150259024Sobrien      if (s->contents == NULL)
1503130561Sobrien	return FALSE;
150459024Sobrien    }
150559024Sobrien  /* We use the reloc_count field to keep track of how many of the
150659024Sobrien     relocs we have output so far.  */
150759024Sobrien  s->reloc_count = 0;
150859024Sobrien
150959024Sobrien  /* Make space for the global offset table.  */
151059024Sobrien  s = bfd_get_section_by_name (dynobj, ".got");
151159024Sobrien  s->contents = (bfd_byte *) bfd_alloc (dynobj, s->_raw_size);
151259024Sobrien  if (s->contents == NULL)
1513130561Sobrien    return FALSE;
151459024Sobrien
151559024Sobrien  *sneedptr = bfd_get_section_by_name (dynobj, ".need");
151659024Sobrien  *srulesptr = bfd_get_section_by_name (dynobj, ".rules");
151759024Sobrien
1518130561Sobrien  return TRUE;
151959024Sobrien}
152059024Sobrien
152159024Sobrien/* Scan the relocs for an input section.  */
152259024Sobrien
1523130561Sobrienstatic bfd_boolean
152459024Sobriensunos_scan_relocs (info, abfd, sec, rel_size)
152559024Sobrien     struct bfd_link_info *info;
152659024Sobrien     bfd *abfd;
152759024Sobrien     asection *sec;
152859024Sobrien     bfd_size_type rel_size;
152959024Sobrien{
153059024Sobrien  PTR relocs;
153159024Sobrien  PTR free_relocs = NULL;
153259024Sobrien
153359024Sobrien  if (rel_size == 0)
1534130561Sobrien    return TRUE;
153559024Sobrien
153659024Sobrien  if (! info->keep_memory)
153789857Sobrien    relocs = free_relocs = bfd_malloc (rel_size);
153859024Sobrien  else
153959024Sobrien    {
154059024Sobrien      struct aout_section_data_struct *n;
154189857Sobrien      bfd_size_type amt = sizeof (struct aout_section_data_struct);
154259024Sobrien
154389857Sobrien      n = (struct aout_section_data_struct *) bfd_alloc (abfd, amt);
154459024Sobrien      if (n == NULL)
154559024Sobrien	relocs = NULL;
154659024Sobrien      else
154759024Sobrien	{
154859024Sobrien	  set_aout_section_data (sec, n);
154989857Sobrien	  relocs = bfd_malloc (rel_size);
155059024Sobrien	  aout_section_data (sec)->relocs = relocs;
155159024Sobrien	}
155259024Sobrien    }
155359024Sobrien  if (relocs == NULL)
1554130561Sobrien    return FALSE;
155559024Sobrien
155659024Sobrien  if (bfd_seek (abfd, sec->rel_filepos, SEEK_SET) != 0
155789857Sobrien      || bfd_bread (relocs, rel_size, abfd) != rel_size)
155859024Sobrien    goto error_return;
155959024Sobrien
156059024Sobrien  if (obj_reloc_entry_size (abfd) == RELOC_STD_SIZE)
156159024Sobrien    {
156259024Sobrien      if (! sunos_scan_std_relocs (info, abfd, sec,
156359024Sobrien				   (struct reloc_std_external *) relocs,
156459024Sobrien				   rel_size))
156559024Sobrien	goto error_return;
156659024Sobrien    }
156759024Sobrien  else
156859024Sobrien    {
156959024Sobrien      if (! sunos_scan_ext_relocs (info, abfd, sec,
157059024Sobrien				   (struct reloc_ext_external *) relocs,
157159024Sobrien				   rel_size))
157259024Sobrien	goto error_return;
157359024Sobrien    }
157459024Sobrien
157559024Sobrien  if (free_relocs != NULL)
157659024Sobrien    free (free_relocs);
157759024Sobrien
1578130561Sobrien  return TRUE;
157959024Sobrien
158059024Sobrien error_return:
158159024Sobrien  if (free_relocs != NULL)
158259024Sobrien    free (free_relocs);
1583130561Sobrien  return FALSE;
158459024Sobrien}
158559024Sobrien
158659024Sobrien/* Scan the relocs for an input section using standard relocs.  We
158759024Sobrien   need to figure out what to do for each reloc against a dynamic
158859024Sobrien   symbol.  If the symbol is in the .text section, an entry is made in
158959024Sobrien   the procedure linkage table.  Note that this will do the wrong
159059024Sobrien   thing if the symbol is actually data; I don't think the Sun 3
159159024Sobrien   native linker handles this case correctly either.  If the symbol is
159259024Sobrien   not in the .text section, we must preserve the reloc as a dynamic
159359024Sobrien   reloc.  FIXME: We should also handle the PIC relocs here by
159459024Sobrien   building global offset table entries.  */
159559024Sobrien
1596130561Sobrienstatic bfd_boolean
159759024Sobriensunos_scan_std_relocs (info, abfd, sec, relocs, rel_size)
159859024Sobrien     struct bfd_link_info *info;
159959024Sobrien     bfd *abfd;
160084865Sobrien     asection *sec ATTRIBUTE_UNUSED;
160159024Sobrien     const struct reloc_std_external *relocs;
160259024Sobrien     bfd_size_type rel_size;
160359024Sobrien{
160459024Sobrien  bfd *dynobj;
160559024Sobrien  asection *splt = NULL;
160659024Sobrien  asection *srel = NULL;
160759024Sobrien  struct sunos_link_hash_entry **sym_hashes;
160859024Sobrien  const struct reloc_std_external *rel, *relend;
160959024Sobrien
161059024Sobrien  /* We only know how to handle m68k plt entries.  */
161159024Sobrien  if (bfd_get_arch (abfd) != bfd_arch_m68k)
161259024Sobrien    {
161359024Sobrien      bfd_set_error (bfd_error_invalid_target);
1614130561Sobrien      return FALSE;
161559024Sobrien    }
161659024Sobrien
161759024Sobrien  dynobj = NULL;
161859024Sobrien
161959024Sobrien  sym_hashes = (struct sunos_link_hash_entry **) obj_aout_sym_hashes (abfd);
162059024Sobrien
162159024Sobrien  relend = relocs + rel_size / RELOC_STD_SIZE;
162259024Sobrien  for (rel = relocs; rel < relend; rel++)
162359024Sobrien    {
162459024Sobrien      int r_index;
162559024Sobrien      struct sunos_link_hash_entry *h;
162659024Sobrien
162759024Sobrien      /* We only want relocs against external symbols.  */
162859024Sobrien      if (bfd_header_big_endian (abfd))
162959024Sobrien	{
163059024Sobrien	  if ((rel->r_type[0] & RELOC_STD_BITS_EXTERN_BIG) == 0)
163159024Sobrien	    continue;
163259024Sobrien	}
163359024Sobrien      else
163459024Sobrien	{
163559024Sobrien	  if ((rel->r_type[0] & RELOC_STD_BITS_EXTERN_LITTLE) == 0)
163659024Sobrien	    continue;
163759024Sobrien	}
163859024Sobrien
163959024Sobrien      /* Get the symbol index.  */
164059024Sobrien      if (bfd_header_big_endian (abfd))
164159024Sobrien	r_index = ((rel->r_index[0] << 16)
164259024Sobrien		   | (rel->r_index[1] << 8)
164359024Sobrien		   | rel->r_index[2]);
164459024Sobrien      else
164559024Sobrien	r_index = ((rel->r_index[2] << 16)
164659024Sobrien		   | (rel->r_index[1] << 8)
164759024Sobrien		   | rel->r_index[0]);
164859024Sobrien
164959024Sobrien      /* Get the hash table entry.  */
165059024Sobrien      h = sym_hashes[r_index];
165159024Sobrien      if (h == NULL)
165259024Sobrien	{
165359024Sobrien	  /* This should not normally happen, but it will in any case
165459024Sobrien	     be caught in the relocation phase.  */
165559024Sobrien	  continue;
165659024Sobrien	}
165759024Sobrien
165859024Sobrien      /* At this point common symbols have already been allocated, so
165959024Sobrien	 we don't have to worry about them.  We need to consider that
166059024Sobrien	 we may have already seen this symbol and marked it undefined;
166159024Sobrien	 if the symbol is really undefined, then SUNOS_DEF_DYNAMIC
166259024Sobrien	 will be zero.  */
166359024Sobrien      if (h->root.root.type != bfd_link_hash_defined
166459024Sobrien	  && h->root.root.type != bfd_link_hash_defweak
166559024Sobrien	  && h->root.root.type != bfd_link_hash_undefined)
166659024Sobrien	continue;
166759024Sobrien
166859024Sobrien      if ((h->flags & SUNOS_DEF_DYNAMIC) == 0
166959024Sobrien	  || (h->flags & SUNOS_DEF_REGULAR) != 0)
167059024Sobrien	continue;
167159024Sobrien
167259024Sobrien      if (dynobj == NULL)
167359024Sobrien	{
167459024Sobrien	  asection *sgot;
167559024Sobrien
1676130561Sobrien	  if (! sunos_create_dynamic_sections (abfd, info, FALSE))
1677130561Sobrien	    return FALSE;
167859024Sobrien	  dynobj = sunos_hash_table (info)->dynobj;
167959024Sobrien	  splt = bfd_get_section_by_name (dynobj, ".plt");
168059024Sobrien	  srel = bfd_get_section_by_name (dynobj, ".dynrel");
168159024Sobrien	  BFD_ASSERT (splt != NULL && srel != NULL);
168259024Sobrien
168359024Sobrien	  sgot = bfd_get_section_by_name (dynobj, ".got");
168459024Sobrien	  BFD_ASSERT (sgot != NULL);
168559024Sobrien	  if (sgot->_raw_size == 0)
168659024Sobrien	    sgot->_raw_size = BYTES_IN_WORD;
1687130561Sobrien	  sunos_hash_table (info)->got_needed = TRUE;
168859024Sobrien	}
168959024Sobrien
169059024Sobrien      BFD_ASSERT ((h->flags & SUNOS_REF_REGULAR) != 0);
169159024Sobrien      BFD_ASSERT (h->plt_offset != 0
169259024Sobrien		  || ((h->root.root.type == bfd_link_hash_defined
169359024Sobrien		       || h->root.root.type == bfd_link_hash_defweak)
169459024Sobrien		      ? (h->root.root.u.def.section->owner->flags
169559024Sobrien			 & DYNAMIC) != 0
169659024Sobrien		      : (h->root.root.u.undef.abfd->flags & DYNAMIC) != 0));
169759024Sobrien
169859024Sobrien      /* This reloc is against a symbol defined only by a dynamic
169959024Sobrien	 object.  */
170059024Sobrien
170159024Sobrien      if (h->root.root.type == bfd_link_hash_undefined)
170259024Sobrien	{
170359024Sobrien	  /* Presumably this symbol was marked as being undefined by
170459024Sobrien	     an earlier reloc.  */
170559024Sobrien	  srel->_raw_size += RELOC_STD_SIZE;
170659024Sobrien	}
170759024Sobrien      else if ((h->root.root.u.def.section->flags & SEC_CODE) == 0)
170859024Sobrien	{
170959024Sobrien	  bfd *sub;
171059024Sobrien
171159024Sobrien	  /* This reloc is not in the .text section.  It must be
171259024Sobrien	     copied into the dynamic relocs.  We mark the symbol as
171359024Sobrien	     being undefined.  */
171459024Sobrien	  srel->_raw_size += RELOC_STD_SIZE;
171559024Sobrien	  sub = h->root.root.u.def.section->owner;
171659024Sobrien	  h->root.root.type = bfd_link_hash_undefined;
171759024Sobrien	  h->root.root.u.undef.abfd = sub;
171859024Sobrien	}
171959024Sobrien      else
172059024Sobrien	{
172159024Sobrien	  /* This symbol is in the .text section.  We must give it an
172259024Sobrien	     entry in the procedure linkage table, if we have not
172359024Sobrien	     already done so.  We change the definition of the symbol
172459024Sobrien	     to the .plt section; this will cause relocs against it to
172559024Sobrien	     be handled correctly.  */
172659024Sobrien	  if (h->plt_offset == 0)
172759024Sobrien	    {
172859024Sobrien	      if (splt->_raw_size == 0)
172959024Sobrien		splt->_raw_size = M68K_PLT_ENTRY_SIZE;
173059024Sobrien	      h->plt_offset = splt->_raw_size;
173159024Sobrien
173259024Sobrien	      if ((h->flags & SUNOS_DEF_REGULAR) == 0)
173359024Sobrien		{
173459024Sobrien		  h->root.root.u.def.section = splt;
173559024Sobrien		  h->root.root.u.def.value = splt->_raw_size;
173659024Sobrien		}
173759024Sobrien
173859024Sobrien	      splt->_raw_size += M68K_PLT_ENTRY_SIZE;
173959024Sobrien
174059024Sobrien	      /* We may also need a dynamic reloc entry.  */
174159024Sobrien	      if ((h->flags & SUNOS_DEF_REGULAR) == 0)
174259024Sobrien		srel->_raw_size += RELOC_STD_SIZE;
174359024Sobrien	    }
174459024Sobrien	}
174559024Sobrien    }
174659024Sobrien
1747130561Sobrien  return TRUE;
174859024Sobrien}
174959024Sobrien
175059024Sobrien/* Scan the relocs for an input section using extended relocs.  We
175159024Sobrien   need to figure out what to do for each reloc against a dynamic
175259024Sobrien   symbol.  If the reloc is a WDISP30, and the symbol is in the .text
175359024Sobrien   section, an entry is made in the procedure linkage table.
175459024Sobrien   Otherwise, we must preserve the reloc as a dynamic reloc.  */
175559024Sobrien
1756130561Sobrienstatic bfd_boolean
175759024Sobriensunos_scan_ext_relocs (info, abfd, sec, relocs, rel_size)
175859024Sobrien     struct bfd_link_info *info;
175959024Sobrien     bfd *abfd;
176084865Sobrien     asection *sec ATTRIBUTE_UNUSED;
176159024Sobrien     const struct reloc_ext_external *relocs;
176259024Sobrien     bfd_size_type rel_size;
176359024Sobrien{
176459024Sobrien  bfd *dynobj;
176559024Sobrien  struct sunos_link_hash_entry **sym_hashes;
176659024Sobrien  const struct reloc_ext_external *rel, *relend;
176759024Sobrien  asection *splt = NULL;
176859024Sobrien  asection *sgot = NULL;
176959024Sobrien  asection *srel = NULL;
177089857Sobrien  bfd_size_type amt;
177159024Sobrien
177259024Sobrien  /* We only know how to handle SPARC plt entries.  */
177359024Sobrien  if (bfd_get_arch (abfd) != bfd_arch_sparc)
177459024Sobrien    {
177559024Sobrien      bfd_set_error (bfd_error_invalid_target);
1776130561Sobrien      return FALSE;
177759024Sobrien    }
177859024Sobrien
177959024Sobrien  dynobj = NULL;
178059024Sobrien
178159024Sobrien  sym_hashes = (struct sunos_link_hash_entry **) obj_aout_sym_hashes (abfd);
178259024Sobrien
178359024Sobrien  relend = relocs + rel_size / RELOC_EXT_SIZE;
178459024Sobrien  for (rel = relocs; rel < relend; rel++)
178559024Sobrien    {
178659024Sobrien      unsigned int r_index;
178759024Sobrien      int r_extern;
178859024Sobrien      int r_type;
178959024Sobrien      struct sunos_link_hash_entry *h = NULL;
179059024Sobrien
179159024Sobrien      /* Swap in the reloc information.  */
179259024Sobrien      if (bfd_header_big_endian (abfd))
179359024Sobrien	{
179459024Sobrien	  r_index = ((rel->r_index[0] << 16)
179559024Sobrien		     | (rel->r_index[1] << 8)
179659024Sobrien		     | rel->r_index[2]);
179759024Sobrien	  r_extern = (0 != (rel->r_type[0] & RELOC_EXT_BITS_EXTERN_BIG));
179859024Sobrien	  r_type = ((rel->r_type[0] & RELOC_EXT_BITS_TYPE_BIG)
179959024Sobrien		    >> RELOC_EXT_BITS_TYPE_SH_BIG);
180059024Sobrien	}
180159024Sobrien      else
180259024Sobrien	{
180359024Sobrien	  r_index = ((rel->r_index[2] << 16)
180459024Sobrien		     | (rel->r_index[1] << 8)
180559024Sobrien		     | rel->r_index[0]);
180659024Sobrien	  r_extern = (0 != (rel->r_type[0] & RELOC_EXT_BITS_EXTERN_LITTLE));
180759024Sobrien	  r_type = ((rel->r_type[0] & RELOC_EXT_BITS_TYPE_LITTLE)
180859024Sobrien		    >> RELOC_EXT_BITS_TYPE_SH_LITTLE);
180959024Sobrien	}
181059024Sobrien
181159024Sobrien      if (r_extern)
181259024Sobrien	{
181359024Sobrien	  h = sym_hashes[r_index];
181459024Sobrien	  if (h == NULL)
181559024Sobrien	    {
181659024Sobrien	      /* This should not normally happen, but it will in any
181759024Sobrien		 case be caught in the relocation phase.  */
181859024Sobrien	      continue;
181959024Sobrien	    }
182059024Sobrien	}
182159024Sobrien
182259024Sobrien      /* If this is a base relative reloc, we need to make an entry in
1823130561Sobrien	 the .got section.  */
182459024Sobrien      if (r_type == RELOC_BASE10
182559024Sobrien	  || r_type == RELOC_BASE13
182659024Sobrien	  || r_type == RELOC_BASE22)
182759024Sobrien	{
182859024Sobrien	  if (dynobj == NULL)
182959024Sobrien	    {
1830130561Sobrien	      if (! sunos_create_dynamic_sections (abfd, info, FALSE))
1831130561Sobrien		return FALSE;
183259024Sobrien	      dynobj = sunos_hash_table (info)->dynobj;
183359024Sobrien	      splt = bfd_get_section_by_name (dynobj, ".plt");
183459024Sobrien	      sgot = bfd_get_section_by_name (dynobj, ".got");
183559024Sobrien	      srel = bfd_get_section_by_name (dynobj, ".dynrel");
183659024Sobrien	      BFD_ASSERT (splt != NULL && sgot != NULL && srel != NULL);
183759024Sobrien
183859024Sobrien	      /* Make sure we have an initial entry in the .got table.  */
183959024Sobrien	      if (sgot->_raw_size == 0)
184059024Sobrien		sgot->_raw_size = BYTES_IN_WORD;
1841130561Sobrien	      sunos_hash_table (info)->got_needed = TRUE;
184259024Sobrien	    }
184359024Sobrien
184459024Sobrien	  if (r_extern)
184559024Sobrien	    {
184659024Sobrien	      if (h->got_offset != 0)
184759024Sobrien		continue;
184859024Sobrien
184959024Sobrien	      h->got_offset = sgot->_raw_size;
185059024Sobrien	    }
185159024Sobrien	  else
185259024Sobrien	    {
185359024Sobrien	      if (r_index >= bfd_get_symcount (abfd))
185459024Sobrien		{
185559024Sobrien		  /* This is abnormal, but should be caught in the
185659024Sobrien		     relocation phase.  */
185759024Sobrien		  continue;
185859024Sobrien		}
185959024Sobrien
186059024Sobrien	      if (adata (abfd).local_got_offsets == NULL)
186159024Sobrien		{
186289857Sobrien		  amt = bfd_get_symcount (abfd);
186389857Sobrien		  amt *= sizeof (bfd_vma);
186459024Sobrien		  adata (abfd).local_got_offsets =
186589857Sobrien		    (bfd_vma *) bfd_zalloc (abfd, amt);
186659024Sobrien		  if (adata (abfd).local_got_offsets == NULL)
1867130561Sobrien		    return FALSE;
186859024Sobrien		}
186959024Sobrien
187059024Sobrien	      if (adata (abfd).local_got_offsets[r_index] != 0)
187159024Sobrien		continue;
187259024Sobrien
187359024Sobrien	      adata (abfd).local_got_offsets[r_index] = sgot->_raw_size;
187459024Sobrien	    }
187559024Sobrien
187659024Sobrien	  sgot->_raw_size += BYTES_IN_WORD;
187759024Sobrien
187859024Sobrien	  /* If we are making a shared library, or if the symbol is
187959024Sobrien	     defined by a dynamic object, we will need a dynamic reloc
188059024Sobrien	     entry.  */
188159024Sobrien	  if (info->shared
188259024Sobrien	      || (h != NULL
188359024Sobrien		  && (h->flags & SUNOS_DEF_DYNAMIC) != 0
188459024Sobrien		  && (h->flags & SUNOS_DEF_REGULAR) == 0))
188559024Sobrien	    srel->_raw_size += RELOC_EXT_SIZE;
188659024Sobrien
188759024Sobrien	  continue;
188859024Sobrien	}
188959024Sobrien
189059024Sobrien      /* Otherwise, we are only interested in relocs against symbols
1891130561Sobrien	 defined in dynamic objects but not in regular objects.  We
1892130561Sobrien	 only need to consider relocs against external symbols.  */
189359024Sobrien      if (! r_extern)
189459024Sobrien	{
189559024Sobrien	  /* But, if we are creating a shared library, we need to
1896130561Sobrien	     generate an absolute reloc.  */
189759024Sobrien	  if (info->shared)
189859024Sobrien	    {
189959024Sobrien	      if (dynobj == NULL)
190059024Sobrien		{
1901130561Sobrien		  if (! sunos_create_dynamic_sections (abfd, info, TRUE))
1902130561Sobrien		    return FALSE;
190359024Sobrien		  dynobj = sunos_hash_table (info)->dynobj;
190459024Sobrien		  splt = bfd_get_section_by_name (dynobj, ".plt");
190559024Sobrien		  sgot = bfd_get_section_by_name (dynobj, ".got");
190659024Sobrien		  srel = bfd_get_section_by_name (dynobj, ".dynrel");
190759024Sobrien		  BFD_ASSERT (splt != NULL && sgot != NULL && srel != NULL);
190859024Sobrien		}
190959024Sobrien
191059024Sobrien	      srel->_raw_size += RELOC_EXT_SIZE;
191159024Sobrien	    }
191259024Sobrien
191359024Sobrien	  continue;
191459024Sobrien	}
191559024Sobrien
191659024Sobrien      /* At this point common symbols have already been allocated, so
191759024Sobrien	 we don't have to worry about them.  We need to consider that
191859024Sobrien	 we may have already seen this symbol and marked it undefined;
191959024Sobrien	 if the symbol is really undefined, then SUNOS_DEF_DYNAMIC
192059024Sobrien	 will be zero.  */
192159024Sobrien      if (h->root.root.type != bfd_link_hash_defined
192259024Sobrien	  && h->root.root.type != bfd_link_hash_defweak
192359024Sobrien	  && h->root.root.type != bfd_link_hash_undefined)
192459024Sobrien	continue;
192559024Sobrien
192659024Sobrien      if (r_type != RELOC_JMP_TBL
192759024Sobrien	  && ! info->shared
192859024Sobrien	  && ((h->flags & SUNOS_DEF_DYNAMIC) == 0
192959024Sobrien	      || (h->flags & SUNOS_DEF_REGULAR) != 0))
193059024Sobrien	continue;
193159024Sobrien
193259024Sobrien      if (r_type == RELOC_JMP_TBL
193359024Sobrien	  && ! info->shared
193459024Sobrien	  && (h->flags & SUNOS_DEF_DYNAMIC) == 0
193559024Sobrien	  && (h->flags & SUNOS_DEF_REGULAR) == 0)
193659024Sobrien	{
193759024Sobrien	  /* This symbol is apparently undefined.  Don't do anything
1938130561Sobrien	     here; just let the relocation routine report an undefined
1939130561Sobrien	     symbol.  */
194059024Sobrien	  continue;
194159024Sobrien	}
194259024Sobrien
194359024Sobrien      if (strcmp (h->root.root.root.string, "__GLOBAL_OFFSET_TABLE_") == 0)
194459024Sobrien	continue;
194559024Sobrien
194659024Sobrien      if (dynobj == NULL)
194759024Sobrien	{
1948130561Sobrien	  if (! sunos_create_dynamic_sections (abfd, info, FALSE))
1949130561Sobrien	    return FALSE;
195059024Sobrien	  dynobj = sunos_hash_table (info)->dynobj;
195159024Sobrien	  splt = bfd_get_section_by_name (dynobj, ".plt");
195259024Sobrien	  sgot = bfd_get_section_by_name (dynobj, ".got");
195359024Sobrien	  srel = bfd_get_section_by_name (dynobj, ".dynrel");
195459024Sobrien	  BFD_ASSERT (splt != NULL && sgot != NULL && srel != NULL);
195559024Sobrien
195659024Sobrien	  /* Make sure we have an initial entry in the .got table.  */
195759024Sobrien	  if (sgot->_raw_size == 0)
195859024Sobrien	    sgot->_raw_size = BYTES_IN_WORD;
1959130561Sobrien	  sunos_hash_table (info)->got_needed = TRUE;
196059024Sobrien	}
196159024Sobrien
196259024Sobrien      BFD_ASSERT (r_type == RELOC_JMP_TBL
196359024Sobrien		  || info->shared
196459024Sobrien		  || (h->flags & SUNOS_REF_REGULAR) != 0);
196559024Sobrien      BFD_ASSERT (r_type == RELOC_JMP_TBL
196659024Sobrien		  || info->shared
196759024Sobrien		  || h->plt_offset != 0
196859024Sobrien		  || ((h->root.root.type == bfd_link_hash_defined
196959024Sobrien		       || h->root.root.type == bfd_link_hash_defweak)
197059024Sobrien		      ? (h->root.root.u.def.section->owner->flags
197159024Sobrien			 & DYNAMIC) != 0
197259024Sobrien		      : (h->root.root.u.undef.abfd->flags & DYNAMIC) != 0));
197359024Sobrien
197459024Sobrien      /* This reloc is against a symbol defined only by a dynamic
197559024Sobrien	 object, or it is a jump table reloc from PIC compiled code.  */
197659024Sobrien
197759024Sobrien      if (r_type != RELOC_JMP_TBL
197859024Sobrien	  && h->root.root.type == bfd_link_hash_undefined)
197959024Sobrien	{
198059024Sobrien	  /* Presumably this symbol was marked as being undefined by
198159024Sobrien	     an earlier reloc.  */
198259024Sobrien	  srel->_raw_size += RELOC_EXT_SIZE;
198359024Sobrien	}
198459024Sobrien      else if (r_type != RELOC_JMP_TBL
198559024Sobrien	       && (h->root.root.u.def.section->flags & SEC_CODE) == 0)
198659024Sobrien	{
198759024Sobrien	  bfd *sub;
198859024Sobrien
198959024Sobrien	  /* This reloc is not in the .text section.  It must be
199059024Sobrien	     copied into the dynamic relocs.  We mark the symbol as
199159024Sobrien	     being undefined.  */
199259024Sobrien	  srel->_raw_size += RELOC_EXT_SIZE;
199359024Sobrien	  if ((h->flags & SUNOS_DEF_REGULAR) == 0)
199459024Sobrien	    {
199559024Sobrien	      sub = h->root.root.u.def.section->owner;
199659024Sobrien	      h->root.root.type = bfd_link_hash_undefined;
199759024Sobrien	      h->root.root.u.undef.abfd = sub;
199859024Sobrien	    }
199959024Sobrien	}
200059024Sobrien      else
200159024Sobrien	{
200259024Sobrien	  /* This symbol is in the .text section.  We must give it an
200359024Sobrien	     entry in the procedure linkage table, if we have not
200459024Sobrien	     already done so.  We change the definition of the symbol
200559024Sobrien	     to the .plt section; this will cause relocs against it to
200659024Sobrien	     be handled correctly.  */
200759024Sobrien	  if (h->plt_offset == 0)
200859024Sobrien	    {
200959024Sobrien	      if (splt->_raw_size == 0)
201059024Sobrien		splt->_raw_size = SPARC_PLT_ENTRY_SIZE;
201159024Sobrien	      h->plt_offset = splt->_raw_size;
201259024Sobrien
201359024Sobrien	      if ((h->flags & SUNOS_DEF_REGULAR) == 0)
201459024Sobrien		{
201559024Sobrien		  if (h->root.root.type == bfd_link_hash_undefined)
201659024Sobrien		    h->root.root.type = bfd_link_hash_defined;
201759024Sobrien		  h->root.root.u.def.section = splt;
201859024Sobrien		  h->root.root.u.def.value = splt->_raw_size;
201959024Sobrien		}
202059024Sobrien
202159024Sobrien	      splt->_raw_size += SPARC_PLT_ENTRY_SIZE;
202259024Sobrien
202359024Sobrien	      /* We will also need a dynamic reloc entry, unless this
2024130561Sobrien		 is a JMP_TBL reloc produced by linking PIC compiled
2025130561Sobrien		 code, and we are not making a shared library.  */
202659024Sobrien	      if (info->shared || (h->flags & SUNOS_DEF_REGULAR) == 0)
202759024Sobrien		srel->_raw_size += RELOC_EXT_SIZE;
202859024Sobrien	    }
202959024Sobrien
203059024Sobrien	  /* If we are creating a shared library, we need to copy over
2031130561Sobrien	     any reloc other than a jump table reloc.  */
203259024Sobrien	  if (info->shared && r_type != RELOC_JMP_TBL)
203359024Sobrien	    srel->_raw_size += RELOC_EXT_SIZE;
203459024Sobrien	}
203559024Sobrien    }
203659024Sobrien
2037130561Sobrien  return TRUE;
203859024Sobrien}
203959024Sobrien
204059024Sobrien/* Build the hash table of dynamic symbols, and to mark as written all
204159024Sobrien   symbols from dynamic objects which we do not plan to write out.  */
204259024Sobrien
2043130561Sobrienstatic bfd_boolean
204459024Sobriensunos_scan_dynamic_symbol (h, data)
204559024Sobrien     struct sunos_link_hash_entry *h;
204659024Sobrien     PTR data;
204759024Sobrien{
204859024Sobrien  struct bfd_link_info *info = (struct bfd_link_info *) data;
204959024Sobrien
205094536Sobrien  if (h->root.root.type == bfd_link_hash_warning)
205194536Sobrien    h = (struct sunos_link_hash_entry *) h->root.root.u.i.link;
205294536Sobrien
205359024Sobrien  /* Set the written flag for symbols we do not want to write out as
205459024Sobrien     part of the regular symbol table.  This is all symbols which are
205559024Sobrien     not defined in a regular object file.  For some reason symbols
205659024Sobrien     which are referenced by a regular object and defined by a dynamic
205759024Sobrien     object do not seem to show up in the regular symbol table.  It is
205859024Sobrien     possible for a symbol to have only SUNOS_REF_REGULAR set here, it
205959024Sobrien     is an undefined symbol which was turned into a common symbol
206059024Sobrien     because it was found in an archive object which was not included
206159024Sobrien     in the link.  */
206259024Sobrien  if ((h->flags & SUNOS_DEF_REGULAR) == 0
206359024Sobrien      && (h->flags & SUNOS_DEF_DYNAMIC) != 0
206459024Sobrien      && strcmp (h->root.root.root.string, "__DYNAMIC") != 0)
2065130561Sobrien    h->root.written = TRUE;
206659024Sobrien
206759024Sobrien  /* If this symbol is defined by a dynamic object and referenced by a
206859024Sobrien     regular object, see whether we gave it a reasonable value while
206959024Sobrien     scanning the relocs.  */
207059024Sobrien
207159024Sobrien  if ((h->flags & SUNOS_DEF_REGULAR) == 0
207259024Sobrien      && (h->flags & SUNOS_DEF_DYNAMIC) != 0
207359024Sobrien      && (h->flags & SUNOS_REF_REGULAR) != 0)
207459024Sobrien    {
207559024Sobrien      if ((h->root.root.type == bfd_link_hash_defined
207659024Sobrien	   || h->root.root.type == bfd_link_hash_defweak)
207759024Sobrien	  && ((h->root.root.u.def.section->owner->flags & DYNAMIC) != 0)
207859024Sobrien	  && h->root.root.u.def.section->output_section == NULL)
207959024Sobrien	{
208059024Sobrien	  bfd *sub;
208159024Sobrien
208259024Sobrien	  /* This symbol is currently defined in a dynamic section
208359024Sobrien	     which is not being put into the output file.  This
208459024Sobrien	     implies that there is no reloc against the symbol.  I'm
208559024Sobrien	     not sure why this case would ever occur.  In any case, we
208659024Sobrien	     change the symbol to be undefined.  */
208759024Sobrien	  sub = h->root.root.u.def.section->owner;
208859024Sobrien	  h->root.root.type = bfd_link_hash_undefined;
208959024Sobrien	  h->root.root.u.undef.abfd = sub;
209059024Sobrien	}
209159024Sobrien    }
209259024Sobrien
209359024Sobrien  /* If this symbol is defined or referenced by a regular file, add it
209459024Sobrien     to the dynamic symbols.  */
209559024Sobrien  if ((h->flags & (SUNOS_DEF_REGULAR | SUNOS_REF_REGULAR)) != 0)
209659024Sobrien    {
209759024Sobrien      asection *s;
209859024Sobrien      size_t len;
209959024Sobrien      bfd_byte *contents;
210059024Sobrien      unsigned char *name;
210159024Sobrien      unsigned long hash;
210259024Sobrien      bfd *dynobj;
210359024Sobrien
210459024Sobrien      BFD_ASSERT (h->dynindx == -2);
210559024Sobrien
210659024Sobrien      dynobj = sunos_hash_table (info)->dynobj;
210759024Sobrien
210859024Sobrien      h->dynindx = sunos_hash_table (info)->dynsymcount;
210959024Sobrien      ++sunos_hash_table (info)->dynsymcount;
211059024Sobrien
211159024Sobrien      len = strlen (h->root.root.root.string);
211259024Sobrien
211359024Sobrien      /* We don't bother to construct a BFD hash table for the strings
211459024Sobrien	 which are the names of the dynamic symbols.  Using a hash
211559024Sobrien	 table for the regular symbols is beneficial, because the
211659024Sobrien	 regular symbols includes the debugging symbols, which have
211759024Sobrien	 long names and are often duplicated in several object files.
211859024Sobrien	 There are no debugging symbols in the dynamic symbols.  */
211959024Sobrien      s = bfd_get_section_by_name (dynobj, ".dynstr");
212059024Sobrien      BFD_ASSERT (s != NULL);
212159024Sobrien      contents = (bfd_byte *) bfd_realloc (s->contents,
212259024Sobrien					   s->_raw_size + len + 1);
212359024Sobrien      if (contents == NULL)
2124130561Sobrien	return FALSE;
212559024Sobrien      s->contents = contents;
212659024Sobrien
212759024Sobrien      h->dynstr_index = s->_raw_size;
212859024Sobrien      strcpy ((char *) contents + s->_raw_size, h->root.root.root.string);
212959024Sobrien      s->_raw_size += len + 1;
213059024Sobrien
213159024Sobrien      /* Add it to the dynamic hash table.  */
213259024Sobrien      name = (unsigned char *) h->root.root.root.string;
213359024Sobrien      hash = 0;
213459024Sobrien      while (*name != '\0')
213559024Sobrien	hash = (hash << 1) + *name++;
213659024Sobrien      hash &= 0x7fffffff;
213759024Sobrien      hash %= sunos_hash_table (info)->bucketcount;
213859024Sobrien
213959024Sobrien      s = bfd_get_section_by_name (dynobj, ".hash");
214059024Sobrien      BFD_ASSERT (s != NULL);
214159024Sobrien
214259024Sobrien      if (GET_SWORD (dynobj, s->contents + hash * HASH_ENTRY_SIZE) == -1)
214359024Sobrien	PUT_WORD (dynobj, h->dynindx, s->contents + hash * HASH_ENTRY_SIZE);
214459024Sobrien      else
214559024Sobrien	{
214659024Sobrien	  bfd_vma next;
214759024Sobrien
214859024Sobrien	  next = GET_WORD (dynobj,
214959024Sobrien			   (s->contents
215059024Sobrien			    + hash * HASH_ENTRY_SIZE
215159024Sobrien			    + BYTES_IN_WORD));
215259024Sobrien	  PUT_WORD (dynobj, s->_raw_size / HASH_ENTRY_SIZE,
215359024Sobrien		    s->contents + hash * HASH_ENTRY_SIZE + BYTES_IN_WORD);
215459024Sobrien	  PUT_WORD (dynobj, h->dynindx, s->contents + s->_raw_size);
215559024Sobrien	  PUT_WORD (dynobj, next, s->contents + s->_raw_size + BYTES_IN_WORD);
215659024Sobrien	  s->_raw_size += HASH_ENTRY_SIZE;
215759024Sobrien	}
215859024Sobrien    }
215959024Sobrien
2160130561Sobrien  return TRUE;
216159024Sobrien}
216259024Sobrien
216359024Sobrien/* Link a dynamic object.  We actually don't have anything to do at
216459024Sobrien   this point.  This entry point exists to prevent the regular linker
216559024Sobrien   code from doing anything with the object.  */
216659024Sobrien
2167130561Sobrienstatic bfd_boolean
216859024Sobriensunos_link_dynamic_object (info, abfd)
216984865Sobrien     struct bfd_link_info *info ATTRIBUTE_UNUSED;
217084865Sobrien     bfd *abfd ATTRIBUTE_UNUSED;
217159024Sobrien{
2172130561Sobrien  return TRUE;
217359024Sobrien}
217459024Sobrien
217559024Sobrien/* Write out a dynamic symbol.  This is called by the final traversal
217659024Sobrien   over the symbol table.  */
217759024Sobrien
2178130561Sobrienstatic bfd_boolean
217959024Sobriensunos_write_dynamic_symbol (output_bfd, info, harg)
218059024Sobrien     bfd *output_bfd;
218159024Sobrien     struct bfd_link_info *info;
218259024Sobrien     struct aout_link_hash_entry *harg;
218359024Sobrien{
218459024Sobrien  struct sunos_link_hash_entry *h = (struct sunos_link_hash_entry *) harg;
218559024Sobrien  int type;
218659024Sobrien  bfd_vma val;
218759024Sobrien  asection *s;
218859024Sobrien  struct external_nlist *outsym;
218959024Sobrien
219059024Sobrien  /* If this symbol is in the procedure linkage table, fill in the
219159024Sobrien     table entry.  */
219259024Sobrien  if (h->plt_offset != 0)
219359024Sobrien    {
219459024Sobrien      bfd *dynobj;
219559024Sobrien      asection *splt;
219659024Sobrien      bfd_byte *p;
219759024Sobrien      bfd_vma r_address;
219859024Sobrien
219959024Sobrien      dynobj = sunos_hash_table (info)->dynobj;
220059024Sobrien      splt = bfd_get_section_by_name (dynobj, ".plt");
220159024Sobrien      p = splt->contents + h->plt_offset;
220259024Sobrien
220359024Sobrien      s = bfd_get_section_by_name (dynobj, ".dynrel");
220459024Sobrien
220559024Sobrien      r_address = (splt->output_section->vma
220659024Sobrien		   + splt->output_offset
220759024Sobrien		   + h->plt_offset);
220859024Sobrien
220959024Sobrien      switch (bfd_get_arch (output_bfd))
221059024Sobrien	{
221159024Sobrien	case bfd_arch_sparc:
221259024Sobrien	  if (info->shared || (h->flags & SUNOS_DEF_REGULAR) == 0)
221359024Sobrien	    {
221459024Sobrien	      bfd_put_32 (output_bfd, SPARC_PLT_ENTRY_WORD0, p);
221559024Sobrien	      bfd_put_32 (output_bfd,
221659024Sobrien			  (SPARC_PLT_ENTRY_WORD1
221759024Sobrien			   + (((- (h->plt_offset + 4) >> 2)
221859024Sobrien			       & 0x3fffffff))),
221959024Sobrien			  p + 4);
222059024Sobrien	      bfd_put_32 (output_bfd, SPARC_PLT_ENTRY_WORD2 + s->reloc_count,
222159024Sobrien			  p + 8);
222259024Sobrien	    }
222359024Sobrien	  else
222459024Sobrien	    {
222559024Sobrien	      val = (h->root.root.u.def.section->output_section->vma
222659024Sobrien		     + h->root.root.u.def.section->output_offset
222759024Sobrien		     + h->root.root.u.def.value);
222859024Sobrien	      bfd_put_32 (output_bfd,
222959024Sobrien			  SPARC_PLT_PIC_WORD0 + ((val >> 10) & 0x3fffff),
223059024Sobrien			  p);
223159024Sobrien	      bfd_put_32 (output_bfd,
223259024Sobrien			  SPARC_PLT_PIC_WORD1 + (val & 0x3ff),
223359024Sobrien			  p + 4);
223459024Sobrien	      bfd_put_32 (output_bfd, SPARC_PLT_PIC_WORD2, p + 8);
223559024Sobrien	    }
223659024Sobrien	  break;
223759024Sobrien
223859024Sobrien	case bfd_arch_m68k:
223959024Sobrien	  if (! info->shared && (h->flags & SUNOS_DEF_REGULAR) != 0)
224059024Sobrien	    abort ();
224159024Sobrien	  bfd_put_16 (output_bfd, M68K_PLT_ENTRY_WORD0, p);
224259024Sobrien	  bfd_put_32 (output_bfd, (- (h->plt_offset + 2)), p + 2);
224389857Sobrien	  bfd_put_16 (output_bfd, (bfd_vma) s->reloc_count, p + 6);
224459024Sobrien	  r_address += 2;
224559024Sobrien	  break;
224659024Sobrien
224759024Sobrien	default:
224859024Sobrien	  abort ();
224959024Sobrien	}
225059024Sobrien
225159024Sobrien      /* We also need to add a jump table reloc, unless this is the
2252130561Sobrien	 result of a JMP_TBL reloc from PIC compiled code.  */
225359024Sobrien      if (info->shared || (h->flags & SUNOS_DEF_REGULAR) == 0)
225459024Sobrien	{
225559024Sobrien	  BFD_ASSERT (h->dynindx >= 0);
225659024Sobrien	  BFD_ASSERT (s->reloc_count * obj_reloc_entry_size (dynobj)
225759024Sobrien		      < s->_raw_size);
225859024Sobrien	  p = s->contents + s->reloc_count * obj_reloc_entry_size (output_bfd);
225959024Sobrien	  if (obj_reloc_entry_size (output_bfd) == RELOC_STD_SIZE)
226059024Sobrien	    {
226159024Sobrien	      struct reloc_std_external *srel;
226259024Sobrien
226359024Sobrien	      srel = (struct reloc_std_external *) p;
226459024Sobrien	      PUT_WORD (output_bfd, r_address, srel->r_address);
226559024Sobrien	      if (bfd_header_big_endian (output_bfd))
226659024Sobrien		{
226784865Sobrien		  srel->r_index[0] = (bfd_byte) (h->dynindx >> 16);
226884865Sobrien		  srel->r_index[1] = (bfd_byte) (h->dynindx >> 8);
226984865Sobrien		  srel->r_index[2] = (bfd_byte) (h->dynindx);
227059024Sobrien		  srel->r_type[0] = (RELOC_STD_BITS_EXTERN_BIG
227159024Sobrien				     | RELOC_STD_BITS_JMPTABLE_BIG);
227259024Sobrien		}
227359024Sobrien	      else
227459024Sobrien		{
227584865Sobrien		  srel->r_index[2] = (bfd_byte) (h->dynindx >> 16);
227684865Sobrien		  srel->r_index[1] = (bfd_byte) (h->dynindx >> 8);
227759024Sobrien		  srel->r_index[0] = (bfd_byte)h->dynindx;
227859024Sobrien		  srel->r_type[0] = (RELOC_STD_BITS_EXTERN_LITTLE
227959024Sobrien				     | RELOC_STD_BITS_JMPTABLE_LITTLE);
228059024Sobrien		}
228159024Sobrien	    }
228259024Sobrien	  else
228359024Sobrien	    {
228459024Sobrien	      struct reloc_ext_external *erel;
228559024Sobrien
228659024Sobrien	      erel = (struct reloc_ext_external *) p;
228759024Sobrien	      PUT_WORD (output_bfd, r_address, erel->r_address);
228859024Sobrien	      if (bfd_header_big_endian (output_bfd))
228959024Sobrien		{
229084865Sobrien		  erel->r_index[0] = (bfd_byte) (h->dynindx >> 16);
229184865Sobrien		  erel->r_index[1] = (bfd_byte) (h->dynindx >> 8);
229259024Sobrien		  erel->r_index[2] = (bfd_byte)h->dynindx;
229359024Sobrien		  erel->r_type[0] =
229459024Sobrien		    (RELOC_EXT_BITS_EXTERN_BIG
229559024Sobrien		     | (RELOC_JMP_SLOT << RELOC_EXT_BITS_TYPE_SH_BIG));
229659024Sobrien		}
229759024Sobrien	      else
229859024Sobrien		{
229984865Sobrien		  erel->r_index[2] = (bfd_byte) (h->dynindx >> 16);
230084865Sobrien		  erel->r_index[1] = (bfd_byte) (h->dynindx >> 8);
230159024Sobrien		  erel->r_index[0] = (bfd_byte)h->dynindx;
230259024Sobrien		  erel->r_type[0] =
230359024Sobrien		    (RELOC_EXT_BITS_EXTERN_LITTLE
230459024Sobrien		     | (RELOC_JMP_SLOT << RELOC_EXT_BITS_TYPE_SH_LITTLE));
230559024Sobrien		}
230659024Sobrien	      PUT_WORD (output_bfd, (bfd_vma) 0, erel->r_addend);
230759024Sobrien	    }
230859024Sobrien
230959024Sobrien	  ++s->reloc_count;
231059024Sobrien	}
231159024Sobrien    }
231259024Sobrien
231359024Sobrien  /* If this is not a dynamic symbol, we don't have to do anything
231459024Sobrien     else.  We only check this after handling the PLT entry, because
231559024Sobrien     we can have a PLT entry for a nondynamic symbol when linking PIC
231659024Sobrien     compiled code from a regular object.  */
231759024Sobrien  if (h->dynindx < 0)
2318130561Sobrien    return TRUE;
231959024Sobrien
232059024Sobrien  switch (h->root.root.type)
232159024Sobrien    {
232259024Sobrien    default:
232359024Sobrien    case bfd_link_hash_new:
232459024Sobrien      abort ();
232559024Sobrien      /* Avoid variable not initialized warnings.  */
2326130561Sobrien      return TRUE;
232759024Sobrien    case bfd_link_hash_undefined:
232859024Sobrien      type = N_UNDF | N_EXT;
232959024Sobrien      val = 0;
233059024Sobrien      break;
233159024Sobrien    case bfd_link_hash_defined:
233259024Sobrien    case bfd_link_hash_defweak:
233359024Sobrien      {
233459024Sobrien	asection *sec;
233559024Sobrien	asection *output_section;
233659024Sobrien
233759024Sobrien	sec = h->root.root.u.def.section;
233859024Sobrien	output_section = sec->output_section;
233959024Sobrien	BFD_ASSERT (bfd_is_abs_section (output_section)
234059024Sobrien		    || output_section->owner == output_bfd);
234159024Sobrien	if (h->plt_offset != 0
234259024Sobrien	    && (h->flags & SUNOS_DEF_REGULAR) == 0)
234359024Sobrien	  {
234459024Sobrien	    type = N_UNDF | N_EXT;
234559024Sobrien	    val = 0;
234659024Sobrien	  }
234759024Sobrien	else
234859024Sobrien	  {
234959024Sobrien	    if (output_section == obj_textsec (output_bfd))
235059024Sobrien	      type = (h->root.root.type == bfd_link_hash_defined
235159024Sobrien		      ? N_TEXT
235259024Sobrien		      : N_WEAKT);
235359024Sobrien	    else if (output_section == obj_datasec (output_bfd))
235459024Sobrien	      type = (h->root.root.type == bfd_link_hash_defined
235559024Sobrien		      ? N_DATA
235659024Sobrien		      : N_WEAKD);
235759024Sobrien	    else if (output_section == obj_bsssec (output_bfd))
235859024Sobrien	      type = (h->root.root.type == bfd_link_hash_defined
235959024Sobrien		      ? N_BSS
236059024Sobrien		      : N_WEAKB);
236159024Sobrien	    else
236259024Sobrien	      type = (h->root.root.type == bfd_link_hash_defined
236359024Sobrien		      ? N_ABS
236459024Sobrien		      : N_WEAKA);
236559024Sobrien	    type |= N_EXT;
236659024Sobrien	    val = (h->root.root.u.def.value
236759024Sobrien		   + output_section->vma
236859024Sobrien		   + sec->output_offset);
236959024Sobrien	  }
237059024Sobrien      }
237159024Sobrien      break;
237259024Sobrien    case bfd_link_hash_common:
237359024Sobrien      type = N_UNDF | N_EXT;
237459024Sobrien      val = h->root.root.u.c.size;
237559024Sobrien      break;
237659024Sobrien    case bfd_link_hash_undefweak:
237759024Sobrien      type = N_WEAKU;
237859024Sobrien      val = 0;
237959024Sobrien      break;
238059024Sobrien    case bfd_link_hash_indirect:
238159024Sobrien    case bfd_link_hash_warning:
238259024Sobrien      /* FIXME: Ignore these for now.  The circumstances under which
238359024Sobrien	 they should be written out are not clear to me.  */
2384130561Sobrien      return TRUE;
238559024Sobrien    }
238659024Sobrien
238759024Sobrien  s = bfd_get_section_by_name (sunos_hash_table (info)->dynobj, ".dynsym");
238859024Sobrien  BFD_ASSERT (s != NULL);
238959024Sobrien  outsym = ((struct external_nlist *)
239059024Sobrien	    (s->contents + h->dynindx * EXTERNAL_NLIST_SIZE));
239159024Sobrien
239289857Sobrien  H_PUT_8 (output_bfd, type, outsym->e_type);
239389857Sobrien  H_PUT_8 (output_bfd, 0, outsym->e_other);
239459024Sobrien
239559024Sobrien  /* FIXME: The native linker doesn't use 0 for desc.  It seems to use
239659024Sobrien     one less than the desc value in the shared library, although that
239759024Sobrien     seems unlikely.  */
239889857Sobrien  H_PUT_16 (output_bfd, 0, outsym->e_desc);
239959024Sobrien
240059024Sobrien  PUT_WORD (output_bfd, h->dynstr_index, outsym->e_strx);
240159024Sobrien  PUT_WORD (output_bfd, val, outsym->e_value);
240259024Sobrien
2403130561Sobrien  return TRUE;
240459024Sobrien}
240559024Sobrien
240659024Sobrien/* This is called for each reloc against an external symbol.  If this
240759024Sobrien   is a reloc which are are going to copy as a dynamic reloc, then
240859024Sobrien   copy it over, and tell the caller to not bother processing this
240959024Sobrien   reloc.  */
241059024Sobrien
2411130561Sobrienstatic bfd_boolean
241259024Sobriensunos_check_dynamic_reloc (info, input_bfd, input_section, harg, reloc,
241359024Sobrien			   contents, skip, relocationp)
241459024Sobrien     struct bfd_link_info *info;
241559024Sobrien     bfd *input_bfd;
241659024Sobrien     asection *input_section;
241759024Sobrien     struct aout_link_hash_entry *harg;
241859024Sobrien     PTR reloc;
241984865Sobrien     bfd_byte *contents ATTRIBUTE_UNUSED;
2420130561Sobrien     bfd_boolean *skip;
242159024Sobrien     bfd_vma *relocationp;
242259024Sobrien{
242359024Sobrien  struct sunos_link_hash_entry *h = (struct sunos_link_hash_entry *) harg;
242459024Sobrien  bfd *dynobj;
2425130561Sobrien  bfd_boolean baserel;
2426130561Sobrien  bfd_boolean jmptbl;
2427130561Sobrien  bfd_boolean pcrel;
242859024Sobrien  asection *s;
242959024Sobrien  bfd_byte *p;
243059024Sobrien  long indx;
243159024Sobrien
2432130561Sobrien  *skip = FALSE;
243359024Sobrien
243459024Sobrien  dynobj = sunos_hash_table (info)->dynobj;
243559024Sobrien
243684865Sobrien  if (h != NULL
243784865Sobrien      && h->plt_offset != 0
243884865Sobrien      && (info->shared
243984865Sobrien	  || (h->flags & SUNOS_DEF_REGULAR) == 0))
244059024Sobrien    {
244159024Sobrien      asection *splt;
244259024Sobrien
244359024Sobrien      /* Redirect the relocation to the PLT entry.  */
244459024Sobrien      splt = bfd_get_section_by_name (dynobj, ".plt");
244559024Sobrien      *relocationp = (splt->output_section->vma
244659024Sobrien		      + splt->output_offset
244759024Sobrien		      + h->plt_offset);
244859024Sobrien    }
244959024Sobrien
245059024Sobrien  if (obj_reloc_entry_size (input_bfd) == RELOC_STD_SIZE)
245159024Sobrien    {
245259024Sobrien      struct reloc_std_external *srel;
245359024Sobrien
245459024Sobrien      srel = (struct reloc_std_external *) reloc;
245559024Sobrien      if (bfd_header_big_endian (input_bfd))
245659024Sobrien	{
245759024Sobrien	  baserel = (0 != (srel->r_type[0] & RELOC_STD_BITS_BASEREL_BIG));
245859024Sobrien	  jmptbl = (0 != (srel->r_type[0] & RELOC_STD_BITS_JMPTABLE_BIG));
245984865Sobrien	  pcrel = (0 != (srel->r_type[0] & RELOC_STD_BITS_PCREL_BIG));
246059024Sobrien	}
246159024Sobrien      else
246259024Sobrien	{
246359024Sobrien	  baserel = (0 != (srel->r_type[0] & RELOC_STD_BITS_BASEREL_LITTLE));
246459024Sobrien	  jmptbl = (0 != (srel->r_type[0] & RELOC_STD_BITS_JMPTABLE_LITTLE));
246584865Sobrien	  pcrel = (0 != (srel->r_type[0] & RELOC_STD_BITS_PCREL_LITTLE));
246659024Sobrien	}
246759024Sobrien    }
246859024Sobrien  else
246959024Sobrien    {
247059024Sobrien      struct reloc_ext_external *erel;
247159024Sobrien      int r_type;
247259024Sobrien
247359024Sobrien      erel = (struct reloc_ext_external *) reloc;
247459024Sobrien      if (bfd_header_big_endian (input_bfd))
247559024Sobrien	r_type = ((erel->r_type[0] & RELOC_EXT_BITS_TYPE_BIG)
247659024Sobrien		  >> RELOC_EXT_BITS_TYPE_SH_BIG);
247759024Sobrien      else
247859024Sobrien	r_type = ((erel->r_type[0] & RELOC_EXT_BITS_TYPE_LITTLE)
247959024Sobrien		  >> RELOC_EXT_BITS_TYPE_SH_LITTLE);
248059024Sobrien      baserel = (r_type == RELOC_BASE10
248159024Sobrien		 || r_type == RELOC_BASE13
248259024Sobrien		 || r_type == RELOC_BASE22);
248359024Sobrien      jmptbl = r_type == RELOC_JMP_TBL;
248484865Sobrien      pcrel = (r_type == RELOC_DISP8
248584865Sobrien	       || r_type == RELOC_DISP16
248684865Sobrien	       || r_type == RELOC_DISP32
248784865Sobrien	       || r_type == RELOC_WDISP30
248884865Sobrien	       || r_type == RELOC_WDISP22);
248984865Sobrien      /* We don't consider the PC10 and PC22 types to be PC relative,
2490130561Sobrien	 because they are pcrel_offset.  */
249159024Sobrien    }
249259024Sobrien
249359024Sobrien  if (baserel)
249459024Sobrien    {
249559024Sobrien      bfd_vma *got_offsetp;
249659024Sobrien      asection *sgot;
249759024Sobrien
249859024Sobrien      if (h != NULL)
249959024Sobrien	got_offsetp = &h->got_offset;
250059024Sobrien      else if (adata (input_bfd).local_got_offsets == NULL)
250159024Sobrien	got_offsetp = NULL;
250259024Sobrien      else
250359024Sobrien	{
250459024Sobrien	  struct reloc_std_external *srel;
250559024Sobrien	  int r_index;
250659024Sobrien
250759024Sobrien	  srel = (struct reloc_std_external *) reloc;
250859024Sobrien	  if (obj_reloc_entry_size (input_bfd) == RELOC_STD_SIZE)
250959024Sobrien	    {
251059024Sobrien	      if (bfd_header_big_endian (input_bfd))
251159024Sobrien		r_index = ((srel->r_index[0] << 16)
251259024Sobrien			   | (srel->r_index[1] << 8)
251359024Sobrien			   | srel->r_index[2]);
251459024Sobrien	      else
251559024Sobrien		r_index = ((srel->r_index[2] << 16)
251659024Sobrien			   | (srel->r_index[1] << 8)
251759024Sobrien			   | srel->r_index[0]);
251859024Sobrien	    }
251959024Sobrien	  else
252059024Sobrien	    {
252159024Sobrien	      struct reloc_ext_external *erel;
252259024Sobrien
252359024Sobrien	      erel = (struct reloc_ext_external *) reloc;
252459024Sobrien	      if (bfd_header_big_endian (input_bfd))
252559024Sobrien		r_index = ((erel->r_index[0] << 16)
252659024Sobrien			   | (erel->r_index[1] << 8)
252759024Sobrien			   | erel->r_index[2]);
252859024Sobrien	      else
252959024Sobrien		r_index = ((erel->r_index[2] << 16)
253059024Sobrien			   | (erel->r_index[1] << 8)
253159024Sobrien			   | erel->r_index[0]);
253259024Sobrien	    }
253359024Sobrien
253459024Sobrien	  got_offsetp = adata (input_bfd).local_got_offsets + r_index;
253559024Sobrien	}
253659024Sobrien
253759024Sobrien      BFD_ASSERT (got_offsetp != NULL && *got_offsetp != 0);
253859024Sobrien
253959024Sobrien      sgot = bfd_get_section_by_name (dynobj, ".got");
254059024Sobrien
254159024Sobrien      /* We set the least significant bit to indicate whether we have
254259024Sobrien	 already initialized the GOT entry.  */
254359024Sobrien      if ((*got_offsetp & 1) == 0)
254459024Sobrien	{
254559024Sobrien	  if (h == NULL
254659024Sobrien	      || (! info->shared
254759024Sobrien		  && ((h->flags & SUNOS_DEF_DYNAMIC) == 0
254859024Sobrien		      || (h->flags & SUNOS_DEF_REGULAR) != 0)))
254959024Sobrien	    PUT_WORD (dynobj, *relocationp, sgot->contents + *got_offsetp);
255059024Sobrien	  else
255159024Sobrien	    PUT_WORD (dynobj, 0, sgot->contents + *got_offsetp);
255259024Sobrien
255359024Sobrien	  if (info->shared
255459024Sobrien	      || (h != NULL
255559024Sobrien		  && (h->flags & SUNOS_DEF_DYNAMIC) != 0
255659024Sobrien		  && (h->flags & SUNOS_DEF_REGULAR) == 0))
255759024Sobrien	    {
255859024Sobrien	      /* We need to create a GLOB_DAT or 32 reloc to tell the
2559130561Sobrien		 dynamic linker to fill in this entry in the table.  */
256059024Sobrien
256159024Sobrien	      s = bfd_get_section_by_name (dynobj, ".dynrel");
256259024Sobrien	      BFD_ASSERT (s != NULL);
256359024Sobrien	      BFD_ASSERT (s->reloc_count * obj_reloc_entry_size (dynobj)
256459024Sobrien			  < s->_raw_size);
256559024Sobrien
256659024Sobrien	      p = (s->contents
256759024Sobrien		   + s->reloc_count * obj_reloc_entry_size (dynobj));
256859024Sobrien
256959024Sobrien	      if (h != NULL)
257059024Sobrien		indx = h->dynindx;
257159024Sobrien	      else
257259024Sobrien		indx = 0;
257359024Sobrien
257459024Sobrien	      if (obj_reloc_entry_size (dynobj) == RELOC_STD_SIZE)
257559024Sobrien		{
257659024Sobrien		  struct reloc_std_external *srel;
257759024Sobrien
257859024Sobrien		  srel = (struct reloc_std_external *) p;
257959024Sobrien		  PUT_WORD (dynobj,
258059024Sobrien			    (*got_offsetp
258159024Sobrien			     + sgot->output_section->vma
258259024Sobrien			     + sgot->output_offset),
258359024Sobrien			    srel->r_address);
258459024Sobrien		  if (bfd_header_big_endian (dynobj))
258559024Sobrien		    {
258684865Sobrien		      srel->r_index[0] = (bfd_byte) (indx >> 16);
258784865Sobrien		      srel->r_index[1] = (bfd_byte) (indx >> 8);
258859024Sobrien		      srel->r_index[2] = (bfd_byte)indx;
258959024Sobrien		      if (h == NULL)
259059024Sobrien			srel->r_type[0] = 2 << RELOC_STD_BITS_LENGTH_SH_BIG;
259159024Sobrien		      else
259259024Sobrien			srel->r_type[0] =
259359024Sobrien			  (RELOC_STD_BITS_EXTERN_BIG
259459024Sobrien			   | RELOC_STD_BITS_BASEREL_BIG
259559024Sobrien			   | RELOC_STD_BITS_RELATIVE_BIG
259659024Sobrien			   | (2 << RELOC_STD_BITS_LENGTH_SH_BIG));
259759024Sobrien		    }
259859024Sobrien		  else
259959024Sobrien		    {
260084865Sobrien		      srel->r_index[2] = (bfd_byte) (indx >> 16);
260184865Sobrien		      srel->r_index[1] = (bfd_byte) (indx >> 8);
260259024Sobrien		      srel->r_index[0] = (bfd_byte)indx;
260359024Sobrien		      if (h == NULL)
260459024Sobrien			srel->r_type[0] = 2 << RELOC_STD_BITS_LENGTH_SH_LITTLE;
260559024Sobrien		      else
260659024Sobrien			srel->r_type[0] =
260759024Sobrien			  (RELOC_STD_BITS_EXTERN_LITTLE
260859024Sobrien			   | RELOC_STD_BITS_BASEREL_LITTLE
260959024Sobrien			   | RELOC_STD_BITS_RELATIVE_LITTLE
261059024Sobrien			   | (2 << RELOC_STD_BITS_LENGTH_SH_LITTLE));
261159024Sobrien		    }
261259024Sobrien		}
261359024Sobrien	      else
261459024Sobrien		{
261559024Sobrien		  struct reloc_ext_external *erel;
261659024Sobrien
261759024Sobrien		  erel = (struct reloc_ext_external *) p;
261859024Sobrien		  PUT_WORD (dynobj,
261959024Sobrien			    (*got_offsetp
262059024Sobrien			     + sgot->output_section->vma
262159024Sobrien			     + sgot->output_offset),
262259024Sobrien			    erel->r_address);
262359024Sobrien		  if (bfd_header_big_endian (dynobj))
262459024Sobrien		    {
262584865Sobrien		      erel->r_index[0] = (bfd_byte) (indx >> 16);
262684865Sobrien		      erel->r_index[1] = (bfd_byte) (indx >> 8);
262759024Sobrien		      erel->r_index[2] = (bfd_byte)indx;
262859024Sobrien		      if (h == NULL)
262959024Sobrien			erel->r_type[0] =
263059024Sobrien			  RELOC_32 << RELOC_EXT_BITS_TYPE_SH_BIG;
263159024Sobrien		      else
263259024Sobrien			erel->r_type[0] =
263359024Sobrien			  (RELOC_EXT_BITS_EXTERN_BIG
263459024Sobrien			   | (RELOC_GLOB_DAT << RELOC_EXT_BITS_TYPE_SH_BIG));
263559024Sobrien		    }
263659024Sobrien		  else
263759024Sobrien		    {
263884865Sobrien		      erel->r_index[2] = (bfd_byte) (indx >> 16);
263984865Sobrien		      erel->r_index[1] = (bfd_byte) (indx >> 8);
264059024Sobrien		      erel->r_index[0] = (bfd_byte)indx;
264159024Sobrien		      if (h == NULL)
264259024Sobrien			erel->r_type[0] =
264359024Sobrien			  RELOC_32 << RELOC_EXT_BITS_TYPE_SH_LITTLE;
264459024Sobrien		      else
264559024Sobrien			erel->r_type[0] =
264659024Sobrien			  (RELOC_EXT_BITS_EXTERN_LITTLE
264759024Sobrien			   | (RELOC_GLOB_DAT
264859024Sobrien			      << RELOC_EXT_BITS_TYPE_SH_LITTLE));
264959024Sobrien		    }
265059024Sobrien		  PUT_WORD (dynobj, 0, erel->r_addend);
265159024Sobrien		}
265259024Sobrien
265359024Sobrien	      ++s->reloc_count;
265459024Sobrien	    }
265559024Sobrien
265659024Sobrien	  *got_offsetp |= 1;
265759024Sobrien	}
265859024Sobrien
265959024Sobrien      *relocationp = (sgot->vma
266089857Sobrien		      + (*got_offsetp &~ (bfd_vma) 1)
266159024Sobrien		      - sunos_hash_table (info)->got_base);
266259024Sobrien
266359024Sobrien      /* There is nothing else to do for a base relative reloc.  */
2664130561Sobrien      return TRUE;
266559024Sobrien    }
266659024Sobrien
266759024Sobrien  if (! sunos_hash_table (info)->dynamic_sections_needed)
2668130561Sobrien    return TRUE;
266959024Sobrien  if (! info->shared)
267059024Sobrien    {
267159024Sobrien      if (h == NULL
267259024Sobrien	  || h->dynindx == -1
267359024Sobrien	  || h->root.root.type != bfd_link_hash_undefined
267459024Sobrien	  || (h->flags & SUNOS_DEF_REGULAR) != 0
267559024Sobrien	  || (h->flags & SUNOS_DEF_DYNAMIC) == 0
267659024Sobrien	  || (h->root.root.u.undef.abfd->flags & DYNAMIC) == 0)
2677130561Sobrien	return TRUE;
267859024Sobrien    }
267959024Sobrien  else
268059024Sobrien    {
268159024Sobrien      if (h != NULL
268259024Sobrien	  && (h->dynindx == -1
268359024Sobrien	      || jmptbl
268459024Sobrien	      || strcmp (h->root.root.root.string,
268559024Sobrien			 "__GLOBAL_OFFSET_TABLE_") == 0))
2686130561Sobrien	return TRUE;
268759024Sobrien    }
268859024Sobrien
268959024Sobrien  /* It looks like this is a reloc we are supposed to copy.  */
269059024Sobrien
269159024Sobrien  s = bfd_get_section_by_name (dynobj, ".dynrel");
269259024Sobrien  BFD_ASSERT (s != NULL);
269359024Sobrien  BFD_ASSERT (s->reloc_count * obj_reloc_entry_size (dynobj) < s->_raw_size);
269459024Sobrien
269559024Sobrien  p = s->contents + s->reloc_count * obj_reloc_entry_size (dynobj);
269659024Sobrien
269759024Sobrien  /* Copy the reloc over.  */
269859024Sobrien  memcpy (p, reloc, obj_reloc_entry_size (dynobj));
269959024Sobrien
270059024Sobrien  if (h != NULL)
270159024Sobrien    indx = h->dynindx;
270259024Sobrien  else
270359024Sobrien    indx = 0;
270459024Sobrien
270559024Sobrien  /* Adjust the address and symbol index.  */
270659024Sobrien  if (obj_reloc_entry_size (dynobj) == RELOC_STD_SIZE)
270759024Sobrien    {
270859024Sobrien      struct reloc_std_external *srel;
270959024Sobrien
271059024Sobrien      srel = (struct reloc_std_external *) p;
271159024Sobrien      PUT_WORD (dynobj,
271259024Sobrien		(GET_WORD (dynobj, srel->r_address)
271359024Sobrien		 + input_section->output_section->vma
271459024Sobrien		 + input_section->output_offset),
271559024Sobrien		srel->r_address);
271659024Sobrien      if (bfd_header_big_endian (dynobj))
271759024Sobrien	{
271884865Sobrien	  srel->r_index[0] = (bfd_byte) (indx >> 16);
271984865Sobrien	  srel->r_index[1] = (bfd_byte) (indx >> 8);
272059024Sobrien	  srel->r_index[2] = (bfd_byte)indx;
272159024Sobrien	}
272259024Sobrien      else
272359024Sobrien	{
272484865Sobrien	  srel->r_index[2] = (bfd_byte) (indx >> 16);
272584865Sobrien	  srel->r_index[1] = (bfd_byte) (indx >> 8);
272659024Sobrien	  srel->r_index[0] = (bfd_byte)indx;
272759024Sobrien	}
272884865Sobrien      /* FIXME: We may have to change the addend for a PC relative
2729130561Sobrien	 reloc.  */
273059024Sobrien    }
273159024Sobrien  else
273259024Sobrien    {
273359024Sobrien      struct reloc_ext_external *erel;
273459024Sobrien
273559024Sobrien      erel = (struct reloc_ext_external *) p;
273659024Sobrien      PUT_WORD (dynobj,
273759024Sobrien		(GET_WORD (dynobj, erel->r_address)
273859024Sobrien		 + input_section->output_section->vma
273959024Sobrien		 + input_section->output_offset),
274059024Sobrien		erel->r_address);
274159024Sobrien      if (bfd_header_big_endian (dynobj))
274259024Sobrien	{
274384865Sobrien	  erel->r_index[0] = (bfd_byte) (indx >> 16);
274484865Sobrien	  erel->r_index[1] = (bfd_byte) (indx >> 8);
274559024Sobrien	  erel->r_index[2] = (bfd_byte)indx;
274659024Sobrien	}
274759024Sobrien      else
274859024Sobrien	{
274984865Sobrien	  erel->r_index[2] = (bfd_byte) (indx >> 16);
275084865Sobrien	  erel->r_index[1] = (bfd_byte) (indx >> 8);
275159024Sobrien	  erel->r_index[0] = (bfd_byte)indx;
275259024Sobrien	}
275384865Sobrien      if (pcrel && h != NULL)
275484865Sobrien	{
275584865Sobrien	  /* Adjust the addend for the change in address.  */
275684865Sobrien	  PUT_WORD (dynobj,
275784865Sobrien		    (GET_WORD (dynobj, erel->r_addend)
275884865Sobrien		     - (input_section->output_section->vma
275984865Sobrien			+ input_section->output_offset
276084865Sobrien			- input_section->vma)),
276184865Sobrien		    erel->r_addend);
276284865Sobrien	}
276359024Sobrien    }
276459024Sobrien
276559024Sobrien  ++s->reloc_count;
276659024Sobrien
276759024Sobrien  if (h != NULL)
2768130561Sobrien    *skip = TRUE;
276959024Sobrien
2770130561Sobrien  return TRUE;
277159024Sobrien}
277259024Sobrien
277359024Sobrien/* Finish up the dynamic linking information.  */
277459024Sobrien
2775130561Sobrienstatic bfd_boolean
277659024Sobriensunos_finish_dynamic_link (abfd, info)
277759024Sobrien     bfd *abfd;
277859024Sobrien     struct bfd_link_info *info;
277959024Sobrien{
278059024Sobrien  bfd *dynobj;
278159024Sobrien  asection *o;
278259024Sobrien  asection *s;
278359024Sobrien  asection *sdyn;
278459024Sobrien
278559024Sobrien  if (! sunos_hash_table (info)->dynamic_sections_needed
278659024Sobrien      && ! sunos_hash_table (info)->got_needed)
2787130561Sobrien    return TRUE;
278859024Sobrien
278959024Sobrien  dynobj = sunos_hash_table (info)->dynobj;
279059024Sobrien
279159024Sobrien  sdyn = bfd_get_section_by_name (dynobj, ".dynamic");
279259024Sobrien  BFD_ASSERT (sdyn != NULL);
279359024Sobrien
279459024Sobrien  /* Finish up the .need section.  The linker emulation code filled it
279559024Sobrien     in, but with offsets from the start of the section instead of
279659024Sobrien     real addresses.  Now that we know the section location, we can
279759024Sobrien     fill in the final values.  */
279859024Sobrien  s = bfd_get_section_by_name (dynobj, ".need");
279959024Sobrien  if (s != NULL && s->_raw_size != 0)
280059024Sobrien    {
280159024Sobrien      file_ptr filepos;
280259024Sobrien      bfd_byte *p;
280359024Sobrien
280459024Sobrien      filepos = s->output_section->filepos + s->output_offset;
280559024Sobrien      p = s->contents;
280659024Sobrien      while (1)
280759024Sobrien	{
280859024Sobrien	  bfd_vma val;
280959024Sobrien
281059024Sobrien	  PUT_WORD (dynobj, GET_WORD (dynobj, p) + filepos, p);
281159024Sobrien	  val = GET_WORD (dynobj, p + 12);
281259024Sobrien	  if (val == 0)
281359024Sobrien	    break;
281459024Sobrien	  PUT_WORD (dynobj, val + filepos, p + 12);
281559024Sobrien	  p += 16;
281659024Sobrien	}
281759024Sobrien    }
281859024Sobrien
281959024Sobrien  /* The first entry in the .got section is the address of the
282059024Sobrien     dynamic information, unless this is a shared library.  */
282159024Sobrien  s = bfd_get_section_by_name (dynobj, ".got");
282259024Sobrien  BFD_ASSERT (s != NULL);
282359024Sobrien  if (info->shared || sdyn->_raw_size == 0)
282459024Sobrien    PUT_WORD (dynobj, 0, s->contents);
282559024Sobrien  else
282659024Sobrien    PUT_WORD (dynobj, sdyn->output_section->vma + sdyn->output_offset,
282759024Sobrien	      s->contents);
282859024Sobrien
282959024Sobrien  for (o = dynobj->sections; o != NULL; o = o->next)
283059024Sobrien    {
283159024Sobrien      if ((o->flags & SEC_HAS_CONTENTS) != 0
283259024Sobrien	  && o->contents != NULL)
283359024Sobrien	{
283459024Sobrien	  BFD_ASSERT (o->output_section != NULL
283559024Sobrien		      && o->output_section->owner == abfd);
283659024Sobrien	  if (! bfd_set_section_contents (abfd, o->output_section,
283789857Sobrien					  o->contents,
283889857Sobrien					  (file_ptr) o->output_offset,
283959024Sobrien					  o->_raw_size))
2840130561Sobrien	    return FALSE;
284159024Sobrien	}
284259024Sobrien    }
284359024Sobrien
284459024Sobrien  if (sdyn->_raw_size > 0)
284559024Sobrien    {
284659024Sobrien      struct external_sun4_dynamic esd;
284759024Sobrien      struct external_sun4_dynamic_link esdl;
284889857Sobrien      file_ptr pos;
284959024Sobrien
285059024Sobrien      /* Finish up the dynamic link information.  */
285159024Sobrien      PUT_WORD (dynobj, (bfd_vma) 3, esd.ld_version);
285259024Sobrien      PUT_WORD (dynobj,
285359024Sobrien		sdyn->output_section->vma + sdyn->output_offset + sizeof esd,
285459024Sobrien		esd.ldd);
285559024Sobrien      PUT_WORD (dynobj,
285659024Sobrien		(sdyn->output_section->vma
285759024Sobrien		 + sdyn->output_offset
285859024Sobrien		 + sizeof esd
285959024Sobrien		 + EXTERNAL_SUN4_DYNAMIC_DEBUGGER_SIZE),
286059024Sobrien		esd.ld);
286159024Sobrien
286259024Sobrien      if (! bfd_set_section_contents (abfd, sdyn->output_section, &esd,
286389857Sobrien				      (file_ptr) sdyn->output_offset,
286489857Sobrien				      (bfd_size_type) sizeof esd))
2865130561Sobrien	return FALSE;
286659024Sobrien
286759024Sobrien      PUT_WORD (dynobj, (bfd_vma) 0, esdl.ld_loaded);
286859024Sobrien
286959024Sobrien      s = bfd_get_section_by_name (dynobj, ".need");
287059024Sobrien      if (s == NULL || s->_raw_size == 0)
287159024Sobrien	PUT_WORD (dynobj, (bfd_vma) 0, esdl.ld_need);
287259024Sobrien      else
287359024Sobrien	PUT_WORD (dynobj, s->output_section->filepos + s->output_offset,
287459024Sobrien		  esdl.ld_need);
287559024Sobrien
287659024Sobrien      s = bfd_get_section_by_name (dynobj, ".rules");
287759024Sobrien      if (s == NULL || s->_raw_size == 0)
287859024Sobrien	PUT_WORD (dynobj, (bfd_vma) 0, esdl.ld_rules);
287959024Sobrien      else
288059024Sobrien	PUT_WORD (dynobj, s->output_section->filepos + s->output_offset,
288159024Sobrien		  esdl.ld_rules);
288259024Sobrien
288359024Sobrien      s = bfd_get_section_by_name (dynobj, ".got");
288459024Sobrien      BFD_ASSERT (s != NULL);
288559024Sobrien      PUT_WORD (dynobj, s->output_section->vma + s->output_offset,
288659024Sobrien		esdl.ld_got);
288759024Sobrien
288859024Sobrien      s = bfd_get_section_by_name (dynobj, ".plt");
288959024Sobrien      BFD_ASSERT (s != NULL);
289059024Sobrien      PUT_WORD (dynobj, s->output_section->vma + s->output_offset,
289159024Sobrien		esdl.ld_plt);
289259024Sobrien      PUT_WORD (dynobj, s->_raw_size, esdl.ld_plt_sz);
289359024Sobrien
289459024Sobrien      s = bfd_get_section_by_name (dynobj, ".dynrel");
289559024Sobrien      BFD_ASSERT (s != NULL);
289659024Sobrien      BFD_ASSERT (s->reloc_count * obj_reloc_entry_size (dynobj)
289759024Sobrien		  == s->_raw_size);
289859024Sobrien      PUT_WORD (dynobj, s->output_section->filepos + s->output_offset,
289959024Sobrien		esdl.ld_rel);
290059024Sobrien
290159024Sobrien      s = bfd_get_section_by_name (dynobj, ".hash");
290259024Sobrien      BFD_ASSERT (s != NULL);
290359024Sobrien      PUT_WORD (dynobj, s->output_section->filepos + s->output_offset,
290459024Sobrien		esdl.ld_hash);
290559024Sobrien
290659024Sobrien      s = bfd_get_section_by_name (dynobj, ".dynsym");
290759024Sobrien      BFD_ASSERT (s != NULL);
290859024Sobrien      PUT_WORD (dynobj, s->output_section->filepos + s->output_offset,
290959024Sobrien		esdl.ld_stab);
291059024Sobrien
291159024Sobrien      PUT_WORD (dynobj, (bfd_vma) 0, esdl.ld_stab_hash);
291259024Sobrien
291359024Sobrien      PUT_WORD (dynobj, (bfd_vma) sunos_hash_table (info)->bucketcount,
291459024Sobrien		esdl.ld_buckets);
291559024Sobrien
291659024Sobrien      s = bfd_get_section_by_name (dynobj, ".dynstr");
291759024Sobrien      BFD_ASSERT (s != NULL);
291859024Sobrien      PUT_WORD (dynobj, s->output_section->filepos + s->output_offset,
291959024Sobrien		esdl.ld_symbols);
292059024Sobrien      PUT_WORD (dynobj, s->_raw_size, esdl.ld_symb_size);
292159024Sobrien
292259024Sobrien      /* The size of the text area is the size of the .text section
292359024Sobrien	 rounded up to a page boundary.  FIXME: Should the page size be
292459024Sobrien	 conditional on something?  */
292559024Sobrien      PUT_WORD (dynobj,
292659024Sobrien		BFD_ALIGN (obj_textsec (abfd)->_raw_size, 0x2000),
292759024Sobrien		esdl.ld_text);
292884865Sobrien
292989857Sobrien      pos = sdyn->output_offset;
293089857Sobrien      pos += sizeof esd + EXTERNAL_SUN4_DYNAMIC_DEBUGGER_SIZE;
293159024Sobrien      if (! bfd_set_section_contents (abfd, sdyn->output_section, &esdl,
293289857Sobrien				      pos, (bfd_size_type) sizeof esdl))
2933130561Sobrien	return FALSE;
293459024Sobrien
293559024Sobrien      abfd->flags |= DYNAMIC;
293659024Sobrien    }
293759024Sobrien
2938130561Sobrien  return TRUE;
293959024Sobrien}
2940