~ubuntu-branches/ubuntu/quantal/gclcvs/quantal

« back to all changes in this revision

Viewing changes to binutils/bfd/elf-eh-frame.c

  • Committer: Bazaar Package Importer
  • Author(s): Camm Maguire
  • Date: 2004-06-24 15:13:46 UTC
  • Revision ID: james.westby@ubuntu.com-20040624151346-xh0xaaktyyp7aorc
Tags: 2.7.0-26
C_GC_OFFSET is 2 on m68k-linux

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* .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) (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
          read_uleb128 (cie.ra_column, buf);
 
510
          ENSURE_NO_RELOCS (buf);
 
511
          cie.lsda_encoding = DW_EH_PE_omit;
 
512
          cie.fde_encoding = DW_EH_PE_omit;
 
513
          cie.per_encoding = DW_EH_PE_omit;
 
514
          aug = cie.augmentation;
 
515
          if (aug[0] != 'e' || aug[1] != 'h')
 
516
            {
 
517
              if (*aug == 'z')
 
518
                {
 
519
                  aug++;
 
520
                  read_uleb128 (cie.augmentation_size, buf);
 
521
                  ENSURE_NO_RELOCS (buf);
 
522
                }
 
523
 
 
524
              while (*aug != '\0')
 
525
                switch (*aug++)
 
526
                  {
 
527
                  case 'L':
 
528
                    cie.lsda_encoding = *buf++;
 
529
                    ENSURE_NO_RELOCS (buf);
 
530
                    if (get_DW_EH_PE_width (cie.lsda_encoding, ptr_size) == 0)
 
531
                      goto free_no_table;
 
532
                    break;
 
533
                  case 'R':
 
534
                    cie.fde_encoding = *buf++;
 
535
                    ENSURE_NO_RELOCS (buf);
 
536
                    if (get_DW_EH_PE_width (cie.fde_encoding, ptr_size) == 0)
 
537
                      goto free_no_table;
 
538
                    break;
 
539
                  case 'P':
 
540
                    {
 
541
                      int per_width;
 
542
 
 
543
                      cie.per_encoding = *buf++;
 
544
                      per_width = get_DW_EH_PE_width (cie.per_encoding,
 
545
                                                      ptr_size);
 
546
                      if (per_width == 0)
 
547
                        goto free_no_table;
 
548
                      if ((cie.per_encoding & 0xf0) == DW_EH_PE_aligned)
 
549
                        buf = (ehbuf
 
550
                               + ((buf - ehbuf + per_width - 1)
 
551
                                  & ~((bfd_size_type) per_width - 1)));
 
552
                      ENSURE_NO_RELOCS (buf);
 
553
                      rel = GET_RELOC (buf);
 
554
                      /* Ensure we have a reloc here, against
 
555
                         a global symbol.  */
 
556
                      if (rel != NULL)
 
557
                        {
 
558
                          unsigned long r_symndx;
 
559
 
 
560
#ifdef BFD64
 
561
                          if (ptr_size == 8)
 
562
                            r_symndx = ELF64_R_SYM (cookie->rel->r_info);
 
563
                          else
 
564
#endif
 
565
                            r_symndx = ELF32_R_SYM (cookie->rel->r_info);
 
566
                          if (r_symndx >= cookie->locsymcount)
 
567
                            {
 
568
                              struct elf_link_hash_entry *h;
 
569
 
 
570
                              r_symndx -= cookie->extsymoff;
 
571
                              h = cookie->sym_hashes[r_symndx];
 
572
 
 
573
                              while (h->root.type == bfd_link_hash_indirect
 
574
                                     || h->root.type == bfd_link_hash_warning)
 
575
                                h = (struct elf_link_hash_entry *)
 
576
                                    h->root.u.i.link;
 
577
 
 
578
                              cie.personality = h;
 
579
                            }
 
580
                          cookie->rel++;
 
581
                        }
 
582
                      buf += per_width;
 
583
                    }
 
584
                    break;
 
585
                  default:
 
586
                    /* Unrecognized augmentation. Better bail out.  */
 
587
                    goto free_no_table;
 
588
                  }
 
589
            }
 
590
 
 
591
          /* For shared libraries, try to get rid of as many RELATIVE relocs
 
592
             as possible.  */
 
593
          if (info->shared
 
594
              && (cie.fde_encoding & 0xf0) == DW_EH_PE_absptr)
 
595
            cie.make_relative = 1;
 
596
 
 
597
          if (info->shared
 
598
              && (cie.lsda_encoding & 0xf0) == DW_EH_PE_absptr)
 
599
            cie.make_lsda_relative = 1;
 
600
 
 
601
          /* If FDE encoding was not specified, it defaults to
 
602
             DW_EH_absptr.  */
 
603
          if (cie.fde_encoding == DW_EH_PE_omit)
 
604
            cie.fde_encoding = DW_EH_PE_absptr;
 
605
 
 
606
          initial_insn_length = cie.hdr.length - (buf - last_fde - 4);
 
607
          if (initial_insn_length <= 50)
 
608
            {
 
609
              cie.initial_insn_length = initial_insn_length;
 
610
              memcpy (cie.initial_instructions, buf, initial_insn_length);
 
611
            }
 
612
          buf += initial_insn_length;
 
613
          ENSURE_NO_RELOCS (buf);
 
614
          last_cie = last_fde;
 
615
        }
 
