This is the mail archive of the binutils@sourceware.org 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]
Other format: [Raw text]

Free linker hash table from bfd_close


Also tidies numerous error exit paths in various link_hash_table_create
functions that failed to free memory.

include/
	* bfdlink.h (struct bfd_link_hash_table): Add hash_table_free field.
bfd/
	* archive.c: Include bfdlink.h.
	(_bfd_archive_close_and_cleanup): Call linker hash_table_free.
	* bfd.c (struct bfd): Add is_linker_output field.
	* elf-bfd.h (_bfd_elf_link_hash_table_free): Update prototype.
	* linker.c (_bfd_link_hash_table_init): Set up hash_table_free,
	link.hash and is_linker_output.
	(_bfd_generic_link_hash_table_free): Replace bfd_link_hash_table*
	param with bfd*.  Assert is_linker_output and link.hash, and
	clear them before exit.
	* elf-m10300.c (elf32_mn10300_link_hash_table_free): Replace
	bfd_link_hash_table* param with bfd*.  Hack is_linker_output
	and link.hash so we can free two linker hash tables.
	(elf32_mn10300_link_hash_table_create): Create static_hash_table
	first.  Clean up on errors.  Set hash_table_free pointer.
	* elf32-arm.c (elf32_arm_link_hash_table_free): Replace
	bfd_link_hash_table* param with bfd*.
	(elf32_arm_link_hash_table_create): Clean up on errors.  Set
	hash_table_free pointer.
	* elf32-avr.c, * elf32-hppa.c, * elf32-i386.c, * elf32-m68hc1x.c,
	* elf32-m68k.c, * elf32-metag.c, * elf32-nios2.c, * elf32-xgate.c,
	* elf64-ia64-vms.c, * elf64-ppc.c, * elf64-x86-64.c, * elflink.c,
	* elfnn-aarch64.c, * elfnn-ia64.c, * elfxx-sparc.c,
	* xcofflink.c: Similarly.
	* simple.c (bfd_simple_get_relocated_section_contents): Save and
	clear link.next before creating linker hash table.  Clean up on
	errors, and restore link.next on exit.
	* elf32-m68hc1x.h (m68hc11_elf_bfd_link_hash_table_free): Delete.
	* elf32-xgate.h (xgate_elf_bfd_link_hash_table_free): Delete.
	* elfxx-sparc.h (_bfd_sparc_elf_link_hash_table_free): Delete.
	* libcoff-in.h (_bfd_xcoff_bfd_link_hash_table_free): Delete.
	* hash.c (bfd_hash_table_init_n): Free table on error.
	* libbfd-in.h (_bfd_generic_link_hash_table_free): Update proto.
	* bfd-in2.h: Regenerate.
	* libbfd.h: Regenerate.
	* libcoff.h: Regenerate.

diff --git a/bfd/archive.c b/bfd/archive.c
index 157a3f7..1c3ad52 100644
--- a/bfd/archive.c
+++ b/bfd/archive.c
@@ -140,6 +140,7 @@ SUBSECTION
 #include "safe-ctype.h"
 #include "hashtab.h"
 #include "filenames.h"
+#include "bfdlink.h"
 
 #ifndef errno
 extern int errno;
@@ -2751,5 +2752,8 @@ _bfd_archive_close_and_cleanup (bfd *abfd)
 	    }
 	}
     }
+  if (abfd->is_linker_output)
+    (*abfd->link.hash->hash_table_free) (abfd);
+
   return TRUE;
 }
diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h
index 07d94df..d9056ce 100644
--- a/bfd/bfd-in2.h
+++ b/bfd/bfd-in2.h
@@ -6488,6 +6488,9 @@ struct bfd
   /* Set if only required symbols should be added in the link hash table for
      this object.  Used by VMS linkers.  */
   unsigned int selective_search : 1;
+
+  /* Set if this is the linker output BFD.  */
+  unsigned int is_linker_output : 1;
 };
 
 /* See note beside bfd_set_section_userdata.  */
diff --git a/bfd/bfd.c b/bfd/bfd.c
index 2406319..e19bcf7 100644
--- a/bfd/bfd.c
+++ b/bfd/bfd.c
@@ -313,6 +313,9 @@ CODE_FRAGMENT
 .  {* Set if only required symbols should be added in the link hash table for
 .     this object.  Used by VMS linkers.  *}
 .  unsigned int selective_search : 1;
+.
+.  {* Set if this is the linker output BFD.  *}
+.  unsigned int is_linker_output : 1;
 .};
 .
 .{* See note beside bfd_set_section_userdata.  *}
diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h
index 1bbe771..a06c54b 100644
--- a/bfd/elf-bfd.h
+++ b/bfd/elf-bfd.h
@@ -1816,7 +1816,7 @@ extern struct bfd_hash_entry *_bfd_elf_link_hash_newfunc
 extern struct bfd_link_hash_table *_bfd_elf_link_hash_table_create
   (bfd *);
 extern void _bfd_elf_link_hash_table_free
-  (struct bfd_link_hash_table *);
+  (bfd *);
 extern void _bfd_elf_link_hash_copy_indirect
   (struct bfd_link_info *, struct elf_link_hash_entry *,
    struct elf_link_hash_entry *);
