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