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] Yet another updated STT_REGISTER patch


Hi!

I've updated the STT_REGISTER patch for Richard's new dynsym handling.
It is still not as clean as I'd like, but I wonder how much is that possible
provided the non-conceptual requirements of STT_REGISTER. E.g. I have to fix
up the dynsym symbols after generic code outputs them from dynlocal, because
they are global/weak, not local.
This patch also contains one hunk which fixes the dynsym handling for all
architectures, sh_info was always less by one than the value it should have.

1999-07-25  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. Put those symbols
	into dynlocal.
	(sparc64_elf_finish_dynamic_sections): Fix up DT_SPARC_REGISTER
	pointers to STT_REGISTER symbols in dynsym section.
	(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): Don't abort if dynlocal symbol
	has special shndx.
	Dynsym section's sh_info should point to first non-local symbol, not
	to last local symbol.
	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.
	* gas/doc/c-sparc.texi: Add description of #ignore special literal
	for .register pseudo-op.

--- bfd/elf.c.jj9	Fri Jul 23 16:46:06 1999
+++ bfd/elf.c	Sat Jul 24 16:22:35 1999
@@ -758,8 +758,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.
@@ -827,7 +840,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/elf-bfd.h.jj9	Fri Jul 23 16:45:59 1999
+++ bfd/elf-bfd.h	Sat Jul 24 20:52:16 1999
@@ -581,6 +581,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 ((bfd *, 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/elflink.h.jj9	Fri Jul 23 16:46:19 1999
+++ bfd/elflink.h	Sun Jul 25 15:14:55 1999
@@ -4257,12 +4257,22 @@ elf_bfd_final_link (abfd, info)
 	      sym.st_info = ELF_ST_INFO (STB_LOCAL,
 					 ELF_ST_TYPE (e->isym.st_info));
 
-	      s = bfd_section_from_elf_index (e->input_bfd, e->isym.st_shndx);
+	      if (e->isym.st_shndx == 0 || e->isym.st_shndx >= SHN_LORESERVE)
+		{
+		  sym.st_shndx = e->isym.st_shndx;
+		  sym.st_value = e->isym.st_value;
+		}
+	      else
+		{
+		  s = bfd_section_from_elf_index (e->input_bfd,
+						  e->isym.st_shndx);
 
-	      sym.st_shndx = elf_section_data (s->output_section)->this_idx;
-	      sym.st_value = (s->output_section->vma
-			      + s->output_offset
-			      + e->isym.st_value);
+		  sym.st_shndx =
+		    elf_section_data (s->output_section)->this_idx;
+		  sym.st_value = (s->output_section->vma
+				  + s->output_offset
+				  + e->isym.st_value);
+		}
 
 	      if (last_local < e->dynindx)
 		last_local = e->dynindx;
@@ -4272,7 +4282,7 @@ elf_bfd_final_link (abfd, info)
 	}
 
       elf_section_data (finfo.dynsym_sec->output_section)
-	->this_hdr.sh_info = last_local;
+	->this_hdr.sh_info = last_local + 1;
     }
 
   /* We get the global symbols from the hash table.  */
@@ -4283,6 +4293,18 @@ elf_bfd_final_link (abfd, info)
 			  (PTR) &eoinfo);
   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)
+	      (abfd, 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))
--- bfd/elf64-sparc.c.jj9	Sat Jul 24 15:31:17 1999
+++ bfd/elf64-sparc.c	Sun Jul 25 15:41:50 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,6 +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 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 *));
@@ -596,6 +605,52 @@ sparc64_elf_write_relocs (abfd, sec, dat
     }
 }
 