616
      else
 
617
        {
 
618
          /* Ensure this FDE uses the last CIE encountered.  */
 
619
          if (last_cie == NULL
 
620
              || hdr.id != (unsigned int) (buf - 4 - last_cie))
 
621
            goto free_no_table;
 
622
 
 
623
          ENSURE_NO_RELOCS (buf);
 
624
          rel = GET_RELOC (buf);
 
625
          if (rel == NULL)
 
626
            /* This should not happen.  */
 
627
            goto free_no_table;
 
628
          if ((*reloc_symbol_deleted_p) (buf - ehbuf, cookie))
 
629
            {
 
630
              cookie->rel = rel;
 
631
              /* This is a FDE against discarded section, it should
 
632
                 be deleted.  */
 
633
              new_size -= hdr.length + 4;
 
634
              sec_info->entry[sec_info->count].removed = 1;
 
635
            }
 
636
          else
 
637
            {
 
638
              if (info->shared
 
639
                  && (((cie.fde_encoding & 0xf0) == DW_EH_PE_absptr
 
640
                       && cie.make_relative == 0)
 
641
                      || (cie.fde_encoding & 0xf0) == DW_EH_PE_aligned))
 
642
                {
 
643
                  /* If shared library uses absolute pointers
 
644
                     which we cannot turn into PC relative,
 
645
                     don't create the binary search table,
 
646
                     since it is affected by runtime relocations.  */
 
647
                  hdr_info->table = false;
 
648
                }
 
649
              cie_usage_count++;
 
650
              hdr_info->fde_count++;
 
651
            }
 
652
          cookie->rel = rel;
 
653
          if (cie.lsda_encoding != DW_EH_PE_omit)
 
654
            {
 
655
              unsigned int dummy;
 
656
 
 
657
              aug = buf;
 
658
              buf += 2 * get_DW_EH_PE_width (cie.fde_encoding, ptr_size);
 
659
              if (cie.augmentation[0] == 'z')
 
660
                read_uleb128 (dummy, buf);
 
661
              /* If some new augmentation data is added before LSDA
 
662
                 in FDE augmentation area, this need to be adjusted.  */
 
663
              sec_info->entry[sec_info->count].lsda_offset = (buf - aug);
 
664
            }
 
665
          buf = last_fde + 4 + hdr.length;
 
666
          SKIP_RELOCS (buf);
 
667
        }
 
668
 
 
669
      sec_info->entry[sec_info->count].fde_encoding = cie.fde_encoding;
 
670
      sec_info->entry[sec_info->count].lsda_encoding = cie.lsda_encoding;
 
671
      sec_info->count++;
 
672
    }
 
673
 
 
674
  elf_section_data (sec)->sec_info = sec_info;
 
675
  elf_section_data (sec)->sec_info_type = ELF_INFO_TYPE_EH_FRAME;
 
676
 
 
677
  /* Ok, now we can assign new offsets.  */
 
678
  offset = 0;
 
679
  last_cie_ndx = 0;
 
680
  for (i = 0; i < sec_info->count; i++)
 
