This is the mail archive of the binutils@sourceware.cygnus.com mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

[PATCH] My current SPARC patches


On Thu, Jul 08, 1999 at 03:50:13PM -0700, Richard Henderson wrote:
> On Mon, Jul 05, 1999 at 05:47:29PM +0200, Jakub Jelinek wrote:
> > This patch adds support for R_SPARC_OLO10 relocation.
> 
> I'm getting errors compiling this code.
> 
> gcc -DHAVE_CONFIG_H -I. -I../../../binutils/bfd -I. -D_GNU_SOURCE -I. -I../../..
> /binutils/bfd -I../../../binutils/bfd/../include -I../../../binutils/bfd/../intl
>  -I../intl -g -O2 -c ../../../binutils/bfd/elf64-sparc.c -o elf64-sparc.o
> .../elf64-sparc.c:2636: warning: initialization makes integer from pointer without a cast
> .../elf64-sparc.c:2636: initializer element is not computable at load time

That's because of the mips64 changes which went in two days ago after I
submited my patch. Below are all my current patches against current cvs
with the exception of the emulparams/elf64_sparc.sh.
> 
> These bits I went ahead and put in.

Thanks.

elf64-sparc.c was not compiling because it used DT_SPARC_PLTFMT, which is
now removed. This is the Diff-pltfmt patch.
ELF64_R_TYPE_DATA is always used on the whole r_info, so the macro has to
mask out ELF64_R_TYPE bits. This is the second patch,
Diff-elf64-r-type-data.
Then there is a c-sparc.texi update and then STT_REGISTER and R_SPARC_OLO10
patches.

Cheers,
    Jakub
___________________________________________________________________
Jakub Jelinek | jj@sunsite.mff.cuni.cz | http://sunsite.mff.cuni.cz
Administrator of SunSITE Czech Republic, MFF, Charles University
___________________________________________________________________
UltraLinux  |  http://ultra.linux.cz/  |  http://ultra.penguin.cz/
Linux version 2.2.10 on a sparc64 machine (1343.49 BogoMips)
___________________________________________________________________
1999-07-09  Jakub Jelinek  <jj@ultra.linux.cz>

	* bfd/elf64-sparc.c (sparc64_elf_size_dynamic_sections): Remove
	DT_SPARC_PLTFMT.

--- bfd/elf64-sparc.c.jj3	Fri Jul  9 13:36:00 1999
+++ bfd/elf64-sparc.c	Fri Jul  9 13:48:07 1999
@@ -1762,9 +1762,7 @@ sparc64_elf_size_dynamic_sections (outpu
 	  if (! bfd_elf64_add_dynamic_entry (info, DT_PLTGOT, 0)
 	      || ! bfd_elf64_add_dynamic_entry (info, DT_PLTRELSZ, 0)
 	      || ! bfd_elf64_add_dynamic_entry (info, DT_PLTREL, DT_RELA)
-	      || ! bfd_elf64_add_dynamic_entry (info, DT_JMPREL, 0)
-	      || ! bfd_elf64_add_dynamic_entry (info, DT_SPARC_PLTFMT,
-						(info->shared != 0) + 1))
+	      || ! bfd_elf64_add_dynamic_entry (info, DT_JMPREL, 0))
 	    return false;
 	}
 
1999-07-09  Jakub Jelinek  <jj@ultra.linux.cz>

	* sparc.h (ELF64_R_TYPE_DATA): Only use ELF64_R_TYPE bits, not
	ELF64_R_SYM bits.

--- include/elf/sparc.h.jj	Fri Jul  9 12:23:51 1999
+++ include/elf/sparc.h	Fri Jul  9 14:16:50 1999
@@ -139,7 +139,7 @@ END_RELOC_NUMBERS
 /* Relocation macros.  */
 
 #define ELF64_R_TYPE_DATA(info) \
-  (((bfd_signed_vma)((info) >> 8) ^ 0x800000) - 0x800000)
+  (((bfd_signed_vma)(ELF64_R_TYPE(info) >> 8) ^ 0x800000) - 0x800000)
 #define ELF64_R_TYPE_ID(info) \
   ((info) & 0xff)
 #define ELF64_R_TYPE_INFO(data, type) \
1999-07-09  Jakub Jelinek  <jj@ultra.linux.cz>

	* gas/doc/c-sparc.texi: Document .register and .nword pseudo-ops.

--- ./gas/doc/c-sparc.texi.jj4	Mon May  3 09:28:45 1999
+++ ./gas/doc/c-sparc.texi	Sat Jul  3 18:38:25 1999
@@ -145,11 +145,24 @@ syntax is different.
 @item .half
 This is functionally identical to @code{.short}.
 
+@cindex @code{nword} directive, SPARC
+@item .nword
+On the Sparc, the @code{.nword} directive produces native word sized value,
+ie. if assembling with -32 it is equivalent to @code{.word}, if assembling
+with -64 it is equivalent to @code{.xword}.
+
 @cindex @code{proc} directive, SPARC
 @item .proc
 This directive is ignored.  Any text following it on the same
 line is also ignored.
 
+@cindex @code{register} directive, SPARC
+@item .register
+This directive declares use of a global application or system register.
+It must be followed by a register name %g2, %g3, %g6 or %g7, comma and
+the symbol name for that register or @code{#scratch} if it is a scratch
+register.
+
 @cindex @code{reserve} directive, SPARC
 @item .reserve
 This must be followed by a symbol name, a positive number, and
@@ -176,4 +189,3 @@ instead of the 16 bit values it produces
 On the Sparc V9 processor, the @code{.xword} directive produces
 64 bit values.
 @end table
-
1999-07-09  Jakub Jelinek  <jj@ultra.linux.cz>

	* bfd/elf-bfd.h (struct elf_backend_data): Add
	print_symbol_all and output_arch_syms backend methods.
	* bfd/elfxx-target.h: Likewise.
	* bfd/elf64-sparc.c (sparc64_elf_bfd_link_hash_table_create,
	sparc64_elf_add_symbol_hook, sparc64_elf_output_arch_syms,
	sparc64_elf_get_symbol_type, sparc64_elf_symbol_processing): New
	functions.
	(sparc64_elf_size_dynamic_sections): Leave space for STT_REGISTER
	symbols in .dynsym, add their names into .dynstr. Use generic
	_bfd_elf_link_adjust_dynindx instead of sparc64_elf_adjust_dynindx).
	(sparc64_elf_adjust_dynindx): Remove.
	(sparc64_elf_finish_dynamic_sections): Output STT_REGISTER symbols
	into .dynsym, fix up DT_SPARC_REGISTER pointers to them.
	(sparc64_elf_print_symbol_all): New function.
	* bfd/elf.c (bfd_elf_print_symbol): Allow special backend symbol
	printing using the print_symbol_all hook.
	* bfd/elflink.h (elf_bfd_final_link): Allow backend to emit some
	global symbols which don't live in the symbol hash table.
	* gas/config/tc-sparc.c (md_longopts): Add --no-undeclared-regs
	option.
	(sparc_ip): Warn if %g2 or %g3 register is used and not covered
	by .register pseudo-op if -64 and --no-undeclared-regs.
	(s_register, sparc_adjust_symtab): New functions.
	* gas/config/tc-sparc.h (tc_adjust_symtab, sparc_adjust_symtab):
	Declare sparc_adjust_symtab as tc_adjust_symtab.

--- ./bfd/elf-bfd.h.jj2	Fri Jul  9 12:17:32 1999
+++ ./bfd/elf-bfd.h	Fri Jul  9 13:36:00 1999
@@ -550,6 +550,21 @@ struct elf_backend_data
   void (*elf_backend_post_process_headers)
     PARAMS ((bfd *, struct bfd_link_info *));
 
+  /* This function, if defined, prints a symbol to file and returns the
+     name of the symbol to be printed.  It should return NULL to fall
+     back to default symbol printing.  */
+  const char *(*elf_backend_print_symbol_all)
+    PARAMS ((bfd *, PTR, asymbol *));
+
+  /* This function, if defined, is called after all local symbols and
+     global symbols converted to locals are emited into the symtab
+     section.  It allows the backend to emit special global symbols
+     not handled in the hash table.  */
+  boolean (*elf_backend_output_arch_syms)
+    PARAMS ((struct bfd_link_info *, PTR,
+	    boolean (*) PARAMS ((PTR, const char *,
+             Elf_Internal_Sym *, asection *))));
+
   /* The swapping table to use when dealing with ECOFF information.
      Used for the MIPS ELF .mdebug section.  */
   const struct ecoff_debug_swap *elf_backend_ecoff_debug_swap;
