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