diff --git a/bfd/elf-m10300.c b/bfd/elf-m10300.c
index 4cc879e..f29025d 100644
--- a/bfd/elf-m10300.c
+++ b/bfd/elf-m10300.c
@@ -4601,15 +4601,16 @@ _bfd_mn10300_copy_indirect_symbol (struct bfd_link_info *        info,
 /* Destroy an mn10300 ELF linker hash table.  */
 
 static void
-elf32_mn10300_link_hash_table_free (struct bfd_link_hash_table *hash)
+elf32_mn10300_link_hash_table_free (bfd *obfd)
 {
   struct elf32_mn10300_link_hash_table *ret
-    = (struct elf32_mn10300_link_hash_table *) hash;
+    = (struct elf32_mn10300_link_hash_table *) obfd->link.hash;
 
-  _bfd_elf_link_hash_table_free
-    ((struct bfd_link_hash_table *) ret->static_hash_table);
-  _bfd_elf_link_hash_table_free
-    ((struct bfd_link_hash_table *) ret);
+  obfd->link.hash = &ret->static_hash_table->root.root;
+  _bfd_elf_link_hash_table_free (obfd);
+  obfd->is_linker_output = TRUE;
+  obfd->link.hash = &ret->root.root;
+  _bfd_elf_link_hash_table_free (obfd);
 }
 
 /* Create an mn10300 ELF linker hash table.  */
@@ -4624,17 +4625,6 @@ elf32_mn10300_link_hash_table_create (bfd *abfd)
   if (ret == NULL)
     return NULL;
 
-  if (!_bfd_elf_link_hash_table_init (&ret->root, abfd,
-				      elf32_mn10300_link_hash_newfunc,
-				      sizeof (struct elf32_mn10300_link_hash_entry),
-				      MN10300_ELF_DATA))
-    {
-      free (ret);
-      return NULL;
-    }
-
-  ret->tls_ldm_got.offset = -1;
-
   amt = sizeof (struct elf_link_hash_table);
   ret->static_hash_table = bfd_zmalloc (amt);
   if (ret->static_hash_table == NULL)
@@ -4652,7 +4642,24 @@ elf32_mn10300_link_hash_table_create (bfd *abfd)
       free (ret);
       return NULL;
     }
-  (void) elf32_mn10300_link_hash_table_free;
+
+  abfd->is_linker_output = FALSE;
+  abfd->link.hash = NULL;
+  if (!_bfd_elf_link_hash_table_init (&ret->root, abfd,
+				      elf32_mn10300_link_hash_newfunc,
+				      sizeof (struct elf32_mn10300_link_hash_entry),
+				      MN10300_ELF_DATA))
+    {
+      abfd->is_linker_output = TRUE;
+      abfd->link.hash = &ret->static_hash_table->root.root;
+      _bfd_elf_link_hash_table_free (abfd);
+      free (ret);
+      return NULL;
+    }
+  ret->root.root.hash_table_free = elf32_mn10300_link_hash_table_free;
+
+  ret->tls_ldm_got.offset = -1;
+
   return & ret->root.root;
 }
 
diff --git a/bfd/elf32-arm.c b/bfd/elf32-arm.c
index 6358b58..ef8bfa6 100644
--- a/bfd/elf32-arm.c
+++ b/bfd/elf32-arm.c
@@ -3526,13 +3526,13 @@ elf32_arm_copy_indirect_symbol (struct bfd_link_info *info,
 /* Destroy an ARM elf linker hash table.  */
 
 static void
-elf32_arm_link_hash_table_free (struct bfd_link_hash_table *hash)
+elf32_arm_link_hash_table_free (bfd *obfd)
 {
   struct elf32_arm_link_hash_table *ret
-    = (struct elf32_arm_link_hash_table *) hash;
+    = (struct elf32_arm_link_hash_table *) obfd->link.hash;
 
   bfd_hash_table_free (&ret->stub_hash_table);
-  _bfd_elf_link_hash_table_free (hash);
+  _bfd_elf_link_hash_table_free (obfd);
 }
 
 /* Create an ARM elf linker hash table.  */
@@ -3570,10 +3570,10 @@ elf32_arm_link_hash_table_create (bfd *abfd)
   if (!bfd_hash_table_init (&ret->stub_hash_table, stub_hash_newfunc,
 			    sizeof (struct elf32_arm_stub_hash_entry)))
     {
-      free (ret);
+      _bfd_elf_link_hash_table_free (abfd);
       return NULL;
     }
-  (void) elf32_arm_link_hash_table_free;
+  ret->root.root.hash_table_free = elf32_arm_link_hash_table_free;
 
   return &ret->root.root;
 }
diff --git a/bfd/elf32-avr.c b/bfd/elf32-avr.c
index 5595384..b46a44c 100644
--- a/bfd/elf32-avr.c
+++ b/bfd/elf32-avr.c
@@ -714,10 +714,10 @@ elf32_avr_link_hash_newfunc (struct bfd_hash_entry * entry,
 /* Free the derived linker hash table.  */
 
 static void
-elf32_avr_link_hash_table_free (struct bfd_link_hash_table *btab)
+elf32_avr_link_hash_table_free (bfd *obfd)
 {
   struct elf32_avr_link_hash_table *htab
-    = (struct elf32_avr_link_hash_table *) btab;
+    = (struct elf32_avr_link_hash_table *) obfd->link.hash;
 
   /* Free the address mapping table.  */
   if (htab->amt_stub_offsets != NULL)
@@ -726,7 +726,7 @@ elf32_avr_link_hash_table_free (struct bfd_link_hash_table *btab)
     free (htab->amt_destination_addr);
 
   bfd_hash_table_free (&htab->bstab);
-  _bfd_elf_link_hash_table_free (btab);
+  _bfd_elf_link_hash_table_free (obfd);
 }
 
 /* Create the derived linker hash table.  The AVR ELF port uses the derived
@@ -755,8 +755,11 @@ elf32_avr_link_hash_table_create (bfd *abfd)
   /* Init the stub hash table too.  */
   if (!bfd_hash_table_init (&htab->bstab, stub_hash_newfunc,
                             sizeof (struct elf32_avr_stub_hash_entry)))
-    return NULL;
-  (void) elf32_avr_link_hash_table_free;
+    {
+      _bfd_elf_link_hash_table_free (abfd);
+      return NULL;
+    }
+  htab->etab.root.hash_table_free = elf32_avr_link_hash_table_free;
 
   return &htab->etab.root;
 }
