This is the mail archive of the binutils@sources.redhat.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] Garbage collect and suffix merge .dynstr and .shstrtab (take 2)


Hi!

Alex Larsson gave me a testcase where my yesterday's patch would leave
_DYNAMIC and _GLOBAL_OFFSET_TABLE_ in .dynstr twice (if it was first
_bfd_elf_strtab_add'ed, then _bfd_elf_strtab_delref'ed and then again
_bfd_elf_strtab_add'ed with the same string).
Fixed thusly, ok to commit:

2001-11-06  Jakub Jelinek  <jakub@redhat.com>

	* Makefile.am (BFD32_BACKENDS): Add elf-strtab.lo.
	(BFD32_BACKENDS_CFILES): Add elf-strtab.c.
	(elf-strtab.lo): Add rule.
	* Makefile.in: Rebuilt.
	* configure.in (elf): Add elf-strtab.lo.
	* configure: Rebuilt.
	* elf-bfd.h (elf_strtab_hash): Forward declare.
	(struct elf_link_hash_table): Change dynstr type to
	struct elf_strtab_hash *.
	(struct elf_obj_tdata): Change strtab_ptr type to
	struct elf_strtab_hash *.
	(_bfd_elf_strtab_init, _bfd_elf_strtab_free, _bfd_elf_strtab_add,
	_bfd_elf_strtab_addref, _bfd_elf_strtab_delref,
	_bfd_elf_strtab_clear_all_refs, _bfd_elf_strtab_size,
	_bfd_elf_strtab_offset, _bfd_elf_strtab_emit,
	_bfd_elf_strtab_finalize): New prototypes.
	* elf-strtab.c: New file.
	* elflink.h (elf_link_add_object_symbols): Use _bfd_elf_strtab_add
	and _bfd_elf_strtab_size instead of _bfd_stringtab calls.
	Call _bfd_elf_strtab_delref if DT_NEEDED entry is not needed or
	when forcing dynamic symbol to local.
	(elf_link_create_dynamic_sections): Call
	_bfd_elf_strtab_init instead of elf_stringtab_init.
	(elf_link_record_local_dynamic_symbol): Likewise, change
	dynstr type.  Use _bfd_elf_strtab functions instead of
	_bfd_stringtab calls.
	(size_dynamic_sections): Use _bfd_elf_strtab functions instead of
	_bfd_stringtab calls.  For DT_RUNPATH and Verdaux vda_name fields,
	call _bfd_elf_strtab_addref.  Call elf_finalize_dynstr.
	(elf_adjust_dynstr_offsets, elf_finalize_dynstr): New functions.
	(elf_fix_symbol_flags): Call _bfd_elf_strtab_delref when forcing
	dynamic symbol to local.
	(elf_link_assign_sym_version): Likewise.
	(elf_bfd_final_link): Call _bfd_elf_strtab_emit instead of
	_bfd_stringtab_emit.
	* elflink.c (_bfd_elf_link_record_dynamic_symbol): Change dynstr
	type.  Call _bfd_elf_strtab functions instead of
	_bfd_stringtab functions.
	* elf64-sparc.c (sparc64_elf_size_dynamic_sections): Likewise.
	* elf.c (_bfd_elf_init_reloc_shdr): Likewise.
	(elf_fake_sections): Likewise.
	(assign_section_numbers): Call _bfd_elf_strtab_clear_all_refs
	on shstrtab hash table, call _bfd_elf_strtab_addref on each section
	name in the output.  Call _bfd_elf_strtab_finalize and
	use _bfd_elf_strtab_offset to finalize sh_name section header fields.
	(_bfd_elf_compute_section_file_positions): Use _bfd_elf_strtab_size
	instead of _bfd_stringtab_size.
	(prep_headers): Change shstrtab type.
	Use _bfd_elf_strtab calls instead of _bfd_stringtab calls.
	
--- bfd/Makefile.am.jj	Fri Nov  2 10:58:28 2001
+++ bfd/Makefile.am	Sat Nov  3 22:23:15 2001
@@ -215,6 +215,7 @@ BFD32_BACKENDS = \
 	elf32-v850.lo \
 	elf32.lo \
 	elflink.lo \
+	elf-strtab.lo \
 	epoc-pe-arm.lo \
 	epoc-pei-arm.lo \
 	hp300bsd.lo \
@@ -355,6 +356,7 @@ BFD32_BACKENDS_CFILES = \
 	elf32-v850.c \
 	elf32.c \
 	elflink.c \
+	elf-strtab.c \
 	epoc-pe-arm.c \
 	epoc-pei-arm.c \
 	hp300bsd.c \
@@ -1129,6 +1131,7 @@ elf32.lo: elf32.c elfcode.h $(INCDIR)/fi
 elflink.lo: elflink.c $(INCDIR)/filenames.h $(INCDIR)/bfdlink.h \
   elf-bfd.h $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h \
   $(INCDIR)/elf/external.h
+elf-strtab.lo: elf-strtab.c $(INCDIR)/filenames.h $(INCDIR)/hashtab.h
 epoc-pe-arm.lo: epoc-pe-arm.c pe-arm.c $(INCDIR)/filenames.h \
   coff-arm.c $(INCDIR)/coff/arm.h $(INCDIR)/coff/external.h \
   $(INCDIR)/coff/internal.h $(INCDIR)/coff/pe.h libcoff.h \
--- bfd/elf-bfd.h.jj	Thu Oct 11 12:37:10 2001
+++ bfd/elf-bfd.h	Sun Nov  4 15:41:36 2001
@@ -79,6 +79,8 @@ typedef struct
 
 } elf_symbol_type;
 
+struct elf_strtab_hash;
+
 /* ELF linker hash table entries.  */
 
 struct elf_link_hash_entry
@@ -248,7 +250,7 @@ struct elf_link_hash_table
 
   /* The string table of dynamic symbols, which becomes the .dynstr
      section.  */
-  struct bfd_strtab_hash *dynstr;
+  struct elf_strtab_hash *dynstr;
 
   /* The number of buckets in the hash table in the .hash section.
      This is based on the number of dynamic symbols.  */
@@ -891,7 +893,7 @@ struct elf_obj_tdata
   Elf_Internal_Shdr **elf_sect_ptr;
   Elf_Internal_Phdr *phdr;
   struct elf_segment_map *segment_map;
-  struct bfd_strtab_hash *strtab_ptr;
+  struct elf_strtab_hash *strtab_ptr;
   int num_locals;
   int num_globals;
   int num_section_syms;
@@ -1202,6 +1204,28 @@ extern boolean _bfd_elf_create_dynamic_s
   PARAMS ((bfd *, struct bfd_link_info *));
 extern struct bfd_strtab_hash *_bfd_elf_stringtab_init
   PARAMS ((void));
