xref: /dflybsd-src/contrib/gdb-7/bfd/merge.c (revision de8e141f24382815c10a4012d209bbbf7abf1112)
15796c8dcSSimon Schubert /* SEC_MERGE support.
25796c8dcSSimon Schubert    Copyright 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
35796c8dcSSimon Schubert    Free Software Foundation, Inc.
45796c8dcSSimon Schubert    Written by Jakub Jelinek <jakub@redhat.com>.
55796c8dcSSimon Schubert 
65796c8dcSSimon Schubert    This file is part of BFD, the Binary File Descriptor library.
75796c8dcSSimon Schubert 
85796c8dcSSimon Schubert    This program is free software; you can redistribute it and/or modify
95796c8dcSSimon Schubert    it under the terms of the GNU General Public License as published by
105796c8dcSSimon Schubert    the Free Software Foundation; either version 3 of the License, or
115796c8dcSSimon Schubert    (at your option) any later version.
125796c8dcSSimon Schubert 
135796c8dcSSimon Schubert    This program is distributed in the hope that it will be useful,
145796c8dcSSimon Schubert    but WITHOUT ANY WARRANTY; without even the implied warranty of
155796c8dcSSimon Schubert    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
165796c8dcSSimon Schubert    GNU General Public License for more details.
175796c8dcSSimon Schubert 
185796c8dcSSimon Schubert    You should have received a copy of the GNU General Public License
195796c8dcSSimon Schubert    along with this program; if not, write to the Free Software
205796c8dcSSimon Schubert    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
215796c8dcSSimon Schubert    MA 02110-1301, USA.  */
225796c8dcSSimon Schubert 
235796c8dcSSimon Schubert 
245796c8dcSSimon Schubert /* This file contains support for merging duplicate entities within sections,
255796c8dcSSimon Schubert    as used in ELF SHF_MERGE.  */
265796c8dcSSimon Schubert 
275796c8dcSSimon Schubert #include "sysdep.h"
285796c8dcSSimon Schubert #include "bfd.h"
295796c8dcSSimon Schubert #include "libbfd.h"
305796c8dcSSimon Schubert #include "hashtab.h"
315796c8dcSSimon Schubert #include "libiberty.h"
325796c8dcSSimon Schubert 
335796c8dcSSimon Schubert struct sec_merge_sec_info;
345796c8dcSSimon Schubert 
355796c8dcSSimon Schubert /* An entry in the section merge hash table.  */
365796c8dcSSimon Schubert 
375796c8dcSSimon Schubert struct sec_merge_hash_entry
385796c8dcSSimon Schubert {
395796c8dcSSimon Schubert   struct bfd_hash_entry root;
405796c8dcSSimon Schubert   /* Length of this entry.  This includes the zero terminator.  */
415796c8dcSSimon Schubert   unsigned int len;
425796c8dcSSimon Schubert   /* Start of this string needs to be aligned to
435796c8dcSSimon Schubert      alignment octets (not 1 << align).  */
445796c8dcSSimon Schubert   unsigned int alignment;
455796c8dcSSimon Schubert   union
465796c8dcSSimon Schubert   {
475796c8dcSSimon Schubert     /* Index within the merged section.  */
485796c8dcSSimon Schubert     bfd_size_type index;
495796c8dcSSimon Schubert     /* Entry this is a suffix of (if alignment is 0).  */
505796c8dcSSimon Schubert     struct sec_merge_hash_entry *suffix;
515796c8dcSSimon Schubert   } u;
525796c8dcSSimon Schubert   /* Which section is it in.  */
535796c8dcSSimon Schubert   struct sec_merge_sec_info *secinfo;
545796c8dcSSimon Schubert   /* Next entity in the hash table.  */
555796c8dcSSimon Schubert   struct sec_merge_hash_entry *next;
565796c8dcSSimon Schubert };
575796c8dcSSimon Schubert 
585796c8dcSSimon Schubert /* The section merge hash table.  */
595796c8dcSSimon Schubert 
605796c8dcSSimon Schubert struct sec_merge_hash
615796c8dcSSimon Schubert {
625796c8dcSSimon Schubert   struct bfd_hash_table table;
635796c8dcSSimon Schubert   /* Next available index.  */
645796c8dcSSimon Schubert   bfd_size_type size;
655796c8dcSSimon Schubert   /* First entity in the SEC_MERGE sections of this type.  */
665796c8dcSSimon Schubert   struct sec_merge_hash_entry *first;
675796c8dcSSimon Schubert   /* Last entity in the SEC_MERGE sections of this type.  */
685796c8dcSSimon Schubert   struct sec_merge_hash_entry *last;
695796c8dcSSimon Schubert   /* Entity size.  */
705796c8dcSSimon Schubert   unsigned int entsize;
715796c8dcSSimon Schubert   /* Are entries fixed size or zero terminated strings?  */
725796c8dcSSimon Schubert   bfd_boolean strings;
735796c8dcSSimon Schubert };
745796c8dcSSimon Schubert 
755796c8dcSSimon Schubert struct sec_merge_info
765796c8dcSSimon Schubert {
775796c8dcSSimon Schubert   /* Chain of sec_merge_infos.  */
785796c8dcSSimon Schubert   struct sec_merge_info *next;
795796c8dcSSimon Schubert   /* Chain of sec_merge_sec_infos.  */
805796c8dcSSimon Schubert   struct sec_merge_sec_info *chain;
815796c8dcSSimon Schubert   /* A hash table used to hold section content.  */
825796c8dcSSimon Schubert   struct sec_merge_hash *htab;
835796c8dcSSimon Schubert };
845796c8dcSSimon Schubert 
855796c8dcSSimon Schubert struct sec_merge_sec_info
865796c8dcSSimon Schubert {
875796c8dcSSimon Schubert   /* Chain of sec_merge_sec_infos.  */
885796c8dcSSimon Schubert   struct sec_merge_sec_info *next;
895796c8dcSSimon Schubert   /* The corresponding section.  */
905796c8dcSSimon Schubert   asection *sec;
915796c8dcSSimon Schubert   /* Pointer to merge_info pointing to us.  */
925796c8dcSSimon Schubert   void **psecinfo;
935796c8dcSSimon Schubert   /* A hash table used to hold section content.  */
945796c8dcSSimon Schubert   struct sec_merge_hash *htab;
955796c8dcSSimon Schubert   /* First string in this section.  */
965796c8dcSSimon Schubert   struct sec_merge_hash_entry *first_str;
975796c8dcSSimon Schubert   /* Original section content.  */
985796c8dcSSimon Schubert   unsigned char contents[1];
995796c8dcSSimon Schubert };
1005796c8dcSSimon Schubert 
1015796c8dcSSimon Schubert 
1025796c8dcSSimon Schubert /* Routine to create an entry in a section merge hashtab.  */
1035796c8dcSSimon Schubert 
1045796c8dcSSimon Schubert static struct bfd_hash_entry *
sec_merge_hash_newfunc(struct bfd_hash_entry * entry,struct bfd_hash_table * table,const char * string)1055796c8dcSSimon Schubert sec_merge_hash_newfunc (struct bfd_hash_entry *entry,
1065796c8dcSSimon Schubert 			struct bfd_hash_table *table, const char *string)
1075796c8dcSSimon Schubert {
1085796c8dcSSimon Schubert   /* Allocate the structure if it has not already been allocated by a
1095796c8dcSSimon Schubert      subclass.  */
1105796c8dcSSimon Schubert   if (entry == NULL)
1115796c8dcSSimon Schubert     entry = (struct bfd_hash_entry *)
1125796c8dcSSimon Schubert         bfd_hash_allocate (table, sizeof (struct sec_merge_hash_entry));
1135796c8dcSSimon Schubert   if (entry == NULL)
1145796c8dcSSimon Schubert     return NULL;
1155796c8dcSSimon Schubert 
1165796c8dcSSimon Schubert   /* Call the allocation method of the superclass.  */
1175796c8dcSSimon Schubert   entry = bfd_hash_newfunc (entry, table, string);
1185796c8dcSSimon Schubert 
1195796c8dcSSimon Schubert   if (entry != NULL)
1205796c8dcSSimon Schubert     {
1215796c8dcSSimon Schubert       /* Initialize the local fields.  */
1225796c8dcSSimon Schubert       struct sec_merge_hash_entry *ret = (struct sec_merge_hash_entry *) entry;
1235796c8dcSSimon Schubert 
1245796c8dcSSimon Schubert       ret->u.suffix = NULL;
1255796c8dcSSimon Schubert       ret->alignment = 0;
1265796c8dcSSimon Schubert       ret->secinfo = NULL;
1275796c8dcSSimon Schubert       ret->next = NULL;
1285796c8dcSSimon Schubert     }
1295796c8dcSSimon Schubert 
1305796c8dcSSimon Schubert   return entry;
1315796c8dcSSimon Schubert }
1325796c8dcSSimon Schubert 
1335796c8dcSSimon Schubert /* Look up an entry in a section merge hash table.  */
1345796c8dcSSimon Schubert 
1355796c8dcSSimon Schubert static struct sec_merge_hash_entry *
sec_merge_hash_lookup(struct sec_merge_hash * table,const char * string,unsigned int alignment,bfd_boolean create)1365796c8dcSSimon Schubert sec_merge_hash_lookup (struct sec_merge_hash *table, const char *string,
1375796c8dcSSimon Schubert 		       unsigned int alignment, bfd_boolean create)
1385796c8dcSSimon Schubert {
139cf7f2e2dSJohn Marino   const unsigned char *s;
140cf7f2e2dSJohn Marino   unsigned long hash;
141cf7f2e2dSJohn Marino   unsigned int c;
1425796c8dcSSimon Schubert   struct sec_merge_hash_entry *hashp;
1435796c8dcSSimon Schubert   unsigned int len, i;
144cf7f2e2dSJohn Marino   unsigned int _index;
1455796c8dcSSimon Schubert 
1465796c8dcSSimon Schubert   hash = 0;
1475796c8dcSSimon Schubert   len = 0;
1485796c8dcSSimon Schubert   s = (const unsigned char *) string;
1495796c8dcSSimon Schubert   if (table->strings)
1505796c8dcSSimon Schubert     {
1515796c8dcSSimon Schubert       if (table->entsize == 1)
1525796c8dcSSimon Schubert 	{
1535796c8dcSSimon Schubert 	  while ((c = *s++) != '\0')
1545796c8dcSSimon Schubert 	    {
1555796c8dcSSimon Schubert 	      hash += c + (c << 17);
1565796c8dcSSimon Schubert 	      hash ^= hash >> 2;
1575796c8dcSSimon Schubert 	      ++len;
1585796c8dcSSimon Schubert 	    }
1595796c8dcSSimon Schubert 	  hash += len + (len << 17);
1605796c8dcSSimon Schubert 	}
1615796c8dcSSimon Schubert       else
1625796c8dcSSimon Schubert 	{
1635796c8dcSSimon Schubert 	  for (;;)
1645796c8dcSSimon Schubert 	    {
1655796c8dcSSimon Schubert 	      for (i = 0; i < table->entsize; ++i)
1665796c8dcSSimon Schubert 		if (s[i] != '\0')
1675796c8dcSSimon Schubert 		  break;
1685796c8dcSSimon Schubert 	      if (i == table->entsize)
1695796c8dcSSimon Schubert 		break;
1705796c8dcSSimon Schubert 	      for (i = 0; i < table->entsize; ++i)
1715796c8dcSSimon Schubert 		{
1725796c8dcSSimon Schubert 		  c = *s++;
1735796c8dcSSimon Schubert 		  hash += c + (c << 17);
1745796c8dcSSimon Schubert 		  hash ^= hash >> 2;
1755796c8dcSSimon Schubert 		}
1765796c8dcSSimon Schubert 	      ++len;
1775796c8dcSSimon Schubert 	    }
1785796c8dcSSimon Schubert 	  hash += len + (len << 17);
1795796c8dcSSimon Schubert 	  len *= table->entsize;
1805796c8dcSSimon Schubert 	}
1815796c8dcSSimon Schubert       hash ^= hash >> 2;
1825796c8dcSSimon Schubert       len += table->entsize;
1835796c8dcSSimon Schubert     }
1845796c8dcSSimon Schubert   else
1855796c8dcSSimon Schubert     {
1865796c8dcSSimon Schubert       for (i = 0; i < table->entsize; ++i)
1875796c8dcSSimon Schubert 	{
1885796c8dcSSimon Schubert 	  c = *s++;
1895796c8dcSSimon Schubert 	  hash += c + (c << 17);
1905796c8dcSSimon Schubert 	  hash ^= hash >> 2;
1915796c8dcSSimon Schubert 	}
1925796c8dcSSimon Schubert       len = table->entsize;
1935796c8dcSSimon Schubert     }
1945796c8dcSSimon Schubert 
195cf7f2e2dSJohn Marino   _index = hash % table->table.size;
196cf7f2e2dSJohn Marino   for (hashp = (struct sec_merge_hash_entry *) table->table.table[_index];
1975796c8dcSSimon Schubert        hashp != NULL;
1985796c8dcSSimon Schubert        hashp = (struct sec_merge_hash_entry *) hashp->root.next)
1995796c8dcSSimon Schubert     {
2005796c8dcSSimon Schubert       if (hashp->root.hash == hash
2015796c8dcSSimon Schubert 	  && len == hashp->len
2025796c8dcSSimon Schubert 	  && memcmp (hashp->root.string, string, len) == 0)
2035796c8dcSSimon Schubert 	{
2045796c8dcSSimon Schubert 	  /* If the string we found does not have at least the required
2055796c8dcSSimon Schubert 	     alignment, we need to insert another copy.  */
2065796c8dcSSimon Schubert 	  if (hashp->alignment < alignment)
2075796c8dcSSimon Schubert 	    {
2085796c8dcSSimon Schubert 	      if (create)
2095796c8dcSSimon Schubert 		{
2105796c8dcSSimon Schubert 		  /*  Mark the less aligned copy as deleted.  */
2115796c8dcSSimon Schubert 		  hashp->len = 0;
2125796c8dcSSimon Schubert 		  hashp->alignment = 0;
2135796c8dcSSimon Schubert 		}
2145796c8dcSSimon Schubert 	      break;
2155796c8dcSSimon Schubert 	    }
2165796c8dcSSimon Schubert 	  return hashp;
2175796c8dcSSimon Schubert 	}
2185796c8dcSSimon Schubert     }
2195796c8dcSSimon Schubert 
2205796c8dcSSimon Schubert   if (! create)
2215796c8dcSSimon Schubert     return NULL;
2225796c8dcSSimon Schubert 
2235796c8dcSSimon Schubert   hashp = ((struct sec_merge_hash_entry *)
2245796c8dcSSimon Schubert 	   bfd_hash_insert (&table->table, string, hash));
2255796c8dcSSimon Schubert   if (hashp == NULL)
2265796c8dcSSimon Schubert     return NULL;
2275796c8dcSSimon Schubert   hashp->len = len;
2285796c8dcSSimon Schubert   hashp->alignment = alignment;
2295796c8dcSSimon Schubert   return hashp;
2305796c8dcSSimon Schubert }
2315796c8dcSSimon Schubert 
2325796c8dcSSimon Schubert /* Create a new hash table.  */
2335796c8dcSSimon Schubert 
2345796c8dcSSimon Schubert static struct sec_merge_hash *
sec_merge_init(unsigned int entsize,bfd_boolean strings)2355796c8dcSSimon Schubert sec_merge_init (unsigned int entsize, bfd_boolean strings)
2365796c8dcSSimon Schubert {
2375796c8dcSSimon Schubert   struct sec_merge_hash *table;
2385796c8dcSSimon Schubert 
2395796c8dcSSimon Schubert   table = (struct sec_merge_hash *) bfd_malloc (sizeof (struct sec_merge_hash));
2405796c8dcSSimon Schubert   if (table == NULL)
2415796c8dcSSimon Schubert     return NULL;
2425796c8dcSSimon Schubert 
2435796c8dcSSimon Schubert   if (! bfd_hash_table_init_n (&table->table, sec_merge_hash_newfunc,
2445796c8dcSSimon Schubert 			       sizeof (struct sec_merge_hash_entry), 16699))
2455796c8dcSSimon Schubert     {
2465796c8dcSSimon Schubert       free (table);
2475796c8dcSSimon Schubert       return NULL;
2485796c8dcSSimon Schubert     }
2495796c8dcSSimon Schubert 
2505796c8dcSSimon Schubert   table->size = 0;
2515796c8dcSSimon Schubert   table->first = NULL;
2525796c8dcSSimon Schubert   table->last = NULL;
2535796c8dcSSimon Schubert   table->entsize = entsize;
2545796c8dcSSimon Schubert   table->strings = strings;
2555796c8dcSSimon Schubert 
2565796c8dcSSimon Schubert   return table;
2575796c8dcSSimon Schubert }
2585796c8dcSSimon Schubert 
2595796c8dcSSimon Schubert /* Get the index of an entity in a hash table, adding it if it is not
2605796c8dcSSimon Schubert    already present.  */
2615796c8dcSSimon Schubert 
2625796c8dcSSimon Schubert 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)2635796c8dcSSimon Schubert sec_merge_add (struct sec_merge_hash *tab, const char *str,
2645796c8dcSSimon Schubert 	       unsigned int alignment, struct sec_merge_sec_info *secinfo)
2655796c8dcSSimon Schubert {
266cf7f2e2dSJohn Marino   struct sec_merge_hash_entry *entry;
2675796c8dcSSimon Schubert 
2685796c8dcSSimon Schubert   entry = sec_merge_hash_lookup (tab, str, alignment, TRUE);
2695796c8dcSSimon Schubert   if (entry == NULL)
2705796c8dcSSimon Schubert     return NULL;
2715796c8dcSSimon Schubert 
2725796c8dcSSimon Schubert   if (entry->secinfo == NULL)
2735796c8dcSSimon Schubert     {
2745796c8dcSSimon Schubert       tab->size++;
2755796c8dcSSimon Schubert       entry->secinfo = secinfo;
2765796c8dcSSimon Schubert       if (tab->first == NULL)
2775796c8dcSSimon Schubert 	tab->first = entry;
2785796c8dcSSimon Schubert       else
2795796c8dcSSimon Schubert 	tab->last->next = entry;
2805796c8dcSSimon Schubert       tab->last = entry;
2815796c8dcSSimon Schubert     }
2825796c8dcSSimon Schubert 
2835796c8dcSSimon Schubert   return entry;
2845796c8dcSSimon Schubert }
2855796c8dcSSimon Schubert 
2865796c8dcSSimon Schubert static bfd_boolean
sec_merge_emit(bfd * abfd,struct sec_merge_hash_entry * entry)2875796c8dcSSimon Schubert sec_merge_emit (bfd *abfd, struct sec_merge_hash_entry *entry)
2885796c8dcSSimon Schubert {
2895796c8dcSSimon Schubert   struct sec_merge_sec_info *secinfo = entry->secinfo;
2905796c8dcSSimon Schubert   asection *sec = secinfo->sec;
2915796c8dcSSimon Schubert   char *pad = NULL;
2925796c8dcSSimon Schubert   bfd_size_type off = 0;
2935796c8dcSSimon Schubert   int alignment_power = sec->output_section->alignment_power;
2945796c8dcSSimon Schubert 
2955796c8dcSSimon Schubert   if (alignment_power)
2965796c8dcSSimon Schubert     {
2975796c8dcSSimon Schubert       pad = (char *) bfd_zmalloc ((bfd_size_type) 1 << alignment_power);
2985796c8dcSSimon Schubert       if (pad == NULL)
2995796c8dcSSimon Schubert 	return FALSE;
3005796c8dcSSimon Schubert     }
3015796c8dcSSimon Schubert 
3025796c8dcSSimon Schubert   for (; entry != NULL && entry->secinfo == secinfo; entry = entry->next)
3035796c8dcSSimon Schubert     {
3045796c8dcSSimon Schubert       const char *str;
3055796c8dcSSimon Schubert       bfd_size_type len;
3065796c8dcSSimon Schubert 
3075796c8dcSSimon Schubert       len = -off & (entry->alignment - 1);
3085796c8dcSSimon Schubert       if (len != 0)
3095796c8dcSSimon Schubert 	{
3105796c8dcSSimon Schubert 	  if (bfd_bwrite (pad, len, abfd) != len)
3115796c8dcSSimon Schubert 	    goto err;
3125796c8dcSSimon Schubert 	  off += len;
3135796c8dcSSimon Schubert 	}
3145796c8dcSSimon Schubert 
3155796c8dcSSimon Schubert       str = entry->root.string;
3165796c8dcSSimon Schubert       len = entry->len;
3175796c8dcSSimon Schubert 
3185796c8dcSSimon Schubert       if (bfd_bwrite (str, len, abfd) != len)
3195796c8dcSSimon Schubert 	goto err;
3205796c8dcSSimon Schubert 
3215796c8dcSSimon Schubert       off += len;
3225796c8dcSSimon Schubert     }
3235796c8dcSSimon Schubert 
3245796c8dcSSimon Schubert   /* Trailing alignment needed?  */
3255796c8dcSSimon Schubert   off = sec->size - off;
3265796c8dcSSimon Schubert   if (off != 0
3275796c8dcSSimon Schubert       && bfd_bwrite (pad, off, abfd) != off)
3285796c8dcSSimon Schubert     goto err;
3295796c8dcSSimon Schubert 
3305796c8dcSSimon Schubert   if (pad != NULL)
3315796c8dcSSimon Schubert     free (pad);
3325796c8dcSSimon Schubert   return TRUE;
3335796c8dcSSimon Schubert 
3345796c8dcSSimon Schubert  err:
3355796c8dcSSimon Schubert   if (pad != NULL)
3365796c8dcSSimon Schubert     free (pad);
3375796c8dcSSimon Schubert   return FALSE;
3385796c8dcSSimon Schubert }
3395796c8dcSSimon Schubert 
3405796c8dcSSimon Schubert /* Register a SEC_MERGE section as a candidate for merging.
3415796c8dcSSimon Schubert    This function is called for all non-dynamic SEC_MERGE input sections.  */
3425796c8dcSSimon Schubert 
3435796c8dcSSimon Schubert bfd_boolean
_bfd_add_merge_section(bfd * abfd,void ** psinfo,asection * sec,void ** psecinfo)3445796c8dcSSimon Schubert _bfd_add_merge_section (bfd *abfd, void **psinfo, asection *sec,
3455796c8dcSSimon Schubert 			void **psecinfo)
3465796c8dcSSimon Schubert {
3475796c8dcSSimon Schubert   struct sec_merge_info *sinfo;
3485796c8dcSSimon Schubert   struct sec_merge_sec_info *secinfo;
3495796c8dcSSimon Schubert   unsigned int align;
3505796c8dcSSimon Schubert   bfd_size_type amt;
351c50c785cSJohn Marino   bfd_byte *contents;
3525796c8dcSSimon Schubert 
3535796c8dcSSimon Schubert   if ((abfd->flags & DYNAMIC) != 0
3545796c8dcSSimon Schubert       || (sec->flags & SEC_MERGE) == 0)
3555796c8dcSSimon Schubert     abort ();
3565796c8dcSSimon Schubert 
3575796c8dcSSimon Schubert   if (sec->size == 0
3585796c8dcSSimon Schubert       || (sec->flags & SEC_EXCLUDE) != 0
3595796c8dcSSimon Schubert       || sec->entsize == 0)
3605796c8dcSSimon Schubert     return TRUE;
3615796c8dcSSimon Schubert 
3625796c8dcSSimon Schubert   if ((sec->flags & SEC_RELOC) != 0)
3635796c8dcSSimon Schubert     {
3645796c8dcSSimon Schubert       /* We aren't prepared to handle relocations in merged sections.  */
3655796c8dcSSimon Schubert       return TRUE;
3665796c8dcSSimon Schubert     }
3675796c8dcSSimon Schubert 
3685796c8dcSSimon Schubert   align = sec->alignment_power;
3695796c8dcSSimon Schubert   if ((sec->entsize < (unsigned) 1 << align
3705796c8dcSSimon Schubert        && ((sec->entsize & (sec->entsize - 1))
3715796c8dcSSimon Schubert 	   || !(sec->flags & SEC_STRINGS)))
3725796c8dcSSimon Schubert       || (sec->entsize > (unsigned) 1 << align
3735796c8dcSSimon Schubert 	  && (sec->entsize & (((unsigned) 1 << align) - 1))))
3745796c8dcSSimon Schubert     {
3755796c8dcSSimon Schubert       /* Sanity check.  If string character size is smaller than
3765796c8dcSSimon Schubert 	 alignment, then we require character size to be a power
3775796c8dcSSimon Schubert 	 of 2, otherwise character size must be integer multiple
3785796c8dcSSimon Schubert 	 of alignment.  For non-string constants, alignment must
3795796c8dcSSimon Schubert 	 be smaller than or equal to entity size and entity size
3805796c8dcSSimon Schubert 	 must be integer multiple of alignment.  */
3815796c8dcSSimon Schubert       return TRUE;
3825796c8dcSSimon Schubert     }
3835796c8dcSSimon Schubert 
3845796c8dcSSimon Schubert   for (sinfo = (struct sec_merge_info *) *psinfo; sinfo; sinfo = sinfo->next)
3855796c8dcSSimon Schubert     if ((secinfo = sinfo->chain)
3865796c8dcSSimon Schubert 	&& ! ((secinfo->sec->flags ^ sec->flags) & (SEC_MERGE | SEC_STRINGS))
3875796c8dcSSimon Schubert 	&& secinfo->sec->entsize == sec->entsize
3885796c8dcSSimon Schubert 	&& secinfo->sec->alignment_power == sec->alignment_power
3895796c8dcSSimon Schubert 	&& secinfo->sec->output_section == sec->output_section)
3905796c8dcSSimon Schubert       break;
3915796c8dcSSimon Schubert 
3925796c8dcSSimon Schubert   if (sinfo == NULL)
3935796c8dcSSimon Schubert     {
3945796c8dcSSimon Schubert       /* Initialize the information we need to keep track of.  */
3955796c8dcSSimon Schubert       sinfo = (struct sec_merge_info *)
3965796c8dcSSimon Schubert           bfd_alloc (abfd, sizeof (struct sec_merge_info));
3975796c8dcSSimon Schubert       if (sinfo == NULL)
3985796c8dcSSimon Schubert 	goto error_return;
3995796c8dcSSimon Schubert       sinfo->next = (struct sec_merge_info *) *psinfo;
4005796c8dcSSimon Schubert       sinfo->chain = NULL;
4015796c8dcSSimon Schubert       *psinfo = sinfo;
4025796c8dcSSimon Schubert       sinfo->htab = sec_merge_init (sec->entsize, (sec->flags & SEC_STRINGS));
4035796c8dcSSimon Schubert       if (sinfo->htab == NULL)
4045796c8dcSSimon Schubert 	goto error_return;
4055796c8dcSSimon Schubert     }
4065796c8dcSSimon Schubert 
4075796c8dcSSimon Schubert   /* Read the section from abfd.  */
4085796c8dcSSimon Schubert 
4095796c8dcSSimon Schubert   amt = sizeof (struct sec_merge_sec_info) - 1 + sec->size;
4105796c8dcSSimon Schubert   if (sec->flags & SEC_STRINGS)
4115796c8dcSSimon Schubert     /* Some versions of gcc may emit a string without a zero terminator.
4125796c8dcSSimon Schubert        See http://gcc.gnu.org/ml/gcc-patches/2006-06/msg01004.html
4135796c8dcSSimon Schubert        Allocate space for an extra zero.  */
4145796c8dcSSimon Schubert     amt += sec->entsize;
4155796c8dcSSimon Schubert   *psecinfo = bfd_alloc (abfd, amt);
4165796c8dcSSimon Schubert   if (*psecinfo == NULL)
4175796c8dcSSimon Schubert     goto error_return;
4185796c8dcSSimon Schubert 
4195796c8dcSSimon Schubert   secinfo = (struct sec_merge_sec_info *) *psecinfo;
4205796c8dcSSimon Schubert   if (sinfo->chain)
4215796c8dcSSimon Schubert     {
4225796c8dcSSimon Schubert       secinfo->next = sinfo->chain->next;
4235796c8dcSSimon Schubert       sinfo->chain->next = secinfo;
4245796c8dcSSimon Schubert     }
4255796c8dcSSimon Schubert   else
4265796c8dcSSimon Schubert     secinfo->next = secinfo;
4275796c8dcSSimon Schubert   sinfo->chain = secinfo;
4285796c8dcSSimon Schubert   secinfo->sec = sec;
4295796c8dcSSimon Schubert   secinfo->psecinfo = psecinfo;
4305796c8dcSSimon Schubert   secinfo->htab = sinfo->htab;
4315796c8dcSSimon Schubert   secinfo->first_str = NULL;
4325796c8dcSSimon Schubert 
4335796c8dcSSimon Schubert   sec->rawsize = sec->size;
4345796c8dcSSimon Schubert   if (sec->flags & SEC_STRINGS)
4355796c8dcSSimon Schubert     memset (secinfo->contents + sec->size, 0, sec->entsize);
436c50c785cSJohn Marino   contents = secinfo->contents;
437c50c785cSJohn Marino   if (! bfd_get_full_section_contents (sec->owner, sec, &contents))
4385796c8dcSSimon Schubert     goto error_return;
4395796c8dcSSimon Schubert 
4405796c8dcSSimon Schubert   return TRUE;
4415796c8dcSSimon Schubert 
4425796c8dcSSimon Schubert  error_return:
4435796c8dcSSimon Schubert   *psecinfo = NULL;
4445796c8dcSSimon Schubert   return FALSE;
4455796c8dcSSimon Schubert }
4465796c8dcSSimon Schubert 
4475796c8dcSSimon Schubert /* Record one section into the hash table.  */
4485796c8dcSSimon Schubert static bfd_boolean
record_section(struct sec_merge_info * sinfo,struct sec_merge_sec_info * secinfo)4495796c8dcSSimon Schubert record_section (struct sec_merge_info *sinfo,
4505796c8dcSSimon Schubert 		struct sec_merge_sec_info *secinfo)
4515796c8dcSSimon Schubert {
4525796c8dcSSimon Schubert   asection *sec = secinfo->sec;
4535796c8dcSSimon Schubert   struct sec_merge_hash_entry *entry;
4545796c8dcSSimon Schubert   bfd_boolean nul;
4555796c8dcSSimon Schubert   unsigned char *p, *end;
4565796c8dcSSimon Schubert   bfd_vma mask, eltalign;
4575796c8dcSSimon Schubert   unsigned int align, i;
4585796c8dcSSimon Schubert 
4595796c8dcSSimon Schubert   align = sec->alignment_power;
4605796c8dcSSimon Schubert   end = secinfo->contents + sec->size;
4615796c8dcSSimon Schubert   nul = FALSE;
4625796c8dcSSimon Schubert   mask = ((bfd_vma) 1 << align) - 1;
4635796c8dcSSimon Schubert   if (sec->flags & SEC_STRINGS)
4645796c8dcSSimon Schubert     {
4655796c8dcSSimon Schubert       for (p = secinfo->contents; p < end; )
4665796c8dcSSimon Schubert 	{
4675796c8dcSSimon Schubert 	  eltalign = p - secinfo->contents;
4685796c8dcSSimon Schubert 	  eltalign = ((eltalign ^ (eltalign - 1)) + 1) >> 1;
4695796c8dcSSimon Schubert 	  if (!eltalign || eltalign > mask)
4705796c8dcSSimon Schubert 	    eltalign = mask + 1;
4715796c8dcSSimon Schubert 	  entry = sec_merge_add (sinfo->htab, (char *) p, (unsigned) eltalign,
4725796c8dcSSimon Schubert 				 secinfo);
4735796c8dcSSimon Schubert 	  if (! entry)
4745796c8dcSSimon Schubert 	    goto error_return;
4755796c8dcSSimon Schubert 	  p += entry->len;
4765796c8dcSSimon Schubert 	  if (sec->entsize == 1)
4775796c8dcSSimon Schubert 	    {
4785796c8dcSSimon Schubert 	      while (p < end && *p == 0)
4795796c8dcSSimon Schubert 		{
4805796c8dcSSimon Schubert 		  if (!nul && !((p - secinfo->contents) & mask))
4815796c8dcSSimon Schubert 		    {
4825796c8dcSSimon Schubert 		      nul = TRUE;
4835796c8dcSSimon Schubert 		      entry = sec_merge_add (sinfo->htab, "",
4845796c8dcSSimon Schubert 					     (unsigned) mask + 1, secinfo);
4855796c8dcSSimon Schubert 		      if (! entry)
4865796c8dcSSimon Schubert 			goto error_return;
4875796c8dcSSimon Schubert 		    }
4885796c8dcSSimon Schubert 		  p++;
4895796c8dcSSimon Schubert 		}
4905796c8dcSSimon Schubert 	    }
4915796c8dcSSimon Schubert 	  else
4925796c8dcSSimon Schubert 	    {
4935796c8dcSSimon Schubert 	      while (p < end)
4945796c8dcSSimon Schubert 		{
4955796c8dcSSimon Schubert 		  for (i = 0; i < sec->entsize; i++)
4965796c8dcSSimon Schubert 		    if (p[i] != '\0')
4975796c8dcSSimon Schubert 		      break;
4985796c8dcSSimon Schubert 		  if (i != sec->entsize)
4995796c8dcSSimon Schubert 		    break;
5005796c8dcSSimon Schubert 		  if (!nul && !((p - secinfo->contents) & mask))
5015796c8dcSSimon Schubert 		    {
5025796c8dcSSimon Schubert 		      nul = TRUE;
5035796c8dcSSimon Schubert 		      entry = sec_merge_add (sinfo->htab, (char *) p,
5045796c8dcSSimon Schubert 					     (unsigned) mask + 1, secinfo);
5055796c8dcSSimon Schubert 		      if (! entry)
5065796c8dcSSimon Schubert 			goto error_return;
5075796c8dcSSimon Schubert 		    }
5085796c8dcSSimon Schubert 		  p += sec->entsize;
5095796c8dcSSimon Schubert 		}
5105796c8dcSSimon Schubert 	    }
5115796c8dcSSimon Schubert 	}
5125796c8dcSSimon Schubert     }
5135796c8dcSSimon Schubert   else
5145796c8dcSSimon Schubert     {
5155796c8dcSSimon Schubert       for (p = secinfo->contents; p < end; p += sec->entsize)
5165796c8dcSSimon Schubert 	{
5175796c8dcSSimon Schubert 	  entry = sec_merge_add (sinfo->htab, (char *) p, 1, secinfo);
5185796c8dcSSimon Schubert 	  if (! entry)
5195796c8dcSSimon Schubert 	    goto error_return;
5205796c8dcSSimon Schubert 	}
5215796c8dcSSimon Schubert     }
5225796c8dcSSimon Schubert 
5235796c8dcSSimon Schubert   return TRUE;
5245796c8dcSSimon Schubert 
5255796c8dcSSimon Schubert error_return:
5265796c8dcSSimon Schubert   for (secinfo = sinfo->chain; secinfo; secinfo = secinfo->next)
5275796c8dcSSimon Schubert     *secinfo->psecinfo = NULL;
5285796c8dcSSimon Schubert   return FALSE;
5295796c8dcSSimon Schubert }
5305796c8dcSSimon Schubert 
5315796c8dcSSimon Schubert static int
strrevcmp(const void * a,const void * b)5325796c8dcSSimon Schubert strrevcmp (const void *a, const void *b)
5335796c8dcSSimon Schubert {
5345796c8dcSSimon Schubert   struct sec_merge_hash_entry *A = *(struct sec_merge_hash_entry **) a;
5355796c8dcSSimon Schubert   struct sec_merge_hash_entry *B = *(struct sec_merge_hash_entry **) b;
5365796c8dcSSimon Schubert   unsigned int lenA = A->len;
5375796c8dcSSimon Schubert   unsigned int lenB = B->len;
5385796c8dcSSimon Schubert   const unsigned char *s = (const unsigned char *) A->root.string + lenA - 1;
5395796c8dcSSimon Schubert   const unsigned char *t = (const unsigned char *) B->root.string + lenB - 1;
5405796c8dcSSimon Schubert   int l = lenA < lenB ? lenA : lenB;
5415796c8dcSSimon Schubert 
5425796c8dcSSimon Schubert   while (l)
5435796c8dcSSimon Schubert     {
5445796c8dcSSimon Schubert       if (*s != *t)
5455796c8dcSSimon Schubert 	return (int) *s - (int) *t;
5465796c8dcSSimon Schubert       s--;
5475796c8dcSSimon Schubert       t--;
5485796c8dcSSimon Schubert       l--;
5495796c8dcSSimon Schubert     }
5505796c8dcSSimon Schubert   return lenA - lenB;
5515796c8dcSSimon Schubert }
5525796c8dcSSimon Schubert 
5535796c8dcSSimon Schubert /* Like strrevcmp, but for the case where all strings have the same
5545796c8dcSSimon Schubert    alignment > entsize.  */
5555796c8dcSSimon Schubert 
5565796c8dcSSimon Schubert static int
strrevcmp_align(const void * a,const void * b)5575796c8dcSSimon Schubert strrevcmp_align (const void *a, const void *b)
5585796c8dcSSimon Schubert {
5595796c8dcSSimon Schubert   struct sec_merge_hash_entry *A = *(struct sec_merge_hash_entry **) a;
5605796c8dcSSimon Schubert   struct sec_merge_hash_entry *B = *(struct sec_merge_hash_entry **) b;
5615796c8dcSSimon Schubert   unsigned int lenA = A->len;
5625796c8dcSSimon Schubert   unsigned int lenB = B->len;
5635796c8dcSSimon Schubert   const unsigned char *s = (const unsigned char *) A->root.string + lenA - 1;
5645796c8dcSSimon Schubert   const unsigned char *t = (const unsigned char *) B->root.string + lenB - 1;
5655796c8dcSSimon Schubert   int l = lenA < lenB ? lenA : lenB;
5665796c8dcSSimon Schubert   int tail_align = (lenA & (A->alignment - 1)) - (lenB & (A->alignment - 1));
5675796c8dcSSimon Schubert 
5685796c8dcSSimon Schubert   if (tail_align != 0)
5695796c8dcSSimon Schubert     return tail_align;
5705796c8dcSSimon Schubert 
5715796c8dcSSimon Schubert   while (l)
5725796c8dcSSimon Schubert     {
5735796c8dcSSimon Schubert       if (*s != *t)
5745796c8dcSSimon Schubert 	return (int) *s - (int) *t;
5755796c8dcSSimon Schubert       s--;
5765796c8dcSSimon Schubert       t--;
5775796c8dcSSimon Schubert       l--;
5785796c8dcSSimon Schubert     }
5795796c8dcSSimon Schubert   return lenA - lenB;
5805796c8dcSSimon Schubert }
5815796c8dcSSimon Schubert 
5825796c8dcSSimon Schubert static inline int
is_suffix(const struct sec_merge_hash_entry * A,const struct sec_merge_hash_entry * B)5835796c8dcSSimon Schubert is_suffix (const struct sec_merge_hash_entry *A,
5845796c8dcSSimon Schubert 	   const struct sec_merge_hash_entry *B)
5855796c8dcSSimon Schubert {
5865796c8dcSSimon Schubert   if (A->len <= B->len)
5875796c8dcSSimon Schubert     /* B cannot be a suffix of A unless A is equal to B, which is guaranteed
5885796c8dcSSimon Schubert        not to be equal by the hash table.  */
5895796c8dcSSimon Schubert     return 0;
5905796c8dcSSimon Schubert 
5915796c8dcSSimon Schubert   return memcmp (A->root.string + (A->len - B->len),
5925796c8dcSSimon Schubert 		 B->root.string, B->len) == 0;
5935796c8dcSSimon Schubert }
5945796c8dcSSimon Schubert 
5955796c8dcSSimon Schubert /* This is a helper function for _bfd_merge_sections.  It attempts to
5965796c8dcSSimon Schubert    merge strings matching suffixes of longer strings.  */
5975796c8dcSSimon Schubert static void
merge_strings(struct sec_merge_info * sinfo)5985796c8dcSSimon Schubert merge_strings (struct sec_merge_info *sinfo)
5995796c8dcSSimon Schubert {
6005796c8dcSSimon Schubert   struct sec_merge_hash_entry **array, **a, *e;
6015796c8dcSSimon Schubert   struct sec_merge_sec_info *secinfo;
6025796c8dcSSimon Schubert   bfd_size_type size, amt;
6035796c8dcSSimon Schubert   unsigned int alignment = 0;
6045796c8dcSSimon Schubert 
6055796c8dcSSimon Schubert   /* Now sort the strings */
6065796c8dcSSimon Schubert   amt = sinfo->htab->size * sizeof (struct sec_merge_hash_entry *);
6075796c8dcSSimon Schubert   array = (struct sec_merge_hash_entry **) bfd_malloc (amt);
6085796c8dcSSimon Schubert   if (array == NULL)
6095796c8dcSSimon Schubert     goto alloc_failure;
6105796c8dcSSimon Schubert 
6115796c8dcSSimon Schubert   for (e = sinfo->htab->first, a = array; e; e = e->next)
6125796c8dcSSimon Schubert     if (e->alignment)
6135796c8dcSSimon Schubert       {
6145796c8dcSSimon Schubert 	*a++ = e;
6155796c8dcSSimon Schubert 	/* Adjust the length to not include the zero terminator.  */
6165796c8dcSSimon Schubert 	e->len -= sinfo->htab->entsize;
6175796c8dcSSimon Schubert 	if (alignment != e->alignment)
6185796c8dcSSimon Schubert 	  {
6195796c8dcSSimon Schubert 	    if (alignment == 0)
6205796c8dcSSimon Schubert 	      alignment = e->alignment;
6215796c8dcSSimon Schubert 	    else
6225796c8dcSSimon Schubert 	      alignment = (unsigned) -1;
6235796c8dcSSimon Schubert 	  }
6245796c8dcSSimon Schubert       }
6255796c8dcSSimon Schubert 
6265796c8dcSSimon Schubert   sinfo->htab->size = a - array;
6275796c8dcSSimon Schubert   if (sinfo->htab->size != 0)
6285796c8dcSSimon Schubert     {
6295796c8dcSSimon Schubert       qsort (array, (size_t) sinfo->htab->size,
6305796c8dcSSimon Schubert 	     sizeof (struct sec_merge_hash_entry *),
6315796c8dcSSimon Schubert 	     (alignment != (unsigned) -1 && alignment > sinfo->htab->entsize
6325796c8dcSSimon Schubert 	      ? strrevcmp_align : strrevcmp));
6335796c8dcSSimon Schubert 
6345796c8dcSSimon Schubert       /* Loop over the sorted array and merge suffixes */
6355796c8dcSSimon Schubert       e = *--a;
6365796c8dcSSimon Schubert       e->len += sinfo->htab->entsize;
6375796c8dcSSimon Schubert       while (--a >= array)
6385796c8dcSSimon Schubert 	{
6395796c8dcSSimon Schubert 	  struct sec_merge_hash_entry *cmp = *a;
6405796c8dcSSimon Schubert 
6415796c8dcSSimon Schubert 	  cmp->len += sinfo->htab->entsize;
6425796c8dcSSimon Schubert 	  if (e->alignment >= cmp->alignment
6435796c8dcSSimon Schubert 	      && !((e->len - cmp->len) & (cmp->alignment - 1))
6445796c8dcSSimon Schubert 	      && is_suffix (e, cmp))
6455796c8dcSSimon Schubert 	    {
6465796c8dcSSimon Schubert 	      cmp->u.suffix = e;
6475796c8dcSSimon Schubert 	      cmp->alignment = 0;
6485796c8dcSSimon Schubert 	    }
6495796c8dcSSimon Schubert 	  else
6505796c8dcSSimon Schubert 	    e = cmp;
6515796c8dcSSimon Schubert 	}
6525796c8dcSSimon Schubert     }
6535796c8dcSSimon Schubert 
6545796c8dcSSimon Schubert alloc_failure:
6555796c8dcSSimon Schubert   if (array)
6565796c8dcSSimon Schubert     free (array);
6575796c8dcSSimon Schubert 
6585796c8dcSSimon Schubert   /* Now assign positions to the strings we want to keep.  */
6595796c8dcSSimon Schubert   size = 0;
6605796c8dcSSimon Schubert   secinfo = sinfo->htab->first->secinfo;
6615796c8dcSSimon Schubert   for (e = sinfo->htab->first; e; e = e->next)
6625796c8dcSSimon Schubert     {
6635796c8dcSSimon Schubert       if (e->secinfo != secinfo)
6645796c8dcSSimon Schubert 	{
6655796c8dcSSimon Schubert 	  secinfo->sec->size = size;
6665796c8dcSSimon Schubert 	  secinfo = e->secinfo;
6675796c8dcSSimon Schubert 	}
6685796c8dcSSimon Schubert       if (e->alignment)
6695796c8dcSSimon Schubert 	{
6705796c8dcSSimon Schubert 	  if (e->secinfo->first_str == NULL)
6715796c8dcSSimon Schubert 	    {
6725796c8dcSSimon Schubert 	      e->secinfo->first_str = e;
6735796c8dcSSimon Schubert 	      size = 0;
6745796c8dcSSimon Schubert 	    }
6755796c8dcSSimon Schubert 	  size = (size + e->alignment - 1) & ~((bfd_vma) e->alignment - 1);
6765796c8dcSSimon Schubert 	  e->u.index = size;
6775796c8dcSSimon Schubert 	  size += e->len;
6785796c8dcSSimon Schubert 	}
6795796c8dcSSimon Schubert     }
6805796c8dcSSimon Schubert   secinfo->sec->size = size;
6815796c8dcSSimon Schubert   if (secinfo->sec->alignment_power != 0)
6825796c8dcSSimon Schubert     {
6835796c8dcSSimon Schubert       bfd_size_type align = (bfd_size_type) 1 << secinfo->sec->alignment_power;
6845796c8dcSSimon Schubert       secinfo->sec->size = (secinfo->sec->size + align - 1) & -align;
6855796c8dcSSimon Schubert     }
6865796c8dcSSimon Schubert 
6875796c8dcSSimon Schubert   /* And now adjust the rest, removing them from the chain (but not hashtable)
6885796c8dcSSimon Schubert      at the same time.  */
6895796c8dcSSimon Schubert   for (a = &sinfo->htab->first, e = *a; e; e = e->next)
6905796c8dcSSimon Schubert     if (e->alignment)
6915796c8dcSSimon Schubert       a = &e->next;
6925796c8dcSSimon Schubert     else
6935796c8dcSSimon Schubert       {
6945796c8dcSSimon Schubert 	*a = e->next;
6955796c8dcSSimon Schubert 	if (e->len)
6965796c8dcSSimon Schubert 	  {
6975796c8dcSSimon Schubert 	    e->secinfo = e->u.suffix->secinfo;
6985796c8dcSSimon Schubert 	    e->alignment = e->u.suffix->alignment;
6995796c8dcSSimon Schubert 	    e->u.index = e->u.suffix->u.index + (e->u.suffix->len - e->len);
7005796c8dcSSimon Schubert 	  }
7015796c8dcSSimon Schubert       }
7025796c8dcSSimon Schubert }
7035796c8dcSSimon Schubert 
7045796c8dcSSimon Schubert /* This function is called once after all SEC_MERGE sections are registered
7055796c8dcSSimon Schubert    with _bfd_merge_section.  */
7065796c8dcSSimon Schubert 
7075796c8dcSSimon Schubert bfd_boolean
_bfd_merge_sections(bfd * abfd,struct bfd_link_info * info ATTRIBUTE_UNUSED,void * xsinfo,void (* remove_hook)(bfd *,asection *))7085796c8dcSSimon Schubert _bfd_merge_sections (bfd *abfd,
7095796c8dcSSimon Schubert 		     struct bfd_link_info *info ATTRIBUTE_UNUSED,
7105796c8dcSSimon Schubert 		     void *xsinfo,
7115796c8dcSSimon Schubert 		     void (*remove_hook) (bfd *, asection *))
7125796c8dcSSimon Schubert {
7135796c8dcSSimon Schubert   struct sec_merge_info *sinfo;
7145796c8dcSSimon Schubert 
7155796c8dcSSimon Schubert   for (sinfo = (struct sec_merge_info *) xsinfo; sinfo; sinfo = sinfo->next)
7165796c8dcSSimon Schubert     {
7175796c8dcSSimon Schubert       struct sec_merge_sec_info * secinfo;
7185796c8dcSSimon Schubert 
7195796c8dcSSimon Schubert       if (! sinfo->chain)
7205796c8dcSSimon Schubert 	continue;
7215796c8dcSSimon Schubert 
7225796c8dcSSimon Schubert       /* Move sinfo->chain to head of the chain, terminate it.  */
7235796c8dcSSimon Schubert       secinfo = sinfo->chain;
7245796c8dcSSimon Schubert       sinfo->chain = secinfo->next;
7255796c8dcSSimon Schubert       secinfo->next = NULL;
7265796c8dcSSimon Schubert 
7275796c8dcSSimon Schubert       /* Record the sections into the hash table.  */
7285796c8dcSSimon Schubert       for (secinfo = sinfo->chain; secinfo; secinfo = secinfo->next)
7295796c8dcSSimon Schubert 	if (secinfo->sec->flags & SEC_EXCLUDE)
7305796c8dcSSimon Schubert 	  {
7315796c8dcSSimon Schubert 	    *secinfo->psecinfo = NULL;
7325796c8dcSSimon Schubert 	    if (remove_hook)
7335796c8dcSSimon Schubert 	      (*remove_hook) (abfd, secinfo->sec);
7345796c8dcSSimon Schubert 	  }
7355796c8dcSSimon Schubert 	else if (! record_section (sinfo, secinfo))
7365796c8dcSSimon Schubert 	  break;
7375796c8dcSSimon Schubert 
7385796c8dcSSimon Schubert       if (secinfo)
7395796c8dcSSimon Schubert 	continue;
7405796c8dcSSimon Schubert 
7415796c8dcSSimon Schubert       if (sinfo->htab->first == NULL)
7425796c8dcSSimon Schubert 	continue;
7435796c8dcSSimon Schubert 
7445796c8dcSSimon Schubert       if (sinfo->htab->strings)
7455796c8dcSSimon Schubert 	merge_strings (sinfo);
7465796c8dcSSimon Schubert       else
7475796c8dcSSimon Schubert 	{
7485796c8dcSSimon Schubert 	  struct sec_merge_hash_entry *e;
7495796c8dcSSimon Schubert 	  bfd_size_type size = 0;
7505796c8dcSSimon Schubert 
7515796c8dcSSimon Schubert 	  /* Things are much simpler for non-strings.
7525796c8dcSSimon Schubert 	     Just assign them slots in the section.  */
7535796c8dcSSimon Schubert 	  secinfo = NULL;
7545796c8dcSSimon Schubert 	  for (e = sinfo->htab->first; e; e = e->next)
7555796c8dcSSimon Schubert 	    {
7565796c8dcSSimon Schubert 	      if (e->secinfo->first_str == NULL)
7575796c8dcSSimon Schubert 		{
7585796c8dcSSimon Schubert 		  if (secinfo)
7595796c8dcSSimon Schubert 		    secinfo->sec->size = size;
7605796c8dcSSimon Schubert 		  e->secinfo->first_str = e;
7615796c8dcSSimon Schubert 		  size = 0;
7625796c8dcSSimon Schubert 		}
7635796c8dcSSimon Schubert 	      size = (size + e->alignment - 1)
7645796c8dcSSimon Schubert 		     & ~((bfd_vma) e->alignment - 1);
7655796c8dcSSimon Schubert 	      e->u.index = size;
7665796c8dcSSimon Schubert 	      size += e->len;
7675796c8dcSSimon Schubert 	      secinfo = e->secinfo;
7685796c8dcSSimon Schubert 	    }
7695796c8dcSSimon Schubert 	  secinfo->sec->size = size;
7705796c8dcSSimon Schubert 	}
7715796c8dcSSimon Schubert 
7725796c8dcSSimon Schubert 	/* Finally remove all input sections which have not made it into
7735796c8dcSSimon Schubert 	   the hash table at all.  */
7745796c8dcSSimon Schubert 	for (secinfo = sinfo->chain; secinfo; secinfo = secinfo->next)
7755796c8dcSSimon Schubert 	  if (secinfo->first_str == NULL)
7765796c8dcSSimon Schubert 	    secinfo->sec->flags |= SEC_EXCLUDE | SEC_KEEP;
7775796c8dcSSimon Schubert     }
7785796c8dcSSimon Schubert 
7795796c8dcSSimon Schubert   return TRUE;
7805796c8dcSSimon Schubert }
7815796c8dcSSimon Schubert 
7825796c8dcSSimon Schubert /* Write out the merged section.  */
7835796c8dcSSimon Schubert 
7845796c8dcSSimon Schubert bfd_boolean
_bfd_write_merged_section(bfd * output_bfd,asection * sec,void * psecinfo)7855796c8dcSSimon Schubert _bfd_write_merged_section (bfd *output_bfd, asection *sec, void *psecinfo)
7865796c8dcSSimon Schubert {
7875796c8dcSSimon Schubert   struct sec_merge_sec_info *secinfo;
7885796c8dcSSimon Schubert   file_ptr pos;
7895796c8dcSSimon Schubert 
7905796c8dcSSimon Schubert   secinfo = (struct sec_merge_sec_info *) psecinfo;
7915796c8dcSSimon Schubert 
7925796c8dcSSimon Schubert   if (!secinfo)
7935796c8dcSSimon Schubert     return FALSE;
7945796c8dcSSimon Schubert 
7955796c8dcSSimon Schubert   if (secinfo->first_str == NULL)
7965796c8dcSSimon Schubert     return TRUE;
7975796c8dcSSimon Schubert 
7985796c8dcSSimon Schubert   /* FIXME: octets_per_byte.  */
7995796c8dcSSimon Schubert   pos = sec->output_section->filepos + sec->output_offset;
8005796c8dcSSimon Schubert   if (bfd_seek (output_bfd, pos, SEEK_SET) != 0)
8015796c8dcSSimon Schubert     return FALSE;
8025796c8dcSSimon Schubert 
8035796c8dcSSimon Schubert   if (! sec_merge_emit (output_bfd, secinfo->first_str))
8045796c8dcSSimon Schubert     return FALSE;
8055796c8dcSSimon Schubert 
8065796c8dcSSimon Schubert   return TRUE;
8075796c8dcSSimon Schubert }
8085796c8dcSSimon Schubert 
8095796c8dcSSimon Schubert /* Adjust an address in the SEC_MERGE section.  Given OFFSET within
8105796c8dcSSimon Schubert    *PSEC, this returns the new offset in the adjusted SEC_MERGE
8115796c8dcSSimon Schubert    section and writes the new section back into *PSEC.  */
8125796c8dcSSimon Schubert 
8135796c8dcSSimon Schubert bfd_vma
_bfd_merged_section_offset(bfd * output_bfd ATTRIBUTE_UNUSED,asection ** psec,void * psecinfo,bfd_vma offset)8145796c8dcSSimon Schubert _bfd_merged_section_offset (bfd *output_bfd ATTRIBUTE_UNUSED, asection **psec,
8155796c8dcSSimon Schubert 			    void *psecinfo, bfd_vma offset)
8165796c8dcSSimon Schubert {
8175796c8dcSSimon Schubert   struct sec_merge_sec_info *secinfo;
8185796c8dcSSimon Schubert   struct sec_merge_hash_entry *entry;
8195796c8dcSSimon Schubert   unsigned char *p;
8205796c8dcSSimon Schubert   asection *sec = *psec;
8215796c8dcSSimon Schubert 
8225796c8dcSSimon Schubert   secinfo = (struct sec_merge_sec_info *) psecinfo;
8235796c8dcSSimon Schubert 
8245796c8dcSSimon Schubert   if (!secinfo)
8255796c8dcSSimon Schubert     return offset;
8265796c8dcSSimon Schubert 
8275796c8dcSSimon Schubert   if (offset >= sec->rawsize)
8285796c8dcSSimon Schubert     {
8295796c8dcSSimon Schubert       if (offset > sec->rawsize)
8305796c8dcSSimon Schubert 	{
8315796c8dcSSimon Schubert 	  (*_bfd_error_handler)
8325796c8dcSSimon Schubert 	    (_("%s: access beyond end of merged section (%ld)"),
8335796c8dcSSimon Schubert 	     bfd_get_filename (sec->owner), (long) offset);
8345796c8dcSSimon Schubert 	}
8355796c8dcSSimon Schubert       return secinfo->first_str ? sec->size : 0;
8365796c8dcSSimon Schubert     }
8375796c8dcSSimon Schubert 
8385796c8dcSSimon Schubert   if (secinfo->htab->strings)
8395796c8dcSSimon Schubert     {
8405796c8dcSSimon Schubert       if (sec->entsize == 1)
8415796c8dcSSimon Schubert 	{
8425796c8dcSSimon Schubert 	  p = secinfo->contents + offset - 1;
8435796c8dcSSimon Schubert 	  while (p >= secinfo->contents && *p)
8445796c8dcSSimon Schubert 	    --p;
8455796c8dcSSimon Schubert 	  ++p;
8465796c8dcSSimon Schubert 	}
8475796c8dcSSimon Schubert       else
8485796c8dcSSimon Schubert 	{
8495796c8dcSSimon Schubert 	  p = secinfo->contents + (offset / sec->entsize) * sec->entsize;
8505796c8dcSSimon Schubert 	  p -= sec->entsize;
8515796c8dcSSimon Schubert 	  while (p >= secinfo->contents)
8525796c8dcSSimon Schubert 	    {
8535796c8dcSSimon Schubert 	      unsigned int i;
8545796c8dcSSimon Schubert 
8555796c8dcSSimon Schubert 	      for (i = 0; i < sec->entsize; ++i)
8565796c8dcSSimon Schubert 		if (p[i] != '\0')
8575796c8dcSSimon Schubert 		  break;
8585796c8dcSSimon Schubert 	      if (i == sec->entsize)
8595796c8dcSSimon Schubert 		break;
8605796c8dcSSimon Schubert 	      p -= sec->entsize;
8615796c8dcSSimon Schubert 	    }
8625796c8dcSSimon Schubert 	  p += sec->entsize;
8635796c8dcSSimon Schubert 	}
8645796c8dcSSimon Schubert     }
8655796c8dcSSimon Schubert   else
8665796c8dcSSimon Schubert     {
8675796c8dcSSimon Schubert       p = secinfo->contents + (offset / sec->entsize) * sec->entsize;
8685796c8dcSSimon Schubert     }
8695796c8dcSSimon Schubert   entry = sec_merge_hash_lookup (secinfo->htab, (char *) p, 0, FALSE);
8705796c8dcSSimon Schubert   if (!entry)
8715796c8dcSSimon Schubert     {
8725796c8dcSSimon Schubert       if (! secinfo->htab->strings)
8735796c8dcSSimon Schubert 	abort ();
8745796c8dcSSimon Schubert       /* This should only happen if somebody points into the padding
8755796c8dcSSimon Schubert 	 after a NUL character but before next entity.  */
8765796c8dcSSimon Schubert       if (*p)
8775796c8dcSSimon Schubert 	abort ();
8785796c8dcSSimon Schubert       if (! secinfo->htab->first)
8795796c8dcSSimon Schubert 	abort ();
8805796c8dcSSimon Schubert       entry = secinfo->htab->first;
8815796c8dcSSimon Schubert       p = (secinfo->contents + (offset / sec->entsize + 1) * sec->entsize
8825796c8dcSSimon Schubert 	   - entry->len);
8835796c8dcSSimon Schubert     }
8845796c8dcSSimon Schubert 
8855796c8dcSSimon Schubert   *psec = entry->secinfo->sec;
8865796c8dcSSimon Schubert   return entry->u.index + (secinfo->contents + offset - p);
8875796c8dcSSimon Schubert }
888*ef5ccd6cSJohn Marino 
889*ef5ccd6cSJohn Marino /* Tidy up when done.  */
890*ef5ccd6cSJohn Marino 
891*ef5ccd6cSJohn Marino void
_bfd_merge_sections_free(void * xsinfo)892*ef5ccd6cSJohn Marino _bfd_merge_sections_free (void *xsinfo)
893*ef5ccd6cSJohn Marino {
894*ef5ccd6cSJohn Marino   struct sec_merge_info *sinfo;
895*ef5ccd6cSJohn Marino 
896*ef5ccd6cSJohn Marino   for (sinfo = (struct sec_merge_info *) xsinfo; sinfo; sinfo = sinfo->next)
897*ef5ccd6cSJohn Marino     {
898*ef5ccd6cSJohn Marino       bfd_hash_table_free (&sinfo->htab->table);
899*ef5ccd6cSJohn Marino       free (sinfo->htab);
900*ef5ccd6cSJohn Marino     }
901*ef5ccd6cSJohn Marino }
902