diff --git a/bfd/elf32-hppa.c b/bfd/elf32-hppa.c
index 635ec42..0588ebb 100644
--- a/bfd/elf32-hppa.c
+++ b/bfd/elf32-hppa.c
@@ -410,13 +410,13 @@ hppa_link_hash_newfunc (struct bfd_hash_entry *entry,
 /* Free the derived linker hash table.  */
 
 static void
-elf32_hppa_link_hash_table_free (struct bfd_link_hash_table *btab)
+elf32_hppa_link_hash_table_free (bfd *obfd)
 {
   struct elf32_hppa_link_hash_table *htab
-    = (struct elf32_hppa_link_hash_table *) btab;
+    = (struct elf32_hppa_link_hash_table *) obfd->link.hash;
 
   bfd_hash_table_free (&htab->bstab);
-  _bfd_elf_link_hash_table_free (btab);
+  _bfd_elf_link_hash_table_free (obfd);
 }
 
 /* Create the derived linker hash table.  The PA ELF port uses the derived
@@ -444,8 +444,11 @@ elf32_hppa_link_hash_table_create (bfd *abfd)
   /* Init the stub hash table too.  */
   if (!bfd_hash_table_init (&htab->bstab, stub_hash_newfunc,
 			    sizeof (struct elf32_hppa_stub_hash_entry)))
-    return NULL;
-  (void) elf32_hppa_link_hash_table_free;
+    {
+      _bfd_elf_link_hash_table_free (abfd);
+      return NULL;
+    }
+  htab->etab.root.hash_table_free = elf32_hppa_link_hash_table_free;
 
   htab->text_segment_base = (bfd_vma) -1;
   htab->data_segment_base = (bfd_vma) -1;
diff --git a/bfd/elf32-i386.c b/bfd/elf32-i386.c
index eb5b3d0..551d179 100644
--- a/bfd/elf32-i386.c
+++ b/bfd/elf32-i386.c
@@ -930,16 +930,16 @@ elf_i386_get_local_sym_hash (struct elf_i386_link_hash_table *htab,
 /* Destroy an i386 ELF linker hash table.  */
 
 static void
-elf_i386_link_hash_table_free (struct bfd_link_hash_table *hash)
+elf_i386_link_hash_table_free (bfd *obfd)
 {
   struct elf_i386_link_hash_table *htab
-    = (struct elf_i386_link_hash_table *) hash;
+    = (struct elf_i386_link_hash_table *) obfd->link.hash;
 
   if (htab->loc_hash_table)
     htab_delete (htab->loc_hash_table);
   if (htab->loc_hash_memory)
     objalloc_free ((struct objalloc *) htab->loc_hash_memory);
-  _bfd_elf_link_hash_table_free (hash);
+  _bfd_elf_link_hash_table_free (obfd);
 }
 
 /* Create an i386 ELF linker hash table.  */
@@ -970,10 +970,10 @@ elf_i386_link_hash_table_create (bfd *abfd)
   ret->loc_hash_memory = objalloc_create ();
   if (!ret->loc_hash_table || !ret->loc_hash_memory)
     {
-      free (ret);
+      elf_i386_link_hash_table_free (abfd);
       return NULL;
     }
-  (void) elf_i386_link_hash_table_free;
+  ret->elf.root.hash_table_free = elf_i386_link_hash_table_free;
 
   return &ret->elf.root;
 }
diff --git a/bfd/elf32-m68hc1x.c b/bfd/elf32-m68hc1x.c
index 7c84517..c3a99df 100644
--- a/bfd/elf32-m68hc1x.c
+++ b/bfd/elf32-m68hc1x.c
@@ -60,15 +60,15 @@ struct m68hc11_scan_param
 
 /* Destroy a 68HC11/68HC12 ELF linker hash table.  */
 
-void
-m68hc11_elf_bfd_link_hash_table_free (struct bfd_link_hash_table *hash)
+static void
+m68hc11_elf_bfd_link_hash_table_free (bfd *obfd)
 {
   struct m68hc11_elf_link_hash_table *ret
-    = (struct m68hc11_elf_link_hash_table *) hash;
+    = (struct m68hc11_elf_link_hash_table *) obfd->link.hash;
 
   bfd_hash_table_free (ret->stub_hash_table);
   free (ret->stub_hash_table);
-  _bfd_elf_link_hash_table_free (hash);
+  _bfd_elf_link_hash_table_free (obfd);
 }
 
 /* Create a 68HC11/68HC12 ELF linker hash table.  */
@@ -97,12 +97,17 @@ m68hc11_elf_hash_table_create (bfd *abfd)
   ret->stub_hash_table = (struct bfd_hash_table*) bfd_malloc (amt);
   if (ret->stub_hash_table == NULL)
     {
-      free (ret);
+      _bfd_elf_link_hash_table_free (abfd);
       return NULL;
     }
   if (!bfd_hash_table_init (ret->stub_hash_table, stub_hash_newfunc,
 			    sizeof (struct elf32_m68hc11_stub_hash_entry)))
-    return NULL;
+    {
+      free (ret->stub_hash_table);
+      _bfd_elf_link_hash_table_free (abfd);
+      return NULL;
+    }
+  ret->root.root.hash_table_free = m68hc11_elf_bfd_link_hash_table_free;
 
   return ret;
 }
diff --git a/bfd/elf32-m68hc1x.h b/bfd/elf32-m68hc1x.h
index 1d1f288..89ccd7f 100644
--- a/bfd/elf32-m68hc1x.h
+++ b/bfd/elf32-m68hc1x.h
@@ -136,7 +136,6 @@ struct m68hc11_elf_link_hash_table
 
 extern struct m68hc11_elf_link_hash_table* m68hc11_elf_hash_table_create
   (bfd*);
-extern void m68hc11_elf_bfd_link_hash_table_free (struct bfd_link_hash_table*);
 
 extern void m68hc11_elf_get_bank_parameters (struct bfd_link_info*);
 
diff --git a/bfd/elf32-m68k.c b/bfd/elf32-m68k.c
index b857a0d..952d819 100644
--- a/bfd/elf32-m68k.c
+++ b/bfd/elf32-m68k.c
@@ -943,18 +943,18 @@ elf_m68k_link_hash_newfunc (struct bfd_hash_entry *entry,
 /* Destroy an m68k ELF linker hash table.  */
 
 static void
-elf_m68k_link_hash_table_free (struct bfd_link_hash_table *_htab)
+elf_m68k_link_hash_table_free (bfd *obfd)
 {
   struct elf_m68k_link_hash_table *htab;
 
-  htab = (struct elf_m68k_link_hash_table *) _htab;
+  htab = (struct elf_m68k_link_hash_table *) obfd->link.hash;
 
   if (htab->multi_got_.bfd2got != NULL)
     {
       htab_delete (htab->multi_got_.bfd2got);
       htab->multi_got_.bfd2got = NULL;
     }
-  _bfd_elf_link_hash_table_free (_htab);
+  _bfd_elf_link_hash_table_free (obfd);
 }
 
 /* Create an m68k ELF linker hash table.  */
@@ -977,7 +977,7 @@ elf_m68k_link_hash_table_create (bfd *abfd)
       free (ret);
       return NULL;
     }