+
+extern struct elf_strtab_hash * _bfd_elf_strtab_init
+  PARAMS ((void));
+extern void _bfd_elf_strtab_free
+  PARAMS ((struct elf_strtab_hash *));
+extern bfd_size_type _bfd_elf_strtab_add
+  PARAMS ((struct elf_strtab_hash *, const char *, boolean));
+extern void _bfd_elf_strtab_addref
+  PARAMS ((struct elf_strtab_hash *, bfd_size_type));
+extern void _bfd_elf_strtab_delref
+  PARAMS ((struct elf_strtab_hash *, bfd_size_type));
+extern void _bfd_elf_strtab_clear_all_refs
+  PARAMS ((struct elf_strtab_hash *));
+extern bfd_size_type _bfd_elf_strtab_size
+  PARAMS ((struct elf_strtab_hash *));
+extern bfd_size_type _bfd_elf_strtab_offset
+  PARAMS ((struct elf_strtab_hash *, bfd_size_type));
+extern boolean _bfd_elf_strtab_emit
+  PARAMS ((bfd *, struct elf_strtab_hash *));
+extern void _bfd_elf_strtab_finalize
+  PARAMS ((struct elf_strtab_hash *));
+
 extern boolean _bfd_elf_link_record_dynamic_symbol
   PARAMS ((struct bfd_link_info *, struct elf_link_hash_entry *));
 extern long _bfd_elf_link_lookup_local_dynindx
