PR ld/12549
[deliverable/binutils-gdb.git] / bfd / elf-strtab.c
CommitLineData
2b0f7ef9 1/* ELF strtab with GC and suffix merging support.
515ef31d 2 Copyright 2001, 2002, 2003, 2005, 2006, 2007, 2008
3db64b00 3 Free Software Foundation, Inc.
2b0f7ef9
JJ
4 Written by Jakub Jelinek <jakub@redhat.com>.
5
7217313c 6 This file is part of BFD, the Binary File Descriptor library.
2b0f7ef9 7
7217313c
NC
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
cd123cb7 10 the Free Software Foundation; either version 3 of the License, or
7217313c 11 (at your option) any later version.
2b0f7ef9 12
7217313c
NC
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
2b0f7ef9 17
7217313c
NC
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
cd123cb7
NC
20 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
21 MA 02110-1301, USA. */
2b0f7ef9 22
2b0f7ef9 23#include "sysdep.h"
3db64b00 24#include "bfd.h"
2b0f7ef9
JJ
25#include "libbfd.h"
26#include "elf-bfd.h"
27#include "hashtab.h"
7217313c 28#include "libiberty.h"
2b0f7ef9
JJ
29
30/* An entry in the strtab hash table. */
31
32struct elf_strtab_hash_entry
33{
34 struct bfd_hash_entry root;
ddb2b442
AM
35 /* Length of this entry. This includes the zero terminator. */
36 int len;
2b0f7ef9
JJ
37 unsigned int refcount;
38 union {
39 /* Index within the merged section. */
40 bfd_size_type index;
ddb2b442 41 /* Entry this is a suffix of (if len < 0). */
2b0f7ef9
JJ
42 struct elf_strtab_hash_entry *suffix;
43 } u;
44};
45
46/* The strtab hash table. */
47
48struct elf_strtab_hash
49{
50 struct bfd_hash_table table;
51 /* Next available index. */
52 bfd_size_type size;
53 /* Number of array entries alloced. */
54 bfd_size_type alloced;
55 /* Final strtab size. */
56 bfd_size_type sec_size;
57 /* Array of pointers to strtab entries. */
58 struct elf_strtab_hash_entry **array;
59};
60
2b0f7ef9
JJ
61/* Routine to create an entry in a section merge hashtab. */
62
63static struct bfd_hash_entry *
c39a58e6
AM
64elf_strtab_hash_newfunc (struct bfd_hash_entry *entry,
65 struct bfd_hash_table *table,
66 const char *string)
2b0f7ef9 67{
2b0f7ef9
JJ
68 /* Allocate the structure if it has not already been allocated by a
69 subclass. */
c39a58e6 70 if (entry == NULL)
a50b1753
NC
71 entry = (struct bfd_hash_entry *)
72 bfd_hash_allocate (table, sizeof (struct elf_strtab_hash_entry));
c39a58e6 73 if (entry == NULL)
2b0f7ef9
JJ
74 return NULL;
75
76 /* Call the allocation method of the superclass. */
c39a58e6 77 entry = bfd_hash_newfunc (entry, table, string);
2b0f7ef9 78
c39a58e6 79 if (entry)
2b0f7ef9
JJ
80 {
81 /* Initialize the local fields. */
c39a58e6
AM
82 struct elf_strtab_hash_entry *ret;
83
84 ret = (struct elf_strtab_hash_entry *) entry;
2b0f7ef9
JJ
85 ret->u.index = -1;
86 ret->refcount = 0;
87 ret->len = 0;
88 }
89
c39a58e6 90 return entry;
2b0f7ef9
JJ
91}
92
93/* Create a new hash table. */
94
95struct elf_strtab_hash *
c39a58e6 96_bfd_elf_strtab_init (void)
2b0f7ef9
JJ
97{
98 struct elf_strtab_hash *table;
99 bfd_size_type amt = sizeof (struct elf_strtab_hash);
100
a50b1753 101 table = (struct elf_strtab_hash *) bfd_malloc (amt);
2b0f7ef9
JJ
102 if (table == NULL)
103 return NULL;
104
66eb6687
AM
105 if (!bfd_hash_table_init (&table->table, elf_strtab_hash_newfunc,
106 sizeof (struct elf_strtab_hash_entry)))
2b0f7ef9
JJ
107 {
108 free (table);
109 return NULL;
110 }
111
112 table->sec_size = 0;
113 table->size = 1;
114 table->alloced = 64;
115 amt = sizeof (struct elf_strtab_hasn_entry *);
a50b1753
NC
116 table->array = (struct elf_strtab_hash_entry **)
117 bfd_malloc (table->alloced * amt);
2b0f7ef9
JJ
118 if (table->array == NULL)
119 {
120 free (table);
121 return NULL;
122 }
123
124 table->array[0] = NULL;
125
126 return table;
127}
128
129/* Free a strtab. */
130
131void
c39a58e6 132_bfd_elf_strtab_free (struct elf_strtab_hash *tab)
2b0f7ef9
JJ
133{
134 bfd_hash_table_free (&tab->table);
135 free (tab->array);
136 free (tab);
137}
138
139/* Get the index of an entity in a hash table, adding it if it is not
140 already present. */
141
142bfd_size_type
c39a58e6
AM
143_bfd_elf_strtab_add (struct elf_strtab_hash *tab,
144 const char *str,
145 bfd_boolean copy)
2b0f7ef9
JJ
146{
147 register struct elf_strtab_hash_entry *entry;
148
149 /* We handle this specially, since we don't want to do refcounting
150 on it. */
151 if (*str == '\0')
152 return 0;
153
154 BFD_ASSERT (tab->sec_size == 0);
155 entry = (struct elf_strtab_hash_entry *)
b34976b6 156 bfd_hash_lookup (&tab->table, str, TRUE, copy);
2b0f7ef9
JJ
157
158 if (entry == NULL)
159 return (bfd_size_type) -1;
160
161 entry->refcount++;
162 if (entry->len == 0)
163 {
164 entry->len = strlen (str) + 1;
ddb2b442
AM
165 /* 2G strings lose. */
166 BFD_ASSERT (entry->len > 0);
2b0f7ef9
JJ
167 if (tab->size == tab->alloced)
168 {
169 bfd_size_type amt = sizeof (struct elf_strtab_hash_entry *);
170 tab->alloced *= 2;
a50b1753
NC
171 tab->array = (struct elf_strtab_hash_entry **)
172 bfd_realloc_or_free (tab->array, tab->alloced * amt);
2b0f7ef9
JJ
173 if (tab->array == NULL)
174 return (bfd_size_type) -1;
175 }
176
177 entry->u.index = tab->size++;
178 tab->array[entry->u.index] = entry;
179 }
180 return entry->u.index;
181}
182
183void
c39a58e6 184_bfd_elf_strtab_addref (struct elf_strtab_hash *tab, bfd_size_type idx)
2b0f7ef9
JJ
185{
186 if (idx == 0 || idx == (bfd_size_type) -1)
187 return;
188 BFD_ASSERT (tab->sec_size == 0);
189 BFD_ASSERT (idx < tab->size);
190 ++tab->array[idx]->refcount;
191}
192
193void
c39a58e6 194_bfd_elf_strtab_delref (struct elf_strtab_hash *tab, bfd_size_type idx)
2b0f7ef9
JJ
195{
196 if (idx == 0 || idx == (bfd_size_type) -1)
197 return;
198 BFD_ASSERT (tab->sec_size == 0);
199 BFD_ASSERT (idx < tab->size);
200 BFD_ASSERT (tab->array[idx]->refcount > 0);
201 --tab->array[idx]->refcount;
202}
203
204void
a4542f1b 205_bfd_elf_strtab_clear_refs (struct elf_strtab_hash *tab, bfd_size_type idx)
2b0f7ef9 206{
a4542f1b
AM
207 while (idx < tab->size)
208 tab->array[idx++]->refcount = 0;
2b0f7ef9
JJ
209}
210
211bfd_size_type
c39a58e6 212_bfd_elf_strtab_size (struct elf_strtab_hash *tab)
2b0f7ef9
JJ
213{
214 return tab->sec_size ? tab->sec_size : tab->size;
215}
216
217bfd_size_type
c39a58e6 218_bfd_elf_strtab_offset (struct elf_strtab_hash *tab, bfd_size_type idx)
2b0f7ef9
JJ
219{
220 struct elf_strtab_hash_entry *entry;
221
222 if (idx == 0)
223 return 0;
224 BFD_ASSERT (idx < tab->size);
225 BFD_ASSERT (tab->sec_size);
226 entry = tab->array[idx];
227 BFD_ASSERT (entry->refcount > 0);
228 entry->refcount--;
229 return tab->array[idx]->u.index;
230}
231
b34976b6 232bfd_boolean
c39a58e6 233_bfd_elf_strtab_emit (register bfd *abfd, struct elf_strtab_hash *tab)
2b0f7ef9
JJ
234{
235 bfd_size_type off = 1, i;
236
237 if (bfd_bwrite ("", 1, abfd) != 1)
b34976b6 238 return FALSE;
2b0f7ef9
JJ
239
240 for (i = 1; i < tab->size; ++i)
241 {
242 register const char *str;
ddb2b442 243 register unsigned int len;
2b0f7ef9 244
2b0f7ef9 245 BFD_ASSERT (tab->array[i]->refcount == 0);
ddb2b442
AM
246 len = tab->array[i]->len;
247 if ((int) len < 0)
2b0f7ef9
JJ
248 continue;
249
ddb2b442 250 str = tab->array[i]->root.string;
c39a58e6 251 if (bfd_bwrite (str, len, abfd) != len)
b34976b6 252 return FALSE;
2b0f7ef9
JJ
253
254 off += len;
255 }
256
257 BFD_ASSERT (off == tab->sec_size);
b34976b6 258 return TRUE;
2b0f7ef9
JJ
259}
260
ddb2b442 261/* Compare two elf_strtab_hash_entry structures. Called via qsort. */
2b0f7ef9
JJ
262
263static int
ddb2b442 264strrevcmp (const void *a, const void *b)
2b0f7ef9 265{
c39a58e6
AM
266 struct elf_strtab_hash_entry *A = *(struct elf_strtab_hash_entry **) a;
267 struct elf_strtab_hash_entry *B = *(struct elf_strtab_hash_entry **) b;
ddb2b442
AM
268 unsigned int lenA = A->len;
269 unsigned int lenB = B->len;
f075ee0c
AM
270 const unsigned char *s = (const unsigned char *) A->root.string + lenA - 1;
271 const unsigned char *t = (const unsigned char *) B->root.string + lenB - 1;
ddb2b442 272 int l = lenA < lenB ? lenA : lenB;
2b0f7ef9 273
ddb2b442
AM
274 while (l)
275 {
276 if (*s != *t)
277 return (int) *s - (int) *t;
278 s--;
279 t--;
280 l--;
281 }
282 return lenA - lenB;
2b0f7ef9
JJ
283}
284
ddb2b442
AM
285static inline int
286is_suffix (const struct elf_strtab_hash_entry *A,
287 const struct elf_strtab_hash_entry *B)
2b0f7ef9 288{
2b0f7ef9
JJ
289 if (A->len <= B->len)
290 /* B cannot be a suffix of A unless A is equal to B, which is guaranteed
291 not to be equal by the hash table. */
292 return 0;
293
294 return memcmp (A->root.string + (A->len - B->len),
ddb2b442 295 B->root.string, B->len - 1) == 0;
2b0f7ef9
JJ
296}
297
2b0f7ef9
JJ
298/* This function assigns final string table offsets for used strings,
299 merging strings matching suffixes of longer strings if possible. */
300
301void
c39a58e6 302_bfd_elf_strtab_finalize (struct elf_strtab_hash *tab)
2b0f7ef9 303{
ddb2b442 304 struct elf_strtab_hash_entry **array, **a, *e;
b959dc73
HPN
305 bfd_size_type size, amt;
306
307 /* GCC 2.91.66 (egcs-1.1.2) on i386 miscompiles this function when i is
308 a 64-bit bfd_size_type: a 64-bit target or --enable-64-bit-bfd.
309 Besides, indexing with a long long wouldn't give anything but extra
310 cycles. */
311 size_t i;
2b0f7ef9 312
ddb2b442 313 /* Sort the strings by suffix and length. */
2b0f7ef9 314 amt = tab->size * sizeof (struct elf_strtab_hash_entry *);
a50b1753 315 array = (struct elf_strtab_hash_entry **) bfd_malloc (amt);
2b0f7ef9
JJ
316 if (array == NULL)
317 goto alloc_failure;
318
319 for (i = 1, a = array; i < tab->size; ++i)
ddb2b442
AM
320 {
321 e = tab->array[i];
322 if (e->refcount)
323 {
324 *a++ = e;
325 /* Adjust the length to not include the zero terminator. */
326 e->len -= 1;
327 }
328 else
329 e->len = 0;
330 }
2b0f7ef9
JJ
331
332 size = a - array;
ddb2b442
AM
333 if (size != 0)
334 {
335 qsort (array, size, sizeof (struct elf_strtab_hash_entry *), strrevcmp);
2b0f7ef9 336
ddb2b442
AM
337 /* Loop over the sorted array and merge suffixes. Start from the
338 end because we want eg.
2b0f7ef9 339
ddb2b442
AM
340 s1 -> "d"
341 s2 -> "bcd"
342 s3 -> "abcd"
2b0f7ef9 343
ddb2b442 344 to end up as
2b0f7ef9 345
ddb2b442
AM
346 s3 -> "abcd"
347 s2 _____^
348 s1 _______^
2b0f7ef9 349
ddb2b442
AM
350 ie. we don't want s1 pointing into the old s2. */
351 e = *--a;
352 e->len += 1;
353 while (--a >= array)
354 {
355 struct elf_strtab_hash_entry *cmp = *a;
53c3f2be 356
ddb2b442
AM
357 cmp->len += 1;
358 if (is_suffix (e, cmp))
53c3f2be 359 {
ddb2b442
AM
360 cmp->u.suffix = e;
361 cmp->len = -cmp->len;
53c3f2be 362 }
ddb2b442
AM
363 else
364 e = cmp;
2b0f7ef9 365 }
2b0f7ef9
JJ
366 }
367
368alloc_failure:
369 if (array)
370 free (array);
2b0f7ef9 371
ddb2b442 372 /* Assign positions to the strings we want to keep. */
2b0f7ef9
JJ
373 size = 1;
374 for (i = 1; i < tab->size; ++i)
375 {
376 e = tab->array[i];
ddb2b442 377 if (e->refcount && e->len > 0)
2b0f7ef9
JJ
378 {
379 e->u.index = size;
380 size += e->len;
381 }
382 }
383
384 tab->sec_size = size;
385
ddb2b442 386 /* Adjust the rest. */
2b0f7ef9
JJ
387 for (i = 1; i < tab->size; ++i)
388 {
389 e = tab->array[i];
ddb2b442
AM
390 if (e->refcount && e->len < 0)
391 e->u.index = e->u.suffix->u.index + (e->u.suffix->len + e->len);
2b0f7ef9
JJ
392 }
393}
This page took 0.666981 seconds and 4 git commands to generate.