--- ./bfd/elf64-sparc.c.jj2	Fri Jul  9 13:27:07 1999
+++ ./bfd/elf64-sparc.c	Fri Jul  9 13:36:00 1999
@@ -32,6 +32,8 @@ Foundation, Inc., 59 Temple Place - Suit
 /* In case we're on a 32-bit machine, construct a 64-bit "-1" value.  */
 #define MINUS_ONE (~ (bfd_vma) 0)
 
+static struct bfd_link_hash_table * sparc64_elf_bfd_link_hash_table_create
+  PARAMS((bfd *));
 static reloc_howto_type *sparc64_elf_reloc_type_lookup
   PARAMS ((bfd *, bfd_reloc_code_real_type));
 static void sparc64_elf_info_to_howto
@@ -51,8 +53,13 @@ static boolean sparc64_elf_adjust_dynami
   PARAMS((struct bfd_link_info *, struct elf_link_hash_entry *));
 static boolean sparc64_elf_size_dynamic_sections
   PARAMS((bfd *, struct bfd_link_info *));
-static boolean sparc64_elf_adjust_dynindx
-  PARAMS((struct elf_link_hash_entry *, PTR));
+static int sparc64_elf_get_symbol_type
+  PARAMS (( Elf_Internal_Sym *, int));
+static boolean sparc64_elf_add_symbol_hook
+  PARAMS ((bfd *, struct bfd_link_info *, const Elf_Internal_Sym *,
+	  const char **, flagword *, asection **, bfd_vma *));
+static void sparc64_elf_symbol_processing
+  PARAMS ((bfd *, asymbol *));
 
 static boolean sparc64_elf_merge_private_bfd_data
   PARAMS ((bfd *, bfd *));
@@ -598,6 +605,54 @@ sparc64_elf_write_relocs (abfd, sec, dat
     }
 }
 
+/* Sparc64 ELF linker hash table.  */
+
+struct sparc64_elf_app_reg
+{
+  unsigned char bind;
+  unsigned short shndx;
+  bfd_size_type dynstr_index;
+  bfd *abfd;
+  char *name;
+};
+
+struct sparc64_elf_link_hash_table
+{
+  struct elf_link_hash_table root;
+
+  struct sparc64_elf_app_reg app_regs [4];
+  int dynindx_reg_base;
+};
+
+/* Get the Sparc64 ELF linker hash table from a link_info structure.  */
+
+#define sparc64_elf_hash_table(p) \
+  ((struct sparc64_elf_link_hash_table *) ((p)->hash))
+  
+/* Create a Sparc64 ELF linker hash table.  */
+
+static struct bfd_link_hash_table *
+sparc64_elf_bfd_link_hash_table_create (abfd)
+     bfd *abfd;
+{
+  struct sparc64_elf_link_hash_table *ret;
+
+  ret = ((struct sparc64_elf_link_hash_table *)
+	 bfd_zalloc (abfd, sizeof (struct sparc64_elf_link_hash_table)));
+  if (ret == (struct sparc64_elf_link_hash_table *) NULL)
+    return NULL;
+
+  if (! _bfd_elf_link_hash_table_init (&ret->root, abfd,
+				       _bfd_elf_link_hash_newfunc))
+    {
+      bfd_release (abfd, ret);
+      return NULL;
+    }
+
+  return &ret->root.root;
+}
+
+
 /* Utility for performing the standard initial work of an instruction
    relocation.
    *PRELOCATION will contain the relocated item.
@@ -1198,6 +1253,202 @@ sparc64_elf_check_relocs (abfd, info, se
   return true;
 }
 
+/* Hook called by the linker routine which adds symbols from an object
+   file.  We use it for STT_REGISTER symbols.  */
+
+static boolean
+sparc64_elf_add_symbol_hook (abfd, info, sym, namep, flagsp, secp, valp)
+     bfd *abfd;
+     struct bfd_link_info *info;
+     const Elf_Internal_Sym *sym;
+     const char **namep;
+     flagword *flagsp;
+     asection **secp;
+     bfd_vma *valp;
+{
+  static char *stt_types[] = { "NOTYPE", "OBJECT", "FUNCTION" };
+
+  if (ELF_ST_TYPE (sym->st_info) == STT_REGISTER)
+    {
+      int reg;
+      struct sparc64_elf_app_reg *p;
+      
+      reg = (int)sym->st_value;
+      switch (reg & ~1)
+	{
+	case 2: reg -= 2; break;
+	case 6: reg -= 4; break;
+	default:
+          (*_bfd_error_handler)
+            (_("%s: Only registers %%g[2367] can be declared using STT_REGISTER"),
+             bfd_get_filename (abfd));
+	  return false;
+	}
+
+      if (info->hash->creator != abfd->xvec
+	  || (abfd->flags & DYNAMIC) != 0)
+        {
+	  /* STT_REGISTER only works when linking an elf64_sparc object.
+	     If STT_REGISTER comes from a dynamic object, don't put it into
+	     the output bfd.  The dynamic linker will recheck it.  */
+	  *namep = NULL;
+	  return true;
+        }
+
+      p = sparc64_elf_hash_table(info)->app_regs + reg;
+
+      if (p->name != NULL && strcmp (p->name, *namep))
+	{
+          (*_bfd_error_handler)
+            (_("Register %%g%d used incompatibly: "
+               "previously declared in %s to %s, in %s redefined to %s"),
+             (int)sym->st_value,
+             bfd_get_filename (p->abfd), *p->name ? p->name : "#scratch",
+             bfd_get_filename (abfd), **namep ? *namep : "#scratch");
+	  return false;
+	}
+
+      if (p->name == NULL)
+	{
+	  if (**namep)
+	    {
+	      struct elf_link_hash_entry *h;
+	      
+	      h = (struct elf_link_hash_entry *)
+		bfd_link_hash_lookup (info->hash, *namep, false, false, false);
+
+	      if (h != NULL)
+		{
+		  unsigned char type = h->type;
+
+		  if (type > STT_FUNC) type = 0;
+		  (*_bfd_error_handler)
+		    (_("Symbol `%s' has differing types: "
+		       "previously %s, REGISTER in %s"),
+		     *namep, stt_types [type], bfd_get_filename (abfd));
+		  return false;
+		}
+
+	      p->name = bfd_hash_allocate (&info->hash->table,
+					   strlen (*namep) + 1);
+	      if (!p->name)
+		return false;
+
+	      strcpy (p->name, *namep);
+	    }
+	  else
+	    p->name = "";
+	  p->bind = ELF_ST_BIND (sym->st_info);
+	  p->abfd = abfd;
+	  p->shndx = sym->st_shndx;
+	}
+      else
+	{
+	  if (p->bind == STB_WEAK
+	      && ELF_ST_BIND (sym->st_info) == STB_GLOBAL)
+	    {
+	      p->bind = STB_GLOBAL;
+	      p->abfd = abfd;
+	    }
+	}
+      *namep = NULL;
+      return true;
+    }
+  else if (! *namep || ! **namep)
+    return true;
+  else
+    {
+      int i;
+      struct sparc64_elf_app_reg *p;
+
+      p = sparc64_elf_hash_table(info)->app_regs;
+      for (i = 0; i < 4; i++, p++)
+	if (p->name != NULL && ! strcmp (p->name, *namep))
+	  {
+	    unsigned char type = ELF_ST_TYPE (sym->st_info);
+
+	    if (type > STT_FUNC) type = 0;
+	    (*_bfd_error_handler)
+	      (_("Symbol `%s' has differing types: "
+		 "REGISTER in %s, %s in %s"),
+	       *namep, bfd_get_filename (p->abfd), stt_types [type],
+	       bfd_get_filename (abfd));
+	    return false;
+	  }
+    }
+  return true;
+}
+
+/* This function takes care of emmiting STT_REGISTER symbols
+   which we cannot easily keep in the symbol hash table.  */
+
+static boolean
+sparc64_elf_output_arch_syms (info, finfo, func)
+     struct bfd_link_info *info;
+     PTR finfo;
+     boolean (*func) PARAMS ((PTR, const char *,
+			      Elf_Internal_Sym *, asection *));
+{
+  int reg;
+  struct sparc64_elf_app_reg *app_regs =
+    sparc64_elf_hash_table(info)->app_regs;
+  Elf_Internal_Sym sym;
+
+  if (info->strip == strip_all)
+    return true;
+
+  for (reg = 0; reg < 4; reg++)
+    if (app_regs [reg].name != NULL)
+      {
+	if (info->strip == strip_some
+	    && bfd_hash_lookup (info->keep_hash,
+				app_regs [reg].name,
+				false, false) == NULL)
+	  continue;
+
+	sym.st_value = reg < 2 ? reg + 2 : reg + 4;
+	sym.st_size = 0;
+	sym.st_other = 0;
+	sym.st_info = ELF_ST_INFO (app_regs [reg].bind, STT_REGISTER);
+	sym.st_shndx = app_regs [reg].shndx;
+	if (! (*func) (finfo, app_regs [reg].name, &sym,
+		       sym.st_shndx == SHN_ABS
+			 ? bfd_abs_section_ptr : bfd_und_section_ptr))
+	  return false;
+      }
+
+  return true;
+}
+
+static int
+sparc64_elf_get_symbol_type (elf_sym, type)
+     Elf_Internal_Sym * elf_sym;
+     int type;
+{
+  if (ELF_ST_TYPE (elf_sym->st_info) == STT_REGISTER)
+    return STT_REGISTER;
+  else
+    return type;
+}
+
+/* A STB_GLOBAL,STT_REGISTER symbol should be BSF_GLOBAL
+   even in SHN_UNDEF section.  */
+
+static void
+sparc64_elf_symbol_processing (abfd, asym)
+     bfd *abfd;
+     asymbol *asym;
+{
+  elf_symbol_type *elfsym;
+
+  elfsym = (elf_symbol_type *) asym;
+  if (elfsym->internal_elf_sym.st_info
+      == ELF_ST_INFO (STB_GLOBAL, STT_REGISTER))
+    {
+      asym->flags |= BSF_GLOBAL;
+    }
+}
+
 /* Adjust a symbol defined by a dynamic object and referenced by a
    regular object.  The current definition is in some section of the
    dynamic object, but we're not including those sections.  We have to
@@ -1497,6 +1748,9 @@ sparc64_elf_size_dynamic_sections (outpu
 	 must add the entries now so that we get the correct size for
 	 the .dynamic section.  The DT_DEBUG entry is filled in by the
 	 dynamic linker and used by the debugger.  */
