Blame bfd/merge.c

Packit bbfece
/* SEC_MERGE support.
Packit bbfece
   Copyright (C) 2001-2018 Free Software Foundation, Inc.
Packit bbfece
   Written by Jakub Jelinek <jakub@redhat.com>.
Packit bbfece
Packit bbfece
   This file is part of BFD, the Binary File Descriptor library.
Packit bbfece
Packit bbfece
   This program is free software; you can redistribute it and/or modify
Packit bbfece
   it under the terms of the GNU General Public License as published by
Packit bbfece
   the Free Software Foundation; either version 3 of the License, or
Packit bbfece
   (at your option) any later version.
Packit bbfece
Packit bbfece
   This program is distributed in the hope that it will be useful,
Packit bbfece
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit bbfece
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit bbfece
   GNU General Public License for more details.
Packit bbfece
Packit bbfece
   You should have received a copy of the GNU General Public License
Packit bbfece
   along with this program; if not, write to the Free Software
Packit bbfece
   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
Packit bbfece
   MA 02110-1301, USA.  */
Packit bbfece
Packit bbfece
Packit bbfece
/* This file contains support for merging duplicate entities within sections,
Packit bbfece
   as used in ELF SHF_MERGE.  */
Packit bbfece
Packit bbfece
#include "sysdep.h"
Packit bbfece
#include "bfd.h"
Packit bbfece
#include "elf-bfd.h"
Packit bbfece
#include "libbfd.h"
Packit bbfece
#include "hashtab.h"
Packit bbfece
#include "libiberty.h"
Packit bbfece
Packit bbfece
struct sec_merge_sec_info;
Packit bbfece
Packit bbfece
/* An entry in the section merge hash table.  */
Packit bbfece
Packit bbfece
struct sec_merge_hash_entry
Packit bbfece
{
Packit bbfece
  struct bfd_hash_entry root;
Packit bbfece
  /* Length of this entry.  This includes the zero terminator.  */
Packit bbfece
  unsigned int len;
Packit bbfece
  /* Start of this string needs to be aligned to
Packit bbfece
     alignment octets (not 1 << align).  */
Packit bbfece
  unsigned int alignment;
Packit bbfece
  union
Packit bbfece
  {
Packit bbfece
    /* Index within the merged section.  */
Packit bbfece
    bfd_size_type index;
Packit bbfece
    /* Entry this is a suffix of (if alignment is 0).  */
Packit bbfece
    struct sec_merge_hash_entry *suffix;
Packit bbfece
  } u;
Packit bbfece
  /* Which section is it in.  */
Packit bbfece
  struct sec_merge_sec_info *secinfo;
Packit bbfece
  /* Next entity in the hash table.  */
Packit bbfece
  struct sec_merge_hash_entry *next;
Packit bbfece
};
Packit bbfece
Packit bbfece
/* The section merge hash table.  */
Packit bbfece
Packit bbfece
struct sec_merge_hash
Packit bbfece
{
Packit bbfece
  struct bfd_hash_table table;
Packit bbfece
  /* Next available index.  */
Packit bbfece
  bfd_size_type size;
Packit bbfece
  /* First entity in the SEC_MERGE sections of this type.  */
Packit bbfece
  struct sec_merge_hash_entry *first;
Packit bbfece
  /* Last entity in the SEC_MERGE sections of this type.  */
Packit bbfece
  struct sec_merge_hash_entry *last;
Packit bbfece
  /* Entity size.  */
Packit bbfece
  unsigned int entsize;
Packit bbfece
  /* Are entries fixed size or zero terminated strings?  */
Packit bbfece
  bfd_boolean strings;
Packit bbfece
};
Packit bbfece
Packit bbfece
struct sec_merge_info
Packit bbfece
{
Packit bbfece
  /* Chain of sec_merge_infos.  */
Packit bbfece
  struct sec_merge_info *next;
Packit bbfece
  /* Chain of sec_merge_sec_infos.  */
Packit bbfece
  struct sec_merge_sec_info *chain;
Packit bbfece
  /* A hash table used to hold section content.  */
Packit bbfece
  struct sec_merge_hash *htab;
Packit bbfece
};
Packit bbfece
Packit bbfece
struct sec_merge_sec_info
Packit bbfece
{
Packit bbfece
  /* Chain of sec_merge_sec_infos.  */
Packit bbfece
  struct sec_merge_sec_info *next;
Packit bbfece
  /* The corresponding section.  */
Packit bbfece
  asection *sec;
Packit bbfece
  /* Pointer to merge_info pointing to us.  */
Packit bbfece
  void **psecinfo;
Packit bbfece
  /* A hash table used to hold section content.  */
Packit bbfece
  struct sec_merge_hash *htab;
Packit bbfece
  /* First string in this section.  */
Packit bbfece
  struct sec_merge_hash_entry *first_str;
Packit bbfece
  /* Original section content.  */
Packit bbfece
  unsigned char contents[1];
Packit bbfece
};
Packit bbfece
Packit bbfece
Packit bbfece
/* Routine to create an entry in a section merge hashtab.  */
Packit bbfece
Packit bbfece
static struct bfd_hash_entry *
Packit bbfece
sec_merge_hash_newfunc (struct bfd_hash_entry *entry,
Packit bbfece
			struct bfd_hash_table *table, const char *string)
