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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [gdb-5.3/] [bfd/] [elf-eh-frame.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1181 sfurman
/* .eh_frame section optimization.
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
#include "bfd.h"
22
#include "sysdep.h"
23
#include "libbfd.h"
24
#include "elf-bfd.h"
25
#include "elf/dwarf2.h"
26
 
27
#define EH_FRAME_HDR_SIZE 8
28
 
29
struct cie_header
30
{
31
  unsigned int length;
32
  unsigned int id;
33
};
34
 
35
struct cie
36
{
37
  struct cie_header hdr;
38
  unsigned char version;
39
  unsigned char augmentation[20];
40
  unsigned int code_align;
41
  int data_align;
42
  unsigned int ra_column;
43
  unsigned int augmentation_size;
44
  struct elf_link_hash_entry *personality;
45
  unsigned char per_encoding;
46
  unsigned char lsda_encoding;
47
  unsigned char fde_encoding;
48
  unsigned char initial_insn_length;
49
  unsigned char make_relative;
50
  unsigned char make_lsda_relative;
51
  unsigned char initial_instructions[50];
52
};
53
 
54
struct eh_cie_fde
55
{
56
  unsigned int offset;
57
  unsigned int size;
58
  asection *sec;
59
  unsigned int new_offset;
60
  unsigned char fde_encoding;
61
  unsigned char lsda_encoding;
62
  unsigned char lsda_offset;
63
  unsigned char cie : 1;
64
  unsigned char removed : 1;
65
  unsigned char make_relative : 1;
66
  unsigned char make_lsda_relative : 1;
67
  unsigned char per_encoding_relative : 1;
68
};
69
 
70
struct eh_frame_sec_info
71
{
72
  unsigned int count;
73
  unsigned int alloced;
74
  struct eh_cie_fde entry[1];
75
};
76
 
77
struct eh_frame_array_ent
78
{
79
  bfd_vma initial_loc;
80
  bfd_vma fde;
81
};
82
 
83
struct eh_frame_hdr_info
84
{
85
  struct cie last_cie;
86
  asection *last_cie_sec;
87
  unsigned int last_cie_offset;
88
  unsigned int fde_count, array_count;
89
  struct eh_frame_array_ent *array;
90
  /* TRUE if .eh_frame_hdr should contain the sorted search table.
91
     We build it if we successfully read all .eh_frame input sections
92
     and recognize them.  */
93
  boolean table;
94
  boolean strip;
95
};
96
 
97
static bfd_vma read_unsigned_leb128
98
  PARAMS ((bfd *, char *, unsigned int *));
99
static bfd_signed_vma read_signed_leb128
100
  PARAMS ((bfd *, char *, unsigned int *));
101
static int get_DW_EH_PE_width
102
  PARAMS ((int, int));
103
static bfd_vma read_value
104
  PARAMS ((bfd *, bfd_byte *, int));
105
static void write_value
106
  PARAMS ((bfd *, bfd_byte *, bfd_vma, int));
107
static int cie_compare
108
  PARAMS ((struct cie *, struct cie *));
109
static int vma_compare
110
  PARAMS ((const PTR a, const PTR b));
111
 
112
/* Helper function for reading uleb128 encoded data.  */
113
 
114
static bfd_vma
115
read_unsigned_leb128 (abfd, buf, bytes_read_ptr)
116
     bfd *abfd ATTRIBUTE_UNUSED;
117
     char *buf;
118
     unsigned int *bytes_read_ptr;
119
{
120
  bfd_vma  result;
121
  unsigned int  num_read;
122
  int           shift;
123
  unsigned char byte;
124
 
125
  result   = 0;
126
  shift    = 0;
127
  num_read = 0;
128
  do
129
    {
130
      byte = bfd_get_8 (abfd, (bfd_byte *) buf);
131
      buf ++;
132
      num_read ++;
133
      result |= (((bfd_vma) byte & 0x7f) << shift);
134
      shift += 7;
135
    }
136
  while (byte & 0x80);
137
  * bytes_read_ptr = num_read;
138
  return result;
139
}
140
 
141
/* Helper function for reading sleb128 encoded data.  */
142
 
143
static bfd_signed_vma
144
read_signed_leb128 (abfd, buf, bytes_read_ptr)
145
     bfd *abfd ATTRIBUTE_UNUSED;
146
     char *buf;
147
     unsigned int * bytes_read_ptr;
148
{
149
  bfd_vma       result;
150
  int           shift;
151
  int           num_read;
152
  unsigned char byte;
153
 
154
  result = 0;
155
  shift = 0;
156
  num_read = 0;
157
  do
158
    {
159
      byte = bfd_get_8 (abfd, (bfd_byte *) buf);
160
      buf ++;
161
      num_read ++;
162
      result |= (((bfd_vma) byte & 0x7f) << shift);
163
      shift += 7;
164
    }
165
  while (byte & 0x80);
166
  if (byte & 0x40)
167
    result |= (((bfd_vma) -1) << (shift - 7)) << 7;
168
  * bytes_read_ptr = num_read;
169
  return result;
170
}
171
 
172
#define read_uleb128(VAR, BUF)                                  \
173
do                                                              \
174
  {                                                             \
175
    (VAR) = read_unsigned_leb128 (abfd, buf, &leb128_tmp);      \
176
    (BUF) += leb128_tmp;                                        \
177
  }                                                             \
178
while (0)
179
 
180
#define read_sleb128(VAR, BUF)                                  \
181
do                                                              \
182
  {                                                             \
183
    (VAR) = read_signed_leb128 (abfd, buf, &leb128_tmp);        \
184
    (BUF) += leb128_tmp;                                        \
185
  }                                                             \
186
while (0)
187
 
188
/* Return 0 if either encoding is variable width, or not yet known to bfd.  */
189
 
190
static
191
int get_DW_EH_PE_width (encoding, ptr_size)
192
     int encoding, ptr_size;
193
{
194
  /* DW_EH_PE_ values of 0x60 and 0x70 weren't defined at the time .eh_frame
195
     was added to bfd.  */
196
  if ((encoding & 0x60) == 0x60)
197
    return 0;
198
 
199
  switch (encoding & 7)
200
    {
201
    case DW_EH_PE_udata2: return 2;
202
    case DW_EH_PE_udata4: return 4;
203
    case DW_EH_PE_udata8: return 8;
204
    case DW_EH_PE_absptr: return ptr_size;
205
    default:
206
      break;
207
    }
208
 
209
  return 0;
210
}
211
 