+/* Sparc64 ELF linker hash table.  */
+
+struct sparc64_elf_app_reg
+{
+  unsigned char bind;
+  unsigned short shndx;
+  bfd *abfd;
+  char *name;
+};
+
+struct sparc64_elf_link_hash_table
+{
+  struct elf_link_hash_table root;
+
+  struct sparc64_elf_app_reg app_regs [4];
+};
+
+/* 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.
@@ -1200,6 +1255,226 @@ 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 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;
+     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;
+
+  /* First we fixup any STT_REGISTER dynlocal symbols.
+     We need those symbols exactly as set up in the isym
+     member of dynlocal entries, while elf_bfd_final_link
+     does not understand this unusual handling.  */
+  if (elf_hash_table (info)->dynlocal)
+    {
+      struct elf_link_local_dynamic_entry *e;
+      bfd * dynobj = elf_hash_table (info)->dynobj;
+      asection *dynsymsec = bfd_get_section_by_name (dynobj, ".dynsym");
+      Elf64_External_Sym *dynsym = (Elf64_External_Sym *)dynsymsec->contents;
+      int c = 0;
+
+      for (e = elf_hash_table (info)->dynlocal; e ; e = e->next)
+	if (e->input_indx == -1)
+	  {
+	    bfd_elf64_swap_symbol_out (output_bfd, &e->isym,
+				       dynsym + e->dynindx);
+	    c++;
+	  }
+      elf_section_data (dynsymsec->output_section)
+	->this_hdr.sh_info -= c;
+    }
+
+  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
@@ -1499,6 +1774,11 @@ 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 reg;
+      struct sparc64_elf_app_reg * app_regs;
+      struct bfd_strtab_hash *dynstr;
+      struct elf_link_hash_table *eht = elf_hash_table (info);
+
       if (! info->shared)
 	{
 	  if (! bfd_elf64_add_dynamic_entry (info, DT_DEBUG, 0))
@@ -1525,6 +1805,52 @@ 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;
+      dynstr = eht->dynstr;
+
+      for (reg = 0; reg < 4; reg++)
+	if (app_regs [reg].name != NULL)
+	  {
+	    struct elf_link_local_dynamic_entry *entry, *e;
+	      
+	    if (! bfd_elf64_add_dynamic_entry (info, DT_SPARC_REGISTER, 0))
+	      return false;
+
+	    entry = (struct elf_link_local_dynamic_entry *)
+	      bfd_hash_allocate (&info->hash->table, sizeof (*entry));
+	    if (entry == NULL)
+	      return false;
+
+	    /* We cheat here a little bit: the symbol will not be local, so we
+	       put it at the end of the dynlocal linked list.  We will fix it later
+	       on, as we have to fix other fields anyway.  */
+	    entry->isym.st_value = reg < 2 ? reg + 2 : reg + 4;
+	    entry->isym.st_size = 0;
+	    if (*app_regs [reg].name != '\0')
+	      entry->isym.st_name = _bfd_stringtab_add (dynstr, app_regs [reg].name,
+							true, false);
+	    else
+	      entry->isym.st_name = 0;
+	    entry->isym.st_other = 0;
+	    entry->isym.st_info = ELF_ST_INFO (app_regs [reg].bind, STT_REGISTER);
+	    entry->isym.st_shndx = app_regs [reg].shndx;
+	    entry->next = NULL;
+	    entry->input_bfd = output_bfd;
+	    entry->input_indx = -1;
+
+	    if (eht->dynlocal == NULL)
+	      eht->dynlocal = entry;
+	    else
+	      {
+		for (e = eht->dynlocal; e->next; e = e->next)
+		  ;
+		e->next = entry;
+	      }
+	    eht->dynsymcount++;
+	  }
     }
 
   return true;