681
    {
 
682
      if (! sec_info->entry[i].removed)
 
683
        {
 
684
          sec_info->entry[i].new_offset = offset;
 
685
          offset += sec_info->entry[i].size;
 
686
          if (sec_info->entry[i].cie)
 
687
            {
 
688
              last_cie_ndx = i;
 
689
              make_relative = sec_info->entry[i].make_relative;
 
690
              make_lsda_relative = sec_info->entry[i].make_lsda_relative;
 
691
            }
 
692
          else
 
693
            {
 
694
              sec_info->entry[i].make_relative = make_relative;
 
695
              sec_info->entry[i].make_lsda_relative = make_lsda_relative;
 
696
              sec_info->entry[i].per_encoding_relative = 0;
 
697
            }
 
698
        }
 
699
      else if (sec_info->entry[i].cie && sec_info->entry[i].sec == sec)
 
700
        {
 
701
          /* Need to adjust new_offset too.  */
 
702
          BFD_ASSERT (sec_info->entry[last_cie_ndx].offset
 
703
                      == sec_info->entry[i].new_offset);
 
704
          sec_info->entry[i].new_offset
 
705
            = sec_info->entry[last_cie_ndx].new_offset;
 
706
        }
 
707
    }
 
708
  if (hdr_info->last_cie_sec == sec)
 
709
    {
 
710
      BFD_ASSERT (sec_info->entry[last_cie_ndx].offset
 
711
                  == hdr_info->last_cie_offset);
 
712
      hdr_info->last_cie_offset = sec_info->entry[last_cie_ndx].new_offset;
 
713
    }
 
714
 
 
715
  /* FIXME: Currently it is not possible to shrink sections to zero size at
 
716
     this point, so build a fake minimal CIE.  */
 
717
  if (new_size == 0)
 
718
    new_size = 16;
 
719
 
 
720
  /* Shrink the sec as needed.  */
 
721
  sec->_cooked_size = new_size;
 
722
  if (sec->_cooked_size == 0)
 
723
    sec->flags |= SEC_EXCLUDE;
 
724
 
 
725
  free (ehbuf);
 
726
  return new_size != sec->_raw_size;
 
727
 
 
728
free_no_table:
 
729
  if (ehbuf)
 
730
    free (ehbuf);
 
731
  if (sec_info)
 
732
    free (sec_info);
 
733
  hdr_info->table = false;
 
734
  hdr_info->last_cie.hdr.length = 0;
 
735
  return false;
 
736
}
 
737
 
 
738
/* This function is called for .eh_frame_hdr section after
 
739
   _bfd_elf_discard_section_eh_frame has been called on all .eh_frame
 
740
   input sections.  It finalizes the size of .eh_frame_hdr section.  */
 
741
 
 
742
boolean
 
743
_bfd_elf_discard_section_eh_frame_hdr (abfd, info, sec)
 
744
     bfd *abfd;
 
745
     struct bfd_link_info *info;
 
746
     asection *sec;
 
747
{
 
748
  struct eh_frame_hdr_info *hdr_info;
 
749
  unsigned int ptr_size;
 
750
 
 
751
  ptr_size = (elf_elfheader (abfd)->e_ident[EI_CLASS]
 
752
              == ELFCLASS64) ? 8 : 4;
 
753
 
 
754
  if ((elf_section_data (sec)->sec_info_type
 
755
       != ELF_INFO_TYPE_EH_FRAME_HDR)
 
756
      || ! info->eh_frame_hdr)
 
757
    {
 
758
      _bfd_strip_section_from_output (info, sec);
 
759
      return false;
 
760
    }
 
761
 
 
762
  hdr_info = (struct eh_frame_hdr_info *)
 
763
             elf_section_data (sec)->sec_info;
 
764
  if (hdr_info->strip)
 
765
    return false;
 
766
  sec->_cooked_size = EH_FRAME_HDR_SIZE;
 
767
  if (hdr_info->table)
 
768
    sec->_cooked_size += 4 + hdr_info->fde_count * 8;
 
769
 
 
770
  /* Request program headers to be recalculated.  */
 
771
  elf_tdata (abfd)->program_header_size = 0;
 
772
  elf_tdata (abfd)->eh_frame_hdr = true;
 
773
  return true;
 
774
}
 
775
 
 
776
/* This function is called from size_dynamic_sections.
 
777
   It needs to decide whether .eh_frame_hdr should be output or not,
 
778
   because later on it is too late for calling _bfd_strip_section_from_output,
 
779
   since dynamic symbol table has been sized.  */
 
780
 
 
781
boolean
 
782
_bfd_elf_maybe_strip_eh_frame_hdr (info)
 
783
     struct bfd_link_info *info;
 