Packit bbfece
{
Packit bbfece
  /* Allocate the structure if it has not already been allocated by a
Packit bbfece
     subclass.  */
Packit bbfece
  if (entry == NULL)
Packit bbfece
    entry = (struct bfd_hash_entry *)
Packit bbfece
	bfd_hash_allocate (table, sizeof (struct sec_merge_hash_entry));
Packit bbfece
  if (entry == NULL)
Packit bbfece
    return NULL;
Packit bbfece
Packit bbfece
  /* Call the allocation method of the superclass.  */
Packit bbfece
  entry = bfd_hash_newfunc (entry, table, string);
Packit bbfece
Packit bbfece
  if (entry != NULL)
Packit bbfece
    {
Packit bbfece
      /* Initialize the local fields.  */
Packit bbfece
      struct sec_merge_hash_entry *ret = (struct sec_merge_hash_entry *) entry;
Packit bbfece
Packit bbfece
      ret->u.suffix = NULL;
Packit bbfece
      ret->alignment = 0;
Packit bbfece
      ret->secinfo = NULL;
Packit bbfece
      ret->next = NULL;
Packit bbfece
    }
Packit bbfece
Packit bbfece
  return entry;
Packit bbfece
}
Packit bbfece
Packit bbfece
/* Look up an entry in a section merge hash table.  */
Packit bbfece
Packit bbfece
static struct sec_merge_hash_entry *
Packit bbfece
sec_merge_hash_lookup (struct sec_merge_hash *table, const char *string,
Packit bbfece
		       unsigned int alignment, bfd_boolean create)
Packit bbfece
{
Packit bbfece
  const unsigned char *s;
Packit bbfece
  unsigned long hash;
Packit bbfece
  unsigned int c;
Packit bbfece
  struct sec_merge_hash_entry *hashp;
Packit bbfece
  unsigned int len, i;
Packit bbfece
  unsigned int _index;
Packit bbfece
Packit bbfece
  hash = 0;
Packit bbfece
  len = 0;
Packit bbfece
  s = (const unsigned char *) string;
Packit bbfece
  if (table->strings)
Packit bbfece
    {
Packit bbfece
      if (table->entsize == 1)
Packit bbfece
	{
Packit bbfece
	  while ((c = *s++) != '\0')
Packit bbfece
	    {
Packit bbfece
	      hash += c + (c << 17);
Packit bbfece
	      hash ^= hash >> 2;
Packit bbfece
	      ++len;
Packit bbfece
	    }
Packit bbfece
	  hash += len + (len << 17);
Packit bbfece
	}
Packit bbfece
      else
Packit bbfece
	{
Packit bbfece
	  for (;;)
Packit bbfece
	    {
Packit bbfece
	      for (i = 0; i < table->entsize; ++i)
Packit bbfece
		if (s[i] != '\0')
Packit bbfece
		  break;
Packit bbfece
	      if (i == table->entsize)
Packit bbfece
		break;
Packit bbfece
	      for (i = 0; i < table->entsize; ++i)
Packit bbfece
		{
Packit bbfece
		  c = *s++;
Packit bbfece
		  hash += c + (c << 17);
Packit bbfece
		  hash ^= hash >> 2;
Packit bbfece
		}
Packit bbfece
	      ++len;
Packit bbfece
	    }
Packit bbfece
	  hash += len + (len << 17);
Packit bbfece
	  len *= table->entsize;
Packit bbfece
	}
Packit bbfece
      hash ^= hash >> 2;
Packit bbfece
      len += table->entsize;
Packit bbfece
    }
Packit bbfece
  else
Packit bbfece
    {
Packit bbfece
      for (i = 0; i < table->entsize; ++i)
Packit bbfece
	{
Packit bbfece
	  c = *s++;
Packit bbfece
	  hash += c + (c << 17);
Packit bbfece
	  hash ^= hash >> 2;
Packit bbfece
	}
Packit bbfece
      len = table->entsize;
Packit bbfece
    }
Packit bbfece
Packit bbfece
  _index = hash % table->table.size;
Packit bbfece
  for (hashp = (struct sec_merge_hash_entry *) table->table.table[_index];
Packit bbfece
       hashp != NULL;
Packit bbfece
       hashp = (struct sec_merge_hash_entry *) hashp->root.next)
Packit bbfece
    {
Packit bbfece
      if (hashp->root.hash == hash
Packit bbfece
	  && len == hashp->len
Packit bbfece
	  && memcmp (hashp->root.string, string, len) == 0)
Packit bbfece
	{
Packit bbfece
	  /* If the string we found does not have at least the required
Packit bbfece
	     alignment, we need to insert another copy.  */
Packit bbfece
	  if (hashp->alignment < alignment)
Packit bbfece
	    {
Packit bbfece
	      if (create)
Packit bbfece
		{
Packit bbfece
		  /*  Mark the less aligned copy as deleted.  */
Packit bbfece
		  hashp->len = 0;
Packit bbfece
		  hashp->alignment = 0;
Packit bbfece
		}
Packit bbfece
	      break;
Packit bbfece
	    }
Packit bbfece
	  return hashp;
Packit bbfece
	}
Packit bbfece
    }
Packit bbfece
Packit bbfece
  if (! create)
Packit bbfece
    return NULL;
Packit bbfece
Packit bbfece
  hashp = ((struct sec_merge_hash_entry *)
Packit bbfece
	   bfd_hash_insert (&table->table, string, hash));
Packit bbfece
  if (hashp == NULL)
Packit bbfece
    return NULL;
Packit bbfece
  hashp->len = len;
Packit bbfece
  hashp->alignment = alignment;
Packit bbfece
  return hashp;
Packit bbfece
}
Packit bbfece
Packit bbfece
/* Create a new hash table.  */
Packit bbfece
Packit bbfece
static struct sec_merge_hash *
Packit bbfece
sec_merge_init (unsigned int entsize, bfd_boolean strings)
Packit bbfece
{
Packit bbfece
  struct sec_merge_hash *table;
Packit bbfece
Packit bbfece
  table = (struct sec_merge_hash *) bfd_malloc (sizeof (struct sec_merge_hash));
Packit bbfece
  if (table == NULL)
Packit bbfece
    return NULL;
Packit bbfece
Packit bbfece
  if (! bfd_hash_table_init_n (&table->table, sec_merge_hash_newfunc,
Packit bbfece
			       sizeof (struct sec_merge_hash_entry), 16699))
Packit bbfece
    {
Packit bbfece
      free (table);
Packit bbfece
      return NULL;
Packit bbfece
    }
Packit bbfece
Packit bbfece
  table->size = 0;
Packit bbfece
  table->first = NULL;
Packit bbfece
  table->last = NULL;
Packit bbfece
  table->entsize = entsize;
Packit bbfece
  table->strings = strings;
Packit bbfece
Packit bbfece
  return table;
Packit bbfece
}
Packit bbfece
Packit bbfece
/* Get the index of an entity in a hash table, adding it if it is not
Packit bbfece
   already present.  */
