*** empty log message ***
[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
02be4619
AM
204unsigned int
205_bfd_elf_strtab_refcount (struct elf_strtab_hash *tab, bfd_size_type idx)
206{
207 return tab->array[idx]->refcount;
208}
209
2b0f7ef9 210void
a4542f1b 211_bfd_elf_strtab_clear_refs (struct elf_strtab_hash *tab, bfd_size_type idx)
2b0f7ef9 212{
a4542f1b
AM
213 while (idx < tab->size)
214 tab->array[idx++]->refcount = 0;
2b0f7ef9
JJ
215}
216
217bfd_size_type
c39a58e6 218_bfd_elf_strtab_size (struct elf_strtab_hash *tab)
2b0f7ef9
JJ
219{
220 return tab->sec_size ? tab->sec_size : tab->size;
221}
222
223bfd_size_type
c39a58e6 224_bfd_elf_strtab_offset (struct elf_strtab_hash *tab, bfd_size_type idx)
2b0f7ef9
JJ
225{
226 struct elf_strtab_hash_entry *entry;
227
228 if (idx == 0)
229 return 0;
230 BFD_ASSERT (idx < tab->size);
231 BFD_ASSERT (tab->sec_size);
232 entry = tab->array[idx];
233 BFD_ASSERT (entry->refcount > 0);
234 entry->refcount--;
235 return tab->array[idx]->u.index;
236}
237
b34976b6 238bfd_boolean
c39a58e6 239_bfd_elf_strtab_emit (register bfd *abfd, struct elf_strtab_hash *tab)
2b0f7ef9
JJ
240{
241 bfd_size_type off = 1, i;
242
243 if (bfd_bwrite ("", 1, abfd) != 1)
b34976b6 244 return FALSE;
2b0f7ef9
JJ
245
246 for (i = 1; i < tab->size; ++i)
247 {
248 register const char *str;
ddb2b442 249 register unsigned int len;
2b0f7ef9 250
2b0f7ef9 251 BFD_ASSERT (tab->array[i]->refcount == 0);
ddb2b442
AM
252 len = tab->array[i]->len;
253 if ((int) len < 0)
2b0f7ef9
JJ
254 continue;
255
ddb2b442 256 str = tab->array[i]->root.string;
c39a58e6 257 if (bfd_bwrite (str, len, abfd) != len)
b34976b6 258 return FALSE;
2b0f7ef9
JJ
259
260 off += len;
261 }
262
263 BFD_ASSERT (off == tab->sec_size);
b34976b6 264 return TRUE;
2b0f7ef9
JJ
265}
266
ddb2b442 267/* Compare two elf_strtab_hash_entry structures. Called via qsort. */
2b0f7ef9
JJ
268
269static int
ddb2b442 270strrevcmp (const void *a, const void *b)
2b0f7ef9 271{
c39a58e6
AM
272 struct elf_strtab_hash_entry *A = *(struct elf_strtab_hash_entry **) a;
273 struct elf_strtab_hash_entry *B = *(struct elf_strtab_hash_entry **) b;
ddb2b442
AM
274 unsigned int lenA = A->len;
275 unsigned int lenB = B->len;
f075ee0c
AM
276 const unsigned char *s = (const unsigned char *) A->root.string + lenA - 1;
277 const unsigned char *t = (const unsigned char *) B->root.string + lenB - 1;
ddb2b442 278 int l = lenA < lenB ? lenA : lenB;
2b0f7ef9 279
ddb2b442
AM
280 while (l)
281 {
282 if (*s != *t)
283 return (int) *s - (int) *t;
284 s--;
285 t--;
286 l--;
287 }
288 return lenA - lenB;
2b0f7ef9
JJ
289}
290
ddb2b442
AM
291static inline int
292is_suffix (const struct elf_strtab_hash_entry *A,
293 const struct elf_strtab_hash_entry *B)
2b0f7ef9 294{
2b0f7ef9
JJ
295 if (A->len <= B->len)
296 /* B cannot be a suffix of A unless A is equal to B, which is guaranteed
297 not to be equal by the hash table. */
298 return 0;
299
300 return memcmp (A->root.string + (A->len - B->len),
ddb2b442 301 B->root.string, B->len - 1) == 0;
2b0f7ef9
JJ
302}
303
2b0f7ef9
JJ
304/* This function assigns final string table offsets for used strings,
305 merging strings matching suffixes of longer strings if possible. */
306
307void
c39a58e6 308_bfd_elf_strtab_finalize (struct elf_strtab_hash *tab)
2b0f7ef9 309{
ddb2b442 310 struct elf_strtab_hash_entry **array, **a, *e;
b959dc73
HPN
311 bfd_size_type size, amt;
312
313 /* GCC 2.91.66 (egcs-1.1.2) on i386 miscompiles this function when i is
314 a 64-bit bfd_size_type: a 64-bit target or --enable-64-bit-bfd.
315 Besides, indexing with a long long wouldn't give anything but extra
316 cycles. */
317 size_t i;
2b0f7ef9 318
ddb2b442 319 /* Sort the strings by suffix and length. */
2b0f7ef9 320 amt = tab->size * sizeof (struct elf_strtab_hash_entry *);
a50b1753 321 array = (struct elf_strtab_hash_entry **) bfd_malloc (amt);
2b0f7ef9
JJ
322 if (array == NULL)
323 goto alloc_failure;
324
325 for (i = 1, a = array; i < tab->size; ++i)
ddb2b442
AM
326 {
327 e = tab->array[i];
328 if (e->refcount)
329 {
330 *a++ = e;
331 /* Adjust the length to not include the zero terminator. */
332 e->len -= 1;
333 }
334 else
335 e->len = 0;
336 }
2b0f7ef9
JJ
337
338 size = a - array;
ddb2b442
AM
339 if (size != 0)
340 {
341 qsort (array, size, sizeof (struct elf_strtab_hash_entry *), strrevcmp);
2b0f7ef9 342
ddb2b442
AM
343 /* Loop over the sorted array and merge suffixes. Start from the
344 end because we want eg.
2b0f7ef9 345
ddb2b442
AM
346 s1 -> "d"
347 s2 -> "bcd"
348 s3 -> "abcd"
2b0f7ef9 349
ddb2b442 350 to end up as
2b0f7ef9 351
ddb2b442
AM
352 s3 -> "abcd"
353 s2 _____^
354 s1 _______^
2b0f7ef9 355
ddb2b442
AM
356 ie. we don't want s1 pointing into the old s2. */
357 e = *--a;
358 e->len += 1;
359 while (--a >= array)
360 {
361 struct elf_strtab_hash_entry *cmp = *a;
53c3f2be 362
ddb2b442
AM
363 cmp->len += 1;
364 if (is_suffix (e, cmp))
53c3f2be 365 {
ddb2b442
AM
366 cmp->u.suffix = e;
367 cmp->len = -cmp->len;
53c3f2be 368 }
ddb2b442
AM
369 else
370 e = cmp;
2b0f7ef9 371 }
2b0f7ef9
JJ
372 }
373
374alloc_failure:
375 if (array)
376 free (array);
2b0f7ef9 377
ddb2b442 378 /* Assign positions to the strings we want to keep. */
2b0f7ef9
JJ
379 size = 1;
380 for (i = 1; i < tab->size; ++i)
381 {
382 e = tab->array[i];
ddb2b442 383 if (e->refcount && e->len > 0)
2b0f7ef9
JJ
384 {
385 e->u.index = size;
386 size += e->len;
387 }
388 }
389
390 tab->sec_size = size;
391
ddb2b442 392 /* Adjust the rest. */
2b0f7ef9
JJ
393 for (i = 1; i < tab->size; ++i)
394 {
395 e = tab->array[i];
ddb2b442
AM
396 if (e->refcount && e->len < 0)
397 e->u.index = e->u.suffix->u.index + (e->u.suffix->len + e->len);
2b0f7ef9
JJ
398 }
399}
This page took 0.550265 seconds and 4 git commands to generate.