160484Sobrien/* BFD back-end for linux flavored sparc a.out binaries.
2218822Sdim   Copyright 1992, 1993, 1994, 1995, 1996, 1997, 1999, 2000, 2001, 2002,
3218822Sdim   2003, 2004, 2006, 2007 Free Software Foundation, Inc.
460484Sobrien
5218822Sdim   This file is part of BFD, the Binary File Descriptor library.
660484Sobrien
7218822Sdim   This program is free software; you can redistribute it and/or modify
8218822Sdim   it under the terms of the GNU General Public License as published by
9218822Sdim   the Free Software Foundation; either version 2 of the License, or
10218822Sdim   (at your option) any later version.
1160484Sobrien
12218822Sdim   This program is distributed in the hope that it will be useful,
13218822Sdim   but WITHOUT ANY WARRANTY; without even the implied warranty of
14218822Sdim   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15218822Sdim   GNU General Public License for more details.
1660484Sobrien
17218822Sdim   You should have received a copy of the GNU General Public License
18218822Sdim   along with this program; if not, write to the Free Software
19218822Sdim   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301,
20218822Sdim   USA.  */
2160484Sobrien
22130561Sobrien#define TARGET_PAGE_SIZE	4096
23130561Sobrien#define ZMAGIC_DISK_BLOCK_SIZE	1024
24130561Sobrien#define SEGMENT_SIZE		TARGET_PAGE_SIZE
25130561Sobrien#define TEXT_START_ADDR		0x0
26130561Sobrien#define N_SHARED_LIB(x)		0
2760484Sobrien
2860484Sobrien#define MACHTYPE_OK(mtype) ((mtype) == M_SPARC || (mtype) == M_UNKNOWN)
2960484Sobrien
30218822Sdim#include "sysdep.h"
3160484Sobrien#include "bfd.h"
3260484Sobrien#include "libbfd.h"
3360484Sobrien#include "aout/aout64.h"
3460484Sobrien#include "aout/stab_gnu.h"
3560484Sobrien#include "aout/ar.h"
3660484Sobrien#include "libaout.h"           /* BFD a.out internal data structures */
3760484Sobrien
3860484Sobrien#define DEFAULT_ARCH bfd_arch_sparc
3989857Sobrien/* Do not "beautify" the CONCAT* macro args.  Traditional C will not
4089857Sobrien   remove whitespace added here, and thus will fail to concatenate
4189857Sobrien   the tokens.  */
4289857Sobrien#define MY(OP) CONCAT2 (sparclinux_,OP)
4360484Sobrien#define TARGETNAME "a.out-sparc-linux"
4460484Sobrien
4560484Sobrienextern const bfd_target MY(vec);
4660484Sobrien
4760484Sobrien/* We always generate QMAGIC files in preference to ZMAGIC files.  It
4860484Sobrien   would be possible to make this a linker option, if that ever
4960484Sobrien   becomes important.  */
5060484Sobrien
5160484Sobrienstatic void MY_final_link_callback
5260484Sobrien  PARAMS ((bfd *, file_ptr *, file_ptr *, file_ptr *));
5360484Sobrien
54130561Sobrienstatic bfd_boolean sparclinux_bfd_final_link
5560484Sobrien  PARAMS ((bfd *abfd, struct bfd_link_info *info));
5660484Sobrien
57130561Sobrienstatic bfd_boolean
5860484Sobriensparclinux_bfd_final_link (abfd, info)
5960484Sobrien     bfd *abfd;
6060484Sobrien     struct bfd_link_info *info;
6160484Sobrien{
6260484Sobrien  obj_aout_subformat (abfd) = q_magic_format;
6360484Sobrien  return NAME(aout,final_link) (abfd, info, MY_final_link_callback);
6460484Sobrien}
6560484Sobrien
6660484Sobrien#define MY_bfd_final_link sparclinux_bfd_final_link
6760484Sobrien
6860484Sobrien/* Set the machine type correctly.  */
6960484Sobrien
70130561Sobrienstatic bfd_boolean sparclinux_write_object_contents PARAMS ((bfd *abfd));
7160484Sobrien
72130561Sobrienstatic bfd_boolean
7360484Sobriensparclinux_write_object_contents (abfd)
7460484Sobrien     bfd *abfd;
7560484Sobrien{
7660484Sobrien  struct external_exec exec_bytes;
7760484Sobrien  struct internal_exec *execp = exec_hdr (abfd);
7860484Sobrien
7960484Sobrien  N_SET_MACHTYPE (*execp, M_SPARC);
8060484Sobrien
8160484Sobrien  obj_reloc_entry_size (abfd) = RELOC_STD_SIZE;
8260484Sobrien
8360484Sobrien  WRITE_HEADERS(abfd, execp);
8460484Sobrien
85130561Sobrien  return TRUE;
8660484Sobrien}
8760484Sobrien
8860484Sobrien#define MY_write_object_contents sparclinux_write_object_contents
8960484Sobrien/* Code to link against Linux a.out shared libraries.  */
9060484Sobrien
9160484Sobrien/* See if a symbol name is a reference to the global offset table.  */
9260484Sobrien
9360484Sobrien#ifndef GOT_REF_PREFIX
94130561Sobrien#define GOT_REF_PREFIX  "__GOT_"
9560484Sobrien#endif
9660484Sobrien
97218822Sdim#define IS_GOT_SYM(name)  (CONST_STRNEQ (name, GOT_REF_PREFIX))
9860484Sobrien
9977298Sobrien/* See if a symbol name is a reference to the procedure linkage table.  */
10060484Sobrien
10160484Sobrien#ifndef PLT_REF_PREFIX
102130561Sobrien#define PLT_REF_PREFIX  "__PLT_"
10360484Sobrien#endif
10460484Sobrien
105218822Sdim#define IS_PLT_SYM(name)  (CONST_STRNEQ (name, PLT_REF_PREFIX))
10660484Sobrien
10760484Sobrien/* This string is used to generate specialized error messages.  */
10860484Sobrien
10960484Sobrien#ifndef NEEDS_SHRLIB
11060484Sobrien#define NEEDS_SHRLIB "__NEEDS_SHRLIB_"
11160484Sobrien#endif
11260484Sobrien
11360484Sobrien/* This special symbol is a set vector that contains a list of
114130561Sobrien   pointers to fixup tables.  It will be present in any dynamically
11560484Sobrien   linked file.  The linker generated fixup table should also be added
11660484Sobrien   to the list, and it should always appear in the second slot (the
11760484Sobrien   first one is a dummy with a magic number that is defined in
11860484Sobrien   crt0.o).  */
11960484Sobrien
12060484Sobrien#ifndef SHARABLE_CONFLICTS
12160484Sobrien#define SHARABLE_CONFLICTS "__SHARABLE_CONFLICTS__"
12260484Sobrien#endif
12360484Sobrien
12460484Sobrien/* We keep a list of fixups.  The terminology is a bit strange, but
12560484Sobrien   each fixup contains two 32 bit numbers.  A regular fixup contains
12660484Sobrien   an address and a pointer, and at runtime we should store the
12760484Sobrien   address at the location pointed to by the pointer.  A builtin fixup
12860484Sobrien   contains two pointers, and we should read the address using one
12960484Sobrien   pointer and store it at the location pointed to by the other
13060484Sobrien   pointer.  Builtin fixups come into play when we have duplicate
13160484Sobrien   __GOT__ symbols for the same variable.  The builtin fixup will copy
13260484Sobrien   the GOT pointer from one over into the other.  */
13360484Sobrien
13460484Sobrienstruct fixup
13560484Sobrien{
13660484Sobrien  struct fixup *next;
13760484Sobrien  struct linux_link_hash_entry *h;
13860484Sobrien  bfd_vma value;
13960484Sobrien
14060484Sobrien  /* Nonzero if this is a jump instruction that needs to be fixed,
14160484Sobrien     zero if this is just a pointer */
14260484Sobrien  char jump;
14360484Sobrien
14460484Sobrien  char builtin;
14560484Sobrien};
14660484Sobrien
14760484Sobrien/* We don't need a special hash table entry structure, but we do need
14860484Sobrien   to keep some information between linker passes, so we use a special
14960484Sobrien   hash table.  */
15060484Sobrien
15160484Sobrienstruct linux_link_hash_entry
15260484Sobrien{
15360484Sobrien  struct aout_link_hash_entry root;
15460484Sobrien};
15560484Sobrien
15660484Sobrienstruct linux_link_hash_table
15760484Sobrien{
15860484Sobrien  struct aout_link_hash_table root;
15960484Sobrien
16060484Sobrien  /* First dynamic object found in link.  */
16160484Sobrien  bfd *dynobj;
16260484Sobrien
16360484Sobrien  /* Number of fixups.  */
16460484Sobrien  size_t fixup_count;
16560484Sobrien
16660484Sobrien  /* Number of builtin fixups.  */
16760484Sobrien  size_t local_builtins;
16860484Sobrien
16960484Sobrien  /* List of fixups.  */
17060484Sobrien  struct fixup *fixup_list;
17160484Sobrien};
17260484Sobrien
17360484Sobrienstatic struct bfd_hash_entry *linux_link_hash_newfunc
17460484Sobrien  PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, const char *));
17560484Sobrienstatic struct bfd_link_hash_table *linux_link_hash_table_create
17660484Sobrien  PARAMS ((bfd *));
17760484Sobrienstatic struct fixup *new_fixup
17860484Sobrien  PARAMS ((struct bfd_link_info *, struct linux_link_hash_entry *,
179130561Sobrien	  bfd_vma, int));
180130561Sobrienstatic bfd_boolean linux_link_create_dynamic_sections
18160484Sobrien  PARAMS ((bfd *, struct bfd_link_info *));
182130561Sobrienstatic bfd_boolean linux_add_one_symbol
18360484Sobrien  PARAMS ((struct bfd_link_info *, bfd *, const char *, flagword, asection *,
184130561Sobrien	  bfd_vma, const char *, bfd_boolean, bfd_boolean,
185130561Sobrien	  struct bfd_link_hash_entry **));
186130561Sobrienstatic bfd_boolean linux_tally_symbols
18760484Sobrien  PARAMS ((struct linux_link_hash_entry *, PTR));
188130561Sobrienstatic bfd_boolean linux_finish_dynamic_link
18960484Sobrien  PARAMS ((bfd *, struct bfd_link_info *));
19060484Sobrien
19160484Sobrien/* Routine to create an entry in an Linux link hash table.  */
19260484Sobrien
19360484Sobrienstatic struct bfd_hash_entry *
19460484Sobrienlinux_link_hash_newfunc (entry, table, string)
19560484Sobrien     struct bfd_hash_entry *entry;
19660484Sobrien     struct bfd_hash_table *table;
19760484Sobrien     const char *string;
19860484Sobrien{
19960484Sobrien  struct linux_link_hash_entry *ret = (struct linux_link_hash_entry *) entry;
20060484Sobrien
20160484Sobrien  /* Allocate the structure if it has not already been allocated by a
20260484Sobrien     subclass.  */
20360484Sobrien  if (ret == (struct linux_link_hash_entry *) NULL)
20460484Sobrien    ret = ((struct linux_link_hash_entry *)
205130561Sobrien	   bfd_hash_allocate (table, sizeof (struct linux_link_hash_entry)));
20660484Sobrien  if (ret == NULL)
20760484Sobrien    return (struct bfd_hash_entry *) ret;
20860484Sobrien
20960484Sobrien  /* Call the allocation method of the superclass.  */
21060484Sobrien  ret = ((struct linux_link_hash_entry *)
211130561Sobrien	 NAME(aout,link_hash_newfunc) ((struct bfd_hash_entry *) ret,
212130561Sobrien				       table, string));
21360484Sobrien  if (ret != NULL)
21460484Sobrien    {
21560484Sobrien      /* Set local fields; there aren't any.  */
21660484Sobrien    }
21760484Sobrien
21860484Sobrien  return (struct bfd_hash_entry *) ret;
21960484Sobrien}
22060484Sobrien
22160484Sobrien/* Create a Linux link hash table.  */
22260484Sobrien
22360484Sobrienstatic struct bfd_link_hash_table *
22460484Sobrienlinux_link_hash_table_create (abfd)
22560484Sobrien     bfd *abfd;
22660484Sobrien{
22760484Sobrien  struct linux_link_hash_table *ret;
22889857Sobrien  bfd_size_type amt = sizeof (struct linux_link_hash_table);
22960484Sobrien
230104834Sobrien  ret = (struct linux_link_hash_table *) bfd_malloc (amt);
23160484Sobrien  if (ret == (struct linux_link_hash_table *) NULL)
23260484Sobrien    return (struct bfd_link_hash_table *) NULL;
233218822Sdim  if (!NAME(aout,link_hash_table_init) (&ret->root, abfd,
234218822Sdim					linux_link_hash_newfunc,
235218822Sdim					sizeof (struct linux_link_hash_entry)))
23660484Sobrien    {
23760484Sobrien      free (ret);
23860484Sobrien      return (struct bfd_link_hash_table *) NULL;
23960484Sobrien    }
24060484Sobrien
24160484Sobrien  ret->dynobj = NULL;
24260484Sobrien  ret->fixup_count = 0;
24360484Sobrien  ret->local_builtins = 0;
24460484Sobrien  ret->fixup_list = NULL;
24560484Sobrien
24660484Sobrien  return &ret->root.root;
24760484Sobrien}
24860484Sobrien
24960484Sobrien/* Look up an entry in a Linux link hash table.  */
25060484Sobrien
25160484Sobrien#define linux_link_hash_lookup(table, string, create, copy, follow) \
25260484Sobrien  ((struct linux_link_hash_entry *) \
25360484Sobrien   aout_link_hash_lookup (&(table)->root, (string), (create), (copy),\
254130561Sobrien			  (follow)))
25560484Sobrien
25660484Sobrien/* Traverse a Linux link hash table.  */
25760484Sobrien
258130561Sobrien#define linux_link_hash_traverse(table, func, info)		       \
259130561Sobrien  (aout_link_hash_traverse					       \
260130561Sobrien   (&(table)->root,						       \
261130561Sobrien    (bfd_boolean (*) PARAMS ((struct aout_link_hash_entry *, PTR))) (func), \
26260484Sobrien    (info)))
26360484Sobrien
26460484Sobrien/* Get the Linux link hash table from the info structure.  This is
26560484Sobrien   just a cast.  */
26660484Sobrien
26760484Sobrien#define linux_hash_table(p) ((struct linux_link_hash_table *) ((p)->hash))
26860484Sobrien
26960484Sobrien/* Store the information for a new fixup.  */
27060484Sobrien
27160484Sobrienstatic struct fixup *
27260484Sobriennew_fixup (info, h, value, builtin)
27360484Sobrien     struct bfd_link_info *info;
27460484Sobrien     struct linux_link_hash_entry *h;
27560484Sobrien     bfd_vma value;
27660484Sobrien     int builtin;
27760484Sobrien{
27860484Sobrien  struct fixup *f;
27960484Sobrien
28060484Sobrien  f = (struct fixup *) bfd_hash_allocate (&info->hash->table,
281130561Sobrien					  sizeof (struct fixup));
28260484Sobrien  if (f == NULL)
28360484Sobrien    return f;
28460484Sobrien  f->next = linux_hash_table (info)->fixup_list;
28560484Sobrien  linux_hash_table (info)->fixup_list = f;
28660484Sobrien  f->h = h;
28760484Sobrien  f->value = value;
28860484Sobrien  f->builtin = builtin;
28960484Sobrien  f->jump = 0;
29060484Sobrien  ++linux_hash_table (info)->fixup_count;
29160484Sobrien  return f;
29260484Sobrien}
29360484Sobrien
29460484Sobrien/* We come here once we realize that we are going to link to a shared
29560484Sobrien   library.  We need to create a special section that contains the
29660484Sobrien   fixup table, and we ultimately need to add a pointer to this into
29760484Sobrien   the set vector for SHARABLE_CONFLICTS.  At this point we do not
29860484Sobrien   know the size of the section, but that's OK - we just need to
29960484Sobrien   create it for now.  */
30060484Sobrien
301130561Sobrienstatic bfd_boolean
30260484Sobrienlinux_link_create_dynamic_sections (abfd, info)
30360484Sobrien     bfd *abfd;
30460484Sobrien     struct bfd_link_info *info ATTRIBUTE_UNUSED;
30560484Sobrien{
30660484Sobrien  flagword flags;
30760484Sobrien  register asection *s;
30860484Sobrien
30960484Sobrien  /* Note that we set the SEC_IN_MEMORY flag.  */
31060484Sobrien  flags = SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY;
31160484Sobrien
31260484Sobrien  /* We choose to use the name ".linux-dynamic" for the fixup table.
313130561Sobrien     Why not?  */
314218822Sdim  s = bfd_make_section_with_flags (abfd, ".linux-dynamic", flags);
31560484Sobrien  if (s == NULL
31660484Sobrien      || ! bfd_set_section_alignment (abfd, s, 2))
317130561Sobrien    return FALSE;
318218822Sdim  s->size = 0;
31960484Sobrien  s->contents = 0;
32060484Sobrien
321130561Sobrien  return TRUE;
32260484Sobrien}
32360484Sobrien
32460484Sobrien/* Function to add a single symbol to the linker hash table.  This is
32560484Sobrien   a wrapper around _bfd_generic_link_add_one_symbol which handles the
32660484Sobrien   tweaking needed for dynamic linking support.  */
32760484Sobrien
328130561Sobrienstatic bfd_boolean
32960484Sobrienlinux_add_one_symbol (info, abfd, name, flags, section, value, string,
330130561Sobrien		      copy, collect, hashp)
33160484Sobrien     struct bfd_link_info *info;
33260484Sobrien     bfd *abfd;
33360484Sobrien     const char *name;
33460484Sobrien     flagword flags;
33560484Sobrien     asection *section;
33660484Sobrien     bfd_vma value;
33760484Sobrien     const char *string;
338130561Sobrien     bfd_boolean copy;
339130561Sobrien     bfd_boolean collect;
34060484Sobrien     struct bfd_link_hash_entry **hashp;
34160484Sobrien{
34260484Sobrien  struct linux_link_hash_entry *h;
343130561Sobrien  bfd_boolean insert;
34460484Sobrien
34560484Sobrien  /* Look up and see if we already have this symbol in the hash table.
34660484Sobrien     If we do, and the defining entry is from a shared library, we
34760484Sobrien     need to create the dynamic sections.
34860484Sobrien
34960484Sobrien     FIXME: What if abfd->xvec != info->hash->creator?  We may want to
35060484Sobrien     be able to link Linux a.out and ELF objects together, but serious
35160484Sobrien     confusion is possible.  */
35260484Sobrien
353130561Sobrien  insert = FALSE;
35460484Sobrien
355130561Sobrien  if (! info->relocatable
35660484Sobrien      && linux_hash_table (info)->dynobj == NULL
35760484Sobrien      && strcmp (name, SHARABLE_CONFLICTS) == 0
35860484Sobrien      && (flags & BSF_CONSTRUCTOR) != 0
35960484Sobrien      && abfd->xvec == info->hash->creator)
36060484Sobrien    {
36160484Sobrien      if (! linux_link_create_dynamic_sections (abfd, info))
362130561Sobrien	return FALSE;
36360484Sobrien      linux_hash_table (info)->dynobj = abfd;
364130561Sobrien      insert = TRUE;
36560484Sobrien    }
36660484Sobrien
36760484Sobrien  if (bfd_is_abs_section (section)
36860484Sobrien      && abfd->xvec == info->hash->creator)
36960484Sobrien    {
370130561Sobrien      h = linux_link_hash_lookup (linux_hash_table (info), name, FALSE,
371130561Sobrien				  FALSE, FALSE);
37260484Sobrien      if (h != NULL
373130561Sobrien	  && (h->root.root.type == bfd_link_hash_defined
374130561Sobrien	      || h->root.root.type == bfd_link_hash_defweak))
375130561Sobrien	{
376130561Sobrien	  struct fixup *f;
37760484Sobrien
378130561Sobrien	  if (hashp != NULL)
379130561Sobrien	    *hashp = (struct bfd_link_hash_entry *) h;
38060484Sobrien
381130561Sobrien	  f = new_fixup (info, h, value, ! IS_PLT_SYM (name));
382130561Sobrien	  if (f == NULL)
383130561Sobrien	    return FALSE;
384130561Sobrien	  f->jump = IS_PLT_SYM (name);
38560484Sobrien
386130561Sobrien	  return TRUE;
387130561Sobrien	}
38860484Sobrien    }
38960484Sobrien
39060484Sobrien  /* Do the usual procedure for adding a symbol.  */
39160484Sobrien  if (! _bfd_generic_link_add_one_symbol (info, abfd, name, flags, section,
392130561Sobrien					  value, string, copy, collect,
393130561Sobrien					  hashp))
394130561Sobrien    return FALSE;
39560484Sobrien
39660484Sobrien  /* Insert a pointer to our table in the set vector.  The dynamic
397130561Sobrien     linker requires this information.  */
39860484Sobrien  if (insert)
39960484Sobrien    {
40060484Sobrien      asection *s;
40160484Sobrien
40260484Sobrien      /* Here we do our special thing to add the pointer to the
403130561Sobrien	 dynamic section in the SHARABLE_CONFLICTS set vector.  */
40460484Sobrien      s = bfd_get_section_by_name (linux_hash_table (info)->dynobj,
405130561Sobrien				   ".linux-dynamic");
40660484Sobrien      BFD_ASSERT (s != NULL);
40760484Sobrien
40860484Sobrien      if (! (_bfd_generic_link_add_one_symbol
409130561Sobrien	     (info, linux_hash_table (info)->dynobj, SHARABLE_CONFLICTS,
410130561Sobrien	      BSF_GLOBAL | BSF_CONSTRUCTOR, s, (bfd_vma) 0, NULL,
411130561Sobrien	      FALSE, FALSE, NULL)))
412130561Sobrien	return FALSE;
41360484Sobrien    }
41460484Sobrien
415130561Sobrien  return TRUE;
41660484Sobrien}
41760484Sobrien
41860484Sobrien/* We will crawl the hash table and come here for every global symbol.
41960484Sobrien   We will examine each entry and see if there are indications that we
42060484Sobrien   need to add a fixup.  There are two possible cases - one is where
42160484Sobrien   you have duplicate definitions of PLT or GOT symbols - these will
42260484Sobrien   have already been caught and added as "builtin" fixups.  If we find
42360484Sobrien   that the corresponding non PLT/GOT symbol is also present, we
42460484Sobrien   convert it to a regular fixup instead.
42560484Sobrien
42660484Sobrien   This function is called via linux_link_hash_traverse.  */
42760484Sobrien
428130561Sobrienstatic bfd_boolean
429218822Sdimlinux_tally_symbols (struct linux_link_hash_entry *h, void * data)
43060484Sobrien{
43160484Sobrien  struct bfd_link_info *info = (struct bfd_link_info *) data;
43260484Sobrien  struct fixup *f, *f1;
43360484Sobrien  int is_plt;
43460484Sobrien  struct linux_link_hash_entry *h1, *h2;
435130561Sobrien  bfd_boolean exists;
43660484Sobrien
43794536Sobrien  if (h->root.root.type == bfd_link_hash_warning)
43894536Sobrien    h = (struct linux_link_hash_entry *) h->root.root.u.i.link;
43994536Sobrien
44060484Sobrien  if (h->root.root.type == bfd_link_hash_undefined
441218822Sdim      && CONST_STRNEQ (h->root.root.root.string, NEEDS_SHRLIB))
44260484Sobrien    {
44360484Sobrien      const char *name;
44460484Sobrien      char *p;
44560484Sobrien      char *alloc = NULL;
44660484Sobrien
44760484Sobrien      name = h->root.root.root.string + sizeof NEEDS_SHRLIB - 1;
44860484Sobrien      p = strrchr (name, '_');
44960484Sobrien      if (p != NULL)
450130561Sobrien	alloc = (char *) bfd_malloc ((bfd_size_type) strlen (name) + 1);
45160484Sobrien
45260484Sobrien      if (p == NULL || alloc == NULL)
453130561Sobrien	(*_bfd_error_handler) (_("Output file requires shared library `%s'\n"),
454130561Sobrien			       name);
45560484Sobrien      else
456130561Sobrien	{
457130561Sobrien	  strcpy (alloc, name);
458130561Sobrien	  p = strrchr (alloc, '_');
459130561Sobrien	  *p++ = '\0';
460130561Sobrien	  (*_bfd_error_handler)
461130561Sobrien	    (_("Output file requires shared library `%s.so.%s'\n"),
462130561Sobrien	     alloc, p);
463130561Sobrien	  free (alloc);
464130561Sobrien	}
46560484Sobrien
46660484Sobrien      abort ();
46760484Sobrien    }
46860484Sobrien
46960484Sobrien  /* If this symbol is not a PLT/GOT, we do not even need to look at
47060484Sobrien     it.  */
47160484Sobrien  is_plt = IS_PLT_SYM (h->root.root.root.string);
47260484Sobrien
47360484Sobrien  if (is_plt || IS_GOT_SYM (h->root.root.root.string))
47460484Sobrien    {
47560484Sobrien      /* Look up this symbol twice.  Once just as a regular lookup,
476130561Sobrien	 and then again following all of the indirect links until we
477130561Sobrien	 reach a real symbol.  */
47860484Sobrien      h1 = linux_link_hash_lookup (linux_hash_table (info),
479130561Sobrien				   (h->root.root.root.string
480130561Sobrien				    + sizeof PLT_REF_PREFIX - 1),
481130561Sobrien				   FALSE, FALSE, TRUE);
48277298Sobrien      /* h2 does not follow indirect symbols.  */
48360484Sobrien      h2 = linux_link_hash_lookup (linux_hash_table (info),
484130561Sobrien				   (h->root.root.root.string
485130561Sobrien				    + sizeof PLT_REF_PREFIX - 1),
486130561Sobrien				   FALSE, FALSE, FALSE);
48760484Sobrien
48860484Sobrien      /* The real symbol must exist but if it is also an ABS symbol,
489130561Sobrien	 there is no need to have a fixup.  This is because they both
490130561Sobrien	 came from the same library.  If on the other hand, we had to
491130561Sobrien	 use an indirect symbol to get to the real symbol, we add the
492130561Sobrien	 fixup anyway, since there are cases where these symbols come
493130561Sobrien	 from different shared libraries */
49460484Sobrien      if (h1 != NULL
495130561Sobrien	  && (((h1->root.root.type == bfd_link_hash_defined
496130561Sobrien		|| h1->root.root.type == bfd_link_hash_defweak)
497130561Sobrien	       && ! bfd_is_abs_section (h1->root.root.u.def.section))
498130561Sobrien	      || h2->root.root.type == bfd_link_hash_indirect))
499130561Sobrien	{
500130561Sobrien	  /* See if there is a "builtin" fixup already present
501130561Sobrien	     involving this symbol.  If so, convert it to a regular
502130561Sobrien	     fixup.  In the end, this relaxes some of the requirements
503130561Sobrien	     about the order of performing fixups.  */
504130561Sobrien	  exists = FALSE;
505130561Sobrien	  for (f1 = linux_hash_table (info)->fixup_list;
506130561Sobrien	       f1 != NULL;
507130561Sobrien	       f1 = f1->next)
508130561Sobrien	    {
509130561Sobrien	      if ((f1->h != h && f1->h != h1)
510130561Sobrien		  || (! f1->builtin && ! f1->jump))
511130561Sobrien		continue;
512130561Sobrien	      if (f1->h == h1)
513130561Sobrien		exists = TRUE;
514130561Sobrien	      if (! exists
515130561Sobrien		  && bfd_is_abs_section (h->root.root.u.def.section))
516130561Sobrien		{
517130561Sobrien		  f = new_fixup (info, h1, f1->h->root.root.u.def.value, 0);
518130561Sobrien		  f->jump = is_plt;
519130561Sobrien		}
520130561Sobrien	      f1->h = h1;
521130561Sobrien	      f1->jump = is_plt;
522130561Sobrien	      f1->builtin = 0;
523130561Sobrien	      exists = TRUE;
524130561Sobrien	    }
525130561Sobrien	  if (! exists
526130561Sobrien	      && bfd_is_abs_section (h->root.root.u.def.section))
527130561Sobrien	    {
528130561Sobrien	      f = new_fixup (info, h1, h->root.root.u.def.value, 0);
529130561Sobrien	      if (f == NULL)
530130561Sobrien		{
531130561Sobrien		  /* FIXME: No way to return error.  */
532130561Sobrien		  abort ();
533130561Sobrien		}
534130561Sobrien	      f->jump = is_plt;
535130561Sobrien	    }
536130561Sobrien	}
53760484Sobrien
53860484Sobrien      /* Quick and dirty way of stripping these symbols from the
539130561Sobrien	 symtab.  */
54060484Sobrien      if (bfd_is_abs_section (h->root.root.u.def.section))
541130561Sobrien	h->root.written = TRUE;
54260484Sobrien    }
54360484Sobrien
544130561Sobrien  return TRUE;
54560484Sobrien}
54660484Sobrien
54760484Sobrien/* This is called to set the size of the .linux-dynamic section is.
54860484Sobrien   It is called by the Linux linker emulation before_allocation
54960484Sobrien   routine.  We have finished reading all of the input files, and now
55060484Sobrien   we just scan the hash tables to find out how many additional fixups
55160484Sobrien   are required.  */
55260484Sobrien
553130561Sobrienbfd_boolean
55460484Sobrienbfd_sparclinux_size_dynamic_sections (output_bfd, info)
55560484Sobrien     bfd *output_bfd;
55660484Sobrien     struct bfd_link_info *info;
55760484Sobrien{
55860484Sobrien  struct fixup *f;
55960484Sobrien  asection *s;
56060484Sobrien
56160484Sobrien  if (output_bfd->xvec != &MY(vec))
562130561Sobrien    return TRUE;
56360484Sobrien
56477298Sobrien  /* First find the fixups...  */
56560484Sobrien  linux_link_hash_traverse (linux_hash_table (info),
566130561Sobrien			    linux_tally_symbols,
567130561Sobrien			    (PTR) info);
56860484Sobrien
56960484Sobrien  /* If there are builtin fixups, leave room for a marker.  This is
57060484Sobrien     used by the dynamic linker so that it knows that all that follow
57160484Sobrien     are builtin fixups instead of regular fixups.  */
57260484Sobrien  for (f = linux_hash_table (info)->fixup_list; f != NULL; f = f->next)
57360484Sobrien    {
57460484Sobrien      if (f->builtin)
575130561Sobrien	{
576130561Sobrien	  ++linux_hash_table (info)->fixup_count;
577130561Sobrien	  ++linux_hash_table (info)->local_builtins;
578130561Sobrien	  break;
579130561Sobrien	}
58060484Sobrien    }
58160484Sobrien
58260484Sobrien  if (linux_hash_table (info)->dynobj == NULL)
58360484Sobrien    {
58460484Sobrien      if (linux_hash_table (info)->fixup_count > 0)
585130561Sobrien	abort ();
586130561Sobrien      return TRUE;
58760484Sobrien    }
58860484Sobrien
58960484Sobrien  /* Allocate memory for our fixup table.  We will fill it in later.  */
59060484Sobrien  s = bfd_get_section_by_name (linux_hash_table (info)->dynobj,
591130561Sobrien			       ".linux-dynamic");
59260484Sobrien  if (s != NULL)
59360484Sobrien    {
594218822Sdim      s->size = linux_hash_table (info)->fixup_count + 1;
595218822Sdim      s->size *= 8;
596218822Sdim      s->contents = (bfd_byte *) bfd_zalloc (output_bfd, s->size);
59760484Sobrien      if (s->contents == NULL)
598130561Sobrien	return FALSE;
59960484Sobrien    }
60060484Sobrien
601130561Sobrien  return TRUE;
60260484Sobrien}
60360484Sobrien
60460484Sobrien/* We come here once we are ready to actually write the fixup table to
60560484Sobrien   the output file.  Scan the fixup tables and so forth and generate
60660484Sobrien   the stuff we need.  */
60760484Sobrien
608130561Sobrienstatic bfd_boolean
60960484Sobrienlinux_finish_dynamic_link (output_bfd, info)
61060484Sobrien     bfd *output_bfd;
61160484Sobrien     struct bfd_link_info *info;
61260484Sobrien{
61360484Sobrien  asection *s, *os, *is;
61460484Sobrien  bfd_byte *fixup_table;
61560484Sobrien  struct linux_link_hash_entry *h;
61660484Sobrien  struct fixup *f;
61760484Sobrien  unsigned int new_addr;
61860484Sobrien  int section_offset;
61960484Sobrien  unsigned int fixups_written;
62060484Sobrien
62160484Sobrien  if (linux_hash_table (info)->dynobj == NULL)
622130561Sobrien    return TRUE;
62360484Sobrien
62460484Sobrien  s = bfd_get_section_by_name (linux_hash_table (info)->dynobj,
625130561Sobrien			       ".linux-dynamic");
62660484Sobrien  BFD_ASSERT (s != NULL);
62760484Sobrien  os = s->output_section;
62860484Sobrien  fixups_written = 0;
62960484Sobrien
63060484Sobrien#ifdef LINUX_LINK_DEBUG
63160484Sobrien  printf ("Fixup table file offset: %x  VMA: %x\n",
632130561Sobrien	  os->filepos + s->output_offset,
633130561Sobrien	  os->vma + s->output_offset);
63460484Sobrien#endif
63560484Sobrien
63660484Sobrien  fixup_table = s->contents;
63789857Sobrien  bfd_put_32 (output_bfd,
63889857Sobrien	      (bfd_vma) linux_hash_table (info)->fixup_count, fixup_table);
63960484Sobrien  fixup_table += 4;
64060484Sobrien
64160484Sobrien  /* Fill in fixup table.  */
64260484Sobrien  for (f = linux_hash_table (info)->fixup_list; f != NULL; f = f->next)
64360484Sobrien    {
64460484Sobrien      if (f->builtin)
645130561Sobrien	continue;
64660484Sobrien
64760484Sobrien      if (f->h->root.root.type != bfd_link_hash_defined
648130561Sobrien	  && f->h->root.root.type != bfd_link_hash_defweak)
649130561Sobrien	{
650130561Sobrien	  (*_bfd_error_handler)
651130561Sobrien	    (_("Symbol %s not defined for fixups\n"),
652130561Sobrien	     f->h->root.root.root.string);
653130561Sobrien	  continue;
654130561Sobrien	}
65560484Sobrien
65660484Sobrien      is = f->h->root.root.u.def.section;
65760484Sobrien      section_offset = is->output_section->vma + is->output_offset;
65860484Sobrien      new_addr = f->h->root.root.u.def.value + section_offset;
65960484Sobrien
66060484Sobrien#ifdef LINUX_LINK_DEBUG
66160484Sobrien      printf ("Fixup(%d) %s: %x %x\n",f->jump, f->h->root.root.string,
662130561Sobrien	      new_addr, f->value);
66360484Sobrien#endif
66460484Sobrien
66560484Sobrien      if (f->jump)
666130561Sobrien	{
667130561Sobrien	  /* Relative address */
668130561Sobrien	  new_addr = new_addr - (f->value + 5);
669130561Sobrien	  bfd_put_32 (output_bfd, (bfd_vma) new_addr, fixup_table);
670130561Sobrien	  fixup_table += 4;
671130561Sobrien	  bfd_put_32 (output_bfd, f->value + 1, fixup_table);
672130561Sobrien	  fixup_table += 4;
673130561Sobrien	}
67460484Sobrien      else
675130561Sobrien	{
676130561Sobrien	  bfd_put_32 (output_bfd, (bfd_vma) new_addr, fixup_table);
677130561Sobrien	  fixup_table += 4;
678130561Sobrien	  bfd_put_32 (output_bfd, f->value, fixup_table);
679130561Sobrien	  fixup_table += 4;
680130561Sobrien	}
68160484Sobrien      ++fixups_written;
68260484Sobrien    }
68360484Sobrien
68460484Sobrien  if (linux_hash_table (info)->local_builtins != 0)
68560484Sobrien    {
68660484Sobrien      /* Special marker so we know to switch to the other type of fixup */
68789857Sobrien      bfd_put_32 (output_bfd, (bfd_vma) 0, fixup_table);
68860484Sobrien      fixup_table += 4;
68989857Sobrien      bfd_put_32 (output_bfd, (bfd_vma) 0, fixup_table);
69060484Sobrien      fixup_table += 4;
69160484Sobrien      ++fixups_written;
69260484Sobrien      for (f = linux_hash_table (info)->fixup_list; f != NULL; f = f->next)
693130561Sobrien	{
694130561Sobrien	  if (! f->builtin)
695130561Sobrien	    continue;
69660484Sobrien
697130561Sobrien	  if (f->h->root.root.type != bfd_link_hash_defined
698130561Sobrien	      && f->h->root.root.type != bfd_link_hash_defweak)
699130561Sobrien	    {
700130561Sobrien	      (*_bfd_error_handler)
701130561Sobrien		(_("Symbol %s not defined for fixups\n"),
702130561Sobrien		 f->h->root.root.root.string);
703130561Sobrien	      continue;
704130561Sobrien	    }
70560484Sobrien
706130561Sobrien	  is = f->h->root.root.u.def.section;
707130561Sobrien	  section_offset = is->output_section->vma + is->output_offset;
708130561Sobrien	  new_addr = f->h->root.root.u.def.value + section_offset;
70960484Sobrien
71060484Sobrien#ifdef LINUX_LINK_DEBUG
711130561Sobrien	  printf ("Fixup(B) %s: %x %x\n", f->h->root.root.string,
712130561Sobrien		  new_addr, f->value);
71360484Sobrien#endif
71460484Sobrien
715130561Sobrien	  bfd_put_32 (output_bfd, (bfd_vma) new_addr, fixup_table);
716130561Sobrien	  fixup_table += 4;
717130561Sobrien	  bfd_put_32 (output_bfd, f->value, fixup_table);
718130561Sobrien	  fixup_table += 4;
719130561Sobrien	  ++fixups_written;
720130561Sobrien	}
721130561Sobrien    }
72260484Sobrien
72360484Sobrien  if (linux_hash_table (info)->fixup_count != fixups_written)
72460484Sobrien    {
72560484Sobrien      (*_bfd_error_handler) (_("Warning: fixup count mismatch\n"));
72660484Sobrien      while (linux_hash_table (info)->fixup_count > fixups_written)
727130561Sobrien	{
728130561Sobrien	  bfd_put_32 (output_bfd, (bfd_vma) 0, fixup_table);
729130561Sobrien	  fixup_table += 4;
730130561Sobrien	  bfd_put_32 (output_bfd, (bfd_vma) 0, fixup_table);
731130561Sobrien	  fixup_table += 4;
732130561Sobrien	  ++fixups_written;
733130561Sobrien	}
73460484Sobrien    }
73560484Sobrien
73660484Sobrien  h = linux_link_hash_lookup (linux_hash_table (info),
737130561Sobrien			      "__BUILTIN_FIXUPS__",
738130561Sobrien			      FALSE, FALSE, FALSE);
73960484Sobrien
74060484Sobrien  if (h != NULL
74160484Sobrien      && (h->root.root.type == bfd_link_hash_defined
742130561Sobrien	  || h->root.root.type == bfd_link_hash_defweak))
74360484Sobrien    {
74460484Sobrien      is = h->root.root.u.def.section;
74560484Sobrien      section_offset = is->output_section->vma + is->output_offset;
74660484Sobrien      new_addr = h->root.root.u.def.value + section_offset;
74760484Sobrien
74860484Sobrien#ifdef LINUX_LINK_DEBUG
74960484Sobrien      printf ("Builtin fixup table at %x\n", new_addr);
75060484Sobrien#endif
75160484Sobrien
75289857Sobrien      bfd_put_32 (output_bfd, (bfd_vma) new_addr, fixup_table);
75360484Sobrien    }
75460484Sobrien  else
75589857Sobrien    bfd_put_32 (output_bfd, (bfd_vma) 0, fixup_table);
75660484Sobrien
75789857Sobrien  if (bfd_seek (output_bfd, (file_ptr) (os->filepos + s->output_offset),
75889857Sobrien		SEEK_SET) != 0)
759130561Sobrien    return FALSE;
76060484Sobrien
761218822Sdim  if (bfd_bwrite ((PTR) s->contents, s->size, output_bfd) != s->size)
762130561Sobrien    return FALSE;
76360484Sobrien
764130561Sobrien  return TRUE;
76560484Sobrien}
76660484Sobrien
76760484Sobrien#define MY_bfd_link_hash_table_create linux_link_hash_table_create
76860484Sobrien#define MY_add_one_symbol linux_add_one_symbol
76960484Sobrien#define MY_finish_dynamic_link linux_finish_dynamic_link
77060484Sobrien
77160484Sobrien#define MY_zmagic_contiguous 1
77260484Sobrien
77360484Sobrien#include "aout-target.h"
774