X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=bfd%2Fmerge.c;h=b7a895d30b0d4c4b1a1e18d6525fcc7792c6e55c;hb=415c8100a28d56628c01730ef279c61f99578518;hp=3811523ecc917a42e87a23c5f723d95a57652882;hpb=753731eef094e983fab58faf7c7c5e8090de6e1b;p=deliverable%2Fbinutils-gdb.git diff --git a/bfd/merge.c b/bfd/merge.c index 3811523ecc..b7a895d30b 100644 --- a/bfd/merge.c +++ b/bfd/merge.c @@ -1,12 +1,12 @@ /* SEC_MERGE support. - Copyright 2001, 2002, 2003 Free Software Foundation, Inc. + Copyright (C) 2001-2021 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 +16,17 @@ 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 +#include "bfd.h" +#include "elf-bfd.h" #include "libbfd.h" #include "hashtab.h" #include "libiberty.h" @@ -66,7 +70,7 @@ struct sec_merge_hash /* Entity size. */ unsigned int entsize; /* Are entries fixed size or zero terminated strings? */ - bfd_boolean strings; + bool strings; }; struct sec_merge_info @@ -90,7 +94,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,44 +106,43 @@ 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 = (struct bfd_hash_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. */ static struct sec_merge_hash_entry * sec_merge_hash_lookup (struct sec_merge_hash *table, const char *string, - unsigned int alignment, bfd_boolean create) + unsigned int alignment, bool 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; @@ -190,9 +193,9 @@ 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]; - hashp != (struct sec_merge_hash_entry *) NULL; + _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) { if (hashp->root.hash == hash @@ -216,36 +219,30 @@ sec_merge_hash_lookup (struct sec_merge_hash *table, const char *string, } if (! create) - return (struct sec_merge_hash_entry *) 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->root.string = string; - hashp->root.hash = hash; + return NULL; + + hashp = ((struct sec_merge_hash_entry *) + bfd_hash_insert (&table->table, string, hash)); + if (hashp == NULL) + return NULL; hashp->len = len; hashp->alignment = alignment; - hashp->root.next = table->table.table[index]; - table->table.table[index] = (struct bfd_hash_entry *) hashp; - return hashp; } /* Create a new hash table. */ static struct sec_merge_hash * -sec_merge_init (unsigned int entsize, bfd_boolean strings) +sec_merge_init (unsigned int entsize, bool strings) { struct sec_merge_hash *table; - bfd_size_type amt = sizeof (struct sec_merge_hash); - table = (struct sec_merge_hash *) bfd_malloc (amt); + 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; @@ -267,9 +264,9 @@ 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); + entry = sec_merge_hash_lookup (tab, str, alignment, true); if (entry == NULL) return NULL; @@ -287,76 +284,124 @@ sec_merge_add (struct sec_merge_hash *tab, const char *str, return entry; } -static bfd_boolean -sec_merge_emit (bfd *abfd, struct sec_merge_hash_entry *entry) +static bool +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 = ""; + char *pad = NULL; bfd_size_type off = 0; - int alignment_power = bfd_get_section_alignment (abfd, sec->output_section); + 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. */ + pad_len = alignment_power ? ((bfd_size_type) 1 << alignment_power) : 16; - if (alignment_power) - pad = bfd_zmalloc ((bfd_size_type) 1 << alignment_power); + pad = (char *) bfd_zmalloc (pad_len); + 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; + 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; } str = entry->root.string; len = entry->len; - if (bfd_bwrite (str, (bfd_size_type) len, abfd) != len) - break; + if (contents) + { + memcpy (contents + offset, str, len); + offset += len; + } + else if (bfd_bwrite (str, len, abfd) != len) + goto err; off += len; } - if (alignment_power) - free (pad); + /* Trailing alignment needed? */ + off = sec->size - off; + 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; + } - return entry == NULL || entry->secinfo != secinfo; + free (pad); + return true; + + err: + 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) +bool +_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; + 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) + abort (); - if (sec->_raw_size == 0 - || (sec->flags & SEC_EXCLUDE) - || (sec->flags & SEC_MERGE) == 0 + if (sec->size == 0 + || (sec->flags & SEC_EXCLUDE) != 0 || sec->entsize == 0) - return TRUE; + 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; + return true; } - align = bfd_get_section_alignment (sec->owner, sec); - if ((sec->entsize < (unsigned int)(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 int)(1 << align) - && (sec->entsize & ((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 @@ -364,21 +409,22 @@ _bfd_merge_section (bfd *abfd, void **psinfo, asection *sec, void **psecinfo) of alignment. For non-string constants, alignment must be smaller than or equal to entity size and entity size must be integer multiple of alignment. */ - return TRUE; + return true; } for (sinfo = (struct sec_merge_info *) *psinfo; sinfo; sinfo = sinfo->next) 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 = (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,12 +437,17 @@ _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) - 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; - secinfo = (struct sec_merge_sec_info *)*psecinfo; + secinfo = (struct sec_merge_sec_info *) *psecinfo; if (sinfo->chain) { secinfo->next = sinfo->chain->next; @@ -408,34 +459,37 @@ _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; - if (! bfd_get_section_contents (sec->owner, sec, secinfo->contents, - (bfd_vma) 0, sec->_raw_size)) + sec->rawsize = sec->size; + if (sec->flags & SEC_STRINGS) + memset (secinfo->contents + sec->size, 0, sec->entsize); + contents = secinfo->contents; + if (! bfd_get_full_section_contents (sec->owner, sec, &contents)) goto error_return; - return TRUE; + return true; error_return: *psecinfo = NULL; - return FALSE; + return false; } /* Record one section into the hash table. */ -static bfd_boolean +static bool record_section (struct sec_merge_info *sinfo, struct sec_merge_sec_info *secinfo) { asection *sec = secinfo->sec; struct sec_merge_hash_entry *entry; - bfd_boolean nul; + bool nul; unsigned char *p, *end; bfd_vma mask, eltalign; unsigned int align, i; - align = bfd_get_section_alignment (sec->owner, sec); - end = secinfo->contents + sec->_raw_size; - nul = FALSE; + align = sec->alignment_power; + end = secinfo->contents + sec->size; + nul = false; mask = ((bfd_vma) 1 << align) - 1; if (sec->flags & SEC_STRINGS) { @@ -445,7 +499,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; @@ -455,7 +510,7 @@ record_section (struct sec_merge_info *sinfo, { if (!nul && !((p - secinfo->contents) & mask)) { - nul = TRUE; + nul = true; entry = sec_merge_add (sinfo->htab, "", (unsigned) mask + 1, secinfo); if (! entry) @@ -475,8 +530,8 @@ record_section (struct sec_merge_info *sinfo, break; if (!nul && !((p - secinfo->contents) & mask)) { - nul = TRUE; - entry = sec_merge_add (sinfo->htab, p, + nul = true; + entry = sec_merge_add (sinfo->htab, (char *) p, (unsigned) mask + 1, secinfo); if (! entry) goto error_return; @@ -490,20 +545,23 @@ 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; } } - return TRUE; + return true; -error_return: + error_return: for (secinfo = sinfo->chain; secinfo; secinfo = secinfo->next) *secinfo->psecinfo = NULL; - return FALSE; + 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) { @@ -511,8 +569,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 +594,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)); @@ -570,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 void +static struct sec_merge_sec_info * merge_strings (struct sec_merge_info *sinfo) { struct sec_merge_hash_entry **array, **a, *e; @@ -582,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) - goto alloc_failure; + return NULL; for (e = sinfo->htab->first, a = array; e; e = e->next) if (e->alignment) @@ -627,9 +685,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; @@ -638,14 +694,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 +709,7 @@ alloc_failure: size += e->len; } } - secinfo->sec->_cooked_size = size; + secinfo->sec->size = size; /* And now adjust the rest, removing them from the chain (but not hashtable) at the same time. */ @@ -670,20 +726,24 @@ alloc_failure: e->u.index = e->u.suffix->u.index + (e->u.suffix->len - e->len); } } + return secinfo; } /* This function is called once after all SEC_MERGE sections are registered with _bfd_merge_section. */ -bfd_boolean -_bfd_merge_sections (bfd *abfd ATTRIBUTE_UNUSED, void *xsinfo, +bool +_bfd_merge_sections (bfd *abfd, + struct bfd_link_info *info ATTRIBUTE_UNUSED, + void *xsinfo, void (*remove_hook) (bfd *, asection *)) { struct sec_merge_info *sinfo; 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; @@ -694,6 +754,7 @@ _bfd_merge_sections (bfd *abfd ATTRIBUTE_UNUSED, void *xsinfo, 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) { @@ -701,77 +762,111 @@ _bfd_merge_sections (bfd *abfd ATTRIBUTE_UNUSED, void *xsinfo, if (remove_hook) (*remove_hook) (abfd, secinfo->sec); } - else if (! record_section (sinfo, secinfo)) - break; - - 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) - 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. */ 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) - & ~((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; } - 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 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; + return true; } /* Write out the merged section. */ -bfd_boolean +bool _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; - if (!secinfo->first) - return TRUE; + if (!secinfo) + return false; - pos = sec->output_section->filepos + sec->output_offset; - if (bfd_seek (output_bfd, pos, SEEK_SET) != 0) - return FALSE; + if (secinfo->first_str == NULL) + return true; - if (! sec_merge_emit (output_bfd, secinfo->first)) - 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, contents, + sec->output_offset)) + return false; - return TRUE; + return true; } /* Adjust an address in the SEC_MERGE section. Given OFFSET within @@ -789,15 +884,17 @@ _bfd_merged_section_offset (bfd *output_bfd ATTRIBUTE_UNUSED, asection **psec, secinfo = (struct sec_merge_sec_info *) psecinfo; - if (offset >= sec->_raw_size) + if (!secinfo) + return offset; + + if (offset >= sec->rawsize) { - if (offset > sec->_raw_size) - { - (*_bfd_error_handler) - (_("%s: access beyond end of merged section (%ld)"), - bfd_get_filename (sec->owner), (long) offset); - } - return (secinfo->first ? sec->_cooked_size : 0); + if (offset > sec->rawsize) + _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; } if (secinfo->htab->strings) @@ -831,7 +928,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) @@ -850,3 +947,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); + } +}