--- bfd/elf-strtab.c.jj	Fri Nov  2 18:54:59 2001
+++ bfd/elf-strtab.c	Tue Nov  6 17:27:24 2001
@@ -0,0 +1,458 @@
+/* ELF strtab with GC and suffix merging support.
+   Copyright 2001 Free Software Foundation, Inc.
+   Written by Jakub Jelinek <jakub@redhat.com>.
+
+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 2 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#include "bfd.h"
+#include "sysdep.h"
+#include "libbfd.h"
+#include "elf-bfd.h"
+#include "hashtab.h"
+
+/* An entry in the strtab hash table.  */
+
+struct elf_strtab_hash_entry
+{
+  struct bfd_hash_entry root;
+  /* Length of this entry.  */
+  unsigned int len;
+  unsigned int refcount;
+  union {
+    /* Index within the merged section.  */
+    bfd_size_type index;
+    /* Entry this is a suffix of (if len is 0).  */
+    struct elf_strtab_hash_entry *suffix;
+  } u;
+};
+
+/* The strtab hash table.  */
+
+struct elf_strtab_hash
+{
+  struct bfd_hash_table table;
+  /* Next available index.  */
+  bfd_size_type size;
+  /* Number of array entries alloced.  */
+  bfd_size_type alloced;
+  /* Final strtab size.  */
+  bfd_size_type sec_size;
+  /* Array of pointers to strtab entries.  */
+  struct elf_strtab_hash_entry **array;
+};
+
+static struct bfd_hash_entry *elf_strtab_hash_newfunc
+  PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, const char *));
+static int cmplengthentry PARAMS ((const PTR, const PTR));
+static int last4_eq PARAMS ((const PTR, const PTR));
+static int last_eq PARAMS ((const PTR, const PTR));
+
+/* Routine to create an entry in a section merge hashtab.  */
+
+static struct bfd_hash_entry *
+elf_strtab_hash_newfunc (entry, table, string)
+     struct bfd_hash_entry *entry;
+     struct bfd_hash_table *table;
+     const char *string;
+{
+  struct elf_strtab_hash_entry *ret = (struct elf_strtab_hash_entry *) entry;
+
+  /* Allocate the structure if it has not already been allocated by a
+     subclass.  */
+  if (ret == (struct elf_strtab_hash_entry *) NULL)
+    ret = ((struct elf_strtab_hash_entry *)
+	   bfd_hash_allocate (table, sizeof (struct elf_strtab_hash_entry)));
+  if (ret == (struct elf_strtab_hash_entry *) NULL)
+    return NULL;
+
+  /* Call the allocation method of the superclass.  */
+  ret = ((struct elf_strtab_hash_entry *)
+	 bfd_hash_newfunc ((struct bfd_hash_entry *) ret, table, string));
+
+  if (ret)
+    {
+      /* Initialize the local fields.  */
+      ret->u.index = -1;
+      ret->refcount = 0;
+    }
+
+  return (struct bfd_hash_entry *)ret;
+}
+
+/* Create a new hash table.  */
+
+struct elf_strtab_hash *
+_bfd_elf_strtab_init ()
+{
+  struct elf_strtab_hash *table;
+  bfd_size_type amt = sizeof (struct elf_strtab_hash);
+
+  table = (struct elf_strtab_hash *) bfd_malloc (amt);
+  if (table == NULL)
+    return NULL;
+
+  if (! bfd_hash_table_init (&table->table, elf_strtab_hash_newfunc))
+    {
+      free (table);
+      return NULL;
+    }
+
+  table->sec_size = 0;
+  table->size = 1;
+  table->alloced = 64;
+  amt = sizeof (struct elf_strtab_hasn_entry *);
+  table->array = (struct elf_strtab_hash_entry **)
+		 bfd_malloc (table->alloced * amt);
+  if (table->array == NULL)
+    {
+      free (table);
+      return NULL;
+    }
+
+  table->array[0] = NULL;
+
+  return table;
+}
+
+/* Free a strtab.  */
+
+void
+_bfd_elf_strtab_free (tab)
+     struct elf_strtab_hash *tab;
+{
+  bfd_hash_table_free (&tab->table);
+  free (tab->array);
+  free (tab);
+}
+
+/* Get the index of an entity in a hash table, adding it if it is not
+   already present.  */
+
+bfd_size_type
+_bfd_elf_strtab_add (tab, str, copy)
+     struct elf_strtab_hash *tab;
+     const char *str;
+     boolean copy;
+{
+  register struct elf_strtab_hash_entry *entry;
+
+  /* We handle this specially, since we don't want to do refcounting
+     on it.  */
+  if (*str == '\0')
+    return 0;
+
+  BFD_ASSERT (tab->sec_size == 0);
+  entry = (struct elf_strtab_hash_entry *)
+	  bfd_hash_lookup (&tab->table, str, true, copy);
+
+  if (entry == NULL)
+    return (bfd_size_type) -1;
+
+  entry->refcount++;
+  if (entry->len == 0)
+    {
+      entry->len = strlen (str) + 1;
+      if (tab->size == tab->alloced)
+	{
+	  bfd_size_type amt = sizeof (struct elf_strtab_hash_entry *);
+	  tab->alloced *= 2;
+	  tab->array = (struct elf_strtab_hash_entry **)
+		       bfd_realloc (tab->array, tab->alloced * amt);
+	  if (tab->array == NULL)
+	    return (bfd_size_type) -1;
+	}
+
+      entry->u.index = tab->size++;
+      tab->array[entry->u.index] = entry;
+    }
+  return entry->u.index;
+}
+
+void
+_bfd_elf_strtab_addref (tab, idx)
+     struct elf_strtab_hash *tab;
+     bfd_size_type idx;
+{
+  if (idx == 0 || idx == (bfd_size_type) -1)
+    return;
+  BFD_ASSERT (tab->sec_size == 0);
+  BFD_ASSERT (idx < tab->size);
+  ++tab->array[idx]->refcount;
+}
+
+void
+_bfd_elf_strtab_delref (tab, idx)
+     struct elf_strtab_hash *tab;
+     bfd_size_type idx;
+{
+  if (idx == 0 || idx == (bfd_size_type) -1)
+    return;
+  BFD_ASSERT (tab->sec_size == 0);
+  BFD_ASSERT (idx < tab->size);
+  BFD_ASSERT (tab->array[idx]->refcount > 0);
+  --tab->array[idx]->refcount;
+}
+
+void
+_bfd_elf_strtab_clear_all_refs (tab)
+     struct elf_strtab_hash *tab;
+{
+  bfd_size_type idx;
+
+  for (idx = 1; idx < tab->size; ++idx)
+    tab->array[idx]->refcount = 0;
+}
+
+bfd_size_type
+_bfd_elf_strtab_size (tab)
+     struct elf_strtab_hash *tab;
+{
+  return tab->sec_size ? tab->sec_size : tab->size;
+}
+
+bfd_size_type
+_bfd_elf_strtab_offset (tab, idx)
+     struct elf_strtab_hash *tab;
+     bfd_size_type idx;
+{
+  struct elf_strtab_hash_entry *entry;
+
+  if (idx == 0)
+    return 0;
+  BFD_ASSERT (idx < tab->size);
+  BFD_ASSERT (tab->sec_size);
+  entry = tab->array[idx];
+  BFD_ASSERT (entry->refcount > 0);
+  entry->refcount--;
+  return tab->array[idx]->u.index;
+}
+
+boolean
+_bfd_elf_strtab_emit (abfd, tab)
+     register bfd *abfd;
+     struct elf_strtab_hash *tab;
+{
+  bfd_size_type off = 1, i;
+
+  if (bfd_bwrite ("", 1, abfd) != 1)
+    return false;
+
+  for (i = 1; i < tab->size; ++i)
+    {
+      register const char *str;
+      register size_t len;
+
+      str = tab->array[i]->root.string;
+      len = tab->array[i]->len;
+      BFD_ASSERT (tab->array[i]->refcount == 0);
+      if (len == 0)
+	continue;
+
+      if (bfd_bwrite ((PTR) str, (bfd_size_type) len, abfd) != len)
+	return false;
+
+      off += len;
+    }
+
+  BFD_ASSERT (off == tab->sec_size);
+  return true;
+}
+
+/* Compare two elf_strtab_hash_entry structures.  This is called via qsort.  */
+
+static int
+cmplengthentry (a, b)
+     const PTR a;
+     const PTR b;
+{
+  struct elf_strtab_hash_entry * A = *(struct elf_strtab_hash_entry **) a;
+  struct elf_strtab_hash_entry * B = *(struct elf_strtab_hash_entry **) b;
+
+  if (A->len < B->len)
+    return 1;
+  else if (A->len > B->len)
+    return -1;
+
+  return memcmp (A->root.string, B->root.string, A->len);
+}
+
+static int
+last4_eq (a, b)
+     const PTR a;
+     const PTR b;
+{
+  struct elf_strtab_hash_entry * A = (struct elf_strtab_hash_entry *) a;
+  struct elf_strtab_hash_entry * B = (struct elf_strtab_hash_entry *) b;
+
+  if (memcmp (A->root.string + A->len - 5, B->root.string + B->len - 5, 4)
+      != 0)
+    /* This was a hashtable collision.  */
+    return 0;
+
+  if (A->len <= B->len)
+    /* B cannot be a suffix of A unless A is equal to B, which is guaranteed
+       not to be equal by the hash table.  */
+    return 0;
+
+  return memcmp (A->root.string + (A->len - B->len),
+		 B->root.string, B->len - 5) == 0;
+}
+
+static int
+last_eq (a, b)
+     const PTR a;
+     const PTR b;
+{
+  struct elf_strtab_hash_entry * A = (struct elf_strtab_hash_entry *) a;
+  struct elf_strtab_hash_entry * B = (struct elf_strtab_hash_entry *) b;
+
+  if (B->len >= 5)
+    /* Longer strings are just pushed into the hash table,
+       they'll be used when looking up for very short strings.  */
+    return 0;
+
+  if (memcmp (A->root.string + A->len - 2, B->root.string + B->len - 2, 1)
+      != 0)
+    /* This was a hashtable collision.  */
+    return 0;
+
+  if (A->len <= B->len)
+    /* B cannot be a suffix of A unless A is equal to B, which is guaranteed
+       not to be equal by the hash table.  */
+    return 0;
+
+  return memcmp (A->root.string + (A->len - B->len),
+		 B->root.string, B->len - 2) == 0;
+}
+
+/* This function assigns final string table offsets for used strings,
+   merging strings matching suffixes of longer strings if possible.  */
+
+void
+_bfd_elf_strtab_finalize (tab)
+     struct elf_strtab_hash *tab;
+{
+  struct elf_strtab_hash_entry **array, **a, **end, *e;
+  htab_t lasttab = NULL, last4tab = NULL;
+  bfd_size_type size, amt, i;
+
+  /* Now sort the strings by length, longest first.  */
+  array = NULL;
+  amt = tab->size * sizeof (struct elf_strtab_hash_entry *);
+  array = (struct elf_strtab_hash_entry **) bfd_malloc (amt);
+  if (array == NULL)
+    goto alloc_failure;
+
+  for (i = 1, a = array; i < tab->size; ++i)
+    if (tab->array[i]->refcount)
+      *a++ = tab->array[i];
+    else
+      tab->array[i]->len = 0;
+
+  size = a - array;
+
+  qsort (array, size, sizeof (struct elf_strtab_hash_entry *), cmplengthentry);
+
+  last4tab = htab_create (size * 4, NULL, last4_eq, NULL);
+  lasttab = htab_create (size * 4, NULL, last_eq, NULL);
+  if (lasttab == NULL || last4tab == NULL)
+    goto alloc_failure;
+
+  /* Now insert the strings into hash tables (strings with last 4 characters
+     and strings with last character equal), look for longer strings which
+     we're suffix of.  */
+  for (a = array, end = array + size; a < end; a++)
+    {
+      register hashval_t hash;
+      unsigned int c;
+      unsigned int i;
+      const unsigned char *s;
+      PTR *p;
+
+      e = *a;
+      if (e->len > 4)
+	{
+	  s = e->root.string + e->len - 1;
+	  hash = 0;
+	  for (i = 0; i < 4; i++)
+	    {
+	      c = *--s;
+	      hash += c + (c << 17);
+	      hash ^= hash >> 2;
+	    }
+	  p = htab_find_slot_with_hash (last4tab, e, hash, INSERT);
+	  if (p == NULL)
+	    goto alloc_failure;
+	  if (*p)
+	    {
+	      struct elf_strtab_hash_entry *ent;
+
+	      ent = (struct elf_strtab_hash_entry *) *p;
+	      e->u.suffix = ent;
+	      e->len = 0;
+	      continue;
+	    }
+	  else
+	    *p = (PTR) e;
+	}
+      c = (unsigned char) e->root.string[e->len - 1];
+      p = htab_find_slot_with_hash (lasttab, e, c, INSERT);
+      if (p == NULL)
+	goto alloc_failure;
+      if (*p)
+	{
+	  struct elf_strtab_hash_entry *ent;
+
+	  ent = (struct elf_strtab_hash_entry *) *p;
+	  e->u.suffix = ent;
+	  e->len = 0;
+	}
+      else
+	*p = (PTR) e;
+    }
+
+alloc_failure:
+  if (array)
+    free (array);
+  if (lasttab)
+    htab_delete (lasttab);
+  if (last4tab)
+    htab_delete (last4tab);
+
+  /* Now assign positions to the strings we want to keep.  */
+  size = 1;
+  for (i = 1; i < tab->size; ++i)
+    {
+      e = tab->array[i];
+      if (e->refcount && e->len)
+	{
+	  e->u.index = size;
+	  size += e->len;
+	}
+    }
+
+  tab->sec_size = size;
+
+  /* And now adjust the rest.  */
+  for (i = 1; i < tab->size; ++i)
+    {
+      e = tab->array[i];
+      if (e->refcount && ! e->len)
+	e->u.index = e->u.suffix->u.index
+		     + (e->u.suffix->len - strlen (e->root.string) - 1);
+    }
+}
--- bfd/Makefile.in.jj	Fri Nov  2 10:58:28 2001
+++ bfd/Makefile.in	Sat Nov  3 22:23:49 2001
@@ -342,6 +342,7 @@ BFD32_BACKENDS = \
 	elf32-v850.lo \
 	elf32.lo \
 	elflink.lo \