784
{
 
785
  asection *sec, *o;
 
786
  bfd *abfd;
 
787
  struct eh_frame_hdr_info *hdr_info;
 
788
 
 
789
  sec = bfd_get_section_by_name (elf_hash_table (info)->dynobj, ".eh_frame_hdr");
 
790
  if (sec == NULL || bfd_is_abs_section (sec->output_section))
 
791
    return true;
 
792
 
 
793
  hdr_info
 
794
    = bfd_zmalloc (sizeof (struct eh_frame_hdr_info));
 
795
  if (hdr_info == NULL)
 
796
    return false;
 
797
 
 
798
  elf_section_data (sec)->sec_info = hdr_info;
 
799
  elf_section_data (sec)->sec_info_type = ELF_INFO_TYPE_EH_FRAME_HDR;
 
800
 
 
801
  abfd = NULL;
 
802
  if (info->eh_frame_hdr)
 
803
    for (abfd = info->input_bfds; abfd != NULL; abfd = abfd->link_next)
 
804
      {
 
805
        /* Count only sections which have at least a single CIE or FDE.
 
806
           There cannot be any CIE or FDE <= 8 bytes.  */
 
807
        o = bfd_get_section_by_name (abfd, ".eh_frame");
 
808
        if (o && o->_raw_size > 8 && !bfd_is_abs_section (o->output_section))
 
809
          break;
 
810
      }
 
811
 
 
812
  if (abfd == NULL)
 
813
    {
 
814
      _bfd_strip_section_from_output (info, sec);
 
815
      hdr_info->strip = true;
 
816
    }
 
817
  else
 
818
    hdr_info->table = true;
 
819
  return true;
 
820
}
 
821
 
 
822
/* Adjust an address in the .eh_frame section.  Given OFFSET within
 
823
   SEC, this returns the new offset in the adjusted .eh_frame section,
 
824
   or -1 if the address refers to a CIE/FDE which has been removed
 
825
   or to offset with dynamic relocation which is no longer needed.  */
 
826
 
 
827
bfd_vma
 
828
_bfd_elf_eh_frame_section_offset (output_bfd, sec, offset)
 
829
     bfd *output_bfd ATTRIBUTE_UNUSED;
 
830
     asection *sec;
 
831
     bfd_vma offset;
 
832
{
 
833
  struct eh_frame_sec_info *sec_info;
 
834
  unsigned int lo, hi, mid;
 
835
 
 
836
  if (elf_section_data (sec)->sec_info_type != ELF_INFO_TYPE_EH_FRAME)
 
837
    return offset;
 
838
  sec_info = (struct eh_frame_sec_info *)
 
839
             elf_section_data (sec)->sec_info;
 
840
 
 
841
  if (offset >= sec->_raw_size)
 
842
    return offset - (sec->_cooked_size - sec->_raw_size);
 
843
 
 
844
  lo = 0;
 
845
  hi = sec_info->count;
 
846
  mid = 0;
 
847
  while (lo < hi)
 
848
    {
 
849
      mid = (lo + hi) / 2;
 
850
      if (offset < sec_info->entry[mid].offset)
 
851
        hi = mid;
 
852
      else if (offset
 
853
               >= sec_info->entry[mid].offset + sec_info->entry[mid].size)
 
854
        lo = mid + 1;
 
855
      else
 
856
        break;
 
857
    }
 
858
 
 
859
  BFD_ASSERT (lo < hi);
 
860
 
 
861
  /* FDE or CIE was removed.  */
 
862
  if (sec_info->entry[mid].removed)
 
863
    return (bfd_vma) -1;
 
864
 
 
865
  /* If converting to DW_EH_PE_pcrel, there will be no need for run-time
 
866
     relocation against FDE's initial_location field.  */
 
867
  if (sec_info->entry[mid].make_relative
 
868
      && ! sec_info->entry[mid].cie
 
869
      && offset == sec_info->entry[mid].offset + 8)
 
870
    return (bfd_vma) -2;
 
871
 
 
872
  /* If converting LSDA pointers to DW_EH_PE_pcrel, there will be no need
 
873
     for run-time relocation against LSDA field.  */
 
874
  if (sec_info->entry[mid].make_lsda_relative
 
875
      && ! sec_info->entry[mid].cie
 
876
      && (offset
 
877
          == (sec_info->entry[mid].offset + 8
 
878
              + sec_info->entry[mid].lsda_offset)))
 
879
    return (bfd_vma) -2;
 
880
 
 
881
  return (offset + sec_info->entry[mid].new_offset
 
882
          - sec_info->entry[mid].offset);
 
883
}
 