212
/* Read a width sized value from memory.  */
213
 
214
static bfd_vma
215
read_value (abfd, buf, width)
216
     bfd *abfd;
217
     bfd_byte *buf;
218
     int width;
219
{
220
  bfd_vma value;
221
 
222
  switch (width)
223
    {
224
    case 2: value = bfd_get_16 (abfd, buf); break;
225
    case 4: value = bfd_get_32 (abfd, buf); break;
226
    case 8: value = bfd_get_64 (abfd, buf); break;
227
    default: BFD_FAIL (); return 0;
228
    }
229
 
230
  return value;
231
}
232
 
233
/* Store a width sized value to memory.  */
234
 
235
static void
236
write_value (abfd, buf, value, width)
237
     bfd *abfd;
238
     bfd_byte *buf;
239
     bfd_vma value;
240
     int width;
241
{
242
  switch (width)
243
    {
244
    case 2: bfd_put_16 (abfd, value, buf); break;
245
    case 4: bfd_put_32 (abfd, value, buf); break;
246
    case 8: bfd_put_64 (abfd, value, buf); break;
247
    default: BFD_FAIL ();
248
    }
249
}
250
 
251
/* Return zero if C1 and C2 CIEs can be merged.  */
252
 
253
static
254
int cie_compare (c1, c2)
255
     struct cie *c1, *c2;
256
{
257
  if (c1->hdr.length == c2->hdr.length
258
      && c1->version == c2->version
259
      && strcmp (c1->augmentation, c2->augmentation) == 0
260
      && strcmp (c1->augmentation, "eh") != 0
261
      && c1->code_align == c2->code_align
262
      && c1->data_align == c2->data_align
263
      && c1->ra_column == c2->ra_column
264
      && c1->augmentation_size == c2->augmentation_size
265
      && c1->personality == c2->personality
266
      && c1->per_encoding == c2->per_encoding
267
      && c1->lsda_encoding == c2->lsda_encoding
268
      && c1->fde_encoding == c2->fde_encoding
269
      && (c1->initial_insn_length
270
          == c2->initial_insn_length)
271
      && memcmp (c1->initial_instructions,
272
                 c2->initial_instructions,
273
                 c1->initial_insn_length) == 0)
274
    return 0;
275
 
276
  return 1;
277
}
278
 
279
/* This function is called for each input file before the .eh_frame
280
   section is relocated.  It discards duplicate CIEs and FDEs for discarded
281
   functions.  The function returns true iff any entries have been
282
   deleted.  */
283
 
284
boolean
285
_bfd_elf_discard_section_eh_frame (abfd, info, sec, ehdrsec,
286
                                   reloc_symbol_deleted_p, cookie)
287
     bfd *abfd;
288
     struct bfd_link_info *info;
289
     asection *sec, *ehdrsec;
290
     boolean (*reloc_symbol_deleted_p) PARAMS ((bfd_vma, PTR));
291
     struct elf_reloc_cookie *cookie;