-  (void) elf_m68k_link_hash_table_free;
+  ret->root.root.hash_table_free = elf_m68k_link_hash_table_free;
 
   ret->multi_got_.global_symndx = 1;
 
diff --git a/bfd/elf32-metag.c b/bfd/elf32-metag.c
index fde454b..47ca5de 100644
--- a/bfd/elf32-metag.c
+++ b/bfd/elf32-metag.c
@@ -1020,13 +1020,13 @@ metag_link_hash_newfunc (struct bfd_hash_entry *entry,
 /* Free the derived linker hash table.  */
 
 static void
-elf_metag_link_hash_table_free (struct bfd_link_hash_table *btab)
+elf_metag_link_hash_table_free (bfd *obfd)
 {
   struct elf_metag_link_hash_table *htab
-    = (struct elf_metag_link_hash_table *) btab;
+    = (struct elf_metag_link_hash_table *) obfd->link.hash;
 
   bfd_hash_table_free (&htab->bstab);
-  _bfd_elf_link_hash_table_free (btab);
+  _bfd_elf_link_hash_table_free (obfd);
 }
 
 /* Create the derived linker hash table.  The Meta ELF port uses the derived
@@ -1055,8 +1055,11 @@ elf_metag_link_hash_table_create (bfd *abfd)
   /* Init the stub hash table too.  */
   if (!bfd_hash_table_init (&htab->bstab, stub_hash_newfunc,
 			    sizeof (struct elf_metag_stub_hash_entry)))
-    return NULL;
-  (void) elf_metag_link_hash_table_free;
+    {
+      _bfd_elf_link_hash_table_free (abfd);
+      return NULL;
+    }
+  htab->etab.root.hash_table_free = elf_metag_link_hash_table_free;
 
   return &htab->etab.root;
 }
diff --git a/bfd/elf32-nios2.c b/bfd/elf32-nios2.c
index ba6a371..9b3f436 100644
--- a/bfd/elf32-nios2.c
+++ b/bfd/elf32-nios2.c
@@ -5106,13 +5106,13 @@ nios2_elf32_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
 
 /* Free the derived linker hash table.  */
 static void
-nios2_elf32_link_hash_table_free (struct bfd_link_hash_table *btab)
+nios2_elf32_link_hash_table_free (bfd *obfd)
 {
   struct elf32_nios2_link_hash_table *htab
-    = (struct elf32_nios2_link_hash_table *) btab;
+    = (struct elf32_nios2_link_hash_table *) obfd->link.hash;
 
   bfd_hash_table_free (&htab->bstab);
-  _bfd_elf_link_hash_table_free (btab);
+  _bfd_elf_link_hash_table_free (obfd);
 }
 
 /* Implement bfd_elf32_bfd_link_hash_table_create.  */
@@ -5139,8 +5139,11 @@ nios2_elf32_link_hash_table_create (bfd *abfd)
   /* Init the stub hash table too.  */
   if (!bfd_hash_table_init (&ret->bstab, stub_hash_newfunc,
 			    sizeof (struct elf32_nios2_stub_hash_entry)))
-    return NULL;
-  (void) nios2_elf32_link_hash_table_free;
+    {
+      _bfd_elf_link_hash_table_free (abfd);
+      return NULL;
+    }
+  ret->root.root.hash_table_free = nios2_elf32_link_hash_table_free;
 
   return &ret->root.root;
 }
diff --git a/bfd/elf32-xgate.c b/bfd/elf32-xgate.c
index 588901b..01f39fa 100644
--- a/bfd/elf32-xgate.c
+++ b/bfd/elf32-xgate.c
@@ -426,20 +426,20 @@ xgate_info_to_howto_rel (bfd *abfd ATTRIBUTE_UNUSED,
   cache_ptr->howto = &elf_xgate_howto_table[r_type];
 }
 
-/* Free the derived linker hash table.  */
+/* Destroy an XGATE ELF linker hash table.  */
 
-void
-xgate_elf_bfd_link_hash_table_free (struct bfd_link_hash_table *hash)
+static void
+xgate_elf_bfd_link_hash_table_free (bfd *obfd)
 {
   struct xgate_elf_link_hash_table *ret =
-      (struct xgate_elf_link_hash_table *) hash;
+      (struct xgate_elf_link_hash_table *) obfd->link.hash;
 
   bfd_hash_table_free (ret->stub_hash_table);
   free (ret->stub_hash_table);
-  _bfd_elf_link_hash_table_free (hash);
+  _bfd_elf_link_hash_table_free (obfd);
 }
 
-/* Create a XGATE ELF linker hash table.  */
+/* Create an XGATE ELF linker hash table.  */
 
 static struct bfd_link_hash_table*
 xgate_elf_bfd_link_hash_table_create (bfd *abfd)
@@ -464,7 +464,7 @@ xgate_elf_bfd_link_hash_table_create (bfd *abfd)
   ret->stub_hash_table = (struct bfd_hash_table*) bfd_zmalloc (amt);
   if (ret->stub_hash_table == NULL)
     {
-      free (ret);
+      _bfd_elf_link_hash_table_free (abfd);
       return NULL;
     }
 
@@ -472,9 +472,10 @@ xgate_elf_bfd_link_hash_table_create (bfd *abfd)
       sizeof(struct elf32_xgate_stub_hash_entry)))
     {
       free (ret->stub_hash_table);
-      free (ret);
+      _bfd_elf_link_hash_table_free (abfd);
       return NULL;
     }
+  ret->root.root.hash_table_free = xgate_elf_bfd_link_hash_table_free;
 
   return &ret->root.root;
 }
diff --git a/bfd/elf32-xgate.h b/bfd/elf32-xgate.h
index 8a178c2..f130001 100644
--- a/bfd/elf32-xgate.h
+++ b/bfd/elf32-xgate.h
@@ -100,7 +100,6 @@ struct xgate_elf_link_hash_table
 
 extern struct xgate_elf_link_hash_table* xgate_elf_hash_table_create
   (bfd *);
-extern void xgate_elf_bfd_link_hash_table_free (struct bfd_link_hash_table *);
 
 extern void xgate_elf_get_bank_parameters (struct bfd_link_info *);
 