+      int i, c;
+      struct sparc64_elf_app_reg * app_regs;
+
       if (! info->shared)
 	{
 	  if (! bfd_elf64_add_dynamic_entry (info, DT_DEBUG, 0))
@@ -1525,6 +1779,44 @@ sparc64_elf_size_dynamic_sections (outpu
 	  if (! bfd_elf64_add_dynamic_entry (info, DT_TEXTREL, 0))
 	    return false;
 	}
+
+      /* Add dynamic STT_REGISTER symbols and corresponding DT_SPARC_REGISTER
+	 entries if needed.  */
+      app_regs = sparc64_elf_hash_table (info)->app_regs;
+      c = 0;
+      for (i = 0; i < 4; i++)
+	if (app_regs [i].name != NULL)
+	  {
+	    if (! bfd_elf64_add_dynamic_entry (info, DT_SPARC_REGISTER, 0))
+	      return false;
+	    c++;
+	  }
+
+      if (c)
+	{
+	  struct bfd_strtab_hash *dynstr;
+
+	  dynstr = elf_hash_table (info)->dynstr;
+	  BFD_ASSERT (dynstr != NULL);
+
+	  elf_link_hash_traverse (elf_hash_table (info),
+				  _bfd_elf_link_adjust_dynindx,
+				  (PTR) &c);
+	  elf_hash_table (info)->dynsymcount += c;
+
+	  for (i = 0; i < 4; i++)
+	    if (app_regs [i].name != NULL
+		&& *app_regs [i].name != '\0')
+	      {
+		app_regs [i].dynstr_index =
+		  _bfd_stringtab_add (dynstr, app_regs [i].name, true, false);
+		if (app_regs [i].dynstr_index == (bfd_size_type) -1)
+		  return false;
+	      }
+
+	  /* The first symbol in .dynsym is a dummy.  */
+	  sparc64_elf_hash_table (info)->dynindx_reg_base = 1;
+	}
     }
 
   /* If we are generating a shared library, we generate a section
@@ -1552,29 +1844,15 @@ sparc64_elf_size_dynamic_sections (outpu
 	}
 
       elf_link_hash_traverse (elf_hash_table (info),
-			      sparc64_elf_adjust_dynindx,
+			      _bfd_elf_link_adjust_dynindx,
 			      (PTR) &c);
       elf_hash_table (info)->dynsymcount += c;
+      sparc64_elf_hash_table (info)->dynindx_reg_base += c;
     }
 
   return true;
 }
 
-/* Increment the index of a dynamic symbol by a given amount.  Called
-   via elf_link_hash_traverse.  */
-
-static boolean
-sparc64_elf_adjust_dynindx (h, cparg)
-     struct elf_link_hash_entry *h;
-     PTR cparg;
-{
-  int *cp = (int *) cparg;
-
-  if (h->dynindx != -1)
-    h->dynindx += *cp;
-  return true;
-}
-
 
 /* Relocate a SPARC64 ELF section.  */
 
@@ -2398,6 +2676,7 @@ sparc64_elf_finish_dynamic_sections (out
   bfd *dynobj;
   asection *sdyn;
   asection *sgot;
+  Elf64_External_Dyn *dt_register_dyn = NULL;
 
   dynobj = elf_hash_table (info)->dynobj;
 
@@ -2426,6 +2705,10 @@ sparc64_elf_finish_dynamic_sections (out
 	    case DT_PLTGOT:   name = ".plt"; size = false; break;
 	    case DT_PLTRELSZ: name = ".rela.plt"; size = true; break;
 	    case DT_JMPREL:   name = ".rela.plt"; size = false; break;
+	    case DT_SPARC_REGISTER:
+			      if (dt_register_dyn == NULL)
+				dt_register_dyn = dyncon;
+			      /* fallthrough */
 	    default:	      name = NULL; size = false; break;
 	    }
 
@@ -2523,6 +2806,53 @@ sparc64_elf_finish_dynamic_sections (out
       elf_section_data (sdynsym->output_section)->this_hdr.sh_info = c + 1;
     }
 
+  if (elf_hash_table (info)->dynamic_sections_created)
+    {
+      int reg;
+      struct sparc64_elf_app_reg *app_regs =
+	sparc64_elf_hash_table(info)->app_regs;
+      asection *sdynsym;
+      Elf_Internal_Sym sym;
+      Elf_Internal_Dyn dyn;
+      int c = sparc64_elf_hash_table (info)->dynindx_reg_base;
+
+      /* Set up the STT_REGISTER dynamic symbols.  */
+
+      sdynsym = bfd_get_section_by_name (dynobj, ".dynsym");
+      BFD_ASSERT (sdynsym != NULL);
+
+      sym.st_size = 0;
+      sym.st_other = 0;
+
+      for (reg = 0; reg < 4; reg++)
+	if (app_regs [reg].name != NULL)
+	  {
+	    sym.st_value = reg < 2 ? reg + 2 : reg + 4;
+	    sym.st_size = 0;
+	    sym.st_name = app_regs [reg].dynstr_index;
+	    sym.st_other = 0;
+	    sym.st_info = ELF_ST_INFO (app_regs [reg].bind, STT_REGISTER);
+	    sym.st_shndx = app_regs [reg].shndx;
+	    bfd_elf64_swap_symbol_out (output_bfd, &sym,
+				       (PTR) (((Elf64_External_Sym *)
+					       sdynsym->contents)
+					      + c));
+	    if (dt_register_dyn == NULL)
+	      return false;
+
+	    bfd_elf64_swap_dyn_in (dynobj, dt_register_dyn, &dyn);
+
+	    if (dyn.d_tag != DT_SPARC_REGISTER)
+	      return false;
+	    
+	    dyn.d_un.d_val = c;
+	    bfd_elf64_swap_dyn_out (output_bfd, &dyn, dt_register_dyn);
+
+	    ++dt_register_dyn;
+	    ++c;
+	  }
+    }
+
   return true;
 }
 
@@ -2599,7 +2929,34 @@ sparc64_elf_merge_private_bfd_data (ibfd
     }
   return true;
 }