292
{
293
  bfd_byte *ehbuf = NULL, *buf;
294
  bfd_byte *last_cie, *last_fde;
295
  struct cie_header hdr;
296
  struct cie cie;
297
  struct eh_frame_hdr_info *hdr_info;
298
  struct eh_frame_sec_info *sec_info = NULL;
299
  unsigned int leb128_tmp;
300
  unsigned int cie_usage_count, last_cie_ndx, i, offset;
301
  unsigned int make_relative, make_lsda_relative;
302
  Elf_Internal_Rela *rel;
303
  bfd_size_type new_size;
304
  unsigned int ptr_size;
305
 
306
  if (sec->_raw_size == 0)
307
    {
308
      /* This file does not contain .eh_frame information.  */
309
      return false;
310
    }
311
 
312
  if ((sec->output_section != NULL
313
       && bfd_is_abs_section (sec->output_section)))
314
    {
315
      /* At least one of the sections is being discarded from the
316
         link, so we should just ignore them.  */
317
      return false;
318
    }
319
 
320
  BFD_ASSERT (elf_section_data (ehdrsec)->sec_info_type
321
              == ELF_INFO_TYPE_EH_FRAME_HDR);
322
  hdr_info = (struct eh_frame_hdr_info *)
323
             elf_section_data (ehdrsec)->sec_info;
324
 
325
  /* Read the frame unwind information from abfd.  */
326
 
327
  ehbuf = (bfd_byte *) bfd_malloc (sec->_raw_size);
328
  if (ehbuf == NULL)
329
    goto free_no_table;
330
 
331
  if (! bfd_get_section_contents (abfd, sec, ehbuf, (bfd_vma) 0,
332
                                  sec->_raw_size))
333
    goto free_no_table;
334
 
335
  if (sec->_raw_size >= 4
336
      && bfd_get_32 (abfd, ehbuf) == 0
337
      && cookie->rel == cookie->relend)
338
    {
339
      /* Empty .eh_frame section.  */
340
      free (ehbuf);
341
      return false;
342
    }
343
 
344
  /* If .eh_frame section size doesn't fit into int, we cannot handle
345
     it (it would need to use 64-bit .eh_frame format anyway).  */
346
  if (sec->_raw_size != (unsigned int) sec->_raw_size)
347
    goto free_no_table;
348
 
349
  ptr_size = (elf_elfheader (abfd)->e_ident[EI_CLASS]
350
              == ELFCLASS64) ? 8 : 4;
351
  buf = ehbuf;
352
  last_cie = NULL;
353
  last_cie_ndx = 0;
354
  memset (&cie, 0, sizeof (cie));
355
  cie_usage_count = 0;
356
  new_size = sec->_raw_size;
357
  make_relative = hdr_info->last_cie.make_relative;
358
  make_lsda_relative = hdr_info->last_cie.make_lsda_relative;
359
  sec_info = bfd_zmalloc (sizeof (struct eh_frame_sec_info)
360
                          + 99 * sizeof (struct eh_cie_fde));
361
  if (sec_info == NULL)
362
    goto free_no_table;
363
  sec_info->alloced = 100;
364
 
365
#define ENSURE_NO_RELOCS(buf)                           \
366
  if (cookie->rel < cookie->relend                      \
367
      && (cookie->rel->r_offset                         \
368
          < (bfd_size_type) ((buf) - ehbuf)))           \
369
    goto free_no_table
370
 
371
#define SKIP_RELOCS(buf)                                \
372
  while (cookie->rel < cookie->relend                   \
373
         && (cookie->rel->r_offset                      \
374
             < (bfd_size_type) ((buf) - ehbuf)))        \
375
    cookie->rel++
376
 
377
#define GET_RELOC(buf)                                  \
378
  ((cookie->rel < cookie->relend                        \
379
    && (cookie->rel->r_offset                           \
380
        == (bfd_size_type) ((buf) - ehbuf)))            \
381
   ? cookie->rel : NULL)
382
 
383
  for (;;)
384
    {
385
      unsigned char *aug;
386
 
387
      if (sec_info->count == sec_info->alloced)
388
        {
389
          sec_info = bfd_realloc (sec_info,
390
                                  sizeof (struct eh_frame_sec_info)
391
                                  + (sec_info->alloced + 99)
392
                                     * sizeof (struct eh_cie_fde));
393
          if (sec_info == NULL)
394
            goto free_no_table;
395
 
396
          memset (&sec_info->entry[sec_info->alloced], 0,
397
                  100 * sizeof (struct eh_cie_fde));
398
          sec_info->alloced += 100;
399
        }
400
 
401
      last_fde = buf;
402
      /* If we are at the end of the section, we still need to decide
403
         on whether to output or discard last encountered CIE (if any).  */
404
      if ((bfd_size_type) (buf - ehbuf) == sec->_raw_size)
405
        hdr.id = (unsigned int) -1;
406
      else
407
        {
408
          if ((bfd_size_type) (buf + 4 - ehbuf) > sec->_raw_size)
409
            /* No space for CIE/FDE header length.  */
410
            goto free_no_table;
411
 
412
          hdr.length = bfd_get_32 (abfd, buf);
413
          if (hdr.length == 0xffffffff)
414
            /* 64-bit .eh_frame is not supported.  */
415
            goto free_no_table;
416
          buf += 4;
417
          if ((buf - ehbuf) + hdr.length > sec->_raw_size)
418
            /* CIE/FDE not contained fully in this .eh_frame input section.  */
419
            goto free_no_table;
420
 
421
          sec_info->entry[sec_info->count].offset = last_fde - ehbuf;
422
          sec_info->entry[sec_info->count].size = 4 + hdr.length;
423
 
424
          if (hdr.length == 0)
425
            {
426
              /* CIE with length 0 must be only the last in the section.  */
427
              if ((bfd_size_type) (buf - ehbuf) < sec->_raw_size)
428
                goto free_no_table;
429
              ENSURE_NO_RELOCS (buf);
430
              sec_info->count++;
431
              /* Now just finish last encountered CIE processing and break
432
                 the loop.  */
433
              hdr.id = (unsigned int) -1;
434
            }
435
          else
436
            {
437
              hdr.id = bfd_get_32 (abfd, buf);
438
              buf += 4;
439
              if (hdr.id == (unsigned int) -1)
440
                goto free_no_table;
441
            }
442
        }
443
 
444
      if (hdr.id == 0 || hdr.id == (unsigned int) -1)
445
        {
446
          unsigned int initial_insn_length;
447
 
448
          /* CIE  */
449
          if (last_cie != NULL)
450
            {
451
              /* Now check if this CIE is identical to last CIE, in which case
452
                 we can remove it, provided we adjust all FDEs.
453
                 Also, it can be removed if we have removed all FDEs using
454
                 that. */
455
              if (cie_compare (&cie, &hdr_info->last_cie) == 0
456
                  || cie_usage_count == 0)
457
                {
458
                  new_size -= cie.hdr.length + 4;
459
                  sec_info->entry[last_cie_ndx].removed = 1;
460
                  sec_info->entry[last_cie_ndx].sec = hdr_info->last_cie_sec;
461
                  sec_info->entry[last_cie_ndx].new_offset
462
                    = hdr_info->last_cie_offset;
463
                }
464
              else
465
                {
466
                  hdr_info->last_cie = cie;
467
                  hdr_info->last_cie_sec = sec;
468
                  hdr_info->last_cie_offset = last_cie - ehbuf;
469
                  sec_info->entry[last_cie_ndx].make_relative
470
                    = cie.make_relative;
471
                  sec_info->entry[last_cie_ndx].make_lsda_relative
472
                    = cie.make_lsda_relative;
473
                  sec_info->entry[last_cie_ndx].per_encoding_relative
474
                    = (cie.per_encoding & 0x70) == DW_EH_PE_pcrel;
475
                }
476
            }
477
 
478
          if (hdr.id == (unsigned int) -1)
479
            break;
480
 
481
          last_cie_ndx = sec_info->count;
482
          sec_info->entry[sec_info->count].cie = 1;
483
 
484
          cie_usage_count = 0;
485
          memset (&cie, 0, sizeof (cie));
486
          cie.hdr = hdr;
487
          cie.version = *buf++;
488
 
489
          /* Cannot handle unknown versions.  */
490
          if (cie.version != 1)
491
            goto free_no_table;
492
          if (strlen (buf) > sizeof (cie.augmentation) - 1)
493
            goto free_no_table;
494
 
495
          strcpy (cie.augmentation, buf);
496
          buf = strchr (buf, '\0') + 1;
497
          ENSURE_NO_RELOCS (buf);
498
          if (buf[0] == 'e' && buf[1] == 'h')
499
            {
500
              /* GCC < 3.0 .eh_frame CIE */
501
              /* We cannot merge "eh" CIEs because __EXCEPTION_TABLE__
502
                 is private to each CIE, so we don't need it for anything.
503
                 Just skip it.  */
504
              buf += ptr_size;
505
              SKIP_RELOCS (buf);
506
            }
507
          read_uleb128 (cie.code_align, buf);
508
          read_sleb128 (cie.data_align, buf);
509
          /* Note - in DWARF2 the return address column is an unsigned byte.
510
             In DWARF3 it is a ULEB128.  We are following DWARF3.  For most
511
             ports this will not matter as the value will be less than 128.
512
             For the others (eg FRV, SH, MMIX, IA64) they need a fixed GCC
513
             which conforms to the DWARF3 standard.  */
514
          read_uleb128 (cie.ra_column, buf);
515
          ENSURE_NO_RELOCS (buf);
516
          cie.lsda_encoding = DW_EH_PE_omit;
517
          cie.fde_encoding = DW_EH_PE_omit;
518
          cie.per_encoding = DW_EH_PE_omit;
519
          aug = cie.augmentation;
520
          if (aug[0] != 'e' || aug[1] != 'h')
521
            {
522
              if (*aug == 'z')
523
                {
524
                  aug++;
525
                  read_uleb128 (cie.augmentation_size, buf);
526
                  ENSURE_NO_RELOCS (buf);
527
                }
528
 
529
              while (*aug != '\0')
530
                switch (*aug++)
531
                  {
532
                  case 'L':
533
                    cie.lsda_encoding = *buf++;
534
                    ENSURE_NO_RELOCS (buf);
535
                    if (get_DW_EH_PE_width (cie.lsda_encoding, ptr_size) == 0)
536
                      goto free_no_table;
537
                    break;
538
                  case 'R':
539
                    cie.fde_encoding = *buf++;
540
                    ENSURE_NO_RELOCS (buf);
541
                    if (get_DW_EH_PE_width (cie.fde_encoding, ptr_size) == 0)
542
                      goto free_no_table;
543
                    break;
544
                  case 'P':
545
                    {
546
                      int per_width;
547
 
548
                      cie.per_encoding = *buf++;
549
                      per_width = get_DW_EH_PE_width (cie.per_encoding,
550
                                                      ptr_size);
551
                      if (per_width == 0)
552
                        goto free_no_table;
553
                      if ((cie.per_encoding & 0xf0) == DW_EH_PE_aligned)
554
                        buf = (ehbuf
555
                               + ((buf - ehbuf + per_width - 1)
556
                                  & ~((bfd_size_type) per_width - 1)));
557
                      ENSURE_NO_RELOCS (buf);
558
                      rel = GET_RELOC (buf);
559
                      /* Ensure we have a reloc here, against
560
                         a global symbol.  */
561
                      if (rel != NULL)
562
                        {
563
                          unsigned long r_symndx;
564
 
565
#ifdef BFD64
566
                          if (ptr_size == 8)
567
                            r_symndx = ELF64_R_SYM (cookie->rel->r_info);
568
                          else
569
#endif
570
                            r_symndx = ELF32_R_SYM (cookie->rel->r_info);
571
                          if (r_symndx >= cookie->locsymcount)
572
                            {
573
                              struct elf_link_hash_entry *h;
574
 
575
                              r_symndx -= cookie->extsymoff;
576
                              h = cookie->sym_hashes[r_symndx];
577
 
578
                              while (h->root.type == bfd_link_hash_indirect
579
                                     || h->root.type == bfd_link_hash_warning)
580
                                h = (struct elf_link_hash_entry *)
581
                                    h->root.u.i.link;
582
 
583
                              cie.personality = h;
584
                            }
585
                          cookie->rel++;
586
                        }
587
                      buf += per_width;
588
                    }
589
                    break;
590
                  default:
591
                    /* Unrecognized augmentation. Better bail out.  */
592
                    goto free_no_table;
593
                  }
594
            }
595
 
596
          /* For shared libraries, try to get rid of as many RELATIVE relocs
597
             as possible.  */
598
          if (info->shared
599
              && (cie.fde_encoding & 0xf0) == DW_EH_PE_absptr)
600
            cie.make_relative = 1;
601
 
602
          if (info->shared
603
              && (cie.lsda_encoding & 0xf0) == DW_EH_PE_absptr)
604
            cie.make_lsda_relative = 1;
605
 
606
          /* If FDE encoding was not specified, it defaults to
607
             DW_EH_absptr.  */
608
          if (cie.fde_encoding == DW_EH_PE_omit)
609
            cie.fde_encoding = DW_EH_PE_absptr;
610
 
611
          initial_insn_length = cie.hdr.length - (buf - last_fde - 4);
612
          if (initial_insn_length <= 50)
613
            {
614
              cie.initial_insn_length = initial_insn_length;
615
              memcpy (cie.initial_instructions, buf, initial_insn_length);
616
            }
617
          buf += initial_insn_length;
618
          ENSURE_NO_RELOCS (buf);
619
          last_cie = last_fde;
620
        }
621
      else
622
        {
623
          /* Ensure this FDE uses the last CIE encountered.  */
624
          if (last_cie == NULL
625
              || hdr.id != (unsigned int) (buf - 4 - last_cie))
626
            goto free_no_table;
627
 
628
          ENSURE_NO_RELOCS (buf);
629
          rel = GET_RELOC (buf);
630
          if (rel == NULL)
631
            /* This should not happen.  */
632
            goto free_no_table;
633
          if ((*reloc_symbol_deleted_p) (buf - ehbuf, cookie))
634
            {
635
              cookie->rel = rel;
636
              /* This is a FDE against discarded section, it should
637
                 be deleted.  */
638
              new_size -= hdr.length + 4;
639
              sec_info->entry[sec_info->count].removed = 1;
640
            }
641
          else
642
            {
643
              if (info->shared
644
                  && (((cie.fde_encoding & 0xf0) == DW_EH_PE_absptr
645
                       && cie.make_relative == 0)
646
                      || (cie.fde_encoding & 0xf0) == DW_EH_PE_aligned))
647
                {
648
                  /* If shared library uses absolute pointers
649
                     which we cannot turn into PC relative,
650
                     don't create the binary search table,
651
                     since it is affected by runtime relocations.  */
652
                  hdr_info->table = false;
653
                }
654
              cie_usage_count++;
655
              hdr_info->fde_count++;
656
            }
657
          cookie->rel = rel;
658
          if (cie.lsda_encoding != DW_EH_PE_omit)
659
            {
660
              unsigned int dummy;
661
 
662
              aug = buf;
663
              buf += 2 * get_DW_EH_PE_width (cie.fde_encoding, ptr_size);
664
              if (cie.augmentation[0] == 'z')
665
                read_uleb128 (dummy, buf);
666
              /* If some new augmentation data is added before LSDA
667
                 in FDE augmentation area, this need to be adjusted.  */
668
              sec_info->entry[sec_info->count].lsda_offset = (buf - aug);
669
            }
670
          buf = last_fde + 4 + hdr.length;
671
          SKIP_RELOCS (buf);
672
        }
673
 
674
      sec_info->entry[sec_info->count].fde_encoding = cie.fde_encoding;
675
      sec_info->entry[sec_info->count].lsda_encoding = cie.lsda_encoding;
676
      sec_info->count++;
677
    }
678
 
679
  elf_section_data (sec)->sec_info = sec_info;
680
  elf_section_data (sec)->sec_info_type = ELF_INFO_TYPE_EH_FRAME;
681
 
682
  /* Ok, now we can assign new offsets.  */
683
  offset = 0;
684
  last_cie_ndx = 0;
685
  for (i = 0; i < sec_info->count; i++)
686
    {
687
      if (! sec_info->entry[i].removed)
688
        {
689
          sec_info->entry[i].new_offset = offset;
690
          offset += sec_info->entry[i].size;
691
          if (sec_info->entry[i].cie)
692
            {
693
              last_cie_ndx = i;
694
              make_relative = sec_info->entry[i].make_relative;
695
              make_lsda_relative = sec_info->entry[i].make_lsda_relative;
696
            }
697
          else
698
            {
699
              sec_info->entry[i].make_relative = make_relative;
700
              sec_info->entry[i].make_lsda_relative = make_lsda_relative;
701
              sec_info->entry[i].per_encoding_relative = 0;
702
            }
703
        }
704
      else if (sec_info->entry[i].cie && sec_info->entry[i].sec == sec)
705
        {
706
          /* Need to adjust new_offset too.  */
707
          BFD_ASSERT (sec_info->entry[last_cie_ndx].offset
708
                      == sec_info->entry[i].new_offset);
709
          sec_info->entry[i].new_offset
710
            = sec_info->entry[last_cie_ndx].new_offset;
711
        }
712
    }
713
  if (hdr_info->last_cie_sec == sec)
714
    {
715
      BFD_ASSERT (sec_info->entry[last_cie_ndx].offset
716
                  == hdr_info->last_cie_offset);
717
      hdr_info->last_cie_offset = sec_info->entry[last_cie_ndx].new_offset;
718
    }
719
 
720
  /* FIXME: Currently it is not possible to shrink sections to zero size at
721
     this point, so build a fake minimal CIE.  */
722
  if (new_size == 0)
723
    new_size = 16;
724
 
725
  /* Shrink the sec as needed.  */
726
  sec->_cooked_size = new_size;
727
  if (sec->_cooked_size == 0)
728
    sec->flags |= SEC_EXCLUDE;
729
 
730
  free (ehbuf);
731
  return new_size != sec->_raw_size;
732
 
733
free_no_table:
734
  if (ehbuf)
735
    free (ehbuf);
736
  if (sec_info)
737
    free (sec_info);
738
  hdr_info->table = false;
739
  hdr_info->last_cie.hdr.length = 0;
740
  return false;
741
}
742
 
