+/* 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 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 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_archive_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: %s in %s, previously %s in %s"),
+ (int) sym->st_value,
+ **namep ? *namep : "#scratch", bfd_archive_filename (abfd),
+ *p->name ? p->name : "#scratch", bfd_archive_filename (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)
+ (_("Symbol `%s' has differing types: REGISTER in %s, previously %s in %s"),
+ *namep, bfd_archive_filename (abfd),
+ stt_types[type], bfd_archive_filename (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->hash->creator == abfd->xvec)
+ {
+ 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: %s in %s, previously REGISTER in %s"),
+ *namep, stt_types[type], bfd_archive_filename (abfd),
+ bfd_archive_filename (p->abfd));
+ return false;
+ }
+ }
+ return true;
+}
+
+/* This function takes care of emiting STT_REGISTER symbols
+ which we cannot easily keep in the symbol hash table. */
+
+static boolean
+sparc64_elf_output_arch_syms (output_bfd, info, finfo, func)
+ bfd *output_bfd ATTRIBUTE_UNUSED;
+ 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;
+
+ /* We arranged in size_dynamic_sections to put the STT_REGISTER entries
+ at the end of the dynlocal list, so they came at the end of the local
+ symbols in the symtab. Except that they aren't STB_LOCAL, so we need
+ to back up symtab->sh_info. */
+ if (elf_hash_table (info)->dynlocal)
+ {
+ bfd * dynobj = elf_hash_table (info)->dynobj;
+ asection *dynsymsec = bfd_get_section_by_name (dynobj, ".dynsym");
+ struct elf_link_local_dynamic_entry *e;
+
+ for (e = elf_hash_table (info)->dynlocal; e ; e = e->next)
+ if (e->input_indx == -1)
+ break;
+ if (e)
+ {
+ elf_section_data (dynsymsec->output_section)->this_hdr.sh_info
+ = e->dynindx;
+ }
+ }
+
+ 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 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;
+ }
+}
+