+
+/* Print a STT_REGISTER symbol to file FILE.  */
 
+static const char *
+sparc64_elf_print_symbol_all (abfd, filep, symbol)
+     bfd *abfd;
+     PTR filep;
+     asymbol *symbol;
+{
+  FILE *file = (FILE *) filep;
+  int reg, type;
+  
+  if (ELF_ST_TYPE (((elf_symbol_type *) symbol)->internal_elf_sym.st_info)
+      != STT_REGISTER)
+    return NULL;
+
+  reg = ((elf_symbol_type *) symbol)->internal_elf_sym.st_value;
+  type = symbol->flags;
+  fprintf (file, "REG_%c%c%11s%c%c    R", "GOLI" [reg / 8], '0' + (reg & 7), "",
+		 ((type & BSF_LOCAL)
+		  ? (type & BSF_GLOBAL) ? '!' : 'l'
+  	          : (type & BSF_GLOBAL) ? 'g' : ' '),
+  	         (type & BSF_WEAK) ? 'w' : ' ');
+  if (symbol->name == NULL || symbol->name [0] == '\0')
+    return "#scratch";
+  else
+    return symbol->name;
+}
 
 /* Set the right machine number for a SPARC64 ELF file.  */
 
@@ -2664,6 +3021,9 @@ const struct elf_size_info sparc64_elf_s
 /* This is the value that we used before the ABI was released.  */
 #define ELF_MACHINE_ALT1 EM_OLD_SPARCV9
 
+#define bfd_elf64_bfd_link_hash_table_create \
+  sparc64_elf_bfd_link_hash_table_create
+  
 #define elf_info_to_howto \
   sparc64_elf_info_to_howto
 #define bfd_elf64_get_reloc_upper_bound \
@@ -2677,6 +3037,12 @@ const struct elf_size_info sparc64_elf_s
 
 #define elf_backend_create_dynamic_sections \
   _bfd_elf_create_dynamic_sections
+#define elf_backend_add_symbol_hook \
+  sparc64_elf_add_symbol_hook
+#define elf_backend_get_symbol_type \
+  sparc64_elf_get_symbol_type
+#define elf_backend_symbol_processing \
+  sparc64_elf_symbol_processing
 #define elf_backend_check_relocs \
   sparc64_elf_check_relocs
 #define elf_backend_adjust_dynamic_symbol \
@@ -2689,6 +3055,10 @@ const struct elf_size_info sparc64_elf_s
   sparc64_elf_finish_dynamic_symbol
 #define elf_backend_finish_dynamic_sections \
   sparc64_elf_finish_dynamic_sections
+#define elf_backend_print_symbol_all \
+  sparc64_elf_print_symbol_all
+#define elf_backend_output_arch_syms \
+  sparc64_elf_output_arch_syms
 
 #define bfd_elf64_bfd_merge_private_bfd_data \
   sparc64_elf_merge_private_bfd_data