743
/* This function is called for .eh_frame_hdr section after
744
   _bfd_elf_discard_section_eh_frame has been called on all .eh_frame
745
   input sections.  It finalizes the size of .eh_frame_hdr section.  */
746
 
747
boolean
748
_bfd_elf_discard_section_eh_frame_hdr (abfd, info, sec)
749
     bfd *abfd;
750
     struct bfd_link_info *info;
751
     asection *sec;
752
{
753
  struct eh_frame_hdr_info *hdr_info;
754
  unsigned int ptr_size;
755
 
756
  ptr_size = (elf_elfheader (abfd)->e_ident[EI_CLASS]
757
              == ELFCLASS64) ? 8 : 4;
758
 
759
  if ((elf_section_data (sec)->sec_info_type
760
       != ELF_INFO_TYPE_EH_FRAME_HDR)
761
      || ! info->eh_frame_hdr)
762
    {
763
      _bfd_strip_section_from_output (info, sec);
764
      return false;
765
    }
766
 
767
  hdr_info = (struct eh_frame_hdr_info *)
768
             elf_section_data (sec)->sec_info;
769
  if (hdr_info->strip)
770
    return false;
771
  sec->_cooked_size = EH_FRAME_HDR_SIZE;
772
  if (hdr_info->table)
773
    sec->_cooked_size += 4 + hdr_info->fde_count * 8;
774
 
775
  /* Request program headers to be recalculated.  */
776
  elf_tdata (abfd)->program_header_size = 0;
777
  elf_tdata (abfd)->eh_frame_hdr = true;
778
  return true;
779
}
780
 
