| /* SPARC-specific support for 64-bit ELF | 
 |    Copyright (C) 1993-2021 Free Software Foundation, Inc. | 
 |  | 
 |    This file is part of BFD, the Binary File Descriptor library. | 
 |  | 
 |    This program is free software; you can redistribute it and/or modify | 
 |    it under the terms of the GNU General Public License as published by | 
 |    the Free Software Foundation; either version 3 of the License, or | 
 |    (at your option) any later version. | 
 |  | 
 |    This program is distributed in the hope that it will be useful, | 
 |    but WITHOUT ANY WARRANTY; without even the implied warranty of | 
 |    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
 |    GNU General Public License for more details. | 
 |  | 
 |    You should have received a copy of the GNU General Public License | 
 |    along with this program; if not, write to the Free Software | 
 |    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, | 
 |    MA 02110-1301, USA.  */ | 
 |  | 
 | #include "sysdep.h" | 
 | #include <limits.h> | 
 | #include "bfd.h" | 
 | #include "libbfd.h" | 
 | #include "elf-bfd.h" | 
 | #include "elf/sparc.h" | 
 | #include "opcode/sparc.h" | 
 | #include "elfxx-sparc.h" | 
 |  | 
 | /* In case we're on a 32-bit machine, construct a 64-bit "-1" value.  */ | 
 | #define MINUS_ONE (~ (bfd_vma) 0) | 
 |  | 
 | /* 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 | 
 | elf64_sparc_get_reloc_upper_bound (bfd *abfd ATTRIBUTE_UNUSED, asection *sec) | 
 | { | 
 | #if SIZEOF_LONG == SIZEOF_INT | 
 |   if (sec->reloc_count >= LONG_MAX / 2 / sizeof (arelent *)) | 
 |     { | 
 |       bfd_set_error (bfd_error_file_too_big); | 
 |       return -1; | 
 |     } | 
 | #endif | 
 |   return (sec->reloc_count * 2 + 1) * sizeof (arelent *); | 
 | } | 
 |  | 
 | static long | 
 | elf64_sparc_get_dynamic_reloc_upper_bound (bfd *abfd) | 
 | { | 
 |   long ret = _bfd_elf_get_dynamic_reloc_upper_bound (abfd); | 
 |   if (ret > LONG_MAX / 2) | 
 |     { | 
 |       bfd_set_error (bfd_error_file_too_big); | 
 |       ret = -1; | 
 |     } | 
 |   else if (ret > 0) | 
 |     ret *= 2; | 
 |   return ret; | 
 | } | 
 |  | 
 | /* 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 bool | 
 | elf64_sparc_slurp_one_reloc_table (bfd *abfd, asection *asect, | 
 | 				   Elf_Internal_Shdr *rel_hdr, | 
 | 				   asymbol **symbols, bool dynamic) | 
 | { | 
 |   void * allocated = NULL; | 
 |   bfd_byte *native_relocs; | 
 |   arelent *relent; | 
 |   unsigned int i; | 
 |   int entsize; | 
 |   bfd_size_type count; | 
 |   arelent *relents; | 
 |  | 
 |   if (bfd_seek (abfd, rel_hdr->sh_offset, SEEK_SET) != 0) | 
 |     return false; | 
 |   allocated = _bfd_malloc_and_read (abfd, rel_hdr->sh_size, rel_hdr->sh_size); | 
 |   if (allocated == NULL) | 
 |     return false; | 
 |  | 
 |   native_relocs = (bfd_byte *) allocated; | 
 |  | 
 |   relents = asect->relocation + canon_reloc_count (asect); | 
 |  | 
 |   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; | 
 |       unsigned int r_type; | 
 |  | 
 |       bfd_elf64_swap_reloca_in (abfd, 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) == STN_UNDEF) | 
 | 	relent->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr; | 
 |       else if (/* PR 17512: file: 996185f8.  */ | 
 | 	       ELF64_R_SYM (rela.r_info) > (dynamic | 
 | 					    ? bfd_get_dynamic_symcount (abfd) | 
 | 					    : bfd_get_symcount (abfd))) | 
 | 	{ | 
 | 	  _bfd_error_handler | 
 | 	    /* xgettext:c-format */ | 
 | 	    (_("%pB(%pA): relocation %d has invalid symbol index %ld"), | 
 | 	     abfd, asect, i, (long) ELF64_R_SYM (rela.r_info)); | 
 | 	  bfd_set_error (bfd_error_bad_value); | 
 | 	  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; | 
 |  | 
 |       r_type = ELF64_R_TYPE_ID (rela.r_info); | 
 |       if (r_type == R_SPARC_OLO10) | 
 | 	{ | 
 | 	  relent->howto = _bfd_sparc_elf_info_to_howto_ptr (abfd, 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 = _bfd_sparc_elf_info_to_howto_ptr (abfd, R_SPARC_13); | 
 | 	} | 
 |       else | 
 | 	{ | 
 | 	  relent->howto = _bfd_sparc_elf_info_to_howto_ptr (abfd, r_type); | 
 | 	  if (relent->howto == NULL) | 
 | 	    goto error_return; | 
 | 	} | 
 |     } | 
 |  | 
 |   canon_reloc_count (asect) += relent - relents; | 
 |  | 
 |   free (allocated); | 
 |   return true; | 
 |  | 
 |  error_return: | 
 |   free (allocated); | 
 |   return false; | 
 | } | 
 |  | 
 | /* Read in and swap the external relocs.  */ | 
 |  | 
 | static bool | 
 | elf64_sparc_slurp_reloc_table (bfd *abfd, asection *asect, | 
 | 			       asymbol **symbols, bool dynamic) | 
 | { | 
 |   struct bfd_elf_section_data * const d = elf_section_data (asect); | 
 |   Elf_Internal_Shdr *rel_hdr; | 
 |   Elf_Internal_Shdr *rel_hdr2; | 
 |   bfd_size_type amt; | 
 |  | 
 |   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->rela.hdr; | 
 |  | 
 |       BFD_ASSERT ((rel_hdr && 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->size == 0) | 
 | 	return true; | 
 |  | 
 |       rel_hdr = &d->this_hdr; | 
 |       asect->reloc_count = NUM_SHDR_ENTRIES (rel_hdr); | 
 |       rel_hdr2 = NULL; | 
 |     } | 
 |  | 
 |   amt = asect->reloc_count; | 
 |   amt *= 2 * sizeof (arelent); | 
 |   asect->relocation = (arelent *) bfd_alloc (abfd, amt); | 
 |   if (asect->relocation == NULL) | 
 |     return false; | 
 |  | 
 |   /* The elf64_sparc_slurp_one_reloc_table routine increments | 
 |      canon_reloc_count.  */ | 
 |   canon_reloc_count (asect) = 0; | 
 |  | 
 |   if (rel_hdr | 
 |       && !elf64_sparc_slurp_one_reloc_table (abfd, asect, rel_hdr, symbols, | 
 | 					     dynamic)) | 
 |     return false; | 
 |  | 
 |   if (rel_hdr2 | 
 |       && !elf64_sparc_slurp_one_reloc_table (abfd, asect, rel_hdr2, symbols, | 
 | 					     dynamic)) | 
 |     return false; | 
 |  | 
 |   return true; | 
 | } | 
 |  | 
 | /* Canonicalize the relocs.  */ | 
 |  | 
 | static long | 
 | elf64_sparc_canonicalize_reloc (bfd *abfd, sec_ptr section, | 
 | 				arelent **relptr, asymbol **symbols) | 
 | { | 
 |   arelent *tblptr; | 
 |   unsigned int i; | 
 |   const struct elf_backend_data *bed = get_elf_backend_data (abfd); | 
 |  | 
 |   if (! bed->s->slurp_reloc_table (abfd, section, symbols, false)) | 
 |     return -1; | 
 |  | 
 |   tblptr = section->relocation; | 
 |   for (i = 0; i < canon_reloc_count (section); i++) | 
 |     *relptr++ = tblptr++; | 
 |  | 
 |   *relptr = NULL; | 
 |  | 
 |   return canon_reloc_count (section); | 
 | } | 
 |  | 
 |  | 
 | /* 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 | 
 | elf64_sparc_canonicalize_dynamic_reloc (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 (! elf64_sparc_slurp_reloc_table (abfd, s, syms, true)) | 
 | 	    return -1; | 
 | 	  count = canon_reloc_count (s); | 
 | 	  p = s->relocation; | 
 | 	  for (i = 0; i < count; i++) | 
 | 	    *storage++ = p++; | 
 | 	  ret += count; | 
 | 	} | 
 |     } | 
 |  | 
 |   *storage = NULL; | 
 |  | 
 |   return ret; | 
 | } | 
 |  | 
 | /* Install a new set of internal relocs.  */ | 
 |  | 
 | static void | 
 | elf64_sparc_set_reloc (bfd *abfd ATTRIBUTE_UNUSED, | 
 | 		       asection *asect, | 
 | 		       arelent **location, | 
 | 		       unsigned int count) | 
 | { | 
 |   asect->orelocation = location; | 
 |   canon_reloc_count (asect) = count; | 
 | } | 
 |  | 
 | /* Write out the relocs.  */ | 
 |  | 
 | static void | 
 | elf64_sparc_write_relocs (bfd *abfd, asection *sec, void * data) | 
 | { | 
 |   bool *failedp = (bool *) data; | 
 |   Elf_Internal_Shdr *rela_hdr; | 
 |   bfd_vma addr_offset; | 
 |   Elf64_External_Rela *outbound_relocas, *src_rela; | 
 |   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 (canon_reloc_count (sec) == 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 < canon_reloc_count (sec); idx++) | 
 |     { | 
 |       bfd_vma addr; | 
 |  | 
 |       ++count; | 
 |  | 
 |       addr = sec->orelocation[idx]->address; | 
 |       if (sec->orelocation[idx]->howto->type == R_SPARC_LO10 | 
 | 	  && idx < canon_reloc_count (sec) - 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)->rela.hdr; | 
 |  | 
 |   rela_hdr->sh_size = rela_hdr->sh_entsize * count; | 
 |   rela_hdr->contents = 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 (); | 
 |  | 
 |   /* 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.  */ | 
 |   addr_offset = 0; | 
 |   if ((abfd->flags & (EXEC_P | DYNAMIC)) != 0) | 
 |     addr_offset = sec->vma; | 
 |  | 
 |   /* orelocation has the data, reloc_count has the count...  */ | 
 |   outbound_relocas = (Elf64_External_Rela *) rela_hdr->contents; | 
 |   src_rela = outbound_relocas; | 
 |  | 
 |   for (idx = 0; idx < canon_reloc_count (sec); idx++) | 
 |     { | 
 |       Elf_Internal_Rela dst_rela; | 
 |       arelent *ptr; | 
 |       asymbol *sym; | 
 |       int n; | 
 |  | 
 |       ptr = sec->orelocation[idx]; | 
 |       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 < canon_reloc_count (sec) - 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_offset = ptr->address + addr_offset; | 
 |       dst_rela.r_addend = ptr->addend; | 
 |  | 
 |       bfd_elf64_swap_reloca_out (abfd, &dst_rela, (bfd_byte *) src_rela); | 
 |       ++src_rela; | 
 |     } | 
 | } | 
 |  | 
 | /* Hook called by the linker routine which adds symbols from an object | 
 |    file.  We use it for STT_REGISTER symbols.  */ | 
 |  | 
 | static bool | 
 | elf64_sparc_add_symbol_hook (bfd *abfd, struct bfd_link_info *info, | 
 | 			     Elf_Internal_Sym *sym, const char **namep, | 
 | 			     flagword *flagsp ATTRIBUTE_UNUSED, | 
 | 			     asection **secp ATTRIBUTE_UNUSED, | 
 | 			     bfd_vma *valp ATTRIBUTE_UNUSED) | 
 | { | 
 |   static const char *const stt_types[] = { "NOTYPE", "OBJECT", "FUNCTION" }; | 
 |  | 
 |   if (ELF_ST_TYPE (sym->st_info) == STT_REGISTER) | 
 |     { | 
 |       int reg; | 
 |       struct _bfd_sparc_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 | 
 | 	    (_("%pB: only registers %%g[2367] can be declared using STT_REGISTER"), | 
 | 	     abfd); | 
 | 	  return false; | 
 | 	} | 
 |  | 
 |       if (info->output_bfd->xvec != 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 = _bfd_sparc_elf_hash_table(info)->app_regs + reg; | 
 |  | 
 |       if (p->name != NULL && strcmp (p->name, *namep)) | 
 | 	{ | 
 | 	  _bfd_error_handler | 
 | 	    /* xgettext:c-format */ | 
 | 	    (_("register %%g%d used incompatibly: %s in %pB," | 
 | 	       " previously %s in %pB"), | 
 | 	     (int) sym->st_value, **namep ? *namep : "#scratch", abfd, | 
 | 	     *p->name ? p->name : "#scratch", p->abfd); | 
 | 	  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 | 
 | 		    /* xgettext:c-format */ | 
 | 		    (_("symbol `%s' has differing types: REGISTER in %pB," | 
 | 		       " previously %s in %pB"), | 
 | 		     *namep, abfd, stt_types[type], p->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 | 
 | 	   && info->output_bfd->xvec == abfd->xvec) | 
 |     { | 
 |       int i; | 
 |       struct _bfd_sparc_elf_app_reg *p; | 
 |  | 
 |       p = _bfd_sparc_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 | 
 | 	      /* xgettext:c-format */ | 
 | 	      (_("Symbol `%s' has differing types: %s in %pB," | 
 | 		 " previously REGISTER in %pB"), | 
 | 	       *namep, stt_types[type], abfd, p->abfd); | 
 | 	    return false; | 
 | 	  } | 
 |     } | 
 |   return true; | 
 | } | 
 |  | 
 | /* This function takes care of emitting STT_REGISTER symbols | 
 |    which we cannot easily keep in the symbol hash table.  */ | 
 |  | 
 | static bool | 
 | elf64_sparc_output_arch_syms (bfd *output_bfd ATTRIBUTE_UNUSED, | 
 | 			      struct bfd_link_info *info, | 
 | 			      void * flaginfo, | 
 | 			      int (*func) (void *, const char *, | 
 | 					   Elf_Internal_Sym *, | 
 | 					   asection *, | 
 | 					   struct elf_link_hash_entry *)) | 
 | { | 
 |   int reg; | 
 |   struct _bfd_sparc_elf_app_reg *app_regs = | 
 |     _bfd_sparc_elf_hash_table(info)->app_regs; | 
 |   Elf_Internal_Sym sym; | 
 |  | 
 |   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; | 
 | 	sym.st_target_internal = 0; | 
 | 	if ((*func) (flaginfo, app_regs [reg].name, &sym, | 
 | 		     sym.st_shndx == SHN_ABS | 
 | 		     ? bfd_abs_section_ptr : bfd_und_section_ptr, | 
 | 		     NULL) != 1) | 
 | 	  return false; | 
 |       } | 
 |  | 
 |   return true; | 
 | } | 
 |  | 
 | static int | 
 | elf64_sparc_get_symbol_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 | 
 | elf64_sparc_symbol_processing (bfd *abfd ATTRIBUTE_UNUSED, 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; | 
 |     } | 
 | } | 
 |  | 
 |  | 
 | /* Functions for dealing with the e_flags field.  */ | 
 |  | 
 | /* Merge backend specific data from an object file to the output | 
 |    object file when linking.  */ | 
 |  | 
 | static bool | 
 | elf64_sparc_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info) | 
 | { | 
 |   bfd *obfd = info->output_bfd; | 
 |   bool error; | 
 |   flagword new_flags, old_flags; | 
 |   int new_mm, old_mm; | 
 |  | 
 |   if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour | 
 |       || bfd_get_flavour (obfd) != bfd_target_elf_flavour) | 
 |     return true; | 
 |  | 
 |   new_flags = elf_elfheader (ibfd)->e_flags; | 
 |   old_flags = elf_elfheader (obfd)->e_flags; | 
 |  | 
 |   if (!elf_flags_init (obfd))   /* First call, no flags set */ | 
 |     { | 
 |       elf_flags_init (obfd) = true; | 
 |       elf_elfheader (obfd)->e_flags = new_flags; | 
 |     } | 
 |  | 
 |   else if (new_flags == old_flags)      /* Compatible flags are ok */ | 
 |     ; | 
 |  | 
 |   else					/* Incompatible flags */ | 
 |     { | 
 |       error = false; | 
 |  | 
 | #define EF_SPARC_ISA_EXTENSIONS \ | 
 |   (EF_SPARC_SUN_US1 | EF_SPARC_SUN_US3 | EF_SPARC_HAL_R1) | 
 |  | 
 |       if ((ibfd->flags & DYNAMIC) != 0) | 
 | 	{ | 
 | 	  /* We don't want dynamic objects memory ordering and | 
 | 	     architecture to have any role. That's what dynamic linker | 
 | 	     should do.  */ | 
 | 	  new_flags &= ~(EF_SPARCV9_MM | EF_SPARC_ISA_EXTENSIONS); | 
 | 	  new_flags |= (old_flags | 
 | 			& (EF_SPARCV9_MM | EF_SPARC_ISA_EXTENSIONS)); | 
 | 	} | 
 |       else | 
 | 	{ | 
 | 	  /* Choose the highest architecture requirements.  */ | 
 | 	  old_flags |= (new_flags & EF_SPARC_ISA_EXTENSIONS); | 
 | 	  new_flags |= (old_flags & EF_SPARC_ISA_EXTENSIONS); | 
 | 	  if ((old_flags & (EF_SPARC_SUN_US1 | EF_SPARC_SUN_US3)) | 
 | 	      && (old_flags & EF_SPARC_HAL_R1)) | 
 | 	    { | 
 | 	      error = true; | 
 | 	      _bfd_error_handler | 
 | 		(_("%pB: linking UltraSPARC specific with HAL specific code"), | 
 | 		 ibfd); | 
 | 	    } | 
 | 	  /* Choose the most restrictive memory ordering.  */ | 
 | 	  old_mm = (old_flags & EF_SPARCV9_MM); | 
 | 	  new_mm = (new_flags & EF_SPARCV9_MM); | 
 | 	  old_flags &= ~EF_SPARCV9_MM; | 
 | 	  new_flags &= ~EF_SPARCV9_MM; | 
 | 	  if (new_mm < old_mm) | 
 | 	    old_mm = new_mm; | 
 | 	  old_flags |= old_mm; | 
 | 	  new_flags |= old_mm; | 
 | 	} | 
 |  | 
 |       /* Warn about any other mismatches */ | 
 |       if (new_flags != old_flags) | 
 | 	{ | 
 | 	  error = true; | 
 | 	  _bfd_error_handler | 
 | 	    /* xgettext:c-format */ | 
 | 	    (_("%pB: uses different e_flags (%#x) fields than previous modules (%#x)"), | 
 | 	     ibfd, new_flags, old_flags); | 
 | 	} | 
 |  | 
 |       elf_elfheader (obfd)->e_flags = old_flags; | 
 |  | 
 |       if (error) | 
 | 	{ | 
 | 	  bfd_set_error (bfd_error_bad_value); | 
 | 	  return false; | 
 | 	} | 
 |     } | 
 |   return _bfd_sparc_elf_merge_private_bfd_data (ibfd, info); | 
 | } | 
 |  | 
 | /* MARCO: Set the correct entry size for the .stab section.  */ | 
 |  | 
 | static bool | 
 | elf64_sparc_fake_sections (bfd *abfd ATTRIBUTE_UNUSED, | 
 | 			   Elf_Internal_Shdr *hdr ATTRIBUTE_UNUSED, | 
 | 			   asection *sec) | 
 | { | 
 |   const char *name; | 
 |  | 
 |   name = bfd_section_name (sec); | 
 |  | 
 |   if (strcmp (name, ".stab") == 0) | 
 |     { | 
 |       /* Even in the 64bit case the stab entries are only 12 bytes long.  */ | 
 |       elf_section_data (sec)->this_hdr.sh_entsize = 12; | 
 |     } | 
 |  | 
 |   return true; | 
 | } | 
 |  | 
 | /* Print a STT_REGISTER symbol to file FILE.  */ | 
 |  | 
 | static const char * | 
 | elf64_sparc_print_symbol_all (bfd *abfd ATTRIBUTE_UNUSED, void * 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; | 
 | } | 
 |  | 
 | /* Used to decide how to sort relocs in an optimal manner for the | 
 |    dynamic linker, before writing them out.  */ | 
 |  | 
 | static enum elf_reloc_type_class | 
 | elf64_sparc_reloc_type_class (const struct bfd_link_info *info, | 
 | 			      const asection *rel_sec ATTRIBUTE_UNUSED, | 
 | 			      const Elf_Internal_Rela *rela) | 
 | { | 
 |   bfd *abfd = info->output_bfd; | 
 |   const struct elf_backend_data *bed = get_elf_backend_data (abfd); | 
 |   struct _bfd_sparc_elf_link_hash_table *htab | 
 |     = _bfd_sparc_elf_hash_table (info); | 
 |   BFD_ASSERT (htab != NULL); | 
 |  | 
 |   if (htab->elf.dynsym != NULL | 
 |       && htab->elf.dynsym->contents != NULL) | 
 |     { | 
 |       /* Check relocation against STT_GNU_IFUNC symbol if there are | 
 | 	 dynamic symbols.  */ | 
 |       unsigned long r_symndx = htab->r_symndx (rela->r_info); | 
 |       if (r_symndx != STN_UNDEF) | 
 | 	{ | 
 | 	  Elf_Internal_Sym sym; | 
 | 	  if (!bed->s->swap_symbol_in (abfd, | 
 | 				       (htab->elf.dynsym->contents | 
 | 					+ r_symndx * bed->s->sizeof_sym), | 
 | 				       0, &sym)) | 
 | 	    abort (); | 
 |  | 
 | 	  if (ELF_ST_TYPE (sym.st_info) == STT_GNU_IFUNC) | 
 | 	    return reloc_class_ifunc; | 
 | 	} | 
 |     } | 
 |  | 
 |   switch ((int) ELF64_R_TYPE (rela->r_info)) | 
 |     { | 
 |     case R_SPARC_IRELATIVE: | 
 |       return reloc_class_ifunc; | 
 |     case R_SPARC_RELATIVE: | 
 |       return reloc_class_relative; | 
 |     case R_SPARC_JMP_SLOT: | 
 |       return reloc_class_plt; | 
 |     case R_SPARC_COPY: | 
 |       return reloc_class_copy; | 
 |     default: | 
 |       return reloc_class_normal; | 
 |     } | 
 | } | 
 |  | 
 | /* 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 elf64_sparc_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), | 
 |   4,		/* 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.  */ | 
 |   3,		/* log_file_align.  */ | 
 |   ELFCLASS64, | 
 |   EV_CURRENT, | 
 |   bfd_elf64_write_out_phdrs, | 
 |   bfd_elf64_write_shdrs_and_ehdr, | 
 |   bfd_elf64_checksum_contents, | 
 |   elf64_sparc_write_relocs, | 
 |   bfd_elf64_swap_symbol_in, | 
 |   bfd_elf64_swap_symbol_out, | 
 |   elf64_sparc_slurp_reloc_table, | 
 |   bfd_elf64_slurp_symbol_table, | 
 |   bfd_elf64_swap_dyn_in, | 
 |   bfd_elf64_swap_dyn_out, | 
 |   bfd_elf64_swap_reloc_in, | 
 |   bfd_elf64_swap_reloc_out, | 
 |   bfd_elf64_swap_reloca_in, | 
 |   bfd_elf64_swap_reloca_out | 
 | }; | 
 |  | 
 | #define TARGET_BIG_SYM	sparc_elf64_vec | 
 | #define TARGET_BIG_NAME	"elf64-sparc" | 
 | #define ELF_ARCH	bfd_arch_sparc | 
 | #define ELF_MAXPAGESIZE 0x100000 | 
 | #define ELF_COMMONPAGESIZE 0x2000 | 
 |  | 
 | /* This is the official ABI value.  */ | 
 | #define ELF_MACHINE_CODE EM_SPARCV9 | 
 |  | 
 | /* This is the value that we used before the ABI was released.  */ | 
 | #define ELF_MACHINE_ALT1 EM_OLD_SPARCV9 | 
 |  | 
 | #define elf_backend_reloc_type_class \ | 
 |   elf64_sparc_reloc_type_class | 
 | #define bfd_elf64_get_reloc_upper_bound \ | 
 |   elf64_sparc_get_reloc_upper_bound | 
 | #define bfd_elf64_get_dynamic_reloc_upper_bound \ | 
 |   elf64_sparc_get_dynamic_reloc_upper_bound | 
 | #define bfd_elf64_canonicalize_reloc \ | 
 |   elf64_sparc_canonicalize_reloc | 
 | #define bfd_elf64_canonicalize_dynamic_reloc \ | 
 |   elf64_sparc_canonicalize_dynamic_reloc | 
 | #define bfd_elf64_set_reloc \ | 
 |   elf64_sparc_set_reloc | 
 | #define elf_backend_add_symbol_hook \ | 
 |   elf64_sparc_add_symbol_hook | 
 | #define elf_backend_get_symbol_type \ | 
 |   elf64_sparc_get_symbol_type | 
 | #define elf_backend_symbol_processing \ | 
 |   elf64_sparc_symbol_processing | 
 | #define elf_backend_print_symbol_all \ | 
 |   elf64_sparc_print_symbol_all | 
 | #define elf_backend_output_arch_syms \ | 
 |   elf64_sparc_output_arch_syms | 
 | #define bfd_elf64_bfd_merge_private_bfd_data \ | 
 |   elf64_sparc_merge_private_bfd_data | 
 | #define elf_backend_fake_sections \ | 
 |   elf64_sparc_fake_sections | 
 | #define elf_backend_size_info \ | 
 |   elf64_sparc_size_info | 
 |  | 
 | #define elf_backend_plt_sym_val	\ | 
 |   _bfd_sparc_elf_plt_sym_val | 
 | #define bfd_elf64_bfd_link_hash_table_create \ | 
 |   _bfd_sparc_elf_link_hash_table_create | 
 | #define elf_info_to_howto \ | 
 |   _bfd_sparc_elf_info_to_howto | 
 | #define elf_backend_copy_indirect_symbol \ | 
 |   _bfd_sparc_elf_copy_indirect_symbol | 
 | #define bfd_elf64_bfd_reloc_type_lookup \ | 
 |   _bfd_sparc_elf_reloc_type_lookup | 
 | #define bfd_elf64_bfd_reloc_name_lookup \ | 
 |   _bfd_sparc_elf_reloc_name_lookup | 
 | #define bfd_elf64_bfd_relax_section \ | 
 |   _bfd_sparc_elf_relax_section | 
 | #define bfd_elf64_new_section_hook \ | 
 |   _bfd_sparc_elf_new_section_hook | 
 |  | 
 | #define elf_backend_create_dynamic_sections \ | 
 |   _bfd_sparc_elf_create_dynamic_sections | 
 | #define elf_backend_relocs_compatible \ | 
 |   _bfd_elf_relocs_compatible | 
 | #define elf_backend_check_relocs \ | 
 |   _bfd_sparc_elf_check_relocs | 
 | #define elf_backend_adjust_dynamic_symbol \ | 
 |   _bfd_sparc_elf_adjust_dynamic_symbol | 
 | #define elf_backend_omit_section_dynsym \ | 
 |   _bfd_sparc_elf_omit_section_dynsym | 
 | #define elf_backend_size_dynamic_sections \ | 
 |   _bfd_sparc_elf_size_dynamic_sections | 
 | #define elf_backend_relocate_section \ | 
 |   _bfd_sparc_elf_relocate_section | 
 | #define elf_backend_finish_dynamic_symbol \ | 
 |   _bfd_sparc_elf_finish_dynamic_symbol | 
 | #define elf_backend_finish_dynamic_sections \ | 
 |   _bfd_sparc_elf_finish_dynamic_sections | 
 | #define elf_backend_fixup_symbol \ | 
 |   _bfd_sparc_elf_fixup_symbol | 
 |  | 
 | #define bfd_elf64_mkobject \ | 
 |   _bfd_sparc_elf_mkobject | 
 | #define elf_backend_object_p \ | 
 |   _bfd_sparc_elf_object_p | 
 | #define elf_backend_gc_mark_hook \ | 
 |   _bfd_sparc_elf_gc_mark_hook | 
 | #define elf_backend_init_index_section \ | 
 |   _bfd_elf_init_1_index_section | 
 |  | 
 | #define elf_backend_can_gc_sections 1 | 
 | #define elf_backend_can_refcount 1 | 
 | #define elf_backend_want_got_plt 0 | 
 | #define elf_backend_plt_readonly 0 | 
 | #define elf_backend_want_plt_sym 1 | 
 | #define elf_backend_got_header_size 8 | 
 | #define elf_backend_want_dynrelro 1 | 
 | #define elf_backend_rela_normal 1 | 
 |  | 
 | /* Section 5.2.4 of the ABI specifies a 256-byte boundary for the table.  */ | 
 | #define elf_backend_plt_alignment 8 | 
 |  | 
 | #include "elf64-target.h" | 
 |  | 
 | /* FreeBSD support */ | 
 | #undef  TARGET_BIG_SYM | 
 | #define TARGET_BIG_SYM sparc_elf64_fbsd_vec | 
 | #undef  TARGET_BIG_NAME | 
 | #define TARGET_BIG_NAME "elf64-sparc-freebsd" | 
 | #undef	ELF_OSABI | 
 | #define	ELF_OSABI ELFOSABI_FREEBSD | 
 |  | 
 | #undef  elf64_bed | 
 | #define elf64_bed				elf64_sparc_fbsd_bed | 
 |  | 
 | #include "elf64-target.h" | 
 |  | 
 | /* Solaris 2.  */ | 
 |  | 
 | #undef	TARGET_BIG_SYM | 
 | #define	TARGET_BIG_SYM				sparc_elf64_sol2_vec | 
 | #undef	TARGET_BIG_NAME | 
 | #define	TARGET_BIG_NAME				"elf64-sparc-sol2" | 
 |  | 
 | /* Restore default: we cannot use ELFOSABI_SOLARIS, otherwise ELFOSABI_NONE | 
 |    objects won't be recognized.  */ | 
 | #undef	ELF_OSABI | 
 |  | 
 | #undef elf64_bed | 
 | #define elf64_bed				elf64_sparc_sol2_bed | 
 |  | 
 | /* The 64-bit static TLS arena size is rounded to the nearest 16-byte | 
 |    boundary.  */ | 
 | #undef elf_backend_static_tls_alignment | 
 | #define elf_backend_static_tls_alignment	16 | 
 |  | 
 | #undef  elf_backend_strtab_flags | 
 | #define elf_backend_strtab_flags       SHF_STRINGS | 
 |  | 
 | static bool | 
 | elf64_sparc_copy_solaris_special_section_fields (const bfd *ibfd ATTRIBUTE_UNUSED, | 
 |                                   bfd *obfd ATTRIBUTE_UNUSED, | 
 |                                   const Elf_Internal_Shdr *isection ATTRIBUTE_UNUSED, | 
 |                                   Elf_Internal_Shdr *osection ATTRIBUTE_UNUSED) | 
 | { | 
 |   /* PR 19938: FIXME: Need to add code for setting the sh_info | 
 |      and sh_link fields of Solaris specific section types.  */ | 
 |   return false; | 
 | } | 
 |  | 
 | #undef  elf_backend_copy_special_section_fields | 
 | #define elf_backend_copy_special_section_fields elf64_sparc_copy_solaris_special_section_fields | 
 |  | 
 | #include "elf64-target.h" | 
 |  | 
 | #undef  elf_backend_strtab_flags | 
 | #undef  elf_backend_copy_special_section_fields |