Packit bbfece
Packit bbfece
static struct sec_merge_hash_entry *
Packit bbfece
sec_merge_add (struct sec_merge_hash *tab, const char *str,
Packit bbfece
	       unsigned int alignment, struct sec_merge_sec_info *secinfo)
Packit bbfece
{
Packit bbfece
  struct sec_merge_hash_entry *entry;
Packit bbfece
Packit bbfece
  entry = sec_merge_hash_lookup (tab, str, alignment, TRUE);
Packit bbfece
  if (entry == NULL)
Packit bbfece
    return NULL;
Packit bbfece
Packit bbfece
  if (entry->secinfo == NULL)
Packit bbfece
    {
Packit bbfece
      tab->size++;
Packit bbfece
      entry->secinfo = secinfo;
Packit bbfece
      if (tab->first == NULL)
Packit bbfece
	tab->first = entry;
Packit bbfece
      else
Packit bbfece
	tab->last->next = entry;
Packit bbfece
      tab->last = entry;
Packit bbfece
    }
Packit bbfece
Packit bbfece
  return entry;
Packit bbfece
}
Packit bbfece
Packit bbfece
static bfd_boolean
Packit bbfece
sec_merge_emit (bfd *abfd, struct sec_merge_hash_entry *entry,
Packit bbfece
		unsigned char *contents, file_ptr offset)
Packit bbfece
{
Packit bbfece
  struct sec_merge_sec_info *secinfo = entry->secinfo;
Packit bbfece
  asection *sec = secinfo->sec;
Packit bbfece
  char *pad = NULL;
Packit bbfece
  bfd_size_type off = 0;
Packit bbfece
  int alignment_power = sec->output_section->alignment_power;
Packit bbfece
  bfd_size_type pad_len;
Packit bbfece
Packit bbfece
  /* FIXME: If alignment_power is 0 then really we should scan the
Packit bbfece
     entry list for the largest required alignment and use that.  */
Packit bbfece
  pad_len = alignment_power ? ((bfd_size_type) 1 << alignment_power) : 16;
Packit bbfece
Packit bbfece
  pad = (char *) bfd_zmalloc (pad_len);
Packit bbfece
  if (pad == NULL)
Packit bbfece
    return FALSE;
Packit bbfece
Packit bbfece
  for (; entry != NULL && entry->secinfo == secinfo; entry = entry->next)
Packit bbfece
    {
Packit bbfece
      const char *str;
Packit bbfece
      bfd_size_type len;
Packit bbfece
Packit bbfece
      len = -off & (entry->alignment - 1);
Packit bbfece
      if (len != 0)
Packit bbfece
	{
Packit bbfece
	  BFD_ASSERT (len <= pad_len);
Packit bbfece
	  if (contents)
Packit bbfece
	    {
Packit bbfece
	      memcpy (contents + offset, pad, len);
Packit bbfece
	      offset += len;
Packit bbfece
	    }
Packit bbfece
	  else if (bfd_bwrite (pad, len, abfd) != len)
Packit bbfece
	    goto err;
Packit bbfece
	  off += len;
Packit bbfece
	}
Packit bbfece
Packit bbfece
      str = entry->root.string;
Packit bbfece
      len = entry->len;
Packit bbfece
Packit bbfece
      if (contents)
Packit bbfece
	{
Packit bbfece
	  memcpy (contents + offset, str, len);
Packit bbfece
	  offset += len;
Packit bbfece
	}
Packit bbfece
      else if (bfd_bwrite (str, len, abfd) != len)
Packit bbfece
	goto err;
Packit bbfece
Packit bbfece
      off += len;
Packit bbfece
    }
Packit bbfece
Packit bbfece
  /* Trailing alignment needed?  */
Packit bbfece
  off = sec->size - off;
Packit bbfece
  if (off != 0)
Packit bbfece
    {
Packit bbfece
      BFD_ASSERT (off <= pad_len);
Packit bbfece
      if (contents)
Packit bbfece
	memcpy (contents + offset, pad, off);
Packit bbfece
      else if (bfd_bwrite (pad, off, abfd) != off)
Packit bbfece
	goto err;
Packit bbfece
    }
Packit bbfece
Packit bbfece
  free (pad);
Packit bbfece
  return TRUE;
Packit bbfece
Packit bbfece
 err:
Packit bbfece
  free (pad);
Packit bbfece
  return FALSE;
Packit bbfece
}
Packit bbfece
Packit bbfece
/* Register a SEC_MERGE section as a candidate for merging.
Packit bbfece
   This function is called for all non-dynamic SEC_MERGE input sections.  */
Packit bbfece
Packit bbfece
bfd_boolean
Packit bbfece
_bfd_add_merge_section (bfd *abfd, void **psinfo, asection *sec,
Packit bbfece
			void **psecinfo)