+	elf-strtab.lo \
 	epoc-pe-arm.lo \
 	epoc-pei-arm.lo \
 	hp300bsd.lo \
@@ -483,6 +484,7 @@ BFD32_BACKENDS_CFILES = \
 	elf32-v850.c \
 	elf32.c \
 	elflink.c \
+	elf-strtab.c \
 	epoc-pe-arm.c \
 	epoc-pei-arm.c \
 	hp300bsd.c \
@@ -1672,6 +1674,7 @@ elf32.lo: elf32.c elfcode.h $(INCDIR)/fi
 elflink.lo: elflink.c $(INCDIR)/filenames.h $(INCDIR)/bfdlink.h \
   elf-bfd.h $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h \
   $(INCDIR)/elf/external.h
+elf-strtab.lo: elf-strtab.c $(INCDIR)/filenames.h $(INCDIR)/hashtab.h
 epoc-pe-arm.lo: epoc-pe-arm.c pe-arm.c $(INCDIR)/filenames.h \
   coff-arm.c $(INCDIR)/coff/arm.h $(INCDIR)/coff/external.h \
   $(INCDIR)/coff/internal.h $(INCDIR)/coff/pe.h libcoff.h \
--- bfd/elflink.h.jj	Fri Nov  2 10:58:31 2001
+++ bfd/elflink.h	Mon Nov  5 11:52:52 2001
@@ -44,6 +44,8 @@ static boolean elf_merge_symbol
 	   boolean *, boolean *, boolean *, boolean));
 static boolean elf_export_symbol
   PARAMS ((struct elf_link_hash_entry *, PTR));
+static boolean elf_finalize_dynstr
+  PARAMS ((bfd *, struct bfd_link_info *));
 static boolean elf_fix_symbol_flags
   PARAMS ((struct elf_link_hash_entry *, struct elf_info_failed *));
 static boolean elf_adjust_dynamic_symbol
@@ -1294,13 +1296,12 @@ elf_link_add_object_symbols (abfd, info)
       if (add_needed)
 	{
 	  /* Add a DT_NEEDED entry for this dynamic object.  */
-	  oldsize = _bfd_stringtab_size (hash_table->dynstr);
-	  strindex = _bfd_stringtab_add (hash_table->dynstr, name,
-					 true, false);
+	  oldsize = _bfd_elf_strtab_size (hash_table->dynstr);
+	  strindex = _bfd_elf_strtab_add (hash_table->dynstr, name, false);
 	  if (strindex == (bfd_size_type) -1)
 	    goto error_return;
 
-	  if (oldsize == _bfd_stringtab_size (hash_table->dynstr))
+	  if (oldsize == _bfd_elf_strtab_size (hash_table->dynstr))
 	    {
 	      asection *sdyn;
 	      Elf_External_Dyn *dyncon, *dynconend;
@@ -1328,6 +1329,7 @@ elf_link_add_object_symbols (abfd, info)
 			free (buf);
 		      if (extversym != NULL)
 			free (extversym);
+		      _bfd_elf_strtab_delref (hash_table->dynstr, strindex);
 		      return true;
 		    }
 		}
@@ -1965,6 +1967,8 @@ elf_link_add_object_symbols (abfd, info)
 	      case STV_HIDDEN:
 		h->elf_link_hash_flags |= ELF_LINK_FORCED_LOCAL;
 		(*bed->elf_backend_hide_symbol) (info, h);
+		_bfd_elf_strtab_delref (hash_table->dynstr,
+					h->dynstr_index);
 		break;
 	      }
 
@@ -1983,15 +1987,13 @@ elf_link_add_object_symbols (abfd, info)
 		 have to make sure there is a DT_NEEDED entry for it.  */
 
 	      dt_needed = false;
-	      oldsize = _bfd_stringtab_size (hash_table->dynstr);
-	      strindex = _bfd_stringtab_add (hash_table->dynstr,
-	      				     elf_dt_soname (abfd),
-					     true, false);
+	      oldsize = _bfd_elf_strtab_size (hash_table->dynstr);
+	      strindex = _bfd_elf_strtab_add (hash_table->dynstr,
+					      elf_dt_soname (abfd), false);
 	      if (strindex == (bfd_size_type) -1)
 		goto error_return;
 