781
/* This function is called from size_dynamic_sections.
782
   It needs to decide whether .eh_frame_hdr should be output or not,
783
   because later on it is too late for calling _bfd_strip_section_from_output,
784
   since dynamic symbol table has been sized.  */
785
 
786
boolean
787
_bfd_elf_maybe_strip_eh_frame_hdr (info)
788
     struct bfd_link_info *info;
789
{
790
  asection *sec, *o;
791
  bfd *abfd;
792
  struct eh_frame_hdr_info *hdr_info;
793
 
794
  sec = bfd_get_section_by_name (elf_hash_table (info)->dynobj, ".eh_frame_hdr");
795
  if (sec == NULL || bfd_is_abs_section (sec->output_section))
796
    return true;
797
 
798
  hdr_info
799
    = bfd_zmalloc (sizeof (struct eh_frame_hdr_info));
800
  if (hdr_info == NULL)
801
    return false;
802
 
803
  elf_section_data (sec)->sec_info = hdr_info;
804
  elf_section_data (sec)->sec_info_type = ELF_INFO_TYPE_EH_FRAME_HDR;
805
 
806
  abfd = NULL;
807
  if (info->eh_frame_hdr)
808
    for (abfd = info->input_bfds; abfd != NULL; abfd = abfd->link_next)
809
      {
810
        /* Count only sections which have at least a single CIE or FDE.
811
           There cannot be any CIE or FDE <= 8 bytes.  */
812
        o = bfd_get_section_by_name (abfd, ".eh_frame");
813
        if (o && o->_raw_size > 8 && !bfd_is_abs_section (o->output_section))
814
          break;
815
      }
816
 
817
  if (abfd == NULL)
818
    {
819
      _bfd_strip_section_from_output (info, sec);
820
      hdr_info->strip = true;
821
    }
822
  else
823
    hdr_info->table = true;
824
  return true;
825
}
826
 