Packit bbfece
{
Packit bbfece
  struct sec_merge_info *sinfo;
Packit bbfece
  struct sec_merge_sec_info *secinfo;
Packit bbfece
  unsigned int align;
Packit bbfece
  bfd_size_type amt;
Packit bbfece
  bfd_byte *contents;
Packit bbfece
Packit bbfece
  if ((abfd->flags & DYNAMIC) != 0
Packit bbfece
      || (sec->flags & SEC_MERGE) == 0)
Packit bbfece
    abort ();
Packit bbfece
Packit bbfece
  if (sec->size == 0
Packit bbfece
      || (sec->flags & SEC_EXCLUDE) != 0
Packit bbfece
      || sec->entsize == 0)
Packit bbfece
    return TRUE;
Packit bbfece
Packit bbfece
  if ((sec->flags & SEC_RELOC) != 0)
Packit bbfece
    {
Packit bbfece
      /* We aren't prepared to handle relocations in merged sections.  */
Packit bbfece
      return TRUE;
Packit bbfece
    }
Packit bbfece
Packit bbfece
  align = sec->alignment_power;
Packit bbfece
  if ((sec->entsize < (unsigned) 1 << align
Packit bbfece
       && ((sec->entsize & (sec->entsize - 1))
Packit bbfece
	   || !(sec->flags & SEC_STRINGS)))
Packit bbfece
      || (sec->entsize > (unsigned) 1 << align
Packit bbfece
	  && (sec->entsize & (((unsigned) 1 << align) - 1))))
Packit bbfece
    {
Packit bbfece
      /* Sanity check.  If string character size is smaller than
Packit bbfece
	 alignment, then we require character size to be a power
Packit bbfece
	 of 2, otherwise character size must be integer multiple
Packit bbfece
	 of alignment.  For non-string constants, alignment must
Packit bbfece
	 be smaller than or equal to entity size and entity size
Packit bbfece
	 must be integer multiple of alignment.  */
Packit bbfece
      return TRUE;
Packit bbfece
    }
Packit bbfece
Packit bbfece
  for (sinfo = (struct sec_merge_info *) *psinfo; sinfo; sinfo = sinfo->next)
Packit bbfece
    if ((secinfo = sinfo->chain)
Packit bbfece
	&& ! ((secinfo->sec->flags ^ sec->flags) & (SEC_MERGE | SEC_STRINGS))
Packit bbfece
	&& secinfo->sec->entsize == sec->entsize
Packit bbfece
	&& secinfo->sec->alignment_power == sec->alignment_power
Packit bbfece
	&& secinfo->sec->output_section == sec->output_section)
Packit bbfece
      break;
Packit bbfece
Packit bbfece
  if (sinfo == NULL)
Packit bbfece
    {
Packit bbfece
      /* Initialize the information we need to keep track of.  */
Packit bbfece
      sinfo = (struct sec_merge_info *)
Packit bbfece
	  bfd_alloc (abfd, sizeof (struct sec_merge_info));
Packit bbfece
      if (sinfo == NULL)
Packit bbfece
	goto error_return;
Packit bbfece
      sinfo->next = (struct sec_merge_info *) *psinfo;
Packit bbfece
      sinfo->chain = NULL;
Packit bbfece
      *psinfo = sinfo;
Packit bbfece
      sinfo->htab = sec_merge_init (sec->entsize, (sec->flags & SEC_STRINGS));
Packit bbfece
      if (sinfo->htab == NULL)
Packit bbfece
	goto error_return;
Packit bbfece
    }
Packit bbfece
Packit bbfece
  /* Read the section from abfd.  */
Packit bbfece
Packit bbfece
  amt = sizeof (struct sec_merge_sec_info) - 1 + sec->size;
Packit bbfece
  if (sec->flags & SEC_STRINGS)
Packit bbfece
    /* Some versions of gcc may emit a string without a zero terminator.
Packit bbfece
       See http://gcc.gnu.org/ml/gcc-patches/2006-06/msg01004.html
Packit bbfece
       Allocate space for an extra zero.  */
Packit bbfece
    amt += sec->entsize;
Packit bbfece
  *psecinfo = bfd_alloc (abfd, amt);
Packit bbfece
  if (*psecinfo == NULL)
Packit bbfece
    goto error_return;
Packit bbfece
Packit bbfece
  secinfo = (struct sec_merge_sec_info *) *psecinfo;
Packit bbfece
  if (sinfo->chain)
Packit bbfece
    {
Packit bbfece
      secinfo->next = sinfo->chain->next;
Packit bbfece
      sinfo->chain->next = secinfo;
Packit bbfece
    }
Packit bbfece
  else
Packit bbfece
    secinfo->next = secinfo;
Packit bbfece
  sinfo->chain = secinfo;
Packit bbfece
  secinfo->sec = sec;
Packit bbfece
  secinfo->psecinfo = psecinfo;
Packit bbfece
  secinfo->htab = sinfo->htab;
Packit bbfece
  secinfo->first_str = NULL;
Packit bbfece
Packit bbfece
  sec->rawsize = sec->size;
Packit bbfece
  if (sec->flags & SEC_STRINGS)
Packit bbfece
    memset (secinfo->contents + sec->size, 0, sec->entsize);
Packit bbfece
  contents = secinfo->contents;
Packit bbfece
  if (! bfd_get_full_section_contents (sec->owner, sec, &contents))
Packit bbfece
    goto error_return;
Packit bbfece
Packit bbfece
  return TRUE;
Packit bbfece
Packit bbfece
 error_return:
Packit bbfece
  *psecinfo = NULL;
Packit bbfece
  return FALSE;
Packit bbfece
}
Packit bbfece
Packit bbfece
/* Record one section into the hash table.  */
Packit bbfece
static bfd_boolean
Packit bbfece
record_section (struct sec_merge_info *sinfo,
Packit bbfece
		struct sec_merge_sec_info *secinfo)