884
 
 
885
/* Write out .eh_frame section.  This is called with the relocated
 
886
   contents.  */
 
887
 
 
888
boolean
 
889
_bfd_elf_write_section_eh_frame (abfd, sec, ehdrsec, contents)
 
890
     bfd *abfd;
 
891
     asection *sec, *ehdrsec;
 
892
     bfd_byte *contents;
 
893
{
 
894
  struct eh_frame_sec_info *sec_info;
 
895
  struct eh_frame_hdr_info *hdr_info;
 
896
  unsigned int i;
 
897
  bfd_byte *p, *buf;
 
898
  unsigned int leb128_tmp;
 
899
  unsigned int cie_offset = 0;
 
900
  unsigned int ptr_size;
 
901
 
 
902
  ptr_size = (elf_elfheader (sec->owner)->e_ident[EI_CLASS]
 
903
              == ELFCLASS64) ? 8 : 4;
 
904
 
 
905
  if (elf_section_data (sec)->sec_info_type != ELF_INFO_TYPE_EH_FRAME)
 
906
    return bfd_set_section_contents (abfd, sec->output_section,
 
907
                                     contents,
 
908
                                     (file_ptr) sec->output_offset,
 
909
                                     sec->_raw_size);
 
910
  sec_info = (struct eh_frame_sec_info *)
 
911
             elf_section_data (sec)->sec_info;
 
912
  hdr_info = NULL;
 
913
  if (ehdrsec
 
914
      && (elf_section_data (ehdrsec)->sec_info_type
 
915
          == ELF_INFO_TYPE_EH_FRAME_HDR))
 
916
    {
 
917
      hdr_info = (struct eh_frame_hdr_info *)
 
918
                 elf_section_data (ehdrsec)->sec_info;
 
919
      if (hdr_info->table && hdr_info->array == NULL)
 
920
        hdr_info->array
 
921
          = bfd_malloc (hdr_info->fde_count * sizeof(*hdr_info->array));
 
922
      if (hdr_info->array == NULL)
 
923
        hdr_info = NULL;
 
924
    }
 
925
 
 
926
  p = contents;
 
927
  for (i = 0; i < sec_info->count; ++i)
 
928
    {
 
929
      if (sec_info->entry[i].removed)
 
930
        {
 
931
          if (sec_info->entry[i].cie)
 
932
            {
 
933
              /* If CIE is removed due to no remaining FDEs referencing it
 
934
                 and there were no CIEs kept before it, sec_info->entry[i].sec
 
935
                 will be zero.  */
 
936
              if (sec_info->entry[i].sec == NULL)
 
937
                cie_offset = 0;
 
938
              else
 
939
                {
 
940
                  cie_offset = sec_info->entry[i].new_offset;
 
941
                  cie_offset += (sec_info->entry[i].sec->output_section->vma
 
942
                                 + sec_info->entry[i].sec->output_offset
 
943
                                 - sec->output_section->vma
 
944
                                 - sec->output_offset);
 
945
                }
 
946
            }
 
947
          continue;
 
948
        }
 
949
 
 
950
      if (sec_info->entry[i].cie)
 
951
        {
 
952
          /* CIE */
 
953
          cie_offset = sec_info->entry[i].new_offset;
 
954
          if (sec_info->entry[i].make_relative
 
955
              || sec_info->entry[i].make_lsda_relative
 
956
              || sec_info->entry[i].per_encoding_relative)
 
957
            {
 
958
              unsigned char *aug;
 
959
              unsigned int action;
 
960
              unsigned int dummy, per_width, per_encoding;
 
961
 
 
962
              /* Need to find 'R' or 'L' augmentation's argument and modify
 
963
                 DW_EH_PE_* value.  */
 
964
              action = (sec_info->entry[i].make_relative ? 1 : 0)
 
965
                       | (sec_info->entry[i].make_lsda_relative ? 2 : 0)
 
966
                       | (sec_info->entry[i].per_encoding_relative ? 4 : 0);
 
967
              buf = contents + sec_info->entry[i].offset;
 
968
              /* Skip length, id and version.  */
 
969
              buf += 9;
 
970
              aug = buf;
 
971
              buf = strchr (buf, '\0') + 1;
 
972
              read_uleb128 (dummy, buf);
 
973
              read_sleb128 (dummy, buf);
 
974
              read_uleb128 (dummy, buf);
 
975
              if (*aug == 'z')
 
976
                {
 
977
                  read_uleb128 (dummy, buf);
 
978
                  aug++;
 
979
                }
 
980
 
 
981
              while (action)
 
982
                switch (*aug++)
 
983
                  {
 
984
                  case 'L':
 
985
                    if (action & 2)
 
986
                      {
 
987
                        BFD_ASSERT (*buf == sec_info->entry[i].lsda_encoding);
 
988
                        *buf |= DW_EH_PE_pcrel;
 
989
                        action &= ~2;
 
990
                      }
 
991
                    buf++;
 
992
                    break;
 
993
                  case 'P':
 
994
                    per_encoding = *buf++;
 
995
                    per_width = get_DW_EH_PE_width (per_encoding,
 
996
                                                    ptr_size);
 
997
                    BFD_ASSERT (per_width != 0);
 
998
                    BFD_ASSERT (((per_encoding & 0x70) == DW_EH_PE_pcrel)
 
999
                                == sec_info->entry[i].per_encoding_relative);
 
1000
                    if ((per_encoding & 0xf0) == DW_EH_PE_aligned)
 
1001
                      buf = (contents
 
1002
                             + ((buf - contents + per_width - 1)
 
1003
                                & ~((bfd_size_type) per_width - 1)));
 
1004
                    if (action & 4)
 
1005
                      {
 
1006
                        bfd_vma value;
 
1007
 
 
1008
                        value = read_value (abfd, buf, per_width);
 
1009
                        value += (sec_info->entry[i].offset
 
1010
                                  - sec_info->entry[i].new_offset);
 
1011
                        write_value (abfd, buf, value, per_width);
 
1012
                        action &= ~4;
 
1013
                      }
 
1014
                    buf += per_width;
 
1015
                    break;
 
1016
                  case 'R':
 
1017
                    if (action & 1)
 
1018
                      {
 
1019
                        BFD_ASSERT (*buf == sec_info->entry[i].fde_encoding);
 
1020
                        *buf |= DW_EH_PE_pcrel;
 
1021
                        action &= ~1;
 
1022
                      }
 
1023
                    buf++;
 
1024
                    break;
 
1025
                  default:
 
1026
                    BFD_FAIL ();
 
1027
                  }
 
1028
            }
 
1029
        }
 
1030
      else if (sec_info->entry[i].size > 4)
 
1031
        {
 
1032
          /* FDE */
 
1033
          bfd_vma value = 0, address;
 
1034
          unsigned int width;
 
1035
 
 
1036
          buf = contents + sec_info->entry[i].offset;
 
1037
          /* Skip length.  */   
 
1038
          buf += 4;
 
1039
          bfd_put_32 (abfd,
 
1040
                      sec_info->entry[i].new_offset + 4 - cie_offset, buf);
 
1041
          buf += 4;
 
1042
          width = get_DW_EH_PE_width (sec_info->entry[i].fde_encoding,
 
1043
                                      ptr_size);
 
1044
          address = value = read_value (abfd, buf, width);
 
1045
          if (value)
 
1046
            {
 
1047
              switch (sec_info->entry[i].fde_encoding & 0xf0)
 
1048
                {
 
1049
                case DW_EH_PE_indirect:
 
1050
                case DW_EH_PE_textrel:
 
1051
                  BFD_ASSERT (hdr_info == NULL);
 
1052
                  break;
 
1053
                case DW_EH_PE_datarel:
 
1054
                  {
 
1055
                    asection *got = bfd_get_section_by_name (abfd, ".got");
 
1056
 
 
1057
                    BFD_ASSERT (got != NULL);
 
1058
                    address += got->vma;
 
1059
                  }
 
1060
                  break;
 
1061
                case DW_EH_PE_pcrel:
 
1062
                  value += (sec_info->entry[i].offset
 
1063
                            - sec_info->entry[i].new_offset);
 
1064
                  address += (sec->output_section->vma + sec->output_offset
 
1065
                              + sec_info->entry[i].offset + 8);
 
1066
                  break;
 
1067
                }
 
1068
              if (sec_info->entry[i].make_relative)
 
1069
                value -= (sec->output_section->vma + sec->output_offset
 
1070
                          + sec_info->entry[i].new_offset + 8);
 
1071
              write_value (abfd, buf, value, width);
 
1072
            }
 
1073
 
 
1074
          if (hdr_info)
 
1075
            {
 
1076
              hdr_info->array[hdr_info->array_count].initial_loc = address;
 
1077
              hdr_info->array[hdr_info->array_count++].fde
 
1078
                = (sec->output_section->vma + sec->output_offset
 
1079
                   + sec_info->entry[i].new_offset);
 
1080
            }
 
1081
 
 
1082
          if ((sec_info->entry[i].lsda_encoding & 0xf0) == DW_EH_PE_pcrel
 
1083
              || sec_info->entry[i].make_lsda_relative)
 
1084
            {
 
1085
              buf += sec_info->entry[i].lsda_offset;
 
1086
              width = get_DW_EH_PE_width (sec_info->entry[i].lsda_encoding,
 
1087
                                          ptr_size);
 
1088
              value = read_value (abfd, buf, width);
 
1089
              if (value)
 
1090
                {
 
1091
                  if ((sec_info->entry[i].lsda_encoding & 0xf0)
 
1092
                      == DW_EH_PE_pcrel)
 
1093
                    value += (sec_info->entry[i].offset
 
1094
                              - sec_info->entry[i].new_offset);
 
1095
                  else if (sec_info->entry[i].make_lsda_relative)
 
1096
                    value -= (sec->output_section->vma + sec->output_offset
 
1097
                              + sec_info->entry[i].new_offset + 8
 
1098
                              + sec_info->entry[i].lsda_offset);
 
1099
                  write_value (abfd, buf, value, width);
 
1100
                }
 
1101
            }
 
1102
        }
 
1103
      else
 
1104
        /* Terminating FDE must be at the end of .eh_frame section only.  */
 
1105
        BFD_ASSERT (i == sec_info->count - 1);
 
1106
 
 
1107
      BFD_ASSERT (p == contents + sec_info->entry[i].new_offset);
 
1108
      memmove (p, contents + sec_info->entry[i].offset,
 
1109
               sec_info->entry[i].size);
 
1110
      p += sec_info->entry[i].size;
 
1111
    }
 
1112
 
 
1113
  /* FIXME: Once _bfd_elf_discard_section_eh_frame will be able to
 
1114
     shrink sections to zero size, this won't be needed any more.  */
 
1115
  if (p == contents && sec->_cooked_size == 16)
 
1116
    {
 
1117
      bfd_put_32 (abfd, 12, p);         /* Fake CIE length */
 
1118
      bfd_put_32 (abfd, 0, p + 4);      /* Fake CIE id */
 
1119
      p[8] = 1;                         /* Fake CIE version */
 
1120
      memset (p + 9, 0, 7);             /* Fake CIE augmentation, 3xleb128
 
1121
                                           and 3xDW_CFA_nop as pad  */
 
1122
      p += 16;
 
1123
    }
 
1124
 
 
1125
  BFD_ASSERT ((bfd_size_type) (p - contents) == sec->_cooked_size);
 
1126
 
 
1127
  return bfd_set_section_contents (abfd, sec->output_section,
 
1128
                                   contents, (file_ptr) sec->output_offset,
 
1129
                                   sec->_cooked_size);
 
1130
}
 
