From d495ab0d843def702a6641fa4fc31708d7fc97b1 Mon Sep 17 00:00:00 2001 From: Alan Modra Date: Fri, 13 Jun 2014 19:11:39 +0930 Subject: [PATCH] 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. --- bfd/ChangeLog | 38 ++++++++++++++++++++++++++++++++++++++ bfd/archive.c | 4 ++++ bfd/bfd-in2.h | 3 +++ bfd/bfd.c | 3 +++ bfd/elf-bfd.h | 2 +- bfd/elf-m10300.c | 43 +++++++++++++++++++++++++------------------ bfd/elf32-arm.c | 10 +++++----- bfd/elf32-avr.c | 13 ++++++++----- bfd/elf32-hppa.c | 13 ++++++++----- bfd/elf32-i386.c | 10 +++++----- bfd/elf32-m68hc1x.c | 17 +++++++++++------ bfd/elf32-m68hc1x.h | 1 - bfd/elf32-m68k.c | 8 ++++---- bfd/elf32-metag.c | 13 ++++++++----- bfd/elf32-nios2.c | 13 ++++++++----- bfd/elf32-xgate.c | 17 +++++++++-------- bfd/elf32-xgate.h | 1 - bfd/elf64-ia64-vms.c | 10 +++++----- bfd/elf64-ppc.c | 21 ++++++++++----------- bfd/elf64-x86-64.c | 10 +++++----- bfd/elflink.c | 9 ++++++--- bfd/elfnn-aarch64.c | 12 ++++++------ bfd/elfnn-ia64.c | 10 +++++----- bfd/elfxx-sparc.c | 11 ++++++----- bfd/elfxx-sparc.h | 2 -- bfd/hash.c | 1 + bfd/libbfd-in.h | 2 +- bfd/libbfd.h | 2 +- bfd/libcoff-in.h | 2 -- bfd/libcoff.h | 2 -- bfd/linker.c | 22 ++++++++++++++++++---- bfd/simple.c | 14 ++++++++++++-- bfd/xcofflink.c | 21 +++++++++++++++------ include/ChangeLog | 4 ++++ include/bfdlink.h | 2 ++ 35 files changed, 237 insertions(+), 129 deletions(-) diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 4cb3d06b9d6..0caff71a83c 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,41 @@ +2014-06-13 Alan Modra + + * 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. + 2014-06-13 Alan Modra PR 17047 diff --git a/bfd/archive.c b/bfd/archive.c index 157a3f7c4d4..1c3ad5240ff 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 07d94dfce2a..d9056ce33ff 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 2406319db57..e19bcf77afe 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 1bbe771cfc5..a06c54bda52 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 4cc879ec32a..f29025d5d92 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 6358b580ba5..ef8bfa65614 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 55953841ce7..b46a44c6191 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 635ec42d943..0588ebbfcdf 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 eb5b3d01be8..551d17978e6 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 7c845171ec2..c3a99df8e48 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 1d1f28814bb..89ccd7fd8ad 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 b857a0dfa88..952d819fe21 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 fde454b80e3..47ca5debe83 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 ba6a3718323..9b3f4361ad6 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 588901bab11..01f39faed50 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 8a178c22ba2..f1300014dc1 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 4beeca204ba..dd86e3c6308 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 581ce55f309..46cba684175 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 27f0a54fdbb..894ab988053 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 2d953b57a06..ee80bcc7e2e 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 4baa41b00c4..a8578dae0cd 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 c87dd996efe..a8d8d0bcc22 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 48ca02af9cd..e8ebcb30632 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 775c4d73c80..cf1991b411b 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 3e6a172ba2f..4149474ffff 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 c17e508289c..03dbd0af347 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 923eb93d673..3bb37260c77 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 367d3bc2e1b..8a45bf62c12 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 24b9b57f4e0..d2c794deb9c 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 1afe4ed6f3e..483a0d4ea92 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 7d256bf36ef..ca64101b83c 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 f6c7fe6fa30..67e1c523d2a 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/ChangeLog b/include/ChangeLog index eaf81fdbc70..96ae31d19f7 100644 --- a/include/ChangeLog +++ b/include/ChangeLog @@ -1,3 +1,7 @@ +2014-06-13 Alan Modra + + * bfdlink.h (struct bfd_link_hash_table): Add hash_table_free field. + 2014-06-13 Alan Modra * bfdlink.h: Update for bfd.link_next change. diff --git a/include/bfdlink.h b/include/bfdlink.h index 391b3a981bf..fc14a9fadb6 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; }; -- 2.30.2