--- ./bfd/elf.c.jj2	Fri Jul  9 12:20:45 1999
+++ ./bfd/elf.c	Fri Jul  9 13:36:00 1999
@@ -756,8 +756,21 @@ bfd_elf_print_symbol (abfd, filep, symbo
     case bfd_print_symbol_all:
       {
 	CONST char *section_name;
+	CONST char *name = NULL;
+	struct elf_backend_data *bed;
+	
 	section_name = symbol->section ? symbol->section->name : "(*none*)";
-	bfd_print_symbol_vandf ((PTR) file, symbol);
+
+	bed = get_elf_backend_data (abfd);
+	if (bed->elf_backend_print_symbol_all)
+	    name = (*bed->elf_backend_print_symbol_all) (abfd, filep, symbol);
+
+	if (name == NULL)
+	  {
+	    name = symbol->name;  
+	    bfd_print_symbol_vandf ((PTR) file, symbol);
+	  }
+
 	fprintf (file, " %s\t", section_name);
 	/* Print the "other" value for a symbol.  For common symbols,
 	   we've already printed the size; now print the alignment.
@@ -825,7 +838,7 @@ bfd_elf_print_symbol (abfd, filep, symbo
 		   ((unsigned int)
 		    ((elf_symbol_type *) symbol)->internal_elf_sym.st_other));
 
-	fprintf (file, " %s", symbol->name);
+	fprintf (file, " %s", name);
       }
       break;
     }
--- ./bfd/elflink.h.jj2	Fri Jul  9 12:19:20 1999
+++ ./bfd/elflink.h	Fri Jul  9 13:36:00 1999
@@ -4177,6 +4177,18 @@ elf_bfd_final_link (abfd, info)
   if (eoinfo.failed)
     return false;
 
+  /* If backend needs to output some symbols not present in the hash
+     table, do it now.  */
+  if (bed->elf_backend_output_arch_syms)
+    {
+      if (! (*bed->elf_backend_output_arch_syms)
+	      (info, (PTR) &finfo,
+	       (boolean (*) PARAMS ((PTR, const char *,
+	                    Elf_Internal_Sym *, asection *)))
+	       elf_link_output_sym))
+	return false;
+    }      
+
   /* Flush all symbols to the file.  */
   if (! elf_link_flush_output_syms (&finfo))
     return false;
--- ./bfd/elfxx-target.h.jj2	Fri Jul  9 12:19:22 1999
+++ ./bfd/elfxx-target.h	Fri Jul  9 13:36:00 1999
@@ -294,6 +294,12 @@ Foundation, Inc., 59 Temple Place - Suit
 #ifndef elf_backend_post_process_headers
 #define elf_backend_post_process_headers	NULL
 #endif
+#ifndef elf_backend_print_symbol_all
+#define elf_backend_print_symbol_all		NULL
+#endif
+#ifndef elf_backend_output_arch_syms
+#define elf_backend_output_arch_syms		NULL
+#endif
 
 /* Previously, backends could only use SHT_REL or SHT_RELA relocation
    sections, but not both.  They defined USE_REL to indicate SHT_REL
@@ -366,6 +372,8 @@ static CONST struct elf_backend_data elf
   elf_backend_gc_mark_hook,
   elf_backend_gc_sweep_hook,
   elf_backend_post_process_headers,
+  elf_backend_print_symbol_all,
+  elf_backend_output_arch_syms,
   elf_backend_ecoff_debug_swap,
   ELF_MACHINE_ALT1,
   ELF_MACHINE_ALT2,
--- ./gas/config/tc-sparc.c.jj4	Wed Jul  7 09:41:46 1999
+++ ./gas/config/tc-sparc.c	Wed Jul  7 13:36:13 1999
@@ -87,6 +87,10 @@ static int warn_on_bump;
    architecture, issue a warning.  */
 static enum sparc_opcode_arch_val warn_after_architecture;
 
+/* Non-zero if as should generate error if an undeclared g[23] register
+   has been used in -64.  */
+static int no_undeclared_regs;
+
 /* Non-zero if we are generating PIC code.  */
 int sparc_pic_code;
 
@@ -97,6 +101,9 @@ extern int target_big_endian;
 
 static int target_little_endian_data;
 
+/* Symbols for global registers on v9.  */
+static symbolS *globals[8];
+
 /* V9 and 86x have big and little endian data, but instructions are always big
    endian.  The sparclet has bi-endian support but both data and insns have
    the same endianness.  Global `target_big_endian' is used for data.
@@ -119,6 +126,7 @@ static void s_common PARAMS ((int));
 static void s_empty PARAMS ((int));
 static void s_uacons PARAMS ((int));
 static void s_ncons PARAMS ((int));
+static void s_register PARAMS ((int));
 
 const pseudo_typeS md_pseudo_table[] =
 {
@@ -143,6 +151,7 @@ const pseudo_typeS md_pseudo_table[] =
   {"2byte", s_uacons, 2},
   {"4byte", s_uacons, 4},
   {"8byte", s_uacons, 8},
+  {"register", s_register, 0},
 #endif
   {NULL, 0, 0},
 };
@@ -400,6 +409,10 @@ struct option md_longopts[] = {
   {"enforce-aligned-data", no_argument, NULL, OPTION_ENFORCE_ALIGNED_DATA},
 #define OPTION_LITTLE_ENDIAN_DATA (OPTION_MD_BASE + 11)
   {"little-endian-data", no_argument, NULL, OPTION_LITTLE_ENDIAN_DATA},
+#ifdef OBJ_ELF
+#define OPTION_NO_UNDECLARED_REGS (OPTION_MD_BASE + 12)
+  {"no-undeclared-regs", no_argument, NULL, OPTION_NO_UNDECLARED_REGS},
+#endif
   {NULL, no_argument, NULL, 0}
 };
 size_t md_longopts_size = sizeof(md_longopts);
@@ -549,6 +562,10 @@ md_parse_option (c, arg)
       else
 	sparc_pic_code = 1;
       break;
+
+    case OPTION_NO_UNDECLARED_REGS:
+      no_undeclared_regs = 1;
+      break;
 #endif
 
     default:
@@ -1865,6 +1882,11 @@ sparc_ip (str, pinsn)
 		      goto error;
 		    }
 
+		  if ((mask & ~1) == 2 && sparc_arch_size == 64
+		      && no_undeclared_regs && ! globals [mask])
+		    as_bad (_("detected global register use not "
+			      "covered by .register pseudo-op"));
+
 		  /* Got the register, now figure out where
 		     it goes in the opcode.  */
 		  switch (*args)
@@ -3706,6 +3728,112 @@ s_ncons (bytes)
 {
   cons (sparc_arch_size == 32 ? 4 : 8);
 }
+
+#ifdef OBJ_ELF
+/* Handle the SPARC ELF .register pseudo-op.  This sets the binding of a
+   global register.
+   The syntax is:
+   
+   .register %g[2367],{#scratch|symbolname}
+   */
+
+static void
+s_register (ignore)
+     int ignore;
+{
+  char c;
+  int reg;
+  int flags;
+  const char *regname;
+
+  if (input_line_pointer[0] != '%'
+      || input_line_pointer[1] != 'g'
+      || ((input_line_pointer[2] & ~1) != '2'
+	  && (input_line_pointer[2] & ~1) != '6')
+      || input_line_pointer[3] != ',')
+    as_bad (_("register syntax is .register %%g[2367],{#scratch|symbolname}"));
+  reg = input_line_pointer[2] - '0';
+  input_line_pointer += 4;
+
+  if (*input_line_pointer == '#')
+    {
+      ++input_line_pointer;
+      regname = input_line_pointer;
+      c = get_symbol_end ();
+      if (strcmp (regname, "scratch"))
+	as_bad (_("register syntax is .register %%g[2367],{#scratch|symbolname}"));
+      regname = "";
+    }
+  else
+    {
+      regname = input_line_pointer;
+      c = get_symbol_end ();
+    }
+  if (sparc_arch_size == 64)
+    {
+      if (globals [reg])
+	{
+	  if (strcmp (S_GET_NAME (globals [reg]), regname))
+	    as_bad (_("redefinition of global register"));
+	}
+      else
+	{
+	  if (*regname)
+	    {
+	      if (symbol_find (regname))
+		as_bad (_("Register symbol %s already defined."), regname);
+	    }
+	  globals [reg] = symbol_make (regname);
+	  flags = symbol_get_bfdsym (globals [reg])->flags;
+	  if (! *regname)
+	    flags = flags & ~(BSF_GLOBAL|BSF_LOCAL|BSF_WEAK);
+	  if (! (flags & (BSF_GLOBAL|BSF_LOCAL|BSF_WEAK)))
+	    flags |= BSF_GLOBAL;
+	  symbol_get_bfdsym (globals [reg])->flags = flags;
+	  S_SET_VALUE (globals [reg], (valueT)reg);
+	  S_SET_ALIGN (globals [reg], reg);
+	  S_SET_SIZE (globals [reg], 0);
+	  /* Although we actually want undefined_section here,
+	     we have to use absolute_section, because otherwise
+	     generic as code will make it a COM section.
+	     We fix this up in sparc_adjust_symtab.  */
+	  S_SET_SEGMENT (globals [reg], absolute_section);
+	  S_SET_OTHER (globals [reg], 0);
+	  elf_symbol (symbol_get_bfdsym (globals [reg]))
+	    ->internal_elf_sym.st_info =
+	      ELF_ST_INFO(STB_GLOBAL, STT_REGISTER);
+	  elf_symbol (symbol_get_bfdsym (globals [reg]))
+	    ->internal_elf_sym.st_shndx = SHN_UNDEF;
+	}
+    }
+
+  *input_line_pointer = c;
+
+  demand_empty_rest_of_line ();
+}
+
+/* Adjust the symbol table.  We set undefined sections for STT_REGISTER
+   symbols which need it.  */
+   
+void
+sparc_adjust_symtab ()
+{
+  symbolS *sym;
+     
+  for (sym = symbol_rootP; sym != NULL; sym = symbol_next (sym))
+    {
+      if (ELF_ST_TYPE (elf_symbol (symbol_get_bfdsym (sym))
+		       ->internal_elf_sym.st_info) != STT_REGISTER)
+	continue;
+
+      if (ELF_ST_TYPE (elf_symbol (symbol_get_bfdsym (sym))
+		       ->internal_elf_sym.st_shndx != SHN_UNDEF))
+	continue;
+
+      S_SET_SEGMENT (sym, undefined_section);
+    }
+}
+#endif
 
 /* If the --enforce-aligned-data option is used, we require .word,
    et. al., to be aligned correctly.  We do it by setting up an
--- ./gas/config/tc-sparc.h.jj4	Mon Jul  5 14:15:17 1999
+++ ./gas/config/tc-sparc.h	Wed Jul  7 13:35:50 1999
@@ -134,6 +134,10 @@ extern int elf32_sparc_force_relocation 
 	       == S_GET_SEGMENT ((FIX)->fx_addsy)))			\
        || strchr (S_GET_NAME ((FIX)->fx_addsy), '\001') != NULL		\
        || strchr (S_GET_NAME ((FIX)->fx_addsy), '\002') != NULL))
+
+/* Finish up the entire symtab.  */
+#define tc_adjust_symtab() sparc_adjust_symtab ()
+extern void sparc_adjust_symtab PARAMS ((void));
 #endif
 
 #ifdef OBJ_AOUT
1999-07-09  Jakub Jelinek  <jj@ultra.linux.cz>

	* bfd/elf64-sparc.c (sparc64_elf_info_to_howto): Use ELF64_R_TYPE_ID.
	(sparc64_elf_get_reloc_upper_bound,
	sparc64_elf_get_dynamic_reloc_upper_bound,
	sparc64_elf_slurp_one_reloc_table, sparc64_elf_slurp_reloc_table,
	sparc64_elf_canonicalize_dynamic_reloc, sparc64_elf_write_relocs):
	New functions.
	(sparc64_elf_check_relocs, sparc64_elf_relocate_section): Use
	ELF64_R_TYPE_ID/DATA where appropriate.
	* gas/config/tc-sparc.c (sparc_ip): Allow OLO10 relocations
	on -64 and not pic.
	(output_insn): Put OLO10's secondary addend into tc_fix_data.
	(md_apply_fix3): Handle BFD_RELOC_SPARC_OLO10.
	(tc_gen_reloc): Return two relocs for OLO10, LO10 and SPARC13.
	* gas/config/tc-sparc.h (RELOC_EXPANSION_POSSIBLE,
	MAX_RELOC_EXPANSION): Define.
	(TC_FIX_TYPE, TC_INIT_FIX_DATA, TC_FIX_DATA_PRINT): Likewise.

--- ./gas/config/tc-sparc.c.jj	Sat Jul  3 18:31:35 1999
+++ ./gas/config/tc-sparc.c	Mon Jul  5 14:31:44 1999
@@ -2248,7 +2248,7 @@ sparc_ip (str, pinsn)
 		      }
 		    else
 		      {
-			if (1 || old_reloc != BFD_RELOC_SPARC13
+			if (old_reloc != BFD_RELOC_SPARC13
 			    || the_insn.reloc != BFD_RELOC_LO10
 			    || sparc_arch_size != 64
 			    || sparc_pic_code)
@@ -2667,6 +2667,8 @@ output_insn (insn, the_insn)
 	 the insn size is 4 and fixup_segment will signal an overflow for
 	 large 8 byte quantities.  */
       fixP->fx_no_overflow = 1;
+      if (the_insn->reloc == BFD_RELOC_SPARC_OLO10)
+	fixP->tc_fix_data = the_insn->exp2.X_add_number;
     }
 
   last_insn = insn;
@@ -3001,6 +3003,11 @@ md_apply_fix3 (fixP, value, segment)
 	    }
 	  break;
 
+	case BFD_RELOC_SPARC_OLO10:
+	  val &= 0x3ff;
+	  val += fixP->tc_fix_data;
+	  /* intentional fallthrough */
+
 	case BFD_RELOC_SPARC13:
 	  if (! in_signed_range (val, 0x1fff))
 	    as_bad_where (fixP->fx_file, fixP->fx_line,
@@ -3070,15 +3077,17 @@ md_apply_fix3 (fixP, value, segment)
 
 /* Translate internal representation of relocation info to BFD target
    format.  */
-arelent *
+arelent **
 tc_gen_reloc (section, fixp)
      asection *section;
      fixS *fixp;
 {
+  static arelent *relocs[3];
   arelent *reloc;
   bfd_reloc_code_real_type code;
 
-  reloc = (arelent *) xmalloc (sizeof (arelent));
+  relocs[0] = reloc = (arelent *) xmalloc (sizeof (arelent));
+  relocs[1] = NULL;
 
   reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
   *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
@@ -3115,6 +3124,7 @@ tc_gen_reloc (section, fixp)
     case BFD_RELOC_SPARC_HIX22:
     case BFD_RELOC_SPARC_LOX10:
     case BFD_RELOC_SPARC_REV32:
+    case BFD_RELOC_SPARC_OLO10:
     case BFD_RELOC_VTABLE_ENTRY:
     case BFD_RELOC_VTABLE_INHERIT:
       code = fixp->fx_r_type;
@@ -3168,13 +3178,18 @@ tc_gen_reloc (section, fixp)
     }
 #endif /* defined (OBJ_ELF) || defined (OBJ_AOUT) */
 
-  reloc->howto = bfd_reloc_type_lookup (stdoutput, code);
+  if (code == BFD_RELOC_SPARC_OLO10)
+    reloc->howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_LO10);
+  else
+    reloc->howto = bfd_reloc_type_lookup (stdoutput, code);
   if (reloc->howto == 0)
     {
       as_bad_where (fixp->fx_file, fixp->fx_line,
 		    _("internal error: can't export reloc type %d (`%s')"),
 		    fixp->fx_r_type, bfd_get_reloc_code_name (code));
-      return 0;
+      xfree (reloc);
+      relocs[0] = NULL;
+      return relocs;
     }
 
   /* @@ Why fx_addnumber sometimes and fx_offset other times?  */
@@ -3209,7 +3224,21 @@ tc_gen_reloc (section, fixp)
     reloc->addend = fixp->fx_offset;
 #endif
 
-  return reloc;
+  /* We expand R_SPARC_OLO10 to R_SPARC_LO10 and R_SPARC_13
+     on the same location.  */
+  if (code == BFD_RELOC_SPARC_OLO10)
+    {
+      relocs[1] = reloc = (arelent *) xmalloc (sizeof (arelent));
+      relocs[2] = NULL;
+
+      reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
+      *reloc->sym_ptr_ptr = symbol_get_bfdsym (section_symbol (absolute_section));
+      reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
+      reloc->howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_SPARC13);
+      reloc->addend = fixp->tc_fix_data;
+    }
+
+  return relocs;
 }
 
 /* We have no need to default values of symbols. */