diff --git a/bfd/elf64-ia64-vms.c b/bfd/elf64-ia64-vms.c
index 4beeca2..dd86e3c 100644
--- a/bfd/elf64-ia64-vms.c
+++ b/bfd/elf64-ia64-vms.c
@@ -1023,10 +1023,10 @@ elf64_ia64_local_dyn_info_free (void **slot,
 /* Destroy IA-64 linker hash table.  */
 
 static void
-elf64_ia64_link_hash_table_free (struct bfd_link_hash_table *hash)
+elf64_ia64_link_hash_table_free (bfd *obfd)
 {
   struct elf64_ia64_link_hash_table *ia64_info
-    = (struct elf64_ia64_link_hash_table *) hash;
+    = (struct elf64_ia64_link_hash_table *) obfd->link.hash;
   if (ia64_info->loc_hash_table)
     {
       htab_traverse (ia64_info->loc_hash_table,
@@ -1037,7 +1037,7 @@ elf64_ia64_link_hash_table_free (struct bfd_link_hash_table *hash)
     objalloc_free ((struct objalloc *) ia64_info->loc_hash_memory);
   elf_link_hash_traverse (&ia64_info->root,
 			  elf64_ia64_global_dyn_info_free, NULL);
-  _bfd_elf_link_hash_table_free (hash);
+  _bfd_elf_link_hash_table_free (obfd);
 }
 
 /* Create the derived linker hash table.  The IA-64 ELF port uses this
@@ -1067,10 +1067,10 @@ elf64_ia64_hash_table_create (bfd *abfd)
   ret->loc_hash_memory = objalloc_create ();
   if (!ret->loc_hash_table || !ret->loc_hash_memory)
     {
-      free (ret);
+      elf64_ia64_link_hash_table_free (abfd);
       return NULL;
     }
-  (void) elf64_ia64_link_hash_table_free;
+  ret->root.root.hash_table_free = elf64_ia64_link_hash_table_free;
 
   return &ret->root.root;
 }
diff --git a/bfd/elf64-ppc.c b/bfd/elf64-ppc.c
index 581ce55..46cba68 100644
--- a/bfd/elf64-ppc.c
+++ b/bfd/elf64-ppc.c
@@ -4144,15 +4144,16 @@ tocsave_htab_eq (const void *p1, const void *p2)
 /* Destroy a ppc64 ELF linker hash table.  */
 
 static void
-ppc64_elf_link_hash_table_free (struct bfd_link_hash_table *hash)
+ppc64_elf_link_hash_table_free (bfd *obfd)
 {
-  struct ppc_link_hash_table *htab = (struct ppc_link_hash_table *) hash;
+  struct ppc_link_hash_table *htab;
 
-  bfd_hash_table_free (&htab->stub_hash_table);
-  bfd_hash_table_free (&htab->branch_hash_table);
+  htab = (struct ppc_link_hash_table *) obfd->link.hash;
   if (htab->tocsave_htab)
     htab_delete (htab->tocsave_htab);
-  _bfd_elf_link_hash_table_free (hash);
+  bfd_hash_table_free (&htab->branch_hash_table);
+  bfd_hash_table_free (&htab->stub_hash_table);
+  _bfd_elf_link_hash_table_free (obfd);
 }
 
 /* Create a ppc64 ELF linker hash table.  */
@@ -4179,7 +4180,7 @@ ppc64_elf_link_hash_table_create (bfd *abfd)
   if (!bfd_hash_table_init (&htab->stub_hash_table, stub_hash_newfunc,
 			    sizeof (struct ppc_stub_hash_entry)))
     {
-      _bfd_elf_link_hash_table_free ((struct bfd_link_hash_table *) htab);
+      _bfd_elf_link_hash_table_free (abfd);
       return NULL;
     }
 
@@ -4188,7 +4189,7 @@ ppc64_elf_link_hash_table_create (bfd *abfd)
 			    sizeof (struct ppc_branch_hash_entry)))
     {
       bfd_hash_table_free (&htab->stub_hash_table);
-      _bfd_elf_link_hash_table_free ((struct bfd_link_hash_table *) htab);
+      _bfd_elf_link_hash_table_free (abfd);
       return NULL;
     }
 
@@ -4198,12 +4199,10 @@ ppc64_elf_link_hash_table_create (bfd *abfd)
 					NULL);
   if (htab->tocsave_htab == NULL)
     {
-      bfd_hash_table_free (&htab->branch_hash_table);
-      bfd_hash_table_free (&htab->stub_hash_table);
-      _bfd_elf_link_hash_table_free ((struct bfd_link_hash_table *) htab);
+      ppc64_elf_link_hash_table_free (abfd);
       return NULL;
     }
-  (void) ppc64_elf_link_hash_table_free;
+  htab->elf.root.hash_table_free = ppc64_elf_link_hash_table_free;
 
   /* Initializing two fields of the union is just cosmetic.  We really
      only care about glist, but when compiled on a 32-bit host the
diff --git a/bfd/elf64-x86-64.c b/bfd/elf64-x86-64.c
index 27f0a54..894ab98 100644
--- a/bfd/elf64-x86-64.c
+++ b/bfd/elf64-x86-64.c
@@ -970,16 +970,16 @@ elf_x86_64_get_local_sym_hash (struct elf_x86_64_link_hash_table *htab,
 /* Destroy an X86-64 ELF linker hash table.  */
 
 static void
-elf_x86_64_link_hash_table_free (struct bfd_link_hash_table *hash)
+elf_x86_64_link_hash_table_free (bfd *obfd)
 {
   struct elf_x86_64_link_hash_table *htab
-    = (struct elf_x86_64_link_hash_table *) hash;
+    = (struct elf_x86_64_link_hash_table *) obfd->link.hash;
 
   if (htab->loc_hash_table)
     htab_delete (htab->loc_hash_table);
   if (htab->loc_hash_memory)
     objalloc_free ((struct objalloc *) htab->loc_hash_memory);
-  _bfd_elf_link_hash_table_free (hash);
+  _bfd_elf_link_hash_table_free (obfd);
 }
 
 /* Create an X86-64 ELF linker hash table.  */
