13d8817e4Smiod /* .eh_frame section optimization.
23d8817e4Smiod Copyright 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
33d8817e4Smiod Written by Jakub Jelinek <jakub@redhat.com>.
43d8817e4Smiod
53d8817e4Smiod This file is part of BFD, the Binary File Descriptor library.
63d8817e4Smiod
73d8817e4Smiod This program is free software; you can redistribute it and/or modify
83d8817e4Smiod it under the terms of the GNU General Public License as published by
93d8817e4Smiod the Free Software Foundation; either version 2 of the License, or
103d8817e4Smiod (at your option) any later version.
113d8817e4Smiod
123d8817e4Smiod This program is distributed in the hope that it will be useful,
133d8817e4Smiod but WITHOUT ANY WARRANTY; without even the implied warranty of
143d8817e4Smiod MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
153d8817e4Smiod GNU General Public License for more details.
163d8817e4Smiod
173d8817e4Smiod You should have received a copy of the GNU General Public License
183d8817e4Smiod along with this program; if not, write to the Free Software
193d8817e4Smiod Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */
203d8817e4Smiod
213d8817e4Smiod #include "bfd.h"
223d8817e4Smiod #include "sysdep.h"
233d8817e4Smiod #include "libbfd.h"
243d8817e4Smiod #include "elf-bfd.h"
253d8817e4Smiod #include "elf/dwarf2.h"
263d8817e4Smiod
273d8817e4Smiod #define EH_FRAME_HDR_SIZE 8
283d8817e4Smiod
29*fc67150aSkettenis struct cie
30*fc67150aSkettenis {
31*fc67150aSkettenis unsigned int length;
32*fc67150aSkettenis unsigned int hash;
33*fc67150aSkettenis unsigned char version;
34*fc67150aSkettenis char augmentation[20];
35*fc67150aSkettenis bfd_vma code_align;
36*fc67150aSkettenis bfd_signed_vma data_align;
37*fc67150aSkettenis bfd_vma ra_column;
38*fc67150aSkettenis bfd_vma augmentation_size;
39*fc67150aSkettenis struct elf_link_hash_entry *personality;
40*fc67150aSkettenis asection *output_sec;
41*fc67150aSkettenis struct eh_cie_fde *cie_inf;
42*fc67150aSkettenis unsigned char per_encoding;
43*fc67150aSkettenis unsigned char lsda_encoding;
44*fc67150aSkettenis unsigned char fde_encoding;
45*fc67150aSkettenis unsigned char initial_insn_length;
46*fc67150aSkettenis unsigned char make_relative;
47*fc67150aSkettenis unsigned char make_lsda_relative;
48*fc67150aSkettenis unsigned char initial_instructions[50];
49*fc67150aSkettenis };
50*fc67150aSkettenis
51*fc67150aSkettenis
52*fc67150aSkettenis
533d8817e4Smiod /* If *ITER hasn't reached END yet, read the next byte into *RESULT and
543d8817e4Smiod move onto the next byte. Return true on success. */
553d8817e4Smiod
563d8817e4Smiod static inline bfd_boolean
read_byte(bfd_byte ** iter,bfd_byte * end,unsigned char * result)573d8817e4Smiod read_byte (bfd_byte **iter, bfd_byte *end, unsigned char *result)
583d8817e4Smiod {
593d8817e4Smiod if (*iter >= end)
603d8817e4Smiod return FALSE;
613d8817e4Smiod *result = *((*iter)++);
623d8817e4Smiod return TRUE;
633d8817e4Smiod }
643d8817e4Smiod
653d8817e4Smiod /* Move *ITER over LENGTH bytes, or up to END, whichever is closer.
663d8817e4Smiod Return true it was possible to move LENGTH bytes. */
673d8817e4Smiod
683d8817e4Smiod static inline bfd_boolean
skip_bytes(bfd_byte ** iter,bfd_byte * end,bfd_size_type length)693d8817e4Smiod skip_bytes (bfd_byte **iter, bfd_byte *end, bfd_size_type length)
703d8817e4Smiod {
713d8817e4Smiod if ((bfd_size_type) (end - *iter) < length)
723d8817e4Smiod {
733d8817e4Smiod *iter = end;
743d8817e4Smiod return FALSE;
753d8817e4Smiod }
763d8817e4Smiod *iter += length;
773d8817e4Smiod return TRUE;
783d8817e4Smiod }
793d8817e4Smiod
803d8817e4Smiod /* Move *ITER over an leb128, stopping at END. Return true if the end
813d8817e4Smiod of the leb128 was found. */
823d8817e4Smiod
833d8817e4Smiod static bfd_boolean
skip_leb128(bfd_byte ** iter,bfd_byte * end)843d8817e4Smiod skip_leb128 (bfd_byte **iter, bfd_byte *end)
853d8817e4Smiod {
863d8817e4Smiod unsigned char byte;
873d8817e4Smiod do
883d8817e4Smiod if (!read_byte (iter, end, &byte))
893d8817e4Smiod return FALSE;
903d8817e4Smiod while (byte & 0x80);
913d8817e4Smiod return TRUE;
923d8817e4Smiod }
933d8817e4Smiod
943d8817e4Smiod /* Like skip_leb128, but treat the leb128 as an unsigned value and
953d8817e4Smiod store it in *VALUE. */
963d8817e4Smiod
973d8817e4Smiod static bfd_boolean
read_uleb128(bfd_byte ** iter,bfd_byte * end,bfd_vma * value)983d8817e4Smiod read_uleb128 (bfd_byte **iter, bfd_byte *end, bfd_vma *value)
993d8817e4Smiod {
1003d8817e4Smiod bfd_byte *start, *p;
1013d8817e4Smiod
1023d8817e4Smiod start = *iter;
1033d8817e4Smiod if (!skip_leb128 (iter, end))
1043d8817e4Smiod return FALSE;
1053d8817e4Smiod
1063d8817e4Smiod p = *iter;
1073d8817e4Smiod *value = *--p;
1083d8817e4Smiod while (p > start)
1093d8817e4Smiod *value = (*value << 7) | (*--p & 0x7f);
1103d8817e4Smiod
1113d8817e4Smiod return TRUE;
1123d8817e4Smiod }
1133d8817e4Smiod
1143d8817e4Smiod /* Like read_uleb128, but for signed values. */
1153d8817e4Smiod
1163d8817e4Smiod static bfd_boolean
read_sleb128(bfd_byte ** iter,bfd_byte * end,bfd_signed_vma * value)1173d8817e4Smiod read_sleb128 (bfd_byte **iter, bfd_byte *end, bfd_signed_vma *value)
1183d8817e4Smiod {
1193d8817e4Smiod bfd_byte *start, *p;
1203d8817e4Smiod
1213d8817e4Smiod start = *iter;
1223d8817e4Smiod if (!skip_leb128 (iter, end))
1233d8817e4Smiod return FALSE;
1243d8817e4Smiod
1253d8817e4Smiod p = *iter;
1263d8817e4Smiod *value = ((*--p & 0x7f) ^ 0x40) - 0x40;
1273d8817e4Smiod while (p > start)
1283d8817e4Smiod *value = (*value << 7) | (*--p & 0x7f);
1293d8817e4Smiod
1303d8817e4Smiod return TRUE;
1313d8817e4Smiod }
1323d8817e4Smiod
1333d8817e4Smiod /* Return 0 if either encoding is variable width, or not yet known to bfd. */
1343d8817e4Smiod
1353d8817e4Smiod static
get_DW_EH_PE_width(int encoding,int ptr_size)1363d8817e4Smiod int get_DW_EH_PE_width (int encoding, int ptr_size)
1373d8817e4Smiod {
1383d8817e4Smiod /* DW_EH_PE_ values of 0x60 and 0x70 weren't defined at the time .eh_frame
1393d8817e4Smiod was added to bfd. */
1403d8817e4Smiod if ((encoding & 0x60) == 0x60)
1413d8817e4Smiod return 0;
1423d8817e4Smiod
1433d8817e4Smiod switch (encoding & 7)
1443d8817e4Smiod {
1453d8817e4Smiod case DW_EH_PE_udata2: return 2;
1463d8817e4Smiod case DW_EH_PE_udata4: return 4;
1473d8817e4Smiod case DW_EH_PE_udata8: return 8;
1483d8817e4Smiod case DW_EH_PE_absptr: return ptr_size;
1493d8817e4Smiod default:
1503d8817e4Smiod break;
1513d8817e4Smiod }
1523d8817e4Smiod
1533d8817e4Smiod return 0;
1543d8817e4Smiod }
1553d8817e4Smiod
1563d8817e4Smiod #define get_DW_EH_PE_signed(encoding) (((encoding) & DW_EH_PE_signed) != 0)
1573d8817e4Smiod
1583d8817e4Smiod /* Read a width sized value from memory. */
1593d8817e4Smiod
1603d8817e4Smiod static bfd_vma
read_value(bfd * abfd,bfd_byte * buf,int width,int is_signed)1613d8817e4Smiod read_value (bfd *abfd, bfd_byte *buf, int width, int is_signed)
1623d8817e4Smiod {
1633d8817e4Smiod bfd_vma value;
1643d8817e4Smiod
1653d8817e4Smiod switch (width)
1663d8817e4Smiod {
1673d8817e4Smiod case 2:
1683d8817e4Smiod if (is_signed)
1693d8817e4Smiod value = bfd_get_signed_16 (abfd, buf);
1703d8817e4Smiod else
1713d8817e4Smiod value = bfd_get_16 (abfd, buf);
1723d8817e4Smiod break;
1733d8817e4Smiod case 4:
1743d8817e4Smiod if (is_signed)
1753d8817e4Smiod value = bfd_get_signed_32 (abfd, buf);
1763d8817e4Smiod else
1773d8817e4Smiod value = bfd_get_32 (abfd, buf);
1783d8817e4Smiod break;
1793d8817e4Smiod case 8:
1803d8817e4Smiod if (is_signed)
1813d8817e4Smiod value = bfd_get_signed_64 (abfd, buf);
1823d8817e4Smiod else
1833d8817e4Smiod value = bfd_get_64 (abfd, buf);
1843d8817e4Smiod break;
1853d8817e4Smiod default:
1863d8817e4Smiod BFD_FAIL ();
1873d8817e4Smiod return 0;
1883d8817e4Smiod }
1893d8817e4Smiod
1903d8817e4Smiod return value;
1913d8817e4Smiod }
1923d8817e4Smiod
1933d8817e4Smiod /* Store a width sized value to memory. */
1943d8817e4Smiod
1953d8817e4Smiod static void
write_value(bfd * abfd,bfd_byte * buf,bfd_vma value,int width)1963d8817e4Smiod write_value (bfd *abfd, bfd_byte *buf, bfd_vma value, int width)
1973d8817e4Smiod {
1983d8817e4Smiod switch (width)
1993d8817e4Smiod {
2003d8817e4Smiod case 2: bfd_put_16 (abfd, value, buf); break;
2013d8817e4Smiod case 4: bfd_put_32 (abfd, value, buf); break;
2023d8817e4Smiod case 8: bfd_put_64 (abfd, value, buf); break;
2033d8817e4Smiod default: BFD_FAIL ();
2043d8817e4Smiod }
2053d8817e4Smiod }
2063d8817e4Smiod
207*fc67150aSkettenis /* Return one if C1 and C2 CIEs can be merged. */
2083d8817e4Smiod
209*fc67150aSkettenis static int
cie_eq(const void * e1,const void * e2)210*fc67150aSkettenis cie_eq (const void *e1, const void *e2)
2113d8817e4Smiod {
212*fc67150aSkettenis const struct cie *c1 = e1;
213*fc67150aSkettenis const struct cie *c2 = e2;
214*fc67150aSkettenis
215*fc67150aSkettenis if (c1->hash == c2->hash
216*fc67150aSkettenis && c1->length == c2->length
2173d8817e4Smiod && c1->version == c2->version
2183d8817e4Smiod && strcmp (c1->augmentation, c2->augmentation) == 0
2193d8817e4Smiod && strcmp (c1->augmentation, "eh") != 0
2203d8817e4Smiod && c1->code_align == c2->code_align
2213d8817e4Smiod && c1->data_align == c2->data_align
2223d8817e4Smiod && c1->ra_column == c2->ra_column
2233d8817e4Smiod && c1->augmentation_size == c2->augmentation_size
2243d8817e4Smiod && c1->personality == c2->personality
225*fc67150aSkettenis && c1->output_sec == c2->output_sec
2263d8817e4Smiod && c1->per_encoding == c2->per_encoding
2273d8817e4Smiod && c1->lsda_encoding == c2->lsda_encoding
2283d8817e4Smiod && c1->fde_encoding == c2->fde_encoding
2293d8817e4Smiod && c1->initial_insn_length == c2->initial_insn_length
2303d8817e4Smiod && memcmp (c1->initial_instructions,
2313d8817e4Smiod c2->initial_instructions,
2323d8817e4Smiod c1->initial_insn_length) == 0)
2333d8817e4Smiod return 1;
234*fc67150aSkettenis
235*fc67150aSkettenis return 0;
236*fc67150aSkettenis }
237*fc67150aSkettenis
238*fc67150aSkettenis static hashval_t
cie_hash(const void * e)239*fc67150aSkettenis cie_hash (const void *e)
240*fc67150aSkettenis {
241*fc67150aSkettenis const struct cie *c = e;
242*fc67150aSkettenis return c->hash;
243*fc67150aSkettenis }
244*fc67150aSkettenis
245*fc67150aSkettenis static hashval_t
cie_compute_hash(struct cie * c)246*fc67150aSkettenis cie_compute_hash (struct cie *c)
247*fc67150aSkettenis {
248*fc67150aSkettenis hashval_t h = 0;
249*fc67150aSkettenis h = iterative_hash_object (c->length, h);
250*fc67150aSkettenis h = iterative_hash_object (c->version, h);
251*fc67150aSkettenis h = iterative_hash (c->augmentation, strlen (c->augmentation) + 1, h);
252*fc67150aSkettenis h = iterative_hash_object (c->code_align, h);
253*fc67150aSkettenis h = iterative_hash_object (c->data_align, h);
254*fc67150aSkettenis h = iterative_hash_object (c->ra_column, h);
255*fc67150aSkettenis h = iterative_hash_object (c->augmentation_size, h);
256*fc67150aSkettenis h = iterative_hash_object (c->personality, h);
257*fc67150aSkettenis h = iterative_hash_object (c->output_sec, h);
258*fc67150aSkettenis h = iterative_hash_object (c->per_encoding, h);
259*fc67150aSkettenis h = iterative_hash_object (c->lsda_encoding, h);
260*fc67150aSkettenis h = iterative_hash_object (c->fde_encoding, h);
261*fc67150aSkettenis h = iterative_hash_object (c->initial_insn_length, h);
262*fc67150aSkettenis h = iterative_hash (c->initial_instructions, c->initial_insn_length, h);
263*fc67150aSkettenis c->hash = h;
264*fc67150aSkettenis return h;
2653d8817e4Smiod }
2663d8817e4Smiod
2673d8817e4Smiod /* Return the number of extra bytes that we'll be inserting into
2683d8817e4Smiod ENTRY's augmentation string. */
2693d8817e4Smiod
2703d8817e4Smiod static INLINE unsigned int
extra_augmentation_string_bytes(struct eh_cie_fde * entry)2713d8817e4Smiod extra_augmentation_string_bytes (struct eh_cie_fde *entry)
2723d8817e4Smiod {
2733d8817e4Smiod unsigned int size = 0;
2743d8817e4Smiod if (entry->cie)
2753d8817e4Smiod {
2763d8817e4Smiod if (entry->add_augmentation_size)
2773d8817e4Smiod size++;
2783d8817e4Smiod if (entry->add_fde_encoding)
2793d8817e4Smiod size++;
2803d8817e4Smiod }
2813d8817e4Smiod return size;
2823d8817e4Smiod }
2833d8817e4Smiod
2843d8817e4Smiod /* Likewise ENTRY's augmentation data. */
2853d8817e4Smiod
2863d8817e4Smiod static INLINE unsigned int
extra_augmentation_data_bytes(struct eh_cie_fde * entry)2873d8817e4Smiod extra_augmentation_data_bytes (struct eh_cie_fde *entry)
2883d8817e4Smiod {
2893d8817e4Smiod unsigned int size = 0;
2903d8817e4Smiod if (entry->cie)
2913d8817e4Smiod {
2923d8817e4Smiod if (entry->add_augmentation_size)
2933d8817e4Smiod size++;
2943d8817e4Smiod if (entry->add_fde_encoding)
2953d8817e4Smiod size++;
2963d8817e4Smiod }
2973d8817e4Smiod else
2983d8817e4Smiod {
2993d8817e4Smiod if (entry->cie_inf->add_augmentation_size)
3003d8817e4Smiod size++;
3013d8817e4Smiod }
3023d8817e4Smiod return size;
3033d8817e4Smiod }
3043d8817e4Smiod
3053d8817e4Smiod /* Return the size that ENTRY will have in the output. ALIGNMENT is the
3063d8817e4Smiod required alignment of ENTRY in bytes. */
3073d8817e4Smiod
3083d8817e4Smiod static unsigned int
size_of_output_cie_fde(struct eh_cie_fde * entry,unsigned int alignment)3093d8817e4Smiod size_of_output_cie_fde (struct eh_cie_fde *entry, unsigned int alignment)
3103d8817e4Smiod {
3113d8817e4Smiod if (entry->removed)
3123d8817e4Smiod return 0;
3133d8817e4Smiod if (entry->size == 4)
3143d8817e4Smiod return 4;
3153d8817e4Smiod return (entry->size
3163d8817e4Smiod + extra_augmentation_string_bytes (entry)
3173d8817e4Smiod + extra_augmentation_data_bytes (entry)
3183d8817e4Smiod + alignment - 1) & -alignment;
3193d8817e4Smiod }
3203d8817e4Smiod
3213d8817e4Smiod /* Assume that the bytes between *ITER and END are CFA instructions.
3223d8817e4Smiod Try to move *ITER past the first instruction and return true on
3233d8817e4Smiod success. ENCODED_PTR_WIDTH gives the width of pointer entries. */
3243d8817e4Smiod
3253d8817e4Smiod static bfd_boolean
skip_cfa_op(bfd_byte ** iter,bfd_byte * end,unsigned int encoded_ptr_width)3263d8817e4Smiod skip_cfa_op (bfd_byte **iter, bfd_byte *end, unsigned int encoded_ptr_width)
3273d8817e4Smiod {
3283d8817e4Smiod bfd_byte op;
3293d8817e4Smiod bfd_vma length;
3303d8817e4Smiod
3313d8817e4Smiod if (!read_byte (iter, end, &op))
3323d8817e4Smiod return FALSE;
3333d8817e4Smiod
334*fc67150aSkettenis switch (op & 0xc0 ? op & 0xc0 : op)
3353d8817e4Smiod {
3363d8817e4Smiod case DW_CFA_nop:
3373d8817e4Smiod case DW_CFA_advance_loc:
3383d8817e4Smiod case DW_CFA_restore:
339*fc67150aSkettenis case DW_CFA_remember_state:
340*fc67150aSkettenis case DW_CFA_restore_state:
341*fc67150aSkettenis case DW_CFA_GNU_window_save:
3423d8817e4Smiod /* No arguments. */
3433d8817e4Smiod return TRUE;
3443d8817e4Smiod
3453d8817e4Smiod case DW_CFA_offset:
3463d8817e4Smiod case DW_CFA_restore_extended:
3473d8817e4Smiod case DW_CFA_undefined:
3483d8817e4Smiod case DW_CFA_same_value:
3493d8817e4Smiod case DW_CFA_def_cfa_register:
3503d8817e4Smiod case DW_CFA_def_cfa_offset:
3513d8817e4Smiod case DW_CFA_def_cfa_offset_sf:
3523d8817e4Smiod case DW_CFA_GNU_args_size:
3533d8817e4Smiod /* One leb128 argument. */
3543d8817e4Smiod return skip_leb128 (iter, end);
3553d8817e4Smiod
356*fc67150aSkettenis case DW_CFA_val_offset:
357*fc67150aSkettenis case DW_CFA_val_offset_sf:
3583d8817e4Smiod case DW_CFA_offset_extended:
3593d8817e4Smiod case DW_CFA_register:
3603d8817e4Smiod case DW_CFA_def_cfa:
3613d8817e4Smiod case DW_CFA_offset_extended_sf:
3623d8817e4Smiod case DW_CFA_GNU_negative_offset_extended:
3633d8817e4Smiod case DW_CFA_def_cfa_sf:
3643d8817e4Smiod /* Two leb128 arguments. */
3653d8817e4Smiod return (skip_leb128 (iter, end)
3663d8817e4Smiod && skip_leb128 (iter, end));
3673d8817e4Smiod
3683d8817e4Smiod case DW_CFA_def_cfa_expression:
3693d8817e4Smiod /* A variable-length argument. */
3703d8817e4Smiod return (read_uleb128 (iter, end, &length)
3713d8817e4Smiod && skip_bytes (iter, end, length));
3723d8817e4Smiod
3733d8817e4Smiod case DW_CFA_expression:
374*fc67150aSkettenis case DW_CFA_val_expression:
3753d8817e4Smiod /* A leb128 followed by a variable-length argument. */
3763d8817e4Smiod return (skip_leb128 (iter, end)
3773d8817e4Smiod && read_uleb128 (iter, end, &length)
3783d8817e4Smiod && skip_bytes (iter, end, length));
3793d8817e4Smiod
3803d8817e4Smiod case DW_CFA_set_loc:
3813d8817e4Smiod return skip_bytes (iter, end, encoded_ptr_width);
3823d8817e4Smiod
3833d8817e4Smiod case DW_CFA_advance_loc1:
3843d8817e4Smiod return skip_bytes (iter, end, 1);
3853d8817e4Smiod
3863d8817e4Smiod case DW_CFA_advance_loc2:
3873d8817e4Smiod return skip_bytes (iter, end, 2);
3883d8817e4Smiod
3893d8817e4Smiod case DW_CFA_advance_loc4:
3903d8817e4Smiod return skip_bytes (iter, end, 4);
3913d8817e4Smiod
3923d8817e4Smiod case DW_CFA_MIPS_advance_loc8:
3933d8817e4Smiod return skip_bytes (iter, end, 8);
3943d8817e4Smiod
3953d8817e4Smiod default:
3963d8817e4Smiod return FALSE;
3973d8817e4Smiod }
3983d8817e4Smiod }
3993d8817e4Smiod
4003d8817e4Smiod /* Try to interpret the bytes between BUF and END as CFA instructions.
4013d8817e4Smiod If every byte makes sense, return a pointer to the first DW_CFA_nop
4023d8817e4Smiod padding byte, or END if there is no padding. Return null otherwise.
4033d8817e4Smiod ENCODED_PTR_WIDTH is as for skip_cfa_op. */
4043d8817e4Smiod
4053d8817e4Smiod static bfd_byte *
skip_non_nops(bfd_byte * buf,bfd_byte * end,unsigned int encoded_ptr_width,unsigned int * set_loc_count)406*fc67150aSkettenis skip_non_nops (bfd_byte *buf, bfd_byte *end, unsigned int encoded_ptr_width,
407*fc67150aSkettenis unsigned int *set_loc_count)
4083d8817e4Smiod {
4093d8817e4Smiod bfd_byte *last;
4103d8817e4Smiod
4113d8817e4Smiod last = buf;
4123d8817e4Smiod while (buf < end)
4133d8817e4Smiod if (*buf == DW_CFA_nop)
4143d8817e4Smiod buf++;
4153d8817e4Smiod else
4163d8817e4Smiod {
417*fc67150aSkettenis if (*buf == DW_CFA_set_loc)
418*fc67150aSkettenis ++*set_loc_count;
4193d8817e4Smiod if (!skip_cfa_op (&buf, end, encoded_ptr_width))
4203d8817e4Smiod return 0;
4213d8817e4Smiod last = buf;
4223d8817e4Smiod }
4233d8817e4Smiod return last;
4243d8817e4Smiod }
4253d8817e4Smiod
4263d8817e4Smiod /* This function is called for each input file before the .eh_frame
4273d8817e4Smiod section is relocated. It discards duplicate CIEs and FDEs for discarded
4283d8817e4Smiod functions. The function returns TRUE iff any entries have been
4293d8817e4Smiod deleted. */
4303d8817e4Smiod
4313d8817e4Smiod bfd_boolean
_bfd_elf_discard_section_eh_frame(bfd * abfd,struct bfd_link_info * info,asection * sec,bfd_boolean (* reloc_symbol_deleted_p)(bfd_vma,void *),struct elf_reloc_cookie * cookie)4323d8817e4Smiod _bfd_elf_discard_section_eh_frame
4333d8817e4Smiod (bfd *abfd, struct bfd_link_info *info, asection *sec,
4343d8817e4Smiod bfd_boolean (*reloc_symbol_deleted_p) (bfd_vma, void *),
4353d8817e4Smiod struct elf_reloc_cookie *cookie)
4363d8817e4Smiod {
4373d8817e4Smiod #define REQUIRE(COND) \
4383d8817e4Smiod do \
4393d8817e4Smiod if (!(COND)) \
4403d8817e4Smiod goto free_no_table; \
4413d8817e4Smiod while (0)
4423d8817e4Smiod
4433d8817e4Smiod bfd_byte *ehbuf = NULL, *buf;
444*fc67150aSkettenis bfd_byte *last_fde;
445*fc67150aSkettenis struct eh_cie_fde *ent, *this_inf;
446*fc67150aSkettenis unsigned int hdr_length, hdr_id;
447*fc67150aSkettenis struct extended_cie
448*fc67150aSkettenis {
4493d8817e4Smiod struct cie cie;
450*fc67150aSkettenis unsigned int offset;
451*fc67150aSkettenis unsigned int usage_count;
452*fc67150aSkettenis unsigned int entry;
453*fc67150aSkettenis } *ecies = NULL, *ecie;
454*fc67150aSkettenis unsigned int ecie_count = 0, ecie_alloced = 0;
455*fc67150aSkettenis struct cie *cie;
4563d8817e4Smiod struct elf_link_hash_table *htab;
4573d8817e4Smiod struct eh_frame_hdr_info *hdr_info;
4583d8817e4Smiod struct eh_frame_sec_info *sec_info = NULL;
459*fc67150aSkettenis unsigned int offset;
4603d8817e4Smiod unsigned int ptr_size;
461*fc67150aSkettenis unsigned int entry_alloced;
4623d8817e4Smiod
4633d8817e4Smiod if (sec->size == 0)
4643d8817e4Smiod {
4653d8817e4Smiod /* This file does not contain .eh_frame information. */
4663d8817e4Smiod return FALSE;
4673d8817e4Smiod }
4683d8817e4Smiod
469*fc67150aSkettenis if (bfd_is_abs_section (sec->output_section))
4703d8817e4Smiod {
4713d8817e4Smiod /* At least one of the sections is being discarded from the
4723d8817e4Smiod link, so we should just ignore them. */
4733d8817e4Smiod return FALSE;
4743d8817e4Smiod }
4753d8817e4Smiod
4763d8817e4Smiod htab = elf_hash_table (info);
4773d8817e4Smiod hdr_info = &htab->eh_info;
4783d8817e4Smiod
479*fc67150aSkettenis if (hdr_info->cies == NULL && !info->relocatable)
480*fc67150aSkettenis hdr_info->cies = htab_try_create (1, cie_hash, cie_eq, free);
481*fc67150aSkettenis
4823d8817e4Smiod /* Read the frame unwind information from abfd. */
4833d8817e4Smiod
4843d8817e4Smiod REQUIRE (bfd_malloc_and_get_section (abfd, sec, &ehbuf));
4853d8817e4Smiod
4863d8817e4Smiod if (sec->size >= 4
4873d8817e4Smiod && bfd_get_32 (abfd, ehbuf) == 0
4883d8817e4Smiod && cookie->rel == cookie->relend)
4893d8817e4Smiod {
4903d8817e4Smiod /* Empty .eh_frame section. */
4913d8817e4Smiod free (ehbuf);
4923d8817e4Smiod return FALSE;
4933d8817e4Smiod }
4943d8817e4Smiod
4953d8817e4Smiod /* If .eh_frame section size doesn't fit into int, we cannot handle
4963d8817e4Smiod it (it would need to use 64-bit .eh_frame format anyway). */
4973d8817e4Smiod REQUIRE (sec->size == (unsigned int) sec->size);
4983d8817e4Smiod
4993d8817e4Smiod ptr_size = (get_elf_backend_data (abfd)
5003d8817e4Smiod ->elf_backend_eh_frame_address_size (abfd, sec));
5013d8817e4Smiod REQUIRE (ptr_size != 0);
5023d8817e4Smiod
5033d8817e4Smiod buf = ehbuf;
5043d8817e4Smiod sec_info = bfd_zmalloc (sizeof (struct eh_frame_sec_info)
5053d8817e4Smiod + 99 * sizeof (struct eh_cie_fde));
5063d8817e4Smiod REQUIRE (sec_info);
5073d8817e4Smiod
508*fc67150aSkettenis entry_alloced = 100;
5093d8817e4Smiod
5103d8817e4Smiod #define ENSURE_NO_RELOCS(buf) \
5113d8817e4Smiod REQUIRE (!(cookie->rel < cookie->relend \
5123d8817e4Smiod && (cookie->rel->r_offset \
5133d8817e4Smiod < (bfd_size_type) ((buf) - ehbuf)) \
5143d8817e4Smiod && cookie->rel->r_info != 0))
5153d8817e4Smiod
5163d8817e4Smiod #define SKIP_RELOCS(buf) \
5173d8817e4Smiod while (cookie->rel < cookie->relend \
5183d8817e4Smiod && (cookie->rel->r_offset \
5193d8817e4Smiod < (bfd_size_type) ((buf) - ehbuf))) \
5203d8817e4Smiod cookie->rel++
5213d8817e4Smiod
5223d8817e4Smiod #define GET_RELOC(buf) \
5233d8817e4Smiod ((cookie->rel < cookie->relend \
5243d8817e4Smiod && (cookie->rel->r_offset \
5253d8817e4Smiod == (bfd_size_type) ((buf) - ehbuf))) \
5263d8817e4Smiod ? cookie->rel : NULL)
5273d8817e4Smiod
5283d8817e4Smiod for (;;)
5293d8817e4Smiod {
5303d8817e4Smiod char *aug;
531*fc67150aSkettenis bfd_byte *start, *end, *insns, *insns_end;
5323d8817e4Smiod bfd_size_type length;
533*fc67150aSkettenis unsigned int set_loc_count;
5343d8817e4Smiod
535*fc67150aSkettenis if (sec_info->count == entry_alloced)
5363d8817e4Smiod {
5373d8817e4Smiod sec_info = bfd_realloc (sec_info,
5383d8817e4Smiod sizeof (struct eh_frame_sec_info)
539*fc67150aSkettenis + ((entry_alloced + 99)
5403d8817e4Smiod * sizeof (struct eh_cie_fde)));
5413d8817e4Smiod REQUIRE (sec_info);
5423d8817e4Smiod
543*fc67150aSkettenis memset (&sec_info->entry[entry_alloced], 0,
5443d8817e4Smiod 100 * sizeof (struct eh_cie_fde));
545*fc67150aSkettenis entry_alloced += 100;
5463d8817e4Smiod }
5473d8817e4Smiod
5483d8817e4Smiod this_inf = sec_info->entry + sec_info->count;
5493d8817e4Smiod last_fde = buf;
550*fc67150aSkettenis
5513d8817e4Smiod if ((bfd_size_type) (buf - ehbuf) == sec->size)
552*fc67150aSkettenis break;
553*fc67150aSkettenis
5543d8817e4Smiod /* Read the length of the entry. */
5553d8817e4Smiod REQUIRE (skip_bytes (&buf, ehbuf + sec->size, 4));
556*fc67150aSkettenis hdr_length = bfd_get_32 (abfd, buf - 4);
5573d8817e4Smiod
5583d8817e4Smiod /* 64-bit .eh_frame is not supported. */
559*fc67150aSkettenis REQUIRE (hdr_length != 0xffffffff);
5603d8817e4Smiod
5613d8817e4Smiod /* The CIE/FDE must be fully contained in this input section. */
562*fc67150aSkettenis REQUIRE ((bfd_size_type) (buf - ehbuf) + hdr_length <= sec->size);
563*fc67150aSkettenis end = buf + hdr_length;
5643d8817e4Smiod
5653d8817e4Smiod this_inf->offset = last_fde - ehbuf;
566*fc67150aSkettenis this_inf->size = 4 + hdr_length;
5673d8817e4Smiod
568*fc67150aSkettenis if (hdr_length == 0)
5693d8817e4Smiod {
5703d8817e4Smiod /* A zero-length CIE should only be found at the end of
5713d8817e4Smiod the section. */
5723d8817e4Smiod REQUIRE ((bfd_size_type) (buf - ehbuf) == sec->size);
5733d8817e4Smiod ENSURE_NO_RELOCS (buf);
5743d8817e4Smiod sec_info->count++;
575*fc67150aSkettenis break;
5763d8817e4Smiod }
5773d8817e4Smiod
578*fc67150aSkettenis REQUIRE (skip_bytes (&buf, end, 4));
579*fc67150aSkettenis hdr_id = bfd_get_32 (abfd, buf - 4);
580*fc67150aSkettenis
581*fc67150aSkettenis if (hdr_id == 0)
5823d8817e4Smiod {
5833d8817e4Smiod unsigned int initial_insn_length;
5843d8817e4Smiod
5853d8817e4Smiod /* CIE */
5863d8817e4Smiod this_inf->cie = 1;
5873d8817e4Smiod
588*fc67150aSkettenis if (ecie_count == ecie_alloced)
589*fc67150aSkettenis {
590*fc67150aSkettenis ecies = bfd_realloc (ecies,
591*fc67150aSkettenis (ecie_alloced + 20) * sizeof (*ecies));
592*fc67150aSkettenis REQUIRE (ecies);
593*fc67150aSkettenis memset (&ecies[ecie_alloced], 0, 20 * sizeof (*ecies));
594*fc67150aSkettenis ecie_alloced += 20;
595*fc67150aSkettenis }
596*fc67150aSkettenis
597*fc67150aSkettenis cie = &ecies[ecie_count].cie;
598*fc67150aSkettenis ecies[ecie_count].offset = this_inf->offset;
599*fc67150aSkettenis ecies[ecie_count++].entry = sec_info->count;
600*fc67150aSkettenis cie->length = hdr_length;
601*fc67150aSkettenis start = buf;
602*fc67150aSkettenis REQUIRE (read_byte (&buf, end, &cie->version));
6033d8817e4Smiod
6043d8817e4Smiod /* Cannot handle unknown versions. */
605*fc67150aSkettenis REQUIRE (cie->version == 1 || cie->version == 3);
606*fc67150aSkettenis REQUIRE (strlen ((char *) buf) < sizeof (cie->augmentation));
6073d8817e4Smiod
608*fc67150aSkettenis strcpy (cie->augmentation, (char *) buf);
6093d8817e4Smiod buf = (bfd_byte *) strchr ((char *) buf, '\0') + 1;
6103d8817e4Smiod ENSURE_NO_RELOCS (buf);
6113d8817e4Smiod if (buf[0] == 'e' && buf[1] == 'h')
6123d8817e4Smiod {
6133d8817e4Smiod /* GCC < 3.0 .eh_frame CIE */
6143d8817e4Smiod /* We cannot merge "eh" CIEs because __EXCEPTION_TABLE__
6153d8817e4Smiod is private to each CIE, so we don't need it for anything.
6163d8817e4Smiod Just skip it. */
6173d8817e4Smiod REQUIRE (skip_bytes (&buf, end, ptr_size));
6183d8817e4Smiod SKIP_RELOCS (buf);
6193d8817e4Smiod }
620*fc67150aSkettenis REQUIRE (read_uleb128 (&buf, end, &cie->code_align));
621*fc67150aSkettenis REQUIRE (read_sleb128 (&buf, end, &cie->data_align));
622*fc67150aSkettenis if (cie->version == 1)
6233d8817e4Smiod {
6243d8817e4Smiod REQUIRE (buf < end);
625*fc67150aSkettenis cie->ra_column = *buf++;
6263d8817e4Smiod }
6273d8817e4Smiod else
628*fc67150aSkettenis REQUIRE (read_uleb128 (&buf, end, &cie->ra_column));
6293d8817e4Smiod ENSURE_NO_RELOCS (buf);
630*fc67150aSkettenis cie->lsda_encoding = DW_EH_PE_omit;
631*fc67150aSkettenis cie->fde_encoding = DW_EH_PE_omit;
632*fc67150aSkettenis cie->per_encoding = DW_EH_PE_omit;
633*fc67150aSkettenis aug = cie->augmentation;
6343d8817e4Smiod if (aug[0] != 'e' || aug[1] != 'h')
6353d8817e4Smiod {
6363d8817e4Smiod if (*aug == 'z')
6373d8817e4Smiod {
6383d8817e4Smiod aug++;
639*fc67150aSkettenis REQUIRE (read_uleb128 (&buf, end, &cie->augmentation_size));
6403d8817e4Smiod ENSURE_NO_RELOCS (buf);
6413d8817e4Smiod }
6423d8817e4Smiod
6433d8817e4Smiod while (*aug != '\0')
6443d8817e4Smiod switch (*aug++)
6453d8817e4Smiod {
6463d8817e4Smiod case 'L':
647*fc67150aSkettenis REQUIRE (read_byte (&buf, end, &cie->lsda_encoding));
6483d8817e4Smiod ENSURE_NO_RELOCS (buf);
649*fc67150aSkettenis REQUIRE (get_DW_EH_PE_width (cie->lsda_encoding, ptr_size));
6503d8817e4Smiod break;
6513d8817e4Smiod case 'R':
652*fc67150aSkettenis REQUIRE (read_byte (&buf, end, &cie->fde_encoding));
6533d8817e4Smiod ENSURE_NO_RELOCS (buf);
654*fc67150aSkettenis REQUIRE (get_DW_EH_PE_width (cie->fde_encoding, ptr_size));
6553d8817e4Smiod break;
6563d8817e4Smiod case 'S':
6573d8817e4Smiod break;
6583d8817e4Smiod case 'P':
6593d8817e4Smiod {
6603d8817e4Smiod int per_width;
6613d8817e4Smiod
662*fc67150aSkettenis REQUIRE (read_byte (&buf, end, &cie->per_encoding));
663*fc67150aSkettenis per_width = get_DW_EH_PE_width (cie->per_encoding,
6643d8817e4Smiod ptr_size);
6653d8817e4Smiod REQUIRE (per_width);
666*fc67150aSkettenis if ((cie->per_encoding & 0xf0) == DW_EH_PE_aligned)
6673d8817e4Smiod {
6683d8817e4Smiod length = -(buf - ehbuf) & (per_width - 1);
6693d8817e4Smiod REQUIRE (skip_bytes (&buf, end, length));
6703d8817e4Smiod }
6713d8817e4Smiod ENSURE_NO_RELOCS (buf);
6723d8817e4Smiod /* Ensure we have a reloc here, against
6733d8817e4Smiod a global symbol. */
6743d8817e4Smiod if (GET_RELOC (buf) != NULL)
6753d8817e4Smiod {
6763d8817e4Smiod unsigned long r_symndx;
6773d8817e4Smiod
6783d8817e4Smiod #ifdef BFD64
6793d8817e4Smiod if (ptr_size == 8)
6803d8817e4Smiod r_symndx = ELF64_R_SYM (cookie->rel->r_info);
6813d8817e4Smiod else
6823d8817e4Smiod #endif
6833d8817e4Smiod r_symndx = ELF32_R_SYM (cookie->rel->r_info);
6843d8817e4Smiod if (r_symndx >= cookie->locsymcount)
6853d8817e4Smiod {
6863d8817e4Smiod struct elf_link_hash_entry *h;
6873d8817e4Smiod
6883d8817e4Smiod r_symndx -= cookie->extsymoff;
6893d8817e4Smiod h = cookie->sym_hashes[r_symndx];
6903d8817e4Smiod
6913d8817e4Smiod while (h->root.type == bfd_link_hash_indirect
6923d8817e4Smiod || h->root.type == bfd_link_hash_warning)
6933d8817e4Smiod h = (struct elf_link_hash_entry *)
6943d8817e4Smiod h->root.u.i.link;
6953d8817e4Smiod
696*fc67150aSkettenis cie->personality = h;
6973d8817e4Smiod }
6983d8817e4Smiod /* Cope with MIPS-style composite relocations. */
6993d8817e4Smiod do
7003d8817e4Smiod cookie->rel++;
7013d8817e4Smiod while (GET_RELOC (buf) != NULL);
7023d8817e4Smiod }
7033d8817e4Smiod REQUIRE (skip_bytes (&buf, end, per_width));
704*fc67150aSkettenis REQUIRE (cie->personality);
7053d8817e4Smiod }
7063d8817e4Smiod break;
7073d8817e4Smiod default:
7083d8817e4Smiod /* Unrecognized augmentation. Better bail out. */
7093d8817e4Smiod goto free_no_table;
7103d8817e4Smiod }
7113d8817e4Smiod }
7123d8817e4Smiod
7133d8817e4Smiod /* For shared libraries, try to get rid of as many RELATIVE relocs
7143d8817e4Smiod as possible. */
7153d8817e4Smiod if (info->shared
7163d8817e4Smiod && (get_elf_backend_data (abfd)
7173d8817e4Smiod ->elf_backend_can_make_relative_eh_frame
7183d8817e4Smiod (abfd, info, sec)))
7193d8817e4Smiod {
720*fc67150aSkettenis if ((cie->fde_encoding & 0xf0) == DW_EH_PE_absptr)
721*fc67150aSkettenis cie->make_relative = 1;
7223d8817e4Smiod /* If the CIE doesn't already have an 'R' entry, it's fairly
7233d8817e4Smiod easy to add one, provided that there's no aligned data
7243d8817e4Smiod after the augmentation string. */
725*fc67150aSkettenis else if (cie->fde_encoding == DW_EH_PE_omit
726*fc67150aSkettenis && (cie->per_encoding & 0xf0) != DW_EH_PE_aligned)
7273d8817e4Smiod {
728*fc67150aSkettenis if (*cie->augmentation == 0)
7293d8817e4Smiod this_inf->add_augmentation_size = 1;
7303d8817e4Smiod this_inf->add_fde_encoding = 1;
731*fc67150aSkettenis cie->make_relative = 1;
7323d8817e4Smiod }
7333d8817e4Smiod }
7343d8817e4Smiod
7353d8817e4Smiod if (info->shared
7363d8817e4Smiod && (get_elf_backend_data (abfd)
7373d8817e4Smiod ->elf_backend_can_make_lsda_relative_eh_frame
7383d8817e4Smiod (abfd, info, sec))
739*fc67150aSkettenis && (cie->lsda_encoding & 0xf0) == DW_EH_PE_absptr)
740*fc67150aSkettenis cie->make_lsda_relative = 1;
7413d8817e4Smiod
7423d8817e4Smiod /* If FDE encoding was not specified, it defaults to
7433d8817e4Smiod DW_EH_absptr. */
744*fc67150aSkettenis if (cie->fde_encoding == DW_EH_PE_omit)
745*fc67150aSkettenis cie->fde_encoding = DW_EH_PE_absptr;
7463d8817e4Smiod
7473d8817e4Smiod initial_insn_length = end - buf;
748*fc67150aSkettenis if (initial_insn_length <= sizeof (cie->initial_instructions))
7493d8817e4Smiod {
750*fc67150aSkettenis cie->initial_insn_length = initial_insn_length;
751*fc67150aSkettenis memcpy (cie->initial_instructions, buf, initial_insn_length);
7523d8817e4Smiod }
7533d8817e4Smiod insns = buf;
7543d8817e4Smiod buf += initial_insn_length;
7553d8817e4Smiod ENSURE_NO_RELOCS (buf);
7563d8817e4Smiod }
7573d8817e4Smiod else
7583d8817e4Smiod {
759*fc67150aSkettenis /* Find the corresponding CIE. */
760*fc67150aSkettenis unsigned int cie_offset = this_inf->offset + 4 - hdr_id;
761*fc67150aSkettenis for (ecie = ecies; ecie < ecies + ecie_count; ++ecie)
762*fc67150aSkettenis if (cie_offset == ecie->offset)
763*fc67150aSkettenis break;
764*fc67150aSkettenis
765*fc67150aSkettenis /* Ensure this FDE references one of the CIEs in this input
766*fc67150aSkettenis section. */
767*fc67150aSkettenis REQUIRE (ecie != ecies + ecie_count);
768*fc67150aSkettenis cie = &ecie->cie;
7693d8817e4Smiod
7703d8817e4Smiod ENSURE_NO_RELOCS (buf);
7713d8817e4Smiod REQUIRE (GET_RELOC (buf));
7723d8817e4Smiod
7733d8817e4Smiod if ((*reloc_symbol_deleted_p) (buf - ehbuf, cookie))
7743d8817e4Smiod /* This is a FDE against a discarded section. It should
7753d8817e4Smiod be deleted. */
7763d8817e4Smiod this_inf->removed = 1;
7773d8817e4Smiod else
7783d8817e4Smiod {
7793d8817e4Smiod if (info->shared
780*fc67150aSkettenis && (((cie->fde_encoding & 0xf0) == DW_EH_PE_absptr
781*fc67150aSkettenis && cie->make_relative == 0)
782*fc67150aSkettenis || (cie->fde_encoding & 0xf0) == DW_EH_PE_aligned))
7833d8817e4Smiod {
7843d8817e4Smiod /* If a shared library uses absolute pointers
7853d8817e4Smiod which we cannot turn into PC relative,
7863d8817e4Smiod don't create the binary search table,
7873d8817e4Smiod since it is affected by runtime relocations. */
7883d8817e4Smiod hdr_info->table = FALSE;
7893d8817e4Smiod }
790*fc67150aSkettenis ecie->usage_count++;
7913d8817e4Smiod hdr_info->fde_count++;
792*fc67150aSkettenis this_inf->cie_inf = (void *) (ecie - ecies);
7933d8817e4Smiod }
794*fc67150aSkettenis
7953d8817e4Smiod /* Skip the initial location and address range. */
7963d8817e4Smiod start = buf;
797*fc67150aSkettenis length = get_DW_EH_PE_width (cie->fde_encoding, ptr_size);
7983d8817e4Smiod REQUIRE (skip_bytes (&buf, end, 2 * length));
7993d8817e4Smiod
8003d8817e4Smiod /* Skip the augmentation size, if present. */
801*fc67150aSkettenis if (cie->augmentation[0] == 'z')
8023d8817e4Smiod REQUIRE (read_uleb128 (&buf, end, &length));
8033d8817e4Smiod else
8043d8817e4Smiod length = 0;
8053d8817e4Smiod
8063d8817e4Smiod /* Of the supported augmentation characters above, only 'L'
8073d8817e4Smiod adds augmentation data to the FDE. This code would need to
8083d8817e4Smiod be adjusted if any future augmentations do the same thing. */
809*fc67150aSkettenis if (cie->lsda_encoding != DW_EH_PE_omit)
8103d8817e4Smiod {
8113d8817e4Smiod this_inf->lsda_offset = buf - start;
8123d8817e4Smiod /* If there's no 'z' augmentation, we don't know where the
8133d8817e4Smiod CFA insns begin. Assume no padding. */
814*fc67150aSkettenis if (cie->augmentation[0] != 'z')
8153d8817e4Smiod length = end - buf;
8163d8817e4Smiod }
8173d8817e4Smiod
8183d8817e4Smiod /* Skip over the augmentation data. */
8193d8817e4Smiod REQUIRE (skip_bytes (&buf, end, length));
8203d8817e4Smiod insns = buf;
8213d8817e4Smiod
822*fc67150aSkettenis buf = last_fde + 4 + hdr_length;
8233d8817e4Smiod SKIP_RELOCS (buf);
8243d8817e4Smiod }
8253d8817e4Smiod
8263d8817e4Smiod /* Try to interpret the CFA instructions and find the first
8273d8817e4Smiod padding nop. Shrink this_inf's size so that it doesn't
828*fc67150aSkettenis include the padding. */
829*fc67150aSkettenis length = get_DW_EH_PE_width (cie->fde_encoding, ptr_size);
830*fc67150aSkettenis set_loc_count = 0;
831*fc67150aSkettenis insns_end = skip_non_nops (insns, end, length, &set_loc_count);
832*fc67150aSkettenis /* If we don't understand the CFA instructions, we can't know
833*fc67150aSkettenis what needs to be adjusted there. */
834*fc67150aSkettenis if (insns_end == NULL
835*fc67150aSkettenis /* For the time being we don't support DW_CFA_set_loc in
836*fc67150aSkettenis CIE instructions. */
837*fc67150aSkettenis || (set_loc_count && this_inf->cie))
838*fc67150aSkettenis goto free_no_table;
839*fc67150aSkettenis this_inf->size -= end - insns_end;
840*fc67150aSkettenis if (insns_end != end && this_inf->cie)
841*fc67150aSkettenis {
842*fc67150aSkettenis cie->initial_insn_length -= end - insns_end;
843*fc67150aSkettenis cie->length -= end - insns_end;
844*fc67150aSkettenis }
845*fc67150aSkettenis if (set_loc_count
846*fc67150aSkettenis && ((cie->fde_encoding & 0xf0) == DW_EH_PE_pcrel
847*fc67150aSkettenis || cie->make_relative))
848*fc67150aSkettenis {
849*fc67150aSkettenis unsigned int cnt;
850*fc67150aSkettenis bfd_byte *p;
8513d8817e4Smiod
852*fc67150aSkettenis this_inf->set_loc = bfd_malloc ((set_loc_count + 1)
853*fc67150aSkettenis * sizeof (unsigned int));
854*fc67150aSkettenis REQUIRE (this_inf->set_loc);
855*fc67150aSkettenis this_inf->set_loc[0] = set_loc_count;
856*fc67150aSkettenis p = insns;
857*fc67150aSkettenis cnt = 0;
858*fc67150aSkettenis while (p < end)
859*fc67150aSkettenis {
860*fc67150aSkettenis if (*p == DW_CFA_set_loc)
861*fc67150aSkettenis this_inf->set_loc[++cnt] = p + 1 - start;
862*fc67150aSkettenis REQUIRE (skip_cfa_op (&p, end, length));
863*fc67150aSkettenis }
864*fc67150aSkettenis }
865*fc67150aSkettenis
866*fc67150aSkettenis this_inf->fde_encoding = cie->fde_encoding;
867*fc67150aSkettenis this_inf->lsda_encoding = cie->lsda_encoding;
8683d8817e4Smiod sec_info->count++;
8693d8817e4Smiod }
8703d8817e4Smiod
8713d8817e4Smiod elf_section_data (sec)->sec_info = sec_info;
8723d8817e4Smiod sec->sec_info_type = ELF_INFO_TYPE_EH_FRAME;
8733d8817e4Smiod
874*fc67150aSkettenis /* Look at all CIEs in this section and determine which can be
875*fc67150aSkettenis removed as unused, which can be merged with previous duplicate
876*fc67150aSkettenis CIEs and which need to be kept. */
877*fc67150aSkettenis for (ecie = ecies; ecie < ecies + ecie_count; ++ecie)
878*fc67150aSkettenis {
879*fc67150aSkettenis if (ecie->usage_count == 0)
880*fc67150aSkettenis {
881*fc67150aSkettenis sec_info->entry[ecie->entry].removed = 1;
882*fc67150aSkettenis continue;
883*fc67150aSkettenis }
884*fc67150aSkettenis ecie->cie.output_sec = sec->output_section;
885*fc67150aSkettenis ecie->cie.cie_inf = sec_info->entry + ecie->entry;
886*fc67150aSkettenis cie_compute_hash (&ecie->cie);
887*fc67150aSkettenis if (hdr_info->cies != NULL)
888*fc67150aSkettenis {
889*fc67150aSkettenis void **loc = htab_find_slot_with_hash (hdr_info->cies, &ecie->cie,
890*fc67150aSkettenis ecie->cie.hash, INSERT);
891*fc67150aSkettenis if (loc != NULL)
892*fc67150aSkettenis {
893*fc67150aSkettenis if (*loc != HTAB_EMPTY_ENTRY)
894*fc67150aSkettenis {
895*fc67150aSkettenis sec_info->entry[ecie->entry].removed = 1;
896*fc67150aSkettenis ecie->cie.cie_inf = ((struct cie *) *loc)->cie_inf;
897*fc67150aSkettenis continue;
898*fc67150aSkettenis }
899*fc67150aSkettenis
900*fc67150aSkettenis *loc = malloc (sizeof (struct cie));
901*fc67150aSkettenis if (*loc == NULL)
902*fc67150aSkettenis *loc = HTAB_DELETED_ENTRY;
903*fc67150aSkettenis else
904*fc67150aSkettenis memcpy (*loc, &ecie->cie, sizeof (struct cie));
905*fc67150aSkettenis }
906*fc67150aSkettenis }
907*fc67150aSkettenis ecie->cie.cie_inf->make_relative = ecie->cie.make_relative;
908*fc67150aSkettenis ecie->cie.cie_inf->make_lsda_relative = ecie->cie.make_lsda_relative;
909*fc67150aSkettenis ecie->cie.cie_inf->per_encoding_relative
910*fc67150aSkettenis = (ecie->cie.per_encoding & 0x70) == DW_EH_PE_pcrel;
911*fc67150aSkettenis }
912*fc67150aSkettenis
9133d8817e4Smiod /* Ok, now we can assign new offsets. */
9143d8817e4Smiod offset = 0;
9153d8817e4Smiod for (ent = sec_info->entry; ent < sec_info->entry + sec_info->count; ++ent)
9163d8817e4Smiod if (!ent->removed)
9173d8817e4Smiod {
918*fc67150aSkettenis if (!ent->cie)
919*fc67150aSkettenis {
920*fc67150aSkettenis ecie = ecies + (unsigned long) ent->cie_inf;
921*fc67150aSkettenis ent->cie_inf = ecie->cie.cie_inf;
922*fc67150aSkettenis }
9233d8817e4Smiod ent->new_offset = offset;
9243d8817e4Smiod offset += size_of_output_cie_fde (ent, ptr_size);
9253d8817e4Smiod }
9263d8817e4Smiod
9273d8817e4Smiod /* Resize the sec as needed. */
9283d8817e4Smiod sec->rawsize = sec->size;
9293d8817e4Smiod sec->size = offset;
9303d8817e4Smiod if (sec->size == 0)
9313d8817e4Smiod sec->flags |= SEC_EXCLUDE;
9323d8817e4Smiod
9333d8817e4Smiod free (ehbuf);
934*fc67150aSkettenis if (ecies)
935*fc67150aSkettenis free (ecies);
9363d8817e4Smiod return offset != sec->rawsize;
9373d8817e4Smiod
9383d8817e4Smiod free_no_table:
9393d8817e4Smiod if (ehbuf)
9403d8817e4Smiod free (ehbuf);
9413d8817e4Smiod if (sec_info)
9423d8817e4Smiod free (sec_info);
943*fc67150aSkettenis if (ecies)
944*fc67150aSkettenis free (ecies);
9453d8817e4Smiod hdr_info->table = FALSE;
9463d8817e4Smiod return FALSE;
9473d8817e4Smiod
9483d8817e4Smiod #undef REQUIRE
9493d8817e4Smiod }
9503d8817e4Smiod
9513d8817e4Smiod /* This function is called for .eh_frame_hdr section after
9523d8817e4Smiod _bfd_elf_discard_section_eh_frame has been called on all .eh_frame
9533d8817e4Smiod input sections. It finalizes the size of .eh_frame_hdr section. */
9543d8817e4Smiod
9553d8817e4Smiod bfd_boolean
_bfd_elf_discard_section_eh_frame_hdr(bfd * abfd,struct bfd_link_info * info)9563d8817e4Smiod _bfd_elf_discard_section_eh_frame_hdr (bfd *abfd, struct bfd_link_info *info)
9573d8817e4Smiod {
9583d8817e4Smiod struct elf_link_hash_table *htab;
9593d8817e4Smiod struct eh_frame_hdr_info *hdr_info;
9603d8817e4Smiod asection *sec;
9613d8817e4Smiod
9623d8817e4Smiod htab = elf_hash_table (info);
9633d8817e4Smiod hdr_info = &htab->eh_info;
964*fc67150aSkettenis
965*fc67150aSkettenis if (hdr_info->cies != NULL)
966*fc67150aSkettenis {
967*fc67150aSkettenis htab_delete (hdr_info->cies);
968*fc67150aSkettenis hdr_info->cies = NULL;
969*fc67150aSkettenis }
970*fc67150aSkettenis
9713d8817e4Smiod sec = hdr_info->hdr_sec;
9723d8817e4Smiod if (sec == NULL)
9733d8817e4Smiod return FALSE;
9743d8817e4Smiod
9753d8817e4Smiod sec->size = EH_FRAME_HDR_SIZE;
9763d8817e4Smiod if (hdr_info->table)
9773d8817e4Smiod sec->size += 4 + hdr_info->fde_count * 8;
9783d8817e4Smiod
9793d8817e4Smiod /* Request program headers to be recalculated. */
9803d8817e4Smiod elf_tdata (abfd)->program_header_size = 0;
9813d8817e4Smiod elf_tdata (abfd)->eh_frame_hdr = sec;
9823d8817e4Smiod return TRUE;
9833d8817e4Smiod }
9843d8817e4Smiod
9853d8817e4Smiod /* This function is called from size_dynamic_sections.
9863d8817e4Smiod It needs to decide whether .eh_frame_hdr should be output or not,
9873d8817e4Smiod because when the dynamic symbol table has been sized it is too late
9883d8817e4Smiod to strip sections. */
9893d8817e4Smiod
9903d8817e4Smiod bfd_boolean
_bfd_elf_maybe_strip_eh_frame_hdr(struct bfd_link_info * info)9913d8817e4Smiod _bfd_elf_maybe_strip_eh_frame_hdr (struct bfd_link_info *info)
9923d8817e4Smiod {
9933d8817e4Smiod asection *o;
9943d8817e4Smiod bfd *abfd;
9953d8817e4Smiod struct elf_link_hash_table *htab;
9963d8817e4Smiod struct eh_frame_hdr_info *hdr_info;
9973d8817e4Smiod
9983d8817e4Smiod htab = elf_hash_table (info);
9993d8817e4Smiod hdr_info = &htab->eh_info;
10003d8817e4Smiod if (hdr_info->hdr_sec == NULL)
10013d8817e4Smiod return TRUE;
10023d8817e4Smiod
10033d8817e4Smiod if (bfd_is_abs_section (hdr_info->hdr_sec->output_section))
10043d8817e4Smiod {
10053d8817e4Smiod hdr_info->hdr_sec = NULL;
10063d8817e4Smiod return TRUE;
10073d8817e4Smiod }
10083d8817e4Smiod
10093d8817e4Smiod abfd = NULL;
10103d8817e4Smiod if (info->eh_frame_hdr)
10113d8817e4Smiod for (abfd = info->input_bfds; abfd != NULL; abfd = abfd->link_next)
10123d8817e4Smiod {
10133d8817e4Smiod /* Count only sections which have at least a single CIE or FDE.
10143d8817e4Smiod There cannot be any CIE or FDE <= 8 bytes. */
10153d8817e4Smiod o = bfd_get_section_by_name (abfd, ".eh_frame");
10163d8817e4Smiod if (o && o->size > 8 && !bfd_is_abs_section (o->output_section))
10173d8817e4Smiod break;
10183d8817e4Smiod }
10193d8817e4Smiod
10203d8817e4Smiod if (abfd == NULL)
10213d8817e4Smiod {
10223d8817e4Smiod hdr_info->hdr_sec->flags |= SEC_EXCLUDE;
10233d8817e4Smiod hdr_info->hdr_sec = NULL;
10243d8817e4Smiod return TRUE;
10253d8817e4Smiod }
10263d8817e4Smiod
10273d8817e4Smiod hdr_info->table = TRUE;
10283d8817e4Smiod return TRUE;
10293d8817e4Smiod }
10303d8817e4Smiod
10313d8817e4Smiod /* Adjust an address in the .eh_frame section. Given OFFSET within
10323d8817e4Smiod SEC, this returns the new offset in the adjusted .eh_frame section,
10333d8817e4Smiod or -1 if the address refers to a CIE/FDE which has been removed
10343d8817e4Smiod or to offset with dynamic relocation which is no longer needed. */
10353d8817e4Smiod
10363d8817e4Smiod bfd_vma
_bfd_elf_eh_frame_section_offset(bfd * output_bfd ATTRIBUTE_UNUSED,struct bfd_link_info * info,asection * sec,bfd_vma offset)10373d8817e4Smiod _bfd_elf_eh_frame_section_offset (bfd *output_bfd ATTRIBUTE_UNUSED,
10383d8817e4Smiod struct bfd_link_info *info,
10393d8817e4Smiod asection *sec,
10403d8817e4Smiod bfd_vma offset)
10413d8817e4Smiod {
10423d8817e4Smiod struct eh_frame_sec_info *sec_info;
10433d8817e4Smiod struct elf_link_hash_table *htab;
10443d8817e4Smiod struct eh_frame_hdr_info *hdr_info;
10453d8817e4Smiod unsigned int lo, hi, mid;
10463d8817e4Smiod
10473d8817e4Smiod if (sec->sec_info_type != ELF_INFO_TYPE_EH_FRAME)
10483d8817e4Smiod return offset;
10493d8817e4Smiod sec_info = elf_section_data (sec)->sec_info;
10503d8817e4Smiod
10513d8817e4Smiod if (offset >= sec->rawsize)
10523d8817e4Smiod return offset - sec->rawsize + sec->size;
10533d8817e4Smiod
10543d8817e4Smiod htab = elf_hash_table (info);
10553d8817e4Smiod hdr_info = &htab->eh_info;
10563d8817e4Smiod if (hdr_info->offsets_adjusted)
10573d8817e4Smiod offset += sec->output_offset;
10583d8817e4Smiod
10593d8817e4Smiod lo = 0;
10603d8817e4Smiod hi = sec_info->count;
10613d8817e4Smiod mid = 0;
10623d8817e4Smiod while (lo < hi)
10633d8817e4Smiod {
10643d8817e4Smiod mid = (lo + hi) / 2;
10653d8817e4Smiod if (offset < sec_info->entry[mid].offset)
10663d8817e4Smiod hi = mid;
10673d8817e4Smiod else if (offset
10683d8817e4Smiod >= sec_info->entry[mid].offset + sec_info->entry[mid].size)
10693d8817e4Smiod lo = mid + 1;
10703d8817e4Smiod else
10713d8817e4Smiod break;
10723d8817e4Smiod }
10733d8817e4Smiod
10743d8817e4Smiod BFD_ASSERT (lo < hi);
10753d8817e4Smiod
10763d8817e4Smiod /* FDE or CIE was removed. */
10773d8817e4Smiod if (sec_info->entry[mid].removed)
10783d8817e4Smiod return (bfd_vma) -1;
10793d8817e4Smiod
10803d8817e4Smiod /* If converting to DW_EH_PE_pcrel, there will be no need for run-time
10813d8817e4Smiod relocation against FDE's initial_location field. */
10823d8817e4Smiod if (!sec_info->entry[mid].cie
10833d8817e4Smiod && sec_info->entry[mid].cie_inf->make_relative
10843d8817e4Smiod && offset == sec_info->entry[mid].offset + 8)
10853d8817e4Smiod return (bfd_vma) -2;
10863d8817e4Smiod
10873d8817e4Smiod /* If converting LSDA pointers to DW_EH_PE_pcrel, there will be no need
10883d8817e4Smiod for run-time relocation against LSDA field. */
10893d8817e4Smiod if (!sec_info->entry[mid].cie
10903d8817e4Smiod && sec_info->entry[mid].cie_inf->make_lsda_relative
10913d8817e4Smiod && (offset == (sec_info->entry[mid].offset + 8
10923d8817e4Smiod + sec_info->entry[mid].lsda_offset))
10933d8817e4Smiod && (sec_info->entry[mid].cie_inf->need_lsda_relative
10943d8817e4Smiod || !hdr_info->offsets_adjusted))
10953d8817e4Smiod {
10963d8817e4Smiod sec_info->entry[mid].cie_inf->need_lsda_relative = 1;
10973d8817e4Smiod return (bfd_vma) -2;
10983d8817e4Smiod }
10993d8817e4Smiod
1100*fc67150aSkettenis /* If converting to DW_EH_PE_pcrel, there will be no need for run-time
1101*fc67150aSkettenis relocation against DW_CFA_set_loc's arguments. */
1102*fc67150aSkettenis if (sec_info->entry[mid].set_loc
1103*fc67150aSkettenis && (sec_info->entry[mid].cie
1104*fc67150aSkettenis ? sec_info->entry[mid].make_relative
1105*fc67150aSkettenis : sec_info->entry[mid].cie_inf->make_relative)
1106*fc67150aSkettenis && (offset >= sec_info->entry[mid].offset + 8
1107*fc67150aSkettenis + sec_info->entry[mid].set_loc[1]))
1108*fc67150aSkettenis {
1109*fc67150aSkettenis unsigned int cnt;
1110*fc67150aSkettenis
1111*fc67150aSkettenis for (cnt = 1; cnt <= sec_info->entry[mid].set_loc[0]; cnt++)
1112*fc67150aSkettenis if (offset == sec_info->entry[mid].offset + 8
1113*fc67150aSkettenis + sec_info->entry[mid].set_loc[cnt])
1114*fc67150aSkettenis return (bfd_vma) -2;
1115*fc67150aSkettenis }
1116*fc67150aSkettenis
11173d8817e4Smiod if (hdr_info->offsets_adjusted)
11183d8817e4Smiod offset -= sec->output_offset;
11193d8817e4Smiod /* Any new augmentation bytes go before the first relocation. */
11203d8817e4Smiod return (offset + sec_info->entry[mid].new_offset
11213d8817e4Smiod - sec_info->entry[mid].offset
11223d8817e4Smiod + extra_augmentation_string_bytes (sec_info->entry + mid)
11233d8817e4Smiod + extra_augmentation_data_bytes (sec_info->entry + mid));
11243d8817e4Smiod }
11253d8817e4Smiod
11263d8817e4Smiod /* Write out .eh_frame section. This is called with the relocated
11273d8817e4Smiod contents. */
11283d8817e4Smiod
11293d8817e4Smiod bfd_boolean
_bfd_elf_write_section_eh_frame(bfd * abfd,struct bfd_link_info * info,asection * sec,bfd_byte * contents)11303d8817e4Smiod _bfd_elf_write_section_eh_frame (bfd *abfd,
11313d8817e4Smiod struct bfd_link_info *info,
11323d8817e4Smiod asection *sec,
11333d8817e4Smiod bfd_byte *contents)
11343d8817e4Smiod {
11353d8817e4Smiod struct eh_frame_sec_info *sec_info;
11363d8817e4Smiod struct elf_link_hash_table *htab;
11373d8817e4Smiod struct eh_frame_hdr_info *hdr_info;
11383d8817e4Smiod unsigned int ptr_size;
11393d8817e4Smiod struct eh_cie_fde *ent;
11403d8817e4Smiod
11413d8817e4Smiod if (sec->sec_info_type != ELF_INFO_TYPE_EH_FRAME)
11423d8817e4Smiod return bfd_set_section_contents (abfd, sec->output_section, contents,
11433d8817e4Smiod sec->output_offset, sec->size);
11443d8817e4Smiod
11453d8817e4Smiod ptr_size = (get_elf_backend_data (abfd)
11463d8817e4Smiod ->elf_backend_eh_frame_address_size (abfd, sec));
11473d8817e4Smiod BFD_ASSERT (ptr_size != 0);
11483d8817e4Smiod
11493d8817e4Smiod sec_info = elf_section_data (sec)->sec_info;
11503d8817e4Smiod htab = elf_hash_table (info);
11513d8817e4Smiod hdr_info = &htab->eh_info;
11523d8817e4Smiod
11533d8817e4Smiod /* First convert all offsets to output section offsets, so that a
11543d8817e4Smiod CIE offset is valid if the CIE is used by a FDE from some other
11553d8817e4Smiod section. This can happen when duplicate CIEs are deleted in
11563d8817e4Smiod _bfd_elf_discard_section_eh_frame. We do all sections here because
11573d8817e4Smiod this function might not be called on sections in the same order as
11583d8817e4Smiod _bfd_elf_discard_section_eh_frame. */
11593d8817e4Smiod if (!hdr_info->offsets_adjusted)
11603d8817e4Smiod {
11613d8817e4Smiod bfd *ibfd;
11623d8817e4Smiod asection *eh;
11633d8817e4Smiod struct eh_frame_sec_info *eh_inf;
11643d8817e4Smiod
11653d8817e4Smiod for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
11663d8817e4Smiod {
11673d8817e4Smiod if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour
11683d8817e4Smiod || (ibfd->flags & DYNAMIC) != 0)
11693d8817e4Smiod continue;
11703d8817e4Smiod
11713d8817e4Smiod eh = bfd_get_section_by_name (ibfd, ".eh_frame");
11723d8817e4Smiod if (eh == NULL || eh->sec_info_type != ELF_INFO_TYPE_EH_FRAME)
11733d8817e4Smiod continue;
11743d8817e4Smiod
11753d8817e4Smiod eh_inf = elf_section_data (eh)->sec_info;
11763d8817e4Smiod for (ent = eh_inf->entry; ent < eh_inf->entry + eh_inf->count; ++ent)
11773d8817e4Smiod {
11783d8817e4Smiod ent->offset += eh->output_offset;
11793d8817e4Smiod ent->new_offset += eh->output_offset;
11803d8817e4Smiod }
11813d8817e4Smiod }
11823d8817e4Smiod hdr_info->offsets_adjusted = TRUE;
11833d8817e4Smiod }
11843d8817e4Smiod
11853d8817e4Smiod if (hdr_info->table && hdr_info->array == NULL)
11863d8817e4Smiod hdr_info->array
11873d8817e4Smiod = bfd_malloc (hdr_info->fde_count * sizeof(*hdr_info->array));
11883d8817e4Smiod if (hdr_info->array == NULL)
11893d8817e4Smiod hdr_info = NULL;
11903d8817e4Smiod
11913d8817e4Smiod /* The new offsets can be bigger or smaller than the original offsets.
11923d8817e4Smiod We therefore need to make two passes over the section: one backward
11933d8817e4Smiod pass to move entries up and one forward pass to move entries down.
11943d8817e4Smiod The two passes won't interfere with each other because entries are
11953d8817e4Smiod not reordered */
11963d8817e4Smiod for (ent = sec_info->entry + sec_info->count; ent-- != sec_info->entry;)
11973d8817e4Smiod if (!ent->removed && ent->new_offset > ent->offset)
11983d8817e4Smiod memmove (contents + ent->new_offset - sec->output_offset,
11993d8817e4Smiod contents + ent->offset - sec->output_offset, ent->size);
12003d8817e4Smiod
12013d8817e4Smiod for (ent = sec_info->entry; ent < sec_info->entry + sec_info->count; ++ent)
12023d8817e4Smiod if (!ent->removed && ent->new_offset < ent->offset)
12033d8817e4Smiod memmove (contents + ent->new_offset - sec->output_offset,
12043d8817e4Smiod contents + ent->offset - sec->output_offset, ent->size);
12053d8817e4Smiod
12063d8817e4Smiod for (ent = sec_info->entry; ent < sec_info->entry + sec_info->count; ++ent)
12073d8817e4Smiod {
12083d8817e4Smiod unsigned char *buf, *end;
12093d8817e4Smiod unsigned int new_size;
12103d8817e4Smiod
12113d8817e4Smiod if (ent->removed)
12123d8817e4Smiod continue;
12133d8817e4Smiod
12143d8817e4Smiod if (ent->size == 4)
12153d8817e4Smiod {
12163d8817e4Smiod /* Any terminating FDE must be at the end of the section. */
12173d8817e4Smiod BFD_ASSERT (ent == sec_info->entry + sec_info->count - 1);
12183d8817e4Smiod continue;
12193d8817e4Smiod }
12203d8817e4Smiod
12213d8817e4Smiod buf = contents + ent->new_offset - sec->output_offset;
12223d8817e4Smiod end = buf + ent->size;
12233d8817e4Smiod new_size = size_of_output_cie_fde (ent, ptr_size);
12243d8817e4Smiod
12253d8817e4Smiod /* Update the size. It may be shrinked. */
12263d8817e4Smiod bfd_put_32 (abfd, new_size - 4, buf);
12273d8817e4Smiod
12283d8817e4Smiod /* Filling the extra bytes with DW_CFA_nops. */
12293d8817e4Smiod if (new_size != ent->size)
12303d8817e4Smiod memset (end, 0, new_size - ent->size);
12313d8817e4Smiod
12323d8817e4Smiod if (ent->cie)
12333d8817e4Smiod {
12343d8817e4Smiod /* CIE */
12353d8817e4Smiod if (ent->make_relative
12363d8817e4Smiod || ent->need_lsda_relative
12373d8817e4Smiod || ent->per_encoding_relative)
12383d8817e4Smiod {
12393d8817e4Smiod char *aug;
12403d8817e4Smiod unsigned int action, extra_string, extra_data;
12413d8817e4Smiod unsigned int per_width, per_encoding;
12423d8817e4Smiod
12433d8817e4Smiod /* Need to find 'R' or 'L' augmentation's argument and modify
12443d8817e4Smiod DW_EH_PE_* value. */
12453d8817e4Smiod action = ((ent->make_relative ? 1 : 0)
12463d8817e4Smiod | (ent->need_lsda_relative ? 2 : 0)
12473d8817e4Smiod | (ent->per_encoding_relative ? 4 : 0));
12483d8817e4Smiod extra_string = extra_augmentation_string_bytes (ent);
12493d8817e4Smiod extra_data = extra_augmentation_data_bytes (ent);
12503d8817e4Smiod
12513d8817e4Smiod /* Skip length, id and version. */
12523d8817e4Smiod buf += 9;
12533d8817e4Smiod aug = (char *) buf;
12543d8817e4Smiod buf += strlen (aug) + 1;
12553d8817e4Smiod skip_leb128 (&buf, end);
12563d8817e4Smiod skip_leb128 (&buf, end);
12573d8817e4Smiod skip_leb128 (&buf, end);
12583d8817e4Smiod if (*aug == 'z')
12593d8817e4Smiod {
12603d8817e4Smiod /* The uleb128 will always be a single byte for the kind
12613d8817e4Smiod of augmentation strings that we're prepared to handle. */
12623d8817e4Smiod *buf++ += extra_data;
12633d8817e4Smiod aug++;
12643d8817e4Smiod }
12653d8817e4Smiod
12663d8817e4Smiod /* Make room for the new augmentation string and data bytes. */
12673d8817e4Smiod memmove (buf + extra_string + extra_data, buf, end - buf);
12683d8817e4Smiod memmove (aug + extra_string, aug, buf - (bfd_byte *) aug);
12693d8817e4Smiod buf += extra_string;
12703d8817e4Smiod end += extra_string + extra_data;
12713d8817e4Smiod
12723d8817e4Smiod if (ent->add_augmentation_size)
12733d8817e4Smiod {
12743d8817e4Smiod *aug++ = 'z';
12753d8817e4Smiod *buf++ = extra_data - 1;
12763d8817e4Smiod }
12773d8817e4Smiod if (ent->add_fde_encoding)
12783d8817e4Smiod {
12793d8817e4Smiod BFD_ASSERT (action & 1);
12803d8817e4Smiod *aug++ = 'R';
12813d8817e4Smiod *buf++ = DW_EH_PE_pcrel;
12823d8817e4Smiod action &= ~1;
12833d8817e4Smiod }
12843d8817e4Smiod
12853d8817e4Smiod while (action)
12863d8817e4Smiod switch (*aug++)
12873d8817e4Smiod {
12883d8817e4Smiod case 'L':
12893d8817e4Smiod if (action & 2)
12903d8817e4Smiod {
12913d8817e4Smiod BFD_ASSERT (*buf == ent->lsda_encoding);
12923d8817e4Smiod *buf |= DW_EH_PE_pcrel;
12933d8817e4Smiod action &= ~2;
12943d8817e4Smiod }
12953d8817e4Smiod buf++;
12963d8817e4Smiod break;
12973d8817e4Smiod case 'P':
12983d8817e4Smiod per_encoding = *buf++;
12993d8817e4Smiod per_width = get_DW_EH_PE_width (per_encoding, ptr_size);
13003d8817e4Smiod BFD_ASSERT (per_width != 0);
13013d8817e4Smiod BFD_ASSERT (((per_encoding & 0x70) == DW_EH_PE_pcrel)
13023d8817e4Smiod == ent->per_encoding_relative);
13033d8817e4Smiod if ((per_encoding & 0xf0) == DW_EH_PE_aligned)
13043d8817e4Smiod buf = (contents
13053d8817e4Smiod + ((buf - contents + per_width - 1)
13063d8817e4Smiod & ~((bfd_size_type) per_width - 1)));
13073d8817e4Smiod if (action & 4)
13083d8817e4Smiod {
13093d8817e4Smiod bfd_vma val;
13103d8817e4Smiod
13113d8817e4Smiod val = read_value (abfd, buf, per_width,
13123d8817e4Smiod get_DW_EH_PE_signed (per_encoding));
13133d8817e4Smiod val += ent->offset - ent->new_offset;
13143d8817e4Smiod val -= extra_string + extra_data;
13153d8817e4Smiod write_value (abfd, buf, val, per_width);
13163d8817e4Smiod action &= ~4;
13173d8817e4Smiod }
13183d8817e4Smiod buf += per_width;
13193d8817e4Smiod break;
13203d8817e4Smiod case 'R':
13213d8817e4Smiod if (action & 1)
13223d8817e4Smiod {
13233d8817e4Smiod BFD_ASSERT (*buf == ent->fde_encoding);
13243d8817e4Smiod *buf |= DW_EH_PE_pcrel;
13253d8817e4Smiod action &= ~1;
13263d8817e4Smiod }
13273d8817e4Smiod buf++;
13283d8817e4Smiod break;
13293d8817e4Smiod case 'S':
13303d8817e4Smiod break;
13313d8817e4Smiod default:
13323d8817e4Smiod BFD_FAIL ();
13333d8817e4Smiod }
13343d8817e4Smiod }
13353d8817e4Smiod }
13363d8817e4Smiod else
13373d8817e4Smiod {
13383d8817e4Smiod /* FDE */
13393d8817e4Smiod bfd_vma value, address;
13403d8817e4Smiod unsigned int width;
1341*fc67150aSkettenis bfd_byte *start;
13423d8817e4Smiod
13433d8817e4Smiod /* Skip length. */
13443d8817e4Smiod buf += 4;
13453d8817e4Smiod value = ent->new_offset + 4 - ent->cie_inf->new_offset;
13463d8817e4Smiod bfd_put_32 (abfd, value, buf);
13473d8817e4Smiod buf += 4;
13483d8817e4Smiod width = get_DW_EH_PE_width (ent->fde_encoding, ptr_size);
13493d8817e4Smiod value = read_value (abfd, buf, width,
13503d8817e4Smiod get_DW_EH_PE_signed (ent->fde_encoding));
13513d8817e4Smiod address = value;
13523d8817e4Smiod if (value)
13533d8817e4Smiod {
13543d8817e4Smiod switch (ent->fde_encoding & 0xf0)
13553d8817e4Smiod {
13563d8817e4Smiod case DW_EH_PE_indirect:
13573d8817e4Smiod case DW_EH_PE_textrel:
13583d8817e4Smiod BFD_ASSERT (hdr_info == NULL);
13593d8817e4Smiod break;
13603d8817e4Smiod case DW_EH_PE_datarel:
13613d8817e4Smiod {
13623d8817e4Smiod asection *got = bfd_get_section_by_name (abfd, ".got");
13633d8817e4Smiod
13643d8817e4Smiod BFD_ASSERT (got != NULL);
13653d8817e4Smiod address += got->vma;
13663d8817e4Smiod }
13673d8817e4Smiod break;
13683d8817e4Smiod case DW_EH_PE_pcrel:
13693d8817e4Smiod value += ent->offset - ent->new_offset;
13703d8817e4Smiod address += sec->output_section->vma + ent->offset + 8;
13713d8817e4Smiod break;
13723d8817e4Smiod }
13733d8817e4Smiod if (ent->cie_inf->make_relative)
13743d8817e4Smiod value -= sec->output_section->vma + ent->new_offset + 8;
13753d8817e4Smiod write_value (abfd, buf, value, width);
13763d8817e4Smiod }
13773d8817e4Smiod
1378*fc67150aSkettenis start = buf;
1379*fc67150aSkettenis
13803d8817e4Smiod if (hdr_info)
13813d8817e4Smiod {
13823d8817e4Smiod hdr_info->array[hdr_info->array_count].initial_loc = address;
13833d8817e4Smiod hdr_info->array[hdr_info->array_count++].fde
13843d8817e4Smiod = sec->output_section->vma + ent->new_offset;
13853d8817e4Smiod }
13863d8817e4Smiod
13873d8817e4Smiod if ((ent->lsda_encoding & 0xf0) == DW_EH_PE_pcrel
13883d8817e4Smiod || ent->cie_inf->need_lsda_relative)
13893d8817e4Smiod {
13903d8817e4Smiod buf += ent->lsda_offset;
13913d8817e4Smiod width = get_DW_EH_PE_width (ent->lsda_encoding, ptr_size);
13923d8817e4Smiod value = read_value (abfd, buf, width,
13933d8817e4Smiod get_DW_EH_PE_signed (ent->lsda_encoding));
13943d8817e4Smiod if (value)
13953d8817e4Smiod {
13963d8817e4Smiod if ((ent->lsda_encoding & 0xf0) == DW_EH_PE_pcrel)
13973d8817e4Smiod value += ent->offset - ent->new_offset;
13983d8817e4Smiod else if (ent->cie_inf->need_lsda_relative)
13993d8817e4Smiod value -= (sec->output_section->vma + ent->new_offset + 8
14003d8817e4Smiod + ent->lsda_offset);
14013d8817e4Smiod write_value (abfd, buf, value, width);
14023d8817e4Smiod }
14033d8817e4Smiod }
14043d8817e4Smiod else if (ent->cie_inf->add_augmentation_size)
14053d8817e4Smiod {
14063d8817e4Smiod /* Skip the PC and length and insert a zero byte for the
14073d8817e4Smiod augmentation size. */
14083d8817e4Smiod buf += width * 2;
14093d8817e4Smiod memmove (buf + 1, buf, end - buf);
14103d8817e4Smiod *buf = 0;
14113d8817e4Smiod }
1412*fc67150aSkettenis
1413*fc67150aSkettenis if (ent->set_loc)
1414*fc67150aSkettenis {
1415*fc67150aSkettenis /* Adjust DW_CFA_set_loc. */
1416*fc67150aSkettenis unsigned int cnt, width;
1417*fc67150aSkettenis bfd_vma new_offset;
1418*fc67150aSkettenis
1419*fc67150aSkettenis width = get_DW_EH_PE_width (ent->fde_encoding, ptr_size);
1420*fc67150aSkettenis new_offset = ent->new_offset + 8
1421*fc67150aSkettenis + extra_augmentation_string_bytes (ent)
1422*fc67150aSkettenis + extra_augmentation_data_bytes (ent);
1423*fc67150aSkettenis
1424*fc67150aSkettenis for (cnt = 1; cnt <= ent->set_loc[0]; cnt++)
1425*fc67150aSkettenis {
1426*fc67150aSkettenis bfd_vma value;
1427*fc67150aSkettenis buf = start + ent->set_loc[cnt];
1428*fc67150aSkettenis
1429*fc67150aSkettenis value = read_value (abfd, buf, width,
1430*fc67150aSkettenis get_DW_EH_PE_signed (ent->fde_encoding));
1431*fc67150aSkettenis if (!value)
1432*fc67150aSkettenis continue;
1433*fc67150aSkettenis
1434*fc67150aSkettenis if ((ent->fde_encoding & 0xf0) == DW_EH_PE_pcrel)
1435*fc67150aSkettenis value += ent->offset + 8 - new_offset;
1436*fc67150aSkettenis if (ent->cie_inf->make_relative)
1437*fc67150aSkettenis value -= sec->output_section->vma + new_offset
1438*fc67150aSkettenis + ent->set_loc[cnt];
1439*fc67150aSkettenis write_value (abfd, buf, value, width);
1440*fc67150aSkettenis }
1441*fc67150aSkettenis }
14423d8817e4Smiod }
14433d8817e4Smiod }
14443d8817e4Smiod
14453d8817e4Smiod /* We don't align the section to its section alignment since the
14463d8817e4Smiod runtime library only expects all CIE/FDE records aligned at
14473d8817e4Smiod the pointer size. _bfd_elf_discard_section_eh_frame should
14483d8817e4Smiod have padded CIE/FDE records to multiple of pointer size with
14493d8817e4Smiod size_of_output_cie_fde. */
14503d8817e4Smiod if ((sec->size % ptr_size) != 0)
14513d8817e4Smiod abort ();
14523d8817e4Smiod
14533d8817e4Smiod return bfd_set_section_contents (abfd, sec->output_section,
14543d8817e4Smiod contents, (file_ptr) sec->output_offset,
14553d8817e4Smiod sec->size);
14563d8817e4Smiod }
14573d8817e4Smiod
14583d8817e4Smiod /* Helper function used to sort .eh_frame_hdr search table by increasing
14593d8817e4Smiod VMA of FDE initial location. */
14603d8817e4Smiod
14613d8817e4Smiod static int
vma_compare(const void * a,const void * b)14623d8817e4Smiod vma_compare (const void *a, const void *b)
14633d8817e4Smiod {
14643d8817e4Smiod const struct eh_frame_array_ent *p = a;
14653d8817e4Smiod const struct eh_frame_array_ent *q = b;
14663d8817e4Smiod if (p->initial_loc > q->initial_loc)
14673d8817e4Smiod return 1;
14683d8817e4Smiod if (p->initial_loc < q->initial_loc)
14693d8817e4Smiod return -1;
14703d8817e4Smiod return 0;
14713d8817e4Smiod }
14723d8817e4Smiod
14733d8817e4Smiod /* Write out .eh_frame_hdr section. This must be called after
14743d8817e4Smiod _bfd_elf_write_section_eh_frame has been called on all input
14753d8817e4Smiod .eh_frame sections.
14763d8817e4Smiod .eh_frame_hdr format:
14773d8817e4Smiod ubyte version (currently 1)
14783d8817e4Smiod ubyte eh_frame_ptr_enc (DW_EH_PE_* encoding of pointer to start of
14793d8817e4Smiod .eh_frame section)
14803d8817e4Smiod ubyte fde_count_enc (DW_EH_PE_* encoding of total FDE count
14813d8817e4Smiod number (or DW_EH_PE_omit if there is no
14823d8817e4Smiod binary search table computed))
14833d8817e4Smiod ubyte table_enc (DW_EH_PE_* encoding of binary search table,
14843d8817e4Smiod or DW_EH_PE_omit if not present.
14853d8817e4Smiod DW_EH_PE_datarel is using address of
14863d8817e4Smiod .eh_frame_hdr section start as base)
14873d8817e4Smiod [encoded] eh_frame_ptr (pointer to start of .eh_frame section)
14883d8817e4Smiod optionally followed by:
14893d8817e4Smiod [encoded] fde_count (total number of FDEs in .eh_frame section)
14903d8817e4Smiod fde_count x [encoded] initial_loc, fde
14913d8817e4Smiod (array of encoded pairs containing
14923d8817e4Smiod FDE initial_location field and FDE address,
14933d8817e4Smiod sorted by increasing initial_loc). */
14943d8817e4Smiod
14953d8817e4Smiod bfd_boolean
_bfd_elf_write_section_eh_frame_hdr(bfd * abfd,struct bfd_link_info * info)14963d8817e4Smiod _bfd_elf_write_section_eh_frame_hdr (bfd *abfd, struct bfd_link_info *info)
14973d8817e4Smiod {
14983d8817e4Smiod struct elf_link_hash_table *htab;
14993d8817e4Smiod struct eh_frame_hdr_info *hdr_info;
15003d8817e4Smiod asection *sec;
15013d8817e4Smiod bfd_byte *contents;
15023d8817e4Smiod asection *eh_frame_sec;
15033d8817e4Smiod bfd_size_type size;
15043d8817e4Smiod bfd_boolean retval;
15053d8817e4Smiod bfd_vma encoded_eh_frame;
15063d8817e4Smiod
15073d8817e4Smiod htab = elf_hash_table (info);
15083d8817e4Smiod hdr_info = &htab->eh_info;
15093d8817e4Smiod sec = hdr_info->hdr_sec;
15103d8817e4Smiod if (sec == NULL)
15113d8817e4Smiod return TRUE;
15123d8817e4Smiod
15133d8817e4Smiod size = EH_FRAME_HDR_SIZE;
15143d8817e4Smiod if (hdr_info->array && hdr_info->array_count == hdr_info->fde_count)
15153d8817e4Smiod size += 4 + hdr_info->fde_count * 8;
15163d8817e4Smiod contents = bfd_malloc (size);
15173d8817e4Smiod if (contents == NULL)
15183d8817e4Smiod return FALSE;
15193d8817e4Smiod
15203d8817e4Smiod eh_frame_sec = bfd_get_section_by_name (abfd, ".eh_frame");
15213d8817e4Smiod if (eh_frame_sec == NULL)
15223d8817e4Smiod {
15233d8817e4Smiod free (contents);
15243d8817e4Smiod return FALSE;
15253d8817e4Smiod }
15263d8817e4Smiod
15273d8817e4Smiod memset (contents, 0, EH_FRAME_HDR_SIZE);
15283d8817e4Smiod contents[0] = 1; /* Version. */
15293d8817e4Smiod contents[1] = get_elf_backend_data (abfd)->elf_backend_encode_eh_address
15303d8817e4Smiod (abfd, info, eh_frame_sec, 0, sec, 4,
15313d8817e4Smiod &encoded_eh_frame); /* .eh_frame offset. */
15323d8817e4Smiod
15333d8817e4Smiod if (hdr_info->array && hdr_info->array_count == hdr_info->fde_count)
15343d8817e4Smiod {
15353d8817e4Smiod contents[2] = DW_EH_PE_udata4; /* FDE count encoding. */
15363d8817e4Smiod contents[3] = DW_EH_PE_datarel | DW_EH_PE_sdata4; /* Search table enc. */
15373d8817e4Smiod }
15383d8817e4Smiod else
15393d8817e4Smiod {
15403d8817e4Smiod contents[2] = DW_EH_PE_omit;
15413d8817e4Smiod contents[3] = DW_EH_PE_omit;
15423d8817e4Smiod }
15433d8817e4Smiod bfd_put_32 (abfd, encoded_eh_frame, contents + 4);
15443d8817e4Smiod
15453d8817e4Smiod if (contents[2] != DW_EH_PE_omit)
15463d8817e4Smiod {
15473d8817e4Smiod unsigned int i;
15483d8817e4Smiod
15493d8817e4Smiod bfd_put_32 (abfd, hdr_info->fde_count, contents + EH_FRAME_HDR_SIZE);
15503d8817e4Smiod qsort (hdr_info->array, hdr_info->fde_count, sizeof (*hdr_info->array),
15513d8817e4Smiod vma_compare);
15523d8817e4Smiod for (i = 0; i < hdr_info->fde_count; i++)
15533d8817e4Smiod {
15543d8817e4Smiod bfd_put_32 (abfd,
15553d8817e4Smiod hdr_info->array[i].initial_loc
15563d8817e4Smiod - sec->output_section->vma,
15573d8817e4Smiod contents + EH_FRAME_HDR_SIZE + i * 8 + 4);
15583d8817e4Smiod bfd_put_32 (abfd,
15593d8817e4Smiod hdr_info->array[i].fde - sec->output_section->vma,
15603d8817e4Smiod contents + EH_FRAME_HDR_SIZE + i * 8 + 8);
15613d8817e4Smiod }
15623d8817e4Smiod }
15633d8817e4Smiod
15643d8817e4Smiod retval = bfd_set_section_contents (abfd, sec->output_section,
15653d8817e4Smiod contents, (file_ptr) sec->output_offset,
15663d8817e4Smiod sec->size);
15673d8817e4Smiod free (contents);
15683d8817e4Smiod return retval;
15693d8817e4Smiod }
15703d8817e4Smiod
15713d8817e4Smiod /* Return the width of FDE addresses. This is the default implementation. */
15723d8817e4Smiod
15733d8817e4Smiod unsigned int
_bfd_elf_eh_frame_address_size(bfd * abfd,asection * sec ATTRIBUTE_UNUSED)15743d8817e4Smiod _bfd_elf_eh_frame_address_size (bfd *abfd, asection *sec ATTRIBUTE_UNUSED)
15753d8817e4Smiod {
15763d8817e4Smiod return elf_elfheader (abfd)->e_ident[EI_CLASS] == ELFCLASS64 ? 8 : 4;
15773d8817e4Smiod }
15783d8817e4Smiod
15793d8817e4Smiod /* Decide whether we can use a PC-relative encoding within the given
15803d8817e4Smiod EH frame section. This is the default implementation. */
15813d8817e4Smiod
15823d8817e4Smiod bfd_boolean
_bfd_elf_can_make_relative(bfd * input_bfd ATTRIBUTE_UNUSED,struct bfd_link_info * info ATTRIBUTE_UNUSED,asection * eh_frame_section ATTRIBUTE_UNUSED)15833d8817e4Smiod _bfd_elf_can_make_relative (bfd *input_bfd ATTRIBUTE_UNUSED,
15843d8817e4Smiod struct bfd_link_info *info ATTRIBUTE_UNUSED,
15853d8817e4Smiod asection *eh_frame_section ATTRIBUTE_UNUSED)
15863d8817e4Smiod {
15873d8817e4Smiod return TRUE;
15883d8817e4Smiod }
15893d8817e4Smiod
15903d8817e4Smiod /* Select an encoding for the given address. Preference is given to
15913d8817e4Smiod PC-relative addressing modes. */
15923d8817e4Smiod
15933d8817e4Smiod bfd_byte
_bfd_elf_encode_eh_address(bfd * abfd ATTRIBUTE_UNUSED,struct bfd_link_info * info ATTRIBUTE_UNUSED,asection * osec,bfd_vma offset,asection * loc_sec,bfd_vma loc_offset,bfd_vma * encoded)15943d8817e4Smiod _bfd_elf_encode_eh_address (bfd *abfd ATTRIBUTE_UNUSED,
15953d8817e4Smiod struct bfd_link_info *info ATTRIBUTE_UNUSED,
15963d8817e4Smiod asection *osec, bfd_vma offset,
15973d8817e4Smiod asection *loc_sec, bfd_vma loc_offset,
15983d8817e4Smiod bfd_vma *encoded)
15993d8817e4Smiod {
16003d8817e4Smiod *encoded = osec->vma + offset -
16013d8817e4Smiod (loc_sec->output_section->vma + loc_sec->output_offset + loc_offset);
16023d8817e4Smiod return DW_EH_PE_pcrel | DW_EH_PE_sdata4;
16033d8817e4Smiod }
1604