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