@@ -1027,10 +1027,10 @@ elf_x86_64_link_hash_table_create (bfd *abfd)
   ret->loc_hash_memory = objalloc_create ();
   if (!ret->loc_hash_table || !ret->loc_hash_memory)
     {
-      free (ret);
+      elf_x86_64_link_hash_table_free (abfd);
       return NULL;
     }
-  (void) elf_x86_64_link_hash_table_free;
+  ret->elf.root.hash_table_free = elf_x86_64_link_hash_table_free;
 
   return &ret->elf.root;
 }
diff --git a/bfd/elflink.c b/bfd/elflink.c
index 2d953b5..ee80bcc 100644
--- a/bfd/elflink.c
+++ b/bfd/elflink.c
@@ -6901,6 +6901,7 @@ _bfd_elf_link_hash_table_create (bfd *abfd)
       free (ret);
       return NULL;
     }
+  ret->root.hash_table_free = _bfd_elf_link_hash_table_free;
 
   return &ret->root;
 }
@@ -6908,13 +6909,15 @@ _bfd_elf_link_hash_table_create (bfd *abfd)
 /* Destroy an ELF linker hash table.  */
 
 void
-_bfd_elf_link_hash_table_free (struct bfd_link_hash_table *hash)
+_bfd_elf_link_hash_table_free (bfd *obfd)
 {
-  struct elf_link_hash_table *htab = (struct elf_link_hash_table *) hash;
+  struct elf_link_hash_table *htab;
+
+  htab = (struct elf_link_hash_table *) obfd->link.hash;
   if (htab->dynstr != NULL)
     _bfd_elf_strtab_free (htab->dynstr);
   _bfd_merge_sections_free (htab->merge_info);
-  _bfd_generic_link_hash_table_free (hash);
+  _bfd_generic_link_hash_table_free (obfd);
 }
 
 /* This is a hook for the ELF emulation code in the generic linker to
diff --git a/bfd/elfnn-aarch64.c b/bfd/elfnn-aarch64.c
index 4baa41b..a8578da 100644
--- a/bfd/elfnn-aarch64.c
+++ b/bfd/elfnn-aarch64.c
@@ -2058,10 +2058,10 @@ elfNN_aarch64_copy_indirect_symbol (struct bfd_link_info *info,
 /* Destroy an AArch64 elf linker hash table.  */
 
 static void
-elfNN_aarch64_link_hash_table_free (struct bfd_link_hash_table *hash)
+elfNN_aarch64_link_hash_table_free (bfd *obfd)
 {
   struct elf_aarch64_link_hash_table *ret
-    = (struct elf_aarch64_link_hash_table *) hash;
+    = (struct elf_aarch64_link_hash_table *) obfd->link.hash;
 
   if (ret->loc_hash_table)
     htab_delete (ret->loc_hash_table);
@@ -2069,7 +2069,7 @@ elfNN_aarch64_link_hash_table_free (struct bfd_link_hash_table *hash)
     objalloc_free ((struct objalloc *) ret->loc_hash_memory);
 
   bfd_hash_table_free (&ret->stub_hash_table);
-  _bfd_elf_link_hash_table_free (hash);
+  _bfd_elf_link_hash_table_free (obfd);
 }
 
 /* Create an AArch64 elf linker hash table.  */
@@ -2100,7 +2100,7 @@ elfNN_aarch64_link_hash_table_create (bfd *abfd)
   if (!bfd_hash_table_init (&ret->stub_hash_table, stub_hash_newfunc,
 			    sizeof (struct elf_aarch64_stub_hash_entry)))
     {
-      free (ret);
+      _bfd_elf_link_hash_table_free (abfd);
       return NULL;
     }
 
@@ -2111,10 +2111,10 @@ elfNN_aarch64_link_hash_table_create (bfd *abfd)
   ret->loc_hash_memory = objalloc_create ();
   if (!ret->loc_hash_table || !ret->loc_hash_memory)
     {
-      free (ret);
+      elfNN_aarch64_link_hash_table_free (abfd);
       return NULL;
     }
-  (void) elfNN_aarch64_link_hash_table_free;
+  ret->root.root.hash_table_free = elfNN_aarch64_link_hash_table_free;
 
   return &ret->root.root;
 }