1131
 
 
1132
/* Helper function used to sort .eh_frame_hdr search table by increasing
 
1133
   VMA of FDE initial location.  */
 
1134
 
 
1135
static int
 
1136
vma_compare (a, b)
 
1137
     const PTR a;
 
1138
     const PTR b;
 
1139
{
 
1140
  struct eh_frame_array_ent *p = (struct eh_frame_array_ent *) a;
 
1141
  struct eh_frame_array_ent *q = (struct eh_frame_array_ent *) b;
 
1142
  if (p->initial_loc > q->initial_loc)
 
1143
    return 1;
 
1144
  if (p->initial_loc < q->initial_loc)
 
1145
    return -1;
 
1146
  return 0;
 
1147
}
 
1148
 
 
1149
/* Write out .eh_frame_hdr section.  This must be called after
 
1150
   _bfd_elf_write_section_eh_frame has been called on all input
 
1151
   .eh_frame sections.
 
1152
   .eh_frame_hdr format:
 
1153
   ubyte version                (currently 1)
 
1154
   ubyte eh_frame_ptr_enc       (DW_EH_PE_* encoding of pointer to start of
 
1155
                                 .eh_frame section)
 
1156
   ubyte fde_count_enc          (DW_EH_PE_* encoding of total FDE count
 
1157
                                 number (or DW_EH_PE_omit if there is no
 
1158
                                 binary search table computed))
 
1159
   ubyte table_enc              (DW_EH_PE_* encoding of binary search table,
 
1160
                                 or DW_EH_PE_omit if not present.
 
1161
                                 DW_EH_PE_datarel is using address of
 
1162
                                 .eh_frame_hdr section start as base)
 
1163
   [encoded] eh_frame_ptr       (pointer to start of .eh_frame section)
 
1164
   optionally followed by:
 
1165
   [encoded] fde_count          (total number of FDEs in .eh_frame section)
 
1166
   fde_count x [encoded] initial_loc, fde
 
1167
                                (array of encoded pairs containing
 
1168
                                 FDE initial_location field and FDE address,
 
1169
                                 sorted by increasing initial_loc)  */
 
