/[gcl]/gcl/binutils/bfd/elf-strtab.c
ViewVC logotype

Diff of /gcl/binutils/bfd/elf-strtab.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.1.1.1 by camm, Fri Aug 9 05:35:55 2002 UTC revision 1.2 by camm, Fri Sep 9 23:32:08 2005 UTC
# Line 1  Line 1 
1  /* ELF strtab with GC and suffix merging support.  /* ELF strtab with GC and suffix merging support.
2     Copyright 2001, 2002 Free Software Foundation, Inc.     Copyright 2001, 2002, 2003, 2005 Free Software Foundation, Inc.
3     Written by Jakub Jelinek <jakub@redhat.com>.     Written by Jakub Jelinek <jakub@redhat.com>.
4    
5     This file is part of BFD, the Binary File Descriptor library.     This file is part of BFD, the Binary File Descriptor library.
# Line 30  Line 30 
30  struct elf_strtab_hash_entry  struct elf_strtab_hash_entry
31  {  {
32    struct bfd_hash_entry root;    struct bfd_hash_entry root;
33    /* Length of this entry.  */    /* Length of this entry.  This includes the zero terminator.  */
34    unsigned int len;    int len;
35    unsigned int refcount;    unsigned int refcount;
36    union {    union {
37      /* Index within the merged section.  */      /* Index within the merged section.  */
38      bfd_size_type index;      bfd_size_type index;
39      /* Entry this is a suffix of (if len is 0).  */      /* Entry this is a suffix of (if len < 0).  */
40      struct elf_strtab_hash_entry *suffix;      struct elf_strtab_hash_entry *suffix;
     struct elf_strtab_hash_entry *next;  
41    } u;    } u;
42  };  };
43    
# Line 57  struct elf_strtab_hash Line 56  struct elf_strtab_hash
56    struct elf_strtab_hash_entry **array;    struct elf_strtab_hash_entry **array;
57  };  };
58    
 static struct bfd_hash_entry *elf_strtab_hash_newfunc  
   PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, const char *));  
 static int cmplengthentry PARAMS ((const PTR, const PTR));  
 static int last4_eq PARAMS ((const PTR, const PTR));  
   
59  /* Routine to create an entry in a section merge hashtab.  */  /* Routine to create an entry in a section merge hashtab.  */
60    
61  static struct bfd_hash_entry *  static struct bfd_hash_entry *
62  elf_strtab_hash_newfunc (entry, table, string)  elf_strtab_hash_newfunc (struct bfd_hash_entry *entry,
63       struct bfd_hash_entry *entry;                           struct bfd_hash_table *table,
64       struct bfd_hash_table *table;                           const char *string)
      const char *string;  
