159024Sobrien/* BFD backend for SunOS binaries.
2218822Sdim   Copyright 1990, 1991, 1992, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
3218822Sdim   2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
459024Sobrien   Written by Cygnus Support.
559024Sobrien
6218822Sdim   This file is part of BFD, the Binary File Descriptor library.
759024Sobrien
8218822Sdim   This program is free software; you can redistribute it and/or modify
9218822Sdim   it under the terms of the GNU General Public License as published by
10218822Sdim   the Free Software Foundation; either version 2 of the License, or
11218822Sdim   (at your option) any later version.
1259024Sobrien
13218822Sdim   This program is distributed in the hope that it will be useful,
14218822Sdim   but WITHOUT ANY WARRANTY; without even the implied warranty of
15218822Sdim   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16218822Sdim   GNU General Public License for more details.
1759024Sobrien
18218822Sdim   You should have received a copy of the GNU General Public License
19218822Sdim   along with this program; if not, write to the Free Software
20218822Sdim   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, 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/* ??? Where should this go?  */
3459024Sobrien#define MACHTYPE_OK(mtype) \
3559024Sobrien  (((mtype) == M_SPARC && bfd_lookup_arch (bfd_arch_sparc, 0) != NULL) \
3659024Sobrien   || ((mtype) == M_SPARCLET \
3759024Sobrien       && bfd_lookup_arch (bfd_arch_sparc, bfd_mach_sparc_sparclet) != NULL) \
3884865Sobrien   || ((mtype) == M_SPARCLITE_LE \
3984865Sobrien       && bfd_lookup_arch (bfd_arch_sparc, bfd_mach_sparc_sparclet) != NULL) \
4059024Sobrien   || (((mtype) == M_UNKNOWN || (mtype) == M_68010 || (mtype) == M_68020) \
4159024Sobrien       && bfd_lookup_arch (bfd_arch_m68k, 0) != NULL))
4259024Sobrien
43218822Sdim#define MY_get_dynamic_symtab_upper_bound  sunos_get_dynamic_symtab_upper_bound
44218822Sdim#define MY_canonicalize_dynamic_symtab     sunos_canonicalize_dynamic_symtab
45218822Sdim#define MY_get_synthetic_symtab            _bfd_nodynamic_get_synthetic_symtab
46218822Sdim#define MY_get_dynamic_reloc_upper_bound   sunos_get_dynamic_reloc_upper_bound
47218822Sdim#define MY_canonicalize_dynamic_reloc      sunos_canonicalize_dynamic_reloc
48218822Sdim#define MY_bfd_link_hash_table_create      sunos_link_hash_table_create
49218822Sdim#define MY_add_dynamic_symbols             sunos_add_dynamic_symbols
50218822Sdim#define MY_add_one_symbol                  sunos_add_one_symbol
51218822Sdim#define MY_link_dynamic_object             sunos_link_dynamic_object
52218822Sdim#define MY_write_dynamic_symbol            sunos_write_dynamic_symbol
53218822Sdim#define MY_check_dynamic_reloc             sunos_check_dynamic_reloc
54218822Sdim#define MY_finish_dynamic_link             sunos_finish_dynamic_link
55218822Sdim
56218822Sdimstatic bfd_boolean sunos_add_dynamic_symbols            (bfd *, struct bfd_link_info *, struct external_nlist **, bfd_size_type *, char **);
57218822Sdimstatic bfd_boolean sunos_add_one_symbol                 (struct bfd_link_info *, bfd *, const char *, flagword, asection *, bfd_vma, const char *, bfd_boolean, bfd_boolean, struct bfd_link_hash_entry **);
58218822Sdimstatic bfd_boolean sunos_link_dynamic_object            (struct bfd_link_info *, bfd *);
59218822Sdimstatic bfd_boolean sunos_write_dynamic_symbol           (bfd *, struct bfd_link_info *, struct aout_link_hash_entry *);
60218822Sdimstatic bfd_boolean sunos_check_dynamic_reloc            (struct bfd_link_info *, bfd *, asection *, struct aout_link_hash_entry *, void *, bfd_byte *, bfd_boolean *, bfd_vma *);
61218822Sdimstatic bfd_boolean sunos_finish_dynamic_link            (bfd *, struct bfd_link_info *);
62218822Sdimstatic struct bfd_link_hash_table *sunos_link_hash_table_create  (bfd *);
63218822Sdimstatic long        sunos_get_dynamic_symtab_upper_bound (bfd *);
64218822Sdimstatic long        sunos_canonicalize_dynamic_symtab    (bfd *, asymbol **);
65218822Sdimstatic long        sunos_get_dynamic_reloc_upper_bound  (bfd *);
66218822Sdimstatic long        sunos_canonicalize_dynamic_reloc     (bfd *, arelent **, asymbol **);
67218822Sdim
6859024Sobrien/* Include the usual a.out support.  */
6959024Sobrien#include "aoutf1.h"
7059024Sobrien
7184865Sobrien/* The SunOS 4.1.4 /usr/include/locale.h defines valid as a macro.  */
7284865Sobrien#undef valid
7384865Sobrien
7459024Sobrien/* SunOS shared library support.  We store a pointer to this structure
7559024Sobrien   in obj_aout_dynamic_info (abfd).  */
7659024Sobrien
7759024Sobrienstruct sunos_dynamic_info
7859024Sobrien{
7959024Sobrien  /* Whether we found any dynamic information.  */
80130561Sobrien  bfd_boolean valid;
8159024Sobrien  /* Dynamic information.  */
8259024Sobrien  struct internal_sun4_dynamic_link dyninfo;
8359024Sobrien  /* Number of dynamic symbols.  */
8459024Sobrien  unsigned long dynsym_count;
8559024Sobrien  /* Read in nlists for dynamic symbols.  */
8659024Sobrien  struct external_nlist *dynsym;
8759024Sobrien  /* asymbol structures for dynamic symbols.  */
8859024Sobrien  aout_symbol_type *canonical_dynsym;
8959024Sobrien  /* Read in dynamic string table.  */
9059024Sobrien  char *dynstr;
9159024Sobrien  /* Number of dynamic relocs.  */
9259024Sobrien  unsigned long dynrel_count;
9359024Sobrien  /* Read in dynamic relocs.  This may be reloc_std_external or
9459024Sobrien     reloc_ext_external.  */
95218822Sdim  void * dynrel;
9659024Sobrien  /* arelent structures for dynamic relocs.  */
9759024Sobrien  arelent *canonical_dynrel;
9859024Sobrien};
9959024Sobrien
10059024Sobrien/* The hash table of dynamic symbols is composed of two word entries.
10159024Sobrien   See include/aout/sun4.h for details.  */
10259024Sobrien
10359024Sobrien#define HASH_ENTRY_SIZE (2 * BYTES_IN_WORD)
10459024Sobrien
10559024Sobrien/* Read in the basic dynamic information.  This locates the __DYNAMIC
10659024Sobrien   structure and uses it to find the dynamic_link structure.  It
10759024Sobrien   creates and saves a sunos_dynamic_info structure.  If it can't find
10859024Sobrien   __DYNAMIC, it sets the valid field of the sunos_dynamic_info
109130561Sobrien   structure to FALSE to avoid doing this work again.  */
11059024Sobrien
111130561Sobrienstatic bfd_boolean
112218822Sdimsunos_read_dynamic_info (bfd *abfd)
11359024Sobrien{
11459024Sobrien  struct sunos_dynamic_info *info;
11559024Sobrien  asection *dynsec;
11659024Sobrien  bfd_vma dynoff;
11759024Sobrien  struct external_sun4_dynamic dyninfo;
11859024Sobrien  unsigned long dynver;
11959024Sobrien  struct external_sun4_dynamic_link linkinfo;
12089857Sobrien  bfd_size_type amt;
12159024Sobrien
122218822Sdim  if (obj_aout_dynamic_info (abfd) != NULL)
123130561Sobrien    return TRUE;
12459024Sobrien
12559024Sobrien  if ((abfd->flags & DYNAMIC) == 0)
12659024Sobrien    {
12759024Sobrien      bfd_set_error (bfd_error_invalid_operation);
128130561Sobrien      return FALSE;
12959024Sobrien    }
13059024Sobrien
13189857Sobrien  amt = sizeof (struct sunos_dynamic_info);
132218822Sdim  info = bfd_zalloc (abfd, amt);
13359024Sobrien  if (!info)
134130561Sobrien    return FALSE;
135130561Sobrien  info->valid = FALSE;
13659024Sobrien  info->dynsym = NULL;
13759024Sobrien  info->dynstr = NULL;
13859024Sobrien  info->canonical_dynsym = NULL;
13959024Sobrien  info->dynrel = NULL;
14059024Sobrien  info->canonical_dynrel = NULL;
141218822Sdim  obj_aout_dynamic_info (abfd) = (void *) info;
14259024Sobrien
14359024Sobrien  /* This code used to look for the __DYNAMIC symbol to locate the dynamic
14459024Sobrien     linking information.
14559024Sobrien     However this inhibits recovering the dynamic symbols from a
14659024Sobrien     stripped object file, so blindly assume that the dynamic linking
14759024Sobrien     information is located at the start of the data section.
14859024Sobrien     We could verify this assumption later by looking through the dynamic
14959024Sobrien     symbols for the __DYNAMIC symbol.  */
15059024Sobrien  if ((abfd->flags & DYNAMIC) == 0)
151130561Sobrien    return TRUE;
152218822Sdim  if (! bfd_get_section_contents (abfd, obj_datasec (abfd), (void *) &dyninfo,
15389857Sobrien				  (file_ptr) 0,
15489857Sobrien				  (bfd_size_type) sizeof dyninfo))
155130561Sobrien    return TRUE;
15659024Sobrien
15759024Sobrien  dynver = GET_WORD (abfd, dyninfo.ld_version);
15859024Sobrien  if (dynver != 2 && dynver != 3)
159130561Sobrien    return TRUE;
16059024Sobrien
16159024Sobrien  dynoff = GET_WORD (abfd, dyninfo.ld);
16259024Sobrien
16359024Sobrien  /* dynoff is a virtual address.  It is probably always in the .data
16459024Sobrien     section, but this code should work even if it moves.  */
16559024Sobrien  if (dynoff < bfd_get_section_vma (abfd, obj_datasec (abfd)))
16659024Sobrien    dynsec = obj_textsec (abfd);
16759024Sobrien  else
16859024Sobrien    dynsec = obj_datasec (abfd);
16959024Sobrien  dynoff -= bfd_get_section_vma (abfd, dynsec);
170218822Sdim  if (dynoff > dynsec->size)
171130561Sobrien    return TRUE;
17259024Sobrien
17359024Sobrien  /* This executable appears to be dynamically linked in a way that we
17459024Sobrien     can understand.  */
175218822Sdim  if (! bfd_get_section_contents (abfd, dynsec, (void *) &linkinfo,
17689857Sobrien				  (file_ptr) dynoff,
17759024Sobrien				  (bfd_size_type) sizeof linkinfo))
178130561Sobrien    return TRUE;
17959024Sobrien
18059024Sobrien  /* Swap in the dynamic link information.  */
18159024Sobrien  info->dyninfo.ld_loaded = GET_WORD (abfd, linkinfo.ld_loaded);
18259024Sobrien  info->dyninfo.ld_need = GET_WORD (abfd, linkinfo.ld_need);
18359024Sobrien  info->dyninfo.ld_rules = GET_WORD (abfd, linkinfo.ld_rules);
18459024Sobrien  info->dyninfo.ld_got = GET_WORD (abfd, linkinfo.ld_got);
18559024Sobrien  info->dyninfo.ld_plt = GET_WORD (abfd, linkinfo.ld_plt);
18659024Sobrien  info->dyninfo.ld_rel = GET_WORD (abfd, linkinfo.ld_rel);
18759024Sobrien  info->dyninfo.ld_hash = GET_WORD (abfd, linkinfo.ld_hash);
18859024Sobrien  info->dyninfo.ld_stab = GET_WORD (abfd, linkinfo.ld_stab);
18959024Sobrien  info->dyninfo.ld_stab_hash = GET_WORD (abfd, linkinfo.ld_stab_hash);
19059024Sobrien  info->dyninfo.ld_buckets = GET_WORD (abfd, linkinfo.ld_buckets);
19159024Sobrien  info->dyninfo.ld_symbols = GET_WORD (abfd, linkinfo.ld_symbols);
19259024Sobrien  info->dyninfo.ld_symb_size = GET_WORD (abfd, linkinfo.ld_symb_size);
19359024Sobrien  info->dyninfo.ld_text = GET_WORD (abfd, linkinfo.ld_text);
19459024Sobrien  info->dyninfo.ld_plt_sz = GET_WORD (abfd, linkinfo.ld_plt_sz);
19559024Sobrien
19659024Sobrien  /* Reportedly the addresses need to be offset by the size of the
19759024Sobrien     exec header in an NMAGIC file.  */
19859024Sobrien  if (adata (abfd).magic == n_magic)
19959024Sobrien    {
20059024Sobrien      unsigned long exec_bytes_size = adata (abfd).exec_bytes_size;
20159024Sobrien
20259024Sobrien      info->dyninfo.ld_need += exec_bytes_size;
20359024Sobrien      info->dyninfo.ld_rules += exec_bytes_size;
20459024Sobrien      info->dyninfo.ld_rel += exec_bytes_size;
20559024Sobrien      info->dyninfo.ld_hash += exec_bytes_size;
20659024Sobrien      info->dyninfo.ld_stab += exec_bytes_size;
20759024Sobrien      info->dyninfo.ld_symbols += exec_bytes_size;
20859024Sobrien    }
20959024Sobrien
21059024Sobrien  /* The only way to get the size of the symbol information appears to
21159024Sobrien     be to determine the distance between it and the string table.  */
21259024Sobrien  info->dynsym_count = ((info->dyninfo.ld_symbols - info->dyninfo.ld_stab)
21359024Sobrien			/ EXTERNAL_NLIST_SIZE);
21459024Sobrien  BFD_ASSERT (info->dynsym_count * EXTERNAL_NLIST_SIZE
21559024Sobrien	      == (unsigned long) (info->dyninfo.ld_symbols
21659024Sobrien				  - info->dyninfo.ld_stab));
21759024Sobrien
21859024Sobrien  /* Similarly, the relocs end at the hash table.  */
21959024Sobrien  info->dynrel_count = ((info->dyninfo.ld_hash - info->dyninfo.ld_rel)
22059024Sobrien			/ obj_reloc_entry_size (abfd));
22159024Sobrien  BFD_ASSERT (info->dynrel_count * obj_reloc_entry_size (abfd)
22259024Sobrien	      == (unsigned long) (info->dyninfo.ld_hash
22359024Sobrien				  - info->dyninfo.ld_rel));
22459024Sobrien
225130561Sobrien  info->valid = TRUE;
22659024Sobrien
227130561Sobrien  return TRUE;
22859024Sobrien}
22959024Sobrien
23059024Sobrien/* Return the amount of memory required for the dynamic symbols.  */
23159024Sobrien
23259024Sobrienstatic long
233218822Sdimsunos_get_dynamic_symtab_upper_bound (bfd *abfd)
23459024Sobrien{
23559024Sobrien  struct sunos_dynamic_info *info;
23659024Sobrien
23759024Sobrien  if (! sunos_read_dynamic_info (abfd))
23859024Sobrien    return -1;
23959024Sobrien
24059024Sobrien  info = (struct sunos_dynamic_info *) obj_aout_dynamic_info (abfd);
24159024Sobrien  if (! info->valid)
24259024Sobrien    {
24359024Sobrien      bfd_set_error (bfd_error_no_symbols);
24459024Sobrien      return -1;
24559024Sobrien    }
24659024Sobrien
24759024Sobrien  return (info->dynsym_count + 1) * sizeof (asymbol *);
24859024Sobrien}
24959024Sobrien
25059024Sobrien/* Read the external dynamic symbols.  */
25159024Sobrien
252130561Sobrienstatic bfd_boolean
253218822Sdimsunos_slurp_dynamic_symtab (bfd *abfd)
25459024Sobrien{
25559024Sobrien  struct sunos_dynamic_info *info;
25689857Sobrien  bfd_size_type amt;
25759024Sobrien
25859024Sobrien  /* Get the general dynamic information.  */
25959024Sobrien  if (obj_aout_dynamic_info (abfd) == NULL)
26059024Sobrien    {
26159024Sobrien      if (! sunos_read_dynamic_info (abfd))
262130561Sobrien	  return FALSE;
26359024Sobrien    }
26459024Sobrien
26559024Sobrien  info = (struct sunos_dynamic_info *) obj_aout_dynamic_info (abfd);
26659024Sobrien  if (! info->valid)
26759024Sobrien    {
26859024Sobrien      bfd_set_error (bfd_error_no_symbols);
269130561Sobrien      return FALSE;
27059024Sobrien    }
27159024Sobrien
27259024Sobrien  /* Get the dynamic nlist structures.  */
273218822Sdim  if (info->dynsym == NULL)
27459024Sobrien    {
27589857Sobrien      amt = (bfd_size_type) info->dynsym_count * EXTERNAL_NLIST_SIZE;
276218822Sdim      info->dynsym = bfd_alloc (abfd, amt);
27759024Sobrien      if (info->dynsym == NULL && info->dynsym_count != 0)
278130561Sobrien	return FALSE;
27989857Sobrien      if (bfd_seek (abfd, (file_ptr) info->dyninfo.ld_stab, SEEK_SET) != 0
280218822Sdim	  || bfd_bread ((void *) info->dynsym, amt, abfd) != amt)
28159024Sobrien	{
28259024Sobrien	  if (info->dynsym != NULL)
28359024Sobrien	    {
28459024Sobrien	      bfd_release (abfd, info->dynsym);
28559024Sobrien	      info->dynsym = NULL;
28659024Sobrien	    }
287130561Sobrien	  return FALSE;
28859024Sobrien	}
28959024Sobrien    }
29059024Sobrien
29159024Sobrien  /* Get the dynamic strings.  */
292218822Sdim  if (info->dynstr == NULL)
29359024Sobrien    {
29489857Sobrien      amt = info->dyninfo.ld_symb_size;
295218822Sdim      info->dynstr = bfd_alloc (abfd, amt);
29659024Sobrien      if (info->dynstr == NULL && info->dyninfo.ld_symb_size != 0)
297130561Sobrien	return FALSE;
29889857Sobrien      if (bfd_seek (abfd, (file_ptr) info->dyninfo.ld_symbols, SEEK_SET) != 0
299218822Sdim	  || bfd_bread ((void *) info->dynstr, amt, abfd) != amt)
30059024Sobrien	{
30159024Sobrien	  if (info->dynstr != NULL)
30259024Sobrien	    {
30359024Sobrien	      bfd_release (abfd, info->dynstr);
30459024Sobrien	      info->dynstr = NULL;
30559024Sobrien	    }
306130561Sobrien	  return FALSE;
30759024Sobrien	}
30859024Sobrien    }
30959024Sobrien
310130561Sobrien  return TRUE;
31159024Sobrien}
31259024Sobrien
31359024Sobrien/* Read in the dynamic symbols.  */
31459024Sobrien
31559024Sobrienstatic long
316218822Sdimsunos_canonicalize_dynamic_symtab (bfd *abfd, asymbol **storage)
31759024Sobrien{
31859024Sobrien  struct sunos_dynamic_info *info;
31959024Sobrien  unsigned long i;
32059024Sobrien
32159024Sobrien  if (! sunos_slurp_dynamic_symtab (abfd))
32259024Sobrien    return -1;
32359024Sobrien
32459024Sobrien  info = (struct sunos_dynamic_info *) obj_aout_dynamic_info (abfd);
32559024Sobrien
32659024Sobrien#ifdef CHECK_DYNAMIC_HASH
32759024Sobrien  /* Check my understanding of the dynamic hash table by making sure
32859024Sobrien     that each symbol can be located in the hash table.  */
32959024Sobrien  {
33059024Sobrien    bfd_size_type table_size;
33159024Sobrien    bfd_byte *table;
33259024Sobrien    bfd_size_type i;
33359024Sobrien
33459024Sobrien    if (info->dyninfo.ld_buckets > info->dynsym_count)
33559024Sobrien      abort ();
33659024Sobrien    table_size = info->dyninfo.ld_stab - info->dyninfo.ld_hash;
337218822Sdim    table = bfd_malloc (table_size);
33859024Sobrien    if (table == NULL && table_size != 0)
33959024Sobrien      abort ();
34089857Sobrien    if (bfd_seek (abfd, (file_ptr) info->dyninfo.ld_hash, SEEK_SET) != 0
341218822Sdim	|| bfd_bread ((void *) table, table_size, abfd) != table_size)
34259024Sobrien      abort ();
34359024Sobrien    for (i = 0; i < info->dynsym_count; i++)
34459024Sobrien      {
34559024Sobrien	unsigned char *name;
34659024Sobrien	unsigned long hash;
34759024Sobrien
34859024Sobrien	name = ((unsigned char *) info->dynstr
34959024Sobrien		+ GET_WORD (abfd, info->dynsym[i].e_strx));
35059024Sobrien	hash = 0;
35159024Sobrien	while (*name != '\0')
35259024Sobrien	  hash = (hash << 1) + *name++;
35359024Sobrien	hash &= 0x7fffffff;
35459024Sobrien	hash %= info->dyninfo.ld_buckets;
35559024Sobrien	while (GET_WORD (abfd, table + hash * HASH_ENTRY_SIZE) != i)
35659024Sobrien	  {
35759024Sobrien	    hash = GET_WORD (abfd,
35859024Sobrien			     table + hash * HASH_ENTRY_SIZE + BYTES_IN_WORD);
35959024Sobrien	    if (hash == 0 || hash >= table_size / HASH_ENTRY_SIZE)
36059024Sobrien	      abort ();
36159024Sobrien	  }
36259024Sobrien      }
36359024Sobrien    free (table);
36459024Sobrien  }
36559024Sobrien#endif /* CHECK_DYNAMIC_HASH */
36659024Sobrien
36759024Sobrien  /* Get the asymbol structures corresponding to the dynamic nlist
36859024Sobrien     structures.  */
369218822Sdim  if (info->canonical_dynsym == NULL)
37059024Sobrien    {
37189857Sobrien      bfd_size_type size;
37289857Sobrien      bfd_size_type strsize = info->dyninfo.ld_symb_size;
37389857Sobrien
37489857Sobrien      size = (bfd_size_type) info->dynsym_count * sizeof (aout_symbol_type);
375218822Sdim      info->canonical_dynsym = bfd_alloc (abfd, size);
37659024Sobrien      if (info->canonical_dynsym == NULL && info->dynsym_count != 0)
37759024Sobrien	return -1;
37859024Sobrien
37959024Sobrien      if (! aout_32_translate_symbol_table (abfd, info->canonical_dynsym,
38089857Sobrien					    info->dynsym,
38189857Sobrien					    (bfd_size_type) info->dynsym_count,
382130561Sobrien					    info->dynstr, strsize, TRUE))
38359024Sobrien	{
38459024Sobrien	  if (info->canonical_dynsym != NULL)
38559024Sobrien	    {
38659024Sobrien	      bfd_release (abfd, info->canonical_dynsym);
38759024Sobrien	      info->canonical_dynsym = NULL;
38859024Sobrien	    }
38959024Sobrien	  return -1;
39059024Sobrien	}
39159024Sobrien    }
39259024Sobrien
39359024Sobrien  /* Return pointers to the dynamic asymbol structures.  */
39459024Sobrien  for (i = 0; i < info->dynsym_count; i++)
39559024Sobrien    *storage++ = (asymbol *) (info->canonical_dynsym + i);
39659024Sobrien  *storage = NULL;
39759024Sobrien
39859024Sobrien  return info->dynsym_count;
39959024Sobrien}
40059024Sobrien
40159024Sobrien/* Return the amount of memory required for the dynamic relocs.  */
40259024Sobrien
40359024Sobrienstatic long
404218822Sdimsunos_get_dynamic_reloc_upper_bound (bfd *abfd)
40559024Sobrien{
40659024Sobrien  struct sunos_dynamic_info *info;
40759024Sobrien
40859024Sobrien  if (! sunos_read_dynamic_info (abfd))
40959024Sobrien    return -1;
41059024Sobrien
41159024Sobrien  info = (struct sunos_dynamic_info *) obj_aout_dynamic_info (abfd);
41259024Sobrien  if (! info->valid)
41359024Sobrien    {
41459024Sobrien      bfd_set_error (bfd_error_no_symbols);
41559024Sobrien      return -1;
41659024Sobrien    }
41759024Sobrien
41859024Sobrien  return (info->dynrel_count + 1) * sizeof (arelent *);
41959024Sobrien}
42059024Sobrien
42159024Sobrien/* Read in the dynamic relocs.  */
42259024Sobrien
42359024Sobrienstatic long
424218822Sdimsunos_canonicalize_dynamic_reloc (bfd *abfd, arelent **storage, asymbol **syms)
42559024Sobrien{
42659024Sobrien  struct sunos_dynamic_info *info;
42759024Sobrien  unsigned long i;
42889857Sobrien  bfd_size_type size;
42959024Sobrien
43059024Sobrien  /* Get the general dynamic information.  */
431218822Sdim  if (obj_aout_dynamic_info (abfd) == NULL)
43259024Sobrien    {
43359024Sobrien      if (! sunos_read_dynamic_info (abfd))
43459024Sobrien	return -1;
43559024Sobrien    }
43659024Sobrien
43759024Sobrien  info = (struct sunos_dynamic_info *) obj_aout_dynamic_info (abfd);
43859024Sobrien  if (! info->valid)
43959024Sobrien    {
44059024Sobrien      bfd_set_error (bfd_error_no_symbols);
44159024Sobrien      return -1;
44259024Sobrien    }
44359024Sobrien
44459024Sobrien  /* Get the dynamic reloc information.  */
44559024Sobrien  if (info->dynrel == NULL)
44659024Sobrien    {
44789857Sobrien      size = (bfd_size_type) info->dynrel_count * obj_reloc_entry_size (abfd);
448218822Sdim      info->dynrel = bfd_alloc (abfd, size);
44989857Sobrien      if (info->dynrel == NULL && size != 0)
45059024Sobrien	return -1;
45189857Sobrien      if (bfd_seek (abfd, (file_ptr) info->dyninfo.ld_rel, SEEK_SET) != 0
452218822Sdim	  || bfd_bread ((void *) info->dynrel, size, abfd) != size)
45359024Sobrien	{
45459024Sobrien	  if (info->dynrel != NULL)
45559024Sobrien	    {
45659024Sobrien	      bfd_release (abfd, info->dynrel);
45759024Sobrien	      info->dynrel = NULL;
45859024Sobrien	    }
45959024Sobrien	  return -1;
46059024Sobrien	}
46159024Sobrien    }
46259024Sobrien
46359024Sobrien  /* Get the arelent structures corresponding to the dynamic reloc
46459024Sobrien     information.  */
465218822Sdim  if (info->canonical_dynrel == NULL)
46659024Sobrien    {
46759024Sobrien      arelent *to;
46859024Sobrien
46989857Sobrien      size = (bfd_size_type) info->dynrel_count * sizeof (arelent);
470218822Sdim      info->canonical_dynrel = bfd_alloc (abfd, size);
47159024Sobrien      if (info->canonical_dynrel == NULL && info->dynrel_count != 0)
47259024Sobrien	return -1;
47384865Sobrien
47459024Sobrien      to = info->canonical_dynrel;
47559024Sobrien
47659024Sobrien      if (obj_reloc_entry_size (abfd) == RELOC_EXT_SIZE)
47759024Sobrien	{
478218822Sdim	  struct reloc_ext_external *p;
47959024Sobrien	  struct reloc_ext_external *pend;
48059024Sobrien
48159024Sobrien	  p = (struct reloc_ext_external *) info->dynrel;
48259024Sobrien	  pend = p + info->dynrel_count;
48359024Sobrien	  for (; p < pend; p++, to++)
484218822Sdim	    NAME (aout, swap_ext_reloc_in) (abfd, p, to, syms,
485218822Sdim					    (bfd_size_type) info->dynsym_count);
48659024Sobrien	}
48759024Sobrien      else
48859024Sobrien	{
489218822Sdim	  struct reloc_std_external *p;
49059024Sobrien	  struct reloc_std_external *pend;
49159024Sobrien
49259024Sobrien	  p = (struct reloc_std_external *) info->dynrel;
49359024Sobrien	  pend = p + info->dynrel_count;
49459024Sobrien	  for (; p < pend; p++, to++)
495218822Sdim	    NAME (aout, swap_std_reloc_in) (abfd, p, to, syms,
496218822Sdim					    (bfd_size_type) info->dynsym_count);
49759024Sobrien	}
49859024Sobrien    }
49959024Sobrien
50059024Sobrien  /* Return pointers to the dynamic arelent structures.  */
50159024Sobrien  for (i = 0; i < info->dynrel_count; i++)
50259024Sobrien    *storage++ = info->canonical_dynrel + i;
50359024Sobrien  *storage = NULL;
50459024Sobrien
50559024Sobrien  return info->dynrel_count;
50659024Sobrien}
50759024Sobrien
50859024Sobrien/* Code to handle linking of SunOS shared libraries.  */
50959024Sobrien
51059024Sobrien/* A SPARC procedure linkage table entry is 12 bytes.  The first entry
51159024Sobrien   in the table is a jump which is filled in by the runtime linker.
51259024Sobrien   The remaining entries are branches back to the first entry,
51359024Sobrien   followed by an index into the relocation table encoded to look like
51459024Sobrien   a sethi of %g0.  */
51559024Sobrien
51659024Sobrien#define SPARC_PLT_ENTRY_SIZE (12)
51759024Sobrien
51859024Sobrienstatic const bfd_byte sparc_plt_first_entry[SPARC_PLT_ENTRY_SIZE] =
51959024Sobrien{
52059024Sobrien  /* sethi %hi(0),%g1; address filled in by runtime linker.  */
52159024Sobrien  0x3, 0, 0, 0,
52259024Sobrien  /* jmp %g1; offset filled in by runtime linker.  */
52359024Sobrien  0x81, 0xc0, 0x60, 0,
52459024Sobrien  /* nop */
52559024Sobrien  0x1, 0, 0, 0
52659024Sobrien};
52759024Sobrien
52859024Sobrien/* save %sp, -96, %sp */
52989857Sobrien#define SPARC_PLT_ENTRY_WORD0 ((bfd_vma) 0x9de3bfa0)
53059024Sobrien/* call; address filled in later.  */
53189857Sobrien#define SPARC_PLT_ENTRY_WORD1 ((bfd_vma) 0x40000000)
53259024Sobrien/* sethi; reloc index filled in later.  */
53389857Sobrien#define SPARC_PLT_ENTRY_WORD2 ((bfd_vma) 0x01000000)
53459024Sobrien
53559024Sobrien/* This sequence is used when for the jump table entry to a defined
53659024Sobrien   symbol in a complete executable.  It is used when linking PIC
53759024Sobrien   compiled code which is not being put into a shared library.  */
53859024Sobrien/* sethi <address to be filled in later>, %g1 */
53989857Sobrien#define SPARC_PLT_PIC_WORD0 ((bfd_vma) 0x03000000)
54059024Sobrien/* jmp %g1 + <address to be filled in later> */
54189857Sobrien#define SPARC_PLT_PIC_WORD1 ((bfd_vma) 0x81c06000)
54259024Sobrien/* nop */
54389857Sobrien#define SPARC_PLT_PIC_WORD2 ((bfd_vma) 0x01000000)
54459024Sobrien
54559024Sobrien/* An m68k procedure linkage table entry is 8 bytes.  The first entry
54659024Sobrien   in the table is a jump which is filled in the by the runtime
54759024Sobrien   linker.  The remaining entries are branches back to the first
54859024Sobrien   entry, followed by a two byte index into the relocation table.  */
54959024Sobrien
55059024Sobrien#define M68K_PLT_ENTRY_SIZE (8)
55159024Sobrien
55259024Sobrienstatic const bfd_byte m68k_plt_first_entry[M68K_PLT_ENTRY_SIZE] =
55359024Sobrien{
55459024Sobrien  /* jmps @# */
55559024Sobrien  0x4e, 0xf9,
55659024Sobrien  /* Filled in by runtime linker with a magic address.  */
55759024Sobrien  0, 0, 0, 0,
55859024Sobrien  /* Not used?  */
55959024Sobrien  0, 0
56059024Sobrien};
56159024Sobrien
56259024Sobrien/* bsrl */
56389857Sobrien#define M68K_PLT_ENTRY_WORD0 ((bfd_vma) 0x61ff)
56459024Sobrien/* Remaining words filled in later.  */
56559024Sobrien
56659024Sobrien/* An entry in the SunOS linker hash table.  */
56759024Sobrien
56859024Sobrienstruct sunos_link_hash_entry
56959024Sobrien{
57059024Sobrien  struct aout_link_hash_entry root;
57159024Sobrien
57259024Sobrien  /* If this is a dynamic symbol, this is its index into the dynamic
57359024Sobrien     symbol table.  This is initialized to -1.  As the linker looks at
57459024Sobrien     the input files, it changes this to -2 if it will be added to the
57559024Sobrien     dynamic symbol table.  After all the input files have been seen,
57659024Sobrien     the linker will know whether to build a dynamic symbol table; if
57759024Sobrien     it does build one, this becomes the index into the table.  */
57859024Sobrien  long dynindx;
57959024Sobrien
58059024Sobrien  /* If this is a dynamic symbol, this is the index of the name in the
58159024Sobrien     dynamic symbol string table.  */
58259024Sobrien  long dynstr_index;
58359024Sobrien
58459024Sobrien  /* The offset into the global offset table used for this symbol.  If
58559024Sobrien     the symbol does not require a GOT entry, this is 0.  */
58659024Sobrien  bfd_vma got_offset;
58759024Sobrien
58859024Sobrien  /* The offset into the procedure linkage table used for this symbol.
58959024Sobrien     If the symbol does not require a PLT entry, this is 0.  */
59059024Sobrien  bfd_vma plt_offset;
59159024Sobrien
59259024Sobrien  /* Some linker flags.  */
59359024Sobrien  unsigned char flags;
59459024Sobrien  /* Symbol is referenced by a regular object.  */
59559024Sobrien#define SUNOS_REF_REGULAR 01
59659024Sobrien  /* Symbol is defined by a regular object.  */
59759024Sobrien#define SUNOS_DEF_REGULAR 02
59859024Sobrien  /* Symbol is referenced by a dynamic object.  */
59959024Sobrien#define SUNOS_REF_DYNAMIC 04
60059024Sobrien  /* Symbol is defined by a dynamic object.  */
60159024Sobrien#define SUNOS_DEF_DYNAMIC 010
60259024Sobrien  /* Symbol is a constructor symbol in a regular object.  */
60359024Sobrien#define SUNOS_CONSTRUCTOR 020
60459024Sobrien};
60559024Sobrien
60659024Sobrien/* The SunOS linker hash table.  */
60759024Sobrien
60859024Sobrienstruct sunos_link_hash_table
60959024Sobrien{
61059024Sobrien  struct aout_link_hash_table root;
61159024Sobrien
61259024Sobrien  /* The object which holds the dynamic sections.  */
61359024Sobrien  bfd *dynobj;
61459024Sobrien
61559024Sobrien  /* Whether we have created the dynamic sections.  */
616130561Sobrien  bfd_boolean dynamic_sections_created;
61759024Sobrien
61859024Sobrien  /* Whether we need the dynamic sections.  */
619130561Sobrien  bfd_boolean dynamic_sections_needed;
62059024Sobrien
62159024Sobrien  /* Whether we need the .got table.  */
622130561Sobrien  bfd_boolean got_needed;
62359024Sobrien
62459024Sobrien  /* The number of dynamic symbols.  */
62559024Sobrien  size_t dynsymcount;
62659024Sobrien
62759024Sobrien  /* The number of buckets in the hash table.  */
62859024Sobrien  size_t bucketcount;
62959024Sobrien
63059024Sobrien  /* The list of dynamic objects needed by dynamic objects included in
63159024Sobrien     the link.  */
63259024Sobrien  struct bfd_link_needed_list *needed;
63359024Sobrien
63459024Sobrien  /* The offset of __GLOBAL_OFFSET_TABLE_ into the .got section.  */
63559024Sobrien  bfd_vma got_base;
63659024Sobrien};
63759024Sobrien
63859024Sobrien/* Routine to create an entry in an SunOS link hash table.  */
63959024Sobrien
64059024Sobrienstatic struct bfd_hash_entry *
641218822Sdimsunos_link_hash_newfunc (struct bfd_hash_entry *entry,
642218822Sdim			 struct bfd_hash_table *table,
643218822Sdim			 const char *string)
64459024Sobrien{
64559024Sobrien  struct sunos_link_hash_entry *ret = (struct sunos_link_hash_entry *) entry;
64659024Sobrien
64759024Sobrien  /* Allocate the structure if it has not already been allocated by a
64859024Sobrien     subclass.  */
649218822Sdim  if (ret ==  NULL)
650218822Sdim    ret = bfd_hash_allocate (table, sizeof (* ret));
651218822Sdim  if (ret == NULL)
652218822Sdim    return NULL;
65359024Sobrien
65459024Sobrien  /* Call the allocation method of the superclass.  */
65559024Sobrien  ret = ((struct sunos_link_hash_entry *)
656218822Sdim	 NAME (aout, link_hash_newfunc) ((struct bfd_hash_entry *) ret,
657218822Sdim					 table, string));
65859024Sobrien  if (ret != NULL)
65959024Sobrien    {
66059024Sobrien      /* Set local fields.  */
66159024Sobrien      ret->dynindx = -1;
66259024Sobrien      ret->dynstr_index = -1;
66359024Sobrien      ret->got_offset = 0;
66459024Sobrien      ret->plt_offset = 0;
66559024Sobrien      ret->flags = 0;
66659024Sobrien    }
66759024Sobrien
66859024Sobrien  return (struct bfd_hash_entry *) ret;
66959024Sobrien}
67059024Sobrien
67159024Sobrien/* Create a SunOS link hash table.  */
67259024Sobrien
67359024Sobrienstatic struct bfd_link_hash_table *
674218822Sdimsunos_link_hash_table_create (bfd *abfd)
67559024Sobrien{
67659024Sobrien  struct sunos_link_hash_table *ret;
67789857Sobrien  bfd_size_type amt = sizeof (struct sunos_link_hash_table);
67859024Sobrien
679218822Sdim  ret = bfd_malloc (amt);
680218822Sdim  if (ret ==  NULL)
681218822Sdim    return NULL;
682218822Sdim  if (!NAME (aout, link_hash_table_init) (&ret->root, abfd,
683218822Sdim					  sunos_link_hash_newfunc,
684218822Sdim					  sizeof (struct sunos_link_hash_entry)))
68559024Sobrien    {
686104834Sobrien      free (ret);
687218822Sdim      return NULL;
68859024Sobrien    }
68959024Sobrien
69059024Sobrien  ret->dynobj = NULL;
691130561Sobrien  ret->dynamic_sections_created = FALSE;
692130561Sobrien  ret->dynamic_sections_needed = FALSE;
693130561Sobrien  ret->got_needed = FALSE;
69459024Sobrien  ret->dynsymcount = 0;
69559024Sobrien  ret->bucketcount = 0;
69659024Sobrien  ret->needed = NULL;
69759024Sobrien  ret->got_base = 0;
69859024Sobrien
69959024Sobrien  return &ret->root.root;
70059024Sobrien}
70159024Sobrien
70259024Sobrien/* Look up an entry in an SunOS link hash table.  */
70359024Sobrien
70459024Sobrien#define sunos_link_hash_lookup(table, string, create, copy, follow) \
70559024Sobrien  ((struct sunos_link_hash_entry *) \
70659024Sobrien   aout_link_hash_lookup (&(table)->root, (string), (create), (copy),\
70759024Sobrien			  (follow)))
70859024Sobrien
70959024Sobrien/* Traverse a SunOS link hash table.  */
71059024Sobrien
71159024Sobrien#define sunos_link_hash_traverse(table, func, info)			\
71259024Sobrien  (aout_link_hash_traverse						\
71359024Sobrien   (&(table)->root,							\
714218822Sdim    (bfd_boolean (*) (struct aout_link_hash_entry *, void *)) (func),	\
71559024Sobrien    (info)))
71659024Sobrien
71759024Sobrien/* Get the SunOS link hash table from the info structure.  This is
71859024Sobrien   just a cast.  */
71959024Sobrien
72059024Sobrien#define sunos_hash_table(p) ((struct sunos_link_hash_table *) ((p)->hash))
72159024Sobrien
72259024Sobrien/* Create the dynamic sections needed if we are linking against a
72359024Sobrien   dynamic object, or if we are linking PIC compiled code.  ABFD is a
72459024Sobrien   bfd we can attach the dynamic sections to.  The linker script will
72559024Sobrien   look for these special sections names and put them in the right
72659024Sobrien   place in the output file.  See include/aout/sun4.h for more details
72759024Sobrien   of the dynamic linking information.  */
72859024Sobrien
729130561Sobrienstatic bfd_boolean
730218822Sdimsunos_create_dynamic_sections (bfd *abfd,
731218822Sdim			       struct bfd_link_info *info,
732218822Sdim			       bfd_boolean needed)
73359024Sobrien{
73459024Sobrien  asection *s;
73559024Sobrien
73659024Sobrien  if (! sunos_hash_table (info)->dynamic_sections_created)
73759024Sobrien    {
73859024Sobrien      flagword flags;
73959024Sobrien
74059024Sobrien      sunos_hash_table (info)->dynobj = abfd;
74159024Sobrien
74259024Sobrien      flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY
74359024Sobrien	       | SEC_LINKER_CREATED);
74459024Sobrien
74559024Sobrien      /* The .dynamic section holds the basic dynamic information: the
74659024Sobrien	 sun4_dynamic structure, the dynamic debugger information, and
74759024Sobrien	 the sun4_dynamic_link structure.  */
748218822Sdim      s = bfd_make_section_with_flags (abfd, ".dynamic", flags);
74959024Sobrien      if (s == NULL
75059024Sobrien	  || ! bfd_set_section_alignment (abfd, s, 2))
751130561Sobrien	return FALSE;
75259024Sobrien
75359024Sobrien      /* The .got section holds the global offset table.  The address
75459024Sobrien	 is put in the ld_got field.  */
755218822Sdim      s = bfd_make_section_with_flags (abfd, ".got", flags);
75659024Sobrien      if (s == NULL
75759024Sobrien	  || ! bfd_set_section_alignment (abfd, s, 2))
758130561Sobrien	return FALSE;
75959024Sobrien
76059024Sobrien      /* The .plt section holds the procedure linkage table.  The
76159024Sobrien	 address is put in the ld_plt field.  */
762218822Sdim      s = bfd_make_section_with_flags (abfd, ".plt", flags | SEC_CODE);
76359024Sobrien      if (s == NULL
76459024Sobrien	  || ! bfd_set_section_alignment (abfd, s, 2))
765130561Sobrien	return FALSE;
76659024Sobrien
76759024Sobrien      /* The .dynrel section holds the dynamic relocs.  The address is
76859024Sobrien	 put in the ld_rel field.  */
769218822Sdim      s = bfd_make_section_with_flags (abfd, ".dynrel", flags | SEC_READONLY);
77059024Sobrien      if (s == NULL
77159024Sobrien	  || ! bfd_set_section_alignment (abfd, s, 2))
772130561Sobrien	return FALSE;
77359024Sobrien
77459024Sobrien      /* The .hash section holds the dynamic hash table.  The address
77559024Sobrien	 is put in the ld_hash field.  */
776218822Sdim      s = bfd_make_section_with_flags (abfd, ".hash", flags | SEC_READONLY);
77759024Sobrien      if (s == NULL
77859024Sobrien	  || ! bfd_set_section_alignment (abfd, s, 2))
779130561Sobrien	return FALSE;
78059024Sobrien
78159024Sobrien      /* The .dynsym section holds the dynamic symbols.  The address
78259024Sobrien	 is put in the ld_stab field.  */
783218822Sdim      s = bfd_make_section_with_flags (abfd, ".dynsym", flags | SEC_READONLY);
78459024Sobrien      if (s == NULL
78559024Sobrien	  || ! bfd_set_section_alignment (abfd, s, 2))
786130561Sobrien	return FALSE;
78759024Sobrien
78859024Sobrien      /* The .dynstr section holds the dynamic symbol string table.
78959024Sobrien	 The address is put in the ld_symbols field.  */
790218822Sdim      s = bfd_make_section_with_flags (abfd, ".dynstr", flags | SEC_READONLY);
79159024Sobrien      if (s == NULL
79259024Sobrien	  || ! bfd_set_section_alignment (abfd, s, 2))
793130561Sobrien	return FALSE;
79459024Sobrien
795130561Sobrien      sunos_hash_table (info)->dynamic_sections_created = TRUE;
79659024Sobrien    }
79759024Sobrien
79859024Sobrien  if ((needed && ! sunos_hash_table (info)->dynamic_sections_needed)
79959024Sobrien      || info->shared)
80059024Sobrien    {
80159024Sobrien      bfd *dynobj;
80259024Sobrien
80359024Sobrien      dynobj = sunos_hash_table (info)->dynobj;
80459024Sobrien
80559024Sobrien      s = bfd_get_section_by_name (dynobj, ".got");
806218822Sdim      if (s->size == 0)
807218822Sdim	s->size = BYTES_IN_WORD;
80859024Sobrien
809130561Sobrien      sunos_hash_table (info)->dynamic_sections_needed = TRUE;
810130561Sobrien      sunos_hash_table (info)->got_needed = TRUE;
81159024Sobrien    }
81259024Sobrien
813130561Sobrien  return TRUE;
81459024Sobrien}
81559024Sobrien
81659024Sobrien/* Add dynamic symbols during a link.  This is called by the a.out
81759024Sobrien   backend linker for each object it encounters.  */
81859024Sobrien
819130561Sobrienstatic bfd_boolean
820218822Sdimsunos_add_dynamic_symbols (bfd *abfd,
821218822Sdim			   struct bfd_link_info *info,
822218822Sdim			   struct external_nlist **symsp,
823218822Sdim			   bfd_size_type *sym_countp,
824218822Sdim			   char **stringsp)
82559024Sobrien{
82659024Sobrien  bfd *dynobj;
82759024Sobrien  struct sunos_dynamic_info *dinfo;
82859024Sobrien  unsigned long need;
82959024Sobrien
83059024Sobrien  /* Make sure we have all the required sections.  */
83159024Sobrien  if (info->hash->creator == abfd->xvec)
83259024Sobrien    {
83359024Sobrien      if (! sunos_create_dynamic_sections (abfd, info,
834130561Sobrien					   ((abfd->flags & DYNAMIC) != 0
835130561Sobrien					    && !info->relocatable)))
836130561Sobrien	return FALSE;
83759024Sobrien    }
83859024Sobrien
83959024Sobrien  /* There is nothing else to do for a normal object.  */
84059024Sobrien  if ((abfd->flags & DYNAMIC) == 0)
841130561Sobrien    return TRUE;
84259024Sobrien
84359024Sobrien  dynobj = sunos_hash_table (info)->dynobj;
84459024Sobrien
84559024Sobrien  /* We do not want to include the sections in a dynamic object in the
84659024Sobrien     output file.  We hack by simply clobbering the list of sections
84759024Sobrien     in the BFD.  This could be handled more cleanly by, say, a new
84859024Sobrien     section flag; the existing SEC_NEVER_LOAD flag is not the one we
84959024Sobrien     want, because that one still implies that the section takes up
85059024Sobrien     space in the output file.  If this is the first object we have
85159024Sobrien     seen, we must preserve the dynamic sections we just created.  */
852218822Sdim  if (abfd != dynobj)
853218822Sdim    abfd->sections = NULL;
854218822Sdim  else
85559024Sobrien    {
856218822Sdim      asection *s;
857218822Sdim
858218822Sdim      for (s = abfd->sections; s != NULL; s = s->next)
859218822Sdim	{
860218822Sdim	  if ((s->flags & SEC_LINKER_CREATED) == 0)
861218822Sdim	    bfd_section_list_remove (abfd, s);
862218822Sdim	}
86359024Sobrien    }
86459024Sobrien
86559024Sobrien  /* The native linker seems to just ignore dynamic objects when -r is
86659024Sobrien     used.  */
867130561Sobrien  if (info->relocatable)
868130561Sobrien    return TRUE;
86959024Sobrien
87059024Sobrien  /* There's no hope of using a dynamic object which does not exactly
87159024Sobrien     match the format of the output file.  */
87259024Sobrien  if (info->hash->creator != abfd->xvec)
87359024Sobrien    {
87459024Sobrien      bfd_set_error (bfd_error_invalid_operation);
875130561Sobrien      return FALSE;
87659024Sobrien    }
87759024Sobrien
87859024Sobrien  /* Make sure we have a .need and a .rules sections.  These are only
87959024Sobrien     needed if there really is a dynamic object in the link, so they
88059024Sobrien     are not added by sunos_create_dynamic_sections.  */
88159024Sobrien  if (bfd_get_section_by_name (dynobj, ".need") == NULL)
88259024Sobrien    {
88359024Sobrien      /* The .need section holds the list of names of shared objets
88459024Sobrien	 which must be included at runtime.  The address of this
88559024Sobrien	 section is put in the ld_need field.  */
886218822Sdim      flagword flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS
887218822Sdim			| SEC_IN_MEMORY | SEC_READONLY);
888218822Sdim      asection *s = bfd_make_section_with_flags (dynobj, ".need", flags);
88959024Sobrien      if (s == NULL
89059024Sobrien	  || ! bfd_set_section_alignment (dynobj, s, 2))
891130561Sobrien	return FALSE;
89259024Sobrien    }
89359024Sobrien
89459024Sobrien  if (bfd_get_section_by_name (dynobj, ".rules") == NULL)
89559024Sobrien    {
89659024Sobrien      /* The .rules section holds the path to search for shared
89759024Sobrien	 objects.  The address of this section is put in the ld_rules
89859024Sobrien	 field.  */
899218822Sdim      flagword flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS
900218822Sdim			| SEC_IN_MEMORY | SEC_READONLY);
901218822Sdim      asection *s = bfd_make_section_with_flags (dynobj, ".rules", flags);
90259024Sobrien      if (s == NULL
90359024Sobrien	  || ! bfd_set_section_alignment (dynobj, s, 2))
904130561Sobrien	return FALSE;
90559024Sobrien    }
90659024Sobrien
90759024Sobrien  /* Pick up the dynamic symbols and return them to the caller.  */
90859024Sobrien  if (! sunos_slurp_dynamic_symtab (abfd))
909130561Sobrien    return FALSE;
91059024Sobrien
91159024Sobrien  dinfo = (struct sunos_dynamic_info *) obj_aout_dynamic_info (abfd);
91259024Sobrien  *symsp = dinfo->dynsym;
91359024Sobrien  *sym_countp = dinfo->dynsym_count;
91459024Sobrien  *stringsp = dinfo->dynstr;
91559024Sobrien
91659024Sobrien  /* Record information about any other objects needed by this one.  */
91759024Sobrien  need = dinfo->dyninfo.ld_need;
91859024Sobrien  while (need != 0)
91959024Sobrien    {
92059024Sobrien      bfd_byte buf[16];
92159024Sobrien      unsigned long name, flags;
92259024Sobrien      unsigned short major_vno, minor_vno;
92359024Sobrien      struct bfd_link_needed_list *needed, **pp;
92459024Sobrien      char *namebuf, *p;
92589857Sobrien      bfd_size_type alc;
92659024Sobrien      bfd_byte b;
92759024Sobrien      char *namecopy;
92859024Sobrien
92989857Sobrien      if (bfd_seek (abfd, (file_ptr) need, SEEK_SET) != 0
93089857Sobrien	  || bfd_bread (buf, (bfd_size_type) 16, abfd) != 16)
931130561Sobrien	return FALSE;
93259024Sobrien
93359024Sobrien      /* For the format of an ld_need entry, see aout/sun4.h.  We
934130561Sobrien	 should probably define structs for this manipulation.  */
93559024Sobrien      name = bfd_get_32 (abfd, buf);
93659024Sobrien      flags = bfd_get_32 (abfd, buf + 4);
93789857Sobrien      major_vno = (unsigned short) bfd_get_16 (abfd, buf + 8);
93889857Sobrien      minor_vno = (unsigned short) bfd_get_16 (abfd, buf + 10);
93959024Sobrien      need = bfd_get_32 (abfd, buf + 12);
94059024Sobrien
94189857Sobrien      alc = sizeof (struct bfd_link_needed_list);
942218822Sdim      needed = bfd_alloc (abfd, alc);
94359024Sobrien      if (needed == NULL)
944130561Sobrien	return FALSE;
94559024Sobrien      needed->by = abfd;
94659024Sobrien
94759024Sobrien      /* We return the name as [-l]name[.maj][.min].  */
94859024Sobrien      alc = 30;
949218822Sdim      namebuf = bfd_malloc (alc + 1);
95059024Sobrien      if (namebuf == NULL)
951130561Sobrien	return FALSE;
95259024Sobrien      p = namebuf;
95359024Sobrien
95459024Sobrien      if ((flags & 0x80000000) != 0)
95559024Sobrien	{
95659024Sobrien	  *p++ = '-';
95759024Sobrien	  *p++ = 'l';
95859024Sobrien	}
95989857Sobrien      if (bfd_seek (abfd, (file_ptr) name, SEEK_SET) != 0)
96059024Sobrien	{
96159024Sobrien	  free (namebuf);
962130561Sobrien	  return FALSE;
96359024Sobrien	}
96459024Sobrien
96559024Sobrien      do
96659024Sobrien	{
96789857Sobrien	  if (bfd_bread (&b, (bfd_size_type) 1, abfd) != 1)
96859024Sobrien	    {
96959024Sobrien	      free (namebuf);
970130561Sobrien	      return FALSE;
97159024Sobrien	    }
97259024Sobrien
97389857Sobrien	  if ((bfd_size_type) (p - namebuf) >= alc)
97459024Sobrien	    {
97559024Sobrien	      char *n;
97659024Sobrien
97759024Sobrien	      alc *= 2;
978218822Sdim	      n = bfd_realloc (namebuf, alc + 1);
97959024Sobrien	      if (n == NULL)
98059024Sobrien		{
98159024Sobrien		  free (namebuf);
982130561Sobrien		  return FALSE;
98359024Sobrien		}
98459024Sobrien	      p = n + (p - namebuf);
98559024Sobrien	      namebuf = n;
98659024Sobrien	    }
98759024Sobrien
98859024Sobrien	  *p++ = b;
98959024Sobrien	}
99059024Sobrien      while (b != '\0');
99159024Sobrien
99259024Sobrien      if (major_vno == 0)
99359024Sobrien	*p = '\0';
99459024Sobrien      else
99559024Sobrien	{
99659024Sobrien	  char majbuf[30];
99759024Sobrien	  char minbuf[30];
99859024Sobrien
99959024Sobrien	  sprintf (majbuf, ".%d", major_vno);
100059024Sobrien	  if (minor_vno == 0)
100159024Sobrien	    minbuf[0] = '\0';
100259024Sobrien	  else
100359024Sobrien	    sprintf (minbuf, ".%d", minor_vno);
100459024Sobrien
100559024Sobrien	  if ((p - namebuf) + strlen (majbuf) + strlen (minbuf) >= alc)
100659024Sobrien	    {
100759024Sobrien	      char *n;
100859024Sobrien
100959024Sobrien	      alc = (p - namebuf) + strlen (majbuf) + strlen (minbuf);
1010218822Sdim	      n = bfd_realloc (namebuf, alc + 1);
101159024Sobrien	      if (n == NULL)
101259024Sobrien		{
101359024Sobrien		  free (namebuf);
1014130561Sobrien		  return FALSE;
101559024Sobrien		}
101659024Sobrien	      p = n + (p - namebuf);
101759024Sobrien	      namebuf = n;
101859024Sobrien	    }
101959024Sobrien
102059024Sobrien	  strcpy (p, majbuf);
102159024Sobrien	  strcat (p, minbuf);
102259024Sobrien	}
102359024Sobrien
102489857Sobrien      namecopy = bfd_alloc (abfd, (bfd_size_type) strlen (namebuf) + 1);
102559024Sobrien      if (namecopy == NULL)
102659024Sobrien	{
102759024Sobrien	  free (namebuf);
1028130561Sobrien	  return FALSE;
102959024Sobrien	}
103059024Sobrien      strcpy (namecopy, namebuf);
103159024Sobrien      free (namebuf);
103259024Sobrien      needed->name = namecopy;
103359024Sobrien
103459024Sobrien      needed->next = NULL;
103559024Sobrien
103659024Sobrien      for (pp = &sunos_hash_table (info)->needed;
103759024Sobrien	   *pp != NULL;
103859024Sobrien	   pp = &(*pp)->next)
103959024Sobrien	;
104059024Sobrien      *pp = needed;
104159024Sobrien    }
104259024Sobrien
1043130561Sobrien  return TRUE;
104459024Sobrien}
104559024Sobrien
104659024Sobrien/* Function to add a single symbol to the linker hash table.  This is
104759024Sobrien   a wrapper around _bfd_generic_link_add_one_symbol which handles the
104859024Sobrien   tweaking needed for dynamic linking support.  */
104959024Sobrien
1050130561Sobrienstatic bfd_boolean
1051218822Sdimsunos_add_one_symbol (struct bfd_link_info *info,
1052218822Sdim		      bfd *abfd,
1053218822Sdim		      const char *name,
1054218822Sdim		      flagword flags,
1055218822Sdim		      asection *section,
1056218822Sdim		      bfd_vma value,
1057218822Sdim		      const char *string,
1058218822Sdim		      bfd_boolean copy,
1059218822Sdim		      bfd_boolean collect,
1060218822Sdim		      struct bfd_link_hash_entry **hashp)
106159024Sobrien{
106259024Sobrien  struct sunos_link_hash_entry *h;
106359024Sobrien  int new_flag;
106459024Sobrien
106559024Sobrien  if ((flags & (BSF_INDIRECT | BSF_WARNING | BSF_CONSTRUCTOR)) != 0
106659024Sobrien      || ! bfd_is_und_section (section))
1067130561Sobrien    h = sunos_link_hash_lookup (sunos_hash_table (info), name, TRUE, copy,
1068130561Sobrien				FALSE);
106959024Sobrien  else
107059024Sobrien    h = ((struct sunos_link_hash_entry *)
1071130561Sobrien	 bfd_wrapped_link_hash_lookup (abfd, info, name, TRUE, copy, FALSE));
107259024Sobrien  if (h == NULL)
1073130561Sobrien    return FALSE;
107459024Sobrien
107559024Sobrien  if (hashp != NULL)
107659024Sobrien    *hashp = (struct bfd_link_hash_entry *) h;
107759024Sobrien
107859024Sobrien  /* Treat a common symbol in a dynamic object as defined in the .bss
107959024Sobrien     section of the dynamic object.  We don't want to allocate space
108059024Sobrien     for it in our process image.  */
108159024Sobrien  if ((abfd->flags & DYNAMIC) != 0
108259024Sobrien      && bfd_is_com_section (section))
108359024Sobrien    section = obj_bsssec (abfd);
108459024Sobrien
108559024Sobrien  if (! bfd_is_und_section (section)
108659024Sobrien      && h->root.root.type != bfd_link_hash_new
108759024Sobrien      && h->root.root.type != bfd_link_hash_undefined
108859024Sobrien      && h->root.root.type != bfd_link_hash_defweak)
108959024Sobrien    {
109059024Sobrien      /* We are defining the symbol, and it is already defined.  This
109159024Sobrien	 is a potential multiple definition error.  */
109259024Sobrien      if ((abfd->flags & DYNAMIC) != 0)
109359024Sobrien	{
109459024Sobrien	  /* The definition we are adding is from a dynamic object.
109559024Sobrien	     We do not want this new definition to override the
109659024Sobrien	     existing definition, so we pretend it is just a
109759024Sobrien	     reference.  */
109859024Sobrien	  section = bfd_und_section_ptr;
109959024Sobrien	}
110059024Sobrien      else if (h->root.root.type == bfd_link_hash_defined
110159024Sobrien	       && h->root.root.u.def.section->owner != NULL
110259024Sobrien	       && (h->root.root.u.def.section->owner->flags & DYNAMIC) != 0)
110359024Sobrien	{
110459024Sobrien	  /* The existing definition is from a dynamic object.  We
110559024Sobrien	     want to override it with the definition we just found.
110659024Sobrien	     Clobber the existing definition.  */
110759024Sobrien	  h->root.root.type = bfd_link_hash_undefined;
110859024Sobrien	  h->root.root.u.undef.abfd = h->root.root.u.def.section->owner;
110959024Sobrien	}
111059024Sobrien      else if (h->root.root.type == bfd_link_hash_common
111159024Sobrien	       && (h->root.root.u.c.p->section->owner->flags & DYNAMIC) != 0)
111259024Sobrien	{
111359024Sobrien	  /* The existing definition is from a dynamic object.  We
111459024Sobrien	     want to override it with the definition we just found.
111559024Sobrien	     Clobber the existing definition.  We can't set it to new,
111659024Sobrien	     because it is on the undefined list.  */
111759024Sobrien	  h->root.root.type = bfd_link_hash_undefined;
111859024Sobrien	  h->root.root.u.undef.abfd = h->root.root.u.c.p->section->owner;
111959024Sobrien	}
112059024Sobrien    }
112159024Sobrien
112259024Sobrien  if ((abfd->flags & DYNAMIC) != 0
112359024Sobrien      && abfd->xvec == info->hash->creator
112459024Sobrien      && (h->flags & SUNOS_CONSTRUCTOR) != 0)
1125218822Sdim    /* The existing symbol is a constructor symbol, and this symbol
1126218822Sdim       is from a dynamic object.  A constructor symbol is actually a
1127218822Sdim       definition, although the type will be bfd_link_hash_undefined
1128218822Sdim       at this point.  We want to ignore the definition from the
1129218822Sdim       dynamic object.  */
1130218822Sdim    section = bfd_und_section_ptr;
113159024Sobrien  else if ((flags & BSF_CONSTRUCTOR) != 0
113259024Sobrien	   && (abfd->flags & DYNAMIC) == 0
113359024Sobrien	   && h->root.root.type == bfd_link_hash_defined
113459024Sobrien	   && h->root.root.u.def.section->owner != NULL
113559024Sobrien	   && (h->root.root.u.def.section->owner->flags & DYNAMIC) != 0)
1136218822Sdim    /* The existing symbol is defined by a dynamic object, and this
1137218822Sdim       is a constructor symbol.  As above, we want to force the use
1138218822Sdim       of the constructor symbol from the regular object.  */
1139218822Sdim    h->root.root.type = bfd_link_hash_new;
114059024Sobrien
114159024Sobrien  /* Do the usual procedure for adding a symbol.  */
114259024Sobrien  if (! _bfd_generic_link_add_one_symbol (info, abfd, name, flags, section,
114359024Sobrien					  value, string, copy, collect,
114459024Sobrien					  hashp))
1145130561Sobrien    return FALSE;
114659024Sobrien
114759024Sobrien  if (abfd->xvec == info->hash->creator)
114859024Sobrien    {
114959024Sobrien      /* Set a flag in the hash table entry indicating the type of
115059024Sobrien	 reference or definition we just found.  Keep a count of the
115159024Sobrien	 number of dynamic symbols we find.  A dynamic symbol is one
115259024Sobrien	 which is referenced or defined by both a regular object and a
115359024Sobrien	 shared object.  */
115459024Sobrien      if ((abfd->flags & DYNAMIC) == 0)
115559024Sobrien	{
115659024Sobrien	  if (bfd_is_und_section (section))
115759024Sobrien	    new_flag = SUNOS_REF_REGULAR;
115859024Sobrien	  else
115959024Sobrien	    new_flag = SUNOS_DEF_REGULAR;
116059024Sobrien	}
116159024Sobrien      else
116259024Sobrien	{
116359024Sobrien	  if (bfd_is_und_section (section))
116459024Sobrien	    new_flag = SUNOS_REF_DYNAMIC;
116559024Sobrien	  else
116659024Sobrien	    new_flag = SUNOS_DEF_DYNAMIC;
116759024Sobrien	}
116859024Sobrien      h->flags |= new_flag;
116959024Sobrien
117059024Sobrien      if (h->dynindx == -1
117159024Sobrien	  && (h->flags & (SUNOS_DEF_REGULAR | SUNOS_REF_REGULAR)) != 0)
117259024Sobrien	{
117359024Sobrien	  ++sunos_hash_table (info)->dynsymcount;
117459024Sobrien	  h->dynindx = -2;
117559024Sobrien	}
117659024Sobrien
117759024Sobrien      if ((flags & BSF_CONSTRUCTOR) != 0
117859024Sobrien	  && (abfd->flags & DYNAMIC) == 0)
117959024Sobrien	h->flags |= SUNOS_CONSTRUCTOR;
118059024Sobrien    }
118159024Sobrien
1182130561Sobrien  return TRUE;
118359024Sobrien}
118459024Sobrien
1185218822Sdimextern const bfd_target MY (vec);
1186218822Sdim
118759024Sobrien/* Return the list of objects needed by BFD.  */
118859024Sobrien
118959024Sobrienstruct bfd_link_needed_list *
1190218822Sdimbfd_sunos_get_needed_list (bfd *abfd ATTRIBUTE_UNUSED,
1191218822Sdim			   struct bfd_link_info *info)
119259024Sobrien{
1193218822Sdim  if (info->hash->creator != &MY (vec))
119459024Sobrien    return NULL;
119559024Sobrien  return sunos_hash_table (info)->needed;
119659024Sobrien}
119759024Sobrien
119859024Sobrien/* Record an assignment made to a symbol by a linker script.  We need
119959024Sobrien   this in case some dynamic object refers to this symbol.  */
120059024Sobrien
1201130561Sobrienbfd_boolean
1202218822Sdimbfd_sunos_record_link_assignment (bfd *output_bfd,
1203218822Sdim				  struct bfd_link_info *info,
1204218822Sdim				  const char *name)
120559024Sobrien{
120659024Sobrien  struct sunos_link_hash_entry *h;
120759024Sobrien
120859024Sobrien  if (output_bfd->xvec != &MY(vec))
1209130561Sobrien    return TRUE;
121059024Sobrien
121159024Sobrien  /* This is called after we have examined all the input objects.  If
121259024Sobrien     the symbol does not exist, it merely means that no object refers
121359024Sobrien     to it, and we can just ignore it at this point.  */
121459024Sobrien  h = sunos_link_hash_lookup (sunos_hash_table (info), name,
1215130561Sobrien			      FALSE, FALSE, FALSE);
121659024Sobrien  if (h == NULL)
1217130561Sobrien    return TRUE;
121859024Sobrien
121959024Sobrien  /* In a shared library, the __DYNAMIC symbol does not appear in the
122059024Sobrien     dynamic symbol table.  */
122159024Sobrien  if (! info->shared || strcmp (name, "__DYNAMIC") != 0)
122259024Sobrien    {
122359024Sobrien      h->flags |= SUNOS_DEF_REGULAR;
122459024Sobrien
122559024Sobrien      if (h->dynindx == -1)
122659024Sobrien	{
122759024Sobrien	  ++sunos_hash_table (info)->dynsymcount;
122859024Sobrien	  h->dynindx = -2;
122959024Sobrien	}
123059024Sobrien    }
123159024Sobrien
1232130561Sobrien  return TRUE;
123359024Sobrien}
123459024Sobrien
123559024Sobrien/* Scan the relocs for an input section using standard relocs.  We
123659024Sobrien   need to figure out what to do for each reloc against a dynamic
123759024Sobrien   symbol.  If the symbol is in the .text section, an entry is made in
123859024Sobrien   the procedure linkage table.  Note that this will do the wrong
123959024Sobrien   thing if the symbol is actually data; I don't think the Sun 3
124059024Sobrien   native linker handles this case correctly either.  If the symbol is
124159024Sobrien   not in the .text section, we must preserve the reloc as a dynamic
124259024Sobrien   reloc.  FIXME: We should also handle the PIC relocs here by
124359024Sobrien   building global offset table entries.  */
124459024Sobrien
1245130561Sobrienstatic bfd_boolean
1246218822Sdimsunos_scan_std_relocs (struct bfd_link_info *info,
1247218822Sdim		       bfd *abfd,
1248218822Sdim		       asection *sec ATTRIBUTE_UNUSED,
1249218822Sdim		       const struct reloc_std_external *relocs,
1250218822Sdim		       bfd_size_type rel_size)
125159024Sobrien{
125259024Sobrien  bfd *dynobj;
125359024Sobrien  asection *splt = NULL;
125459024Sobrien  asection *srel = NULL;
125559024Sobrien  struct sunos_link_hash_entry **sym_hashes;
125659024Sobrien  const struct reloc_std_external *rel, *relend;
125759024Sobrien
125859024Sobrien  /* We only know how to handle m68k plt entries.  */
125959024Sobrien  if (bfd_get_arch (abfd) != bfd_arch_m68k)
126059024Sobrien    {
126159024Sobrien      bfd_set_error (bfd_error_invalid_target);
1262130561Sobrien      return FALSE;
126359024Sobrien    }
126459024Sobrien
126559024Sobrien  dynobj = NULL;
126659024Sobrien
126759024Sobrien  sym_hashes = (struct sunos_link_hash_entry **) obj_aout_sym_hashes (abfd);
126859024Sobrien
126959024Sobrien  relend = relocs + rel_size / RELOC_STD_SIZE;
127059024Sobrien  for (rel = relocs; rel < relend; rel++)
127159024Sobrien    {
127259024Sobrien      int r_index;
127359024Sobrien      struct sunos_link_hash_entry *h;
127459024Sobrien
127559024Sobrien      /* We only want relocs against external symbols.  */
127659024Sobrien      if (bfd_header_big_endian (abfd))
127759024Sobrien	{
127859024Sobrien	  if ((rel->r_type[0] & RELOC_STD_BITS_EXTERN_BIG) == 0)
127959024Sobrien	    continue;
128059024Sobrien	}
128159024Sobrien      else
128259024Sobrien	{
128359024Sobrien	  if ((rel->r_type[0] & RELOC_STD_BITS_EXTERN_LITTLE) == 0)
128459024Sobrien	    continue;
128559024Sobrien	}
128659024Sobrien
128759024Sobrien      /* Get the symbol index.  */
128859024Sobrien      if (bfd_header_big_endian (abfd))
128959024Sobrien	r_index = ((rel->r_index[0] << 16)
129059024Sobrien		   | (rel->r_index[1] << 8)
129159024Sobrien		   | rel->r_index[2]);
129259024Sobrien      else
129359024Sobrien	r_index = ((rel->r_index[2] << 16)
129459024Sobrien		   | (rel->r_index[1] << 8)
129559024Sobrien		   | rel->r_index[0]);
129659024Sobrien
129759024Sobrien      /* Get the hash table entry.  */
129859024Sobrien      h = sym_hashes[r_index];
129959024Sobrien      if (h == NULL)
1300218822Sdim	/* This should not normally happen, but it will in any case
1301218822Sdim	   be caught in the relocation phase.  */
1302218822Sdim	continue;
130359024Sobrien
130459024Sobrien      /* At this point common symbols have already been allocated, so
130559024Sobrien	 we don't have to worry about them.  We need to consider that
130659024Sobrien	 we may have already seen this symbol and marked it undefined;
130759024Sobrien	 if the symbol is really undefined, then SUNOS_DEF_DYNAMIC
130859024Sobrien	 will be zero.  */
130959024Sobrien      if (h->root.root.type != bfd_link_hash_defined
131059024Sobrien	  && h->root.root.type != bfd_link_hash_defweak
131159024Sobrien	  && h->root.root.type != bfd_link_hash_undefined)
131259024Sobrien	continue;
131359024Sobrien
131459024Sobrien      if ((h->flags & SUNOS_DEF_DYNAMIC) == 0
131559024Sobrien	  || (h->flags & SUNOS_DEF_REGULAR) != 0)
131659024Sobrien	continue;
131759024Sobrien
131859024Sobrien      if (dynobj == NULL)
131959024Sobrien	{
132059024Sobrien	  asection *sgot;
132159024Sobrien
1322130561Sobrien	  if (! sunos_create_dynamic_sections (abfd, info, FALSE))
1323130561Sobrien	    return FALSE;
132459024Sobrien	  dynobj = sunos_hash_table (info)->dynobj;
132559024Sobrien	  splt = bfd_get_section_by_name (dynobj, ".plt");
132659024Sobrien	  srel = bfd_get_section_by_name (dynobj, ".dynrel");
132759024Sobrien	  BFD_ASSERT (splt != NULL && srel != NULL);
132859024Sobrien
132959024Sobrien	  sgot = bfd_get_section_by_name (dynobj, ".got");
133059024Sobrien	  BFD_ASSERT (sgot != NULL);
1331218822Sdim	  if (sgot->size == 0)
1332218822Sdim	    sgot->size = BYTES_IN_WORD;
1333130561Sobrien	  sunos_hash_table (info)->got_needed = TRUE;
133459024Sobrien	}
133559024Sobrien
133659024Sobrien      BFD_ASSERT ((h->flags & SUNOS_REF_REGULAR) != 0);
133759024Sobrien      BFD_ASSERT (h->plt_offset != 0
133859024Sobrien		  || ((h->root.root.type == bfd_link_hash_defined
133959024Sobrien		       || h->root.root.type == bfd_link_hash_defweak)
134059024Sobrien		      ? (h->root.root.u.def.section->owner->flags
134159024Sobrien			 & DYNAMIC) != 0
134259024Sobrien		      : (h->root.root.u.undef.abfd->flags & DYNAMIC) != 0));
134359024Sobrien
134459024Sobrien      /* This reloc is against a symbol defined only by a dynamic
134559024Sobrien	 object.  */
134659024Sobrien      if (h->root.root.type == bfd_link_hash_undefined)
1347218822Sdim	/* Presumably this symbol was marked as being undefined by
1348218822Sdim	   an earlier reloc.  */
1349218822Sdim	srel->size += RELOC_STD_SIZE;
135059024Sobrien      else if ((h->root.root.u.def.section->flags & SEC_CODE) == 0)
135159024Sobrien	{
135259024Sobrien	  bfd *sub;
135359024Sobrien
135459024Sobrien	  /* This reloc is not in the .text section.  It must be
135559024Sobrien	     copied into the dynamic relocs.  We mark the symbol as
135659024Sobrien	     being undefined.  */
1357218822Sdim	  srel->size += RELOC_STD_SIZE;
135859024Sobrien	  sub = h->root.root.u.def.section->owner;
135959024Sobrien	  h->root.root.type = bfd_link_hash_undefined;
136059024Sobrien	  h->root.root.u.undef.abfd = sub;
136159024Sobrien	}
136259024Sobrien      else
136359024Sobrien	{
136459024Sobrien	  /* This symbol is in the .text section.  We must give it an
136559024Sobrien	     entry in the procedure linkage table, if we have not
136659024Sobrien	     already done so.  We change the definition of the symbol
136759024Sobrien	     to the .plt section; this will cause relocs against it to
136859024Sobrien	     be handled correctly.  */
136959024Sobrien	  if (h->plt_offset == 0)
137059024Sobrien	    {
1371218822Sdim	      if (splt->size == 0)
1372218822Sdim		splt->size = M68K_PLT_ENTRY_SIZE;
1373218822Sdim	      h->plt_offset = splt->size;
137459024Sobrien
137559024Sobrien	      if ((h->flags & SUNOS_DEF_REGULAR) == 0)
137659024Sobrien		{
137759024Sobrien		  h->root.root.u.def.section = splt;
1378218822Sdim		  h->root.root.u.def.value = splt->size;
137959024Sobrien		}
138059024Sobrien
1381218822Sdim	      splt->size += M68K_PLT_ENTRY_SIZE;
138259024Sobrien
138359024Sobrien	      /* We may also need a dynamic reloc entry.  */
138459024Sobrien	      if ((h->flags & SUNOS_DEF_REGULAR) == 0)
1385218822Sdim		srel->size += RELOC_STD_SIZE;
138659024Sobrien	    }
138759024Sobrien	}
138859024Sobrien    }
138959024Sobrien
1390130561Sobrien  return TRUE;
139159024Sobrien}
139259024Sobrien
139359024Sobrien/* Scan the relocs for an input section using extended relocs.  We
139459024Sobrien   need to figure out what to do for each reloc against a dynamic
139559024Sobrien   symbol.  If the reloc is a WDISP30, and the symbol is in the .text
139659024Sobrien   section, an entry is made in the procedure linkage table.
139759024Sobrien   Otherwise, we must preserve the reloc as a dynamic reloc.  */
139859024Sobrien
1399130561Sobrienstatic bfd_boolean
1400218822Sdimsunos_scan_ext_relocs (struct bfd_link_info *info,
1401218822Sdim		       bfd *abfd,
1402218822Sdim		       asection *sec ATTRIBUTE_UNUSED,
1403218822Sdim		       const struct reloc_ext_external *relocs,
1404218822Sdim		       bfd_size_type rel_size)
140559024Sobrien{
140659024Sobrien  bfd *dynobj;
140759024Sobrien  struct sunos_link_hash_entry **sym_hashes;
140859024Sobrien  const struct reloc_ext_external *rel, *relend;
140959024Sobrien  asection *splt = NULL;
141059024Sobrien  asection *sgot = NULL;
141159024Sobrien  asection *srel = NULL;
141289857Sobrien  bfd_size_type amt;
141359024Sobrien
141459024Sobrien  /* We only know how to handle SPARC plt entries.  */
141559024Sobrien  if (bfd_get_arch (abfd) != bfd_arch_sparc)
141659024Sobrien    {
141759024Sobrien      bfd_set_error (bfd_error_invalid_target);
1418130561Sobrien      return FALSE;
141959024Sobrien    }
142059024Sobrien
142159024Sobrien  dynobj = NULL;
142259024Sobrien
142359024Sobrien  sym_hashes = (struct sunos_link_hash_entry **) obj_aout_sym_hashes (abfd);
142459024Sobrien
142559024Sobrien  relend = relocs + rel_size / RELOC_EXT_SIZE;
142659024Sobrien  for (rel = relocs; rel < relend; rel++)
142759024Sobrien    {
142859024Sobrien      unsigned int r_index;
142959024Sobrien      int r_extern;
143059024Sobrien      int r_type;
143159024Sobrien      struct sunos_link_hash_entry *h = NULL;
143259024Sobrien
143359024Sobrien      /* Swap in the reloc information.  */
143459024Sobrien      if (bfd_header_big_endian (abfd))
143559024Sobrien	{
143659024Sobrien	  r_index = ((rel->r_index[0] << 16)
143759024Sobrien		     | (rel->r_index[1] << 8)
143859024Sobrien		     | rel->r_index[2]);
143959024Sobrien	  r_extern = (0 != (rel->r_type[0] & RELOC_EXT_BITS_EXTERN_BIG));
144059024Sobrien	  r_type = ((rel->r_type[0] & RELOC_EXT_BITS_TYPE_BIG)
144159024Sobrien		    >> RELOC_EXT_BITS_TYPE_SH_BIG);
144259024Sobrien	}
144359024Sobrien      else
144459024Sobrien	{
144559024Sobrien	  r_index = ((rel->r_index[2] << 16)
144659024Sobrien		     | (rel->r_index[1] << 8)
144759024Sobrien		     | rel->r_index[0]);
144859024Sobrien	  r_extern = (0 != (rel->r_type[0] & RELOC_EXT_BITS_EXTERN_LITTLE));
144959024Sobrien	  r_type = ((rel->r_type[0] & RELOC_EXT_BITS_TYPE_LITTLE)
145059024Sobrien		    >> RELOC_EXT_BITS_TYPE_SH_LITTLE);
145159024Sobrien	}
145259024Sobrien
145359024Sobrien      if (r_extern)
145459024Sobrien	{
145559024Sobrien	  h = sym_hashes[r_index];
145659024Sobrien	  if (h == NULL)
145759024Sobrien	    {
145859024Sobrien	      /* This should not normally happen, but it will in any
145959024Sobrien		 case be caught in the relocation phase.  */
146059024Sobrien	      continue;
146159024Sobrien	    }
146259024Sobrien	}
146359024Sobrien
146459024Sobrien      /* If this is a base relative reloc, we need to make an entry in
1465130561Sobrien	 the .got section.  */
146659024Sobrien      if (r_type == RELOC_BASE10
146759024Sobrien	  || r_type == RELOC_BASE13
146859024Sobrien	  || r_type == RELOC_BASE22)
146959024Sobrien	{
147059024Sobrien	  if (dynobj == NULL)
147159024Sobrien	    {
1472130561Sobrien	      if (! sunos_create_dynamic_sections (abfd, info, FALSE))
1473130561Sobrien		return FALSE;
147459024Sobrien	      dynobj = sunos_hash_table (info)->dynobj;
147559024Sobrien	      splt = bfd_get_section_by_name (dynobj, ".plt");
147659024Sobrien	      sgot = bfd_get_section_by_name (dynobj, ".got");
147759024Sobrien	      srel = bfd_get_section_by_name (dynobj, ".dynrel");
147859024Sobrien	      BFD_ASSERT (splt != NULL && sgot != NULL && srel != NULL);
147959024Sobrien
148059024Sobrien	      /* Make sure we have an initial entry in the .got table.  */
1481218822Sdim	      if (sgot->size == 0)
1482218822Sdim		sgot->size = BYTES_IN_WORD;
1483130561Sobrien	      sunos_hash_table (info)->got_needed = TRUE;
148459024Sobrien	    }
148559024Sobrien
148659024Sobrien	  if (r_extern)
148759024Sobrien	    {
148859024Sobrien	      if (h->got_offset != 0)
148959024Sobrien		continue;
149059024Sobrien
1491218822Sdim	      h->got_offset = sgot->size;
149259024Sobrien	    }
149359024Sobrien	  else
149459024Sobrien	    {
149559024Sobrien	      if (r_index >= bfd_get_symcount (abfd))
1496218822Sdim		/* This is abnormal, but should be caught in the
1497218822Sdim		   relocation phase.  */
1498218822Sdim		continue;
149959024Sobrien
150059024Sobrien	      if (adata (abfd).local_got_offsets == NULL)
150159024Sobrien		{
150289857Sobrien		  amt = bfd_get_symcount (abfd);
150389857Sobrien		  amt *= sizeof (bfd_vma);
1504218822Sdim		  adata (abfd).local_got_offsets = bfd_zalloc (abfd, amt);
150559024Sobrien		  if (adata (abfd).local_got_offsets == NULL)
1506130561Sobrien		    return FALSE;
150759024Sobrien		}
150859024Sobrien
150959024Sobrien	      if (adata (abfd).local_got_offsets[r_index] != 0)
151059024Sobrien		continue;
151159024Sobrien
1512218822Sdim	      adata (abfd).local_got_offsets[r_index] = sgot->size;
151359024Sobrien	    }
151459024Sobrien
1515218822Sdim	  sgot->size += BYTES_IN_WORD;
151659024Sobrien
151759024Sobrien	  /* If we are making a shared library, or if the symbol is
151859024Sobrien	     defined by a dynamic object, we will need a dynamic reloc
151959024Sobrien	     entry.  */
152059024Sobrien	  if (info->shared
152159024Sobrien	      || (h != NULL
152259024Sobrien		  && (h->flags & SUNOS_DEF_DYNAMIC) != 0
152359024Sobrien		  && (h->flags & SUNOS_DEF_REGULAR) == 0))
1524218822Sdim	    srel->size += RELOC_EXT_SIZE;
152559024Sobrien
152659024Sobrien	  continue;
152759024Sobrien	}
152859024Sobrien
152959024Sobrien      /* Otherwise, we are only interested in relocs against symbols
1530130561Sobrien	 defined in dynamic objects but not in regular objects.  We
1531130561Sobrien	 only need to consider relocs against external symbols.  */
153259024Sobrien      if (! r_extern)
153359024Sobrien	{
153459024Sobrien	  /* But, if we are creating a shared library, we need to
1535130561Sobrien	     generate an absolute reloc.  */
153659024Sobrien	  if (info->shared)
153759024Sobrien	    {
153859024Sobrien	      if (dynobj == NULL)
153959024Sobrien		{
1540130561Sobrien		  if (! sunos_create_dynamic_sections (abfd, info, TRUE))
1541130561Sobrien		    return FALSE;
154259024Sobrien		  dynobj = sunos_hash_table (info)->dynobj;
154359024Sobrien		  splt = bfd_get_section_by_name (dynobj, ".plt");
154459024Sobrien		  sgot = bfd_get_section_by_name (dynobj, ".got");
154559024Sobrien		  srel = bfd_get_section_by_name (dynobj, ".dynrel");
154659024Sobrien		  BFD_ASSERT (splt != NULL && sgot != NULL && srel != NULL);
154759024Sobrien		}
154859024Sobrien
1549218822Sdim	      srel->size += RELOC_EXT_SIZE;
155059024Sobrien	    }
155159024Sobrien
155259024Sobrien	  continue;
155359024Sobrien	}
155459024Sobrien
155559024Sobrien      /* At this point common symbols have already been allocated, so
155659024Sobrien	 we don't have to worry about them.  We need to consider that
155759024Sobrien	 we may have already seen this symbol and marked it undefined;
155859024Sobrien	 if the symbol is really undefined, then SUNOS_DEF_DYNAMIC
155959024Sobrien	 will be zero.  */
156059024Sobrien      if (h->root.root.type != bfd_link_hash_defined
156159024Sobrien	  && h->root.root.type != bfd_link_hash_defweak
156259024Sobrien	  && h->root.root.type != bfd_link_hash_undefined)
156359024Sobrien	continue;
156459024Sobrien
156559024Sobrien      if (r_type != RELOC_JMP_TBL
156659024Sobrien	  && ! info->shared
156759024Sobrien	  && ((h->flags & SUNOS_DEF_DYNAMIC) == 0
156859024Sobrien	      || (h->flags & SUNOS_DEF_REGULAR) != 0))
156959024Sobrien	continue;
157059024Sobrien
157159024Sobrien      if (r_type == RELOC_JMP_TBL
157259024Sobrien	  && ! info->shared
157359024Sobrien	  && (h->flags & SUNOS_DEF_DYNAMIC) == 0
157459024Sobrien	  && (h->flags & SUNOS_DEF_REGULAR) == 0)
157559024Sobrien	{
157659024Sobrien	  /* This symbol is apparently undefined.  Don't do anything
1577130561Sobrien	     here; just let the relocation routine report an undefined
1578130561Sobrien	     symbol.  */
157959024Sobrien	  continue;
158059024Sobrien	}
158159024Sobrien
158259024Sobrien      if (strcmp (h->root.root.root.string, "__GLOBAL_OFFSET_TABLE_") == 0)
158359024Sobrien	continue;
158459024Sobrien
158559024Sobrien      if (dynobj == NULL)
158659024Sobrien	{
1587130561Sobrien	  if (! sunos_create_dynamic_sections (abfd, info, FALSE))
1588130561Sobrien	    return FALSE;
158959024Sobrien	  dynobj = sunos_hash_table (info)->dynobj;
159059024Sobrien	  splt = bfd_get_section_by_name (dynobj, ".plt");
159159024Sobrien	  sgot = bfd_get_section_by_name (dynobj, ".got");
159259024Sobrien	  srel = bfd_get_section_by_name (dynobj, ".dynrel");
159359024Sobrien	  BFD_ASSERT (splt != NULL && sgot != NULL && srel != NULL);
159459024Sobrien
159559024Sobrien	  /* Make sure we have an initial entry in the .got table.  */
1596218822Sdim	  if (sgot->size == 0)
1597218822Sdim	    sgot->size = BYTES_IN_WORD;
1598130561Sobrien	  sunos_hash_table (info)->got_needed = TRUE;
159959024Sobrien	}
160059024Sobrien
160159024Sobrien      BFD_ASSERT (r_type == RELOC_JMP_TBL
160259024Sobrien		  || info->shared
160359024Sobrien		  || (h->flags & SUNOS_REF_REGULAR) != 0);
160459024Sobrien      BFD_ASSERT (r_type == RELOC_JMP_TBL
160559024Sobrien		  || info->shared
160659024Sobrien		  || h->plt_offset != 0
160759024Sobrien		  || ((h->root.root.type == bfd_link_hash_defined
160859024Sobrien		       || h->root.root.type == bfd_link_hash_defweak)
160959024Sobrien		      ? (h->root.root.u.def.section->owner->flags
161059024Sobrien			 & DYNAMIC) != 0
161159024Sobrien		      : (h->root.root.u.undef.abfd->flags & DYNAMIC) != 0));
161259024Sobrien
161359024Sobrien      /* This reloc is against a symbol defined only by a dynamic
161459024Sobrien	 object, or it is a jump table reloc from PIC compiled code.  */
161559024Sobrien
161659024Sobrien      if (r_type != RELOC_JMP_TBL
161759024Sobrien	  && h->root.root.type == bfd_link_hash_undefined)
1618218822Sdim	/* Presumably this symbol was marked as being undefined by
1619218822Sdim	   an earlier reloc.  */
1620218822Sdim	srel->size += RELOC_EXT_SIZE;
1621218822Sdim
162259024Sobrien      else if (r_type != RELOC_JMP_TBL
162359024Sobrien	       && (h->root.root.u.def.section->flags & SEC_CODE) == 0)
162459024Sobrien	{
162559024Sobrien	  bfd *sub;
162659024Sobrien
162759024Sobrien	  /* This reloc is not in the .text section.  It must be
162859024Sobrien	     copied into the dynamic relocs.  We mark the symbol as
162959024Sobrien	     being undefined.  */
1630218822Sdim	  srel->size += RELOC_EXT_SIZE;
163159024Sobrien	  if ((h->flags & SUNOS_DEF_REGULAR) == 0)
163259024Sobrien	    {
163359024Sobrien	      sub = h->root.root.u.def.section->owner;
163459024Sobrien	      h->root.root.type = bfd_link_hash_undefined;
163559024Sobrien	      h->root.root.u.undef.abfd = sub;
163659024Sobrien	    }
163759024Sobrien	}
163859024Sobrien      else
163959024Sobrien	{
164059024Sobrien	  /* This symbol is in the .text section.  We must give it an
164159024Sobrien	     entry in the procedure linkage table, if we have not
164259024Sobrien	     already done so.  We change the definition of the symbol
164359024Sobrien	     to the .plt section; this will cause relocs against it to
164459024Sobrien	     be handled correctly.  */
164559024Sobrien	  if (h->plt_offset == 0)
164659024Sobrien	    {
1647218822Sdim	      if (splt->size == 0)
1648218822Sdim		splt->size = SPARC_PLT_ENTRY_SIZE;
1649218822Sdim	      h->plt_offset = splt->size;
165059024Sobrien
165159024Sobrien	      if ((h->flags & SUNOS_DEF_REGULAR) == 0)
165259024Sobrien		{
165359024Sobrien		  if (h->root.root.type == bfd_link_hash_undefined)
165459024Sobrien		    h->root.root.type = bfd_link_hash_defined;
165559024Sobrien		  h->root.root.u.def.section = splt;
1656218822Sdim		  h->root.root.u.def.value = splt->size;
165759024Sobrien		}
165859024Sobrien
1659218822Sdim	      splt->size += SPARC_PLT_ENTRY_SIZE;
166059024Sobrien
166159024Sobrien	      /* We will also need a dynamic reloc entry, unless this
1662130561Sobrien		 is a JMP_TBL reloc produced by linking PIC compiled
1663130561Sobrien		 code, and we are not making a shared library.  */
166459024Sobrien	      if (info->shared || (h->flags & SUNOS_DEF_REGULAR) == 0)
1665218822Sdim		srel->size += RELOC_EXT_SIZE;
166659024Sobrien	    }
166759024Sobrien
166859024Sobrien	  /* If we are creating a shared library, we need to copy over
1669130561Sobrien	     any reloc other than a jump table reloc.  */
167059024Sobrien	  if (info->shared && r_type != RELOC_JMP_TBL)
1671218822Sdim	    srel->size += RELOC_EXT_SIZE;
167259024Sobrien	}
167359024Sobrien    }
167459024Sobrien
1675130561Sobrien  return TRUE;
167659024Sobrien}
167759024Sobrien
1678218822Sdim/* Scan the relocs for an input section.  */
1679218822Sdim
1680218822Sdimstatic bfd_boolean
1681218822Sdimsunos_scan_relocs (struct bfd_link_info *info,
1682218822Sdim		   bfd *abfd,
1683218822Sdim		   asection *sec,
1684218822Sdim		   bfd_size_type rel_size)
1685218822Sdim{
1686218822Sdim  void * relocs;
1687218822Sdim  void * free_relocs = NULL;
1688218822Sdim
1689218822Sdim  if (rel_size == 0)
1690218822Sdim    return TRUE;
1691218822Sdim
1692218822Sdim  if (! info->keep_memory)
1693218822Sdim    relocs = free_relocs = bfd_malloc (rel_size);
1694218822Sdim  else
1695218822Sdim    {
1696218822Sdim      struct aout_section_data_struct *n;
1697218822Sdim      bfd_size_type amt = sizeof (struct aout_section_data_struct);
1698218822Sdim
1699218822Sdim      n = bfd_alloc (abfd, amt);
1700218822Sdim      if (n == NULL)
1701218822Sdim	relocs = NULL;
1702218822Sdim      else
1703218822Sdim	{
1704218822Sdim	  set_aout_section_data (sec, n);
1705218822Sdim	  relocs = bfd_malloc (rel_size);
1706218822Sdim	  aout_section_data (sec)->relocs = relocs;
1707218822Sdim	}
1708218822Sdim    }
1709218822Sdim  if (relocs == NULL)
1710218822Sdim    return FALSE;
1711218822Sdim
1712218822Sdim  if (bfd_seek (abfd, sec->rel_filepos, SEEK_SET) != 0
1713218822Sdim      || bfd_bread (relocs, rel_size, abfd) != rel_size)
1714218822Sdim    goto error_return;
1715218822Sdim
1716218822Sdim  if (obj_reloc_entry_size (abfd) == RELOC_STD_SIZE)
1717218822Sdim    {
1718218822Sdim      if (! sunos_scan_std_relocs (info, abfd, sec,
1719218822Sdim				   (struct reloc_std_external *) relocs,
1720218822Sdim				   rel_size))
1721218822Sdim	goto error_return;
1722218822Sdim    }
1723218822Sdim  else
1724218822Sdim    {
1725218822Sdim      if (! sunos_scan_ext_relocs (info, abfd, sec,
1726218822Sdim				   (struct reloc_ext_external *) relocs,
1727218822Sdim				   rel_size))
1728218822Sdim	goto error_return;
1729218822Sdim    }
1730218822Sdim
1731218822Sdim  if (free_relocs != NULL)
1732218822Sdim    free (free_relocs);
1733218822Sdim
1734218822Sdim  return TRUE;
1735218822Sdim
1736218822Sdim error_return:
1737218822Sdim  if (free_relocs != NULL)
1738218822Sdim    free (free_relocs);
1739218822Sdim  return FALSE;
1740218822Sdim}
1741218822Sdim
174259024Sobrien/* Build the hash table of dynamic symbols, and to mark as written all
174359024Sobrien   symbols from dynamic objects which we do not plan to write out.  */
174459024Sobrien
1745130561Sobrienstatic bfd_boolean
1746218822Sdimsunos_scan_dynamic_symbol (struct sunos_link_hash_entry *h, void * data)
174759024Sobrien{
174859024Sobrien  struct bfd_link_info *info = (struct bfd_link_info *) data;
174959024Sobrien
175094536Sobrien  if (h->root.root.type == bfd_link_hash_warning)
175194536Sobrien    h = (struct sunos_link_hash_entry *) h->root.root.u.i.link;
175294536Sobrien
175359024Sobrien  /* Set the written flag for symbols we do not want to write out as
175459024Sobrien     part of the regular symbol table.  This is all symbols which are
175559024Sobrien     not defined in a regular object file.  For some reason symbols
175659024Sobrien     which are referenced by a regular object and defined by a dynamic
175759024Sobrien     object do not seem to show up in the regular symbol table.  It is
175859024Sobrien     possible for a symbol to have only SUNOS_REF_REGULAR set here, it
175959024Sobrien     is an undefined symbol which was turned into a common symbol
176059024Sobrien     because it was found in an archive object which was not included
176159024Sobrien     in the link.  */
176259024Sobrien  if ((h->flags & SUNOS_DEF_REGULAR) == 0
176359024Sobrien      && (h->flags & SUNOS_DEF_DYNAMIC) != 0
176459024Sobrien      && strcmp (h->root.root.root.string, "__DYNAMIC") != 0)
1765130561Sobrien    h->root.written = TRUE;
176659024Sobrien
176759024Sobrien  /* If this symbol is defined by a dynamic object and referenced by a
176859024Sobrien     regular object, see whether we gave it a reasonable value while
176959024Sobrien     scanning the relocs.  */
177059024Sobrien  if ((h->flags & SUNOS_DEF_REGULAR) == 0
177159024Sobrien      && (h->flags & SUNOS_DEF_DYNAMIC) != 0
177259024Sobrien      && (h->flags & SUNOS_REF_REGULAR) != 0)
177359024Sobrien    {
177459024Sobrien      if ((h->root.root.type == bfd_link_hash_defined
177559024Sobrien	   || h->root.root.type == bfd_link_hash_defweak)
177659024Sobrien	  && ((h->root.root.u.def.section->owner->flags & DYNAMIC) != 0)
177759024Sobrien	  && h->root.root.u.def.section->output_section == NULL)
177859024Sobrien	{
177959024Sobrien	  bfd *sub;
178059024Sobrien
178159024Sobrien	  /* This symbol is currently defined in a dynamic section
178259024Sobrien	     which is not being put into the output file.  This
178359024Sobrien	     implies that there is no reloc against the symbol.  I'm
178459024Sobrien	     not sure why this case would ever occur.  In any case, we
178559024Sobrien	     change the symbol to be undefined.  */
178659024Sobrien	  sub = h->root.root.u.def.section->owner;
178759024Sobrien	  h->root.root.type = bfd_link_hash_undefined;
178859024Sobrien	  h->root.root.u.undef.abfd = sub;
178959024Sobrien	}
179059024Sobrien    }
179159024Sobrien
179259024Sobrien  /* If this symbol is defined or referenced by a regular file, add it
179359024Sobrien     to the dynamic symbols.  */
179459024Sobrien  if ((h->flags & (SUNOS_DEF_REGULAR | SUNOS_REF_REGULAR)) != 0)
179559024Sobrien    {
179659024Sobrien      asection *s;
179759024Sobrien      size_t len;
179859024Sobrien      bfd_byte *contents;
179959024Sobrien      unsigned char *name;
180059024Sobrien      unsigned long hash;
180159024Sobrien      bfd *dynobj;
180259024Sobrien
180359024Sobrien      BFD_ASSERT (h->dynindx == -2);
180459024Sobrien
180559024Sobrien      dynobj = sunos_hash_table (info)->dynobj;
180659024Sobrien
180759024Sobrien      h->dynindx = sunos_hash_table (info)->dynsymcount;
180859024Sobrien      ++sunos_hash_table (info)->dynsymcount;
180959024Sobrien
181059024Sobrien      len = strlen (h->root.root.root.string);
181159024Sobrien
181259024Sobrien      /* We don't bother to construct a BFD hash table for the strings
181359024Sobrien	 which are the names of the dynamic symbols.  Using a hash
181459024Sobrien	 table for the regular symbols is beneficial, because the
181559024Sobrien	 regular symbols includes the debugging symbols, which have
181659024Sobrien	 long names and are often duplicated in several object files.
181759024Sobrien	 There are no debugging symbols in the dynamic symbols.  */
181859024Sobrien      s = bfd_get_section_by_name (dynobj, ".dynstr");
181959024Sobrien      BFD_ASSERT (s != NULL);
1820218822Sdim      contents = bfd_realloc (s->contents, s->size + len + 1);
182159024Sobrien      if (contents == NULL)
1822130561Sobrien	return FALSE;
182359024Sobrien      s->contents = contents;
182459024Sobrien
1825218822Sdim      h->dynstr_index = s->size;
1826218822Sdim      strcpy ((char *) contents + s->size, h->root.root.root.string);
1827218822Sdim      s->size += len + 1;
182859024Sobrien
182959024Sobrien      /* Add it to the dynamic hash table.  */
183059024Sobrien      name = (unsigned char *) h->root.root.root.string;
183159024Sobrien      hash = 0;
183259024Sobrien      while (*name != '\0')
183359024Sobrien	hash = (hash << 1) + *name++;
183459024Sobrien      hash &= 0x7fffffff;
183559024Sobrien      hash %= sunos_hash_table (info)->bucketcount;
183659024Sobrien
183759024Sobrien      s = bfd_get_section_by_name (dynobj, ".hash");
183859024Sobrien      BFD_ASSERT (s != NULL);
183959024Sobrien
184059024Sobrien      if (GET_SWORD (dynobj, s->contents + hash * HASH_ENTRY_SIZE) == -1)
184159024Sobrien	PUT_WORD (dynobj, h->dynindx, s->contents + hash * HASH_ENTRY_SIZE);
184259024Sobrien      else
184359024Sobrien	{
184459024Sobrien	  bfd_vma next;
184559024Sobrien
184659024Sobrien	  next = GET_WORD (dynobj,
184759024Sobrien			   (s->contents
184859024Sobrien			    + hash * HASH_ENTRY_SIZE
184959024Sobrien			    + BYTES_IN_WORD));
1850218822Sdim	  PUT_WORD (dynobj, s->size / HASH_ENTRY_SIZE,
185159024Sobrien		    s->contents + hash * HASH_ENTRY_SIZE + BYTES_IN_WORD);
1852218822Sdim	  PUT_WORD (dynobj, h->dynindx, s->contents + s->size);
1853218822Sdim	  PUT_WORD (dynobj, next, s->contents + s->size + BYTES_IN_WORD);
1854218822Sdim	  s->size += HASH_ENTRY_SIZE;
185559024Sobrien	}
185659024Sobrien    }
185759024Sobrien
1858130561Sobrien  return TRUE;
185959024Sobrien}
186059024Sobrien
1861218822Sdim/* Set up the sizes and contents of the dynamic sections created in
1862218822Sdim   sunos_add_dynamic_symbols.  This is called by the SunOS linker
1863218822Sdim   emulation before_allocation routine.  We must set the sizes of the
1864218822Sdim   sections before the linker sets the addresses of the various
1865218822Sdim   sections.  This unfortunately requires reading all the relocs so
1866218822Sdim   that we can work out which ones need to become dynamic relocs.  If
1867218822Sdim   info->keep_memory is TRUE, we keep the relocs in memory; otherwise,
1868218822Sdim   we discard them, and will read them again later.  */
1869218822Sdim
1870218822Sdimbfd_boolean
1871218822Sdimbfd_sunos_size_dynamic_sections (bfd *output_bfd,
1872218822Sdim				 struct bfd_link_info *info,
1873218822Sdim				 asection **sdynptr,
1874218822Sdim				 asection **sneedptr,
1875218822Sdim				 asection **srulesptr)
1876218822Sdim{
1877218822Sdim  bfd *dynobj;
1878218822Sdim  bfd_size_type dynsymcount;
1879218822Sdim  struct sunos_link_hash_entry *h;
1880218822Sdim  asection *s;
1881218822Sdim  size_t bucketcount;
1882218822Sdim  bfd_size_type hashalloc;
1883218822Sdim  size_t i;
1884218822Sdim  bfd *sub;
1885218822Sdim
1886218822Sdim  *sdynptr = NULL;
1887218822Sdim  *sneedptr = NULL;
1888218822Sdim  *srulesptr = NULL;
1889218822Sdim
1890218822Sdim  if (info->relocatable)
1891218822Sdim    return TRUE;
1892218822Sdim
1893218822Sdim  if (output_bfd->xvec != &MY(vec))
1894218822Sdim    return TRUE;
1895218822Sdim
1896218822Sdim  /* Look through all the input BFD's and read their relocs.  It would
1897218822Sdim     be better if we didn't have to do this, but there is no other way
1898218822Sdim     to determine the number of dynamic relocs we need, and, more
1899218822Sdim     importantly, there is no other way to know which symbols should
1900218822Sdim     get an entry in the procedure linkage table.  */
1901218822Sdim  for (sub = info->input_bfds; sub != NULL; sub = sub->link_next)
1902218822Sdim    {
1903218822Sdim      if ((sub->flags & DYNAMIC) == 0
1904218822Sdim	  && sub->xvec == output_bfd->xvec)
1905218822Sdim	{
1906218822Sdim	  if (! sunos_scan_relocs (info, sub, obj_textsec (sub),
1907218822Sdim				   exec_hdr (sub)->a_trsize)
1908218822Sdim	      || ! sunos_scan_relocs (info, sub, obj_datasec (sub),
1909218822Sdim				      exec_hdr (sub)->a_drsize))
1910218822Sdim	    return FALSE;
1911218822Sdim	}
1912218822Sdim    }
1913218822Sdim
1914218822Sdim  dynobj = sunos_hash_table (info)->dynobj;
1915218822Sdim  dynsymcount = sunos_hash_table (info)->dynsymcount;
1916218822Sdim
1917218822Sdim  /* If there were no dynamic objects in the link, and we don't need
1918218822Sdim     to build a global offset table, there is nothing to do here.  */
1919218822Sdim  if (! sunos_hash_table (info)->dynamic_sections_needed
1920218822Sdim      && ! sunos_hash_table (info)->got_needed)
1921218822Sdim    return TRUE;
1922218822Sdim
1923218822Sdim  /* If __GLOBAL_OFFSET_TABLE_ was mentioned, define it.  */
1924218822Sdim  h = sunos_link_hash_lookup (sunos_hash_table (info),
1925218822Sdim			      "__GLOBAL_OFFSET_TABLE_", FALSE, FALSE, FALSE);
1926218822Sdim  if (h != NULL && (h->flags & SUNOS_REF_REGULAR) != 0)
1927218822Sdim    {
1928218822Sdim      h->flags |= SUNOS_DEF_REGULAR;
1929218822Sdim      if (h->dynindx == -1)
1930218822Sdim	{
1931218822Sdim	  ++sunos_hash_table (info)->dynsymcount;
1932218822Sdim	  h->dynindx = -2;
1933218822Sdim	}
1934218822Sdim      h->root.root.type = bfd_link_hash_defined;
1935218822Sdim      h->root.root.u.def.section = bfd_get_section_by_name (dynobj, ".got");
1936218822Sdim
1937218822Sdim      /* If the .got section is more than 0x1000 bytes, we set
1938218822Sdim	 __GLOBAL_OFFSET_TABLE_ to be 0x1000 bytes into the section,
1939218822Sdim	 so that 13 bit relocations have a greater chance of working.  */
1940218822Sdim      s = bfd_get_section_by_name (dynobj, ".got");
1941218822Sdim      BFD_ASSERT (s != NULL);
1942218822Sdim      if (s->size >= 0x1000)
1943218822Sdim	h->root.root.u.def.value = 0x1000;
1944218822Sdim      else
1945218822Sdim	h->root.root.u.def.value = 0;
1946218822Sdim
1947218822Sdim      sunos_hash_table (info)->got_base = h->root.root.u.def.value;
1948218822Sdim    }
1949218822Sdim
1950218822Sdim  /* If there are any shared objects in the link, then we need to set
1951218822Sdim     up the dynamic linking information.  */
1952218822Sdim  if (sunos_hash_table (info)->dynamic_sections_needed)
1953218822Sdim    {
1954218822Sdim      *sdynptr = bfd_get_section_by_name (dynobj, ".dynamic");
1955218822Sdim
1956218822Sdim      /* The .dynamic section is always the same size.  */
1957218822Sdim      s = *sdynptr;
1958218822Sdim      BFD_ASSERT (s != NULL);
1959218822Sdim      s->size = (sizeof (struct external_sun4_dynamic)
1960218822Sdim		      + EXTERNAL_SUN4_DYNAMIC_DEBUGGER_SIZE
1961218822Sdim		      + sizeof (struct external_sun4_dynamic_link));
1962218822Sdim
1963218822Sdim      /* Set the size of the .dynsym and .hash sections.  We counted
1964218822Sdim	 the number of dynamic symbols as we read the input files.  We
1965218822Sdim	 will build the dynamic symbol table (.dynsym) and the hash
1966218822Sdim	 table (.hash) when we build the final symbol table, because
1967218822Sdim	 until then we do not know the correct value to give the
1968218822Sdim	 symbols.  We build the dynamic symbol string table (.dynstr)
1969218822Sdim	 in a traversal of the symbol table using
1970218822Sdim	 sunos_scan_dynamic_symbol.  */
1971218822Sdim      s = bfd_get_section_by_name (dynobj, ".dynsym");
1972218822Sdim      BFD_ASSERT (s != NULL);
1973218822Sdim      s->size = dynsymcount * sizeof (struct external_nlist);
1974218822Sdim      s->contents = bfd_alloc (output_bfd, s->size);
1975218822Sdim      if (s->contents == NULL && s->size != 0)
1976218822Sdim	return FALSE;
1977218822Sdim
1978218822Sdim      /* The number of buckets is just the number of symbols divided
1979218822Sdim	 by four.  To compute the final size of the hash table, we
1980218822Sdim	 must actually compute the hash table.  Normally we need
1981218822Sdim	 exactly as many entries in the hash table as there are
1982218822Sdim	 dynamic symbols, but if some of the buckets are not used we
1983218822Sdim	 will need additional entries.  In the worst case, every
1984218822Sdim	 symbol will hash to the same bucket, and we will need
1985218822Sdim	 BUCKETCOUNT - 1 extra entries.  */
1986218822Sdim      if (dynsymcount >= 4)
1987218822Sdim	bucketcount = dynsymcount / 4;
1988218822Sdim      else if (dynsymcount > 0)
1989218822Sdim	bucketcount = dynsymcount;
1990218822Sdim      else
1991218822Sdim	bucketcount = 1;
1992218822Sdim      s = bfd_get_section_by_name (dynobj, ".hash");
1993218822Sdim      BFD_ASSERT (s != NULL);
1994218822Sdim      hashalloc = (dynsymcount + bucketcount - 1) * HASH_ENTRY_SIZE;
1995218822Sdim      s->contents = bfd_zalloc (dynobj, hashalloc);
1996218822Sdim      if (s->contents == NULL && dynsymcount > 0)
1997218822Sdim	return FALSE;
1998218822Sdim      for (i = 0; i < bucketcount; i++)
1999218822Sdim	PUT_WORD (output_bfd, (bfd_vma) -1, s->contents + i * HASH_ENTRY_SIZE);
2000218822Sdim      s->size = bucketcount * HASH_ENTRY_SIZE;
2001218822Sdim
2002218822Sdim      sunos_hash_table (info)->bucketcount = bucketcount;
2003218822Sdim
2004218822Sdim      /* Scan all the symbols, place them in the dynamic symbol table,
2005218822Sdim	 and build the dynamic hash table.  We reuse dynsymcount as a
2006218822Sdim	 counter for the number of symbols we have added so far.  */
2007218822Sdim      sunos_hash_table (info)->dynsymcount = 0;
2008218822Sdim      sunos_link_hash_traverse (sunos_hash_table (info),
2009218822Sdim				sunos_scan_dynamic_symbol,
2010218822Sdim				(void *) info);
2011218822Sdim      BFD_ASSERT (sunos_hash_table (info)->dynsymcount == dynsymcount);
2012218822Sdim
2013218822Sdim      /* The SunOS native linker seems to align the total size of the
2014218822Sdim	 symbol strings to a multiple of 8.  I don't know if this is
2015218822Sdim	 important, but it can't hurt much.  */
2016218822Sdim      s = bfd_get_section_by_name (dynobj, ".dynstr");
2017218822Sdim      BFD_ASSERT (s != NULL);
2018218822Sdim      if ((s->size & 7) != 0)
2019218822Sdim	{
2020218822Sdim	  bfd_size_type add;
2021218822Sdim	  bfd_byte *contents;
2022218822Sdim
2023218822Sdim	  add = 8 - (s->size & 7);
2024218822Sdim	  contents = bfd_realloc (s->contents, s->size + add);
2025218822Sdim	  if (contents == NULL)
2026218822Sdim	    return FALSE;
2027218822Sdim	  memset (contents + s->size, 0, (size_t) add);
2028218822Sdim	  s->contents = contents;
2029218822Sdim	  s->size += add;
2030218822Sdim	}
2031218822Sdim    }
2032218822Sdim
2033218822Sdim  /* Now that we have worked out the sizes of the procedure linkage
2034218822Sdim     table and the dynamic relocs, allocate storage for them.  */
2035218822Sdim  s = bfd_get_section_by_name (dynobj, ".plt");
2036218822Sdim  BFD_ASSERT (s != NULL);
2037218822Sdim  if (s->size != 0)
2038218822Sdim    {
2039218822Sdim      s->contents = bfd_alloc (dynobj, s->size);
2040218822Sdim      if (s->contents == NULL)
2041218822Sdim	return FALSE;
2042218822Sdim
2043218822Sdim      /* Fill in the first entry in the table.  */
2044218822Sdim      switch (bfd_get_arch (dynobj))
2045218822Sdim	{
2046218822Sdim	case bfd_arch_sparc:
2047218822Sdim	  memcpy (s->contents, sparc_plt_first_entry, SPARC_PLT_ENTRY_SIZE);
2048218822Sdim	  break;
2049218822Sdim
2050218822Sdim	case bfd_arch_m68k:
2051218822Sdim	  memcpy (s->contents, m68k_plt_first_entry, M68K_PLT_ENTRY_SIZE);
2052218822Sdim	  break;
2053218822Sdim
2054218822Sdim	default:
2055218822Sdim	  abort ();
2056218822Sdim	}
2057218822Sdim    }
2058218822Sdim
2059218822Sdim  s = bfd_get_section_by_name (dynobj, ".dynrel");
2060218822Sdim  if (s->size != 0)
2061218822Sdim    {
2062218822Sdim      s->contents = bfd_alloc (dynobj, s->size);
2063218822Sdim      if (s->contents == NULL)
2064218822Sdim	return FALSE;
2065218822Sdim    }
2066218822Sdim  /* We use the reloc_count field to keep track of how many of the
2067218822Sdim     relocs we have output so far.  */
2068218822Sdim  s->reloc_count = 0;
2069218822Sdim
2070218822Sdim  /* Make space for the global offset table.  */
2071218822Sdim  s = bfd_get_section_by_name (dynobj, ".got");
2072218822Sdim  s->contents = bfd_alloc (dynobj, s->size);
2073218822Sdim  if (s->contents == NULL)
2074218822Sdim    return FALSE;
2075218822Sdim
2076218822Sdim  *sneedptr = bfd_get_section_by_name (dynobj, ".need");
2077218822Sdim  *srulesptr = bfd_get_section_by_name (dynobj, ".rules");
2078218822Sdim
2079218822Sdim  return TRUE;
2080218822Sdim}
2081218822Sdim
208259024Sobrien/* Link a dynamic object.  We actually don't have anything to do at
208359024Sobrien   this point.  This entry point exists to prevent the regular linker
208459024Sobrien   code from doing anything with the object.  */
208559024Sobrien
2086130561Sobrienstatic bfd_boolean
2087218822Sdimsunos_link_dynamic_object (struct bfd_link_info *info ATTRIBUTE_UNUSED,
2088218822Sdim			   bfd *abfd ATTRIBUTE_UNUSED)
208959024Sobrien{
2090130561Sobrien  return TRUE;
209159024Sobrien}
209259024Sobrien
209359024Sobrien/* Write out a dynamic symbol.  This is called by the final traversal
209459024Sobrien   over the symbol table.  */
209559024Sobrien
2096130561Sobrienstatic bfd_boolean
2097218822Sdimsunos_write_dynamic_symbol (bfd *output_bfd,
2098218822Sdim			    struct bfd_link_info *info,
2099218822Sdim			    struct aout_link_hash_entry *harg)
210059024Sobrien{
210159024Sobrien  struct sunos_link_hash_entry *h = (struct sunos_link_hash_entry *) harg;
210259024Sobrien  int type;
210359024Sobrien  bfd_vma val;
210459024Sobrien  asection *s;
210559024Sobrien  struct external_nlist *outsym;
210659024Sobrien
210759024Sobrien  /* If this symbol is in the procedure linkage table, fill in the
210859024Sobrien     table entry.  */
210959024Sobrien  if (h->plt_offset != 0)
211059024Sobrien    {
211159024Sobrien      bfd *dynobj;
211259024Sobrien      asection *splt;
211359024Sobrien      bfd_byte *p;
211459024Sobrien      bfd_vma r_address;
211559024Sobrien
211659024Sobrien      dynobj = sunos_hash_table (info)->dynobj;
211759024Sobrien      splt = bfd_get_section_by_name (dynobj, ".plt");
211859024Sobrien      p = splt->contents + h->plt_offset;
211959024Sobrien
212059024Sobrien      s = bfd_get_section_by_name (dynobj, ".dynrel");
212159024Sobrien
212259024Sobrien      r_address = (splt->output_section->vma
212359024Sobrien		   + splt->output_offset
212459024Sobrien		   + h->plt_offset);
212559024Sobrien
212659024Sobrien      switch (bfd_get_arch (output_bfd))
212759024Sobrien	{
212859024Sobrien	case bfd_arch_sparc:
212959024Sobrien	  if (info->shared || (h->flags & SUNOS_DEF_REGULAR) == 0)
213059024Sobrien	    {
213159024Sobrien	      bfd_put_32 (output_bfd, SPARC_PLT_ENTRY_WORD0, p);
213259024Sobrien	      bfd_put_32 (output_bfd,
213359024Sobrien			  (SPARC_PLT_ENTRY_WORD1
213459024Sobrien			   + (((- (h->plt_offset + 4) >> 2)
213559024Sobrien			       & 0x3fffffff))),
213659024Sobrien			  p + 4);
213759024Sobrien	      bfd_put_32 (output_bfd, SPARC_PLT_ENTRY_WORD2 + s->reloc_count,
213859024Sobrien			  p + 8);
213959024Sobrien	    }
214059024Sobrien	  else
214159024Sobrien	    {
214259024Sobrien	      val = (h->root.root.u.def.section->output_section->vma
214359024Sobrien		     + h->root.root.u.def.section->output_offset
214459024Sobrien		     + h->root.root.u.def.value);
214559024Sobrien	      bfd_put_32 (output_bfd,
214659024Sobrien			  SPARC_PLT_PIC_WORD0 + ((val >> 10) & 0x3fffff),
214759024Sobrien			  p);
214859024Sobrien	      bfd_put_32 (output_bfd,
214959024Sobrien			  SPARC_PLT_PIC_WORD1 + (val & 0x3ff),
215059024Sobrien			  p + 4);
215159024Sobrien	      bfd_put_32 (output_bfd, SPARC_PLT_PIC_WORD2, p + 8);
215259024Sobrien	    }
215359024Sobrien	  break;
215459024Sobrien
215559024Sobrien	case bfd_arch_m68k:
215659024Sobrien	  if (! info->shared && (h->flags & SUNOS_DEF_REGULAR) != 0)
215759024Sobrien	    abort ();
215859024Sobrien	  bfd_put_16 (output_bfd, M68K_PLT_ENTRY_WORD0, p);
215959024Sobrien	  bfd_put_32 (output_bfd, (- (h->plt_offset + 2)), p + 2);
216089857Sobrien	  bfd_put_16 (output_bfd, (bfd_vma) s->reloc_count, p + 6);
216159024Sobrien	  r_address += 2;
216259024Sobrien	  break;
216359024Sobrien
216459024Sobrien	default:
216559024Sobrien	  abort ();
216659024Sobrien	}
216759024Sobrien
216859024Sobrien      /* We also need to add a jump table reloc, unless this is the
2169130561Sobrien	 result of a JMP_TBL reloc from PIC compiled code.  */
217059024Sobrien      if (info->shared || (h->flags & SUNOS_DEF_REGULAR) == 0)
217159024Sobrien	{
217259024Sobrien	  BFD_ASSERT (h->dynindx >= 0);
217359024Sobrien	  BFD_ASSERT (s->reloc_count * obj_reloc_entry_size (dynobj)
2174218822Sdim		      < s->size);
217559024Sobrien	  p = s->contents + s->reloc_count * obj_reloc_entry_size (output_bfd);
217659024Sobrien	  if (obj_reloc_entry_size (output_bfd) == RELOC_STD_SIZE)
217759024Sobrien	    {
217859024Sobrien	      struct reloc_std_external *srel;
217959024Sobrien
218059024Sobrien	      srel = (struct reloc_std_external *) p;
218159024Sobrien	      PUT_WORD (output_bfd, r_address, srel->r_address);
218259024Sobrien	      if (bfd_header_big_endian (output_bfd))
218359024Sobrien		{
218484865Sobrien		  srel->r_index[0] = (bfd_byte) (h->dynindx >> 16);
218584865Sobrien		  srel->r_index[1] = (bfd_byte) (h->dynindx >> 8);
218684865Sobrien		  srel->r_index[2] = (bfd_byte) (h->dynindx);
218759024Sobrien		  srel->r_type[0] = (RELOC_STD_BITS_EXTERN_BIG
218859024Sobrien				     | RELOC_STD_BITS_JMPTABLE_BIG);
218959024Sobrien		}
219059024Sobrien	      else
219159024Sobrien		{
219284865Sobrien		  srel->r_index[2] = (bfd_byte) (h->dynindx >> 16);
219384865Sobrien		  srel->r_index[1] = (bfd_byte) (h->dynindx >> 8);
219459024Sobrien		  srel->r_index[0] = (bfd_byte)h->dynindx;
219559024Sobrien		  srel->r_type[0] = (RELOC_STD_BITS_EXTERN_LITTLE
219659024Sobrien				     | RELOC_STD_BITS_JMPTABLE_LITTLE);
219759024Sobrien		}
219859024Sobrien	    }
219959024Sobrien	  else
220059024Sobrien	    {
220159024Sobrien	      struct reloc_ext_external *erel;
220259024Sobrien
220359024Sobrien	      erel = (struct reloc_ext_external *) p;
220459024Sobrien	      PUT_WORD (output_bfd, r_address, erel->r_address);
220559024Sobrien	      if (bfd_header_big_endian (output_bfd))
220659024Sobrien		{
220784865Sobrien		  erel->r_index[0] = (bfd_byte) (h->dynindx >> 16);
220884865Sobrien		  erel->r_index[1] = (bfd_byte) (h->dynindx >> 8);
220959024Sobrien		  erel->r_index[2] = (bfd_byte)h->dynindx;
221059024Sobrien		  erel->r_type[0] =
221159024Sobrien		    (RELOC_EXT_BITS_EXTERN_BIG
221259024Sobrien		     | (RELOC_JMP_SLOT << RELOC_EXT_BITS_TYPE_SH_BIG));
221359024Sobrien		}
221459024Sobrien	      else
221559024Sobrien		{
221684865Sobrien		  erel->r_index[2] = (bfd_byte) (h->dynindx >> 16);
221784865Sobrien		  erel->r_index[1] = (bfd_byte) (h->dynindx >> 8);
221859024Sobrien		  erel->r_index[0] = (bfd_byte)h->dynindx;
221959024Sobrien		  erel->r_type[0] =
222059024Sobrien		    (RELOC_EXT_BITS_EXTERN_LITTLE
222159024Sobrien		     | (RELOC_JMP_SLOT << RELOC_EXT_BITS_TYPE_SH_LITTLE));
222259024Sobrien		}
222359024Sobrien	      PUT_WORD (output_bfd, (bfd_vma) 0, erel->r_addend);
222459024Sobrien	    }
222559024Sobrien
222659024Sobrien	  ++s->reloc_count;
222759024Sobrien	}
222859024Sobrien    }
222959024Sobrien
223059024Sobrien  /* If this is not a dynamic symbol, we don't have to do anything
223159024Sobrien     else.  We only check this after handling the PLT entry, because
223259024Sobrien     we can have a PLT entry for a nondynamic symbol when linking PIC
223359024Sobrien     compiled code from a regular object.  */
223459024Sobrien  if (h->dynindx < 0)
2235130561Sobrien    return TRUE;
223659024Sobrien
223759024Sobrien  switch (h->root.root.type)
223859024Sobrien    {
223959024Sobrien    default:
224059024Sobrien    case bfd_link_hash_new:
224159024Sobrien      abort ();
224259024Sobrien      /* Avoid variable not initialized warnings.  */
2243130561Sobrien      return TRUE;
224459024Sobrien    case bfd_link_hash_undefined:
224559024Sobrien      type = N_UNDF | N_EXT;
224659024Sobrien      val = 0;
224759024Sobrien      break;
224859024Sobrien    case bfd_link_hash_defined:
224959024Sobrien    case bfd_link_hash_defweak:
225059024Sobrien      {
225159024Sobrien	asection *sec;
225259024Sobrien	asection *output_section;
225359024Sobrien
225459024Sobrien	sec = h->root.root.u.def.section;
225559024Sobrien	output_section = sec->output_section;
225659024Sobrien	BFD_ASSERT (bfd_is_abs_section (output_section)
225759024Sobrien		    || output_section->owner == output_bfd);
225859024Sobrien	if (h->plt_offset != 0
225959024Sobrien	    && (h->flags & SUNOS_DEF_REGULAR) == 0)
226059024Sobrien	  {
226159024Sobrien	    type = N_UNDF | N_EXT;
226259024Sobrien	    val = 0;
226359024Sobrien	  }
226459024Sobrien	else
226559024Sobrien	  {
226659024Sobrien	    if (output_section == obj_textsec (output_bfd))
226759024Sobrien	      type = (h->root.root.type == bfd_link_hash_defined
226859024Sobrien		      ? N_TEXT
226959024Sobrien		      : N_WEAKT);
227059024Sobrien	    else if (output_section == obj_datasec (output_bfd))
227159024Sobrien	      type = (h->root.root.type == bfd_link_hash_defined
227259024Sobrien		      ? N_DATA
227359024Sobrien		      : N_WEAKD);
227459024Sobrien	    else if (output_section == obj_bsssec (output_bfd))
227559024Sobrien	      type = (h->root.root.type == bfd_link_hash_defined
227659024Sobrien		      ? N_BSS
227759024Sobrien		      : N_WEAKB);
227859024Sobrien	    else
227959024Sobrien	      type = (h->root.root.type == bfd_link_hash_defined
228059024Sobrien		      ? N_ABS
228159024Sobrien		      : N_WEAKA);
228259024Sobrien	    type |= N_EXT;
228359024Sobrien	    val = (h->root.root.u.def.value
228459024Sobrien		   + output_section->vma
228559024Sobrien		   + sec->output_offset);
228659024Sobrien	  }
228759024Sobrien      }
228859024Sobrien      break;
228959024Sobrien    case bfd_link_hash_common:
229059024Sobrien      type = N_UNDF | N_EXT;
229159024Sobrien      val = h->root.root.u.c.size;
229259024Sobrien      break;
229359024Sobrien    case bfd_link_hash_undefweak:
229459024Sobrien      type = N_WEAKU;
229559024Sobrien      val = 0;
229659024Sobrien      break;
229759024Sobrien    case bfd_link_hash_indirect:
229859024Sobrien    case bfd_link_hash_warning:
229959024Sobrien      /* FIXME: Ignore these for now.  The circumstances under which
230059024Sobrien	 they should be written out are not clear to me.  */
2301130561Sobrien      return TRUE;
230259024Sobrien    }
230359024Sobrien
230459024Sobrien  s = bfd_get_section_by_name (sunos_hash_table (info)->dynobj, ".dynsym");
230559024Sobrien  BFD_ASSERT (s != NULL);
230659024Sobrien  outsym = ((struct external_nlist *)
230759024Sobrien	    (s->contents + h->dynindx * EXTERNAL_NLIST_SIZE));
230859024Sobrien
230989857Sobrien  H_PUT_8 (output_bfd, type, outsym->e_type);
231089857Sobrien  H_PUT_8 (output_bfd, 0, outsym->e_other);
231159024Sobrien
231259024Sobrien  /* FIXME: The native linker doesn't use 0 for desc.  It seems to use
231359024Sobrien     one less than the desc value in the shared library, although that
231459024Sobrien     seems unlikely.  */
231589857Sobrien  H_PUT_16 (output_bfd, 0, outsym->e_desc);
231659024Sobrien
231759024Sobrien  PUT_WORD (output_bfd, h->dynstr_index, outsym->e_strx);
231859024Sobrien  PUT_WORD (output_bfd, val, outsym->e_value);
231959024Sobrien
2320130561Sobrien  return TRUE;
232159024Sobrien}
232259024Sobrien
232359024Sobrien/* This is called for each reloc against an external symbol.  If this
232459024Sobrien   is a reloc which are are going to copy as a dynamic reloc, then
232559024Sobrien   copy it over, and tell the caller to not bother processing this
232659024Sobrien   reloc.  */
232759024Sobrien
2328130561Sobrienstatic bfd_boolean
2329218822Sdimsunos_check_dynamic_reloc (struct bfd_link_info *info,
2330218822Sdim			   bfd *input_bfd,
2331218822Sdim			   asection *input_section,
2332218822Sdim			   struct aout_link_hash_entry *harg,
2333218822Sdim			   void * reloc,
2334218822Sdim			   bfd_byte *contents ATTRIBUTE_UNUSED,
2335218822Sdim			   bfd_boolean *skip,
2336218822Sdim			   bfd_vma *relocationp)
233759024Sobrien{
233859024Sobrien  struct sunos_link_hash_entry *h = (struct sunos_link_hash_entry *) harg;
233959024Sobrien  bfd *dynobj;
2340130561Sobrien  bfd_boolean baserel;
2341130561Sobrien  bfd_boolean jmptbl;
2342130561Sobrien  bfd_boolean pcrel;
234359024Sobrien  asection *s;
234459024Sobrien  bfd_byte *p;
234559024Sobrien  long indx;
234659024Sobrien
2347130561Sobrien  *skip = FALSE;
234859024Sobrien
234959024Sobrien  dynobj = sunos_hash_table (info)->dynobj;
235059024Sobrien
235184865Sobrien  if (h != NULL
235284865Sobrien      && h->plt_offset != 0
235384865Sobrien      && (info->shared
235484865Sobrien	  || (h->flags & SUNOS_DEF_REGULAR) == 0))
235559024Sobrien    {
235659024Sobrien      asection *splt;
235759024Sobrien
235859024Sobrien      /* Redirect the relocation to the PLT entry.  */
235959024Sobrien      splt = bfd_get_section_by_name (dynobj, ".plt");
236059024Sobrien      *relocationp = (splt->output_section->vma
236159024Sobrien		      + splt->output_offset
236259024Sobrien		      + h->plt_offset);
236359024Sobrien    }
236459024Sobrien
236559024Sobrien  if (obj_reloc_entry_size (input_bfd) == RELOC_STD_SIZE)
236659024Sobrien    {
236759024Sobrien      struct reloc_std_external *srel;
236859024Sobrien
236959024Sobrien      srel = (struct reloc_std_external *) reloc;
237059024Sobrien      if (bfd_header_big_endian (input_bfd))
237159024Sobrien	{
237259024Sobrien	  baserel = (0 != (srel->r_type[0] & RELOC_STD_BITS_BASEREL_BIG));
237359024Sobrien	  jmptbl = (0 != (srel->r_type[0] & RELOC_STD_BITS_JMPTABLE_BIG));
237484865Sobrien	  pcrel = (0 != (srel->r_type[0] & RELOC_STD_BITS_PCREL_BIG));
237559024Sobrien	}
237659024Sobrien      else
237759024Sobrien	{
237859024Sobrien	  baserel = (0 != (srel->r_type[0] & RELOC_STD_BITS_BASEREL_LITTLE));
237959024Sobrien	  jmptbl = (0 != (srel->r_type[0] & RELOC_STD_BITS_JMPTABLE_LITTLE));
238084865Sobrien	  pcrel = (0 != (srel->r_type[0] & RELOC_STD_BITS_PCREL_LITTLE));
238159024Sobrien	}
238259024Sobrien    }
238359024Sobrien  else
238459024Sobrien    {
238559024Sobrien      struct reloc_ext_external *erel;
238659024Sobrien      int r_type;
238759024Sobrien
238859024Sobrien      erel = (struct reloc_ext_external *) reloc;
238959024Sobrien      if (bfd_header_big_endian (input_bfd))
239059024Sobrien	r_type = ((erel->r_type[0] & RELOC_EXT_BITS_TYPE_BIG)
239159024Sobrien		  >> RELOC_EXT_BITS_TYPE_SH_BIG);
239259024Sobrien      else
239359024Sobrien	r_type = ((erel->r_type[0] & RELOC_EXT_BITS_TYPE_LITTLE)
239459024Sobrien		  >> RELOC_EXT_BITS_TYPE_SH_LITTLE);
239559024Sobrien      baserel = (r_type == RELOC_BASE10
239659024Sobrien		 || r_type == RELOC_BASE13
239759024Sobrien		 || r_type == RELOC_BASE22);
239859024Sobrien      jmptbl = r_type == RELOC_JMP_TBL;
239984865Sobrien      pcrel = (r_type == RELOC_DISP8
240084865Sobrien	       || r_type == RELOC_DISP16
240184865Sobrien	       || r_type == RELOC_DISP32
240284865Sobrien	       || r_type == RELOC_WDISP30
240384865Sobrien	       || r_type == RELOC_WDISP22);
240484865Sobrien      /* We don't consider the PC10 and PC22 types to be PC relative,
2405130561Sobrien	 because they are pcrel_offset.  */
240659024Sobrien    }
240759024Sobrien
240859024Sobrien  if (baserel)
240959024Sobrien    {
241059024Sobrien      bfd_vma *got_offsetp;
241159024Sobrien      asection *sgot;
241259024Sobrien
241359024Sobrien      if (h != NULL)
241459024Sobrien	got_offsetp = &h->got_offset;
241559024Sobrien      else if (adata (input_bfd).local_got_offsets == NULL)
241659024Sobrien	got_offsetp = NULL;
241759024Sobrien      else
241859024Sobrien	{
241959024Sobrien	  struct reloc_std_external *srel;
242059024Sobrien	  int r_index;
242159024Sobrien
242259024Sobrien	  srel = (struct reloc_std_external *) reloc;
242359024Sobrien	  if (obj_reloc_entry_size (input_bfd) == RELOC_STD_SIZE)
242459024Sobrien	    {
242559024Sobrien	      if (bfd_header_big_endian (input_bfd))
242659024Sobrien		r_index = ((srel->r_index[0] << 16)
242759024Sobrien			   | (srel->r_index[1] << 8)
242859024Sobrien			   | srel->r_index[2]);
242959024Sobrien	      else
243059024Sobrien		r_index = ((srel->r_index[2] << 16)
243159024Sobrien			   | (srel->r_index[1] << 8)
243259024Sobrien			   | srel->r_index[0]);
243359024Sobrien	    }
243459024Sobrien	  else
243559024Sobrien	    {
243659024Sobrien	      struct reloc_ext_external *erel;
243759024Sobrien
243859024Sobrien	      erel = (struct reloc_ext_external *) reloc;
243959024Sobrien	      if (bfd_header_big_endian (input_bfd))
244059024Sobrien		r_index = ((erel->r_index[0] << 16)
244159024Sobrien			   | (erel->r_index[1] << 8)
244259024Sobrien			   | erel->r_index[2]);
244359024Sobrien	      else
244459024Sobrien		r_index = ((erel->r_index[2] << 16)
244559024Sobrien			   | (erel->r_index[1] << 8)
244659024Sobrien			   | erel->r_index[0]);
244759024Sobrien	    }
244859024Sobrien
244959024Sobrien	  got_offsetp = adata (input_bfd).local_got_offsets + r_index;
245059024Sobrien	}
245159024Sobrien
245259024Sobrien      BFD_ASSERT (got_offsetp != NULL && *got_offsetp != 0);
245359024Sobrien
245459024Sobrien      sgot = bfd_get_section_by_name (dynobj, ".got");
245559024Sobrien
245659024Sobrien      /* We set the least significant bit to indicate whether we have
245759024Sobrien	 already initialized the GOT entry.  */
245859024Sobrien      if ((*got_offsetp & 1) == 0)
245959024Sobrien	{
246059024Sobrien	  if (h == NULL
246159024Sobrien	      || (! info->shared
246259024Sobrien		  && ((h->flags & SUNOS_DEF_DYNAMIC) == 0
246359024Sobrien		      || (h->flags & SUNOS_DEF_REGULAR) != 0)))
246459024Sobrien	    PUT_WORD (dynobj, *relocationp, sgot->contents + *got_offsetp);
246559024Sobrien	  else
246659024Sobrien	    PUT_WORD (dynobj, 0, sgot->contents + *got_offsetp);
246759024Sobrien
246859024Sobrien	  if (info->shared
246959024Sobrien	      || (h != NULL
247059024Sobrien		  && (h->flags & SUNOS_DEF_DYNAMIC) != 0
247159024Sobrien		  && (h->flags & SUNOS_DEF_REGULAR) == 0))
247259024Sobrien	    {
247359024Sobrien	      /* We need to create a GLOB_DAT or 32 reloc to tell the
2474130561Sobrien		 dynamic linker to fill in this entry in the table.  */
247559024Sobrien
247659024Sobrien	      s = bfd_get_section_by_name (dynobj, ".dynrel");
247759024Sobrien	      BFD_ASSERT (s != NULL);
247859024Sobrien	      BFD_ASSERT (s->reloc_count * obj_reloc_entry_size (dynobj)
2479218822Sdim			  < s->size);
248059024Sobrien
248159024Sobrien	      p = (s->contents
248259024Sobrien		   + s->reloc_count * obj_reloc_entry_size (dynobj));
248359024Sobrien
248459024Sobrien	      if (h != NULL)
248559024Sobrien		indx = h->dynindx;
248659024Sobrien	      else
248759024Sobrien		indx = 0;
248859024Sobrien
248959024Sobrien	      if (obj_reloc_entry_size (dynobj) == RELOC_STD_SIZE)
249059024Sobrien		{
249159024Sobrien		  struct reloc_std_external *srel;
249259024Sobrien
249359024Sobrien		  srel = (struct reloc_std_external *) p;
249459024Sobrien		  PUT_WORD (dynobj,
249559024Sobrien			    (*got_offsetp
249659024Sobrien			     + sgot->output_section->vma
249759024Sobrien			     + sgot->output_offset),
249859024Sobrien			    srel->r_address);
249959024Sobrien		  if (bfd_header_big_endian (dynobj))
250059024Sobrien		    {
250184865Sobrien		      srel->r_index[0] = (bfd_byte) (indx >> 16);
250284865Sobrien		      srel->r_index[1] = (bfd_byte) (indx >> 8);
250359024Sobrien		      srel->r_index[2] = (bfd_byte)indx;
250459024Sobrien		      if (h == NULL)
250559024Sobrien			srel->r_type[0] = 2 << RELOC_STD_BITS_LENGTH_SH_BIG;
250659024Sobrien		      else
250759024Sobrien			srel->r_type[0] =
250859024Sobrien			  (RELOC_STD_BITS_EXTERN_BIG
250959024Sobrien			   | RELOC_STD_BITS_BASEREL_BIG
251059024Sobrien			   | RELOC_STD_BITS_RELATIVE_BIG
251159024Sobrien			   | (2 << RELOC_STD_BITS_LENGTH_SH_BIG));
251259024Sobrien		    }
251359024Sobrien		  else
251459024Sobrien		    {
251584865Sobrien		      srel->r_index[2] = (bfd_byte) (indx >> 16);
251684865Sobrien		      srel->r_index[1] = (bfd_byte) (indx >> 8);
251759024Sobrien		      srel->r_index[0] = (bfd_byte)indx;
251859024Sobrien		      if (h == NULL)
251959024Sobrien			srel->r_type[0] = 2 << RELOC_STD_BITS_LENGTH_SH_LITTLE;
252059024Sobrien		      else
252159024Sobrien			srel->r_type[0] =
252259024Sobrien			  (RELOC_STD_BITS_EXTERN_LITTLE
252359024Sobrien			   | RELOC_STD_BITS_BASEREL_LITTLE
252459024Sobrien			   | RELOC_STD_BITS_RELATIVE_LITTLE
252559024Sobrien			   | (2 << RELOC_STD_BITS_LENGTH_SH_LITTLE));
252659024Sobrien		    }
252759024Sobrien		}
252859024Sobrien	      else
252959024Sobrien		{
253059024Sobrien		  struct reloc_ext_external *erel;
253159024Sobrien
253259024Sobrien		  erel = (struct reloc_ext_external *) p;
253359024Sobrien		  PUT_WORD (dynobj,
253459024Sobrien			    (*got_offsetp
253559024Sobrien			     + sgot->output_section->vma
253659024Sobrien			     + sgot->output_offset),
253759024Sobrien			    erel->r_address);
253859024Sobrien		  if (bfd_header_big_endian (dynobj))
253959024Sobrien		    {
254084865Sobrien		      erel->r_index[0] = (bfd_byte) (indx >> 16);
254184865Sobrien		      erel->r_index[1] = (bfd_byte) (indx >> 8);
254259024Sobrien		      erel->r_index[2] = (bfd_byte)indx;
254359024Sobrien		      if (h == NULL)
254459024Sobrien			erel->r_type[0] =
254559024Sobrien			  RELOC_32 << RELOC_EXT_BITS_TYPE_SH_BIG;
254659024Sobrien		      else
254759024Sobrien			erel->r_type[0] =
254859024Sobrien			  (RELOC_EXT_BITS_EXTERN_BIG
254959024Sobrien			   | (RELOC_GLOB_DAT << RELOC_EXT_BITS_TYPE_SH_BIG));
255059024Sobrien		    }
255159024Sobrien		  else
255259024Sobrien		    {
255384865Sobrien		      erel->r_index[2] = (bfd_byte) (indx >> 16);
255484865Sobrien		      erel->r_index[1] = (bfd_byte) (indx >> 8);
255559024Sobrien		      erel->r_index[0] = (bfd_byte)indx;
255659024Sobrien		      if (h == NULL)
255759024Sobrien			erel->r_type[0] =
255859024Sobrien			  RELOC_32 << RELOC_EXT_BITS_TYPE_SH_LITTLE;
255959024Sobrien		      else
256059024Sobrien			erel->r_type[0] =
256159024Sobrien			  (RELOC_EXT_BITS_EXTERN_LITTLE
256259024Sobrien			   | (RELOC_GLOB_DAT
256359024Sobrien			      << RELOC_EXT_BITS_TYPE_SH_LITTLE));
256459024Sobrien		    }
256559024Sobrien		  PUT_WORD (dynobj, 0, erel->r_addend);
256659024Sobrien		}
256759024Sobrien
256859024Sobrien	      ++s->reloc_count;
256959024Sobrien	    }
257059024Sobrien
257159024Sobrien	  *got_offsetp |= 1;
257259024Sobrien	}
257359024Sobrien
257459024Sobrien      *relocationp = (sgot->vma
257589857Sobrien		      + (*got_offsetp &~ (bfd_vma) 1)
257659024Sobrien		      - sunos_hash_table (info)->got_base);
257759024Sobrien
257859024Sobrien      /* There is nothing else to do for a base relative reloc.  */
2579130561Sobrien      return TRUE;
258059024Sobrien    }
258159024Sobrien
258259024Sobrien  if (! sunos_hash_table (info)->dynamic_sections_needed)
2583130561Sobrien    return TRUE;
258459024Sobrien  if (! info->shared)
258559024Sobrien    {
258659024Sobrien      if (h == NULL
258759024Sobrien	  || h->dynindx == -1
258859024Sobrien	  || h->root.root.type != bfd_link_hash_undefined
258959024Sobrien	  || (h->flags & SUNOS_DEF_REGULAR) != 0
259059024Sobrien	  || (h->flags & SUNOS_DEF_DYNAMIC) == 0
259159024Sobrien	  || (h->root.root.u.undef.abfd->flags & DYNAMIC) == 0)
2592130561Sobrien	return TRUE;
259359024Sobrien    }
259459024Sobrien  else
259559024Sobrien    {
259659024Sobrien      if (h != NULL
259759024Sobrien	  && (h->dynindx == -1
259859024Sobrien	      || jmptbl
259959024Sobrien	      || strcmp (h->root.root.root.string,
260059024Sobrien			 "__GLOBAL_OFFSET_TABLE_") == 0))
2601130561Sobrien	return TRUE;
260259024Sobrien    }
260359024Sobrien
260459024Sobrien  /* It looks like this is a reloc we are supposed to copy.  */
260559024Sobrien
260659024Sobrien  s = bfd_get_section_by_name (dynobj, ".dynrel");
260759024Sobrien  BFD_ASSERT (s != NULL);
2608218822Sdim  BFD_ASSERT (s->reloc_count * obj_reloc_entry_size (dynobj) < s->size);
260959024Sobrien
261059024Sobrien  p = s->contents + s->reloc_count * obj_reloc_entry_size (dynobj);
261159024Sobrien
261259024Sobrien  /* Copy the reloc over.  */
261359024Sobrien  memcpy (p, reloc, obj_reloc_entry_size (dynobj));
261459024Sobrien
261559024Sobrien  if (h != NULL)
261659024Sobrien    indx = h->dynindx;
261759024Sobrien  else
261859024Sobrien    indx = 0;
261959024Sobrien
262059024Sobrien  /* Adjust the address and symbol index.  */
262159024Sobrien  if (obj_reloc_entry_size (dynobj) == RELOC_STD_SIZE)
262259024Sobrien    {
262359024Sobrien      struct reloc_std_external *srel;
262459024Sobrien
262559024Sobrien      srel = (struct reloc_std_external *) p;
262659024Sobrien      PUT_WORD (dynobj,
262759024Sobrien		(GET_WORD (dynobj, srel->r_address)
262859024Sobrien		 + input_section->output_section->vma
262959024Sobrien		 + input_section->output_offset),
263059024Sobrien		srel->r_address);
263159024Sobrien      if (bfd_header_big_endian (dynobj))
263259024Sobrien	{
263384865Sobrien	  srel->r_index[0] = (bfd_byte) (indx >> 16);
263484865Sobrien	  srel->r_index[1] = (bfd_byte) (indx >> 8);
263559024Sobrien	  srel->r_index[2] = (bfd_byte)indx;
263659024Sobrien	}
263759024Sobrien      else
263859024Sobrien	{
263984865Sobrien	  srel->r_index[2] = (bfd_byte) (indx >> 16);
264084865Sobrien	  srel->r_index[1] = (bfd_byte) (indx >> 8);
264159024Sobrien	  srel->r_index[0] = (bfd_byte)indx;
264259024Sobrien	}
264384865Sobrien      /* FIXME: We may have to change the addend for a PC relative
2644130561Sobrien	 reloc.  */
264559024Sobrien    }
264659024Sobrien  else
264759024Sobrien    {
264859024Sobrien      struct reloc_ext_external *erel;
264959024Sobrien
265059024Sobrien      erel = (struct reloc_ext_external *) p;
265159024Sobrien      PUT_WORD (dynobj,
265259024Sobrien		(GET_WORD (dynobj, erel->r_address)
265359024Sobrien		 + input_section->output_section->vma
265459024Sobrien		 + input_section->output_offset),
265559024Sobrien		erel->r_address);
265659024Sobrien      if (bfd_header_big_endian (dynobj))
265759024Sobrien	{
265884865Sobrien	  erel->r_index[0] = (bfd_byte) (indx >> 16);
265984865Sobrien	  erel->r_index[1] = (bfd_byte) (indx >> 8);
266059024Sobrien	  erel->r_index[2] = (bfd_byte)indx;
266159024Sobrien	}
266259024Sobrien      else
266359024Sobrien	{
266484865Sobrien	  erel->r_index[2] = (bfd_byte) (indx >> 16);
266584865Sobrien	  erel->r_index[1] = (bfd_byte) (indx >> 8);
266659024Sobrien	  erel->r_index[0] = (bfd_byte)indx;
266759024Sobrien	}
266884865Sobrien      if (pcrel && h != NULL)
266984865Sobrien	{
267084865Sobrien	  /* Adjust the addend for the change in address.  */
267184865Sobrien	  PUT_WORD (dynobj,
267284865Sobrien		    (GET_WORD (dynobj, erel->r_addend)
267384865Sobrien		     - (input_section->output_section->vma
267484865Sobrien			+ input_section->output_offset
267584865Sobrien			- input_section->vma)),
267684865Sobrien		    erel->r_addend);
267784865Sobrien	}
267859024Sobrien    }
267959024Sobrien
268059024Sobrien  ++s->reloc_count;
268159024Sobrien
268259024Sobrien  if (h != NULL)
2683130561Sobrien    *skip = TRUE;
268459024Sobrien
2685130561Sobrien  return TRUE;
268659024Sobrien}
268759024Sobrien
268859024Sobrien/* Finish up the dynamic linking information.  */
268959024Sobrien
2690130561Sobrienstatic bfd_boolean
2691218822Sdimsunos_finish_dynamic_link (bfd *abfd, struct bfd_link_info *info)
269259024Sobrien{
269359024Sobrien  bfd *dynobj;
269459024Sobrien  asection *o;
269559024Sobrien  asection *s;
269659024Sobrien  asection *sdyn;
269759024Sobrien
269859024Sobrien  if (! sunos_hash_table (info)->dynamic_sections_needed
269959024Sobrien      && ! sunos_hash_table (info)->got_needed)
2700130561Sobrien    return TRUE;
270159024Sobrien
270259024Sobrien  dynobj = sunos_hash_table (info)->dynobj;
270359024Sobrien
270459024Sobrien  sdyn = bfd_get_section_by_name (dynobj, ".dynamic");
270559024Sobrien  BFD_ASSERT (sdyn != NULL);
270659024Sobrien
270759024Sobrien  /* Finish up the .need section.  The linker emulation code filled it
270859024Sobrien     in, but with offsets from the start of the section instead of
270959024Sobrien     real addresses.  Now that we know the section location, we can
271059024Sobrien     fill in the final values.  */
271159024Sobrien  s = bfd_get_section_by_name (dynobj, ".need");
2712218822Sdim  if (s != NULL && s->size != 0)
271359024Sobrien    {
271459024Sobrien      file_ptr filepos;
271559024Sobrien      bfd_byte *p;
271659024Sobrien
271759024Sobrien      filepos = s->output_section->filepos + s->output_offset;
271859024Sobrien      p = s->contents;
271959024Sobrien      while (1)
272059024Sobrien	{
272159024Sobrien	  bfd_vma val;
272259024Sobrien
272359024Sobrien	  PUT_WORD (dynobj, GET_WORD (dynobj, p) + filepos, p);
272459024Sobrien	  val = GET_WORD (dynobj, p + 12);
272559024Sobrien	  if (val == 0)
272659024Sobrien	    break;
272759024Sobrien	  PUT_WORD (dynobj, val + filepos, p + 12);
272859024Sobrien	  p += 16;
272959024Sobrien	}
273059024Sobrien    }
273159024Sobrien
273259024Sobrien  /* The first entry in the .got section is the address of the
273359024Sobrien     dynamic information, unless this is a shared library.  */
273459024Sobrien  s = bfd_get_section_by_name (dynobj, ".got");
273559024Sobrien  BFD_ASSERT (s != NULL);
2736218822Sdim  if (info->shared || sdyn->size == 0)
273759024Sobrien    PUT_WORD (dynobj, 0, s->contents);
273859024Sobrien  else
273959024Sobrien    PUT_WORD (dynobj, sdyn->output_section->vma + sdyn->output_offset,
274059024Sobrien	      s->contents);
274159024Sobrien
274259024Sobrien  for (o = dynobj->sections; o != NULL; o = o->next)
274359024Sobrien    {
274459024Sobrien      if ((o->flags & SEC_HAS_CONTENTS) != 0
274559024Sobrien	  && o->contents != NULL)
274659024Sobrien	{
274759024Sobrien	  BFD_ASSERT (o->output_section != NULL
274859024Sobrien		      && o->output_section->owner == abfd);
274959024Sobrien	  if (! bfd_set_section_contents (abfd, o->output_section,
275089857Sobrien					  o->contents,
275189857Sobrien					  (file_ptr) o->output_offset,
2752218822Sdim					  o->size))
2753130561Sobrien	    return FALSE;
275459024Sobrien	}
275559024Sobrien    }
275659024Sobrien
2757218822Sdim  if (sdyn->size > 0)
275859024Sobrien    {
275959024Sobrien      struct external_sun4_dynamic esd;
276059024Sobrien      struct external_sun4_dynamic_link esdl;
276189857Sobrien      file_ptr pos;
276259024Sobrien
276359024Sobrien      /* Finish up the dynamic link information.  */
276459024Sobrien      PUT_WORD (dynobj, (bfd_vma) 3, esd.ld_version);
276559024Sobrien      PUT_WORD (dynobj,
276659024Sobrien		sdyn->output_section->vma + sdyn->output_offset + sizeof esd,
276759024Sobrien		esd.ldd);
276859024Sobrien      PUT_WORD (dynobj,
276959024Sobrien		(sdyn->output_section->vma
277059024Sobrien		 + sdyn->output_offset
277159024Sobrien		 + sizeof esd
277259024Sobrien		 + EXTERNAL_SUN4_DYNAMIC_DEBUGGER_SIZE),
277359024Sobrien		esd.ld);
277459024Sobrien
277559024Sobrien      if (! bfd_set_section_contents (abfd, sdyn->output_section, &esd,
277689857Sobrien				      (file_ptr) sdyn->output_offset,
277789857Sobrien				      (bfd_size_type) sizeof esd))
2778130561Sobrien	return FALSE;
277959024Sobrien
278059024Sobrien      PUT_WORD (dynobj, (bfd_vma) 0, esdl.ld_loaded);
278159024Sobrien
278259024Sobrien      s = bfd_get_section_by_name (dynobj, ".need");
2783218822Sdim      if (s == NULL || s->size == 0)
278459024Sobrien	PUT_WORD (dynobj, (bfd_vma) 0, esdl.ld_need);
278559024Sobrien      else
278659024Sobrien	PUT_WORD (dynobj, s->output_section->filepos + s->output_offset,
278759024Sobrien		  esdl.ld_need);
278859024Sobrien
278959024Sobrien      s = bfd_get_section_by_name (dynobj, ".rules");
2790218822Sdim      if (s == NULL || s->size == 0)
279159024Sobrien	PUT_WORD (dynobj, (bfd_vma) 0, esdl.ld_rules);
279259024Sobrien      else
279359024Sobrien	PUT_WORD (dynobj, s->output_section->filepos + s->output_offset,
279459024Sobrien		  esdl.ld_rules);
279559024Sobrien
279659024Sobrien      s = bfd_get_section_by_name (dynobj, ".got");
279759024Sobrien      BFD_ASSERT (s != NULL);
279859024Sobrien      PUT_WORD (dynobj, s->output_section->vma + s->output_offset,
279959024Sobrien		esdl.ld_got);
280059024Sobrien
280159024Sobrien      s = bfd_get_section_by_name (dynobj, ".plt");
280259024Sobrien      BFD_ASSERT (s != NULL);
280359024Sobrien      PUT_WORD (dynobj, s->output_section->vma + s->output_offset,
280459024Sobrien		esdl.ld_plt);
2805218822Sdim      PUT_WORD (dynobj, s->size, esdl.ld_plt_sz);
280659024Sobrien
280759024Sobrien      s = bfd_get_section_by_name (dynobj, ".dynrel");
280859024Sobrien      BFD_ASSERT (s != NULL);
280959024Sobrien      BFD_ASSERT (s->reloc_count * obj_reloc_entry_size (dynobj)
2810218822Sdim		  == s->size);
281159024Sobrien      PUT_WORD (dynobj, s->output_section->filepos + s->output_offset,
281259024Sobrien		esdl.ld_rel);
281359024Sobrien
281459024Sobrien      s = bfd_get_section_by_name (dynobj, ".hash");
281559024Sobrien      BFD_ASSERT (s != NULL);
281659024Sobrien      PUT_WORD (dynobj, s->output_section->filepos + s->output_offset,
281759024Sobrien		esdl.ld_hash);
281859024Sobrien
281959024Sobrien      s = bfd_get_section_by_name (dynobj, ".dynsym");
282059024Sobrien      BFD_ASSERT (s != NULL);
282159024Sobrien      PUT_WORD (dynobj, s->output_section->filepos + s->output_offset,
282259024Sobrien		esdl.ld_stab);
282359024Sobrien
282459024Sobrien      PUT_WORD (dynobj, (bfd_vma) 0, esdl.ld_stab_hash);
282559024Sobrien
282659024Sobrien      PUT_WORD (dynobj, (bfd_vma) sunos_hash_table (info)->bucketcount,
282759024Sobrien		esdl.ld_buckets);
282859024Sobrien
282959024Sobrien      s = bfd_get_section_by_name (dynobj, ".dynstr");
283059024Sobrien      BFD_ASSERT (s != NULL);
283159024Sobrien      PUT_WORD (dynobj, s->output_section->filepos + s->output_offset,
283259024Sobrien		esdl.ld_symbols);
2833218822Sdim      PUT_WORD (dynobj, s->size, esdl.ld_symb_size);
283459024Sobrien
283559024Sobrien      /* The size of the text area is the size of the .text section
283659024Sobrien	 rounded up to a page boundary.  FIXME: Should the page size be
283759024Sobrien	 conditional on something?  */
283859024Sobrien      PUT_WORD (dynobj,
2839218822Sdim		BFD_ALIGN (obj_textsec (abfd)->size, 0x2000),
284059024Sobrien		esdl.ld_text);
284184865Sobrien
284289857Sobrien      pos = sdyn->output_offset;
284389857Sobrien      pos += sizeof esd + EXTERNAL_SUN4_DYNAMIC_DEBUGGER_SIZE;
284459024Sobrien      if (! bfd_set_section_contents (abfd, sdyn->output_section, &esdl,
284589857Sobrien				      pos, (bfd_size_type) sizeof esdl))
2846130561Sobrien	return FALSE;
284759024Sobrien
284859024Sobrien      abfd->flags |= DYNAMIC;
284959024Sobrien    }
285059024Sobrien
2851130561Sobrien  return TRUE;
285259024Sobrien}
2853