X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=bfd%2Fmerge.c;h=7aa088ff94734a50eb070351849507b567498f38;hb=91d6fa6a035cc7d0b7be5c99c194a64cb80924b0;hp=eb8ec667ead44ca0cc5e57b6e40c2c1866ffc80d;hpb=eea6121ac0cb22524c627017191ca09825e3d702;p=deliverable%2Fbinutils-gdb.git diff --git a/bfd/merge.c b/bfd/merge.c index eb8ec667ea..7aa088ff94 100644 --- a/bfd/merge.c +++ b/bfd/merge.c @@ -1,12 +1,13 @@ /* SEC_MERGE support. - Copyright 2001, 2002, 2003, 2004 Free Software Foundation, Inc. + Copyright 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 + Free Software Foundation, Inc. Written by Jakub Jelinek . 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 + the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, @@ -16,13 +17,15 @@ 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. */ + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, + MA 02110-1301, USA. */ + /* This file contains support for merging duplicate entities within sections, as used in ELF SHF_MERGE. */ -#include "bfd.h" #include "sysdep.h" +#include "bfd.h" #include "libbfd.h" #include "hashtab.h" #include "libiberty.h" @@ -105,7 +108,8 @@ sec_merge_hash_newfunc (struct bfd_hash_entry *entry, /* Allocate the structure if it has not already been allocated by a subclass. */ if (entry == NULL) - entry = bfd_hash_allocate (table, sizeof (struct sec_merge_hash_entry)); + entry = (struct bfd_hash_entry *) + bfd_hash_allocate (table, sizeof (struct sec_merge_hash_entry)); if (entry == NULL) return NULL; @@ -132,12 +136,12 @@ static struct sec_merge_hash_entry * sec_merge_hash_lookup (struct sec_merge_hash *table, const char *string, unsigned int alignment, bfd_boolean create) { - register const unsigned char *s; - register unsigned long hash; - register unsigned int c; + const unsigned char *s; + unsigned long hash; + unsigned int c; struct sec_merge_hash_entry *hashp; unsigned int len, i; - unsigned int index; + unsigned int _index; hash = 0; len = 0; @@ -188,8 +192,8 @@ sec_merge_hash_lookup (struct sec_merge_hash *table, const char *string, len = table->entsize; } - index = hash % table->table.size; - for (hashp = (struct sec_merge_hash_entry *) table->table.table[index]; + _index = hash % table->table.size; + for (hashp = (struct sec_merge_hash_entry *) table->table.table[_index]; hashp != NULL; hashp = (struct sec_merge_hash_entry *) hashp->root.next) { @@ -217,16 +221,11 @@ sec_merge_hash_lookup (struct sec_merge_hash *table, const char *string, return NULL; hashp = ((struct sec_merge_hash_entry *) - sec_merge_hash_newfunc (NULL, &table->table, string)); + bfd_hash_insert (&table->table, string, hash)); if (hashp == NULL) return NULL; - hashp->root.string = string; - hashp->root.hash = hash; hashp->len = len; hashp->alignment = alignment; - hashp->root.next = table->table.table[index]; - table->table.table[index] = (struct bfd_hash_entry *) hashp; - return hashp; } @@ -237,11 +236,12 @@ sec_merge_init (unsigned int entsize, bfd_boolean strings) { struct sec_merge_hash *table; - table = bfd_malloc (sizeof (struct sec_merge_hash)); + table = (struct sec_merge_hash *) bfd_malloc (sizeof (struct sec_merge_hash)); if (table == NULL) return NULL; - if (! bfd_hash_table_init (&table->table, sec_merge_hash_newfunc)) + if (! bfd_hash_table_init_n (&table->table, sec_merge_hash_newfunc, + sizeof (struct sec_merge_hash_entry), 16699)) { free (table); return NULL; @@ -263,7 +263,7 @@ static struct sec_merge_hash_entry * sec_merge_add (struct sec_merge_hash *tab, const char *str, unsigned int alignment, struct sec_merge_sec_info *secinfo) { - register struct sec_merge_hash_entry *entry; + struct sec_merge_hash_entry *entry; entry = sec_merge_hash_lookup (tab, str, alignment, TRUE); if (entry == NULL) @@ -288,24 +288,27 @@ sec_merge_emit (bfd *abfd, struct sec_merge_hash_entry *entry) { struct sec_merge_sec_info *secinfo = entry->secinfo; asection *sec = secinfo->sec; - char *pad = ""; + char *pad = NULL; bfd_size_type off = 0; int alignment_power = sec->output_section->alignment_power; if (alignment_power) - pad = bfd_zmalloc ((bfd_size_type) 1 << alignment_power); + { + pad = (char *) bfd_zmalloc ((bfd_size_type) 1 << alignment_power); + if (pad == NULL) + return FALSE; + } for (; entry != NULL && entry->secinfo == secinfo; entry = entry->next) { - register const char *str; - register size_t len; + const char *str; + bfd_size_type len; - len = off & (entry->alignment - 1); - if (len) + len = -off & (entry->alignment - 1); + if (len != 0) { - len = entry->alignment - len; if (bfd_bwrite (pad, len, abfd) != len) - break; + goto err; off += len; } @@ -313,15 +316,25 @@ sec_merge_emit (bfd *abfd, struct sec_merge_hash_entry *entry) len = entry->len; if (bfd_bwrite (str, len, abfd) != len) - break; + goto err; off += len; } - if (alignment_power) + /* Trailing alignment needed? */ + off = sec->size - off; + if (off != 0 + && bfd_bwrite (pad, off, abfd) != off) + goto err; + + if (pad != NULL) free (pad); + return TRUE; - return entry == NULL || entry->secinfo != secinfo; + err: + if (pad != NULL) + free (pad); + return FALSE; } /* Register a SEC_MERGE section as a candidate for merging. @@ -378,7 +391,8 @@ _bfd_add_merge_section (bfd *abfd, void **psinfo, asection *sec, if (sinfo == NULL) { /* Initialize the information we need to keep track of. */ - sinfo = bfd_alloc (abfd, sizeof (struct sec_merge_info)); + sinfo = (struct sec_merge_info *) + bfd_alloc (abfd, sizeof (struct sec_merge_info)); if (sinfo == NULL) goto error_return; sinfo->next = (struct sec_merge_info *) *psinfo; @@ -391,7 +405,12 @@ _bfd_add_merge_section (bfd *abfd, void **psinfo, asection *sec, /* Read the section from abfd. */ - amt = sizeof (struct sec_merge_sec_info) + sec->size - 1; + amt = sizeof (struct sec_merge_sec_info) - 1 + sec->size; + if (sec->flags & SEC_STRINGS) + /* Some versions of gcc may emit a string without a zero terminator. + See http://gcc.gnu.org/ml/gcc-patches/2006-06/msg01004.html + Allocate space for an extra zero. */ + amt += sec->entsize; *psecinfo = bfd_alloc (abfd, amt); if (*psecinfo == NULL) goto error_return; @@ -411,6 +430,8 @@ _bfd_add_merge_section (bfd *abfd, void **psinfo, asection *sec, secinfo->first_str = NULL; sec->rawsize = sec->size; + if (sec->flags & SEC_STRINGS) + memset (secinfo->contents + sec->size, 0, sec->entsize); if (! bfd_get_section_contents (sec->owner, sec, secinfo->contents, 0, sec->size)) goto error_return; @@ -446,7 +467,8 @@ record_section (struct sec_merge_info *sinfo, eltalign = ((eltalign ^ (eltalign - 1)) + 1) >> 1; if (!eltalign || eltalign > mask) eltalign = mask + 1; - entry = sec_merge_add (sinfo->htab, p, (unsigned) eltalign, secinfo); + entry = sec_merge_add (sinfo->htab, (char *) p, (unsigned) eltalign, + secinfo); if (! entry) goto error_return; p += entry->len; @@ -477,7 +499,7 @@ record_section (struct sec_merge_info *sinfo, if (!nul && !((p - secinfo->contents) & mask)) { nul = TRUE; - entry = sec_merge_add (sinfo->htab, p, + entry = sec_merge_add (sinfo->htab, (char *) p, (unsigned) mask + 1, secinfo); if (! entry) goto error_return; @@ -491,7 +513,7 @@ record_section (struct sec_merge_info *sinfo, { for (p = secinfo->contents; p < end; p += sec->entsize) { - entry = sec_merge_add (sinfo->htab, p, 1, secinfo); + entry = sec_merge_add (sinfo->htab, (char *) p, 1, secinfo); if (! entry) goto error_return; } @@ -512,8 +534,8 @@ strrevcmp (const void *a, const void *b) struct sec_merge_hash_entry *B = *(struct sec_merge_hash_entry **) b; unsigned int lenA = A->len; unsigned int lenB = B->len; - const unsigned char *s = A->root.string + lenA - 1; - const unsigned char *t = B->root.string + lenB - 1; + const unsigned char *s = (const unsigned char *) A->root.string + lenA - 1; + const unsigned char *t = (const unsigned char *) B->root.string + lenB - 1; int l = lenA < lenB ? lenA : lenB; while (l) @@ -537,8 +559,8 @@ strrevcmp_align (const void *a, const void *b) struct sec_merge_hash_entry *B = *(struct sec_merge_hash_entry **) b; unsigned int lenA = A->len; unsigned int lenB = B->len; - const unsigned char *s = A->root.string + lenA - 1; - const unsigned char *t = B->root.string + lenB - 1; + const unsigned char *s = (const unsigned char *) A->root.string + lenA - 1; + const unsigned char *t = (const unsigned char *) B->root.string + lenB - 1; int l = lenA < lenB ? lenA : lenB; int tail_align = (lenA & (A->alignment - 1)) - (lenB & (A->alignment - 1)); @@ -581,7 +603,7 @@ merge_strings (struct sec_merge_info *sinfo) /* Now sort the strings */ amt = sinfo->htab->size * sizeof (struct sec_merge_hash_entry *); - array = bfd_malloc (amt); + array = (struct sec_merge_hash_entry **) bfd_malloc (amt); if (array == NULL) goto alloc_failure; @@ -655,6 +677,11 @@ alloc_failure: } } secinfo->sec->size = size; + if (secinfo->sec->alignment_power != 0) + { + bfd_size_type align = (bfd_size_type) 1 << secinfo->sec->alignment_power; + secinfo->sec->size = (secinfo->sec->size + align - 1) & -align; + } /* And now adjust the rest, removing them from the chain (but not hashtable) at the same time. */ @@ -677,8 +704,10 @@ alloc_failure: with _bfd_merge_section. */ bfd_boolean -_bfd_merge_sections (bfd *abfd ATTRIBUTE_UNUSED, struct bfd_link_info *info, - void *xsinfo, void (*remove_hook) (bfd *, asection *)) +_bfd_merge_sections (bfd *abfd, + struct bfd_link_info *info ATTRIBUTE_UNUSED, + void *xsinfo, + void (*remove_hook) (bfd *, asection *)) { struct sec_merge_info *sinfo; @@ -743,7 +772,7 @@ _bfd_merge_sections (bfd *abfd ATTRIBUTE_UNUSED, struct bfd_link_info *info, the hash table at all. */ for (secinfo = sinfo->chain; secinfo; secinfo = secinfo->next) if (secinfo->first_str == NULL) - _bfd_strip_section_from_output (info, secinfo->sec); + secinfo->sec->flags |= SEC_EXCLUDE | SEC_KEEP; } return TRUE; @@ -759,9 +788,13 @@ _bfd_write_merged_section (bfd *output_bfd, asection *sec, void *psecinfo) secinfo = (struct sec_merge_sec_info *) psecinfo; + if (!secinfo) + return FALSE; + if (secinfo->first_str == NULL) return TRUE; + /* FIXME: octets_per_byte. */ pos = sec->output_section->filepos + sec->output_offset; if (bfd_seek (output_bfd, pos, SEEK_SET) != 0) return FALSE; @@ -787,6 +820,9 @@ _bfd_merged_section_offset (bfd *output_bfd ATTRIBUTE_UNUSED, asection **psec, secinfo = (struct sec_merge_sec_info *) psecinfo; + if (!secinfo) + return offset; + if (offset >= sec->rawsize) { if (offset > sec->rawsize) @@ -829,7 +865,7 @@ _bfd_merged_section_offset (bfd *output_bfd ATTRIBUTE_UNUSED, asection **psec, { p = secinfo->contents + (offset / sec->entsize) * sec->entsize; } - entry = sec_merge_hash_lookup (secinfo->htab, p, 0, FALSE); + entry = sec_merge_hash_lookup (secinfo->htab, (char *) p, 0, FALSE); if (!entry) { if (! secinfo->htab->strings)