xref: /dflybsd-src/contrib/binutils-2.27/bfd/merge.c (revision e656dc90e3d65d744d534af2f5ea88cf8101ebcf)
1*a9fa9459Szrj /* SEC_MERGE support.
2*a9fa9459Szrj    Copyright (C) 2001-2016 Free Software Foundation, Inc.
3*a9fa9459Szrj    Written by Jakub Jelinek <jakub@redhat.com>.
4*a9fa9459Szrj 
5*a9fa9459Szrj    This file is part of BFD, the Binary File Descriptor library.
6*a9fa9459Szrj 
7*a9fa9459Szrj    This program is free software; you can redistribute it and/or modify
8*a9fa9459Szrj    it under the terms of the GNU General Public License as published by
9*a9fa9459Szrj    the Free Software Foundation; either version 3 of the License, or
10*a9fa9459Szrj    (at your option) any later version.
11*a9fa9459Szrj 
12*a9fa9459Szrj    This program is distributed in the hope that it will be useful,
13*a9fa9459Szrj    but WITHOUT ANY WARRANTY; without even the implied warranty of
14*a9fa9459Szrj    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15*a9fa9459Szrj    GNU General Public License for more details.
16*a9fa9459Szrj 
17*a9fa9459Szrj    You should have received a copy of the GNU General Public License
18*a9fa9459Szrj    along with this program; if not, write to the Free Software
19*a9fa9459Szrj    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
20*a9fa9459Szrj    MA 02110-1301, USA.  */
21*a9fa9459Szrj 
22*a9fa9459Szrj 
23*a9fa9459Szrj /* This file contains support for merging duplicate entities within sections,
24*a9fa9459Szrj    as used in ELF SHF_MERGE.  */
25*a9fa9459Szrj 
26*a9fa9459Szrj #include "sysdep.h"
27*a9fa9459Szrj #include "bfd.h"
28*a9fa9459Szrj #include "elf-bfd.h"
29*a9fa9459Szrj #include "libbfd.h"
30*a9fa9459Szrj #include "hashtab.h"
31*a9fa9459Szrj #include "libiberty.h"
32*a9fa9459Szrj 
33*a9fa9459Szrj struct sec_merge_sec_info;
34*a9fa9459Szrj 
35*a9fa9459Szrj /* An entry in the section merge hash table.  */
36*a9fa9459Szrj 
37*a9fa9459Szrj struct sec_merge_hash_entry
38*a9fa9459Szrj {
39*a9fa9459Szrj   struct bfd_hash_entry root;
40*a9fa9459Szrj   /* Length of this entry.  This includes the zero terminator.  */
41*a9fa9459Szrj   unsigned int len;
42*a9fa9459Szrj   /* Start of this string needs to be aligned to
43*a9fa9459Szrj      alignment octets (not 1 << align).  */
44*a9fa9459Szrj   unsigned int alignment;
45*a9fa9459Szrj   union
46*a9fa9459Szrj   {
47*a9fa9459Szrj     /* Index within the merged section.  */
48*a9fa9459Szrj     bfd_size_type index;
49*a9fa9459Szrj     /* Entry this is a suffix of (if alignment is 0).  */
50*a9fa9459Szrj     struct sec_merge_hash_entry *suffix;
51*a9fa9459Szrj   } u;
52*a9fa9459Szrj   /* Which section is it in.  */
53*a9fa9459Szrj   struct sec_merge_sec_info *secinfo;
54*a9fa9459Szrj   /* Next entity in the hash table.  */
55*a9fa9459Szrj   struct sec_merge_hash_entry *next;
56*a9fa9459Szrj };
57*a9fa9459Szrj 
58*a9fa9459Szrj /* The section merge hash table.  */
59*a9fa9459Szrj 
60*a9fa9459Szrj struct sec_merge_hash
61*a9fa9459Szrj {
62*a9fa9459Szrj   struct bfd_hash_table table;
63*a9fa9459Szrj   /* Next available index.  */
64*a9fa9459Szrj   bfd_size_type size;
65*a9fa9459Szrj   /* First entity in the SEC_MERGE sections of this type.  */
66*a9fa9459Szrj   struct sec_merge_hash_entry *first;
67*a9fa9459Szrj   /* Last entity in the SEC_MERGE sections of this type.  */
68*a9fa9459Szrj   struct sec_merge_hash_entry *last;
69*a9fa9459Szrj   /* Entity size.  */
70*a9fa9459Szrj   unsigned int entsize;
71*a9fa9459Szrj   /* Are entries fixed size or zero terminated strings?  */
72*a9fa9459Szrj   bfd_boolean strings;
73*a9fa9459Szrj };
74*a9fa9459Szrj 
75*a9fa9459Szrj struct sec_merge_info
76*a9fa9459Szrj {
77*a9fa9459Szrj   /* Chain of sec_merge_infos.  */
78*a9fa9459Szrj   struct sec_merge_info *next;
79*a9fa9459Szrj   /* Chain of sec_merge_sec_infos.  */
80*a9fa9459Szrj   struct sec_merge_sec_info *chain;
81*a9fa9459Szrj   /* A hash table used to hold section content.  */
82*a9fa9459Szrj   struct sec_merge_hash *htab;
83*a9fa9459Szrj };
84*a9fa9459Szrj 
85*a9fa9459Szrj struct sec_merge_sec_info
86*a9fa9459Szrj {
87*a9fa9459Szrj   /* Chain of sec_merge_sec_infos.  */
88*a9fa9459Szrj   struct sec_merge_sec_info *next;
89*a9fa9459Szrj   /* The corresponding section.  */
90*a9fa9459Szrj   asection *sec;
91*a9fa9459Szrj   /* Pointer to merge_info pointing to us.  */
92*a9fa9459Szrj   void **psecinfo;
93*a9fa9459Szrj   /* A hash table used to hold section content.  */
94*a9fa9459Szrj   struct sec_merge_hash *htab;
95*a9fa9459Szrj   /* First string in this section.  */
96*a9fa9459Szrj   struct sec_merge_hash_entry *first_str;
97*a9fa9459Szrj   /* Original section content.  */
98*a9fa9459Szrj   unsigned char contents[1];
99*a9fa9459Szrj };
100*a9fa9459Szrj 
101*a9fa9459Szrj 
102*a9fa9459Szrj /* Routine to create an entry in a section merge hashtab.  */
103*a9fa9459Szrj 
104*a9fa9459Szrj static struct bfd_hash_entry *
sec_merge_hash_newfunc(struct bfd_hash_entry * entry,struct bfd_hash_table * table,const char * string)105*a9fa9459Szrj sec_merge_hash_newfunc (struct bfd_hash_entry *entry,
106*a9fa9459Szrj 			struct bfd_hash_table *table, const char *string)
107*a9fa9459Szrj {
108*a9fa9459Szrj   /* Allocate the structure if it has not already been allocated by a
109*a9fa9459Szrj      subclass.  */
110*a9fa9459Szrj   if (entry == NULL)
111*a9fa9459Szrj     entry = (struct bfd_hash_entry *)
112*a9fa9459Szrj         bfd_hash_allocate (table, sizeof (struct sec_merge_hash_entry));
113*a9fa9459Szrj   if (entry == NULL)
114*a9fa9459Szrj     return NULL;
115*a9fa9459Szrj 
116*a9fa9459Szrj   /* Call the allocation method of the superclass.  */
117*a9fa9459Szrj   entry = bfd_hash_newfunc (entry, table, string);
118*a9fa9459Szrj 
119*a9fa9459Szrj   if (entry != NULL)
120*a9fa9459Szrj     {
121*a9fa9459Szrj       /* Initialize the local fields.  */
122*a9fa9459Szrj       struct sec_merge_hash_entry *ret = (struct sec_merge_hash_entry *) entry;
123*a9fa9459Szrj 
124*a9fa9459Szrj       ret->u.suffix = NULL;
125*a9fa9459Szrj       ret->alignment = 0;
126*a9fa9459Szrj       ret->secinfo = NULL;
127*a9fa9459Szrj       ret->next = NULL;
128*a9fa9459Szrj     }
129*a9fa9459Szrj 
130*a9fa9459Szrj   return entry;
131*a9fa9459Szrj }
132*a9fa9459Szrj 
133*a9fa9459Szrj /* Look up an entry in a section merge hash table.  */
134*a9fa9459Szrj 
135*a9fa9459Szrj static struct sec_merge_hash_entry *
sec_merge_hash_lookup(struct sec_merge_hash * table,const char * string,unsigned int alignment,bfd_boolean create)136*a9fa9459Szrj sec_merge_hash_lookup (struct sec_merge_hash *table, const char *string,
137*a9fa9459Szrj 		       unsigned int alignment, bfd_boolean create)
138*a9fa9459Szrj {
139*a9fa9459Szrj   const unsigned char *s;
140*a9fa9459Szrj   unsigned long hash;
141*a9fa9459Szrj   unsigned int c;
142*a9fa9459Szrj   struct sec_merge_hash_entry *hashp;
143*a9fa9459Szrj   unsigned int len, i;
144*a9fa9459Szrj   unsigned int _index;
145*a9fa9459Szrj 
146*a9fa9459Szrj   hash = 0;
147*a9fa9459Szrj   len = 0;
148*a9fa9459Szrj   s = (const unsigned char *) string;
149*a9fa9459Szrj   if (table->strings)
150*a9fa9459Szrj     {
151*a9fa9459Szrj       if (table->entsize == 1)
152*a9fa9459Szrj 	{
153*a9fa9459Szrj 	  while ((c = *s++) != '\0')
154*a9fa9459Szrj 	    {
155*a9fa9459Szrj 	      hash += c + (c << 17);
156*a9fa9459Szrj 	      hash ^= hash >> 2;
157*a9fa9459Szrj 	      ++len;
158*a9fa9459Szrj 	    }
159*a9fa9459Szrj 	  hash += len + (len << 17);
160*a9fa9459Szrj 	}
161*a9fa9459Szrj       else
162*a9fa9459Szrj 	{
163*a9fa9459Szrj 	  for (;;)
164*a9fa9459Szrj 	    {
165*a9fa9459Szrj 	      for (i = 0; i < table->entsize; ++i)
166*a9fa9459Szrj 		if (s[i] != '\0')
167*a9fa9459Szrj 		  break;
168*a9fa9459Szrj 	      if (i == table->entsize)
169*a9fa9459Szrj 		break;
170*a9fa9459Szrj 	      for (i = 0; i < table->entsize; ++i)
171*a9fa9459Szrj 		{
172*a9fa9459Szrj 		  c = *s++;
173*a9fa9459Szrj 		  hash += c + (c << 17);
174*a9fa9459Szrj 		  hash ^= hash >> 2;
175*a9fa9459Szrj 		}
176*a9fa9459Szrj 	      ++len;
177*a9fa9459Szrj 	    }
178*a9fa9459Szrj 	  hash += len + (len << 17);
179*a9fa9459Szrj 	  len *= table->entsize;
180*a9fa9459Szrj 	}
181*a9fa9459Szrj       hash ^= hash >> 2;
182*a9fa9459Szrj       len += table->entsize;
183*a9fa9459Szrj     }
184*a9fa9459Szrj   else
185*a9fa9459Szrj     {
186*a9fa9459Szrj       for (i = 0; i < table->entsize; ++i)
187*a9fa9459Szrj 	{
188*a9fa9459Szrj 	  c = *s++;
189*a9fa9459Szrj 	  hash += c + (c << 17);
190*a9fa9459Szrj 	  hash ^= hash >> 2;
191*a9fa9459Szrj 	}
192*a9fa9459Szrj       len = table->entsize;
193*a9fa9459Szrj     }
194*a9fa9459Szrj 
195*a9fa9459Szrj   _index = hash % table->table.size;
196*a9fa9459Szrj   for (hashp = (struct sec_merge_hash_entry *) table->table.table[_index];
197*a9fa9459Szrj        hashp != NULL;
198*a9fa9459Szrj        hashp = (struct sec_merge_hash_entry *) hashp->root.next)
199*a9fa9459Szrj     {
200*a9fa9459Szrj       if (hashp->root.hash == hash
201*a9fa9459Szrj 	  && len == hashp->len
202*a9fa9459Szrj 	  && memcmp (hashp->root.string, string, len) == 0)
203*a9fa9459Szrj 	{
204*a9fa9459Szrj 	  /* If the string we found does not have at least the required
205*a9fa9459Szrj 	     alignment, we need to insert another copy.  */
206*a9fa9459Szrj 	  if (hashp->alignment < alignment)
207*a9fa9459Szrj 	    {
208*a9fa9459Szrj 	      if (create)
209*a9fa9459Szrj 		{
210*a9fa9459Szrj 		  /*  Mark the less aligned copy as deleted.  */
211*a9fa9459Szrj 		  hashp->len = 0;
212*a9fa9459Szrj 		  hashp->alignment = 0;
213*a9fa9459Szrj 		}
214*a9fa9459Szrj 	      break;
215*a9fa9459Szrj 	    }
216*a9fa9459Szrj 	  return hashp;
217*a9fa9459Szrj 	}
218*a9fa9459Szrj     }
219*a9fa9459Szrj 
220*a9fa9459Szrj   if (! create)
221*a9fa9459Szrj     return NULL;
222*a9fa9459Szrj 
223*a9fa9459Szrj   hashp = ((struct sec_merge_hash_entry *)
224*a9fa9459Szrj 	   bfd_hash_insert (&table->table, string, hash));
225*a9fa9459Szrj   if (hashp == NULL)
226*a9fa9459Szrj     return NULL;
227*a9fa9459Szrj   hashp->len = len;
228*a9fa9459Szrj   hashp->alignment = alignment;
229*a9fa9459Szrj   return hashp;
230*a9fa9459Szrj }
231*a9fa9459Szrj 
232*a9fa9459Szrj /* Create a new hash table.  */
233*a9fa9459Szrj 
234*a9fa9459Szrj static struct sec_merge_hash *
sec_merge_init(unsigned int entsize,bfd_boolean strings)235*a9fa9459Szrj sec_merge_init (unsigned int entsize, bfd_boolean strings)
236*a9fa9459Szrj {
237*a9fa9459Szrj   struct sec_merge_hash *table;
238*a9fa9459Szrj 
239*a9fa9459Szrj   table = (struct sec_merge_hash *) bfd_malloc (sizeof (struct sec_merge_hash));
240*a9fa9459Szrj   if (table == NULL)
241*a9fa9459Szrj     return NULL;
242*a9fa9459Szrj 
243*a9fa9459Szrj   if (! bfd_hash_table_init_n (&table->table, sec_merge_hash_newfunc,
244*a9fa9459Szrj 			       sizeof (struct sec_merge_hash_entry), 16699))
245*a9fa9459Szrj     {
246*a9fa9459Szrj       free (table);
247*a9fa9459Szrj       return NULL;
248*a9fa9459Szrj     }
249*a9fa9459Szrj 
250*a9fa9459Szrj   table->size = 0;
251*a9fa9459Szrj   table->first = NULL;
252*a9fa9459Szrj   table->last = NULL;
253*a9fa9459Szrj   table->entsize = entsize;
254*a9fa9459Szrj   table->strings = strings;
255*a9fa9459Szrj 
256*a9fa9459Szrj   return table;
257*a9fa9459Szrj }
258*a9fa9459Szrj 
259*a9fa9459Szrj /* Get the index of an entity in a hash table, adding it if it is not
260*a9fa9459Szrj    already present.  */
261*a9fa9459Szrj 
262*a9fa9459Szrj 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)263*a9fa9459Szrj sec_merge_add (struct sec_merge_hash *tab, const char *str,
264*a9fa9459Szrj 	       unsigned int alignment, struct sec_merge_sec_info *secinfo)
265*a9fa9459Szrj {
266*a9fa9459Szrj   struct sec_merge_hash_entry *entry;
267*a9fa9459Szrj 
268*a9fa9459Szrj   entry = sec_merge_hash_lookup (tab, str, alignment, TRUE);
269*a9fa9459Szrj   if (entry == NULL)
270*a9fa9459Szrj     return NULL;
271*a9fa9459Szrj 
272*a9fa9459Szrj   if (entry->secinfo == NULL)
273*a9fa9459Szrj     {
274*a9fa9459Szrj       tab->size++;
275*a9fa9459Szrj       entry->secinfo = secinfo;
276*a9fa9459Szrj       if (tab->first == NULL)
277*a9fa9459Szrj 	tab->first = entry;
278*a9fa9459Szrj       else
279*a9fa9459Szrj 	tab->last->next = entry;
280*a9fa9459Szrj       tab->last = entry;
281*a9fa9459Szrj     }
282*a9fa9459Szrj 
283*a9fa9459Szrj   return entry;
284*a9fa9459Szrj }
285*a9fa9459Szrj 
286*a9fa9459Szrj static bfd_boolean
sec_merge_emit(bfd * abfd,struct sec_merge_hash_entry * entry,unsigned char * contents,file_ptr offset)287*a9fa9459Szrj sec_merge_emit (bfd *abfd, struct sec_merge_hash_entry *entry,
288*a9fa9459Szrj 		unsigned char *contents, file_ptr offset)
289*a9fa9459Szrj {
290*a9fa9459Szrj   struct sec_merge_sec_info *secinfo = entry->secinfo;
291*a9fa9459Szrj   asection *sec = secinfo->sec;
292*a9fa9459Szrj   char *pad = NULL;
293*a9fa9459Szrj   bfd_size_type off = 0;
294*a9fa9459Szrj   int alignment_power = sec->output_section->alignment_power;
295*a9fa9459Szrj 
296*a9fa9459Szrj   if (alignment_power)
297*a9fa9459Szrj     {
298*a9fa9459Szrj       pad = (char *) bfd_zmalloc ((bfd_size_type) 1 << alignment_power);
299*a9fa9459Szrj       if (pad == NULL)
300*a9fa9459Szrj 	return FALSE;
301*a9fa9459Szrj     }
302*a9fa9459Szrj 
303*a9fa9459Szrj   for (; entry != NULL && entry->secinfo == secinfo; entry = entry->next)
304*a9fa9459Szrj     {
305*a9fa9459Szrj       const char *str;
306*a9fa9459Szrj       bfd_size_type len;
307*a9fa9459Szrj 
308*a9fa9459Szrj       len = -off & (entry->alignment - 1);
309*a9fa9459Szrj       if (len != 0)
310*a9fa9459Szrj 	{
311*a9fa9459Szrj 	  if (contents)
312*a9fa9459Szrj 	    {
313*a9fa9459Szrj 	      memcpy (contents + offset, pad, len);
314*a9fa9459Szrj 	      offset += len;
315*a9fa9459Szrj 	    }
316*a9fa9459Szrj 	  else if (bfd_bwrite (pad, len, abfd) != len)
317*a9fa9459Szrj 	    goto err;
318*a9fa9459Szrj 	  off += len;
319*a9fa9459Szrj 	}
320*a9fa9459Szrj 
321*a9fa9459Szrj       str = entry->root.string;
322*a9fa9459Szrj       len = entry->len;
323*a9fa9459Szrj 
324*a9fa9459Szrj       if (contents)
325*a9fa9459Szrj 	{
326*a9fa9459Szrj 	  memcpy (contents + offset, str, len);
327*a9fa9459Szrj 	  offset += len;
328*a9fa9459Szrj 	}
329*a9fa9459Szrj       else if (bfd_bwrite (str, len, abfd) != len)
330*a9fa9459Szrj 	goto err;
331*a9fa9459Szrj 
332*a9fa9459Szrj       off += len;
333*a9fa9459Szrj     }
334*a9fa9459Szrj 
335*a9fa9459Szrj   /* Trailing alignment needed?  */
336*a9fa9459Szrj   off = sec->size - off;
337*a9fa9459Szrj   if (off != 0)
338*a9fa9459Szrj     {
339*a9fa9459Szrj       if (contents)
340*a9fa9459Szrj 	memcpy (contents + offset, pad, off);
341*a9fa9459Szrj       else if (bfd_bwrite (pad, off, abfd) != off)
342*a9fa9459Szrj 	goto err;
343*a9fa9459Szrj     }
344*a9fa9459Szrj 
345*a9fa9459Szrj   if (pad != NULL)
346*a9fa9459Szrj     free (pad);
347*a9fa9459Szrj   return TRUE;
348*a9fa9459Szrj 
349*a9fa9459Szrj  err:
350*a9fa9459Szrj   if (pad != NULL)
351*a9fa9459Szrj     free (pad);
352*a9fa9459Szrj   return FALSE;
353*a9fa9459Szrj }
354*a9fa9459Szrj 
355*a9fa9459Szrj /* Register a SEC_MERGE section as a candidate for merging.
356*a9fa9459Szrj    This function is called for all non-dynamic SEC_MERGE input sections.  */
357*a9fa9459Szrj 
358*a9fa9459Szrj bfd_boolean
_bfd_add_merge_section(bfd * abfd,void ** psinfo,asection * sec,void ** psecinfo)359*a9fa9459Szrj _bfd_add_merge_section (bfd *abfd, void **psinfo, asection *sec,
360*a9fa9459Szrj 			void **psecinfo)
361*a9fa9459Szrj {
362*a9fa9459Szrj   struct sec_merge_info *sinfo;
363*a9fa9459Szrj   struct sec_merge_sec_info *secinfo;
364*a9fa9459Szrj   unsigned int align;
365*a9fa9459Szrj   bfd_size_type amt;
366*a9fa9459Szrj   bfd_byte *contents;
367*a9fa9459Szrj 
368*a9fa9459Szrj   if ((abfd->flags & DYNAMIC) != 0
369*a9fa9459Szrj       || (sec->flags & SEC_MERGE) == 0)
370*a9fa9459Szrj     abort ();
371*a9fa9459Szrj 
372*a9fa9459Szrj   if (sec->size == 0
373*a9fa9459Szrj       || (sec->flags & SEC_EXCLUDE) != 0
374*a9fa9459Szrj       || sec->entsize == 0)
375*a9fa9459Szrj     return TRUE;
376*a9fa9459Szrj 
377*a9fa9459Szrj   if ((sec->flags & SEC_RELOC) != 0)
378*a9fa9459Szrj     {
379*a9fa9459Szrj       /* We aren't prepared to handle relocations in merged sections.  */
380*a9fa9459Szrj       return TRUE;
381*a9fa9459Szrj     }
382*a9fa9459Szrj 
383*a9fa9459Szrj   align = sec->alignment_power;
384*a9fa9459Szrj   if ((sec->entsize < (unsigned) 1 << align
385*a9fa9459Szrj        && ((sec->entsize & (sec->entsize - 1))
386*a9fa9459Szrj 	   || !(sec->flags & SEC_STRINGS)))
387*a9fa9459Szrj       || (sec->entsize > (unsigned) 1 << align
388*a9fa9459Szrj 	  && (sec->entsize & (((unsigned) 1 << align) - 1))))
389*a9fa9459Szrj     {
390*a9fa9459Szrj       /* Sanity check.  If string character size is smaller than
391*a9fa9459Szrj 	 alignment, then we require character size to be a power
392*a9fa9459Szrj 	 of 2, otherwise character size must be integer multiple
393*a9fa9459Szrj 	 of alignment.  For non-string constants, alignment must
394*a9fa9459Szrj 	 be smaller than or equal to entity size and entity size
395*a9fa9459Szrj 	 must be integer multiple of alignment.  */
396*a9fa9459Szrj       return TRUE;
397*a9fa9459Szrj     }
398*a9fa9459Szrj 
399*a9fa9459Szrj   for (sinfo = (struct sec_merge_info *) *psinfo; sinfo; sinfo = sinfo->next)
400*a9fa9459Szrj     if ((secinfo = sinfo->chain)
401*a9fa9459Szrj 	&& ! ((secinfo->sec->flags ^ sec->flags) & (SEC_MERGE | SEC_STRINGS))
402*a9fa9459Szrj 	&& secinfo->sec->entsize == sec->entsize
403*a9fa9459Szrj 	&& secinfo->sec->alignment_power == sec->alignment_power
404*a9fa9459Szrj 	&& secinfo->sec->output_section == sec->output_section)
405*a9fa9459Szrj       break;
406*a9fa9459Szrj 
407*a9fa9459Szrj   if (sinfo == NULL)
408*a9fa9459Szrj     {
409*a9fa9459Szrj       /* Initialize the information we need to keep track of.  */
410*a9fa9459Szrj       sinfo = (struct sec_merge_info *)
411*a9fa9459Szrj           bfd_alloc (abfd, sizeof (struct sec_merge_info));
412*a9fa9459Szrj       if (sinfo == NULL)
413*a9fa9459Szrj 	goto error_return;
414*a9fa9459Szrj       sinfo->next = (struct sec_merge_info *) *psinfo;
415*a9fa9459Szrj       sinfo->chain = NULL;
416*a9fa9459Szrj       *psinfo = sinfo;
417*a9fa9459Szrj       sinfo->htab = sec_merge_init (sec->entsize, (sec->flags & SEC_STRINGS));
418*a9fa9459Szrj       if (sinfo->htab == NULL)
419*a9fa9459Szrj 	goto error_return;
420*a9fa9459Szrj     }
421*a9fa9459Szrj 
422*a9fa9459Szrj   /* Read the section from abfd.  */
423*a9fa9459Szrj 
424*a9fa9459Szrj   amt = sizeof (struct sec_merge_sec_info) - 1 + sec->size;
425*a9fa9459Szrj   if (sec->flags & SEC_STRINGS)
426*a9fa9459Szrj     /* Some versions of gcc may emit a string without a zero terminator.
427*a9fa9459Szrj        See http://gcc.gnu.org/ml/gcc-patches/2006-06/msg01004.html
428*a9fa9459Szrj        Allocate space for an extra zero.  */
429*a9fa9459Szrj     amt += sec->entsize;
430*a9fa9459Szrj   *psecinfo = bfd_alloc (abfd, amt);
431*a9fa9459Szrj   if (*psecinfo == NULL)
432*a9fa9459Szrj     goto error_return;
433*a9fa9459Szrj 
434*a9fa9459Szrj   secinfo = (struct sec_merge_sec_info *) *psecinfo;
435*a9fa9459Szrj   if (sinfo->chain)
436*a9fa9459Szrj     {
437*a9fa9459Szrj       secinfo->next = sinfo->chain->next;
438*a9fa9459Szrj       sinfo->chain->next = secinfo;
439*a9fa9459Szrj     }
440*a9fa9459Szrj   else
441*a9fa9459Szrj     secinfo->next = secinfo;
442*a9fa9459Szrj   sinfo->chain = secinfo;
443*a9fa9459Szrj   secinfo->sec = sec;
444*a9fa9459Szrj   secinfo->psecinfo = psecinfo;
445*a9fa9459Szrj   secinfo->htab = sinfo->htab;
446*a9fa9459Szrj   secinfo->first_str = NULL;
447*a9fa9459Szrj 
448*a9fa9459Szrj   sec->rawsize = sec->size;
449*a9fa9459Szrj   if (sec->flags & SEC_STRINGS)
450*a9fa9459Szrj     memset (secinfo->contents + sec->size, 0, sec->entsize);
451*a9fa9459Szrj   contents = secinfo->contents;
452*a9fa9459Szrj   if (! bfd_get_full_section_contents (sec->owner, sec, &contents))
453*a9fa9459Szrj     goto error_return;
454*a9fa9459Szrj 
455*a9fa9459Szrj   return TRUE;
456*a9fa9459Szrj 
457*a9fa9459Szrj  error_return:
458*a9fa9459Szrj   *psecinfo = NULL;
459*a9fa9459Szrj   return FALSE;
460*a9fa9459Szrj }
461*a9fa9459Szrj 
462*a9fa9459Szrj /* Record one section into the hash table.  */
463*a9fa9459Szrj static bfd_boolean
record_section(struct sec_merge_info * sinfo,struct sec_merge_sec_info * secinfo)464*a9fa9459Szrj record_section (struct sec_merge_info *sinfo,
465*a9fa9459Szrj 		struct sec_merge_sec_info *secinfo)
466*a9fa9459Szrj {
467*a9fa9459Szrj   asection *sec = secinfo->sec;
468*a9fa9459Szrj   struct sec_merge_hash_entry *entry;
469*a9fa9459Szrj   bfd_boolean nul;
470*a9fa9459Szrj   unsigned char *p, *end;
471*a9fa9459Szrj   bfd_vma mask, eltalign;
472*a9fa9459Szrj   unsigned int align, i;
473*a9fa9459Szrj 
474*a9fa9459Szrj   align = sec->alignment_power;
475*a9fa9459Szrj   end = secinfo->contents + sec->size;
476*a9fa9459Szrj   nul = FALSE;
477*a9fa9459Szrj   mask = ((bfd_vma) 1 << align) - 1;
478*a9fa9459Szrj   if (sec->flags & SEC_STRINGS)
479*a9fa9459Szrj     {
480*a9fa9459Szrj       for (p = secinfo->contents; p < end; )
481*a9fa9459Szrj 	{
482*a9fa9459Szrj 	  eltalign = p - secinfo->contents;
483*a9fa9459Szrj 	  eltalign = ((eltalign ^ (eltalign - 1)) + 1) >> 1;
484*a9fa9459Szrj 	  if (!eltalign || eltalign > mask)
485*a9fa9459Szrj 	    eltalign = mask + 1;
486*a9fa9459Szrj 	  entry = sec_merge_add (sinfo->htab, (char *) p, (unsigned) eltalign,
487*a9fa9459Szrj 				 secinfo);
488*a9fa9459Szrj 	  if (! entry)
489*a9fa9459Szrj 	    goto error_return;
490*a9fa9459Szrj 	  p += entry->len;
491*a9fa9459Szrj 	  if (sec->entsize == 1)
492*a9fa9459Szrj 	    {
493*a9fa9459Szrj 	      while (p < end && *p == 0)
494*a9fa9459Szrj 		{
495*a9fa9459Szrj 		  if (!nul && !((p - secinfo->contents) & mask))
496*a9fa9459Szrj 		    {
497*a9fa9459Szrj 		      nul = TRUE;
498*a9fa9459Szrj 		      entry = sec_merge_add (sinfo->htab, "",
499*a9fa9459Szrj 					     (unsigned) mask + 1, secinfo);
500*a9fa9459Szrj 		      if (! entry)
501*a9fa9459Szrj 			goto error_return;
502*a9fa9459Szrj 		    }
503*a9fa9459Szrj 		  p++;
504*a9fa9459Szrj 		}
505*a9fa9459Szrj 	    }
506*a9fa9459Szrj 	  else
507*a9fa9459Szrj 	    {
508*a9fa9459Szrj 	      while (p < end)
509*a9fa9459Szrj 		{
510*a9fa9459Szrj 		  for (i = 0; i < sec->entsize; i++)
511*a9fa9459Szrj 		    if (p[i] != '\0')
512*a9fa9459Szrj 		      break;
513*a9fa9459Szrj 		  if (i != sec->entsize)
514*a9fa9459Szrj 		    break;
515*a9fa9459Szrj 		  if (!nul && !((p - secinfo->contents) & mask))
516*a9fa9459Szrj 		    {
517*a9fa9459Szrj 		      nul = TRUE;
518*a9fa9459Szrj 		      entry = sec_merge_add (sinfo->htab, (char *) p,
519*a9fa9459Szrj 					     (unsigned) mask + 1, secinfo);
520*a9fa9459Szrj 		      if (! entry)
521*a9fa9459Szrj 			goto error_return;
522*a9fa9459Szrj 		    }
523*a9fa9459Szrj 		  p += sec->entsize;
524*a9fa9459Szrj 		}
525*a9fa9459Szrj 	    }
526*a9fa9459Szrj 	}
527*a9fa9459Szrj     }
528*a9fa9459Szrj   else
529*a9fa9459Szrj     {
530*a9fa9459Szrj       for (p = secinfo->contents; p < end; p += sec->entsize)
531*a9fa9459Szrj 	{
532*a9fa9459Szrj 	  entry = sec_merge_add (sinfo->htab, (char *) p, 1, secinfo);
533*a9fa9459Szrj 	  if (! entry)
534*a9fa9459Szrj 	    goto error_return;
535*a9fa9459Szrj 	}
536*a9fa9459Szrj     }
537*a9fa9459Szrj 
538*a9fa9459Szrj   return TRUE;
539*a9fa9459Szrj 
540*a9fa9459Szrj error_return:
541*a9fa9459Szrj   for (secinfo = sinfo->chain; secinfo; secinfo = secinfo->next)
542*a9fa9459Szrj     *secinfo->psecinfo = NULL;
543*a9fa9459Szrj   return FALSE;
544*a9fa9459Szrj }
545*a9fa9459Szrj 
546*a9fa9459Szrj static int
strrevcmp(const void * a,const void * b)547*a9fa9459Szrj strrevcmp (const void *a, const void *b)
548*a9fa9459Szrj {
549*a9fa9459Szrj   struct sec_merge_hash_entry *A = *(struct sec_merge_hash_entry **) a;
550*a9fa9459Szrj   struct sec_merge_hash_entry *B = *(struct sec_merge_hash_entry **) b;
551*a9fa9459Szrj   unsigned int lenA = A->len;
552*a9fa9459Szrj   unsigned int lenB = B->len;
553*a9fa9459Szrj   const unsigned char *s = (const unsigned char *) A->root.string + lenA - 1;
554*a9fa9459Szrj   const unsigned char *t = (const unsigned char *) B->root.string + lenB - 1;
555*a9fa9459Szrj   int l = lenA < lenB ? lenA : lenB;
556*a9fa9459Szrj 
557*a9fa9459Szrj   while (l)
558*a9fa9459Szrj     {
559*a9fa9459Szrj       if (*s != *t)
560*a9fa9459Szrj 	return (int) *s - (int) *t;
561*a9fa9459Szrj       s--;
562*a9fa9459Szrj       t--;
563*a9fa9459Szrj       l--;
564*a9fa9459Szrj     }
565*a9fa9459Szrj   return lenA - lenB;
566*a9fa9459Szrj }
567*a9fa9459Szrj 
568*a9fa9459Szrj /* Like strrevcmp, but for the case where all strings have the same
569*a9fa9459Szrj    alignment > entsize.  */
570*a9fa9459Szrj 
571*a9fa9459Szrj static int
strrevcmp_align(const void * a,const void * b)572*a9fa9459Szrj strrevcmp_align (const void *a, const void *b)
573*a9fa9459Szrj {
574*a9fa9459Szrj   struct sec_merge_hash_entry *A = *(struct sec_merge_hash_entry **) a;
575*a9fa9459Szrj   struct sec_merge_hash_entry *B = *(struct sec_merge_hash_entry **) b;
576*a9fa9459Szrj   unsigned int lenA = A->len;
577*a9fa9459Szrj   unsigned int lenB = B->len;
578*a9fa9459Szrj   const unsigned char *s = (const unsigned char *) A->root.string + lenA - 1;
579*a9fa9459Szrj   const unsigned char *t = (const unsigned char *) B->root.string + lenB - 1;
580*a9fa9459Szrj   int l = lenA < lenB ? lenA : lenB;
581*a9fa9459Szrj   int tail_align = (lenA & (A->alignment - 1)) - (lenB & (A->alignment - 1));
582*a9fa9459Szrj 
583*a9fa9459Szrj   if (tail_align != 0)
584*a9fa9459Szrj     return tail_align;
585*a9fa9459Szrj 
586*a9fa9459Szrj   while (l)
587*a9fa9459Szrj     {
588*a9fa9459Szrj       if (*s != *t)
589*a9fa9459Szrj 	return (int) *s - (int) *t;
590*a9fa9459Szrj       s--;
591*a9fa9459Szrj       t--;
592*a9fa9459Szrj       l--;
593*a9fa9459Szrj     }
594*a9fa9459Szrj   return lenA - lenB;
595*a9fa9459Szrj }
596*a9fa9459Szrj 
597*a9fa9459Szrj static inline int
is_suffix(const struct sec_merge_hash_entry * A,const struct sec_merge_hash_entry * B)598*a9fa9459Szrj is_suffix (const struct sec_merge_hash_entry *A,
599*a9fa9459Szrj 	   const struct sec_merge_hash_entry *B)
600*a9fa9459Szrj {
601*a9fa9459Szrj   if (A->len <= B->len)
602*a9fa9459Szrj     /* B cannot be a suffix of A unless A is equal to B, which is guaranteed
603*a9fa9459Szrj        not to be equal by the hash table.  */
604*a9fa9459Szrj     return 0;
605*a9fa9459Szrj 
606*a9fa9459Szrj   return memcmp (A->root.string + (A->len - B->len),
607*a9fa9459Szrj 		 B->root.string, B->len) == 0;
608*a9fa9459Szrj }
609*a9fa9459Szrj 
610*a9fa9459Szrj /* This is a helper function for _bfd_merge_sections.  It attempts to
611*a9fa9459Szrj    merge strings matching suffixes of longer strings.  */
612*a9fa9459Szrj static void
merge_strings(struct sec_merge_info * sinfo)613*a9fa9459Szrj merge_strings (struct sec_merge_info *sinfo)
614*a9fa9459Szrj {
615*a9fa9459Szrj   struct sec_merge_hash_entry **array, **a, *e;
616*a9fa9459Szrj   struct sec_merge_sec_info *secinfo;
617*a9fa9459Szrj   bfd_size_type size, amt;
618*a9fa9459Szrj   unsigned int alignment = 0;
619*a9fa9459Szrj 
620*a9fa9459Szrj   /* Now sort the strings */
621*a9fa9459Szrj   amt = sinfo->htab->size * sizeof (struct sec_merge_hash_entry *);
622*a9fa9459Szrj   array = (struct sec_merge_hash_entry **) bfd_malloc (amt);
623*a9fa9459Szrj   if (array == NULL)
624*a9fa9459Szrj     goto alloc_failure;
625*a9fa9459Szrj 
626*a9fa9459Szrj   for (e = sinfo->htab->first, a = array; e; e = e->next)
627*a9fa9459Szrj     if (e->alignment)
628*a9fa9459Szrj       {
629*a9fa9459Szrj 	*a++ = e;
630*a9fa9459Szrj 	/* Adjust the length to not include the zero terminator.  */
631*a9fa9459Szrj 	e->len -= sinfo->htab->entsize;
632*a9fa9459Szrj 	if (alignment != e->alignment)
633*a9fa9459Szrj 	  {
634*a9fa9459Szrj 	    if (alignment == 0)
635*a9fa9459Szrj 	      alignment = e->alignment;
636*a9fa9459Szrj 	    else
637*a9fa9459Szrj 	      alignment = (unsigned) -1;
638*a9fa9459Szrj 	  }
639*a9fa9459Szrj       }
640*a9fa9459Szrj 
641*a9fa9459Szrj   sinfo->htab->size = a - array;
642*a9fa9459Szrj   if (sinfo->htab->size != 0)
643*a9fa9459Szrj     {
644*a9fa9459Szrj       qsort (array, (size_t) sinfo->htab->size,
645*a9fa9459Szrj 	     sizeof (struct sec_merge_hash_entry *),
646*a9fa9459Szrj 	     (alignment != (unsigned) -1 && alignment > sinfo->htab->entsize
647*a9fa9459Szrj 	      ? strrevcmp_align : strrevcmp));
648*a9fa9459Szrj 
649*a9fa9459Szrj       /* Loop over the sorted array and merge suffixes */
650*a9fa9459Szrj       e = *--a;
651*a9fa9459Szrj       e->len += sinfo->htab->entsize;
652*a9fa9459Szrj       while (--a >= array)
653*a9fa9459Szrj 	{
654*a9fa9459Szrj 	  struct sec_merge_hash_entry *cmp = *a;
655*a9fa9459Szrj 
656*a9fa9459Szrj 	  cmp->len += sinfo->htab->entsize;
657*a9fa9459Szrj 	  if (e->alignment >= cmp->alignment
658*a9fa9459Szrj 	      && !((e->len - cmp->len) & (cmp->alignment - 1))
659*a9fa9459Szrj 	      && is_suffix (e, cmp))
660*a9fa9459Szrj 	    {
661*a9fa9459Szrj 	      cmp->u.suffix = e;
662*a9fa9459Szrj 	      cmp->alignment = 0;
663*a9fa9459Szrj 	    }
664*a9fa9459Szrj 	  else
665*a9fa9459Szrj 	    e = cmp;
666*a9fa9459Szrj 	}
667*a9fa9459Szrj     }
668*a9fa9459Szrj 
669*a9fa9459Szrj alloc_failure:
670*a9fa9459Szrj   if (array)
671*a9fa9459Szrj     free (array);
672*a9fa9459Szrj 
673*a9fa9459Szrj   /* Now assign positions to the strings we want to keep.  */
674*a9fa9459Szrj   size = 0;
675*a9fa9459Szrj   secinfo = sinfo->htab->first->secinfo;
676*a9fa9459Szrj   for (e = sinfo->htab->first; e; e = e->next)
677*a9fa9459Szrj     {
678*a9fa9459Szrj       if (e->secinfo != secinfo)
679*a9fa9459Szrj 	{
680*a9fa9459Szrj 	  secinfo->sec->size = size;
681*a9fa9459Szrj 	  secinfo = e->secinfo;
682*a9fa9459Szrj 	}
683*a9fa9459Szrj       if (e->alignment)
684*a9fa9459Szrj 	{
685*a9fa9459Szrj 	  if (e->secinfo->first_str == NULL)
686*a9fa9459Szrj 	    {
687*a9fa9459Szrj 	      e->secinfo->first_str = e;
688*a9fa9459Szrj 	      size = 0;
689*a9fa9459Szrj 	    }
690*a9fa9459Szrj 	  size = (size + e->alignment - 1) & ~((bfd_vma) e->alignment - 1);
691*a9fa9459Szrj 	  e->u.index = size;
692*a9fa9459Szrj 	  size += e->len;
693*a9fa9459Szrj 	}
694*a9fa9459Szrj     }
695*a9fa9459Szrj   secinfo->sec->size = size;
696*a9fa9459Szrj   if (secinfo->sec->alignment_power != 0)
697*a9fa9459Szrj     {
698*a9fa9459Szrj       bfd_size_type align = (bfd_size_type) 1 << secinfo->sec->alignment_power;
699*a9fa9459Szrj       secinfo->sec->size = (secinfo->sec->size + align - 1) & -align;
700*a9fa9459Szrj     }
701*a9fa9459Szrj 
702*a9fa9459Szrj   /* And now adjust the rest, removing them from the chain (but not hashtable)
703*a9fa9459Szrj      at the same time.  */
704*a9fa9459Szrj   for (a = &sinfo->htab->first, e = *a; e; e = e->next)
705*a9fa9459Szrj     if (e->alignment)
706*a9fa9459Szrj       a = &e->next;
707*a9fa9459Szrj     else
708*a9fa9459Szrj       {
709*a9fa9459Szrj 	*a = e->next;
710*a9fa9459Szrj 	if (e->len)
711*a9fa9459Szrj 	  {
712*a9fa9459Szrj 	    e->secinfo = e->u.suffix->secinfo;
713*a9fa9459Szrj 	    e->alignment = e->u.suffix->alignment;
714*a9fa9459Szrj 	    e->u.index = e->u.suffix->u.index + (e->u.suffix->len - e->len);
715*a9fa9459Szrj 	  }
716*a9fa9459Szrj       }
717*a9fa9459Szrj }
718*a9fa9459Szrj 
719*a9fa9459Szrj /* This function is called once after all SEC_MERGE sections are registered
720*a9fa9459Szrj    with _bfd_merge_section.  */
721*a9fa9459Szrj 
722*a9fa9459Szrj bfd_boolean
_bfd_merge_sections(bfd * abfd,struct bfd_link_info * info ATTRIBUTE_UNUSED,void * xsinfo,void (* remove_hook)(bfd *,asection *))723*a9fa9459Szrj _bfd_merge_sections (bfd *abfd,
724*a9fa9459Szrj 		     struct bfd_link_info *info ATTRIBUTE_UNUSED,
725*a9fa9459Szrj 		     void *xsinfo,
726*a9fa9459Szrj 		     void (*remove_hook) (bfd *, asection *))
727*a9fa9459Szrj {
728*a9fa9459Szrj   struct sec_merge_info *sinfo;
729*a9fa9459Szrj 
730*a9fa9459Szrj   for (sinfo = (struct sec_merge_info *) xsinfo; sinfo; sinfo = sinfo->next)
731*a9fa9459Szrj     {
732*a9fa9459Szrj       struct sec_merge_sec_info * secinfo;
733*a9fa9459Szrj 
734*a9fa9459Szrj       if (! sinfo->chain)
735*a9fa9459Szrj 	continue;
736*a9fa9459Szrj 
737*a9fa9459Szrj       /* Move sinfo->chain to head of the chain, terminate it.  */
738*a9fa9459Szrj       secinfo = sinfo->chain;
739*a9fa9459Szrj       sinfo->chain = secinfo->next;
740*a9fa9459Szrj       secinfo->next = NULL;
741*a9fa9459Szrj 
742*a9fa9459Szrj       /* Record the sections into the hash table.  */
743*a9fa9459Szrj       for (secinfo = sinfo->chain; secinfo; secinfo = secinfo->next)
744*a9fa9459Szrj 	if (secinfo->sec->flags & SEC_EXCLUDE)
745*a9fa9459Szrj 	  {
746*a9fa9459Szrj 	    *secinfo->psecinfo = NULL;
747*a9fa9459Szrj 	    if (remove_hook)
748*a9fa9459Szrj 	      (*remove_hook) (abfd, secinfo->sec);
749*a9fa9459Szrj 	  }
750*a9fa9459Szrj 	else if (! record_section (sinfo, secinfo))
751*a9fa9459Szrj 	  break;
752*a9fa9459Szrj 
753*a9fa9459Szrj       if (secinfo)
754*a9fa9459Szrj 	continue;
755*a9fa9459Szrj 
756*a9fa9459Szrj       if (sinfo->htab->first == NULL)
757*a9fa9459Szrj 	continue;
758*a9fa9459Szrj 
759*a9fa9459Szrj       if (sinfo->htab->strings)
760*a9fa9459Szrj 	merge_strings (sinfo);
761*a9fa9459Szrj       else
762*a9fa9459Szrj 	{
763*a9fa9459Szrj 	  struct sec_merge_hash_entry *e;
764*a9fa9459Szrj 	  bfd_size_type size = 0;
765*a9fa9459Szrj 
766*a9fa9459Szrj 	  /* Things are much simpler for non-strings.
767*a9fa9459Szrj 	     Just assign them slots in the section.  */
768*a9fa9459Szrj 	  secinfo = NULL;
769*a9fa9459Szrj 	  for (e = sinfo->htab->first; e; e = e->next)
770*a9fa9459Szrj 	    {
771*a9fa9459Szrj 	      if (e->secinfo->first_str == NULL)
772*a9fa9459Szrj 		{
773*a9fa9459Szrj 		  if (secinfo)
774*a9fa9459Szrj 		    secinfo->sec->size = size;
775*a9fa9459Szrj 		  e->secinfo->first_str = e;
776*a9fa9459Szrj 		  size = 0;
777*a9fa9459Szrj 		}
778*a9fa9459Szrj 	      size = (size + e->alignment - 1)
779*a9fa9459Szrj 		     & ~((bfd_vma) e->alignment - 1);
780*a9fa9459Szrj 	      e->u.index = size;
781*a9fa9459Szrj 	      size += e->len;
782*a9fa9459Szrj 	      secinfo = e->secinfo;
783*a9fa9459Szrj 	    }
784*a9fa9459Szrj 	  secinfo->sec->size = size;
785*a9fa9459Szrj 	}
786*a9fa9459Szrj 
787*a9fa9459Szrj 	/* Finally remove all input sections which have not made it into
788*a9fa9459Szrj 	   the hash table at all.  */
789*a9fa9459Szrj 	for (secinfo = sinfo->chain; secinfo; secinfo = secinfo->next)
790*a9fa9459Szrj 	  if (secinfo->first_str == NULL)
791*a9fa9459Szrj 	    secinfo->sec->flags |= SEC_EXCLUDE | SEC_KEEP;
792*a9fa9459Szrj     }
793*a9fa9459Szrj 
794*a9fa9459Szrj   return TRUE;
795*a9fa9459Szrj }
796*a9fa9459Szrj 
797*a9fa9459Szrj /* Write out the merged section.  */
798*a9fa9459Szrj 
799*a9fa9459Szrj bfd_boolean
_bfd_write_merged_section(bfd * output_bfd,asection * sec,void * psecinfo)800*a9fa9459Szrj _bfd_write_merged_section (bfd *output_bfd, asection *sec, void *psecinfo)
801*a9fa9459Szrj {
802*a9fa9459Szrj   struct sec_merge_sec_info *secinfo;
803*a9fa9459Szrj   file_ptr pos;
804*a9fa9459Szrj   unsigned char *contents;
805*a9fa9459Szrj   Elf_Internal_Shdr *hdr;
806*a9fa9459Szrj 
807*a9fa9459Szrj   secinfo = (struct sec_merge_sec_info *) psecinfo;
808*a9fa9459Szrj 
809*a9fa9459Szrj   if (!secinfo)
810*a9fa9459Szrj     return FALSE;
811*a9fa9459Szrj 
812*a9fa9459Szrj   if (secinfo->first_str == NULL)
813*a9fa9459Szrj     return TRUE;
814*a9fa9459Szrj 
815*a9fa9459Szrj   /* FIXME: octets_per_byte.  */
816*a9fa9459Szrj   hdr = &elf_section_data (sec->output_section)->this_hdr;
817*a9fa9459Szrj   if (hdr->sh_offset == (file_ptr) -1)
818*a9fa9459Szrj     {
819*a9fa9459Szrj       /* We must compress this section.  Write output to the
820*a9fa9459Szrj 	 buffer.  */
821*a9fa9459Szrj       contents = hdr->contents;
822*a9fa9459Szrj       if ((sec->output_section->flags & SEC_ELF_COMPRESS) == 0
823*a9fa9459Szrj 	  || contents == NULL)
824*a9fa9459Szrj 	abort ();
825*a9fa9459Szrj     }
826*a9fa9459Szrj   else
827*a9fa9459Szrj     {
828*a9fa9459Szrj       contents = NULL;
829*a9fa9459Szrj       pos = sec->output_section->filepos + sec->output_offset;
830*a9fa9459Szrj       if (bfd_seek (output_bfd, pos, SEEK_SET) != 0)
831*a9fa9459Szrj 	return FALSE;
832*a9fa9459Szrj     }
833*a9fa9459Szrj 
834*a9fa9459Szrj   if (! sec_merge_emit (output_bfd, secinfo->first_str, contents,
835*a9fa9459Szrj 			sec->output_offset))
836*a9fa9459Szrj     return FALSE;
837*a9fa9459Szrj 
838*a9fa9459Szrj   return TRUE;
839*a9fa9459Szrj }
840*a9fa9459Szrj 
841*a9fa9459Szrj /* Adjust an address in the SEC_MERGE section.  Given OFFSET within
842*a9fa9459Szrj    *PSEC, this returns the new offset in the adjusted SEC_MERGE
843*a9fa9459Szrj    section and writes the new section back into *PSEC.  */
844*a9fa9459Szrj 
845*a9fa9459Szrj bfd_vma
_bfd_merged_section_offset(bfd * output_bfd ATTRIBUTE_UNUSED,asection ** psec,void * psecinfo,bfd_vma offset)846*a9fa9459Szrj _bfd_merged_section_offset (bfd *output_bfd ATTRIBUTE_UNUSED, asection **psec,
847*a9fa9459Szrj 			    void *psecinfo, bfd_vma offset)
848*a9fa9459Szrj {
849*a9fa9459Szrj   struct sec_merge_sec_info *secinfo;
850*a9fa9459Szrj   struct sec_merge_hash_entry *entry;
851*a9fa9459Szrj   unsigned char *p;
852*a9fa9459Szrj   asection *sec = *psec;
853*a9fa9459Szrj 
854*a9fa9459Szrj   secinfo = (struct sec_merge_sec_info *) psecinfo;
855*a9fa9459Szrj 
856*a9fa9459Szrj   if (!secinfo)
857*a9fa9459Szrj     return offset;
858*a9fa9459Szrj 
859*a9fa9459Szrj   if (offset >= sec->rawsize)
860*a9fa9459Szrj     {
861*a9fa9459Szrj       if (offset > sec->rawsize)
862*a9fa9459Szrj 	{
863*a9fa9459Szrj 	  (*_bfd_error_handler)
864*a9fa9459Szrj 	    (_("%s: access beyond end of merged section (%ld)"),
865*a9fa9459Szrj 	     bfd_get_filename (sec->owner), (long) offset);
866*a9fa9459Szrj 	}
867*a9fa9459Szrj       return secinfo->first_str ? sec->size : 0;
868*a9fa9459Szrj     }
869*a9fa9459Szrj 
870*a9fa9459Szrj   if (secinfo->htab->strings)
871*a9fa9459Szrj     {
872*a9fa9459Szrj       if (sec->entsize == 1)
873*a9fa9459Szrj 	{
874*a9fa9459Szrj 	  p = secinfo->contents + offset - 1;
875*a9fa9459Szrj 	  while (p >= secinfo->contents && *p)
876*a9fa9459Szrj 	    --p;
877*a9fa9459Szrj 	  ++p;
878*a9fa9459Szrj 	}
879*a9fa9459Szrj       else
880*a9fa9459Szrj 	{
881*a9fa9459Szrj 	  p = secinfo->contents + (offset / sec->entsize) * sec->entsize;
882*a9fa9459Szrj 	  p -= sec->entsize;
883*a9fa9459Szrj 	  while (p >= secinfo->contents)
884*a9fa9459Szrj 	    {
885*a9fa9459Szrj 	      unsigned int i;
886*a9fa9459Szrj 
887*a9fa9459Szrj 	      for (i = 0; i < sec->entsize; ++i)
888*a9fa9459Szrj 		if (p[i] != '\0')
889*a9fa9459Szrj 		  break;
890*a9fa9459Szrj 	      if (i == sec->entsize)
891*a9fa9459Szrj 		break;
892*a9fa9459Szrj 	      p -= sec->entsize;
893*a9fa9459Szrj 	    }
894*a9fa9459Szrj 	  p += sec->entsize;
895*a9fa9459Szrj 	}
896*a9fa9459Szrj     }
897*a9fa9459Szrj   else
898*a9fa9459Szrj     {
899*a9fa9459Szrj       p = secinfo->contents + (offset / sec->entsize) * sec->entsize;
900*a9fa9459Szrj     }
901*a9fa9459Szrj   entry = sec_merge_hash_lookup (secinfo->htab, (char *) p, 0, FALSE);
902*a9fa9459Szrj   if (!entry)
903*a9fa9459Szrj     {
904*a9fa9459Szrj       if (! secinfo->htab->strings)
905*a9fa9459Szrj 	abort ();
906*a9fa9459Szrj       /* This should only happen if somebody points into the padding
907*a9fa9459Szrj 	 after a NUL character but before next entity.  */
908*a9fa9459Szrj       if (*p)
909*a9fa9459Szrj 	abort ();
910*a9fa9459Szrj       if (! secinfo->htab->first)
911*a9fa9459Szrj 	abort ();
912*a9fa9459Szrj       entry = secinfo->htab->first;
913*a9fa9459Szrj       p = (secinfo->contents + (offset / sec->entsize + 1) * sec->entsize
914*a9fa9459Szrj 	   - entry->len);
915*a9fa9459Szrj     }
916*a9fa9459Szrj 
917*a9fa9459Szrj   *psec = entry->secinfo->sec;
918*a9fa9459Szrj   return entry->u.index + (secinfo->contents + offset - p);
919*a9fa9459Szrj }
920*a9fa9459Szrj 
921*a9fa9459Szrj /* Tidy up when done.  */
922*a9fa9459Szrj 
923*a9fa9459Szrj void
_bfd_merge_sections_free(void * xsinfo)924*a9fa9459Szrj _bfd_merge_sections_free (void *xsinfo)
925*a9fa9459Szrj {
926*a9fa9459Szrj   struct sec_merge_info *sinfo;
927*a9fa9459Szrj 
928*a9fa9459Szrj   for (sinfo = (struct sec_merge_info *) xsinfo; sinfo; sinfo = sinfo->next)
929*a9fa9459Szrj     {
930*a9fa9459Szrj       bfd_hash_table_free (&sinfo->htab->table);
931*a9fa9459Szrj       free (sinfo->htab);
932*a9fa9459Szrj     }
933*a9fa9459Szrj }
934