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