@@ -2351,6 +2677,7 @@ sparc64_elf_finish_dynamic_sections (out
      struct bfd_link_info *info;
 {
   bfd *dynobj;
+  int stt_regidx = -1;
   asection *sdyn;
   asection *sgot;
 
@@ -2381,6 +2708,17 @@ 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 (stt_regidx == -1)
+		{
+		  stt_regidx =
+		    _bfd_elf_link_lookup_local_dynindx (info, output_bfd, -1);
+		  if (stt_regidx == -1)
+		    return false;
+		}
+	      dyn.d_un.d_val = stt_regidx++;
+	      bfd_elf64_swap_dyn_out (output_bfd, &dyn, dyncon);
+	      /* fallthrough */
 	    default:	      name = NULL; size = false; break;
 	    }
 
@@ -2510,7 +2848,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.  */
 
@@ -2575,6 +2940,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 \
@@ -2588,6 +2956,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 \
@@ -2600,6 +2974,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/elfxx-target.h.jj9	Fri Jul 23 16:46:24 1999
+++ bfd/elfxx-target.h	Sat Jul 24 16:22:35 1999
@@ -297,6 +297,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
@@ -369,6 +375,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,
--- binutils/readelf.c.jj9	Fri Jul 23 16:57:05 1999
+++ binutils/readelf.c	Sun Jul 25 15:25:57 1999
@@ -129,6 +129,7 @@ static bfd_vma (*         byte_get)     
 static bfd_vma            byte_get_little_endian      PARAMS ((unsigned char *, int));
 static bfd_vma            byte_get_big_endian         PARAMS ((unsigned char *, int));
 static const char *       get_mips_dynamic_type       PARAMS ((unsigned long));
+static const char *       get_sparc64_dynamic_type    PARAMS ((unsigned long));
 static const char *       get_dynamic_type            PARAMS ((unsigned long));
 static int                dump_relocations            PARAMS ((FILE *, unsigned long, unsigned long, Elf_Internal_Sym *, unsigned long, char *, int));
 static char *             get_file_type               PARAMS ((unsigned));
@@ -841,6 +842,18 @@ get_mips_dynamic_type (type)
 }
 
 static const char *
+get_sparc64_dynamic_type (type)
+     unsigned long type;
+{
+  switch (type)
+    {
+    case DT_SPARC_REGISTER: return "SPARC_REGISTER";
+    default:
+      return NULL;
+    }
+}    
+
+static const char *
 get_dynamic_type (type)
      unsigned long type;
 {
@@ -913,6 +926,9 @@ get_dynamic_type (type)
 	    case EM_MIPS:
 	    case EM_MIPS_RS4_BE:
 	      result = get_mips_dynamic_type (type);
+	      break;
+	    case EM_SPARCV9:
+	      result = get_sparc64_dynamic_type (type);
 	      break;
 	    default:
 	      result = NULL;
--- gas/config/tc-sparc.c.jj9	Fri Jul 23 17:00:15 1999
+++ gas/config/tc-sparc.c	Mon Jul 26 16:00:18 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,123 @@ 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|#ignore}
+   */
+
+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|#ignore}"));
+  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") && strcmp (regname, "ignore"))
+	as_bad (_("register syntax is .register %%g[2367],{#scratch|symbolname|#ignore}"));
+      if (regname [0] == 'i')
+	regname = NULL;
+      else
+	regname = "";
+    }
+  else
+    {
+      regname = input_line_pointer;
+      c = get_symbol_end ();
+    }
+  if (sparc_arch_size == 64)
+    {
+      if (globals [reg])
+	{
+	  if ((regname && globals [reg] != (symbolS *)1
+	       && strcmp (S_GET_NAME (globals [reg]), regname))
+	      || ((regname != NULL) ^ (globals [reg] != (symbolS *)1)))
+	    as_bad (_("redefinition of global register"));
+	}
+      else
+	{
+	  if (regname == NULL)
+	    globals [reg] = (symbolS *)1;
+	  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.jj9	Mon Jul 26 15:53:47 1999
+++ gas/config/tc-sparc.h	Mon Jul 26 15:38:56 1999
@@ -134,6 +134,11 @@ 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
--- gas/doc/c-sparc.texi.jj9	Fri Jul 23 15:31:34 1999
+++ gas/doc/c-sparc.texi	Sun Jul 25 16:15:03 1999
@@ -160,8 +160,11 @@ line is also ignored.
 @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.
+the symbol name for that register.  If symbol name is @code{#scratch},
+it is a scratch register, if it is @code{#ignore}, it just surpresses any
+errors about using undeclared global register, but does not emit any
+information about it into the object file.  This can be useful e.g. if you
+save the register before use and restore it after.
 
 @cindex @code{reserve} directive, SPARC
 @item .reserve

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.9 on a sparc64 machine (1343.49 BogoMips)
___________________________________________________________________

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