Packit bbfece
{
Packit bbfece
  asection *sec = secinfo->sec;
Packit bbfece
  struct sec_merge_hash_entry *entry;
Packit bbfece
  bfd_boolean nul;
Packit bbfece
  unsigned char *p, *end;
Packit bbfece
  bfd_vma mask, eltalign;
Packit bbfece
  unsigned int align, i;
Packit bbfece
Packit bbfece
  align = sec->alignment_power;
Packit bbfece
  end = secinfo->contents + sec->size;
Packit bbfece
  nul = FALSE;
Packit bbfece
  mask = ((bfd_vma) 1 << align) - 1;
Packit bbfece
  if (sec->flags & SEC_STRINGS)
Packit bbfece
    {
Packit bbfece
      for (p = secinfo->contents; p < end; )
Packit bbfece
	{
Packit bbfece
	  eltalign = p - secinfo->contents;
Packit bbfece
	  eltalign = ((eltalign ^ (eltalign - 1)) + 1) >> 1;
Packit bbfece
	  if (!eltalign || eltalign > mask)
Packit bbfece
	    eltalign = mask + 1;
Packit bbfece
	  entry = sec_merge_add (sinfo->htab, (char *) p, (unsigned) eltalign,
Packit bbfece
				 secinfo);
Packit bbfece
	  if (! entry)
Packit bbfece
	    goto error_return;
Packit bbfece
	  p += entry->len;
Packit bbfece
	  if (sec->entsize == 1)
Packit bbfece
	    {
Packit bbfece
	      while (p < end && *p == 0)
Packit bbfece
		{
Packit bbfece
		  if (!nul && !((p - secinfo->contents) & mask))
Packit bbfece
		    {
Packit bbfece
		      nul = TRUE;
Packit bbfece
		      entry = sec_merge_add (sinfo->htab, "",
Packit bbfece
					     (unsigned) mask + 1, secinfo);
Packit bbfece
		      if (! entry)
Packit bbfece
			goto error_return;
Packit bbfece
		    }
Packit bbfece
		  p++;
Packit bbfece
		}
Packit bbfece
	    }
Packit bbfece
	  else
Packit bbfece
	    {
Packit bbfece
	      while (p < end)
Packit bbfece
		{
Packit bbfece
		  for (i = 0; i < sec->entsize; i++)
Packit bbfece
		    if (p[i] != '\0')
Packit bbfece
		      break;
Packit bbfece
		  if (i != sec->entsize)
Packit bbfece
		    break;
Packit bbfece
		  if (!nul && !((p - secinfo->contents) & mask))
Packit bbfece
		    {
Packit bbfece
		      nul = TRUE;
Packit bbfece
		      entry = sec_merge_add (sinfo->htab, (char *) p,
Packit bbfece
					     (unsigned) mask + 1, secinfo);
Packit bbfece
		      if (! entry)
Packit bbfece
			goto error_return;
Packit bbfece
		    }
Packit bbfece
		  p += sec->entsize;
Packit bbfece
		}
Packit bbfece
	    }
Packit bbfece
	}
Packit bbfece
    }
Packit bbfece
  else
Packit bbfece
    {
Packit bbfece
      for (p = secinfo->contents; p < end; p += sec->entsize)
Packit bbfece
	{
Packit bbfece
	  entry = sec_merge_add (sinfo->htab, (char *) p, 1, secinfo);
Packit bbfece
	  if (! entry)
Packit bbfece
	    goto error_return;
Packit bbfece
	}
Packit bbfece
    }
Packit bbfece
Packit bbfece
  return TRUE;
Packit bbfece
Packit bbfece
error_return:
Packit bbfece
  for (secinfo = sinfo->chain; secinfo; secinfo = secinfo->next)
Packit bbfece
    *secinfo->psecinfo = NULL;
Packit bbfece
  return FALSE;
Packit bbfece
}
Packit bbfece
Packit bbfece
static int
Packit bbfece
strrevcmp (const void *a, const void *b)
Packit bbfece
{
Packit bbfece
  struct sec_merge_hash_entry *A = *(struct sec_merge_hash_entry **) a;
Packit bbfece
  struct sec_merge_hash_entry *B = *(struct sec_merge_hash_entry **) b;
Packit bbfece
  unsigned int lenA = A->len;
Packit bbfece
  unsigned int lenB = B->len;
Packit bbfece
  const unsigned char *s = (const unsigned char *) A->root.string + lenA - 1;
Packit bbfece
  const unsigned char *t = (const unsigned char *) B->root.string + lenB - 1;
Packit bbfece
  int l = lenA < lenB ? lenA : lenB;
Packit bbfece
Packit bbfece
  while (l)
Packit bbfece
    {
Packit bbfece
      if (*s != *t)
Packit bbfece
	return (int) *s - (int) *t;
Packit bbfece
      s--;
Packit bbfece
      t--;
Packit bbfece
      l--;
Packit bbfece
    }
Packit bbfece
  return lenA - lenB;
Packit bbfece
}
Packit bbfece
Packit bbfece
/* Like strrevcmp, but for the case where all strings have the same
Packit bbfece
   alignment > entsize.  */
Packit bbfece
Packit bbfece
static int
Packit bbfece
strrevcmp_align (const void *a, const void *b)
Packit bbfece
{
Packit bbfece
  struct sec_merge_hash_entry *A = *(struct sec_merge_hash_entry **) a;
Packit bbfece
  struct sec_merge_hash_entry *B = *(struct sec_merge_hash_entry **) b;
Packit bbfece
  unsigned int lenA = A->len;
Packit bbfece
  unsigned int lenB = B->len;
Packit bbfece
  const unsigned char *s = (const unsigned char *) A->root.string + lenA - 1;
Packit bbfece
  const unsigned char *t = (const unsigned char *) B->root.string + lenB - 1;
Packit bbfece
  int l = lenA < lenB ? lenA : lenB;
Packit bbfece
  int tail_align = (lenA & (A->alignment - 1)) - (lenB & (A->alignment - 1));
Packit bbfece
Packit bbfece
  if (tail_align != 0)
Packit bbfece
    return tail_align;
Packit bbfece
Packit bbfece
  while (l)
Packit bbfece
    {
Packit bbfece
      if (*s != *t)
Packit bbfece
	return (int) *s - (int) *t;
Packit bbfece
      s--;
Packit bbfece
      t--;
Packit bbfece
      l--;
Packit bbfece
    }
Packit bbfece
  return lenA - lenB;
Packit bbfece
}
Packit bbfece
Packit bbfece
static inline int
Packit bbfece
is_suffix (const struct sec_merge_hash_entry *A,
Packit bbfece
	   const struct sec_merge_hash_entry *B)