--- ./gas/config/tc-sparc.h.jj	Tue Jun 29 10:49:38 1999
+++ ./gas/config/tc-sparc.h	Mon Jul  5 14:15:17 1999
@@ -35,6 +35,9 @@ struct frag;
 extern const char *sparc_target_format PARAMS ((void));
 #define TARGET_FORMAT sparc_target_format ()
 
+#define RELOC_EXPANSION_POSSIBLE
+#define MAX_RELOC_EXPANSION 2
+
 #if 0
 #ifdef TE_SPARCAOUT
 /* Bi-endian support may eventually be unconditional, but until things are
@@ -160,5 +163,22 @@ extern void sparc_md_end PARAMS ((void))
 #define TC_CONS_FIX_NEW cons_fix_new_sparc
 extern void cons_fix_new_sparc
   PARAMS ((struct frag *, int, unsigned int, struct expressionS *));
+
+#define TC_FIX_TYPE	valueT
+
+#define TC_INIT_FIX_DATA(X)			\
+  do						\
+     {						\
+       (X)->tc_fix_data = 0;			\
+     }						\
+  while(0)
+
+#define TC_FIX_DATA_PRINT(FILE, FIXP)					\
+  do									\
+    {									\
+      fprintf((FILE), "addend2=%ld\n",   				\
+	      (unsigned long) (FIXP)->tc_fix_data);			\
+    }									\
+  while(0)
 
 /* end of tc-sparc.h */
--- bfd/elf64-sparc.c.jj	Fri Jul  9 12:18:56 1999
+++ bfd/elf64-sparc.c	Fri Jul  9 13:27:07 1999
@@ -61,6 +61,15 @@
   PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *,
 	   Elf_Internal_Rela *, Elf_Internal_Sym *, asection **));
 static boolean sparc64_elf_object_p PARAMS ((bfd *));
+static long sparc64_elf_get_reloc_upper_bound PARAMS ((bfd *, asection *));
+static long sparc64_elf_get_dynamic_reloc_upper_bound PARAMS ((bfd *));
+static boolean sparc64_elf_slurp_one_reloc_table
+  PARAMS ((bfd *, asection *, Elf_Internal_Shdr *, asymbol **, boolean));
+static boolean sparc64_elf_slurp_reloc_table
+  PARAMS ((bfd *, asection *, asymbol **, boolean));
+static long sparc64_elf_canonicalize_dynamic_reloc
+  PARAMS ((bfd *, arelent **, asymbol **));
+static void sparc64_elf_write_relocs PARAMS ((bfd *, asection *, PTR));
 
 /* The relocation "howto" table.  */
 