1170
 
 
1171
boolean
 
1172
_bfd_elf_write_section_eh_frame_hdr (abfd, sec)
 
1173
     bfd *abfd;
 
1174
     asection *sec;
 
1175
{
 
1176
  struct eh_frame_hdr_info *hdr_info;
 
1177
  unsigned int ptr_size;
 
1178
  bfd_byte *contents;
 
1179
  asection *eh_frame_sec;
 
1180
  bfd_size_type size;
 
1181
 
 
1182
  ptr_size = (elf_elfheader (sec->owner)->e_ident[EI_CLASS]
 
1183
              == ELFCLASS64) ? 8 : 4;
 
1184
 
 
1185
  BFD_ASSERT (elf_section_data (sec)->sec_info_type
 
1186
              == ELF_INFO_TYPE_EH_FRAME_HDR);
 
1187
  hdr_info = (struct eh_frame_hdr_info *)
 
1188
             elf_section_data (sec)->sec_info;
 
1189
  if (hdr_info->strip)
 
1190
    return true;
 
1191
 
 
1192
  size = EH_FRAME_HDR_SIZE;
 
1193
  if (hdr_info->array && hdr_info->array_count == hdr_info->fde_count)
 
1194
    size += 4 + hdr_info->fde_count * 8;
 
1195
  contents = bfd_malloc (size);
 
1196
  if (contents == NULL)
 
1197
    return false;
 
1198
 
 
1199
  eh_frame_sec = bfd_get_section_by_name (abfd, ".eh_frame");
 
1200
  if (eh_frame_sec == NULL)
 
1201
    return false;
 
1202
 
 
1203
  memset (contents, 0, EH_FRAME_HDR_SIZE);
 
1204
  contents[0] = 1;                              /* Version  */
 
1205
  contents[1] = DW_EH_PE_pcrel | DW_EH_PE_sdata4; /* .eh_frame offset  */
 
1206
  if (hdr_info->array && hdr_info->array_count == hdr_info->fde_count)
 
1207
    {
 
1208
      contents[2] = DW_EH_PE_udata4;            /* FDE count encoding  */
 
1209
      contents[3] = DW_EH_PE_datarel | DW_EH_PE_sdata4; /* search table enc  */
 
1210
    }
 
1211
  else
 
1212
    {
 
1213
      contents[2] = DW_EH_PE_omit;
 
1214
      contents[3] = DW_EH_PE_omit;
 
1215
    }
 
1216
  bfd_put_32 (abfd, eh_frame_sec->vma - sec->output_section->vma - 4,
 
1217
              contents + 4);
 
1218
  if (contents[2] != DW_EH_PE_omit)
 
1219
    {
 
1220
      unsigned int i;
 
1221
 
 
1222
      bfd_put_32 (abfd, hdr_info->fde_count, contents + EH_FRAME_HDR_SIZE);
 
1223
      qsort (hdr_info->array, hdr_info->fde_count, sizeof (*hdr_info->array),
 
1224
             vma_compare);
 
1225
      for (i = 0; i < hdr_info->fde_count; i++)
 
1226
        {
 
1227
          bfd_put_32 (abfd,
 
1228
                      hdr_info->array[i].initial_loc
 
1229
                      - sec->output_section->vma,
 
1230
                      contents + EH_FRAME_HDR_SIZE + i * 8 + 4);
 
1231
          bfd_put_32 (abfd,
 
1232
                      hdr_info->array[i].fde - sec->output_section->vma,
 
1233
                      contents + EH_FRAME_HDR_SIZE + i * 8 + 8);
 
1234
        }
 
1235
    }
 
1236
 
 
1237
  return bfd_set_section_contents (abfd, sec->output_section,
 
1238
                                   contents, (file_ptr) sec->output_offset,
 
1239
                                   sec->_cooked_size);
 
1240
}