OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [insight/] [bfd/] [merge.c] - Blame information for rev 1771

Go to most recent revision | Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.