65  {  {
   struct elf_strtab_hash_entry *ret = (struct elf_strtab_hash_entry *) entry;  
   
66    /* Allocate the structure if it has not already been allocated by a    /* Allocate the structure if it has not already been allocated by a
67       subclass.  */       subclass.  */
68    if (ret == (struct elf_strtab_hash_entry *) NULL)    if (entry == NULL)
69      ret = ((struct elf_strtab_hash_entry *)      entry = bfd_hash_allocate (table, sizeof (struct elf_strtab_hash_entry));
70             bfd_hash_allocate (table, sizeof (struct elf_strtab_hash_entry)));    if (entry == NULL)
   if (ret == (struct elf_strtab_hash_entry *) NULL)  
71      return NULL;      return NULL;
72    
73    /* Call the allocation method of the superclass.  */    /* Call the allocation method of the superclass.  */
74    ret = ((struct elf_strtab_hash_entry *)    entry = bfd_hash_newfunc (entry, table, string);
          bfd_hash_newfunc ((struct bfd_hash_entry *) ret, table, string));  
75    
76    if (ret)    if (entry)
77      {      {
78        /* Initialize the local fields.  */        /* Initialize the local fields.  */
79          struct elf_strtab_hash_entry *ret;
80    
81          ret = (struct elf_strtab_hash_entry *) entry;
82        ret->u.index = -1;        ret->u.index = -1;
83        ret->refcount = 0;        ret->refcount = 0;
84        ret->len = 0;        ret->len = 0;
85      }      }
86    
87    return (struct bfd_hash_entry *)ret;    return entry;
88  }  }
89    
90  /* Create a new hash table.  */  /* Create a new hash table.  */
91    
92  struct elf_strtab_hash *  struct elf_strtab_hash *
93  _bfd_elf_strtab_init ()  _bfd_elf_strtab_init (void)
94  {  {
95    struct elf_strtab_hash *table;    struct elf_strtab_hash *table;
96    bfd_size_type amt = sizeof (struct elf_strtab_hash);    bfd_size_type amt = sizeof (struct elf_strtab_hash);
97    
98    table = (struct elf_strtab_hash *) bfd_malloc (amt);    table = bfd_malloc (amt);
99    if (table == NULL)    if (table == NULL)
100      return NULL;      return NULL;
101    
# Line 117  _bfd_elf_strtab_init () Line 109  _bfd_elf_strtab_init ()
109    table->size = 1;    table->size = 1;
110    table->alloced = 64;    table->alloced = 64;
111    amt = sizeof (struct elf_strtab_hasn_entry *);    amt = sizeof (struct elf_strtab_hasn_entry *);
112    table->array = (struct elf_strtab_hash_entry **)    table->array = bfd_malloc (table->alloced * amt);
                  bfd_malloc (table->alloced * amt);  
113    if (table->array == NULL)    if (table->array == NULL)
114      {      {
115        free (table);        free (table);
# Line 133  _bfd_elf_strtab_init () Line 124  _bfd_elf_strtab_init ()
124  /* Free a strtab.  */  /* Free a strtab.  */
125    
126  void  void
127  _bfd_elf_strtab_free (tab)  _bfd_elf_strtab_free (struct elf_strtab_hash *tab)
      struct elf_strtab_hash *tab;  
128  {  {
129    bfd_hash_table_free (&tab->table);    bfd_hash_table_free (&tab->table);
130    free (tab->array);    free (tab->array);
# Line 145  _bfd_elf_strtab_free (tab) Line 135  _bfd_elf_strtab_free (tab)
135     already present.  */     already present.  */
136    
137  bfd_size_type  bfd_size_type
138  _bfd_elf_strtab_add (tab, str, copy)  _bfd_elf_strtab_add (struct elf_strtab_hash *tab,
139       struct elf_strtab_hash *tab;                       const char *str,
140       const char *str;                       bfd_boolean copy)
      boolean copy;  
141  {  {
142    register struct elf_strtab_hash_entry *entry;    register struct elf_strtab_hash_entry *entry;
143    
# Line 159  _bfd_elf_strtab_add (tab, str, copy) Line 148  _bfd_elf_strtab_add (tab, str, copy)
148    
149    BFD_ASSERT (tab->sec_size == 0);    BFD_ASSERT (tab->sec_size == 0);
150    entry = (struct elf_strtab_hash_entry *)    entry = (struct elf_strtab_hash_entry *)
151            bfd_hash_lookup (&tab->table, str, true, copy);            bfd_hash_lookup (&tab->table, str, TRUE, copy);
152    
153    if (entry == NULL)    if (entry == NULL)
154      return (bfd_size_type) -1;      return (bfd_size_type) -1;
# Line 168  _bfd_elf_strtab_add (tab, str, copy) Line 157  _bfd_elf_strtab_add (tab, str, copy)
157    if (entry->len == 0)    if (entry->len == 0)
158      {      {
159        entry->len = strlen (str) + 1;        entry->len = strlen (str) + 1;
160          /* 2G strings lose.  */
161          BFD_ASSERT (entry->len > 0);
162        if (tab->size == tab->alloced)        if (tab->size == tab->alloced)
163          {          {
164            bfd_size_type amt = sizeof (struct elf_strtab_hash_entry *);            bfd_size_type amt = sizeof (struct elf_strtab_hash_entry *);
165            tab->alloced *= 2;            tab->alloced *= 2;
166            tab->array = (struct elf_strtab_hash_entry **)            tab->array = bfd_realloc (tab->array, tab->alloced * amt);
                        bfd_realloc (tab->array, tab->alloced * amt);  
167            if (tab->array == NULL)            if (tab->array == NULL)
168              return (bfd_size_type) -1;              return (bfd_size_type) -1;
169          }          }
# Line 185  _bfd_elf_strtab_add (tab, str, copy) Line 175  _bfd_elf_strtab_add (tab, str, copy)
175  }  }
176    
177  void  void
178  _bfd_elf_strtab_addref (tab, idx)  _bfd_elf_strtab_addref (struct elf_strtab_hash *tab, bfd_size_type idx)
      struct elf_strtab_hash *tab;  
      bfd_size_type idx;  
179  {  {
180    if (idx == 0 || idx == (bfd_size_type) -1)    if (idx == 0 || idx == (bfd_size_type) -1)
181      return;      return;
# Line 197  _bfd_elf_strtab_addref (tab, idx) Line 185  _bfd_elf_strtab_addref (tab, idx)
185  }  }
186    
187  void  void
188  _bfd_elf_strtab_delref (tab, idx)  _bfd_elf_strtab_delref (struct elf_strtab_hash *tab, bfd_size_type idx)
      struct elf_strtab_hash *tab;  
      bfd_size_type idx;  
189  {  {
190    if (idx == 0 || idx == (bfd_size_type) -1)    if (idx == 0 || idx == (bfd_size_type) -1)
191      return;      return;
# Line 210  _bfd_elf_strtab_delref (tab, idx) Line 196  _bfd_elf_strtab_delref (tab, idx)
196  }  }
197    
198  void  void
199  _bfd_elf_strtab_clear_all_refs (tab)  _bfd_elf_strtab_clear_all_refs (struct elf_strtab_hash *tab)
      struct elf_strtab_hash *tab;  
200  {  {
201    bfd_size_type idx;    bfd_size_type idx;
202    
# Line 220  _bfd_elf_strtab_clear_all_refs (tab) Line 205  _bfd_elf_strtab_clear_all_refs (tab)
205  }  }
206    
207  bfd_size_type  bfd_size_type
208  _bfd_elf_strtab_size (tab)  _bfd_elf_strtab_size (struct elf_strtab_hash *tab)
      struct elf_strtab_hash *tab;  
209  {  {
210    return tab->sec_size ? tab->sec_size : tab->size;    return tab->sec_size ? tab->sec_size : tab->size;
211  }  }
212    
213  bfd_size_type  bfd_size_type
214  _bfd_elf_strtab_offset (tab, idx)  _bfd_elf_strtab_offset (struct elf_strtab_hash *tab, bfd_size_type idx)
      struct elf_strtab_hash *tab;  
      bfd_size_type idx;  
215  {  {
216    struct elf_strtab_hash_entry *entry;    struct elf_strtab_hash_entry *entry;
217    
# Line 243  _bfd_elf_strtab_offset (tab, idx) Line 225  _bfd_elf_strtab_offset (tab, idx)
225    return tab->array[idx]->u.index;    return tab->array[idx]->u.index;
226  }  }
227    
228  boolean  bfd_boolean
229  _bfd_elf_strtab_emit (abfd, tab)  _bfd_elf_strtab_emit (register bfd *abfd, struct elf_strtab_hash *tab)
      register bfd *abfd;  
      struct elf_strtab_hash *tab;  
230  {  {
231    bfd_size_type off = 1, i;    bfd_size_type off = 1, i;
232    
233    if (bfd_bwrite ("", 1, abfd) != 1)    if (bfd_bwrite ("", 1, abfd) != 1)
234      return false;      return FALSE;
235    
236    for (i = 1; i < tab->size; ++i)    for (i = 1; i < tab->size; ++i)
237      {      {
238        register const char *str;        register const char *str;
239        register size_t len;        register unsigned int len;
240    
       str = tab->array[i]->root.string;  
       len = tab->array[i]->len;  
241        BFD_ASSERT (tab->array[i]->refcount == 0);        BFD_ASSERT (tab->array[i]->refcount == 0);
242        if (len == 0)        len = tab->array[i]->len;
243          if ((int) len < 0)
244          continue;          continue;
245    
246        if (bfd_bwrite ((PTR) str, (bfd_size_type) len, abfd) != len)        str = tab->array[i]->root.string;
247          return false;        if (bfd_bwrite (str, len, abfd) != len)
248            return FALSE;
249    
250        off += len;        off += len;
251      }      }
252    
253    BFD_ASSERT (off == tab->sec_size);    BFD_ASSERT (off == tab->sec_size);
254    return true;    return TRUE;
255  }  }
256    
257  /* Compare two elf_strtab_hash_entry structures.  This is called via qsort.  */  /* Compare two elf_strtab_hash_entry structures.  Called via qsort.  */
258    
259  static int  static int
260  cmplengthentry (a, b)  strrevcmp (const void *a, const void *b)
261       const PTR a;  {
262       const PTR b;    struct elf_strtab_hash_entry *A = *(struct elf_strtab_hash_entry **) a;
263  {    struct elf_strtab_hash_entry *B = *(struct elf_strtab_hash_entry **) b;
264    struct elf_strtab_hash_entry * A = *(struct elf_strtab_hash_entry **) a;    unsigned int lenA = A->len;
265    struct elf_strtab_hash_entry * B = *(struct elf_strtab_hash_entry **) b;    unsigned int lenB = B->len;
266      const unsigned char *s = (const unsigned char *) A->root.string + lenA - 1;
267    if (A->len < B->len)    const unsigned char *t = (const unsigned char *) B->root.string + lenB - 1;
268      return 1;    int l = lenA < lenB ? lenA : lenB;
   else if (A->len > B->len)  
     return -1;  
269    
270    return memcmp (A->root.string, B->root.string, A->len);    while (l)
271        {
272          if (*s != *t)
273            return (int) *s - (int) *t;
274          s--;
275          t--;
276          l--;
277        }
278      return lenA - lenB;
279  }  }
280    
281  static int  static inline int
282  last4_eq (a, b)  is_suffix (const struct elf_strtab_hash_entry *A,
283       const PTR a;             const struct elf_strtab_hash_entry *B)
284       const PTR b;  {
 {  
   struct elf_strtab_hash_entry * A = (struct elf_strtab_hash_entry *) a;  
   struct elf_strtab_hash_entry * B = (struct elf_strtab_hash_entry *) b;  
   
   if (memcmp (A->root.string + A->len - 5, B->root.string + B->len - 5, 4)  
       != 0)  
     /* This was a hashtable collision.  */  
     return 0;  
   
285    if (A->len <= B->len)    if (A->len <= B->len)
286      /* B cannot be a suffix of A unless A is equal to B, which is guaranteed      /* B cannot be a suffix of A unless A is equal to B, which is guaranteed
287         not to be equal by the hash table.  */         not to be equal by the hash table.  */
288      return 0;      return 0;
289    
290    return memcmp (A->root.string + (A->len - B->len),    return memcmp (A->root.string + (A->len - B->len),
291                   B->root.string, B->len - 5) == 0;                   B->root.string, B->len - 1) == 0;
292  }  }
293    
294  /* This function assigns final string table offsets for used strings,  /* This function assigns final string table offsets for used strings,
295     merging strings matching suffixes of longer strings if possible.  */     merging strings matching suffixes of longer strings if possible.  */
296    
297  void  void
298  _bfd_elf_strtab_finalize (tab)  _bfd_elf_strtab_finalize (struct elf_strtab_hash *tab)
      struct elf_strtab_hash *tab;  
299  {  {
300    struct elf_strtab_hash_entry **array, **a, **end, *e;    struct elf_strtab_hash_entry **array, **a, *e;
   htab_t last4tab = NULL;  
301    bfd_size_type size, amt;    bfd_size_type size, amt;
   struct elf_strtab_hash_entry *last[256], **last_ptr[256];  
302    
303    /* GCC 2.91.66 (egcs-1.1.2) on i386 miscompiles this function when i is    /* GCC 2.91.66 (egcs-1.1.2) on i386 miscompiles this function when i is
304       a 64-bit bfd_size_type: a 64-bit target or --enable-64-bit-bfd.       a 64-bit bfd_size_type: a 64-bit target or --enable-64-bit-bfd.
# Line 332  _bfd_elf_strtab_finalize (tab) Line 306  _bfd_elf_strtab_finalize (tab)
306       cycles.  */       cycles.  */
307    size_t i;    size_t i;
308    
309    /* Now sort the strings by length, longest first.  */    /* Sort the strings by suffix and length.  */
   array = NULL;  
310    amt = tab->size * sizeof (struct elf_strtab_hash_entry *);    amt = tab->size * sizeof (struct elf_strtab_hash_entry *);
311    array = (struct elf_strtab_hash_entry **) bfd_malloc (amt);    array = bfd_malloc (amt);
312    if (array == NULL)    if (array == NULL)
313      goto alloc_failure;      goto alloc_failure;
314    
   memset (last, 0, sizeof (last));  
   for (i = 0; i < 256; ++i)  
     last_ptr[i] = &last[i];  
315    for (i = 1, a = array; i < tab->size; ++i)    for (i = 1, a = array; i < tab->size; ++i)
316      if (tab->array[i]->refcount)      {
317        *a++ = tab->array[i];        e = tab->array[i];
318      else        if (e->refcount)
319        tab->array[i]->len = 0;          {
320              *a++ = e;
321              /* Adjust the length to not include the zero terminator.  */
322              e->len -= 1;
323            }
324          else
325            e->len = 0;
326        }
327    
328    size = a - array;    size = a - array;
329      if (size != 0)
330        {
331          qsort (array, size, sizeof (struct elf_strtab_hash_entry *), strrevcmp);
332    
333    qsort (array, size, sizeof (struct elf_strtab_hash_entry *), cmplengthentry);        /* Loop over the sorted array and merge suffixes.  Start from the
334             end because we want eg.
335    
336    last4tab = htab_create_alloc (size * 4, NULL, last4_eq, NULL, calloc, free);           s1 -> "d"
337    if (last4tab == NULL)           s2 -> "bcd"
338      goto alloc_failure;           s3 -> "abcd"
339    
340    /* Now insert the strings into hash tables (strings with last 4 characters           to end up as
      and strings with last character equal), look for longer strings which  
      we're suffix of.  */  
   for (a = array, end = array + size; a < end; a++)  
     {  
       register hashval_t hash;  
       unsigned int c;  
       unsigned int j;  
       const unsigned char *s;  
       PTR *p;  
341    
342        e = *a;           s3 -> "abcd"
343        if (e->len > 4)           s2 _____^
344          {           s1 _______^
           s = e->root.string + e->len - 1;  
           hash = 0;  
           for (j = 0; j < 4; j++)  
             {  
               c = *--s;  
               hash += c + (c << 17);  
               hash ^= hash >> 2;  
             }  
           p = htab_find_slot_with_hash (last4tab, e, hash, INSERT);  
           if (p == NULL)  
             goto alloc_failure;  
           if (*p)  
             {  
               struct elf_strtab_hash_entry *ent;  
345    
346                ent = (struct elf_strtab_hash_entry *) *p;           ie. we don't want s1 pointing into the old s2.  */
347                e->u.suffix = ent;        e = *--a;
348                e->len = 0;        e->len += 1;
349                continue;        while (--a >= array)
             }  
           else  
             *p = (PTR) e;  
         }  
       else  
350          {          {
351            struct elf_strtab_hash_entry *tem;            struct elf_strtab_hash_entry *cmp = *a;
   
           c = e->root.string[e->len - 2] & 0xff;  
352    
353            for (tem = last[c]; tem; tem = tem->u.next)            cmp->len += 1;
354              if (tem->len > e->len            if (is_suffix (e, cmp))
                 && memcmp (tem->root.string + (tem->len - e->len),  
                            e->root.string, e->len - 1) == 0)  
               break;  
           if (tem)  
355              {              {
356                e->u.suffix = tem;                cmp->u.suffix = e;
357                e->len = 0;                cmp->len = -cmp->len;
               continue;  
358              }              }
359              else
360                e = cmp;
361          }          }
   
       c = e->root.string[e->len - 2] & 0xff;  
       /* Put longest strings first.  */  
       *last_ptr[c] = e;  
       last_ptr[c] = &e->u.next;  
       e->u.next = NULL;  
362      }      }
363    
364  alloc_failure:  alloc_failure:
365    if (array)    if (array)
366      free (array);      free (array);
   if (last4tab)  
     htab_delete (last4tab);  
367    
368    /* Now assign positions to the strings we want to keep.  */    /* Assign positions to the strings we want to keep.  */
369    size = 1;    size = 1;
370    for (i = 1; i < tab->size; ++i)    for (i = 1; i < tab->size; ++i)
371      {      {
372        e = tab->array[i];        e = tab->array[i];
373        if (e->refcount && e->len)        if (e->refcount && e->len > 0)
374          {          {
375            e->u.index = size;            e->u.index = size;
376            size += e->len;            size += e->len;
# Line 439  alloc_failure: Line 379  alloc_failure:
379    
380    tab->sec_size = size;    tab->sec_size = size;
381    
382    /* And now adjust the rest.  */    /* Adjust the rest.  */
383    for (i = 1; i < tab->size; ++i)    for (i = 1; i < tab->size; ++i)
384      {      {
385        e = tab->array[i];        e = tab->array[i];
386        if (e->refcount && ! e->len)        if (e->refcount && e->len < 0)
387          e->u.index = e->u.suffix->u.index          e->u.index = e->u.suffix->u.index + (e->u.suffix->len + e->len);
                      + (e->u.suffix->len - strlen (e->root.string) - 1);  
388      }      }
389  }  }

Legend:
Removed from v.1.1.1.1  
changed lines
  Added in v.1.2

savannah-hackers-public@gnu.org
ViewVC Help
Powered by ViewVC 1.1.26