summaryrefslogtreecommitdiffstats
path: root/binutils-2.17/bfd/elf-eh-frame.c
diff options
context:
space:
mode:
Diffstat (limited to 'binutils-2.17/bfd/elf-eh-frame.c')
-rw-r--r--binutils-2.17/bfd/elf-eh-frame.c1424
1 files changed, 0 insertions, 1424 deletions
diff --git a/binutils-2.17/bfd/elf-eh-frame.c b/binutils-2.17/bfd/elf-eh-frame.c
deleted file mode 100644
index 5100e729..00000000
--- a/binutils-2.17/bfd/elf-eh-frame.c
+++ /dev/null
@@ -1,1424 +0,0 @@
-/* .eh_frame section optimization.
- Copyright 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
- Written by Jakub Jelinek <jakub@redhat.com>.
-
- This file is part of BFD, the Binary File Descriptor library.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */
-
-#include "bfd.h"
-#include "sysdep.h"
-#include "libbfd.h"
-#include "elf-bfd.h"
-#include "elf/dwarf2.h"
-
-#define EH_FRAME_HDR_SIZE 8
-
-/* If *ITER hasn't reached END yet, read the next byte into *RESULT and
- move onto the next byte. Return true on success. */
-
-static inline bfd_boolean
-read_byte (bfd_byte **iter, bfd_byte *end, unsigned char *result)
-{
- if (*iter >= end)
- return FALSE;
- *result = *((*iter)++);
- return TRUE;
-}
-
-/* Move *ITER over LENGTH bytes, or up to END, whichever is closer.
- Return true it was possible to move LENGTH bytes. */
-
-static inline bfd_boolean
-skip_bytes (bfd_byte **iter, bfd_byte *end, bfd_size_type length)
-{
- if ((bfd_size_type) (end - *iter) < length)
- {
- *iter = end;
- return FALSE;
- }
- *iter += length;
- return TRUE;
-}
-
-/* Move *ITER over an leb128, stopping at END. Return true if the end
- of the leb128 was found. */
-
-static bfd_boolean
-skip_leb128 (bfd_byte **iter, bfd_byte *end)
-{
- unsigned char byte;
- do
- if (!read_byte (iter, end, &byte))
- return FALSE;
- while (byte & 0x80);
- return TRUE;
-}
-
-/* Like skip_leb128, but treat the leb128 as an unsigned value and
- store it in *VALUE. */
-
-static bfd_boolean
-read_uleb128 (bfd_byte **iter, bfd_byte *end, bfd_vma *value)
-{
- bfd_byte *start, *p;
-
- start = *iter;
- if (!skip_leb128 (iter, end))
- return FALSE;
-
- p = *iter;
- *value = *--p;
- while (p > start)
- *value = (*value << 7) | (*--p & 0x7f);
-
- return TRUE;
-}
-
-/* Like read_uleb128, but for signed values. */
-
-static bfd_boolean
-read_sleb128 (bfd_byte **iter, bfd_byte *end, bfd_signed_vma *value)
-{
- bfd_byte *start, *p;
-
- start = *iter;
- if (!skip_leb128 (iter, end))
- return FALSE;
-
- p = *iter;
- *value = ((*--p & 0x7f) ^ 0x40) - 0x40;
- while (p > start)
- *value = (*value << 7) | (*--p & 0x7f);
-
- return TRUE;
-}
-
-/* Return 0 if either encoding is variable width, or not yet known to bfd. */
-
-static
-int get_DW_EH_PE_width (int encoding, int ptr_size)
-{
- /* DW_EH_PE_ values of 0x60 and 0x70 weren't defined at the time .eh_frame
- was added to bfd. */
- if ((encoding & 0x60) == 0x60)
- return 0;
-
- switch (encoding & 7)
- {
- case DW_EH_PE_udata2: return 2;
- case DW_EH_PE_udata4: return 4;
- case DW_EH_PE_udata8: return 8;
- case DW_EH_PE_absptr: return ptr_size;
- default:
- break;
- }
-
- return 0;
-}
-
-#define get_DW_EH_PE_signed(encoding) (((encoding) & DW_EH_PE_signed) != 0)
-
-/* Read a width sized value from memory. */
-
-static bfd_vma
-read_value (bfd *abfd, bfd_byte *buf, int width, int is_signed)
-{
- bfd_vma value;
-
- switch (width)
- {
- case 2:
- if (is_signed)
- value = bfd_get_signed_16 (abfd, buf);
- else
- value = bfd_get_16 (abfd, buf);
- break;
- case 4:
- if (is_signed)
- value = bfd_get_signed_32 (abfd, buf);
- else
- value = bfd_get_32 (abfd, buf);
- break;
- case 8:
- if (is_signed)
- value = bfd_get_signed_64 (abfd, buf);
- else
- value = bfd_get_64 (abfd, buf);
- break;
- default:
- BFD_FAIL ();
- return 0;
- }
-
- return value;
-}
-
-/* Store a width sized value to memory. */
-
-static void
-write_value (bfd *abfd, bfd_byte *buf, bfd_vma value, int width)
-{
- switch (width)
- {
- case 2: bfd_put_16 (abfd, value, buf); break;
- case 4: bfd_put_32 (abfd, value, buf); break;
- case 8: bfd_put_64 (abfd, value, buf); break;
- default: BFD_FAIL ();
- }
-}
-
-/* Return zero if C1 and C2 CIEs can be merged. */
-
-static
-int cie_compare (struct cie *c1, struct cie *c2)
-{
- if (c1->hdr.length == c2->hdr.length
- && c1->version == c2->version
- && strcmp (c1->augmentation, c2->augmentation) == 0
- && strcmp (c1->augmentation, "eh") != 0
- && c1->code_align == c2->code_align
- && c1->data_align == c2->data_align
- && c1->ra_column == c2->ra_column
- && c1->augmentation_size == c2->augmentation_size
- && c1->personality == c2->personality
- && c1->per_encoding == c2->per_encoding
- && c1->lsda_encoding == c2->lsda_encoding
- && c1->fde_encoding == c2->fde_encoding
- && c1->initial_insn_length == c2->initial_insn_length
- && memcmp (c1->initial_instructions,
- c2->initial_instructions,
- c1->initial_insn_length) == 0)
- return 0;
-
- return 1;
-}
-
-/* Return the number of extra bytes that we'll be inserting into
- ENTRY's augmentation string. */
-
-static INLINE unsigned int
-extra_augmentation_string_bytes (struct eh_cie_fde *entry)
-{
- unsigned int size = 0;
- if (entry->cie)
- {
- if (entry->add_augmentation_size)
- size++;
- if (entry->add_fde_encoding)
- size++;
- }
- return size;
-}
-
-/* Likewise ENTRY's augmentation data. */
-
-static INLINE unsigned int
-extra_augmentation_data_bytes (struct eh_cie_fde *entry)
-{
- unsigned int size = 0;
- if (entry->cie)
- {
- if (entry->add_augmentation_size)
- size++;
- if (entry->add_fde_encoding)
- size++;
- }
- else
- {
- if (entry->cie_inf->add_augmentation_size)
- size++;
- }
- return size;
-}
-
-/* Return the size that ENTRY will have in the output. ALIGNMENT is the
- required alignment of ENTRY in bytes. */
-
-static unsigned int
-size_of_output_cie_fde (struct eh_cie_fde *entry, unsigned int alignment)
-{
- if (entry->removed)
- return 0;
- if (entry->size == 4)
- return 4;
- return (entry->size
- + extra_augmentation_string_bytes (entry)
- + extra_augmentation_data_bytes (entry)
- + alignment - 1) & -alignment;
-}
-
-/* Assume that the bytes between *ITER and END are CFA instructions.
- Try to move *ITER past the first instruction and return true on
- success. ENCODED_PTR_WIDTH gives the width of pointer entries. */
-
-static bfd_boolean
-skip_cfa_op (bfd_byte **iter, bfd_byte *end, unsigned int encoded_ptr_width)
-{
- bfd_byte op;
- bfd_vma length;
-
- if (!read_byte (iter, end, &op))
- return FALSE;
-
- switch (op & 0x80 ? op & 0xc0 : op)
- {
- case DW_CFA_nop:
- case DW_CFA_advance_loc:
- case DW_CFA_restore:
- /* No arguments. */
- return TRUE;
-
- case DW_CFA_offset:
- case DW_CFA_restore_extended:
- case DW_CFA_undefined:
- case DW_CFA_same_value:
- case DW_CFA_def_cfa_register:
- case DW_CFA_def_cfa_offset:
- case DW_CFA_def_cfa_offset_sf:
- case DW_CFA_GNU_args_size:
- /* One leb128 argument. */
- return skip_leb128 (iter, end);
-
- case DW_CFA_offset_extended:
- case DW_CFA_register:
- case DW_CFA_def_cfa:
- case DW_CFA_offset_extended_sf:
- case DW_CFA_GNU_negative_offset_extended:
- case DW_CFA_def_cfa_sf:
- /* Two leb128 arguments. */
- return (skip_leb128 (iter, end)
- && skip_leb128 (iter, end));
-
- case DW_CFA_def_cfa_expression:
- /* A variable-length argument. */
- return (read_uleb128 (iter, end, &length)
- && skip_bytes (iter, end, length));
-
- case DW_CFA_expression:
- /* A leb128 followed by a variable-length argument. */
- return (skip_leb128 (iter, end)
- && read_uleb128 (iter, end, &length)
- && skip_bytes (iter, end, length));
-
- case DW_CFA_set_loc:
- return skip_bytes (iter, end, encoded_ptr_width);
-
- case DW_CFA_advance_loc1:
- return skip_bytes (iter, end, 1);
-
- case DW_CFA_advance_loc2:
- return skip_bytes (iter, end, 2);
-
- case DW_CFA_advance_loc4:
- return skip_bytes (iter, end, 4);
-
- case DW_CFA_MIPS_advance_loc8:
- return skip_bytes (iter, end, 8);
-
- default:
- return FALSE;
- }
-}
-
-/* Try to interpret the bytes between BUF and END as CFA instructions.
- If every byte makes sense, return a pointer to the first DW_CFA_nop
- padding byte, or END if there is no padding. Return null otherwise.
- ENCODED_PTR_WIDTH is as for skip_cfa_op. */
-
-static bfd_byte *
-skip_non_nops (bfd_byte *buf, bfd_byte *end, unsigned int encoded_ptr_width)
-{
- bfd_byte *last;
-
- last = buf;
- while (buf < end)
- if (*buf == DW_CFA_nop)
- buf++;
- else
- {
- if (!skip_cfa_op (&buf, end, encoded_ptr_width))
- return 0;
- last = buf;
- }
- return last;
-}
-
-/* This function is called for each input file before the .eh_frame
- section is relocated. It discards duplicate CIEs and FDEs for discarded
- functions. The function returns TRUE iff any entries have been
- deleted. */
-
-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)
-{
-#define REQUIRE(COND) \
- do \
- if (!(COND)) \
- goto free_no_table; \
- while (0)
-
- bfd_byte *ehbuf = NULL, *buf;
- bfd_byte *last_cie, *last_fde;
- struct eh_cie_fde *ent, *last_cie_inf, *this_inf;
- struct cie_header hdr;
- struct cie cie;
- struct elf_link_hash_table *htab;
- struct eh_frame_hdr_info *hdr_info;
- struct eh_frame_sec_info *sec_info = NULL;
- unsigned int cie_usage_count, offset;
- unsigned int ptr_size;
-
- if (sec->size == 0)
- {
- /* This file does not contain .eh_frame information. */
- return FALSE;
- }
-
- if ((sec->output_section != NULL
- && bfd_is_abs_section (sec->output_section)))
- {
- /* At least one of the sections is being discarded from the
- link, so we should just ignore them. */
- return FALSE;
- }
-
- htab = elf_hash_table (info);
- hdr_info = &htab->eh_info;
-
- /* Read the frame unwind information from abfd. */
-
- REQUIRE (bfd_malloc_and_get_section (abfd, sec, &ehbuf));
-
- if (sec->size >= 4
- && bfd_get_32 (abfd, ehbuf) == 0
- && cookie->rel == cookie->relend)
- {
- /* Empty .eh_frame section. */
- free (ehbuf);
- return FALSE;
- }
-
- /* If .eh_frame section size doesn't fit into int, we cannot handle
- it (it would need to use 64-bit .eh_frame format anyway). */
- REQUIRE (sec->size == (unsigned int) sec->size);
-
- ptr_size = (get_elf_backend_data (abfd)
- ->elf_backend_eh_frame_address_size (abfd, sec));
- REQUIRE (ptr_size != 0);
-
- buf = ehbuf;
- last_cie = NULL;
- last_cie_inf = NULL;
- memset (&cie, 0, sizeof (cie));
- cie_usage_count = 0;
- sec_info = bfd_zmalloc (sizeof (struct eh_frame_sec_info)
- + 99 * sizeof (struct eh_cie_fde));
- REQUIRE (sec_info);
-
- sec_info->alloced = 100;
-
-#define ENSURE_NO_RELOCS(buf) \
- REQUIRE (!(cookie->rel < cookie->relend \
- && (cookie->rel->r_offset \
- < (bfd_size_type) ((buf) - ehbuf)) \
- && cookie->rel->r_info != 0))
-
-#define SKIP_RELOCS(buf) \
- while (cookie->rel < cookie->relend \
- && (cookie->rel->r_offset \
- < (bfd_size_type) ((buf) - ehbuf))) \
- cookie->rel++
-
-#define GET_RELOC(buf) \
- ((cookie->rel < cookie->relend \
- && (cookie->rel->r_offset \
- == (bfd_size_type) ((buf) - ehbuf))) \
- ? cookie->rel : NULL)
-
- for (;;)
- {
- char *aug;
- bfd_byte *start, *end, *insns;
- bfd_size_type length;
-
- if (sec_info->count == sec_info->alloced)
- {
- struct eh_cie_fde *old_entry = sec_info->entry;
- sec_info = bfd_realloc (sec_info,
- sizeof (struct eh_frame_sec_info)
- + ((sec_info->alloced + 99)
- * sizeof (struct eh_cie_fde)));
- REQUIRE (sec_info);
-
- memset (&sec_info->entry[sec_info->alloced], 0,
- 100 * sizeof (struct eh_cie_fde));
- sec_info->alloced += 100;
-
- /* Now fix any pointers into the array. */
- if (last_cie_inf >= old_entry
- && last_cie_inf < old_entry + sec_info->count)
- last_cie_inf = sec_info->entry + (last_cie_inf - old_entry);
- }
-
- this_inf = sec_info->entry + sec_info->count;
- last_fde = buf;
- /* If we are at the end of the section, we still need to decide
- on whether to output or discard last encountered CIE (if any). */
- if ((bfd_size_type) (buf - ehbuf) == sec->size)
- {
- hdr.length = 0;
- hdr.id = (unsigned int) -1;
- end = buf;
- }
- else
- {
- /* Read the length of the entry. */
- REQUIRE (skip_bytes (&buf, ehbuf + sec->size, 4));
- hdr.length = bfd_get_32 (abfd, buf - 4);
-
- /* 64-bit .eh_frame is not supported. */
- REQUIRE (hdr.length != 0xffffffff);
-
- /* The CIE/FDE must be fully contained in this input section. */
- REQUIRE ((bfd_size_type) (buf - ehbuf) + hdr.length <= sec->size);
- end = buf + hdr.length;
-
- this_inf->offset = last_fde - ehbuf;
- this_inf->size = 4 + hdr.length;
-
- if (hdr.length == 0)
- {
- /* A zero-length CIE should only be found at the end of
- the section. */
- REQUIRE ((bfd_size_type) (buf - ehbuf) == sec->size);
- ENSURE_NO_RELOCS (buf);
- sec_info->count++;
- /* Now just finish last encountered CIE processing and break
- the loop. */
- hdr.id = (unsigned int) -1;
- }
- else
- {
- REQUIRE (skip_bytes (&buf, end, 4));
- hdr.id = bfd_get_32 (abfd, buf - 4);
- REQUIRE (hdr.id != (unsigned int) -1);
- }
- }
-
- if (hdr.id == 0 || hdr.id == (unsigned int) -1)
- {
- unsigned int initial_insn_length;
-
- /* CIE */
- if (last_cie != NULL)
- {
- /* Now check if this CIE is identical to the last CIE,
- in which case we can remove it provided we adjust
- all FDEs. Also, it can be removed if we have removed
- all FDEs using it. */
- if ((!info->relocatable
- && hdr_info->last_cie_sec
- && (sec->output_section
- == hdr_info->last_cie_sec->output_section)
- && cie_compare (&cie, &hdr_info->last_cie) == 0)
- || cie_usage_count == 0)
- last_cie_inf->removed = 1;
- else
- {
- hdr_info->last_cie = cie;
- hdr_info->last_cie_sec = sec;
- last_cie_inf->make_relative = cie.make_relative;
- last_cie_inf->make_lsda_relative = cie.make_lsda_relative;
- last_cie_inf->per_encoding_relative
- = (cie.per_encoding & 0x70) == DW_EH_PE_pcrel;
- }
- }
-
- if (hdr.id == (unsigned int) -1)
- break;
-
- last_cie_inf = this_inf;
- this_inf->cie = 1;
-
- cie_usage_count = 0;
- memset (&cie, 0, sizeof (cie));
- cie.hdr = hdr;
- REQUIRE (read_byte (&buf, end, &cie.version));
-
- /* Cannot handle unknown versions. */
- REQUIRE (cie.version == 1 || cie.version == 3);
- REQUIRE (strlen ((char *) buf) < sizeof (cie.augmentation));
-
- strcpy (cie.augmentation, (char *) buf);
- buf = (bfd_byte *) strchr ((char *) buf, '\0') + 1;
- ENSURE_NO_RELOCS (buf);
- if (buf[0] == 'e' && buf[1] == 'h')
- {
- /* GCC < 3.0 .eh_frame CIE */
- /* We cannot merge "eh" CIEs because __EXCEPTION_TABLE__
- is private to each CIE, so we don't need it for anything.
- Just skip it. */
- REQUIRE (skip_bytes (&buf, end, ptr_size));
- SKIP_RELOCS (buf);
- }
- REQUIRE (read_uleb128 (&buf, end, &cie.code_align));
- REQUIRE (read_sleb128 (&buf, end, &cie.data_align));
- if (cie.version == 1)
- {
- REQUIRE (buf < end);
- cie.ra_column = *buf++;
- }
- else
- REQUIRE (read_uleb128 (&buf, end, &cie.ra_column));
- ENSURE_NO_RELOCS (buf);
- cie.lsda_encoding = DW_EH_PE_omit;
- cie.fde_encoding = DW_EH_PE_omit;
- cie.per_encoding = DW_EH_PE_omit;
- aug = cie.augmentation;
- if (aug[0] != 'e' || aug[1] != 'h')
- {
- if (*aug == 'z')
- {
- aug++;
- REQUIRE (read_uleb128 (&buf, end, &cie.augmentation_size));
- ENSURE_NO_RELOCS (buf);
- }
-
- while (*aug != '\0')
- switch (*aug++)
- {
- case 'L':
- REQUIRE (read_byte (&buf, end, &cie.lsda_encoding));
- ENSURE_NO_RELOCS (buf);
- REQUIRE (get_DW_EH_PE_width (cie.lsda_encoding, ptr_size));
- break;
- case 'R':
- REQUIRE (read_byte (&buf, end, &cie.fde_encoding));
- ENSURE_NO_RELOCS (buf);
- REQUIRE (get_DW_EH_PE_width (cie.fde_encoding, ptr_size));
- break;
- case 'S':
- break;
- case 'P':
- {
- int per_width;
-
- REQUIRE (read_byte (&buf, end, &cie.per_encoding));
- per_width = get_DW_EH_PE_width (cie.per_encoding,
- ptr_size);
- REQUIRE (per_width);
- if ((cie.per_encoding & 0xf0) == DW_EH_PE_aligned)
- {
- length = -(buf - ehbuf) & (per_width - 1);
- REQUIRE (skip_bytes (&buf, end, length));
- }
- ENSURE_NO_RELOCS (buf);
- /* Ensure we have a reloc here, against
- a global symbol. */
- if (GET_RELOC (buf) != NULL)
- {
- unsigned long r_symndx;
-
-#ifdef BFD64
- if (ptr_size == 8)
- r_symndx = ELF64_R_SYM (cookie->rel->r_info);
- else
-#endif
- r_symndx = ELF32_R_SYM (cookie->rel->r_info);
- if (r_symndx >= cookie->locsymcount)
- {
- struct elf_link_hash_entry *h;
-
- r_symndx -= cookie->extsymoff;
- h = cookie->sym_hashes[r_symndx];
-
- while (h->root.type == bfd_link_hash_indirect
- || h->root.type == bfd_link_hash_warning)
- h = (struct elf_link_hash_entry *)
- h->root.u.i.link;
-
- cie.personality = h;
- }
- /* Cope with MIPS-style composite relocations. */
- do
- cookie->rel++;
- while (GET_RELOC (buf) != NULL);
- }
- REQUIRE (skip_bytes (&buf, end, per_width));
- }
- break;
- default:
- /* Unrecognized augmentation. Better bail out. */
- goto free_no_table;
- }
- }
-
- /* For shared libraries, try to get rid of as many RELATIVE relocs
- as possible. */
- if (info->shared
- && (get_elf_backend_data (abfd)
- ->elf_backend_can_make_relative_eh_frame
- (abfd, info, sec)))
- {
- if ((cie.fde_encoding & 0xf0) == DW_EH_PE_absptr)
- cie.make_relative = 1;
- /* If the CIE doesn't already have an 'R' entry, it's fairly
- easy to add one, provided that there's no aligned data
- after the augmentation string. */
- else if (cie.fde_encoding == DW_EH_PE_omit
- && (cie.per_encoding & 0xf0) != DW_EH_PE_aligned)
- {
- if (*cie.augmentation == 0)
- this_inf->add_augmentation_size = 1;
- this_inf->add_fde_encoding = 1;
- cie.make_relative = 1;
- }
- }
-
- if (info->shared
- && (get_elf_backend_data (abfd)
- ->elf_backend_can_make_lsda_relative_eh_frame
- (abfd, info, sec))
- && (cie.lsda_encoding & 0xf0) == DW_EH_PE_absptr)
- cie.make_lsda_relative = 1;
-
- /* If FDE encoding was not specified, it defaults to
- DW_EH_absptr. */
- if (cie.fde_encoding == DW_EH_PE_omit)
- cie.fde_encoding = DW_EH_PE_absptr;
-
- initial_insn_length = end - buf;
- if (initial_insn_length <= 50)
- {
- cie.initial_insn_length = initial_insn_length;
- memcpy (cie.initial_instructions, buf, initial_insn_length);
- }
- insns = buf;
- buf += initial_insn_length;
- ENSURE_NO_RELOCS (buf);
- last_cie = last_fde;
- }
- else
- {
- /* Ensure this FDE uses the last CIE encountered. */
- REQUIRE (last_cie);
- REQUIRE (hdr.id == (unsigned int) (buf - 4 - last_cie));
-
- ENSURE_NO_RELOCS (buf);
- REQUIRE (GET_RELOC (buf));
-
- if ((*reloc_symbol_deleted_p) (buf - ehbuf, cookie))
- /* This is a FDE against a discarded section. It should
- be deleted. */
- this_inf->removed = 1;
- else
- {
- if (info->shared
- && (((cie.fde_encoding & 0xf0) == DW_EH_PE_absptr
- && cie.make_relative == 0)
- || (cie.fde_encoding & 0xf0) == DW_EH_PE_aligned))
- {
- /* If a shared library uses absolute pointers
- which we cannot turn into PC relative,
- don't create the binary search table,
- since it is affected by runtime relocations. */
- hdr_info->table = FALSE;
- }
- cie_usage_count++;
- hdr_info->fde_count++;
- }
- /* Skip the initial location and address range. */
- start = buf;
- length = get_DW_EH_PE_width (cie.fde_encoding, ptr_size);
- REQUIRE (skip_bytes (&buf, end, 2 * length));
-
- /* Skip the augmentation size, if present. */
- if (cie.augmentation[0] == 'z')
- REQUIRE (read_uleb128 (&buf, end, &length));
- else
- length = 0;
-
- /* Of the supported augmentation characters above, only 'L'
- adds augmentation data to the FDE. This code would need to
- be adjusted if any future augmentations do the same thing. */
- if (cie.lsda_encoding != DW_EH_PE_omit)
- {
- this_inf->lsda_offset = buf - start;
- /* If there's no 'z' augmentation, we don't know where the
- CFA insns begin. Assume no padding. */
- if (cie.augmentation[0] != 'z')
- length = end - buf;
- }
-
- /* Skip over the augmentation data. */
- REQUIRE (skip_bytes (&buf, end, length));
- insns = buf;
-
- buf = last_fde + 4 + hdr.length;
- SKIP_RELOCS (buf);
- }
-
- /* Try to interpret the CFA instructions and find the first
- padding nop. Shrink this_inf's size so that it doesn't
- including the padding. */
- length = get_DW_EH_PE_width (cie.fde_encoding, ptr_size);
- insns = skip_non_nops (insns, end, length);
- if (insns != 0)
- this_inf->size -= end - insns;
-
- this_inf->fde_encoding = cie.fde_encoding;
- this_inf->lsda_encoding = cie.lsda_encoding;
- sec_info->count++;
- }
-
- elf_section_data (sec)->sec_info = sec_info;
- sec->sec_info_type = ELF_INFO_TYPE_EH_FRAME;
-
- /* Ok, now we can assign new offsets. */
- offset = 0;
- last_cie_inf = hdr_info->last_cie_inf;
- for (ent = sec_info->entry; ent < sec_info->entry + sec_info->count; ++ent)
- if (!ent->removed)
- {
- if (ent->cie)
- last_cie_inf = ent;
- else
- ent->cie_inf = last_cie_inf;
- ent->new_offset = offset;
- offset += size_of_output_cie_fde (ent, ptr_size);
- }
- hdr_info->last_cie_inf = last_cie_inf;
-
- /* Resize the sec as needed. */
- sec->rawsize = sec->size;
- sec->size = offset;
- if (sec->size == 0)
- sec->flags |= SEC_EXCLUDE;
-
- free (ehbuf);
- return offset != sec->rawsize;
-
-free_no_table:
- if (ehbuf)
- free (ehbuf);
- if (sec_info)
- free (sec_info);
- hdr_info->table = FALSE;
- hdr_info->last_cie.hdr.length = 0;
- return FALSE;
-
-#undef REQUIRE
-}
-
-/* This function is called for .eh_frame_hdr section after
- _bfd_elf_discard_section_eh_frame has been called on all .eh_frame
- input sections. It finalizes the size of .eh_frame_hdr section. */
-
-bfd_boolean
-_bfd_elf_discard_section_eh_frame_hdr (bfd *abfd, struct bfd_link_info *info)
-{
- struct elf_link_hash_table *htab;
- struct eh_frame_hdr_info *hdr_info;
- asection *sec;
-
- htab = elf_hash_table (info);
- hdr_info = &htab->eh_info;
- sec = hdr_info->hdr_sec;
- if (sec == NULL)
- return FALSE;
-
- sec->size = EH_FRAME_HDR_SIZE;
- if (hdr_info->table)
- sec->size += 4 + hdr_info->fde_count * 8;
-
- /* Request program headers to be recalculated. */
- elf_tdata (abfd)->program_header_size = 0;
- elf_tdata (abfd)->eh_frame_hdr = sec;
- return TRUE;
-}
-
-/* This function is called from size_dynamic_sections.
- It needs to decide whether .eh_frame_hdr should be output or not,
- because when the dynamic symbol table has been sized it is too late
- to strip sections. */
-
-bfd_boolean
-_bfd_elf_maybe_strip_eh_frame_hdr (struct bfd_link_info *info)
-{
- asection *o;
- bfd *abfd;
- struct elf_link_hash_table *htab;
- struct eh_frame_hdr_info *hdr_info;
-
- htab = elf_hash_table (info);
- hdr_info = &htab->eh_info;
- if (hdr_info->hdr_sec == NULL)
- return TRUE;
-
- if (bfd_is_abs_section (hdr_info->hdr_sec->output_section))
- {
- hdr_info->hdr_sec = NULL;
- return TRUE;
- }
-
- abfd = NULL;
- if (info->eh_frame_hdr)
- for (abfd = info->input_bfds; abfd != NULL; abfd = abfd->link_next)
- {
- /* Count only sections which have at least a single CIE or FDE.
- There cannot be any CIE or FDE <= 8 bytes. */
- o = bfd_get_section_by_name (abfd, ".eh_frame");
- if (o && o->size > 8 && !bfd_is_abs_section (o->output_section))
- break;
- }
-
- if (abfd == NULL)
- {
- hdr_info->hdr_sec->flags |= SEC_EXCLUDE;
- hdr_info->hdr_sec = NULL;
- return TRUE;
- }
-
- hdr_info->table = TRUE;
- return TRUE;
-}
-
-/* Adjust an address in the .eh_frame section. Given OFFSET within
- SEC, this returns the new offset in the adjusted .eh_frame section,
- or -1 if the address refers to a CIE/FDE which has been removed
- or to offset with dynamic relocation which is no longer needed. */
-
-bfd_vma
-_bfd_elf_eh_frame_section_offset (bfd *output_bfd ATTRIBUTE_UNUSED,
- struct bfd_link_info *info,
- asection *sec,
- bfd_vma offset)
-{
- struct eh_frame_sec_info *sec_info;
- struct elf_link_hash_table *htab;
- struct eh_frame_hdr_info *hdr_info;
- unsigned int lo, hi, mid;
-
- if (sec->sec_info_type != ELF_INFO_TYPE_EH_FRAME)
- return offset;
- sec_info = elf_section_data (sec)->sec_info;
-
- if (offset >= sec->rawsize)
- return offset - sec->rawsize + sec->size;
-
- htab = elf_hash_table (info);
- hdr_info = &htab->eh_info;
- if (hdr_info->offsets_adjusted)
- offset += sec->output_offset;
-
- lo = 0;
- hi = sec_info->count;
- mid = 0;
- while (lo < hi)
- {
- mid = (lo + hi) / 2;
- if (offset < sec_info->entry[mid].offset)
- hi = mid;
- else if (offset
- >= sec_info->entry[mid].offset + sec_info->entry[mid].size)
- lo = mid + 1;
- else
- break;
- }
-
- BFD_ASSERT (lo < hi);
-
- /* FDE or CIE was removed. */
- if (sec_info->entry[mid].removed)
- return (bfd_vma) -1;
-
- /* If converting to DW_EH_PE_pcrel, there will be no need for run-time
- relocation against FDE's initial_location field. */
- if (!sec_info->entry[mid].cie
- && sec_info->entry[mid].cie_inf->make_relative
- && offset == sec_info->entry[mid].offset + 8)
- return (bfd_vma) -2;
-
- /* If converting LSDA pointers to DW_EH_PE_pcrel, there will be no need
- for run-time relocation against LSDA field. */
- if (!sec_info->entry[mid].cie
- && sec_info->entry[mid].cie_inf->make_lsda_relative
- && (offset == (sec_info->entry[mid].offset + 8
- + sec_info->entry[mid].lsda_offset))
- && (sec_info->entry[mid].cie_inf->need_lsda_relative
- || !hdr_info->offsets_adjusted))
- {
- sec_info->entry[mid].cie_inf->need_lsda_relative = 1;
- return (bfd_vma) -2;
- }
-
- if (hdr_info->offsets_adjusted)
- offset -= sec->output_offset;
- /* Any new augmentation bytes go before the first relocation. */
- return (offset + sec_info->entry[mid].new_offset
- - sec_info->entry[mid].offset
- + extra_augmentation_string_bytes (sec_info->entry + mid)
- + extra_augmentation_data_bytes (sec_info->entry + mid));
-}
-
-/* Write out .eh_frame section. This is called with the relocated
- contents. */
-
-bfd_boolean
-_bfd_elf_write_section_eh_frame (bfd *abfd,
- struct bfd_link_info *info,
- asection *sec,
- bfd_byte *contents)
-{
- struct eh_frame_sec_info *sec_info;
- struct elf_link_hash_table *htab;
- struct eh_frame_hdr_info *hdr_info;
- unsigned int ptr_size;
- struct eh_cie_fde *ent;
-
- if (sec->sec_info_type != ELF_INFO_TYPE_EH_FRAME)
- return bfd_set_section_contents (abfd, sec->output_section, contents,
- sec->output_offset, sec->size);
-
- ptr_size = (get_elf_backend_data (abfd)
- ->elf_backend_eh_frame_address_size (abfd, sec));
- BFD_ASSERT (ptr_size != 0);
-
- sec_info = elf_section_data (sec)->sec_info;
- htab = elf_hash_table (info);
- hdr_info = &htab->eh_info;
-
- /* First convert all offsets to output section offsets, so that a
- CIE offset is valid if the CIE is used by a FDE from some other
- section. This can happen when duplicate CIEs are deleted in
- _bfd_elf_discard_section_eh_frame. We do all sections here because
- this function might not be called on sections in the same order as
- _bfd_elf_discard_section_eh_frame. */
- if (!hdr_info->offsets_adjusted)
- {
- bfd *ibfd;
- asection *eh;
- struct eh_frame_sec_info *eh_inf;
-
- for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
- {
- if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour
- || (ibfd->flags & DYNAMIC) != 0)
- continue;
-
- eh = bfd_get_section_by_name (ibfd, ".eh_frame");
- if (eh == NULL || eh->sec_info_type != ELF_INFO_TYPE_EH_FRAME)
- continue;
-
- eh_inf = elf_section_data (eh)->sec_info;
- for (ent = eh_inf->entry; ent < eh_inf->entry + eh_inf->count; ++ent)
- {
- ent->offset += eh->output_offset;
- ent->new_offset += eh->output_offset;
- }
- }
- hdr_info->offsets_adjusted = TRUE;
- }
-
- if (hdr_info->table && hdr_info->array == NULL)
- hdr_info->array
- = bfd_malloc (hdr_info->fde_count * sizeof(*hdr_info->array));
- if (hdr_info->array == NULL)
- hdr_info = NULL;
-
- /* The new offsets can be bigger or smaller than the original offsets.
- We therefore need to make two passes over the section: one backward
- pass to move entries up and one forward pass to move entries down.
- The two passes won't interfere with each other because entries are
- not reordered */
- for (ent = sec_info->entry + sec_info->count; ent-- != sec_info->entry;)
- if (!ent->removed && ent->new_offset > ent->offset)
- memmove (contents + ent->new_offset - sec->output_offset,
- contents + ent->offset - sec->output_offset, ent->size);
-
- for (ent = sec_info->entry; ent < sec_info->entry + sec_info->count; ++ent)
- if (!ent->removed && ent->new_offset < ent->offset)
- memmove (contents + ent->new_offset - sec->output_offset,
- contents + ent->offset - sec->output_offset, ent->size);
-
- for (ent = sec_info->entry; ent < sec_info->entry + sec_info->count; ++ent)
- {
- unsigned char *buf, *end;
- unsigned int new_size;
-
- if (ent->removed)
- continue;
-
- if (ent->size == 4)
- {
- /* Any terminating FDE must be at the end of the section. */
- BFD_ASSERT (ent == sec_info->entry + sec_info->count - 1);
- continue;
- }
-
- buf = contents + ent->new_offset - sec->output_offset;
- end = buf + ent->size;
- new_size = size_of_output_cie_fde (ent, ptr_size);
-
- /* Update the size. It may be shrinked. */
- bfd_put_32 (abfd, new_size - 4, buf);
-
- /* Filling the extra bytes with DW_CFA_nops. */
- if (new_size != ent->size)
- memset (end, 0, new_size - ent->size);
-
- if (ent->cie)
- {
- /* CIE */
- if (ent->make_relative
- || ent->need_lsda_relative
- || ent->per_encoding_relative)
- {
- char *aug;
- unsigned int action, extra_string, extra_data;
- unsigned int per_width, per_encoding;
-
- /* Need to find 'R' or 'L' augmentation's argument and modify
- DW_EH_PE_* value. */
- action = ((ent->make_relative ? 1 : 0)
- | (ent->need_lsda_relative ? 2 : 0)
- | (ent->per_encoding_relative ? 4 : 0));
- extra_string = extra_augmentation_string_bytes (ent);
- extra_data = extra_augmentation_data_bytes (ent);
-
- /* Skip length, id and version. */
- buf += 9;
- aug = (char *) buf;
- buf += strlen (aug) + 1;
- skip_leb128 (&buf, end);
- skip_leb128 (&buf, end);
- skip_leb128 (&buf, end);
- if (*aug == 'z')
- {
- /* The uleb128 will always be a single byte for the kind
- of augmentation strings that we're prepared to handle. */
- *buf++ += extra_data;
- aug++;
- }
-
- /* Make room for the new augmentation string and data bytes. */
- memmove (buf + extra_string + extra_data, buf, end - buf);
- memmove (aug + extra_string, aug, buf - (bfd_byte *) aug);
- buf += extra_string;
- end += extra_string + extra_data;
-
- if (ent->add_augmentation_size)
- {
- *aug++ = 'z';
- *buf++ = extra_data - 1;
- }
- if (ent->add_fde_encoding)
- {
- BFD_ASSERT (action & 1);
- *aug++ = 'R';
- *buf++ = DW_EH_PE_pcrel;
- action &= ~1;
- }
-
- while (action)
- switch (*aug++)
- {
- case 'L':
- if (action & 2)
- {
- BFD_ASSERT (*buf == ent->lsda_encoding);
- *buf |= DW_EH_PE_pcrel;
- action &= ~2;
- }
- buf++;
- break;
- case 'P':
- per_encoding = *buf++;
- per_width = get_DW_EH_PE_width (per_encoding, ptr_size);
- BFD_ASSERT (per_width != 0);
- BFD_ASSERT (((per_encoding & 0x70) == DW_EH_PE_pcrel)
- == ent->per_encoding_relative);
- if ((per_encoding & 0xf0) == DW_EH_PE_aligned)
- buf = (contents
- + ((buf - contents + per_width - 1)
- & ~((bfd_size_type) per_width - 1)));
- if (action & 4)
- {
- bfd_vma val;
-
- val = read_value (abfd, buf, per_width,
- get_DW_EH_PE_signed (per_encoding));
- val += ent->offset - ent->new_offset;
- val -= extra_string + extra_data;
- write_value (abfd, buf, val, per_width);
- action &= ~4;
- }
- buf += per_width;
- break;
- case 'R':
- if (action & 1)
- {
- BFD_ASSERT (*buf == ent->fde_encoding);
- *buf |= DW_EH_PE_pcrel;
- action &= ~1;
- }
- buf++;
- break;
- case 'S':
- break;
- default:
- BFD_FAIL ();
- }
- }
- }
- else
- {
- /* FDE */
- bfd_vma value, address;
- unsigned int width;
-
- /* Skip length. */
- buf += 4;
- value = ent->new_offset + 4 - ent->cie_inf->new_offset;
- bfd_put_32 (abfd, value, buf);
- buf += 4;
- width = get_DW_EH_PE_width (ent->fde_encoding, ptr_size);
- value = read_value (abfd, buf, width,
- get_DW_EH_PE_signed (ent->fde_encoding));
- address = value;
- if (value)
- {
- switch (ent->fde_encoding & 0xf0)
- {
- case DW_EH_PE_indirect:
- case DW_EH_PE_textrel:
- BFD_ASSERT (hdr_info == NULL);
- break;
- case DW_EH_PE_datarel:
- {
- asection *got = bfd_get_section_by_name (abfd, ".got");
-
- BFD_ASSERT (got != NULL);
- address += got->vma;
- }
- break;
- case DW_EH_PE_pcrel:
- value += ent->offset - ent->new_offset;
- address += sec->output_section->vma + ent->offset + 8;
- break;
- }
- if (ent->cie_inf->make_relative)
- value -= sec->output_section->vma + ent->new_offset + 8;
- write_value (abfd, buf, value, width);
- }
-
- if (hdr_info)
- {
- hdr_info->array[hdr_info->array_count].initial_loc = address;
- hdr_info->array[hdr_info->array_count++].fde
- = sec->output_section->vma + ent->new_offset;
- }
-
- if ((ent->lsda_encoding & 0xf0) == DW_EH_PE_pcrel
- || ent->cie_inf->need_lsda_relative)
- {
- buf += ent->lsda_offset;
- width = get_DW_EH_PE_width (ent->lsda_encoding, ptr_size);
- value = read_value (abfd, buf, width,
- get_DW_EH_PE_signed (ent->lsda_encoding));
- if (value)
- {
- if ((ent->lsda_encoding & 0xf0) == DW_EH_PE_pcrel)
- value += ent->offset - ent->new_offset;
- else if (ent->cie_inf->need_lsda_relative)
- value -= (sec->output_section->vma + ent->new_offset + 8
- + ent->lsda_offset);
- write_value (abfd, buf, value, width);
- }
- }
- else if (ent->cie_inf->add_augmentation_size)
- {
- /* Skip the PC and length and insert a zero byte for the
- augmentation size. */
- buf += width * 2;
- memmove (buf + 1, buf, end - buf);
- *buf = 0;
- }
- }
- }
-
- /* We don't align the section to its section alignment since the
- runtime library only expects all CIE/FDE records aligned at
- the pointer size. _bfd_elf_discard_section_eh_frame should
- have padded CIE/FDE records to multiple of pointer size with
- size_of_output_cie_fde. */
- if ((sec->size % ptr_size) != 0)
- abort ();
-
- return bfd_set_section_contents (abfd, sec->output_section,
- contents, (file_ptr) sec->output_offset,
- sec->size);
-}
-
-/* Helper function used to sort .eh_frame_hdr search table by increasing
- VMA of FDE initial location. */
-
-static int
-vma_compare (const void *a, const void *b)
-{
- const struct eh_frame_array_ent *p = a;
- const struct eh_frame_array_ent *q = b;
- if (p->initial_loc > q->initial_loc)
- return 1;
- if (p->initial_loc < q->initial_loc)
- return -1;
- return 0;
-}
-
-/* Write out .eh_frame_hdr section. This must be called after
- _bfd_elf_write_section_eh_frame has been called on all input
- .eh_frame sections.
- .eh_frame_hdr format:
- ubyte version (currently 1)
- ubyte eh_frame_ptr_enc (DW_EH_PE_* encoding of pointer to start of
- .eh_frame section)
- ubyte fde_count_enc (DW_EH_PE_* encoding of total FDE count
- number (or DW_EH_PE_omit if there is no
- binary search table computed))
- ubyte table_enc (DW_EH_PE_* encoding of binary search table,
- or DW_EH_PE_omit if not present.
- DW_EH_PE_datarel is using address of
- .eh_frame_hdr section start as base)
- [encoded] eh_frame_ptr (pointer to start of .eh_frame section)
- optionally followed by:
- [encoded] fde_count (total number of FDEs in .eh_frame section)
- fde_count x [encoded] initial_loc, fde
- (array of encoded pairs containing
- FDE initial_location field and FDE address,
- sorted by increasing initial_loc). */
-
-bfd_boolean
-_bfd_elf_write_section_eh_frame_hdr (bfd *abfd, struct bfd_link_info *info)
-{
- struct elf_link_hash_table *htab;
- struct eh_frame_hdr_info *hdr_info;
- asection *sec;
- bfd_byte *contents;
- asection *eh_frame_sec;
- bfd_size_type size;
- bfd_boolean retval;
- bfd_vma encoded_eh_frame;
-
- htab = elf_hash_table (info);
- hdr_info = &htab->eh_info;
- sec = hdr_info->hdr_sec;
- if (sec == NULL)
- return TRUE;
-
- size = EH_FRAME_HDR_SIZE;
- if (hdr_info->array && hdr_info->array_count == hdr_info->fde_count)
- size += 4 + hdr_info->fde_count * 8;
- contents = bfd_malloc (size);
- if (contents == NULL)
- return FALSE;
-
- eh_frame_sec = bfd_get_section_by_name (abfd, ".eh_frame");
- if (eh_frame_sec == NULL)
- {
- free (contents);
- return FALSE;
- }
-
- memset (contents, 0, EH_FRAME_HDR_SIZE);
- contents[0] = 1; /* Version. */
- contents[1] = get_elf_backend_data (abfd)->elf_backend_encode_eh_address
- (abfd, info, eh_frame_sec, 0, sec, 4,
- &encoded_eh_frame); /* .eh_frame offset. */
-
- if (hdr_info->array && hdr_info->array_count == hdr_info->fde_count)
- {
- contents[2] = DW_EH_PE_udata4; /* FDE count encoding. */
- contents[3] = DW_EH_PE_datarel | DW_EH_PE_sdata4; /* Search table enc. */
- }
- else
- {
- contents[2] = DW_EH_PE_omit;
- contents[3] = DW_EH_PE_omit;
- }
- bfd_put_32 (abfd, encoded_eh_frame, contents + 4);
-
- if (contents[2] != DW_EH_PE_omit)
- {
- unsigned int i;
-
- bfd_put_32 (abfd, hdr_info->fde_count, contents + EH_FRAME_HDR_SIZE);
- qsort (hdr_info->array, hdr_info->fde_count, sizeof (*hdr_info->array),
- vma_compare);
- for (i = 0; i < hdr_info->fde_count; i++)
- {
- bfd_put_32 (abfd,
- hdr_info->array[i].initial_loc
- - sec->output_section->vma,
- contents + EH_FRAME_HDR_SIZE + i * 8 + 4);
- bfd_put_32 (abfd,
- hdr_info->array[i].fde - sec->output_section->vma,
- contents + EH_FRAME_HDR_SIZE + i * 8 + 8);
- }
- }
-
- retval = bfd_set_section_contents (abfd, sec->output_section,
- contents, (file_ptr) sec->output_offset,
- sec->size);
- free (contents);
- return retval;
-}
-
-/* Return the width of FDE addresses. This is the default implementation. */
-
-unsigned int
-_bfd_elf_eh_frame_address_size (bfd *abfd, asection *sec ATTRIBUTE_UNUSED)
-{
- return elf_elfheader (abfd)->e_ident[EI_CLASS] == ELFCLASS64 ? 8 : 4;
-}
-
-/* Decide whether we can use a PC-relative encoding within the given
- EH frame section. This is the default implementation. */
-
-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)
-{
- return TRUE;
-}
-
-/* Select an encoding for the given address. Preference is given to
- PC-relative addressing modes. */
-
-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)
-{
- *encoded = osec->vma + offset -
- (loc_sec->output_section->vma + loc_sec->output_offset + loc_offset);
- return DW_EH_PE_pcrel | DW_EH_PE_sdata4;
-}