Packit bbfece
{
Packit bbfece
  if (A->len <= B->len)
Packit bbfece
    /* B cannot be a suffix of A unless A is equal to B, which is guaranteed
Packit bbfece
       not to be equal by the hash table.  */
Packit bbfece
    return 0;
Packit bbfece
Packit bbfece
  return memcmp (A->root.string + (A->len - B->len),
Packit bbfece
		 B->root.string, B->len) == 0;
Packit bbfece
}
Packit bbfece
Packit bbfece
/* This is a helper function for _bfd_merge_sections.  It attempts to
Packit bbfece
   merge strings matching suffixes of longer strings.  */
Packit bbfece
static bfd_boolean
Packit bbfece
merge_strings (struct sec_merge_info *sinfo)
Packit bbfece
{
Packit bbfece
  struct sec_merge_hash_entry **array, **a, *e;
Packit bbfece
  struct sec_merge_sec_info *secinfo;
Packit bbfece
  bfd_size_type size, amt;
Packit bbfece
  unsigned int alignment = 0;
Packit bbfece
Packit bbfece
  /* Now sort the strings */
Packit bbfece
  amt = sinfo->htab->size * sizeof (struct sec_merge_hash_entry *);
Packit bbfece
  array = (struct sec_merge_hash_entry **) bfd_malloc (amt);
Packit bbfece
  if (array == NULL)
Packit bbfece
    return FALSE;
Packit bbfece
Packit bbfece
  for (e = sinfo->htab->first, a = array; e; e = e->next)
Packit bbfece
    if (e->alignment)
Packit bbfece
      {
Packit bbfece
	*a++ = e;
Packit bbfece
	/* Adjust the length to not include the zero terminator.  */
Packit bbfece
	e->len -= sinfo->htab->entsize;
Packit bbfece
	if (alignment != e->alignment)
Packit bbfece
	  {
Packit bbfece
	    if (alignment == 0)
Packit bbfece
	      alignment = e->alignment;
Packit bbfece
	    else
Packit bbfece
	      alignment = (unsigned) -1;
Packit bbfece
	  }
Packit bbfece
      }
Packit bbfece
Packit bbfece
  sinfo->htab->size = a - array;
Packit bbfece
  if (sinfo->htab->size != 0)
Packit bbfece
    {
Packit bbfece
      qsort (array, (size_t) sinfo->htab->size,
Packit bbfece
	     sizeof (struct sec_merge_hash_entry *),
Packit bbfece
	     (alignment != (unsigned) -1 && alignment > sinfo->htab->entsize
Packit bbfece
	      ? strrevcmp_align : strrevcmp));
Packit bbfece
Packit bbfece
      /* Loop over the sorted array and merge suffixes */
Packit bbfece
      e = *--a;
Packit bbfece
      e->len += sinfo->htab->entsize;
Packit bbfece
      while (--a >= array)
Packit bbfece
	{
Packit bbfece
	  struct sec_merge_hash_entry *cmp = *a;
Packit bbfece
Packit bbfece
	  cmp->len += sinfo->htab->entsize;
Packit bbfece
	  if (e->alignment >= cmp->alignment
Packit bbfece
	      && !((e->len - cmp->len) & (cmp->alignment - 1))
Packit bbfece
	      && is_suffix (e, cmp))
Packit bbfece
	    {
Packit bbfece
	      cmp->u.suffix = e;
Packit bbfece
	      cmp->alignment = 0;
Packit bbfece
	    }
Packit bbfece
	  else
Packit bbfece
	    e = cmp;
Packit bbfece
	}
Packit bbfece
    }
Packit bbfece
Packit bbfece
  free (array);
Packit bbfece
Packit bbfece
  /* Now assign positions to the strings we want to keep.  */
Packit bbfece
  size = 0;
Packit bbfece
  secinfo = sinfo->htab->first->secinfo;
Packit bbfece
  for (e = sinfo->htab->first; e; e = e->next)
Packit bbfece
    {
Packit bbfece
      if (e->secinfo != secinfo)
Packit bbfece
	{
Packit bbfece
	  secinfo->sec->size = size;
Packit bbfece
	  secinfo = e->secinfo;
Packit bbfece
	}
Packit bbfece
      if (e->alignment)
Packit bbfece
	{
Packit bbfece
	  if (e->secinfo->first_str == NULL)
Packit bbfece
	    {
Packit bbfece
	      e->secinfo->first_str = e;
Packit bbfece
	      size = 0;
Packit bbfece
	    }
Packit bbfece
	  size = (size + e->alignment - 1) & ~((bfd_vma) e->alignment - 1);
Packit bbfece
	  e->u.index = size;
Packit bbfece
	  size += e->len;
Packit bbfece
	}
Packit bbfece
    }
Packit bbfece
  secinfo->sec->size = size;
Packit bbfece
  if (secinfo->sec->alignment_power != 0)
Packit bbfece
    {
Packit bbfece
      bfd_size_type align = (bfd_size_type) 1 << secinfo->sec->alignment_power;
Packit bbfece
      secinfo->sec->size = (secinfo->sec->size + align - 1) & -align;
Packit bbfece
    }
Packit bbfece
Packit bbfece
  /* And now adjust the rest, removing them from the chain (but not hashtable)
Packit bbfece
     at the same time.  */
Packit bbfece
  for (a = &sinfo->htab->first, e = *a; e; e = e->next)
Packit bbfece
    if (e->alignment)
Packit bbfece
      a = &e->next;
Packit bbfece
    else
Packit bbfece
      {
Packit bbfece
	*a = e->next;
Packit bbfece
	if (e->len)
Packit bbfece
	  {
Packit bbfece
	    e->secinfo = e->u.suffix->secinfo;
Packit bbfece
	    e->alignment = e->u.suffix->alignment;
Packit bbfece
	    e->u.index = e->u.suffix->u.index + (e->u.suffix->len - e->len);
Packit bbfece
	  }
Packit bbfece
      }
Packit bbfece
  return TRUE;
Packit bbfece
}
Packit bbfece
Packit bbfece
/* This function is called once after all SEC_MERGE sections are registered
Packit bbfece
   with _bfd_merge_section.  */