diff --git a/bfd/elfnn-ia64.c b/bfd/elfnn-ia64.c
index c87dd99..a8d8d0b 100644
--- a/bfd/elfnn-ia64.c
+++ b/bfd/elfnn-ia64.c
@@ -1414,10 +1414,10 @@ elfNN_ia64_local_dyn_info_free (void **slot,
 /* Destroy IA-64 linker hash table.  */
 
 static void
-elfNN_ia64_link_hash_table_free (struct bfd_link_hash_table *hash)
+elfNN_ia64_link_hash_table_free (bfd *obfd)
 {
   struct elfNN_ia64_link_hash_table *ia64_info
-    = (struct elfNN_ia64_link_hash_table *) hash;
+    = (struct elfNN_ia64_link_hash_table *) obfd->link.hash;
   if (ia64_info->loc_hash_table)
     {
       htab_traverse (ia64_info->loc_hash_table,
@@ -1428,7 +1428,7 @@ elfNN_ia64_link_hash_table_free (struct bfd_link_hash_table *hash)
     objalloc_free ((struct objalloc *) ia64_info->loc_hash_memory);
   elf_link_hash_traverse (&ia64_info->root,
 			  elfNN_ia64_global_dyn_info_free, NULL);
-  _bfd_elf_link_hash_table_free (hash);
+  _bfd_elf_link_hash_table_free (obfd);
 }
 
 /* Create the derived linker hash table.  The IA-64 ELF port uses this
@@ -1458,10 +1458,10 @@ elfNN_ia64_hash_table_create (bfd *abfd)
   ret->loc_hash_memory = objalloc_create ();
   if (!ret->loc_hash_table || !ret->loc_hash_memory)
     {
-      free (ret);
+      elfNN_ia64_link_hash_table_free (abfd);
       return NULL;
     }
-  (void) elfNN_ia64_link_hash_table_free;
+  ret->root.root.hash_table_free = elfNN_ia64_link_hash_table_free;
 
   return &ret->root.root;
 }
diff --git a/bfd/elfxx-sparc.c b/bfd/elfxx-sparc.c
index 48ca02a..e8ebcb3 100644
--- a/bfd/elfxx-sparc.c
+++ b/bfd/elfxx-sparc.c
@@ -1104,17 +1104,17 @@ elf_sparc_get_local_sym_hash (struct _bfd_sparc_elf_link_hash_table *htab,
 
 /* Destroy a SPARC ELF linker hash table.  */
 
-void
-_bfd_sparc_elf_link_hash_table_free (struct bfd_link_hash_table *hash)
+static void
+_bfd_sparc_elf_link_hash_table_free (bfd *obfd)
 {
   struct _bfd_sparc_elf_link_hash_table *htab
-    = (struct _bfd_sparc_elf_link_hash_table *) hash;
+    = (struct _bfd_sparc_elf_link_hash_table *) obfd->link.hash;
 
   if (htab->loc_hash_table)
     htab_delete (htab->loc_hash_table);
   if (htab->loc_hash_memory)
     objalloc_free ((struct objalloc *) htab->loc_hash_memory);
-  _bfd_generic_link_hash_table_free (hash);
+  _bfd_elf_link_hash_table_free (obfd);
 }
 
 /* Create a SPARC ELF linker hash table.  */
@@ -1183,9 +1183,10 @@ _bfd_sparc_elf_link_hash_table_create (bfd *abfd)
   ret->loc_hash_memory = objalloc_create ();
   if (!ret->loc_hash_table || !ret->loc_hash_memory)
     {
-      free (ret);
+      _bfd_sparc_elf_link_hash_table_free (abfd);
       return NULL;
     }
+  ret->elf.root.hash_table_free = _bfd_sparc_elf_link_hash_table_free;
 
   return &ret->elf.root;
 }
diff --git a/bfd/elfxx-sparc.h b/bfd/elfxx-sparc.h
index 775c4d7..cf1991b 100644
--- a/bfd/elfxx-sparc.h
+++ b/bfd/elfxx-sparc.h
@@ -106,8 +106,6 @@ extern bfd_boolean _bfd_sparc_elf_mkobject
   (bfd *);
 extern struct bfd_link_hash_table *_bfd_sparc_elf_link_hash_table_create
   (bfd *);
-extern void _bfd_sparc_elf_link_hash_table_free
-  (struct bfd_link_hash_table *);
 extern bfd_boolean _bfd_sparc_elf_create_dynamic_sections
   (bfd *, struct bfd_link_info *);
 extern void _bfd_sparc_elf_copy_indirect_symbol
diff --git a/bfd/hash.c b/bfd/hash.c
index 3e6a172..4149474 100644
--- a/bfd/hash.c
+++ b/bfd/hash.c
@@ -392,6 +392,7 @@ bfd_hash_table_init_n (struct bfd_hash_table *table,
       objalloc_alloc ((struct objalloc *) table->memory, alloc);
   if (table->table == NULL)
     {
+      bfd_hash_table_free (table);
       bfd_set_error (bfd_error_no_memory);
       return FALSE;
     }
diff --git a/bfd/libbfd-in.h b/bfd/libbfd-in.h
index c17e508..03dbd0a 100644
--- a/bfd/libbfd-in.h
+++ b/bfd/libbfd-in.h
@@ -588,7 +588,7 @@ extern struct bfd_link_hash_table *_bfd_generic_link_hash_table_create
 
 /* Generic link hash table destruction routine.  */
 extern void _bfd_generic_link_hash_table_free
-  (struct bfd_link_hash_table *);
+  (bfd *);
 
 /* Generic add symbol routine.  */
 extern bfd_boolean _bfd_generic_link_add_symbols
diff --git a/bfd/libbfd.h b/bfd/libbfd.h
index 923eb93..3bb3726 100644
--- a/bfd/libbfd.h
+++ b/bfd/libbfd.h
@@ -593,7 +593,7 @@ extern struct bfd_link_hash_table *_bfd_generic_link_hash_table_create
 
 /* Generic link hash table destruction routine.  */
 extern void _bfd_generic_link_hash_table_free
-  (struct bfd_link_hash_table *);
+  (bfd *);
 
 /* Generic add symbol routine.  */
 extern bfd_boolean _bfd_generic_link_add_symbols
diff --git a/bfd/libcoff-in.h b/bfd/libcoff-in.h
index 367d3bc..8a45bf6 100644
--- a/bfd/libcoff-in.h
+++ b/bfd/libcoff-in.h
@@ -603,8 +603,6 @@ extern long _bfd_xcoff_canonicalize_dynamic_reloc
   (bfd *, arelent **, asymbol **);
 extern struct bfd_link_hash_table *_bfd_xcoff_bfd_link_hash_table_create
   (bfd *);
-extern void _bfd_xcoff_bfd_link_hash_table_free
-  (struct bfd_link_hash_table *);
 extern bfd_boolean _bfd_xcoff_bfd_link_add_symbols
   (bfd *, struct bfd_link_info *);
 extern bfd_boolean _bfd_xcoff_bfd_final_link
diff --git a/bfd/libcoff.h b/bfd/libcoff.h
index 24b9b57..d2c794d 100644
--- a/bfd/libcoff.h
+++ b/bfd/libcoff.h
@@ -607,8 +607,6 @@ extern long _bfd_xcoff_canonicalize_dynamic_reloc
   (bfd *, arelent **, asymbol **);
 extern struct bfd_link_hash_table *_bfd_xcoff_bfd_link_hash_table_create
   (bfd *);
-extern void _bfd_xcoff_bfd_link_hash_table_free
-  (struct bfd_link_hash_table *);
 extern bfd_boolean _bfd_xcoff_bfd_link_add_symbols
   (bfd *, struct bfd_link_info *);
 extern bfd_boolean _bfd_xcoff_bfd_final_link
diff --git a/bfd/linker.c b/bfd/linker.c
index 1afe4ed..483a0d4 100644
--- a/bfd/linker.c
+++ b/bfd/linker.c
@@ -482,11 +482,22 @@ _bfd_link_hash_table_init
 				      const char *),
    unsigned int entsize)
 {
+  bfd_boolean ret;
+
+  BFD_ASSERT (!abfd->is_linker_output && !abfd->link.hash);
   table->undefs = NULL;
   table->undefs_tail = NULL;
   table->type = bfd_link_generic_hash_table;
 
-  return bfd_hash_table_init (&table->table, newfunc, entsize);
+  ret = bfd_hash_table_init (&table->table, newfunc, entsize);
+  if (ret)
+    {
+      /* Arrange for destruction of this hash table on closing ABFD.  */
+      table->hash_table_free = _bfd_generic_link_hash_table_free;
+      abfd->link.hash = table;
+      abfd->is_linker_output = TRUE;
+    }
+  return ret;
 }
 
 /* Look up a symbol in a link hash table.  If follow is TRUE, we
@@ -771,13 +782,16 @@ _bfd_generic_link_hash_table_create (bfd *abfd)
 }
 
 void
-_bfd_generic_link_hash_table_free (struct bfd_link_hash_table *hash)
+_bfd_generic_link_hash_table_free (bfd *obfd)
 {
-  struct generic_link_hash_table *ret
-    = (struct generic_link_hash_table *) hash;
+  struct generic_link_hash_table *ret;
 
+  BFD_ASSERT (obfd->is_linker_output && obfd->link.hash);
+  ret = (struct generic_link_hash_table *) obfd->link.hash;
   bfd_hash_table_free (&ret->root.table);
   free (ret);
+  obfd->link.hash = NULL;
+  obfd->is_linker_output = FALSE;
 }
 
 /* Grab the symbols for an object file when doing a generic link.  We
diff --git a/bfd/simple.c b/bfd/simple.c
index 7d256bf..ca64101 100644
--- a/bfd/simple.c
+++ b/bfd/simple.c
@@ -188,6 +188,7 @@ bfd_simple_get_relocated_section_contents (bfd *abfd,
   bfd_byte *contents, *data;
   int storage_needed;
   struct saved_offsets saved_offsets;
+  bfd *link_next;
 
   /* Don't apply relocation on executable and shared library.  See
      PR 4756.  */
@@ -209,6 +210,8 @@ bfd_simple_get_relocated_section_contents (bfd *abfd,
   link_info.input_bfds = abfd;
   link_info.input_bfds_tail = &abfd->link.next;
 
+  link_next = abfd->link.next;
+  abfd->link.next = NULL;
   link_info.hash = _bfd_generic_link_hash_table_create (abfd);
   link_info.callbacks = &callbacks;
   callbacks.warning = simple_dummy_warning;
@@ -232,7 +235,11 @@ bfd_simple_get_relocated_section_contents (bfd *abfd,
       bfd_size_type amt = sec->rawsize > sec->size ? sec->rawsize : sec->size;
       data = (bfd_byte *) bfd_malloc (amt);
       if (data == NULL)
-	return NULL;
+	{
+	  _bfd_generic_link_hash_table_free (abfd);
+	  abfd->link.next = link_next;
+	  return NULL;
+	}
       outbuf = data;
     }
 
@@ -243,6 +250,8 @@ bfd_simple_get_relocated_section_contents (bfd *abfd,
     {
       if (data)
 	free (data);
+      _bfd_generic_link_hash_table_free (abfd);
+      abfd->link.next = link_next;
       return NULL;
     }
   bfd_map_over_sections (abfd, simple_save_output_info, &saved_offsets);
@@ -270,6 +279,7 @@ bfd_simple_get_relocated_section_contents (bfd *abfd,
   bfd_map_over_sections (abfd, simple_restore_output_info, &saved_offsets);
   free (saved_offsets.sections);
 
-  _bfd_generic_link_hash_table_free (link_info.hash);
+  _bfd_generic_link_hash_table_free (abfd);
+  abfd->link.next = link_next;
   return contents;
 }
diff --git a/bfd/xcofflink.c b/bfd/xcofflink.c
index f6c7fe6..67e1c52 100644
--- a/bfd/xcofflink.c
+++ b/bfd/xcofflink.c
@@ -573,14 +573,17 @@ xcoff_link_hash_newfunc (struct bfd_hash_entry *entry,
 
 /* Destroy an XCOFF link hash table.  */
 
-void
-_bfd_xcoff_bfd_link_hash_table_free (struct bfd_link_hash_table *hash)
+static void
+_bfd_xcoff_bfd_link_hash_table_free (bfd *obfd)
 {
-  struct xcoff_link_hash_table *ret = (struct xcoff_link_hash_table *) hash;
+  struct xcoff_link_hash_table *ret;
 
-  _bfd_stringtab_free (ret->debug_strtab);
-  bfd_hash_table_free (&ret->root.table);
-  free (ret);
+  ret = (struct xcoff_link_hash_table *) obfd->link.hash;
+  if (ret->archive_info)
+    htab_delete (ret->archive_info);
+  if (ret->debug_strtab)
+    _bfd_stringtab_free (ret->debug_strtab);
+  _bfd_generic_link_hash_table_free (obfd);
 }
 
 /* Create an XCOFF link hash table.  */
@@ -604,6 +607,12 @@ _bfd_xcoff_bfd_link_hash_table_create (bfd *abfd)
   ret->debug_strtab = _bfd_xcoff_stringtab_init ();
   ret->archive_info = htab_create (37, xcoff_archive_info_hash,
 				   xcoff_archive_info_eq, NULL);
+  if (!ret->debug_strtab || !ret->archive_info)
+    {
+      _bfd_xcoff_bfd_link_hash_table_free (abfd);
+      return NULL;
+    }
+  ret->root.hash_table_free = _bfd_xcoff_bfd_link_hash_table_free;
 
   /* The linker will always generate a full a.out header.  We need to
      record that fact now, before the sizeof_headers routine could be
diff --git a/include/bfdlink.h b/include/bfdlink.h
index 391b3a9..fc14a9f 100644
--- a/include/bfdlink.h
+++ b/include/bfdlink.h
@@ -167,6 +167,8 @@ struct bfd_link_hash_table
   struct bfd_link_hash_entry *undefs;
   /* Entries are added to the tail of the undefs list.  */
   struct bfd_link_hash_entry *undefs_tail;
+  /* Function to free the hash table on closing BFD.  */
+  void (*hash_table_free) (bfd *);
   /* The type of the link hash table.  */
   enum bfd_link_hash_table_type type;
 };

-- 
Alan Modra
Australia Development Lab, IBM


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