(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 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
elf32-v850.lo \
elf32.lo \
elflink.lo \
+ elf-strtab.lo \
epoc-pe-arm.lo \
epoc-pei-arm.lo \
hp300bsd.lo \
elf32-v850.c \
elf32.c \
elflink.c \
+ elf-strtab.c \
epoc-pe-arm.c \
epoc-pei-arm.c \
hp300bsd.c \
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 \
elf32-v850.lo \
elf32.lo \
elflink.lo \
+ elf-strtab.lo \
epoc-pe-arm.lo \
epoc-pei-arm.lo \
hp300bsd.lo \
elf32-v850.c \
elf32.c \
elflink.c \
+ elf-strtab.c \
epoc-pe-arm.c \
epoc-pei-arm.c \
hp300bsd.c \
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 \
# 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
# 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
} elf_symbol_type;
\f
+struct elf_strtab_hash;
+
/* ELF linker hash table entries. */
struct elf_link_hash_entry
/* 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. */
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;
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
--- /dev/null
+/* 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);
+ }
+}
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;
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;
{
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
}
}
+ 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;
}
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;
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;
}
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)
/* 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)
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);
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;
{
if (h->dynindx == -1)
{
- struct bfd_strtab_hash *dynstr;
+ struct elf_strtab_hash *dynstr;
char *p, *alc;
const char *name;
boolean copy;
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;
}
copy = true;
}
- indx = _bfd_stringtab_add (dynstr, name, true, copy);
+ indx = _bfd_elf_strtab_add (dynstr, name, copy);
if (alc != NULL)
free (alc);
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
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;
free (buf);
if (extversym != NULL)
free (extversym);
+ _bfd_elf_strtab_delref (hash_table->dynstr, strindex);
return true;
}
}
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;
}
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;
/* 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;
}
{
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;
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;
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))
{
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
{
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;
{
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))
{
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)
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;
}
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;
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
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
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;
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;
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))
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
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);
}
{
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;
{
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;
}
{
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);
}
}
}
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;
}
}