@@ -213,8 +222,380 @@
      arelent *cache_ptr;
      Elf64_Internal_Rela *dst;
 {
-  BFD_ASSERT (ELF64_R_TYPE (dst->r_info) < (unsigned int) R_SPARC_max_std);
-  cache_ptr->howto = &sparc64_elf_howto_table[ELF64_R_TYPE (dst->r_info)];
+  BFD_ASSERT (ELF64_R_TYPE_ID (dst->r_info) < (unsigned int) R_SPARC_max_std);
+  cache_ptr->howto = &sparc64_elf_howto_table[ELF64_R_TYPE_ID (dst->r_info)];
+}
+
+/* Due to the way how we handle R_SPARC_OLO10, each entry in a SHT_RELA
+   section can represent up to two relocs, we must tell the user to allocate
+   more space.  */
+   
+static long
+sparc64_elf_get_reloc_upper_bound (abfd, sec)
+     bfd *abfd;
+     asection *sec;
+{
+  return (sec->reloc_count * 2 + 1) * sizeof (arelent *);
+}
+
+static long
+sparc64_elf_get_dynamic_reloc_upper_bound (abfd)
+     bfd *abfd;
+{
+  return _bfd_elf_get_dynamic_reloc_upper_bound (abfd) * 2;
+}
+
+/* Read  relocations for ASECT from REL_HDR.  There are RELOC_COUNT of 
+   them.  We cannot use generic elf routines for this,  because R_SPARC_OLO10
+   has secondary addend in ELF64_R_TYPE_DATA.  We handle it as two relocations
+   for the same location,  R_SPARC_LO10 and R_SPARC_13.  */
+
+static boolean
+sparc64_elf_slurp_one_reloc_table (abfd, asect, rel_hdr, symbols, dynamic)
+     bfd *abfd;
+     asection *asect;
+     Elf_Internal_Shdr *rel_hdr;
+     asymbol **symbols;
+     boolean dynamic;
+{
+  struct elf_backend_data * const ebd = get_elf_backend_data (abfd);
+  PTR allocated = NULL;
+  bfd_byte *native_relocs;
+  arelent *relent;
+  unsigned int i;
+  int entsize;
+  bfd_size_type count;
+  arelent *relents;
+
+  allocated = (PTR) bfd_malloc ((size_t) rel_hdr->sh_size);
+  if (allocated == NULL)
+    goto error_return;
+
+  if (bfd_seek (abfd, rel_hdr->sh_offset, SEEK_SET) != 0
+      || (bfd_read (allocated, 1, rel_hdr->sh_size, abfd)
+	  != rel_hdr->sh_size))
+    goto error_return;
+
+  native_relocs = (bfd_byte *) allocated;
+
+  relents = asect->relocation + asect->reloc_count;
+
+  entsize = rel_hdr->sh_entsize;
+  BFD_ASSERT (entsize == sizeof (Elf64_External_Rela));
+  
+  count = rel_hdr->sh_size / entsize;
+
+  for (i = 0, relent = relents; i < count;
+       i++, relent++, native_relocs += entsize)
+    {
+      Elf_Internal_Rela rela;
+
+      bfd_elf64_swap_reloca_in (abfd, (Elf64_External_Rela *) native_relocs, &rela);
+
+      /* The address of an ELF reloc is section relative for an object
+	 file, and absolute for an executable file or shared library.
+	 The address of a normal BFD reloc is always section relative,
+	 and the address of a dynamic reloc is absolute..  */
+      if ((abfd->flags & (EXEC_P | DYNAMIC)) == 0 || dynamic)
+	relent->address = rela.r_offset;
+      else
+	relent->address = rela.r_offset - asect->vma;
+
+      if (ELF64_R_SYM (rela.r_info) == 0)
+	relent->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr;
+      else
+	{
+	  asymbol **ps, *s;
+
+	  ps = symbols + ELF64_R_SYM (rela.r_info) - 1;
+	  s = *ps;
+
+	  /* Canonicalize ELF section symbols.  FIXME: Why?  */
+	  if ((s->flags & BSF_SECTION_SYM) == 0)
+	    relent->sym_ptr_ptr = ps;
+	  else
+	    relent->sym_ptr_ptr = s->section->symbol_ptr_ptr;
+	}
+
+      relent->addend = rela.r_addend;
+
+      BFD_ASSERT (ELF64_R_TYPE_ID (rela.r_info) < (unsigned int) R_SPARC_max_std);
+      if (ELF64_R_TYPE_ID (rela.r_info) == R_SPARC_OLO10)
+	{
+	  relent->howto = &sparc64_elf_howto_table[R_SPARC_LO10];
+	  relent[1].address = relent->address;
+	  relent++;
+	  relent->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr;
+	  relent->addend = ELF64_R_TYPE_DATA (rela.r_info);
+	  relent->howto = &sparc64_elf_howto_table[R_SPARC_13];
+	}
+      else
+	relent->howto = &sparc64_elf_howto_table[ELF64_R_TYPE_ID (rela.r_info)];
+    }
+
+  asect->reloc_count += relent - relents;
+
+  if (allocated != NULL)
+    free (allocated);
+
+  return true;
+
+ error_return:
+  if (allocated != NULL)
+    free (allocated);
+  return false;
+}
+
+/* Read in and swap the external relocs.  */
+
+static boolean
+sparc64_elf_slurp_reloc_table (abfd, asect, symbols, dynamic)
+     bfd *abfd;
+     asection *asect;
+     asymbol **symbols;
+     boolean dynamic;
+{
+  struct bfd_elf_section_data * const d = elf_section_data (asect);
+  Elf_Internal_Shdr *rel_hdr;
+  Elf_Internal_Shdr *rel_hdr2;
+
+  if (asect->relocation != NULL)
+    return true;
+
+  if (! dynamic)
+    {
+      if ((asect->flags & SEC_RELOC) == 0
+	  || asect->reloc_count == 0)
+	return true;
+
+      rel_hdr = &d->rel_hdr;
+      rel_hdr2 = d->rel_hdr2;
+
+      BFD_ASSERT (asect->rel_filepos == rel_hdr->sh_offset
+		  || (rel_hdr2 && asect->rel_filepos == rel_hdr2->sh_offset));
+    }
+  else
+    {
+      /* Note that ASECT->RELOC_COUNT tends not to be accurate in this
+	 case because relocations against this section may use the
+	 dynamic symbol table, and in that case bfd_section_from_shdr
+	 in elf.c does not update the RELOC_COUNT.  */
+      if (asect->_raw_size == 0)
+	return true;
+
+      rel_hdr = &d->this_hdr;
+      asect->reloc_count = rel_hdr->sh_size / rel_hdr->sh_entsize;
+      rel_hdr2 = NULL;
+    }
+
+  asect->relocation = ((arelent *) 
+		       bfd_alloc (abfd, 
+				  asect->reloc_count * 2 * sizeof (arelent)));
+  if (asect->relocation == NULL)
+    return false;
+
+  /* The sparc64_elf_slurp_one_reloc_table routine increments reloc_count.  */
+  asect->reloc_count = 0;
+    
+  if (!sparc64_elf_slurp_one_reloc_table (abfd, asect, rel_hdr, symbols,
+					  dynamic))
+    return false;
+  
+  if (rel_hdr2 
+      && !sparc64_elf_slurp_one_reloc_table (abfd, asect, rel_hdr2, symbols,
+					     dynamic))
+    return false;
+
+  return true;
+}
+
+/* Canonicalize the dynamic relocation entries.  Note that we return
+   the dynamic relocations as a single block, although they are
+   actually associated with particular sections; the interface, which
+   was designed for SunOS style shared libraries, expects that there
+   is only one set of dynamic relocs.  Any section that was actually
+   installed in the BFD, and has type SHT_REL or SHT_RELA, and uses
+   the dynamic symbol table, is considered to be a dynamic reloc
+   section.  */
+
+static long
+sparc64_elf_canonicalize_dynamic_reloc (abfd, storage, syms)
+     bfd *abfd;
+     arelent **storage;
+     asymbol **syms;
+{
+  asection *s;
+  long ret;
+
+  if (elf_dynsymtab (abfd) == 0)
+    {
+      bfd_set_error (bfd_error_invalid_operation);
+      return -1;
+    }
+
+  ret = 0;
+  for (s = abfd->sections; s != NULL; s = s->next)
+    {
+      if (elf_section_data (s)->this_hdr.sh_link == elf_dynsymtab (abfd)
+	  && (elf_section_data (s)->this_hdr.sh_type == SHT_RELA))
+	{
+	  arelent *p;
+	  long count, i;
+
+	  if (! sparc64_elf_slurp_reloc_table (abfd, s, syms, true))
+	    return -1;
+	  count = s->reloc_count;
+	  p = s->relocation;
+	  for (i = 0; i < count; i++)
+	    *storage++ = p++;
+	  ret += count;
+	}
+    }
+
+  *storage = NULL;
+
+  return ret;
+}
+
+/* Write out the relocs.  */
+
+static void
+sparc64_elf_write_relocs (abfd, sec, data)
+     bfd *abfd;
+     asection *sec;
+     PTR data;
+{
+  boolean *failedp = (boolean *) data;
+  Elf_Internal_Shdr *rela_hdr;
+  Elf64_External_Rela *outbound_relocas;
+  unsigned int idx, count;
+  asymbol *last_sym = 0;
+  int last_sym_idx = 0;
+
+  /* If we have already failed, don't do anything.  */
+  if (*failedp)
+    return;
+
+  if ((sec->flags & SEC_RELOC) == 0)
+    return;
+
+  /* The linker backend writes the relocs out itself, and sets the
+     reloc_count field to zero to inhibit writing them here.  Also,
+     sometimes the SEC_RELOC flag gets set even when there aren't any
+     relocs.  */
+  if (sec->reloc_count == 0)
+    return;
+
+  /* We can combine two relocs that refer to the same address
+     into R_SPARC_OLO10 if first one is R_SPARC_LO10 and the
+     latter is R_SPARC_13 with no associated symbol.  */
+  count = 0;
+  for (idx = 0; idx < sec->reloc_count; idx++)
+    {
+      bfd_vma addr;
+      unsigned int i;
+
+      ++count;
+
+      addr = sec->orelocation[idx]->address;
+      if (sec->orelocation[idx]->howto->type == R_SPARC_LO10
+	  && idx < sec->reloc_count - 1)
+	{
+	  arelent *r = sec->orelocation[idx + 1];
+
+	  if (r->howto->type == R_SPARC_13
+	      && r->address == addr
+	      && bfd_is_abs_section ((*r->sym_ptr_ptr)->section)
+	      && (*r->sym_ptr_ptr)->value == 0)
+	    ++idx;
+	}
+    }
+
+  rela_hdr = &elf_section_data (sec)->rel_hdr;
+
+  rela_hdr->sh_size = rela_hdr->sh_entsize * count;
+  rela_hdr->contents = (PTR) bfd_alloc (abfd, rela_hdr->sh_size);
+  if (rela_hdr->contents == NULL)
+    {
+      *failedp = true;
+      return;
+    }
+
+  /* Figure out whether the relocations are RELA or REL relocations.  */
+  if (rela_hdr->sh_type != SHT_RELA)
+    abort ();
+
+  /* orelocation has the data, reloc_count has the count... */
+  outbound_relocas = (Elf64_External_Rela *) rela_hdr->contents;
+
+  for (idx = 0; idx < sec->reloc_count; idx++)
+    {
+      Elf_Internal_Rela dst_rela;
+      Elf64_External_Rela *src_rela;
+      arelent *ptr;
+      asymbol *sym;
+      int n;
+
+      ptr = sec->orelocation[idx];
+      src_rela = outbound_relocas + idx;
+
+      /* The address of an ELF reloc is section relative for an object
+	 file, and absolute for an executable file or shared library.
+	 The address of a BFD reloc is always section relative.  */
+      if ((abfd->flags & (EXEC_P | DYNAMIC)) == 0)
+	dst_rela.r_offset = ptr->address;
+      else
+	dst_rela.r_offset = ptr->address + sec->vma;
+
+      sym = *ptr->sym_ptr_ptr;
+      if (sym == last_sym)
+	n = last_sym_idx;
+      else if (bfd_is_abs_section (sym->section) && sym->value == 0)
+	n = STN_UNDEF;
+      else
+	{
+	  last_sym = sym;
+	  n = _bfd_elf_symbol_from_bfd_symbol (abfd, &sym);
+	  if (n < 0)
+	    {
+	      *failedp = true;
+	      return;
+	    }
+	  last_sym_idx = n;
+	}
+
+      if ((*ptr->sym_ptr_ptr)->the_bfd != NULL
+	  && (*ptr->sym_ptr_ptr)->the_bfd->xvec != abfd->xvec
+	  && ! _bfd_elf_validate_reloc (abfd, ptr))
+	{
+	  *failedp = true;
+	  return;
+	}
+
+      if (ptr->howto->type == R_SPARC_LO10
+	  && idx < sec->reloc_count - 1)
+	{
+	  arelent *r = sec->orelocation[idx + 1];
+
+	  if (r->howto->type == R_SPARC_13
+	      && r->address == ptr->address
+	      && bfd_is_abs_section ((*r->sym_ptr_ptr)->section)
+	      && (*r->sym_ptr_ptr)->value == 0)
+	    {
+	      idx++;
+	      dst_rela.r_info
+		= ELF64_R_INFO (n, ELF64_R_TYPE_INFO (r->addend,
+						      R_SPARC_OLO10));
+	    }
+	  else
+	    dst_rela.r_info = ELF64_R_INFO (n, R_SPARC_LO10);
+	}
+      else
+	dst_rela.r_info = ELF64_R_INFO (n, ptr->howto->type);
+
+      dst_rela.r_addend = ptr->addend;
+      bfd_elf64_swap_reloca_out (abfd, &dst_rela, src_rela);
+    }
 }
 
 /* Utility for performing the standard initial work of an instruction
@@ -570,7 +951,7 @@
       else
 	h = sym_hashes[r_symndx - symtab_hdr->sh_info];
 
-      switch (ELF64_R_TYPE (rel->r_info))
+      switch (ELF64_R_TYPE_ID (rel->r_info))
 	{
 	case R_SPARC_GOT10:
 	case R_SPARC_GOT13:
@@ -809,7 +1190,7 @@
 	default:
 	  (*_bfd_error_handler)(_("%s: check_relocs: unhandled reloc type %d"),
 				bfd_get_filename(abfd),
-				ELF64_R_TYPE (rel->r_info));
+				ELF64_R_TYPE_ID (rel->r_info));
 	  return false;
 	}
     }
@@ -1245,7 +1626,7 @@
       bfd_vma relocation;
       bfd_reloc_status_type r;
 
-      r_type = ELF64_R_TYPE (rel->r_info);
+      r_type = ELF64_R_TYPE_ID (rel->r_info);
       if (r_type < 0 || r_type >= (int) R_SPARC_max_std)
 	{
 	  bfd_set_error (bfd_error_bad_value);
@@ -1531,7 +1912,11 @@
 				 & ELF_LINK_HASH_DEF_REGULAR) == 0))
 		  {
 		    BFD_ASSERT (h->dynindx != -1);
-		    outrel.r_info = ELF64_R_INFO (h->dynindx, r_type);
+		    outrel.r_info
+		      = ELF64_R_INFO (h->dynindx,
+				      ELF64_R_TYPE_INFO (
+					ELF64_R_TYPE_DATA (rel->r_info),
+							   r_type));
 		    outrel.r_addend = rel->r_addend;
 		  }
 		else
@@ -1581,7 +1966,11 @@
 			      }
 			  }
 
-			outrel.r_info = ELF64_R_INFO (indx, r_type);
+			outrel.r_info
+			  = ELF64_R_INFO (indx,
+					  ELF64_R_TYPE_INFO (
+					    ELF64_R_TYPE_DATA (rel->r_info),
+							       r_type));
 
 			/* For non-RELATIVE dynamic relocations, we keep the
 			   same symbol, and so generally the same addend.  But
@@ -1605,7 +1994,7 @@
 		   reloc in an unallocated section.  */
 		if (skip
 		    || (input_section->flags & SEC_ALLOC) != 0
-		    || ELF64_R_TYPE (outrel.r_info) != R_SPARC_RELATIVE)
+		    || ELF64_R_TYPE_ID (outrel.r_info) != R_SPARC_RELATIVE)
 		  continue;
 	      }
 	    break;