827
/* Adjust an address in the .eh_frame section.  Given OFFSET within
828
   SEC, this returns the new offset in the adjusted .eh_frame section,
829
   or -1 if the address refers to a CIE/FDE which has been removed
830
   or to offset with dynamic relocation which is no longer needed.  */
831
 
832
bfd_vma
833
_bfd_elf_eh_frame_section_offset (output_bfd, sec, offset)
834
     bfd *output_bfd ATTRIBUTE_UNUSED;
835
     asection *sec;
836
     bfd_vma offset;
837
{
838
  struct eh_frame_sec_info *sec_info;
839
  unsigned int lo, hi, mid;
840
 
841
  if (elf_section_data (sec)->sec_info_type != ELF_INFO_TYPE_EH_FRAME)
842
    return offset;
843
  sec_info = (struct eh_frame_sec_info *)
844
             elf_section_data (sec)->sec_info;
845
 
846
  if (offset >= sec->_raw_size)
847
    return offset - (sec->_cooked_size - sec->_raw_size);
848
 
849
  lo = 0;
850
  hi = sec_info->count;
851
  mid = 0;
852
  while (lo < hi)
853
    {
854
      mid = (lo + hi) / 2;
855
      if (offset < sec_info->entry[mid].offset)
856
        hi = mid;
857
      else if (offset
858
               >= sec_info->entry[mid].offset + sec_info->entry[mid].size)
859
        lo = mid + 1;
860
      else
861
        break;
862
    }
863
 
864
  BFD_ASSERT (lo < hi);
865
 
866
  /* FDE or CIE was removed.  */
867
  if (sec_info->entry[mid].removed)
868
    return (bfd_vma) -1;
869
 
870
  /* If converting to DW_EH_PE_pcrel, there will be no need for run-time
871
     relocation against FDE's initial_location field.  */
872
  if (sec_info->entry[mid].make_relative
873
      && ! sec_info->entry[mid].cie
874
      && offset == sec_info->entry[mid].offset + 8)
875
    return (bfd_vma) -2;
876
 
877
  /* If converting LSDA pointers to DW_EH_PE_pcrel, there will be no need
878
     for run-time relocation against LSDA field.  */
879
  if (sec_info->entry[mid].make_lsda_relative
880
      && ! sec_info->entry[mid].cie
881
      && (offset
882
          == (sec_info->entry[mid].offset + 8
883
              + sec_info->entry[mid].lsda_offset)))
884
    return (bfd_vma) -2;
885
 
886
  return (offset + sec_info->entry[mid].new_offset
887
          - sec_info->entry[mid].offset);
888
}
889
 
890
/* Write out .eh_frame section.  This is called with the relocated
891
   contents.  */
892
 
893
boolean
894
_bfd_elf_write_section_eh_frame (abfd, sec, ehdrsec, contents)
895
     bfd *abfd;
896
     asection *sec, *ehdrsec;
897
     bfd_byte *contents;