Packit bbfece
Packit bbfece
bfd_boolean
Packit bbfece
_bfd_merge_sections (bfd *abfd,
Packit bbfece
		     struct bfd_link_info *info ATTRIBUTE_UNUSED,
Packit bbfece
		     void *xsinfo,
Packit bbfece
		     void (*remove_hook) (bfd *, asection *))
Packit bbfece
{
Packit bbfece
  struct sec_merge_info *sinfo;
Packit bbfece
Packit bbfece
  for (sinfo = (struct sec_merge_info *) xsinfo; sinfo; sinfo = sinfo->next)
Packit bbfece
    {
Packit bbfece
      struct sec_merge_sec_info * secinfo;
Packit bbfece
Packit bbfece
      if (! sinfo->chain)
Packit bbfece
	continue;
Packit bbfece
Packit bbfece
      /* Move sinfo->chain to head of the chain, terminate it.  */
Packit bbfece
      secinfo = sinfo->chain;
Packit bbfece
      sinfo->chain = secinfo->next;
Packit bbfece
      secinfo->next = NULL;
Packit bbfece
Packit bbfece
      /* Record the sections into the hash table.  */
Packit bbfece
      for (secinfo = sinfo->chain; secinfo; secinfo = secinfo->next)
Packit bbfece
	if (secinfo->sec->flags & SEC_EXCLUDE)
Packit bbfece
	  {
Packit bbfece
	    *secinfo->psecinfo = NULL;
Packit bbfece
	    if (remove_hook)
Packit bbfece
	      (*remove_hook) (abfd, secinfo->sec);
Packit bbfece
	  }
Packit bbfece
	else if (! record_section (sinfo, secinfo))
Packit bbfece
	  return FALSE;
Packit bbfece
Packit bbfece
      if (secinfo)
Packit bbfece
	continue;
Packit bbfece
Packit bbfece
      if (sinfo->htab->first == NULL)
Packit bbfece
	continue;
Packit bbfece
Packit bbfece
      if (sinfo->htab->strings)
Packit bbfece
	{
Packit bbfece
	  if (!merge_strings (sinfo))
Packit bbfece
	    return FALSE;
Packit bbfece
	}
Packit bbfece
      else
Packit bbfece
	{
Packit bbfece
	  struct sec_merge_hash_entry *e;
Packit bbfece
	  bfd_size_type size = 0;
Packit bbfece
Packit bbfece
	  /* Things are much simpler for non-strings.
Packit bbfece
	     Just assign them slots in the section.  */
Packit bbfece
	  secinfo = NULL;
Packit bbfece
	  for (e = sinfo->htab->first; e; e = e->next)
Packit bbfece
	    {
Packit bbfece
	      if (e->secinfo->first_str == NULL)
Packit bbfece
		{
Packit bbfece
		  if (secinfo)
Packit bbfece
		    secinfo->sec->size = size;
Packit bbfece
		  e->secinfo->first_str = e;
Packit bbfece
		  size = 0;
Packit bbfece
		}
Packit bbfece
	      size = (size + e->alignment - 1)
Packit bbfece
		     & ~((bfd_vma) e->alignment - 1);
Packit bbfece
	      e->u.index = size;
Packit bbfece
	      size += e->len;
Packit bbfece
	      secinfo = e->secinfo;
Packit bbfece
	    }
Packit bbfece
	  secinfo->sec->size = size;
Packit bbfece
	}
Packit bbfece
Packit bbfece
	/* Finally remove all input sections which have not made it into
Packit bbfece
	   the hash table at all.  */
Packit bbfece
	for (secinfo = sinfo->chain; secinfo; secinfo = secinfo->next)
Packit bbfece
	  if (secinfo->first_str == NULL)
Packit bbfece
	    secinfo->sec->flags |= SEC_EXCLUDE | SEC_KEEP;
Packit bbfece
    }
Packit bbfece
Packit bbfece
  return TRUE;
Packit bbfece
}
Packit bbfece
Packit bbfece
/* Write out the merged section.  */
Packit bbfece
Packit bbfece
bfd_boolean
Packit bbfece
_bfd_write_merged_section (bfd *output_bfd, asection *sec, void *psecinfo)
Packit bbfece
{
Packit bbfece
  struct sec_merge_sec_info *secinfo;
Packit bbfece
  file_ptr pos;
Packit bbfece
  unsigned char *contents;
Packit bbfece
  Elf_Internal_Shdr *hdr;
Packit bbfece
Packit bbfece
  secinfo = (struct sec_merge_sec_info *) psecinfo;
Packit bbfece
Packit bbfece
  if (!secinfo)
Packit bbfece
    return FALSE;
Packit bbfece
Packit bbfece
  if (secinfo->first_str == NULL)
Packit bbfece
    return TRUE;
Packit bbfece
Packit bbfece
  /* FIXME: octets_per_byte.  */
Packit bbfece
  hdr = &elf_section_data (sec->output_section)->this_hdr;
Packit bbfece
  if (hdr->sh_offset == (file_ptr) -1)
Packit bbfece
    {
Packit bbfece
      /* We must compress this section.  Write output to the
Packit bbfece
	 buffer.  */
Packit bbfece
      contents = hdr->contents;
Packit bbfece
      if ((sec->output_section->flags & SEC_ELF_COMPRESS) == 0
Packit bbfece
	  || contents == NULL)
Packit bbfece
	abort ();
Packit bbfece
    }
Packit bbfece
  else
Packit bbfece
    {
Packit bbfece
      contents = NULL;
Packit bbfece
      pos = sec->output_section->filepos + sec->output_offset;
Packit bbfece
      if (bfd_seek (output_bfd, pos, SEEK_SET) != 0)
Packit bbfece
	return FALSE;
Packit bbfece
    }
Packit bbfece
Packit bbfece
  if (! sec_merge_emit (output_bfd, secinfo->first_str, contents,
Packit bbfece
			sec->output_offset))
Packit bbfece
    return FALSE;
Packit bbfece
Packit bbfece
  return TRUE;
Packit bbfece
}
Packit bbfece
Packit bbfece
/* Adjust an address in the SEC_MERGE section.  Given OFFSET within
Packit bbfece
   *PSEC, this returns the new offset in the adjusted SEC_MERGE
Packit bbfece
   section and writes the new section back into *PSEC.  */
