X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=bfd%2Fmerge.c;h=fb7c0858bebb27b5375564054c148b2b68124554;hb=54b65c9b51ec80ef5812dde1a508ce171eeb8ce6;hp=de1e9510819577628538e4ebfa856e021eaa199c;hpb=9ca98086ff2854970c4085fffd1a0e3ccf7b07fa;p=deliverable%2Fbinutils-gdb.git diff --git a/bfd/merge.c b/bfd/merge.c index de1e951081..fb7c0858be 100644 --- a/bfd/merge.c +++ b/bfd/merge.c @@ -1,6 +1,5 @@ /* SEC_MERGE support. - Copyright 2001, 2002, 2003, 2004, 2005, 2006, 2007 - Free Software Foundation, Inc. + Copyright (C) 2001-2019 Free Software Foundation, Inc. Written by Jakub Jelinek . This file is part of BFD, the Binary File Descriptor library. @@ -25,7 +24,9 @@ as used in ELF SHF_MERGE. */ #include "sysdep.h" +#include #include "bfd.h" +#include "elf-bfd.h" #include "libbfd.h" #include "hashtab.h" #include "libiberty.h" @@ -108,7 +109,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; @@ -135,12 +137,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; @@ -191,8 +193,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) { @@ -235,7 +237,7 @@ 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; @@ -262,7 +264,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) @@ -283,20 +285,23 @@ sec_merge_add (struct sec_merge_hash *tab, const char *str, } static bfd_boolean -sec_merge_emit (bfd *abfd, struct sec_merge_hash_entry *entry) +sec_merge_emit (bfd *abfd, struct sec_merge_hash_entry *entry, + unsigned char *contents, file_ptr offset) { struct sec_merge_sec_info *secinfo = entry->secinfo; asection *sec = secinfo->sec; char *pad = NULL; bfd_size_type off = 0; int alignment_power = sec->output_section->alignment_power; + bfd_size_type pad_len; - if (alignment_power) - { - pad = bfd_zmalloc ((bfd_size_type) 1 << alignment_power); - if (pad == NULL) - return FALSE; - } + /* FIXME: If alignment_power is 0 then really we should scan the + entry list for the largest required alignment and use that. */ + pad_len = alignment_power ? ((bfd_size_type) 1 << alignment_power) : 16; + + pad = (char *) bfd_zmalloc (pad_len); + if (pad == NULL) + return FALSE; for (; entry != NULL && entry->secinfo == secinfo; entry = entry->next) { @@ -306,7 +311,13 @@ sec_merge_emit (bfd *abfd, struct sec_merge_hash_entry *entry) len = -off & (entry->alignment - 1); if (len != 0) { - if (bfd_bwrite (pad, len, abfd) != len) + BFD_ASSERT (len <= pad_len); + if (contents) + { + memcpy (contents + offset, pad, len); + offset += len; + } + else if (bfd_bwrite (pad, len, abfd) != len) goto err; off += len; } @@ -314,7 +325,12 @@ sec_merge_emit (bfd *abfd, struct sec_merge_hash_entry *entry) str = entry->root.string; len = entry->len; - if (bfd_bwrite (str, len, abfd) != len) + if (contents) + { + memcpy (contents + offset, str, len); + offset += len; + } + else if (bfd_bwrite (str, len, abfd) != len) goto err; off += len; @@ -322,17 +338,20 @@ sec_merge_emit (bfd *abfd, struct sec_merge_hash_entry *entry) /* Trailing alignment needed? */ off = sec->size - off; - if (off != 0 - && bfd_bwrite (pad, off, abfd) != off) - goto err; + if (off != 0) + { + BFD_ASSERT (off <= pad_len); + if (contents) + memcpy (contents + offset, pad, off); + else if (bfd_bwrite (pad, off, abfd) != off) + goto err; + } - if (pad != NULL) - free (pad); + free (pad); return TRUE; err: - if (pad != NULL) - free (pad); + free (pad); return FALSE; } @@ -347,6 +366,7 @@ _bfd_add_merge_section (bfd *abfd, void **psinfo, asection *sec, struct sec_merge_sec_info *secinfo; unsigned int align; bfd_size_type amt; + bfd_byte *contents; if ((abfd->flags & DYNAMIC) != 0 || (sec->flags & SEC_MERGE) == 0) @@ -357,18 +377,27 @@ _bfd_add_merge_section (bfd *abfd, void **psinfo, asection *sec, || sec->entsize == 0) return TRUE; + if (sec->size % sec->entsize != 0) + return TRUE; + if ((sec->flags & SEC_RELOC) != 0) { /* We aren't prepared to handle relocations in merged sections. */ return TRUE; } - align = sec->alignment_power; - if ((sec->entsize < (unsigned) 1 << align +#ifndef CHAR_BIT +#define CHAR_BIT 8 +#endif + if (sec->alignment_power >= sizeof (align) * CHAR_BIT) + return TRUE; + + align = 1u << sec->alignment_power; + if ((sec->entsize < align && ((sec->entsize & (sec->entsize - 1)) || !(sec->flags & SEC_STRINGS))) - || (sec->entsize > (unsigned) 1 << align - && (sec->entsize & (((unsigned) 1 << align) - 1)))) + || (sec->entsize > align + && (sec->entsize & (align - 1)))) { /* Sanity check. If string character size is smaller than alignment, then we require character size to be a power @@ -390,7 +419,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; @@ -430,8 +460,8 @@ _bfd_add_merge_section (bfd *abfd, void **psinfo, asection *sec, 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)) + contents = secinfo->contents; + if (! bfd_get_full_section_contents (sec->owner, sec, &contents)) goto error_return; return TRUE; @@ -591,7 +621,7 @@ is_suffix (const struct sec_merge_hash_entry *A, /* This is a helper function for _bfd_merge_sections. It attempts to merge strings matching suffixes of longer strings. */ -static void +static bfd_boolean merge_strings (struct sec_merge_info *sinfo) { struct sec_merge_hash_entry **array, **a, *e; @@ -601,9 +631,9 @@ 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; + return FALSE; for (e = sinfo->htab->first, a = array; e; e = e->next) if (e->alignment) @@ -648,9 +678,7 @@ merge_strings (struct sec_merge_info *sinfo) } } -alloc_failure: - if (array) - free (array); + free (array); /* Now assign positions to the strings we want to keep. */ size = 0; @@ -696,6 +724,7 @@ alloc_failure: e->u.index = e->u.suffix->u.index + (e->u.suffix->len - e->len); } } + return TRUE; } /* This function is called once after all SEC_MERGE sections are registered @@ -730,7 +759,7 @@ _bfd_merge_sections (bfd *abfd, (*remove_hook) (abfd, secinfo->sec); } else if (! record_section (sinfo, secinfo)) - break; + return FALSE; if (secinfo) continue; @@ -739,7 +768,10 @@ _bfd_merge_sections (bfd *abfd, continue; if (sinfo->htab->strings) - merge_strings (sinfo); + { + if (!merge_strings (sinfo)) + return FALSE; + } else { struct sec_merge_hash_entry *e; @@ -783,6 +815,8 @@ _bfd_write_merged_section (bfd *output_bfd, asection *sec, void *psecinfo) { struct sec_merge_sec_info *secinfo; file_ptr pos; + unsigned char *contents; + Elf_Internal_Shdr *hdr; secinfo = (struct sec_merge_sec_info *) psecinfo; @@ -792,11 +826,27 @@ _bfd_write_merged_section (bfd *output_bfd, asection *sec, void *psecinfo) 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; + /* FIXME: octets_per_byte. */ + hdr = &elf_section_data (sec->output_section)->this_hdr; + if (hdr->sh_offset == (file_ptr) -1) + { + /* We must compress this section. Write output to the + buffer. */ + contents = hdr->contents; + if ((sec->output_section->flags & SEC_ELF_COMPRESS) == 0 + || contents == NULL) + abort (); + } + else + { + contents = NULL; + 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_str)) + if (! sec_merge_emit (output_bfd, secinfo->first_str, contents, + sec->output_offset)) return FALSE; return TRUE; @@ -823,11 +873,10 @@ _bfd_merged_section_offset (bfd *output_bfd ATTRIBUTE_UNUSED, asection **psec, if (offset >= sec->rawsize) { if (offset > sec->rawsize) - { - (*_bfd_error_handler) - (_("%s: access beyond end of merged section (%ld)"), - bfd_get_filename (sec->owner), (long) offset); - } + _bfd_error_handler + /* xgettext:c-format */ + (_("%pB: access beyond end of merged section (%" PRId64 ")"), + sec->owner, (int64_t) offset); return secinfo->first_str ? sec->size : 0; } @@ -881,3 +930,17 @@ _bfd_merged_section_offset (bfd *output_bfd ATTRIBUTE_UNUSED, asection **psec, *psec = entry->secinfo->sec; return entry->u.index + (secinfo->contents + offset - p); } + +/* Tidy up when done. */ + +void +_bfd_merge_sections_free (void *xsinfo) +{ + struct sec_merge_info *sinfo; + + for (sinfo = (struct sec_merge_info *) xsinfo; sinfo; sinfo = sinfo->next) + { + bfd_hash_table_free (&sinfo->htab->table); + free (sinfo->htab); + } +}