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


Hi!

The following patch kills nearly half of .dynstr size for libc.so (17KB)
by garbage collecting strings and suffix merging.
Alex Larsson told me the wasted space in .dynstr in mozilla is way bigger.
To do this, I've added a special strtab (in elf-strtab.c).
Unlike _bfd_stringtab_add, _bfd_elf_strtab_add returns just an integer magic
cookie, not the final stringtab offset (because those can be determined only
when all strings in the stringtab are finalized - otherwise adding a longer
string whose suffix is already in the hash table could not cause that older
string not to be emitted and also GC could not work).
This strtab maintains a reference count, so when doing *hide_symbol to
FORCE_LOCAL, one should _bfd_elf_strtab_delref to show one of the symbol
references is gone (string "" is always at offset 0 in strtab and doesn't
do reference counting). Similarly, when a strtab cookie is copied,
_bfd_elf_strtab_addref should be called.
After all stringtab strings are in the hash table and those which will not be
used have the reference count 0, one should call _bfd_elf_strtab_finalize,
which will do the actual suffix merging and assign stringtab offsets.
Then, for each field which carries the stringtab cookie, the cookie should
be replaced by the actual stringtab offset, using _bfd_elf_strtab_offset.
elf-strtab.c requires that the number of _bfd_elf_strtab_offset calls for
each string matches its reference count. As there are just a few locations
where .dynstr offsets are stored in (.dynsym .st_name fields, a couple of
.dynamic tags, .vda_name, .vna_name and .vn_file fields in
.gnu.version_{r,d} sections), it is not that hard to update them all.
Tested using make check and linking libc.so and comparing readelf output
(after growing .dynstr section in the linker script, so that it has the same
size as when linked without this patch).
Ok to commit?

2001-11-05  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	Sun Nov  4 15:48:57 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->refcount == 1)
+    {
+      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]