X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=bfd%2Fmerge.c;h=0c6f7a10d3d8c67946e26be3880d1f2e1c75e531;hb=0203cad215219c3f78c5dff246fbc189946d06ce;hp=832cb16d5ceb510ebf41dc98c3a5d2a720a971ec;hpb=219d1afa89d0d53ca93a684cac341f16470f3ca0;p=deliverable%2Fbinutils-gdb.git diff --git a/bfd/merge.c b/bfd/merge.c index 832cb16d5c..0c6f7a10d3 100644 --- a/bfd/merge.c +++ b/bfd/merge.c @@ -1,5 +1,5 @@ /* SEC_MERGE support. - Copyright (C) 2001-2018 Free Software Foundation, Inc. + Copyright (C) 2001-2020 Free Software Foundation, Inc. Written by Jakub Jelinek . This file is part of BFD, the Binary File Descriptor library. @@ -24,6 +24,7 @@ as used in ELF SHF_MERGE. */ #include "sysdep.h" +#include #include "bfd.h" #include "elf-bfd.h" #include "libbfd.h" @@ -291,8 +292,9 @@ sec_merge_emit (bfd *abfd, struct sec_merge_hash_entry *entry, 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; + unsigned int opb = bfd_octets_per_byte (abfd, sec); + int alignment_power = sec->output_section->alignment_power * opb; + bfd_size_type pad_len; /* Octets. */ /* FIXME: If alignment_power is 0 then really we should scan the entry list for the largest required alignment and use that. */ @@ -363,9 +365,11 @@ _bfd_add_merge_section (bfd *abfd, void **psinfo, asection *sec, { struct sec_merge_info *sinfo; struct sec_merge_sec_info *secinfo; - unsigned int align; + unsigned int alignment_power; /* Octets. */ + unsigned int align; /* Octets. */ bfd_size_type amt; bfd_byte *contents; + unsigned int opb = bfd_octets_per_byte (abfd, sec); if ((abfd->flags & DYNAMIC) != 0 || (sec->flags & SEC_MERGE) == 0) @@ -376,18 +380,28 @@ _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 + alignment_power = sec->alignment_power * opb; + if (alignment_power >= sizeof (align) * CHAR_BIT) + return TRUE; + + align = 1u << 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 @@ -539,12 +553,15 @@ record_section (struct sec_merge_info *sinfo, return TRUE; -error_return: + error_return: for (secinfo = sinfo->chain; secinfo; secinfo = secinfo->next) *secinfo->psecinfo = NULL; return FALSE; } +/* qsort comparison function. Won't ever return zero as all entries + differ, so there is no issue with qsort stability here. */ + static int strrevcmp (const void *a, const void *b) { @@ -611,7 +628,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 bfd_boolean +static struct sec_merge_sec_info * merge_strings (struct sec_merge_info *sinfo) { struct sec_merge_hash_entry **array, **a, *e; @@ -623,7 +640,7 @@ merge_strings (struct sec_merge_info *sinfo) amt = sinfo->htab->size * sizeof (struct sec_merge_hash_entry *); array = (struct sec_merge_hash_entry **) bfd_malloc (amt); if (array == NULL) - return FALSE; + return NULL; for (e = sinfo->htab->first, a = array; e; e = e->next) if (e->alignment) @@ -693,11 +710,6 @@ merge_strings (struct sec_merge_info *sinfo) } } 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. */ @@ -714,7 +726,7 @@ merge_strings (struct sec_merge_info *sinfo) e->u.index = e->u.suffix->u.index + (e->u.suffix->len - e->len); } } - return TRUE; + return secinfo; } /* This function is called once after all SEC_MERGE sections are registered @@ -730,7 +742,8 @@ _bfd_merge_sections (bfd *abfd, for (sinfo = (struct sec_merge_info *) xsinfo; sinfo; sinfo = sinfo->next) { - struct sec_merge_sec_info * secinfo; + struct sec_merge_sec_info *secinfo; + bfd_size_type align; /* Bytes. */ if (! sinfo->chain) continue; @@ -741,6 +754,7 @@ _bfd_merge_sections (bfd *abfd, secinfo->next = NULL; /* Record the sections into the hash table. */ + align = 1; for (secinfo = sinfo->chain; secinfo; secinfo = secinfo->next) if (secinfo->sec->flags & SEC_EXCLUDE) { @@ -748,24 +762,33 @@ _bfd_merge_sections (bfd *abfd, if (remove_hook) (*remove_hook) (abfd, secinfo->sec); } - else if (! record_section (sinfo, secinfo)) - return FALSE; - - if (secinfo) - continue; + else + { + if (!record_section (sinfo, secinfo)) + return FALSE; + if (align) + { + unsigned int opb = bfd_octets_per_byte (abfd, secinfo->sec); + + align = (bfd_size_type) 1 << secinfo->sec->alignment_power; + if (((secinfo->sec->size / opb) & (align - 1)) != 0) + align = 0; + } + } if (sinfo->htab->first == NULL) continue; if (sinfo->htab->strings) { - if (!merge_strings (sinfo)) + secinfo = merge_strings (sinfo); + if (!secinfo) return FALSE; } else { struct sec_merge_hash_entry *e; - bfd_size_type size = 0; + bfd_size_type size = 0; /* Octets. */ /* Things are much simpler for non-strings. Just assign them slots in the section. */ @@ -779,8 +802,7 @@ _bfd_merge_sections (bfd *abfd, e->secinfo->first_str = e; size = 0; } - size = (size + e->alignment - 1) - & ~((bfd_vma) e->alignment - 1); + size = (size + e->alignment - 1) & ~((bfd_vma) e->alignment - 1); e->u.index = size; size += e->len; secinfo = e->secinfo; @@ -788,11 +810,16 @@ _bfd_merge_sections (bfd *abfd, 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_str == NULL) - secinfo->sec->flags |= SEC_EXCLUDE | SEC_KEEP; + /* If the input sections were padded according to their alignments, + then pad the output too. */ + if (align) + secinfo->sec->size = (secinfo->sec->size + align - 1) & -align; + + /* 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_str == NULL) + secinfo->sec->flags |= SEC_EXCLUDE | SEC_KEEP; } return TRUE; @@ -865,8 +892,8 @@ _bfd_merged_section_offset (bfd *output_bfd ATTRIBUTE_UNUSED, asection **psec, if (offset > sec->rawsize) _bfd_error_handler /* xgettext:c-format */ - (_("%B: access beyond end of merged section (%Ld)"), - sec->owner, offset); + (_("%pB: access beyond end of merged section (%" PRId64 ")"), + sec->owner, (int64_t) offset); return secinfo->first_str ? sec->size : 0; }