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