00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #include "bfd.h"
00029 #include "sysdep.h"
00030 #include "libbfd.h"
00031 #include "hashtab.h"
00032 #include "libiberty.h"
00033
00034 struct sec_merge_sec_info;
00035
00036
00037
00038 struct sec_merge_hash_entry
00039 {
00040 struct bfd_hash_entry root;
00041
00042 unsigned int len;
00043
00044
00045 unsigned int alignment;
00046 union
00047 {
00048
00049 bfd_size_type index;
00050
00051 struct sec_merge_hash_entry *suffix;
00052 } u;
00053
00054 struct sec_merge_sec_info *secinfo;
00055
00056 struct sec_merge_hash_entry *next;
00057 };
00058
00059
00060
00061 struct sec_merge_hash
00062 {
00063 struct bfd_hash_table table;
00064
00065 bfd_size_type size;
00066
00067 struct sec_merge_hash_entry *first;
00068
00069 struct sec_merge_hash_entry *last;
00070
00071 unsigned int entsize;
00072
00073 bfd_boolean strings;
00074 };
00075
00076 struct sec_merge_info
00077 {
00078
00079 struct sec_merge_info *next;
00080
00081 struct sec_merge_sec_info *chain;
00082
00083 struct sec_merge_hash *htab;
00084 };
00085
00086 struct sec_merge_sec_info
00087 {
00088
00089 struct sec_merge_sec_info *next;
00090
00091 asection *sec;
00092
00093 void **psecinfo;
00094
00095 struct sec_merge_hash *htab;
00096
00097 struct sec_merge_hash_entry *first_str;
00098
00099 unsigned char contents[1];
00100 };
00101
00102
00103
00104
00105 static struct bfd_hash_entry *
00106 sec_merge_hash_newfunc (struct bfd_hash_entry *entry,
00107 struct bfd_hash_table *table, const char *string)
00108 {
00109
00110
00111 if (entry == NULL)
00112 entry = bfd_hash_allocate (table, sizeof (struct sec_merge_hash_entry));
00113 if (entry == NULL)
00114 return NULL;
00115
00116
00117 entry = bfd_hash_newfunc (entry, table, string);
00118
00119 if (entry != NULL)
00120 {
00121
00122 struct sec_merge_hash_entry *ret = (struct sec_merge_hash_entry *) entry;
00123
00124 ret->u.suffix = NULL;
00125 ret->alignment = 0;
00126 ret->secinfo = NULL;
00127 ret->next = NULL;
00128 }
00129
00130 return entry;
00131 }
00132
00133
00134
00135 static struct sec_merge_hash_entry *
00136 sec_merge_hash_lookup (struct sec_merge_hash *table, const char *string,
00137 unsigned int alignment, bfd_boolean create)
00138 {
00139 register const unsigned char *s;
00140 register unsigned long hash;
00141 register unsigned int c;
00142 struct sec_merge_hash_entry *hashp;
00143 unsigned int len, i;
00144 unsigned int index;
00145
00146 hash = 0;
00147 len = 0;
00148 s = (const unsigned char *) string;
00149 if (table->strings)
00150 {
00151 if (table->entsize == 1)
00152 {
00153 while ((c = *s++) != '\0')
00154 {
00155 hash += c + (c << 17);
00156 hash ^= hash >> 2;
00157 ++len;
00158 }
00159 hash += len + (len << 17);
00160 }
00161 else
00162 {
00163 for (;;)
00164 {
00165 for (i = 0; i < table->entsize; ++i)
00166 if (s[i] != '\0')
00167 break;
00168 if (i == table->entsize)
00169 break;
00170 for (i = 0; i < table->entsize; ++i)
00171 {
00172 c = *s++;
00173 hash += c + (c << 17);
00174 hash ^= hash >> 2;
00175 }
00176 ++len;
00177 }
00178 hash += len + (len << 17);
00179 len *= table->entsize;
00180 }
00181 hash ^= hash >> 2;
00182 len += table->entsize;
00183 }
00184 else
00185 {
00186 for (i = 0; i < table->entsize; ++i)
00187 {
00188 c = *s++;
00189 hash += c + (c << 17);
00190 hash ^= hash >> 2;
00191 }
00192 len = table->entsize;
00193 }
00194
00195 index = hash % table->table.size;
00196 for (hashp = (struct sec_merge_hash_entry *) table->table.table[index];
00197 hashp != NULL;
00198 hashp = (struct sec_merge_hash_entry *) hashp->root.next)
00199 {
00200 if (hashp->root.hash == hash
00201 && len == hashp->len
00202 && memcmp (hashp->root.string, string, len) == 0)
00203 {
00204
00205
00206 if (hashp->alignment < alignment)
00207 {
00208 if (create)
00209 {
00210
00211 hashp->len = 0;
00212 hashp->alignment = 0;
00213 }
00214 break;
00215 }
00216 return hashp;
00217 }
00218 }
00219
00220 if (! create)
00221 return NULL;
00222
00223 hashp = ((struct sec_merge_hash_entry *)
00224 sec_merge_hash_newfunc (NULL, &table->table, string));
00225 if (hashp == NULL)
00226 return NULL;
00227 hashp->root.string = string;
00228 hashp->root.hash = hash;
00229 hashp->len = len;
00230 hashp->alignment = alignment;
00231 hashp->root.next = table->table.table[index];
00232 table->table.table[index] = (struct bfd_hash_entry *) hashp;
00233
00234 return hashp;
00235 }
00236
00237
00238
00239 static struct sec_merge_hash *
00240 sec_merge_init (unsigned int entsize, bfd_boolean strings)
00241 {
00242 struct sec_merge_hash *table;
00243
00244 table = bfd_malloc (sizeof (struct sec_merge_hash));
00245 if (table == NULL)
00246 return NULL;
00247
00248 if (! bfd_hash_table_init (&table->table, sec_merge_hash_newfunc))
00249 {
00250 free (table);
00251 return NULL;
00252 }
00253
00254 table->size = 0;
00255 table->first = NULL;
00256 table->last = NULL;
00257 table->entsize = entsize;
00258 table->strings = strings;
00259
00260 return table;
00261 }
00262
00263
00264
00265
00266 static struct sec_merge_hash_entry *
00267 sec_merge_add (struct sec_merge_hash *tab, const char *str,
00268 unsigned int alignment, struct sec_merge_sec_info *secinfo)
00269 {
00270 register struct sec_merge_hash_entry *entry;
00271
00272 entry = sec_merge_hash_lookup (tab, str, alignment, TRUE);
00273 if (entry == NULL)
00274 return NULL;
00275
00276 if (entry->secinfo == NULL)
00277 {
00278 tab->size++;
00279 entry->secinfo = secinfo;
00280 if (tab->first == NULL)
00281 tab->first = entry;
00282 else
00283 tab->last->next = entry;
00284 tab->last = entry;
00285 }
00286
00287 return entry;
00288 }
00289
00290 static bfd_boolean
00291 sec_merge_emit (bfd *abfd, struct sec_merge_hash_entry *entry)
00292 {
00293 struct sec_merge_sec_info *secinfo = entry->secinfo;
00294 asection *sec = secinfo->sec;
00295 char *pad = "";
00296 bfd_size_type off = 0;
00297 int alignment_power = sec->output_section->alignment_power;
00298
00299 if (alignment_power)
00300 pad = bfd_zmalloc ((bfd_size_type) 1 << alignment_power);
00301
00302 for (; entry != NULL && entry->secinfo == secinfo; entry = entry->next)
00303 {
00304 register const char *str;
00305 register size_t len;
00306
00307 len = off & (entry->alignment - 1);
00308 if (len)
00309 {
00310 len = entry->alignment - len;
00311 if (bfd_bwrite (pad, len, abfd) != len)
00312 break;
00313 off += len;
00314 }
00315
00316 str = entry->root.string;
00317 len = entry->len;
00318
00319 if (bfd_bwrite (str, len, abfd) != len)
00320 break;
00321
00322 off += len;
00323 }
00324
00325 if (alignment_power)
00326 free (pad);
00327
00328 return entry == NULL || entry->secinfo != secinfo;
00329 }
00330
00331
00332
00333
00334 bfd_boolean
00335 _bfd_add_merge_section (bfd *abfd, void **psinfo, asection *sec,
00336 void **psecinfo)
00337 {
00338 struct sec_merge_info *sinfo;
00339 struct sec_merge_sec_info *secinfo;
00340 unsigned int align;
00341 bfd_size_type amt;
00342
00343 if ((abfd->flags & DYNAMIC) != 0
00344 || (sec->flags & SEC_MERGE) == 0)
00345 abort ();
00346
00347 if (sec->size == 0
00348 || (sec->flags & SEC_EXCLUDE) != 0
00349 || sec->entsize == 0)
00350 return TRUE;
00351
00352 if ((sec->flags & SEC_RELOC) != 0)
00353 {
00354
00355 return TRUE;
00356 }
00357
00358 align = sec->alignment_power;
00359 if ((sec->entsize < (unsigned) 1 << align
00360 && ((sec->entsize & (sec->entsize - 1))
00361 || !(sec->flags & SEC_STRINGS)))
00362 || (sec->entsize > (unsigned) 1 << align
00363 && (sec->entsize & (((unsigned) 1 << align) - 1))))
00364 {
00365
00366
00367
00368
00369
00370
00371 return TRUE;
00372 }
00373
00374 for (sinfo = (struct sec_merge_info *) *psinfo; sinfo; sinfo = sinfo->next)
00375 if ((secinfo = sinfo->chain)
00376 && ! ((secinfo->sec->flags ^ sec->flags) & (SEC_MERGE | SEC_STRINGS))
00377 && secinfo->sec->entsize == sec->entsize
00378 && secinfo->sec->alignment_power == sec->alignment_power
00379 && secinfo->sec->output_section == sec->output_section)
00380 break;
00381
00382 if (sinfo == NULL)
00383 {
00384
00385 sinfo = bfd_alloc (abfd, sizeof (struct sec_merge_info));
00386 if (sinfo == NULL)
00387 goto error_return;
00388 sinfo->next = (struct sec_merge_info *) *psinfo;
00389 sinfo->chain = NULL;
00390 *psinfo = sinfo;
00391 sinfo->htab = sec_merge_init (sec->entsize, (sec->flags & SEC_STRINGS));
00392 if (sinfo->htab == NULL)
00393 goto error_return;
00394 }
00395
00396
00397
00398 amt = sizeof (struct sec_merge_sec_info) + sec->size - 1;
00399 *psecinfo = bfd_alloc (abfd, amt);
00400 if (*psecinfo == NULL)
00401 goto error_return;
00402
00403 secinfo = (struct sec_merge_sec_info *) *psecinfo;
00404 if (sinfo->chain)
00405 {
00406 secinfo->next = sinfo->chain->next;
00407 sinfo->chain->next = secinfo;
00408 }
00409 else
00410 secinfo->next = secinfo;
00411 sinfo->chain = secinfo;
00412 secinfo->sec = sec;
00413 secinfo->psecinfo = psecinfo;
00414 secinfo->htab = sinfo->htab;
00415 secinfo->first_str = NULL;
00416
00417 sec->rawsize = sec->size;
00418 if (! bfd_get_section_contents (sec->owner, sec, secinfo->contents,
00419 0, sec->size))
00420 goto error_return;
00421
00422 return TRUE;
00423
00424 error_return:
00425 *psecinfo = NULL;
00426 return FALSE;
00427 }
00428
00429
00430 static bfd_boolean
00431 record_section (struct sec_merge_info *sinfo,
00432 struct sec_merge_sec_info *secinfo)
00433 {
00434 asection *sec = secinfo->sec;
00435 struct sec_merge_hash_entry *entry;
00436 bfd_boolean nul;
00437 unsigned char *p, *end;
00438 bfd_vma mask, eltalign;
00439 unsigned int align, i;
00440
00441 align = sec->alignment_power;
00442 end = secinfo->contents + sec->size;
00443 nul = FALSE;
00444 mask = ((bfd_vma) 1 << align) - 1;
00445 if (sec->flags & SEC_STRINGS)
00446 {
00447 for (p = secinfo->contents; p < end; )
00448 {
00449 eltalign = p - secinfo->contents;
00450 eltalign = ((eltalign ^ (eltalign - 1)) + 1) >> 1;
00451 if (!eltalign || eltalign > mask)
00452 eltalign = mask + 1;
00453 entry = sec_merge_add (sinfo->htab, (char *) p, (unsigned) eltalign,
00454 secinfo);
00455 if (! entry)
00456 goto error_return;
00457 p += entry->len;
00458 if (sec->entsize == 1)
00459 {
00460 while (p < end && *p == 0)
00461 {
00462 if (!nul && !((p - secinfo->contents) & mask))
00463 {
00464 nul = TRUE;
00465 entry = sec_merge_add (sinfo->htab, "",
00466 (unsigned) mask + 1, secinfo);
00467 if (! entry)
00468 goto error_return;
00469 }
00470 p++;
00471 }
00472 }
00473 else
00474 {
00475 while (p < end)
00476 {
00477 for (i = 0; i < sec->entsize; i++)
00478 if (p[i] != '\0')
00479 break;
00480 if (i != sec->entsize)
00481 break;
00482 if (!nul && !((p - secinfo->contents) & mask))
00483 {
00484 nul = TRUE;
00485 entry = sec_merge_add (sinfo->htab, (char *) p,
00486 (unsigned) mask + 1, secinfo);
00487 if (! entry)
00488 goto error_return;
00489 }
00490 p += sec->entsize;
00491 }
00492 }
00493 }
00494 }
00495 else
00496 {
00497 for (p = secinfo->contents; p < end; p += sec->entsize)
00498 {
00499 entry = sec_merge_add (sinfo->htab, (char *) p, 1, secinfo);
00500 if (! entry)
00501 goto error_return;
00502 }
00503 }
00504
00505 return TRUE;
00506
00507 error_return:
00508 for (secinfo = sinfo->chain; secinfo; secinfo = secinfo->next)
00509 *secinfo->psecinfo = NULL;
00510 return FALSE;
00511 }
00512
00513 static int
00514 strrevcmp (const void *a, const void *b)
00515 {
00516 struct sec_merge_hash_entry *A = *(struct sec_merge_hash_entry **) a;
00517 struct sec_merge_hash_entry *B = *(struct sec_merge_hash_entry **) b;
00518 unsigned int lenA = A->len;
00519 unsigned int lenB = B->len;
00520 const unsigned char *s = (const unsigned char *) A->root.string + lenA - 1;
00521 const unsigned char *t = (const unsigned char *) B->root.string + lenB - 1;
00522 int l = lenA < lenB ? lenA : lenB;
00523
00524 while (l)
00525 {
00526 if (*s != *t)
00527 return (int) *s - (int) *t;
00528 s--;
00529 t--;
00530 l--;
00531 }
00532 return lenA - lenB;
00533 }
00534
00535
00536
00537
00538 static int
00539 strrevcmp_align (const void *a, const void *b)
00540 {
00541 struct sec_merge_hash_entry *A = *(struct sec_merge_hash_entry **) a;
00542 struct sec_merge_hash_entry *B = *(struct sec_merge_hash_entry **) b;
00543 unsigned int lenA = A->len;
00544 unsigned int lenB = B->len;
00545 const unsigned char *s = (const unsigned char *) A->root.string + lenA - 1;
00546 const unsigned char *t = (const unsigned char *) B->root.string + lenB - 1;
00547 int l = lenA < lenB ? lenA : lenB;
00548 int tail_align = (lenA & (A->alignment - 1)) - (lenB & (A->alignment - 1));
00549
00550 if (tail_align != 0)
00551 return tail_align;
00552
00553 while (l)
00554 {
00555 if (*s != *t)
00556 return (int) *s - (int) *t;
00557 s--;
00558 t--;
00559 l--;
00560 }
00561 return lenA - lenB;
00562 }
00563
00564 static inline int
00565 is_suffix (const struct sec_merge_hash_entry *A,
00566 const struct sec_merge_hash_entry *B)
00567 {
00568 if (A->len <= B->len)
00569
00570
00571 return 0;
00572
00573 return memcmp (A->root.string + (A->len - B->len),
00574 B->root.string, B->len) == 0;
00575 }
00576
00577
00578
00579 static void
00580 merge_strings (struct sec_merge_info *sinfo)
00581 {
00582 struct sec_merge_hash_entry **array, **a, *e;
00583 struct sec_merge_sec_info *secinfo;
00584 bfd_size_type size, amt;
00585 unsigned int alignment = 0;
00586
00587
00588 amt = sinfo->htab->size * sizeof (struct sec_merge_hash_entry *);
00589 array = bfd_malloc (amt);
00590 if (array == NULL)
00591 goto alloc_failure;
00592
00593 for (e = sinfo->htab->first, a = array; e; e = e->next)
00594 if (e->alignment)
00595 {
00596 *a++ = e;
00597
00598 e->len -= sinfo->htab->entsize;
00599 if (alignment != e->alignment)
00600 {
00601 if (alignment == 0)
00602 alignment = e->alignment;
00603 else
00604 alignment = (unsigned) -1;
00605 }
00606 }
00607
00608 sinfo->htab->size = a - array;
00609 if (sinfo->htab->size != 0)
00610 {
00611 qsort (array, (size_t) sinfo->htab->size,
00612 sizeof (struct sec_merge_hash_entry *),
00613 (alignment != (unsigned) -1 && alignment > sinfo->htab->entsize
00614 ? strrevcmp_align : strrevcmp));
00615
00616
00617 e = *--a;
00618 e->len += sinfo->htab->entsize;
00619 while (--a >= array)
00620 {
00621 struct sec_merge_hash_entry *cmp = *a;
00622
00623 cmp->len += sinfo->htab->entsize;
00624 if (e->alignment >= cmp->alignment
00625 && !((e->len - cmp->len) & (cmp->alignment - 1))
00626 && is_suffix (e, cmp))
00627 {
00628 cmp->u.suffix = e;
00629 cmp->alignment = 0;
00630 }
00631 else
00632 e = cmp;
00633 }
00634 }
00635
00636 alloc_failure:
00637 if (array)
00638 free (array);
00639
00640
00641 size = 0;
00642 secinfo = sinfo->htab->first->secinfo;
00643 for (e = sinfo->htab->first; e; e = e->next)
00644 {
00645 if (e->secinfo != secinfo)
00646 {
00647 secinfo->sec->size = size;
00648 secinfo = e->secinfo;
00649 }
00650 if (e->alignment)
00651 {
00652 if (e->secinfo->first_str == NULL)
00653 {
00654 e->secinfo->first_str = e;
00655 size = 0;
00656 }
00657 size = (size + e->alignment - 1) & ~((bfd_vma) e->alignment - 1);
00658 e->u.index = size;
00659 size += e->len;
00660 }
00661 }
00662 secinfo->sec->size = size;
00663
00664
00665
00666 for (a = &sinfo->htab->first, e = *a; e; e = e->next)
00667 if (e->alignment)
00668 a = &e->next;
00669 else
00670 {
00671 *a = e->next;
00672 if (e->len)
00673 {
00674 e->secinfo = e->u.suffix->secinfo;
00675 e->alignment = e->u.suffix->alignment;
00676 e->u.index = e->u.suffix->u.index + (e->u.suffix->len - e->len);
00677 }
00678 }
00679 }
00680
00681
00682
00683
00684 bfd_boolean
00685 _bfd_merge_sections (bfd *abfd ATTRIBUTE_UNUSED, struct bfd_link_info *info,
00686 void *xsinfo, void (*remove_hook) (bfd *, asection *))
00687 {
00688 struct sec_merge_info *sinfo;
00689
00690 for (sinfo = (struct sec_merge_info *) xsinfo; sinfo; sinfo = sinfo->next)
00691 {
00692 struct sec_merge_sec_info * secinfo;
00693
00694 if (! sinfo->chain)
00695 continue;
00696
00697
00698 secinfo = sinfo->chain;
00699 sinfo->chain = secinfo->next;
00700 secinfo->next = NULL;
00701
00702
00703 for (secinfo = sinfo->chain; secinfo; secinfo = secinfo->next)
00704 if (secinfo->sec->flags & SEC_EXCLUDE)
00705 {
00706 *secinfo->psecinfo = NULL;
00707 if (remove_hook)
00708 (*remove_hook) (abfd, secinfo->sec);
00709 }
00710 else if (! record_section (sinfo, secinfo))
00711 break;
00712
00713 if (secinfo)
00714 continue;
00715
00716 if (sinfo->htab->first == NULL)
00717 continue;
00718
00719 if (sinfo->htab->strings)
00720 merge_strings (sinfo);
00721 else
00722 {
00723 struct sec_merge_hash_entry *e;
00724 bfd_size_type size = 0;
00725
00726
00727
00728 secinfo = NULL;
00729 for (e = sinfo->htab->first; e; e = e->next)
00730 {
00731 if (e->secinfo->first_str == NULL)
00732 {
00733 if (secinfo)
00734 secinfo->sec->size = size;
00735 e->secinfo->first_str = e;
00736 size = 0;
00737 }
00738 size = (size + e->alignment - 1)
00739 & ~((bfd_vma) e->alignment - 1);
00740 e->u.index = size;
00741 size += e->len;
00742 secinfo = e->secinfo;
00743 }
00744 secinfo->sec->size = size;
00745 }
00746
00747
00748
00749 for (secinfo = sinfo->chain; secinfo; secinfo = secinfo->next)
00750 if (secinfo->first_str == NULL)
00751 _bfd_strip_section_from_output (info, secinfo->sec);
00752 }
00753
00754 return TRUE;
00755 }
00756
00757
00758
00759 bfd_boolean
00760 _bfd_write_merged_section (bfd *output_bfd, asection *sec, void *psecinfo)
00761 {
00762 struct sec_merge_sec_info *secinfo;
00763 file_ptr pos;
00764
00765 secinfo = (struct sec_merge_sec_info *) psecinfo;
00766
00767 if (secinfo->first_str == NULL)
00768 return TRUE;
00769
00770 pos = sec->output_section->filepos + sec->output_offset;
00771 if (bfd_seek (output_bfd, pos, SEEK_SET) != 0)
00772 return FALSE;
00773
00774 if (! sec_merge_emit (output_bfd, secinfo->first_str))
00775 return FALSE;
00776
00777 return TRUE;
00778 }
00779
00780
00781
00782
00783
00784 bfd_vma
00785 _bfd_merged_section_offset (bfd *output_bfd ATTRIBUTE_UNUSED, asection **psec,
00786 void *psecinfo, bfd_vma offset)
00787 {
00788 struct sec_merge_sec_info *secinfo;
00789 struct sec_merge_hash_entry *entry;
00790 unsigned char *p;
00791 asection *sec = *psec;
00792
00793 secinfo = (struct sec_merge_sec_info *) psecinfo;
00794
00795 if (offset >= sec->rawsize)
00796 {
00797 if (offset > sec->rawsize)
00798 {
00799 (*_bfd_error_handler)
00800 (_("%s: access beyond end of merged section (%ld)"),
00801 bfd_get_filename (sec->owner), (long) offset);
00802 }
00803 return secinfo->first_str ? sec->size : 0;
00804 }
00805
00806 if (secinfo->htab->strings)
00807 {
00808 if (sec->entsize == 1)
00809 {
00810 p = secinfo->contents + offset - 1;
00811 while (p >= secinfo->contents && *p)
00812 --p;
00813 ++p;
00814 }
00815 else
00816 {
00817 p = secinfo->contents + (offset / sec->entsize) * sec->entsize;
00818 p -= sec->entsize;
00819 while (p >= secinfo->contents)
00820 {
00821 unsigned int i;
00822
00823 for (i = 0; i < sec->entsize; ++i)
00824 if (p[i] != '\0')
00825 break;
00826 if (i == sec->entsize)
00827 break;
00828 p -= sec->entsize;
00829 }
00830 p += sec->entsize;
00831 }
00832 }
00833 else
00834 {
00835 p = secinfo->contents + (offset / sec->entsize) * sec->entsize;
00836 }
00837 entry = sec_merge_hash_lookup (secinfo->htab, (char *) p, 0, FALSE);
00838 if (!entry)
00839 {
00840 if (! secinfo->htab->strings)
00841 abort ();
00842
00843
00844 if (*p)
00845 abort ();
00846 if (! secinfo->htab->first)
00847 abort ();
00848 entry = secinfo->htab->first;
00849 p = (secinfo->contents + (offset / sec->entsize + 1) * sec->entsize
00850 - entry->len);
00851 }
00852
00853 *psec = entry->secinfo->sec;
00854 return entry->u.index + (secinfo->contents + offset - p);
00855 }