diff options
author | obrien <obrien@FreeBSD.org> | 2009-01-19 17:25:17 +0000 |
---|---|---|
committer | obrien <obrien@FreeBSD.org> | 2009-01-19 17:25:17 +0000 |
commit | 2b02dfaa48ad11ff3ee427ee1db57fb6017a8a5e (patch) | |
tree | af590d7b357b1c28ab81f0cde1b0ea76a098fb7e /contrib/binutils/bfd/elf-eh-frame.c | |
parent | cd5f96a9efbe194cb6e0506e727cb6d287247d69 (diff) | |
download | FreeBSD-src-2b02dfaa48ad11ff3ee427ee1db57fb6017a8a5e.zip FreeBSD-src-2b02dfaa48ad11ff3ee427ee1db57fb6017a8a5e.tar.gz |
Rename vendor/binutils/*/contrib to vendor/binutils/*/x
Binutils has a "contrib" subdirectory - thus flattening cannot happen
without renaming the upper level contrib directory in a first pass.
Also, don't record this move and remove any keyword expansion.
Diffstat (limited to 'contrib/binutils/bfd/elf-eh-frame.c')
-rw-r--r-- | contrib/binutils/bfd/elf-eh-frame.c | 1219 |
1 files changed, 0 insertions, 1219 deletions
diff --git a/contrib/binutils/bfd/elf-eh-frame.c b/contrib/binutils/bfd/elf-eh-frame.c deleted file mode 100644 index d3777b4..0000000 --- a/contrib/binutils/bfd/elf-eh-frame.c +++ /dev/null @@ -1,1219 +0,0 @@ -/* .eh_frame section optimization. - Copyright 2001, 2002, 2003 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - -#include "bfd.h" -#include "sysdep.h" -#include "libbfd.h" -#include "elf-bfd.h" -#include "elf/dwarf2.h" - -#define EH_FRAME_HDR_SIZE 8 - -/* Helper function for reading uleb128 encoded data. */ - -static bfd_vma -read_unsigned_leb128 (bfd *abfd ATTRIBUTE_UNUSED, - char *buf, - unsigned int *bytes_read_ptr) -{ - bfd_vma result; - unsigned int num_read; - int shift; - unsigned char byte; - - result = 0; - shift = 0; - num_read = 0; - do - { - byte = bfd_get_8 (abfd, (bfd_byte *) buf); - buf++; - num_read++; - result |= (((bfd_vma) byte & 0x7f) << shift); - shift += 7; - } - while (byte & 0x80); - *bytes_read_ptr = num_read; - return result; -} - -/* Helper function for reading sleb128 encoded data. */ - -static bfd_signed_vma -read_signed_leb128 (bfd *abfd ATTRIBUTE_UNUSED, - char *buf, - unsigned int * bytes_read_ptr) -{ - bfd_vma result; - int shift; - int num_read; - unsigned char byte; - - result = 0; - shift = 0; - num_read = 0; - do - { - byte = bfd_get_8 (abfd, (bfd_byte *) buf); - buf ++; - num_read ++; - result |= (((bfd_vma) byte & 0x7f) << shift); - shift += 7; - } - while (byte & 0x80); - if (byte & 0x40) - result |= (((bfd_vma) -1) << (shift - 7)) << 7; - *bytes_read_ptr = num_read; - return result; -} - -#define read_uleb128(VAR, BUF) \ -do \ - { \ - (VAR) = read_unsigned_leb128 (abfd, buf, &leb128_tmp); \ - (BUF) += leb128_tmp; \ - } \ -while (0) - -#define read_sleb128(VAR, BUF) \ -do \ - { \ - (VAR) = read_signed_leb128 (abfd, buf, &leb128_tmp); \ - (BUF) += leb128_tmp; \ - } \ -while (0) - -/* 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; -} - -/* 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) -{ - bfd_byte *ehbuf = NULL, *buf; - bfd_byte *last_cie, *last_fde; - 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 leb128_tmp; - unsigned int cie_usage_count, last_cie_ndx, i, offset; - unsigned int make_relative, make_lsda_relative; - bfd_size_type new_size; - unsigned int ptr_size; - - if (sec->_raw_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. */ - - ehbuf = bfd_malloc (sec->_raw_size); - if (ehbuf == NULL) - goto free_no_table; - - if (! bfd_get_section_contents (abfd, sec, ehbuf, 0, sec->_raw_size)) - goto free_no_table; - - if (sec->_raw_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). */ - if (sec->_raw_size != (unsigned int) sec->_raw_size) - goto free_no_table; - - ptr_size = (elf_elfheader (abfd)->e_ident[EI_CLASS] - == ELFCLASS64) ? 8 : 4; - buf = ehbuf; - last_cie = NULL; - last_cie_ndx = 0; - memset (&cie, 0, sizeof (cie)); - cie_usage_count = 0; - new_size = sec->_raw_size; - make_relative = hdr_info->last_cie.make_relative; - make_lsda_relative = hdr_info->last_cie.make_lsda_relative; - sec_info = bfd_zmalloc (sizeof (struct eh_frame_sec_info) - + 99 * sizeof (struct eh_cie_fde)); - if (sec_info == NULL) - goto free_no_table; - sec_info->alloced = 100; - -#define ENSURE_NO_RELOCS(buf) \ - if (cookie->rel < cookie->relend \ - && (cookie->rel->r_offset \ - < (bfd_size_type) ((buf) - ehbuf)) \ - && cookie->rel->r_info != 0) \ - goto free_no_table - -#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 (;;) - { - unsigned char *aug; - - if (sec_info->count == sec_info->alloced) - { - sec_info = bfd_realloc (sec_info, - sizeof (struct eh_frame_sec_info) - + (sec_info->alloced + 99) - * sizeof (struct eh_cie_fde)); - if (sec_info == NULL) - goto free_no_table; - - memset (&sec_info->entry[sec_info->alloced], 0, - 100 * sizeof (struct eh_cie_fde)); - sec_info->alloced += 100; - } - - 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->_raw_size) - hdr.id = (unsigned int) -1; - else - { - if ((bfd_size_type) (buf + 4 - ehbuf) > sec->_raw_size) - /* No space for CIE/FDE header length. */ - goto free_no_table; - - hdr.length = bfd_get_32 (abfd, buf); - if (hdr.length == 0xffffffff) - /* 64-bit .eh_frame is not supported. */ - goto free_no_table; - buf += 4; - if ((bfd_size_type) (buf - ehbuf) + hdr.length > sec->_raw_size) - /* CIE/FDE not contained fully in this .eh_frame input section. */ - goto free_no_table; - - sec_info->entry[sec_info->count].offset = last_fde - ehbuf; - sec_info->entry[sec_info->count].size = 4 + hdr.length; - - if (hdr.length == 0) - { - /* CIE with length 0 must be only the last in the section. */ - if ((bfd_size_type) (buf - ehbuf) < sec->_raw_size) - goto free_no_table; - ENSURE_NO_RELOCS (buf); - sec_info->count++; - /* Now just finish last encountered CIE processing and break - the loop. */ - hdr.id = (unsigned int) -1; - } - else - { - hdr.id = bfd_get_32 (abfd, buf); - buf += 4; - if (hdr.id == (unsigned int) -1) - goto free_no_table; - } - } - - 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) - { - new_size -= cie.hdr.length + 4; - sec_info->entry[last_cie_ndx].removed = 1; - sec_info->entry[last_cie_ndx].sec = hdr_info->last_cie_sec; - sec_info->entry[last_cie_ndx].new_offset - = hdr_info->last_cie_offset; - } - else - { - hdr_info->last_cie = cie; - hdr_info->last_cie_sec = sec; - hdr_info->last_cie_offset = last_cie - ehbuf; - sec_info->entry[last_cie_ndx].make_relative - = cie.make_relative; - sec_info->entry[last_cie_ndx].make_lsda_relative - = cie.make_lsda_relative; - sec_info->entry[last_cie_ndx].per_encoding_relative - = (cie.per_encoding & 0x70) == DW_EH_PE_pcrel; - } - } - - if (hdr.id == (unsigned int) -1) - break; - - last_cie_ndx = sec_info->count; - sec_info->entry[sec_info->count].cie = 1; - - cie_usage_count = 0; - memset (&cie, 0, sizeof (cie)); - cie.hdr = hdr; - cie.version = *buf++; - - /* Cannot handle unknown versions. */ - if (cie.version != 1) - goto free_no_table; - if (strlen (buf) > sizeof (cie.augmentation) - 1) - goto free_no_table; - - strcpy (cie.augmentation, buf); - buf = strchr (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. */ - buf += ptr_size; - SKIP_RELOCS (buf); - } - read_uleb128 (cie.code_align, buf); - read_sleb128 (cie.data_align, buf); - /* Note - in DWARF2 the return address column is an unsigned byte. - In DWARF3 it is a ULEB128. We are following DWARF3. For most - ports this will not matter as the value will be less than 128. - For the others (eg FRV, SH, MMIX, IA64) they need a fixed GCC - which conforms to the DWARF3 standard. */ - read_uleb128 (cie.ra_column, buf); - 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++; - read_uleb128 (cie.augmentation_size, buf); - ENSURE_NO_RELOCS (buf); - } - - while (*aug != '\0') - switch (*aug++) - { - case 'L': - cie.lsda_encoding = *buf++; - ENSURE_NO_RELOCS (buf); - if (get_DW_EH_PE_width (cie.lsda_encoding, ptr_size) == 0) - goto free_no_table; - break; - case 'R': - cie.fde_encoding = *buf++; - ENSURE_NO_RELOCS (buf); - if (get_DW_EH_PE_width (cie.fde_encoding, ptr_size) == 0) - goto free_no_table; - break; - case 'P': - { - int per_width; - - cie.per_encoding = *buf++; - per_width = get_DW_EH_PE_width (cie.per_encoding, - ptr_size); - if (per_width == 0) - goto free_no_table; - if ((cie.per_encoding & 0xf0) == DW_EH_PE_aligned) - buf = (ehbuf - + ((buf - ehbuf + per_width - 1) - & ~((bfd_size_type) per_width - 1))); - 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; - } - cookie->rel++; - } - buf += 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)) - && (cie.fde_encoding & 0xf0) == DW_EH_PE_absptr) - 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 = cie.hdr.length - (buf - last_fde - 4); - if (initial_insn_length <= 50) - { - cie.initial_insn_length = initial_insn_length; - memcpy (cie.initial_instructions, buf, initial_insn_length); - } - buf += initial_insn_length; - ENSURE_NO_RELOCS (buf); - last_cie = last_fde; - } - else - { - /* Ensure this FDE uses the last CIE encountered. */ - if (last_cie == NULL - || hdr.id != (unsigned int) (buf - 4 - last_cie)) - goto free_no_table; - - ENSURE_NO_RELOCS (buf); - if (GET_RELOC (buf) == NULL) - /* This should not happen. */ - goto free_no_table; - if ((*reloc_symbol_deleted_p) (buf - ehbuf, cookie)) - { - /* This is a FDE against a discarded section. It should - be deleted. */ - new_size -= hdr.length + 4; - sec_info->entry[sec_info->count].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++; - } - if (cie.lsda_encoding != DW_EH_PE_omit) - { - unsigned int dummy; - - aug = buf; - buf += 2 * get_DW_EH_PE_width (cie.fde_encoding, ptr_size); - if (cie.augmentation[0] == 'z') - read_uleb128 (dummy, buf); - /* If some new augmentation data is added before LSDA - in FDE augmentation area, this need to be adjusted. */ - sec_info->entry[sec_info->count].lsda_offset = (buf - aug); - } - buf = last_fde + 4 + hdr.length; - SKIP_RELOCS (buf); - } - - sec_info->entry[sec_info->count].fde_encoding = cie.fde_encoding; - sec_info->entry[sec_info->count].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_ndx = 0; - for (i = 0; i < sec_info->count; i++) - { - if (! sec_info->entry[i].removed) - { - sec_info->entry[i].new_offset = offset; - offset += sec_info->entry[i].size; - if (sec_info->entry[i].cie) - { - last_cie_ndx = i; - make_relative = sec_info->entry[i].make_relative; - make_lsda_relative = sec_info->entry[i].make_lsda_relative; - } - else - { - sec_info->entry[i].make_relative = make_relative; - sec_info->entry[i].make_lsda_relative = make_lsda_relative; - sec_info->entry[i].per_encoding_relative = 0; - } - } - else if (sec_info->entry[i].cie && sec_info->entry[i].sec == sec) - { - /* Need to adjust new_offset too. */ - BFD_ASSERT (sec_info->entry[last_cie_ndx].offset - == sec_info->entry[i].new_offset); - sec_info->entry[i].new_offset - = sec_info->entry[last_cie_ndx].new_offset; - } - } - if (hdr_info->last_cie_sec == sec) - { - BFD_ASSERT (sec_info->entry[last_cie_ndx].offset - == hdr_info->last_cie_offset); - hdr_info->last_cie_offset = sec_info->entry[last_cie_ndx].new_offset; - } - - /* FIXME: Currently it is not possible to shrink sections to zero size at - this point, so build a fake minimal CIE. */ - if (new_size == 0) - new_size = 16; - - /* Shrink the sec as needed. */ - sec->_cooked_size = new_size; - if (sec->_cooked_size == 0) - sec->flags |= SEC_EXCLUDE; - - free (ehbuf); - return new_size != sec->_raw_size; - -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; -} - -/* 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->_cooked_size = EH_FRAME_HDR_SIZE; - if (hdr_info->table) - sec->_cooked_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 later on it is too late for calling _bfd_strip_section_from_output, - since dynamic symbol table has been sized. */ - -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->_raw_size > 8 && !bfd_is_abs_section (o->output_section)) - break; - } - - if (abfd == NULL) - { - _bfd_strip_section_from_output (info, hdr_info->hdr_sec); - 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, - asection *sec, - bfd_vma offset) -{ - struct eh_frame_sec_info *sec_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->_raw_size) - return offset - (sec->_cooked_size - sec->_raw_size); - - 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].make_relative - && ! sec_info->entry[mid].cie - && 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].make_lsda_relative - && ! sec_info->entry[mid].cie - && (offset == (sec_info->entry[mid].offset + 8 - + sec_info->entry[mid].lsda_offset))) - return (bfd_vma) -2; - - return (offset + sec_info->entry[mid].new_offset - - sec_info->entry[mid].offset); -} - -/* 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 i; - bfd_byte *p, *buf; - unsigned int leb128_tmp; - unsigned int cie_offset = 0; - unsigned int ptr_size; - - ptr_size = (elf_elfheader (sec->owner)->e_ident[EI_CLASS] - == ELFCLASS64) ? 8 : 4; - - if (sec->sec_info_type != ELF_INFO_TYPE_EH_FRAME) - return bfd_set_section_contents (abfd, sec->output_section, contents, - sec->output_offset, sec->_raw_size); - sec_info = elf_section_data (sec)->sec_info; - htab = elf_hash_table (info); - hdr_info = &htab->eh_info; - 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; - - p = contents; - for (i = 0; i < sec_info->count; ++i) - { - if (sec_info->entry[i].removed) - { - if (sec_info->entry[i].cie) - { - /* If CIE is removed due to no remaining FDEs referencing it - and there were no CIEs kept before it, sec_info->entry[i].sec - will be zero. */ - if (sec_info->entry[i].sec == NULL) - cie_offset = 0; - else - { - cie_offset = sec_info->entry[i].new_offset; - cie_offset += (sec_info->entry[i].sec->output_section->vma - + sec_info->entry[i].sec->output_offset - - sec->output_section->vma - - sec->output_offset); - } - } - continue; - } - - if (sec_info->entry[i].cie) - { - /* CIE */ - cie_offset = sec_info->entry[i].new_offset; - if (sec_info->entry[i].make_relative - || sec_info->entry[i].make_lsda_relative - || sec_info->entry[i].per_encoding_relative) - { - unsigned char *aug; - unsigned int action; - unsigned int dummy, per_width, per_encoding; - - /* Need to find 'R' or 'L' augmentation's argument and modify - DW_EH_PE_* value. */ - action = (sec_info->entry[i].make_relative ? 1 : 0) - | (sec_info->entry[i].make_lsda_relative ? 2 : 0) - | (sec_info->entry[i].per_encoding_relative ? 4 : 0); - buf = contents + sec_info->entry[i].offset; - /* Skip length, id and version. */ - buf += 9; - aug = buf; - buf = strchr (buf, '\0') + 1; - read_uleb128 (dummy, buf); - read_sleb128 (dummy, buf); - read_uleb128 (dummy, buf); - if (*aug == 'z') - { - read_uleb128 (dummy, buf); - aug++; - } - - while (action) - switch (*aug++) - { - case 'L': - if (action & 2) - { - BFD_ASSERT (*buf == sec_info->entry[i].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) - == sec_info->entry[i].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 value; - - value = read_value (abfd, buf, per_width, - get_DW_EH_PE_signed - (per_encoding)); - value += (sec_info->entry[i].offset - - sec_info->entry[i].new_offset); - write_value (abfd, buf, value, per_width); - action &= ~4; - } - buf += per_width; - break; - case 'R': - if (action & 1) - { - BFD_ASSERT (*buf == sec_info->entry[i].fde_encoding); - *buf |= DW_EH_PE_pcrel; - action &= ~1; - } - buf++; - break; - default: - BFD_FAIL (); - } - } - } - else if (sec_info->entry[i].size > 4) - { - /* FDE */ - bfd_vma value = 0, address; - unsigned int width; - - buf = contents + sec_info->entry[i].offset; - /* Skip length. */ - buf += 4; - bfd_put_32 (abfd, - sec_info->entry[i].new_offset + 4 - cie_offset, buf); - buf += 4; - width = get_DW_EH_PE_width (sec_info->entry[i].fde_encoding, - ptr_size); - address = value = read_value (abfd, buf, width, - get_DW_EH_PE_signed - (sec_info->entry[i].fde_encoding)); - if (value) - { - switch (sec_info->entry[i].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 += (sec_info->entry[i].offset - - sec_info->entry[i].new_offset); - address += (sec->output_section->vma + sec->output_offset - + sec_info->entry[i].offset + 8); - break; - } - if (sec_info->entry[i].make_relative) - value -= (sec->output_section->vma + sec->output_offset - + sec_info->entry[i].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 + sec->output_offset - + sec_info->entry[i].new_offset); - } - - if ((sec_info->entry[i].lsda_encoding & 0xf0) == DW_EH_PE_pcrel - || sec_info->entry[i].make_lsda_relative) - { - buf += sec_info->entry[i].lsda_offset; - width = get_DW_EH_PE_width (sec_info->entry[i].lsda_encoding, - ptr_size); - value = read_value (abfd, buf, width, - get_DW_EH_PE_signed - (sec_info->entry[i].lsda_encoding)); - if (value) - { - if ((sec_info->entry[i].lsda_encoding & 0xf0) - == DW_EH_PE_pcrel) - value += (sec_info->entry[i].offset - - sec_info->entry[i].new_offset); - else if (sec_info->entry[i].make_lsda_relative) - value -= (sec->output_section->vma + sec->output_offset - + sec_info->entry[i].new_offset + 8 - + sec_info->entry[i].lsda_offset); - write_value (abfd, buf, value, width); - } - } - } - else - /* Terminating FDE must be at the end of .eh_frame section only. */ - BFD_ASSERT (i == sec_info->count - 1); - - BFD_ASSERT (p == contents + sec_info->entry[i].new_offset); - memmove (p, contents + sec_info->entry[i].offset, - sec_info->entry[i].size); - p += sec_info->entry[i].size; - } - - /* FIXME: Once _bfd_elf_discard_section_eh_frame will be able to - shrink sections to zero size, this won't be needed any more. */ - if (p == contents && sec->_cooked_size == 16) - { - bfd_put_32 (abfd, 12, p); /* Fake CIE length */ - bfd_put_32 (abfd, 0, p + 4); /* Fake CIE id */ - p[8] = 1; /* Fake CIE version */ - memset (p + 9, 0, 7); /* Fake CIE augmentation, 3xleb128 - and 3xDW_CFA_nop as pad */ - p += 16; - } - else - { - unsigned int alignment = 1 << sec->alignment_power; - unsigned int pad = sec->_cooked_size % alignment; - - /* Don't pad beyond the raw size of the output section. It - can happen at the last input section. */ - if (pad - && ((sec->output_offset + sec->_cooked_size + pad) - <= sec->output_section->_raw_size)) - { - /* Find the last CIE/FDE. */ - for (i = sec_info->count - 1; i > 0; i--) - if (! sec_info->entry[i].removed) - break; - - /* The size of the last CIE/FDE must be at least 4. */ - if (sec_info->entry[i].removed - || sec_info->entry[i].size < 4) - abort (); - - pad = alignment - pad; - - buf = contents + sec_info->entry[i].new_offset; - - /* Update length. */ - sec_info->entry[i].size += pad; - bfd_put_32 (abfd, sec_info->entry[i].size - 4, buf); - - /* Pad it with DW_CFA_nop */ - memset (p, 0, pad); - p += pad; - - sec->_cooked_size += pad; - } - } - - BFD_ASSERT ((bfd_size_type) (p - contents) == sec->_cooked_size); - - return bfd_set_section_contents (abfd, sec->output_section, - contents, (file_ptr) sec->output_offset, - sec->_cooked_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->_cooked_size); - free (contents); - return retval; -} - -/* 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; -} |