898
{
899
  struct eh_frame_sec_info *sec_info;
900
  struct eh_frame_hdr_info *hdr_info;
901
  unsigned int i;
902
  bfd_byte *p, *buf;
903
  unsigned int leb128_tmp;
904
  unsigned int cie_offset = 0;
905
  unsigned int ptr_size;
906
 
907
  ptr_size = (elf_elfheader (sec->owner)->e_ident[EI_CLASS]
908
              == ELFCLASS64) ? 8 : 4;
909
 
910
  if (elf_section_data (sec)->sec_info_type != ELF_INFO_TYPE_EH_FRAME)
911
    return bfd_set_section_contents (abfd, sec->output_section,
912
                                     contents,
913
                                     (file_ptr) sec->output_offset,
914
                                     sec->_raw_size);
915
  sec_info = (struct eh_frame_sec_info *)
916
             elf_section_data (sec)->sec_info;
917
  hdr_info = NULL;
918
  if (ehdrsec
919
      && (elf_section_data (ehdrsec)->sec_info_type
920
          == ELF_INFO_TYPE_EH_FRAME_HDR))
921
    {
922
      hdr_info = (struct eh_frame_hdr_info *)
923
                 elf_section_data (ehdrsec)->sec_info;
924
      if (hdr_info->table && hdr_info->array == NULL)
925
        hdr_info->array
926
          = bfd_malloc (hdr_info->fde_count * sizeof(*hdr_info->array));
927
      if (hdr_info->array == NULL)
928
        hdr_info = NULL;
929
    }
930
 
931
  p = contents;
932
  for (i = 0; i < sec_info->count; ++i)
933
    {
934
      if (sec_info->entry[i].removed)
935
        {
936
          if (sec_info->entry[i].cie)
937
            {
938
              /* If CIE is removed due to no remaining FDEs referencing it
939
                 and there were no CIEs kept before it, sec_info->entry[i].sec
940
                 will be zero.  */
941
              if (sec_info->entry[i].sec == NULL)
942
                cie_offset = 0;
943
              else
944
                {
945
                  cie_offset = sec_info->entry[i].new_offset;
946
                  cie_offset += (sec_info->entry[i].sec->output_section->vma
947
                                 + sec_info->entry[i].sec->output_offset
948
                                 - sec->output_section->vma
949
                                 - sec->output_offset);
950
                }
951
            }
952
          continue;
953
        }
954
 
955
      if (sec_info->entry[i].cie)
956
        {
957
          /* CIE */
958
          cie_offset = sec_info->entry[i].new_offset;
959
          if (sec_info->entry[i].make_relative
960
              || sec_info->entry[i].make_lsda_relative
961
              || sec_info->entry[i].per_encoding_relative)
962
            {
963
              unsigned char *aug;
964
              unsigned int action;
965
              unsigned int dummy, per_width, per_encoding;
966
 
967
              /* Need to find 'R' or 'L' augmentation's argument and modify
968
                 DW_EH_PE_* value.  */
969
              action = (sec_info->entry[i].make_relative ? 1 : 0)
970
                       | (sec_info->entry[i].make_lsda_relative ? 2 : 0)
971
                       | (sec_info->entry[i].per_encoding_relative ? 4 : 0);
972
              buf = contents + sec_info->entry[i].offset;
973
              /* Skip length, id and version.  */
974
              buf += 9;
975
              aug = buf;
976
              buf = strchr (buf, '\0') + 1;
977
              read_uleb128 (dummy, buf);
978
              read_sleb128 (dummy, buf);
979
              read_uleb128 (dummy, buf);
980
              if (*aug == 'z')
981
                {
982
                  read_uleb128 (dummy, buf);
983
                  aug++;
984
                }
985
 
986
              while (action)
987
                switch (*aug++)
988
                  {
989
                  case 'L':
990
                    if (action & 2)
991
                      {
992
                        BFD_ASSERT (*buf == sec_info->entry[i].lsda_encoding);
993
                        *buf |= DW_EH_PE_pcrel;
994
                        action &= ~2;
995
                      }
996
                    buf++;
997
                    break;
998
                  case 'P':
999
                    per_encoding = *buf++;
1000
                    per_width = get_DW_EH_PE_width (per_encoding,
1001
                                                    ptr_size);
1002
                    BFD_ASSERT (per_width != 0);
1003
                    BFD_ASSERT (((per_encoding & 0x70) == DW_EH_PE_pcrel)
1004
                                == sec_info->entry[i].per_encoding_relative);
1005
                    if ((per_encoding & 0xf0) == DW_EH_PE_aligned)
1006
                      buf = (contents
1007
                             + ((buf - contents + per_width - 1)
1008
                                & ~((bfd_size_type) per_width - 1)));
1009
                    if (action & 4)
1010
                      {
1011
                        bfd_vma value;
1012
 
1013
                        value = read_value (abfd, buf, per_width);
1014
                        value += (sec_info->entry[i].offset
1015
                                  - sec_info->entry[i].new_offset);
1016
                        write_value (abfd, buf, value, per_width);
1017
                        action &= ~4;
1018
                      }
1019
                    buf += per_width;
1020
                    break;
1021
                  case 'R':
1022
                    if (action & 1)
1023
                      {
1024
                        BFD_ASSERT (*buf == sec_info->entry[i].fde_encoding);
1025
                        *buf |= DW_EH_PE_pcrel;
1026
                        action &= ~1;
1027
                      }
1028
                    buf++;
1029
                    break;
1030
                  default:
1031
                    BFD_FAIL ();
1032
                  }
1033
            }
1034
        }
1035
      else if (sec_info->entry[i].size > 4)
1036
        {
1037
          /* FDE */
1038
          bfd_vma value = 0, address;
1039
          unsigned int width;
1040
 
1041
          buf = contents + sec_info->entry[i].offset;
1042
          /* Skip length.  */
1043
          buf += 4;
1044
          bfd_put_32 (abfd,
1045
                      sec_info->entry[i].new_offset + 4 - cie_offset, buf);
1046
          buf += 4;
1047
          width = get_DW_EH_PE_width (sec_info->entry[i].fde_encoding,
1048
                                      ptr_size);
1049
          address = value = read_value (abfd, buf, width);
1050
          if (value)
1051
            {
1052
              switch (sec_info->entry[i].fde_encoding & 0xf0)
1053
                {
1054
                case DW_EH_PE_indirect:
1055
                case DW_EH_PE_textrel:
1056
                  BFD_ASSERT (hdr_info == NULL);
1057
                  break;
1058
                case DW_EH_PE_datarel:
1059
                  {
1060
                    asection *got = bfd_get_section_by_name (abfd, ".got");
1061
 
1062
                    BFD_ASSERT (got != NULL);
1063
                    address += got->vma;
1064
                  }
1065
                  break;
1066
                case DW_EH_PE_pcrel:
1067
                  value += (sec_info->entry[i].offset
1068
                            - sec_info->entry[i].new_offset);
1069
                  address += (sec->output_section->vma + sec->output_offset
1070
                              + sec_info->entry[i].offset + 8);
1071
                  break;
1072
                }
1073
              if (sec_info->entry[i].make_relative)
1074
                value -= (sec->output_section->vma + sec->output_offset
1075
                          + sec_info->entry[i].new_offset + 8);
1076
              write_value (abfd, buf, value, width);
1077
            }
1078
 
1079
          if (hdr_info)
1080
            {
1081
              hdr_info->array[hdr_info->array_count].initial_loc = address;
1082
              hdr_info->array[hdr_info->array_count++].fde
1083
                = (sec->output_section->vma + sec->output_offset
1084
                   + sec_info->entry[i].new_offset);
1085
            }
1086
 
1087
          if ((sec_info->entry[i].lsda_encoding & 0xf0) == DW_EH_PE_pcrel
1088
              || sec_info->entry[i].make_lsda_relative)
1089
            {
1090
              buf += sec_info->entry[i].lsda_offset;
1091
              width = get_DW_EH_PE_width (sec_info->entry[i].lsda_encoding,
1092
                                          ptr_size);
1093
              value = read_value (abfd, buf, width);
1094
              if (value)
1095
                {
1096
                  if ((sec_info->entry[i].lsda_encoding & 0xf0)
1097
                      == DW_EH_PE_pcrel)
1098
                    value += (sec_info->entry[i].offset
1099
                              - sec_info->entry[i].new_offset);
1100
                  else if (sec_info->entry[i].make_lsda_relative)
1101
                    value -= (sec->output_section->vma + sec->output_offset
1102
                              + sec_info->entry[i].new_offset + 8
1103
                              + sec_info->entry[i].lsda_offset);
1104
                  write_value (abfd, buf, value, width);
1105
                }
1106
            }
1107
        }
1108
      else
1109
        /* Terminating FDE must be at the end of .eh_frame section only.  */
1110
        BFD_ASSERT (i == sec_info->count - 1);
1111
 
1112
      BFD_ASSERT (p == contents + sec_info->entry[i].new_offset);
1113
      memmove (p, contents + sec_info->entry[i].offset,
1114
               sec_info->entry[i].size);
1115
      p += sec_info->entry[i].size;
1116
    }
1117
 
1118
  /* FIXME: Once _bfd_elf_discard_section_eh_frame will be able to
1119
     shrink sections to zero size, this won't be needed any more.  */
1120
  if (p == contents && sec->_cooked_size == 16)
1121
    {
1122
      bfd_put_32 (abfd, 12, p);         /* Fake CIE length */
1123
      bfd_put_32 (abfd, 0, p + 4);       /* Fake CIE id */
1124
      p[8] = 1;                         /* Fake CIE version */
1125
      memset (p + 9, 0, 7);              /* Fake CIE augmentation, 3xleb128
1126
                                           and 3xDW_CFA_nop as pad  */
1127
      p += 16;
1128
    }
1129
 
1130
  BFD_ASSERT ((bfd_size_type) (p - contents) == sec->_cooked_size);
1131
 
1132
  return bfd_set_section_contents (abfd, sec->output_section,
1133
                                   contents, (file_ptr) sec->output_offset,
1134
                                   sec->_cooked_size);
1135
}
1136
 