Packit bbfece
Packit bbfece
bfd_vma
Packit bbfece
_bfd_merged_section_offset (bfd *output_bfd ATTRIBUTE_UNUSED, asection **psec,
Packit bbfece
			    void *psecinfo, bfd_vma offset)
Packit bbfece
{
Packit bbfece
  struct sec_merge_sec_info *secinfo;
Packit bbfece
  struct sec_merge_hash_entry *entry;
Packit bbfece
  unsigned char *p;
Packit bbfece
  asection *sec = *psec;
Packit bbfece
Packit bbfece
  secinfo = (struct sec_merge_sec_info *) psecinfo;
Packit bbfece
Packit bbfece
  if (!secinfo)
Packit bbfece
    return offset;
Packit bbfece
Packit bbfece
  if (offset >= sec->rawsize)
Packit bbfece
    {
Packit bbfece
      if (offset > sec->rawsize)
Packit bbfece
	_bfd_error_handler
Packit bbfece
	  /* xgettext:c-format */
Packit bbfece
	  (_("%B: access beyond end of merged section (%Ld)"),
Packit bbfece
	   sec->owner, offset);
Packit bbfece
      return secinfo->first_str ? sec->size : 0;
Packit bbfece
    }
Packit bbfece
Packit bbfece
  if (secinfo->htab->strings)
Packit bbfece
    {
Packit bbfece
      if (sec->entsize == 1)
Packit bbfece
	{
Packit bbfece
	  p = secinfo->contents + offset - 1;
Packit bbfece
	  while (p >= secinfo->contents && *p)
Packit bbfece
	    --p;
Packit bbfece
	  ++p;
Packit bbfece
	}
Packit bbfece
      else
Packit bbfece
	{
Packit bbfece
	  p = secinfo->contents + (offset / sec->entsize) * sec->entsize;
Packit bbfece
	  p -= sec->entsize;
Packit bbfece
	  while (p >= secinfo->contents)
Packit bbfece
	    {
Packit bbfece
	      unsigned int i;
Packit bbfece
Packit bbfece
	      for (i = 0; i < sec->entsize; ++i)
Packit bbfece
		if (p[i] != '\0')
Packit bbfece
		  break;
Packit bbfece
	      if (i == sec->entsize)
Packit bbfece
		break;
Packit bbfece
	      p -= sec->entsize;
Packit bbfece
	    }
Packit bbfece
	  p += sec->entsize;
Packit bbfece
	}
Packit bbfece
    }
Packit bbfece
  else
Packit bbfece
    {
Packit bbfece
      p = secinfo->contents + (offset / sec->entsize) * sec->entsize;
Packit bbfece
    }
Packit bbfece
  entry = sec_merge_hash_lookup (secinfo->htab, (char *) p, 0, FALSE);
Packit bbfece
  if (!entry)
Packit bbfece
    {
Packit bbfece
      if (! secinfo->htab->strings)
Packit bbfece
	abort ();
Packit bbfece
      /* This should only happen if somebody points into the padding
Packit bbfece
	 after a NUL character but before next entity.  */
Packit bbfece
      if (*p)
Packit bbfece
	abort ();
Packit bbfece
      if (! secinfo->htab->first)
Packit bbfece
	abort ();
Packit bbfece
      entry = secinfo->htab->first;
Packit bbfece
      p = (secinfo->contents + (offset / sec->entsize + 1) * sec->entsize
Packit bbfece
	   - entry->len);
Packit bbfece
    }
Packit bbfece
Packit bbfece
  *psec = entry->secinfo->sec;
Packit bbfece
  return entry->u.index + (secinfo->contents + offset - p);
Packit bbfece
}
Packit bbfece
Packit bbfece
/* Tidy up when done.  */
Packit bbfece
Packit bbfece
void
Packit bbfece
_bfd_merge_sections_free (void *xsinfo)
Packit bbfece
{
Packit bbfece
  struct sec_merge_info *sinfo;
Packit bbfece
Packit bbfece
  for (sinfo = (struct sec_merge_info *) xsinfo; sinfo; sinfo = sinfo->next)
Packit bbfece
    {
Packit bbfece
      bfd_hash_table_free (&sinfo->htab->table);
Packit bbfece
      free (sinfo->htab);
Packit bbfece
    }
Packit bbfece
}