@@ -2225,6 +2614,45 @@
   return bfd_default_set_arch_mach (abfd, bfd_arch_sparc, mach);
 }
 
+/* Relocations in the 64 bit SPARC ELF ABI are more complex than in
+   standard ELF, because R_SPARC_OLO10 has secondary addend in
+   ELF64_R_TYPE_DATA field.  This structure is used to redirect the
+   relocation handling routines.  */
+
+const struct elf_size_info sparc64_elf_size_info =
+{
+  sizeof (Elf64_External_Ehdr),
+  sizeof (Elf64_External_Phdr),
+  sizeof (Elf64_External_Shdr),
+  sizeof (Elf64_External_Rel),
+  sizeof (Elf64_External_Rela),
+  sizeof (Elf64_External_Sym),
+  sizeof (Elf64_External_Dyn),
+  sizeof (Elf_External_Note),
+  8,		/* hash-table entry size */
+  /* internal relocations per external relocations.
+     For link purposes we use just 1 internal per
+     1 external, for assembly and slurp symbol table
+     we use 2. */
+  1,
+  64,		/* arch_size */
+  8,		/* file_align */
+  ELFCLASS64,
+  EV_CURRENT,
+  bfd_elf64_write_out_phdrs,
+  bfd_elf64_write_shdrs_and_ehdr,
+  sparc64_elf_write_relocs,
+  bfd_elf64_swap_symbol_out,
+  sparc64_elf_slurp_reloc_table,
+  bfd_elf64_slurp_symbol_table,
+  bfd_elf64_swap_dyn_in,
+  bfd_elf64_swap_dyn_out,
+  NULL,
+  NULL,
+  NULL,
+  NULL
+};
+
 #define TARGET_BIG_SYM	bfd_elf64_sparc_vec
 #define TARGET_BIG_NAME	"elf64-sparc"
 #define ELF_ARCH	bfd_arch_sparc
@@ -2238,6 +2666,12 @@
 
 #define elf_info_to_howto \
   sparc64_elf_info_to_howto
+#define bfd_elf64_get_reloc_upper_bound \
+  sparc64_elf_get_reloc_upper_bound
+#define bfd_elf64_get_dynamic_reloc_upper_bound \
+  sparc64_elf_get_dynamic_reloc_upper_bound
+#define bfd_elf64_canonicalize_dynamic_reloc \
+  sparc64_elf_canonicalize_dynamic_reloc
 #define bfd_elf64_bfd_reloc_type_lookup \
   sparc64_elf_reloc_type_lookup
 
@@ -2259,6 +2693,8 @@
 #define bfd_elf64_bfd_merge_private_bfd_data \
   sparc64_elf_merge_private_bfd_data
 
+#define elf_backend_size_info \
+  sparc64_elf_size_info
 #define elf_backend_object_p \
   sparc64_elf_object_p
 

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]