1137
/* Helper function used to sort .eh_frame_hdr search table by increasing
1138
   VMA of FDE initial location.  */
1139
 
1140
static int
1141
vma_compare (a, b)
1142
     const PTR a;
1143
     const PTR b;
1144
{
1145
  struct eh_frame_array_ent *p = (struct eh_frame_array_ent *) a;
1146
  struct eh_frame_array_ent *q = (struct eh_frame_array_ent *) b;
1147
  if (p->initial_loc > q->initial_loc)
1148
    return 1;
1149
  if (p->initial_loc < q->initial_loc)
1150
    return -1;
1151
  return 0;
1152
}
1153
 
1154
/* Write out .eh_frame_hdr section.  This must be called after
1155
   _bfd_elf_write_section_eh_frame has been called on all input
1156
   .eh_frame sections.
1157
   .eh_frame_hdr format:
1158
   ubyte version                (currently 1)
1159
   ubyte eh_frame_ptr_enc       (DW_EH_PE_* encoding of pointer to start of
1160
                                 .eh_frame section)
1161
   ubyte fde_count_enc          (DW_EH_PE_* encoding of total FDE count
1162
                                 number (or DW_EH_PE_omit if there is no
1163
                                 binary search table computed))
1164
   ubyte table_enc              (DW_EH_PE_* encoding of binary search table,
1165
                                 or DW_EH_PE_omit if not present.
1166
                                 DW_EH_PE_datarel is using address of
1167
                                 .eh_frame_hdr section start as base)
1168
   [encoded] eh_frame_ptr       (pointer to start of .eh_frame section)
1169
   optionally followed by:
1170
   [encoded] fde_count          (total number of FDEs in .eh_frame section)
1171
   fde_count x [encoded] initial_loc, fde
1172
                                (array of encoded pairs containing
1173
                                 FDE initial_location field and FDE address,
1174
                                 sorted by increasing initial_loc)  */
1175
 
1176
boolean
1177
_bfd_elf_write_section_eh_frame_hdr (abfd, sec)
1178
     bfd *abfd;
1179
     asection *sec;
1180
{
1181
  struct eh_frame_hdr_info *hdr_info;
1182
  unsigned int ptr_size;
1183
  bfd_byte *contents;
1184
  asection *eh_frame_sec;
1185
  bfd_size_type size;
1186
 
1187
  ptr_size = (elf_elfheader (sec->owner)->e_ident[EI_CLASS]
1188
              == ELFCLASS64) ? 8 : 4;
1189
 
1190
  BFD_ASSERT (elf_section_data (sec)->sec_info_type
1191
              == ELF_INFO_TYPE_EH_FRAME_HDR);
1192
  hdr_info = (struct eh_frame_hdr_info *)
1193
             elf_section_data (sec)->sec_info;
1194
  if (hdr_info->strip)
1195
    return true;
1196
 
1197
  size = EH_FRAME_HDR_SIZE;
1198
  if (hdr_info->array && hdr_info->array_count == hdr_info->fde_count)
1199
    size += 4 + hdr_info->fde_count * 8;
1200
  contents = bfd_malloc (size);
1201
  if (contents == NULL)
1202
    return false;
1203
 
1204
  eh_frame_sec = bfd_get_section_by_name (abfd, ".eh_frame");
1205
  if (eh_frame_sec == NULL)
1206
    return false;
1207
 
1208
  memset (contents, 0, EH_FRAME_HDR_SIZE);
1209
  contents[0] = 1;                               /* Version  */
1210
  contents[1] = DW_EH_PE_pcrel | DW_EH_PE_sdata4; /* .eh_frame offset  */
1211
  if (hdr_info->array && hdr_info->array_count == hdr_info->fde_count)
1212
    {
1213
      contents[2] = DW_EH_PE_udata4;            /* FDE count encoding  */
1214
      contents[3] = DW_EH_PE_datarel | DW_EH_PE_sdata4; /* search table enc  */
1215
    }
1216
  else
1217
    {
1218
      contents[2] = DW_EH_PE_omit;
1219
      contents[3] = DW_EH_PE_omit;
1220
    }
1221
  bfd_put_32 (abfd, eh_frame_sec->vma - sec->output_section->vma - 4,
1222
              contents + 4);
1223
  if (contents[2] != DW_EH_PE_omit)
1224
    {
1225
      unsigned int i;
1226
 
1227
      bfd_put_32 (abfd, hdr_info->fde_count, contents + EH_FRAME_HDR_SIZE);
1228
      qsort (hdr_info->array, hdr_info->fde_count, sizeof (*hdr_info->array),
1229
             vma_compare);
1230
      for (i = 0; i < hdr_info->fde_count; i++)
1231
        {
1232
          bfd_put_32 (abfd,
1233
                      hdr_info->array[i].initial_loc
1234
                      - sec->output_section->vma,
1235
                      contents + EH_FRAME_HDR_SIZE + i * 8 + 4);
1236
          bfd_put_32 (abfd,
1237
                      hdr_info->array[i].fde - sec->output_section->vma,
1238
                      contents + EH_FRAME_HDR_SIZE + i * 8 + 8);
1239
        }
1240
    }
1241
 
1242
  return bfd_set_section_contents (abfd, sec->output_section,
1243
                                   contents, (file_ptr) sec->output_offset,
1244
                                   sec->_cooked_size);
1245
}

powered by: WebSVN 2.1.0

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