-	      if (oldsize
-		  == _bfd_stringtab_size (hash_table->dynstr))
+	      if (oldsize == _bfd_elf_strtab_size (hash_table->dynstr))
 		{
 		  asection *sdyn;
 		  Elf_External_Dyn *dyncon, *dynconend;
@@ -2290,7 +2292,7 @@ elf_link_create_dynamic_sections (abfd, 
   /* Create a strtab to hold the dynamic symbol names.  */
   if (elf_hash_table (info)->dynstr == NULL)
     {
-      elf_hash_table (info)->dynstr = elf_stringtab_init ();
+      elf_hash_table (info)->dynstr = _bfd_elf_strtab_init ();
       if (elf_hash_table (info)->dynstr == NULL)
 	return false;
     }
@@ -2390,7 +2392,7 @@ elf_link_record_local_dynamic_symbol (in
 {
   struct elf_link_local_dynamic_entry *entry;
   struct elf_link_hash_table *eht;
-  struct bfd_strtab_hash *dynstr;
+  struct elf_strtab_hash *dynstr;
   Elf_External_Sym esym;
   unsigned long dynstr_index;
   char *name;
@@ -2426,12 +2428,12 @@ elf_link_record_local_dynamic_symbol (in
   if (dynstr == NULL)
     {
       /* Create a strtab to hold the dynamic symbol names.  */
-      elf_hash_table (info)->dynstr = dynstr = _bfd_elf_stringtab_init ();
+      elf_hash_table (info)->dynstr = dynstr = _bfd_elf_strtab_init ();
       if (dynstr == NULL)
 	return false;
     }
 
-  dynstr_index = _bfd_stringtab_add (dynstr, name, true, false);
+  dynstr_index = _bfd_elf_strtab_add (dynstr, name, false);
   if (dynstr_index == (unsigned long) -1)
     return false;
   entry->isym.st_name = dynstr_index;
@@ -2949,8 +2951,8 @@ NAME(bfd_elf,size_dynamic_sections) (out
 
       if (soname != NULL)
 	{
-	  soname_indx = _bfd_stringtab_add (elf_hash_table (info)->dynstr,
-					    soname, true, true);
+	  soname_indx = _bfd_elf_strtab_add (elf_hash_table (info)->dynstr,
+					     soname, true);
 	  if (soname_indx == (bfd_size_type) -1
 	      || ! elf_add_dynamic_entry (info, (bfd_vma) DT_SONAME,
 					  soname_indx))
@@ -2969,8 +2971,10 @@ NAME(bfd_elf,size_dynamic_sections) (out
 	{
 	  bfd_size_type indx;
 
-	  indx = _bfd_stringtab_add (elf_hash_table (info)->dynstr, rpath,
-				     true, true);
+	  indx = _bfd_elf_strtab_add (elf_hash_table (info)->dynstr, rpath,
+				      true);
+	  if (info->new_dtags)
+	    _bfd_elf_strtab_addref (elf_hash_table (info)->dynstr, indx);
 	  if (indx == (bfd_size_type) -1
 	      || ! elf_add_dynamic_entry (info, (bfd_vma) DT_RPATH, indx)
 	      || (info->new_dtags
@@ -2983,8 +2987,8 @@ NAME(bfd_elf,size_dynamic_sections) (out
 	{
 	  bfd_size_type indx;
 
-	  indx = _bfd_stringtab_add (elf_hash_table (info)->dynstr,
-				     filter_shlib, true, true);
+	  indx = _bfd_elf_strtab_add (elf_hash_table (info)->dynstr,
+				      filter_shlib, true);
 	  if (indx == (bfd_size_type) -1
 	      || ! elf_add_dynamic_entry (info, (bfd_vma) DT_FILTER, indx))
 	    return false;
@@ -2998,8 +3002,8 @@ NAME(bfd_elf,size_dynamic_sections) (out
 	    {
 	      bfd_size_type indx;
 
-	      indx = _bfd_stringtab_add (elf_hash_table (info)->dynstr,
-					 *p, true, true);
+	      indx = _bfd_elf_strtab_add (elf_hash_table (info)->dynstr,
+					  *p, true);
 	      if (indx == (bfd_size_type) -1
 		  || ! elf_add_dynamic_entry (info, (bfd_vma) DT_AUXILIARY,
 					      indx))
@@ -3081,7 +3085,7 @@ NAME(bfd_elf,size_dynamic_sections) (out
 	{
 	  bfd_size_type strsize;
 
-	  strsize = _bfd_stringtab_size (elf_hash_table (info)->dynstr);
+	  strsize = _bfd_elf_strtab_size (elf_hash_table (info)->dynstr);
 	  if (! elf_add_dynamic_entry (info, (bfd_vma) DT_HASH, (bfd_vma) 0)
 	      || ! elf_add_dynamic_entry (info, (bfd_vma) DT_STRTAB, (bfd_vma) 0)
 	      || ! elf_add_dynamic_entry (info, (bfd_vma) DT_SYMTAB, (bfd_vma) 0)
@@ -3164,6 +3168,8 @@ NAME(bfd_elf,size_dynamic_sections) (out
 
 	  if (soname_indx != (bfd_size_type) -1)
 	    {
+	      _bfd_elf_strtab_addref (elf_hash_table (info)->dynstr,
+				      soname_indx);
 	      def.vd_hash = bfd_elf_hash (soname);
 	      defaux.vda_name = soname_indx;
 	    }
@@ -3174,8 +3180,8 @@ NAME(bfd_elf,size_dynamic_sections) (out
 
 	      name = basename (output_bfd->filename);
 	      def.vd_hash = bfd_elf_hash (name);
-	      indx = _bfd_stringtab_add (elf_hash_table (info)->dynstr,
-					    name, true, false);
+	      indx = _bfd_elf_strtab_add (elf_hash_table (info)->dynstr,
+					  name, false);
 	      if (indx == (bfd_size_type) -1)
 		return false;
 	      defaux.vda_name = indx;
@@ -3234,6 +3240,8 @@ NAME(bfd_elf,size_dynamic_sections) (out
 	      p += sizeof (Elf_External_Verdef);
 
 	      defaux.vda_name = h->dynstr_index;
+	      _bfd_elf_strtab_addref (elf_hash_table (info)->dynstr,
+				      h->dynstr_index);
 	      if (t->deps == NULL)
 		defaux.vda_next = 0;
 	      else
@@ -3253,7 +3261,11 @@ NAME(bfd_elf,size_dynamic_sections) (out
 		      defaux.vda_name = 0;
 		    }
 		  else
-		    defaux.vda_name = n->version_needed->name_indx;
+		    {
+		      defaux.vda_name = n->version_needed->name_indx;
+		      _bfd_elf_strtab_addref (elf_hash_table (info)->dynstr,
+					      defaux.vda_name);
+		    }
 		  if (n->next == NULL)
 		    defaux.vda_next = 0;
 		  else
@@ -3352,14 +3364,11 @@ NAME(bfd_elf,size_dynamic_sections) (out
 
 		t->vn_version = VER_NEED_CURRENT;
 		t->vn_cnt = caux;
-		if (elf_dt_name (t->vn_bfd) != NULL)
-		  indx = _bfd_stringtab_add (elf_hash_table (info)->dynstr,
-					     elf_dt_name (t->vn_bfd),
-					     true, false);
-		else
-		  indx = _bfd_stringtab_add (elf_hash_table (info)->dynstr,
-					     basename (t->vn_bfd->filename),
-					     true, false);
+		indx = _bfd_elf_strtab_add (elf_hash_table (info)->dynstr,
+					    elf_dt_name (t->vn_bfd) != NULL
+					    ? elf_dt_name (t->vn_bfd)
+					    : basename (t->vn_bfd->filename),
+					    false);
 		if (indx == (bfd_size_type) -1)
 		  return false;
 		t->vn_file = indx;
@@ -3377,8 +3386,8 @@ NAME(bfd_elf,size_dynamic_sections) (out
 		for (a = t->vn_auxptr; a != NULL; a = a->vna_nextptr)
 		  {
 		    a->vna_hash = bfd_elf_hash (a->vna_nodename);
-		    indx = _bfd_stringtab_add (elf_hash_table (info)->dynstr,
-					       a->vna_nodename, true, false);
+		    indx = _bfd_elf_strtab_add (elf_hash_table (info)->dynstr,
+						a->vna_nodename, false);
 		    if (indx == (bfd_size_type) -1)
 		      return false;
 		    a->vna_name = indx;
@@ -3482,7 +3491,10 @@ NAME(bfd_elf,size_dynamic_sections) (out
 
       s = bfd_get_section_by_name (dynobj, ".dynstr");
       BFD_ASSERT (s != NULL);
-      s->_raw_size = _bfd_stringtab_size (elf_hash_table (info)->dynstr);
+
+      elf_finalize_dynstr (output_bfd, info);
+
+      s->_raw_size = _bfd_elf_strtab_size (elf_hash_table (info)->dynstr);
 
       for (dtagcount = 0; dtagcount <= info->spare_dynamic_tags; ++dtagcount)
 	if (! elf_add_dynamic_entry (info, (bfd_vma) DT_NULL, (bfd_vma) 0))
@@ -3492,6 +3504,150 @@ NAME(bfd_elf,size_dynamic_sections) (out
   return true;
 }
 
+/* This function is used to adjust offsets into .dynstr for
+   dynamic symbols.  This is called via elf_link_hash_traverse.  */
+      
+static boolean elf_adjust_dynstr_offsets
+PARAMS ((struct elf_link_hash_entry *, PTR));
+        
+static boolean
+elf_adjust_dynstr_offsets (h, data)
+     struct elf_link_hash_entry *h;
+     PTR data;
+{
+  struct elf_strtab_hash *dynstr = (struct elf_strtab_hash *) data;
+
+  if (h->dynindx != -1)
+    h->dynstr_index = _bfd_elf_strtab_offset (dynstr, h->dynstr_index);
+  return true;
+}
+
+/* Assign string offsets in .dynstr, update all structures referencing
+   them.  */
+
+static boolean
+elf_finalize_dynstr (output_bfd, info)
+     bfd *output_bfd;
+     struct bfd_link_info *info;
+{
+  struct elf_link_local_dynamic_entry *entry;
+  struct elf_strtab_hash *dynstr = elf_hash_table (info)->dynstr;
+  bfd *dynobj = elf_hash_table (info)->dynobj;
+  asection *sdyn;
+  bfd_size_type size;
+  Elf_External_Dyn *dyncon, *dynconend;
+
+  _bfd_elf_strtab_finalize (dynstr);
+  size = _bfd_elf_strtab_size (dynstr);
+
+  /* Update all .dynamic entries referencing .dynstr strings.  */
+  sdyn = bfd_get_section_by_name (dynobj, ".dynamic");
+  BFD_ASSERT (sdyn != NULL);
+
+  dyncon = (Elf_External_Dyn *) sdyn->contents;
+  dynconend = (Elf_External_Dyn *) (sdyn->contents +
+				    sdyn->_raw_size);
+  for (; dyncon < dynconend; dyncon++)
+    {
+      Elf_Internal_Dyn dyn;
+
+      elf_swap_dyn_in (dynobj, dyncon, & dyn);
+      switch (dyn.d_tag)
+	{
+	case DT_STRSZ:
+	  dyn.d_un.d_val = size;
+	  elf_swap_dyn_out (dynobj, & dyn, dyncon);
+	  break;
+	case DT_NEEDED:
+	case DT_SONAME:
+	case DT_RPATH:
+	case DT_RUNPATH:
+	case DT_FILTER:
+	case DT_AUXILIARY:
+	  dyn.d_un.d_val = _bfd_elf_strtab_offset (dynstr, dyn.d_un.d_val);
+	  elf_swap_dyn_out (dynobj, & dyn, dyncon);
+	  break;
+	default:
+	  break;
+	}
+    }
+
+  /* Now update local dynamic symbols.  */
+  for (entry = elf_hash_table (info)->dynlocal; entry ; entry = entry->next)
+    entry->isym.st_name = _bfd_elf_strtab_offset (dynstr,
+						  entry->isym.st_name);
+
+  /* And the rest of dynamic symbols.  */
+  elf_link_hash_traverse (elf_hash_table (info),
+			  elf_adjust_dynstr_offsets, dynstr);
+
+  /* Adjust version definitions.  */
+  if (elf_tdata (output_bfd)->cverdefs)
+    {
+      asection *s;
+      bfd_byte *p;
+      bfd_size_type i;
+      Elf_Internal_Verdef def;
+      Elf_Internal_Verdaux defaux;
+                    
+      s = bfd_get_section_by_name (dynobj, ".gnu.version_d");
+      p = (bfd_byte *) s->contents;
+      do
+	{
+	  _bfd_elf_swap_verdef_in (output_bfd, (Elf_External_Verdef *) p,
+				   &def);
+	  p += sizeof (Elf_External_Verdef);
+	  for (i = 0; i < def.vd_cnt; ++i)
+	    {
+	      _bfd_elf_swap_verdaux_in (output_bfd,
+					(Elf_External_Verdaux *) p, &defaux);
+	      defaux.vda_name = _bfd_elf_strtab_offset (dynstr,
+							defaux.vda_name);
+	      _bfd_elf_swap_verdaux_out (output_bfd,
+					 &defaux, (Elf_External_Verdaux *) p);
+	      p += sizeof (Elf_External_Verdaux);
+	    }
+	}
+      while (def.vd_next);
+    }
+
+  /* Adjust version references.  */
+  if (elf_tdata (output_bfd)->verref)
+    {
+      asection *s;
+      bfd_byte *p;
+      bfd_size_type i;
+      Elf_Internal_Verneed need;
+      Elf_Internal_Vernaux needaux;
+                    
+      s = bfd_get_section_by_name (dynobj, ".gnu.version_r");
+      p = (bfd_byte *) s->contents;
+      do
+	{
+	  _bfd_elf_swap_verneed_in (output_bfd, (Elf_External_Verneed *) p,
+				    &need);
+	  need.vn_file = _bfd_elf_strtab_offset (dynstr, need.vn_file);
+	  _bfd_elf_swap_verneed_out (output_bfd, &need,
+				     (Elf_External_Verneed *) p);
+	  p += sizeof (Elf_External_Verneed);
+	  for (i = 0; i < need.vn_cnt; ++i)
+	    {
+	      _bfd_elf_swap_vernaux_in (output_bfd,
+					(Elf_External_Vernaux *) p, &needaux);
+	      needaux.vna_name = _bfd_elf_strtab_offset (dynstr,
+							 needaux.vna_name);
+	      _bfd_elf_swap_vernaux_out (output_bfd,
+					 &needaux,
+					 (Elf_External_Vernaux *) p);
+	      p += sizeof (Elf_External_Vernaux);
+	    }
+	}
+      while (need.vn_next);
+    }
+
+  return true;
+}
+
 /* Fix up the flags for a symbol.  This handles various cases which
    can only be fixed after all the input files are seen.  This is
    currently called by both adjust_dynamic_symbol and
@@ -3591,7 +3747,11 @@ elf_fix_symbol_flags (h, eif)
       bed = get_elf_backend_data (elf_hash_table (eif->info)->dynobj);
       if (ELF_ST_VISIBILITY (h->other) == STV_INTERNAL
 	  || ELF_ST_VISIBILITY (h->other) == STV_HIDDEN)
-	h->elf_link_hash_flags |= ELF_LINK_FORCED_LOCAL;
+	{
+	  h->elf_link_hash_flags |= ELF_LINK_FORCED_LOCAL;
+	  _bfd_elf_strtab_delref (elf_hash_table (eif->info)->dynstr,
+				  h->dynstr_index);
+	}
       (*bed->elf_backend_hide_symbol) (eif->info, h);
     }
 
@@ -3976,9 +4136,8 @@ elf_link_assign_sym_version (h, data)
 			    {
 			      h->elf_link_hash_flags |= ELF_LINK_FORCED_LOCAL;
 			      (*bed->elf_backend_hide_symbol) (info, h);
-			      /* FIXME: The name of the symbol has
-				 already been recorded in the dynamic
-				 string table section.  */
+			      _bfd_elf_strtab_delref (elf_hash_table (info)->dynstr,
+						      h->dynstr_index);
 			    }
 
 			  break;
@@ -4089,9 +4248,8 @@ elf_link_assign_sym_version (h, data)
 			{
 			  h->elf_link_hash_flags |= ELF_LINK_FORCED_LOCAL;
 			  (*bed->elf_backend_hide_symbol) (info, h);
-			  /* FIXME: The name of the symbol has already
-			     been recorded in the dynamic string table
-			     section.  */
+			  _bfd_elf_strtab_delref (elf_hash_table (info)->dynstr,
+						  h->dynstr_index);
 			}
 		      break;
 		    }
@@ -4111,8 +4269,8 @@ elf_link_assign_sym_version (h, data)
 	    {
 	      h->elf_link_hash_flags |= ELF_LINK_FORCED_LOCAL;
 	      (*bed->elf_backend_hide_symbol) (info, h);
-	      /* FIXME: The name of the symbol has already been
-		 recorded in the dynamic string table section.  */
+	      _bfd_elf_strtab_delref (elf_hash_table (info)->dynstr,
+				      h->dynstr_index);
 	    }
 	}
     }
@@ -5308,8 +5466,8 @@ elf_bfd_final_link (abfd, info)
                  stringtab.  */
 	      off = elf_section_data (o->output_section)->this_hdr.sh_offset;
 	      if (bfd_seek (abfd, off, SEEK_SET) != 0
-		  || ! _bfd_stringtab_emit (abfd,
-					    elf_hash_table (info)->dynstr))
+		  || ! _bfd_elf_strtab_emit (abfd,
+					     elf_hash_table (info)->dynstr))
 		goto error_return;
 	    }
 	}
--- bfd/elflink.c.jj	Fri Oct  5 13:02:12 2001
+++ bfd/elflink.c	Sat Nov  3 21:59:53 2001
@@ -230,7 +230,7 @@ _bfd_elf_link_record_dynamic_symbol (inf
 {
   if (h->dynindx == -1)
     {
-      struct bfd_strtab_hash *dynstr;
+      struct elf_strtab_hash *dynstr;
       char *p, *alc;
       const char *name;
       boolean copy;
@@ -262,7 +262,7 @@ _bfd_elf_link_record_dynamic_symbol (inf
       if (dynstr == NULL)
 	{
 	  /* Create a strtab to hold the dynamic symbol names.  */
-	  elf_hash_table (info)->dynstr = dynstr = _bfd_elf_stringtab_init ();
+	  elf_hash_table (info)->dynstr = dynstr = _bfd_elf_strtab_init ();
 	  if (dynstr == NULL)
 	    return false;
 	}
@@ -287,7 +287,7 @@ _bfd_elf_link_record_dynamic_symbol (inf
 	  copy = true;
 	}
 
-      indx = _bfd_stringtab_add (dynstr, name, true, copy);
+      indx = _bfd_elf_strtab_add (dynstr, name, copy);
 
       if (alc != NULL)
 	free (alc);
--- bfd/elf64-sparc.c.jj	Tue Sep 25 20:55:04 2001
+++ bfd/elf64-sparc.c	Fri Nov  2 19:59:48 2001
@@ -1840,7 +1840,7 @@ sparc64_elf_size_dynamic_sections (outpu
 	    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);
+		= _bfd_elf_strtab_add (dynstr, app_regs[reg].name, false);
 	    else
 	      entry->isym.st_name = 0;
 	    entry->isym.st_other = 0;
--- bfd/configure.in.jj	Fri Nov  2 10:58:29 2001
+++ bfd/configure.in	Sat Nov  3 22:33:08 2001
@@ -503,7 +503,7 @@ selarchs="$f"
 # Target backend .o files.
 tb=
 
-elf="elf.lo elflink.lo dwarf1.lo"
+elf="elf.lo elflink.lo elf-strtab.lo dwarf1.lo"
 
 for vec in $selvecs
 do
--- bfd/configure.jj	Fri Nov  2 10:58:29 2001
+++ bfd/configure	Sat Nov  3 22:33:28 2001
@@ -5923,7 +5923,7 @@ selarchs="$f"
 # Target backend .o files.
 tb=
 
-elf="elf.lo elflink.lo dwarf1.lo"
+elf="elf.lo elflink.lo elf-strtab.lo dwarf1.lo"
 
 for vec in $selvecs
 do
--- bfd/elf.c.jj	Fri Nov  2 10:58:29 2001
+++ bfd/elf.c	Sun Nov  4 15:37:03 2001
@@ -1939,8 +1939,8 @@ _bfd_elf_init_reloc_shdr (abfd, rel_hdr,
     return false;
   sprintf (name, "%s%s", use_rela_p ? ".rela" : ".rel", asect->name);
   rel_hdr->sh_name =
-    (unsigned int) _bfd_stringtab_add (elf_shstrtab (abfd), name,
-				       true, false);
+    (unsigned int) _bfd_elf_strtab_add (elf_shstrtab (abfd), name,
+					false);
   if (rel_hdr->sh_name == (unsigned int) -1)
     return false;
   rel_hdr->sh_type = use_rela_p ? SHT_RELA : SHT_REL;
@@ -1977,9 +1977,8 @@ elf_fake_sections (abfd, asect, failedpt
 
   this_hdr = &elf_section_data (asect)->this_hdr;
 
-  this_hdr->sh_name = (unsigned long) _bfd_stringtab_add (elf_shstrtab (abfd),
-							  asect->name,
-							  true, false);
+  this_hdr->sh_name = (unsigned long) _bfd_elf_strtab_add (elf_shstrtab (abfd),
+							   asect->name, false);
   if (this_hdr->sh_name == (unsigned long) -1)
     {
       *failedptr = true;
@@ -2200,38 +2199,51 @@ assign_section_numbers (abfd)
 {
   struct elf_obj_tdata *t = elf_tdata (abfd);
   asection *sec;
-  unsigned int section_number;
+  unsigned int section_number, secn;
   Elf_Internal_Shdr **i_shdrp;
   bfd_size_type amt;
 
   section_number = 1;
 
+  _bfd_elf_strtab_clear_all_refs (elf_shstrtab (abfd));
+
   for (sec = abfd->sections; sec; sec = sec->next)
     {
       struct bfd_elf_section_data *d = elf_section_data (sec);
 
       d->this_idx = section_number++;
+      _bfd_elf_strtab_addref (elf_shstrtab (abfd), d->this_hdr.sh_name);
       if ((sec->flags & SEC_RELOC) == 0)
 	d->rel_idx = 0;
       else
-	d->rel_idx = section_number++;
+	{
+	  d->rel_idx = section_number++;
+	  _bfd_elf_strtab_addref (elf_shstrtab (abfd), d->rel_hdr.sh_name);
+	}
 
       if (d->rel_hdr2)
-	d->rel_idx2 = section_number++;
+	{
+	  d->rel_idx2 = section_number++;
+	  _bfd_elf_strtab_addref (elf_shstrtab (abfd), d->rel_hdr2->sh_name);
+	}
       else
 	d->rel_idx2 = 0;
     }
 
   t->shstrtab_section = section_number++;
+  _bfd_elf_strtab_addref (elf_shstrtab (abfd), t->shstrtab_hdr.sh_name);
   elf_elfheader (abfd)->e_shstrndx = t->shstrtab_section;
-  t->shstrtab_hdr.sh_size = _bfd_stringtab_size (elf_shstrtab (abfd));
 
   if (bfd_get_symcount (abfd) > 0)
     {
       t->symtab_section = section_number++;
+      _bfd_elf_strtab_addref (elf_shstrtab (abfd), t->symtab_hdr.sh_name);
       t->strtab_section = section_number++;
+      _bfd_elf_strtab_addref (elf_shstrtab (abfd), t->strtab_hdr.sh_name);
     }
 
+  _bfd_elf_strtab_finalize (elf_shstrtab (abfd));
+  t->shstrtab_hdr.sh_size = _bfd_elf_strtab_size (elf_shstrtab (abfd));
   elf_elfheader (abfd)->e_shnum = section_number;
 
   /* Set up the list of section header pointers, in agreement with the
@@ -2368,6 +2380,10 @@ assign_section_numbers (abfd)
 	}
     }
 
+  for (secn = 1; secn < section_number; ++secn)
+    i_shdrp[secn]->sh_name = _bfd_elf_strtab_offset (elf_shstrtab (abfd),
+						     i_shdrp[secn]->sh_name);
+
   return true;
 }
 
@@ -2629,7 +2645,7 @@ _bfd_elf_compute_section_file_positions 
   shstrtab_hdr->sh_type = SHT_STRTAB;
   shstrtab_hdr->sh_flags = 0;
   shstrtab_hdr->sh_addr = 0;
-  shstrtab_hdr->sh_size = _bfd_stringtab_size (elf_shstrtab (abfd));
+  shstrtab_hdr->sh_size = _bfd_elf_strtab_size (elf_shstrtab (abfd));
   shstrtab_hdr->sh_entsize = 0;
   shstrtab_hdr->sh_link = 0;
   shstrtab_hdr->sh_info = 0;
@@ -3620,13 +3636,13 @@ prep_headers (abfd)
   Elf_Internal_Phdr *i_phdrp = 0; /* Program header table, internal form */
   Elf_Internal_Shdr **i_shdrp;	/* Section header table, internal form */
   int count;
-  struct bfd_strtab_hash *shstrtab;
+  struct elf_strtab_hash *shstrtab;
   struct elf_backend_data *bed = get_elf_backend_data (abfd);
 
   i_ehdrp = elf_elfheader (abfd);
   i_shdrp = elf_elfsections (abfd);
 
-  shstrtab = _bfd_elf_stringtab_init ();
+  shstrtab = _bfd_elf_strtab_init ();
   if (shstrtab == NULL)
     return false;
 
@@ -3712,11 +3728,11 @@ prep_headers (abfd)
     }
 
   elf_tdata (abfd)->symtab_hdr.sh_name =
-    (unsigned int) _bfd_stringtab_add (shstrtab, ".symtab", true, false);
+    (unsigned int) _bfd_elf_strtab_add (shstrtab, ".symtab", false);
   elf_tdata (abfd)->strtab_hdr.sh_name =
-    (unsigned int) _bfd_stringtab_add (shstrtab, ".strtab", true, false);
+    (unsigned int) _bfd_elf_strtab_add (shstrtab, ".strtab", false);
   elf_tdata (abfd)->shstrtab_hdr.sh_name =
-    (unsigned int) _bfd_stringtab_add (shstrtab, ".shstrtab", true, false);
+    (unsigned int) _bfd_elf_strtab_add (shstrtab, ".shstrtab", false);
   if (elf_tdata (abfd)->symtab_hdr.sh_name == (unsigned int) -1
       || elf_tdata (abfd)->symtab_hdr.sh_name == (unsigned int) -1
       || elf_tdata (abfd)->shstrtab_hdr.sh_name == (unsigned int) -1)
@@ -3795,7 +3811,7 @@ _bfd_elf_write_object_contents (abfd)
 
   /* Write out the section header names.  */
   if (bfd_seek (abfd, elf_tdata (abfd)->shstrtab_hdr.sh_offset, SEEK_SET) != 0
-      || ! _bfd_stringtab_emit (abfd, elf_shstrtab (abfd)))
+      || ! _bfd_elf_strtab_emit (abfd, elf_shstrtab (abfd)))
     return false;
 
   if (bed->elf_backend_final_write_processing)
@@ -5549,7 +5565,7 @@ _bfd_elf_close_and_cleanup (abfd)
   if (bfd_get_format (abfd) == bfd_object)
     {
       if (elf_shstrtab (abfd) != NULL)
-	_bfd_stringtab_free (elf_shstrtab (abfd));
+	_bfd_elf_strtab_free (elf_shstrtab (abfd));
     }
 
   return _bfd_generic_close_and_cleanup (abfd);


	Jakub


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