diff options
Diffstat (limited to 'contrib/binutils/bfd/merge.c')
-rw-r--r-- | contrib/binutils/bfd/merge.c | 208 |
1 files changed, 113 insertions, 95 deletions
diff --git a/contrib/binutils/bfd/merge.c b/contrib/binutils/bfd/merge.c index 89f45cd521a2..c1795d29112f 100644 --- a/contrib/binutils/bfd/merge.c +++ b/contrib/binutils/bfd/merge.c @@ -1,5 +1,6 @@ /* SEC_MERGE support. - Copyright 2001, 2002, 2003 Free Software Foundation, Inc. + Copyright 2001, 2002, 2003, 2004, 2005, 2006 + Free Software Foundation, Inc. Written by Jakub Jelinek <jakub@redhat.com>. This file is part of BFD, the Binary File Descriptor library. @@ -16,7 +17,7 @@ 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. */ @@ -90,7 +91,7 @@ struct sec_merge_sec_info /* A hash table used to hold section content. */ struct sec_merge_hash *htab; /* First string in this section. */ - struct sec_merge_hash_entry *first; + struct sec_merge_hash_entry *first_str; /* Original section content. */ unsigned char contents[1]; }; @@ -102,30 +103,28 @@ static struct bfd_hash_entry * sec_merge_hash_newfunc (struct bfd_hash_entry *entry, struct bfd_hash_table *table, const char *string) { - struct sec_merge_hash_entry *ret = (struct sec_merge_hash_entry *) entry; - /* Allocate the structure if it has not already been allocated by a subclass. */ - if (ret == (struct sec_merge_hash_entry *) NULL) - ret = ((struct sec_merge_hash_entry *) - bfd_hash_allocate (table, sizeof (struct sec_merge_hash_entry))); - if (ret == (struct sec_merge_hash_entry *) NULL) + if (entry == NULL) + entry = bfd_hash_allocate (table, sizeof (struct sec_merge_hash_entry)); + if (entry == NULL) return NULL; /* Call the allocation method of the superclass. */ - ret = ((struct sec_merge_hash_entry *) - bfd_hash_newfunc ((struct bfd_hash_entry *) ret, table, string)); + entry = bfd_hash_newfunc (entry, table, string); - if (ret) + if (entry != NULL) { /* Initialize the local fields. */ + struct sec_merge_hash_entry *ret = (struct sec_merge_hash_entry *) entry; + ret->u.suffix = NULL; ret->alignment = 0; ret->secinfo = NULL; ret->next = NULL; } - return (struct bfd_hash_entry *) ret; + return entry; } /* Look up an entry in a section merge hash table. */ @@ -192,7 +191,7 @@ sec_merge_hash_lookup (struct sec_merge_hash *table, const char *string, index = hash % table->table.size; for (hashp = (struct sec_merge_hash_entry *) table->table.table[index]; - hashp != (struct sec_merge_hash_entry *) NULL; + hashp != NULL; hashp = (struct sec_merge_hash_entry *) hashp->root.next) { if (hashp->root.hash == hash @@ -216,13 +215,12 @@ sec_merge_hash_lookup (struct sec_merge_hash *table, const char *string, } if (! create) - return (struct sec_merge_hash_entry *) NULL; + return NULL; - hashp = (struct sec_merge_hash_entry *) - sec_merge_hash_newfunc ((struct bfd_hash_entry *) NULL, - (struct bfd_hash_table *) table, string); - if (hashp == (struct sec_merge_hash_entry *) NULL) - return (struct sec_merge_hash_entry *) NULL; + hashp = ((struct sec_merge_hash_entry *) + sec_merge_hash_newfunc (NULL, &table->table, string)); + if (hashp == NULL) + return NULL; hashp->root.string = string; hashp->root.hash = hash; hashp->len = len; @@ -239,13 +237,13 @@ static struct sec_merge_hash * sec_merge_init (unsigned int entsize, bfd_boolean strings) { struct sec_merge_hash *table; - bfd_size_type amt = sizeof (struct sec_merge_hash); - table = (struct sec_merge_hash *) bfd_malloc (amt); + table = 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; @@ -292,56 +290,73 @@ 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 = bfd_get_section_alignment (abfd, sec->output_section); + int alignment_power = sec->output_section->alignment_power; if (alignment_power) - pad = bfd_zmalloc ((bfd_size_type) 1 << alignment_power); + { + pad = 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, (bfd_size_type) len, abfd) != len) - break; + if (bfd_bwrite (pad, len, abfd) != len) + goto err; off += len; } str = entry->root.string; len = entry->len; - if (bfd_bwrite (str, (bfd_size_type) len, abfd) != len) - break; + if (bfd_bwrite (str, len, abfd) != len) + 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; } -/* This function is called for each input file from the add_symbols - pass of the linker. */ +/* Register a SEC_MERGE section as a candidate for merging. + This function is called for all non-dynamic SEC_MERGE input sections. */ bfd_boolean -_bfd_merge_section (bfd *abfd, void **psinfo, asection *sec, void **psecinfo) +_bfd_add_merge_section (bfd *abfd, void **psinfo, asection *sec, + void **psecinfo) { struct sec_merge_info *sinfo; struct sec_merge_sec_info *secinfo; unsigned int align; bfd_size_type amt; - if (sec->_raw_size == 0 - || (sec->flags & SEC_EXCLUDE) - || (sec->flags & SEC_MERGE) == 0 + if ((abfd->flags & DYNAMIC) != 0 + || (sec->flags & SEC_MERGE) == 0) + abort (); + + if (sec->size == 0 + || (sec->flags & SEC_EXCLUDE) != 0 || sec->entsize == 0) return TRUE; @@ -351,12 +366,12 @@ _bfd_merge_section (bfd *abfd, void **psinfo, asection *sec, void **psecinfo) return TRUE; } - align = bfd_get_section_alignment (sec->owner, sec); - if ((sec->entsize < (unsigned int)(1 << align) + align = sec->alignment_power; + if ((sec->entsize < (unsigned) 1 << align && ((sec->entsize & (sec->entsize - 1)) || !(sec->flags & SEC_STRINGS))) - || (sec->entsize > (unsigned int)(1 << align) - && (sec->entsize & ((1 << align) - 1)))) + || (sec->entsize > (unsigned) 1 << align + && (sec->entsize & (((unsigned) 1 << align) - 1)))) { /* Sanity check. If string character size is smaller than alignment, then we require character size to be a power @@ -371,14 +386,14 @@ _bfd_merge_section (bfd *abfd, void **psinfo, asection *sec, void **psecinfo) if ((secinfo = sinfo->chain) && ! ((secinfo->sec->flags ^ sec->flags) & (SEC_MERGE | SEC_STRINGS)) && secinfo->sec->entsize == sec->entsize - && ! strcmp (secinfo->sec->name, sec->name)) + && secinfo->sec->alignment_power == sec->alignment_power + && secinfo->sec->output_section == sec->output_section) break; if (sinfo == NULL) { /* Initialize the information we need to keep track of. */ - amt = sizeof (struct sec_merge_info); - sinfo = (struct sec_merge_info *) bfd_alloc (abfd, amt); + sinfo = bfd_alloc (abfd, sizeof (struct sec_merge_info)); if (sinfo == NULL) goto error_return; sinfo->next = (struct sec_merge_info *) *psinfo; @@ -391,12 +406,12 @@ _bfd_merge_section (bfd *abfd, void **psinfo, asection *sec, void **psecinfo) /* Read the section from abfd. */ - amt = sizeof (struct sec_merge_sec_info) + sec->_raw_size - 1; + amt = sizeof (struct sec_merge_sec_info) + sec->size - 1; *psecinfo = bfd_alloc (abfd, amt); if (*psecinfo == NULL) goto error_return; - secinfo = (struct sec_merge_sec_info *)*psecinfo; + secinfo = (struct sec_merge_sec_info *) *psecinfo; if (sinfo->chain) { secinfo->next = sinfo->chain->next; @@ -408,10 +423,11 @@ _bfd_merge_section (bfd *abfd, void **psinfo, asection *sec, void **psecinfo) secinfo->sec = sec; secinfo->psecinfo = psecinfo; secinfo->htab = sinfo->htab; - secinfo->first = NULL; + secinfo->first_str = NULL; + sec->rawsize = sec->size; if (! bfd_get_section_contents (sec->owner, sec, secinfo->contents, - (bfd_vma) 0, sec->_raw_size)) + 0, sec->size)) goto error_return; return TRUE; @@ -433,8 +449,8 @@ record_section (struct sec_merge_info *sinfo, bfd_vma mask, eltalign; unsigned int align, i; - align = bfd_get_section_alignment (sec->owner, sec); - end = secinfo->contents + sec->_raw_size; + align = sec->alignment_power; + end = secinfo->contents + sec->size; nul = FALSE; mask = ((bfd_vma) 1 << align) - 1; if (sec->flags & SEC_STRINGS) @@ -445,7 +461,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; @@ -476,7 +493,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; @@ -490,7 +507,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; } @@ -511,8 +528,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) @@ -536,8 +553,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)); @@ -580,7 +597,7 @@ merge_strings (struct sec_merge_info *sinfo) /* Now sort the strings */ amt = sinfo->htab->size * sizeof (struct sec_merge_hash_entry *); - array = (struct sec_merge_hash_entry **) bfd_malloc (amt); + array = bfd_malloc (amt); if (array == NULL) goto alloc_failure; @@ -638,14 +655,14 @@ alloc_failure: { if (e->secinfo != secinfo) { - secinfo->sec->_cooked_size = size; + secinfo->sec->size = size; secinfo = e->secinfo; } if (e->alignment) { - if (e->secinfo->first == NULL) + if (e->secinfo->first_str == NULL) { - e->secinfo->first = e; + e->secinfo->first_str = e; size = 0; } size = (size + e->alignment - 1) & ~((bfd_vma) e->alignment - 1); @@ -653,7 +670,12 @@ alloc_failure: size += e->len; } } - secinfo->sec->_cooked_size = size; + 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. */ @@ -676,7 +698,9 @@ alloc_failure: with _bfd_merge_section. */ bfd_boolean -_bfd_merge_sections (bfd *abfd ATTRIBUTE_UNUSED, void *xsinfo, +_bfd_merge_sections (bfd *abfd ATTRIBUTE_UNUSED, + struct bfd_link_info *info ATTRIBUTE_UNUSED, + void *xsinfo, void (*remove_hook) (bfd *, asection *)) { struct sec_merge_info *sinfo; @@ -722,11 +746,11 @@ _bfd_merge_sections (bfd *abfd ATTRIBUTE_UNUSED, void *xsinfo, secinfo = NULL; for (e = sinfo->htab->first; e; e = e->next) { - if (e->secinfo->first == NULL) + if (e->secinfo->first_str == NULL) { if (secinfo) - secinfo->sec->_cooked_size = size; - e->secinfo->first = e; + secinfo->sec->size = size; + e->secinfo->first_str = e; size = 0; } size = (size + e->alignment - 1) @@ -735,17 +759,14 @@ _bfd_merge_sections (bfd *abfd ATTRIBUTE_UNUSED, void *xsinfo, size += e->len; secinfo = e->secinfo; } - secinfo->sec->_cooked_size = size; + secinfo->sec->size = size; } /* Finally remove all input sections which have not made it into the hash table at all. */ for (secinfo = sinfo->chain; secinfo; secinfo = secinfo->next) - if (secinfo->first == NULL) - { - secinfo->sec->_cooked_size = 0; - secinfo->sec->flags |= SEC_EXCLUDE; - } + if (secinfo->first_str == NULL) + secinfo->sec->flags |= SEC_EXCLUDE; } return TRUE; @@ -761,14 +782,14 @@ _bfd_write_merged_section (bfd *output_bfd, asection *sec, void *psecinfo) secinfo = (struct sec_merge_sec_info *) psecinfo; - if (!secinfo->first) + if (secinfo->first_str == NULL) return TRUE; pos = sec->output_section->filepos + sec->output_offset; if (bfd_seek (output_bfd, pos, SEEK_SET) != 0) return FALSE; - if (! sec_merge_emit (output_bfd, secinfo->first)) + if (! sec_merge_emit (output_bfd, secinfo->first_str)) return FALSE; return TRUE; @@ -780,7 +801,7 @@ _bfd_write_merged_section (bfd *output_bfd, asection *sec, void *psecinfo) bfd_vma _bfd_merged_section_offset (bfd *output_bfd ATTRIBUTE_UNUSED, asection **psec, - void *psecinfo, bfd_vma offset, bfd_vma addend) + void *psecinfo, bfd_vma offset) { struct sec_merge_sec_info *secinfo; struct sec_merge_hash_entry *entry; @@ -789,30 +810,29 @@ _bfd_merged_section_offset (bfd *output_bfd ATTRIBUTE_UNUSED, asection **psec, secinfo = (struct sec_merge_sec_info *) psecinfo; - if (offset + addend >= sec->_raw_size) + if (offset >= sec->rawsize) { - if (offset + addend > sec->_raw_size) + if (offset > sec->rawsize) { (*_bfd_error_handler) - (_("%s: access beyond end of merged section (%ld + %ld)"), - bfd_get_filename (sec->owner), (long) offset, (long) addend); + (_("%s: access beyond end of merged section (%ld)"), + bfd_get_filename (sec->owner), (long) offset); } - return (secinfo->first ? sec->_cooked_size : 0); + return secinfo->first_str ? sec->size : 0; } if (secinfo->htab->strings) { if (sec->entsize == 1) { - p = secinfo->contents + offset + addend - 1; + p = secinfo->contents + offset - 1; while (p >= secinfo->contents && *p) --p; ++p; } else { - p = secinfo->contents - + ((offset + addend) / sec->entsize) * sec->entsize; + p = secinfo->contents + (offset / sec->entsize) * sec->entsize; p -= sec->entsize; while (p >= secinfo->contents) { @@ -830,10 +850,9 @@ _bfd_merged_section_offset (bfd *output_bfd ATTRIBUTE_UNUSED, asection **psec, } else { - p = secinfo->contents - + ((offset + addend) / sec->entsize) * sec->entsize; + 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) @@ -845,9 +864,8 @@ _bfd_merged_section_offset (bfd *output_bfd ATTRIBUTE_UNUSED, asection **psec, if (! secinfo->htab->first) abort (); entry = secinfo->htab->first; - p = secinfo->contents - + ((offset + addend) / sec->entsize + 1) * sec->entsize - - entry->len; + p = (secinfo->contents + (offset / sec->entsize + 1) * sec->entsize + - entry->len); } *psec = entry->secinfo->sec; |