* Makefile.am (BFD32_BACKENDS): Add elf-strtab.lo.
authorJakub Jelinek <jakub@redhat.com>
Wed, 7 Nov 2001 16:50:38 +0000 (16:50 +0000)
committerJakub Jelinek <jakub@redhat.com>
Wed, 7 Nov 2001 16:50:38 +0000 (16:50 +0000)
(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/ChangeLog
bfd/Makefile.am
bfd/Makefile.in
bfd/configure
bfd/configure.in
bfd/elf-bfd.h
bfd/elf-strtab.c [new file with mode: 0644]
bfd/elf.c
bfd/elf64-sparc.c
bfd/elflink.c
bfd/elflink.h

index b5009f9c304be95cb3103b325b7e4c71626b537f..9aa309a7c7709227a96adf59b734ef9327dcc461 100644 (file)
@@ -1,3 +1,55 @@
+2001-11-07  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.
+
 2001-11-07  Alan Modra  <amodra@bigpond.net.au>
 
        * elflink.h (elf_link_input_bfd <removed linkonce relocs>): Fix
index a1f737f3df8a106a869b3e6c3af92ef98f73b838..b6753685fae37104d044a498132a94da7f6c7b07 100644 (file)
@@ -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)/filenames.h $(INCDIR)/libiberty.h \
 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 \
index efaae6276bd37b98855cf840ec9ceb0c86d02594..379c9427d4fe68a6d31ccff0791c720d064a250a 100644 (file)
@@ -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)/filenames.h $(INCDIR)/libiberty.h \
 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 \
index df9ba479f7c7c9008f265420cf3653c202bf7633..4a34b1a130cf36e1f4bd5227be1c3c36ac37cea3 100755 (executable)
@@ -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
index abbd790c29c48a999ef17e514ebc1af273ec4803..0ae2b62c56d2dd3baa9434d864fe5182cf09d69f 100644 (file)
@@ -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
index fdb69c6097d0b89d8b90bfa4ef912e58b035c7c6..e9a8b83836867f0be494e2045a4ba84c983f2014 100644 (file)
@@ -79,6 +79,8 @@ typedef struct
 
 } elf_symbol_type;
 \f
+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_sections
   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
diff --git a/bfd/elf-strtab.c b/bfd/elf-strtab.c
new file mode 100644 (file)
index 0000000..59a25a5
--- /dev/null
@@ -0,0 +1,459 @@
+/* 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;
+      ret->len = 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);
+    }
+}
index c03bd4a5ce0651203f05e6527b6c4592613fbc1a..8c1694e41cf7d0ef03250962c601adbdd5f0ed8f 100644 (file)
--- a/bfd/elf.c
+++ b/bfd/elf.c
@@ -1939,8 +1939,8 @@ _bfd_elf_init_reloc_shdr (abfd, rel_hdr, asect, use_rela_p)
     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, failedptrarg)
 
   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 (abfd, link_info)
   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);
index cb03eeb54855e998a34bed954d818289002cf469..cd0d914de5c18d840823d833f96bde6663e499db 100644 (file)
@@ -1840,7 +1840,7 @@ sparc64_elf_size_dynamic_sections (output_bfd, info)
            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;
index 05a2288f52f9af7118ad88f4a7f1b00854de23fc..fdc82b70aa4c018fe3719e74bffdda38ba89dff8 100644 (file)
@@ -230,7 +230,7 @@ _bfd_elf_link_record_dynamic_symbol (info, h)
 {
   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 (info, h)
       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 (info, h)
          copy = true;
        }
 
-      indx = _bfd_stringtab_add (dynstr, name, true, copy);
+      indx = _bfd_elf_strtab_add (dynstr, name, copy);
 
       if (alc != NULL)
        free (alc);
index bc85175d4927bcffa4eae994abd8bcfa46affdb4..d1db64a46642cb75f5763d8e2a39a5674898dd42 100644 (file)
@@ -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, info)
   /* 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 (info, input_bfd, input_indx)
 {
   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 (info, input_bfd, input_indx)
   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) (output_bfd, soname, rpath,
 
       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) (output_bfd, soname, rpath,
        {
          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) (output_bfd, soname, rpath,
        {
          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) (output_bfd, soname, rpath,
            {
              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) (output_bfd, soname, rpath,
        {
          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) (output_bfd, soname, rpath,
 
          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) (output_bfd, soname, rpath,
 
              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) (output_bfd, soname, rpath,
              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) (output_bfd, soname, rpath,
                      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) (output_bfd, soname, rpath,
 
                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) (output_bfd, soname, rpath,
                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) (output_bfd, soname, rpath,
 
       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) (output_bfd, soname, rpath,
   return true;
 }
 \f
+/* 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;
            }
        }