summaryrefslogtreecommitdiffstats
path: root/contrib/binutils/bfd/elf-eh-frame.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/binutils/bfd/elf-eh-frame.c')
-rw-r--r--contrib/binutils/bfd/elf-eh-frame.c549
1 files changed, 264 insertions, 285 deletions
diff --git a/contrib/binutils/bfd/elf-eh-frame.c b/contrib/binutils/bfd/elf-eh-frame.c
index 62226c5..d3777b4 100644
--- a/contrib/binutils/bfd/elf-eh-frame.c
+++ b/contrib/binutils/bfd/elf-eh-frame.c
@@ -1,22 +1,22 @@
/* .eh_frame section optimization.
- Copyright 2001, 2002 Free Software Foundation, Inc.
+ 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 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 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.
+ 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. */
+ 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"
@@ -26,129 +26,44 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#define EH_FRAME_HDR_SIZE 8
-struct cie_header
-{
- unsigned int length;
- unsigned int id;
-};
-
-struct cie
-{
- struct cie_header hdr;
- unsigned char version;
- unsigned char augmentation[20];
- unsigned int code_align;
- int data_align;
- unsigned int ra_column;
- unsigned int augmentation_size;
- struct elf_link_hash_entry *personality;
- unsigned char per_encoding;
- unsigned char lsda_encoding;
- unsigned char fde_encoding;
- unsigned char initial_insn_length;
- unsigned char make_relative;
- unsigned char make_lsda_relative;
- unsigned char initial_instructions[50];
-};
-
-struct eh_cie_fde
-{
- unsigned int offset;
- unsigned int size;
- asection *sec;
- unsigned int new_offset;
- unsigned char fde_encoding;
- unsigned char lsda_encoding;
- unsigned char lsda_offset;
- unsigned char cie : 1;
- unsigned char removed : 1;
- unsigned char make_relative : 1;
- unsigned char make_lsda_relative : 1;
- unsigned char per_encoding_relative : 1;
-};
-
-struct eh_frame_sec_info
-{
- unsigned int count;
- unsigned int alloced;
- struct eh_cie_fde entry[1];
-};
-
-struct eh_frame_array_ent
-{
- bfd_vma initial_loc;
- bfd_vma fde;
-};
-
-struct eh_frame_hdr_info
-{
- struct cie last_cie;
- asection *last_cie_sec;
- unsigned int last_cie_offset;
- unsigned int fde_count, array_count;
- struct eh_frame_array_ent *array;
- /* TRUE if .eh_frame_hdr should contain the sorted search table.
- We build it if we successfully read all .eh_frame input sections
- and recognize them. */
- boolean table;
- boolean strip;
-};
-
-static bfd_vma read_unsigned_leb128
- PARAMS ((bfd *, char *, unsigned int *));
-static bfd_signed_vma read_signed_leb128
- PARAMS ((bfd *, char *, unsigned int *));
-static int get_DW_EH_PE_width
- PARAMS ((int, int));
-static bfd_vma read_value
- PARAMS ((bfd *, bfd_byte *, int));
-static void write_value
- PARAMS ((bfd *, bfd_byte *, bfd_vma, int));
-static int cie_compare
- PARAMS ((struct cie *, struct cie *));
-static int vma_compare
- PARAMS ((const PTR a, const PTR b));
-
/* Helper function for reading uleb128 encoded data. */
static bfd_vma
-read_unsigned_leb128 (abfd, buf, bytes_read_ptr)
- bfd *abfd ATTRIBUTE_UNUSED;
- char *buf;
- unsigned int *bytes_read_ptr;
+read_unsigned_leb128 (bfd *abfd ATTRIBUTE_UNUSED,
+ char *buf,
+ unsigned int *bytes_read_ptr)
{
- bfd_vma result;
- unsigned int num_read;
- int shift;
+ bfd_vma result;
+ unsigned int num_read;
+ int shift;
unsigned char byte;
- result = 0;
- shift = 0;
+ result = 0;
+ shift = 0;
num_read = 0;
do
{
byte = bfd_get_8 (abfd, (bfd_byte *) buf);
- buf ++;
- num_read ++;
+ buf++;
+ num_read++;
result |= (((bfd_vma) byte & 0x7f) << shift);
shift += 7;
}
while (byte & 0x80);
- * bytes_read_ptr = num_read;
+ *bytes_read_ptr = num_read;
return result;
}
/* Helper function for reading sleb128 encoded data. */
static bfd_signed_vma
-read_signed_leb128 (abfd, buf, bytes_read_ptr)
- bfd *abfd ATTRIBUTE_UNUSED;
- char *buf;
- unsigned int * bytes_read_ptr;
+read_signed_leb128 (bfd *abfd ATTRIBUTE_UNUSED,
+ char *buf,
+ unsigned int * bytes_read_ptr)
{
- bfd_vma result;
- int shift;
- int num_read;
+ bfd_vma result;
+ int shift;
+ int num_read;
unsigned char byte;
result = 0;
@@ -165,7 +80,7 @@ read_signed_leb128 (abfd, buf, bytes_read_ptr)
while (byte & 0x80);
if (byte & 0x40)
result |= (((bfd_vma) -1) << (shift - 7)) << 7;
- * bytes_read_ptr = num_read;
+ *bytes_read_ptr = num_read;
return result;
}
@@ -188,8 +103,7 @@ while (0)
/* Return 0 if either encoding is variable width, or not yet known to bfd. */
static
-int get_DW_EH_PE_width (encoding, ptr_size)
- int encoding, ptr_size;
+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. */
@@ -209,35 +123,47 @@ int get_DW_EH_PE_width (encoding, ptr_size)
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 (abfd, buf, width)
- bfd *abfd;
- bfd_byte *buf;
- int width;
+read_value (bfd *abfd, bfd_byte *buf, int width, int is_signed)
{
bfd_vma value;
switch (width)
{
- case 2: value = bfd_get_16 (abfd, buf); break;
- case 4: value = bfd_get_32 (abfd, buf); break;
- case 8: value = bfd_get_64 (abfd, buf); break;
- default: BFD_FAIL (); return 0;
+ 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 (abfd, buf, value, width)
- bfd *abfd;
- bfd_byte *buf;
- bfd_vma value;
- int width;
+write_value (bfd *abfd, bfd_byte *buf, bfd_vma value, int width)
{
switch (width)
{
@@ -251,8 +177,7 @@ write_value (abfd, buf, value, width)
/* Return zero if C1 and C2 CIEs can be merged. */
static
-int cie_compare (c1, c2)
- struct cie *c1, *c2;
+int cie_compare (struct cie *c1, struct cie *c2)
{
if (c1->hdr.length == c2->hdr.length
&& c1->version == c2->version
@@ -266,8 +191,7 @@ int cie_compare (c1, c2)
&& 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)
+ && c1->initial_insn_length == c2->initial_insn_length
&& memcmp (c1->initial_instructions,
c2->initial_instructions,
c1->initial_insn_length) == 0)
@@ -278,35 +202,32 @@ int cie_compare (c1, c2)
/* 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
+ functions. The function returns TRUE iff any entries have been
deleted. */
-boolean
-_bfd_elf_discard_section_eh_frame (abfd, info, sec, ehdrsec,
- reloc_symbol_deleted_p, cookie)
- bfd *abfd;
- struct bfd_link_info *info;
- asection *sec, *ehdrsec;
- boolean (*reloc_symbol_deleted_p) (bfd_vma, PTR);
- struct elf_reloc_cookie *cookie;
+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;
- Elf_Internal_Rela *rel;
bfd_size_type new_size;
unsigned int ptr_size;
if (sec->_raw_size == 0)
{
/* This file does not contain .eh_frame information. */
- return false;
+ return FALSE;
}
if ((sec->output_section != NULL
@@ -314,22 +235,19 @@ _bfd_elf_discard_section_eh_frame (abfd, info, sec, ehdrsec,
{
/* At least one of the sections is being discarded from the
link, so we should just ignore them. */
- return false;
+ return FALSE;
}
- BFD_ASSERT (elf_section_data (ehdrsec)->sec_info_type
- == ELF_INFO_TYPE_EH_FRAME_HDR);
- hdr_info = (struct eh_frame_hdr_info *)
- elf_section_data (ehdrsec)->sec_info;
+ htab = elf_hash_table (info);
+ hdr_info = &htab->eh_info;
/* Read the frame unwind information from abfd. */
- ehbuf = (bfd_byte *) bfd_malloc (sec->_raw_size);
+ ehbuf = bfd_malloc (sec->_raw_size);
if (ehbuf == NULL)
goto free_no_table;
- if (! bfd_get_section_contents (abfd, sec, ehbuf, (bfd_vma) 0,
- sec->_raw_size))
+ if (! bfd_get_section_contents (abfd, sec, ehbuf, 0, sec->_raw_size))
goto free_no_table;
if (sec->_raw_size >= 4
@@ -338,7 +256,7 @@ _bfd_elf_discard_section_eh_frame (abfd, info, sec, ehdrsec,
{
/* Empty .eh_frame section. */
free (ehbuf);
- return false;
+ return FALSE;
}
/* If .eh_frame section size doesn't fit into int, we cannot handle
@@ -365,7 +283,8 @@ _bfd_elf_discard_section_eh_frame (abfd, info, sec, ehdrsec,
#define ENSURE_NO_RELOCS(buf) \
if (cookie->rel < cookie->relend \
&& (cookie->rel->r_offset \
- < (bfd_size_type) ((buf) - ehbuf))) \
+ < (bfd_size_type) ((buf) - ehbuf)) \
+ && cookie->rel->r_info != 0) \
goto free_no_table
#define SKIP_RELOCS(buf) \
@@ -448,11 +367,15 @@ _bfd_elf_discard_section_eh_frame (abfd, info, sec, ehdrsec,
/* CIE */
if (last_cie != NULL)
{
- /* Now check if this CIE is identical to 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
- that. */
- if (cie_compare (&cie, &hdr_info->last_cie) == 0
+ /* 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;
@@ -506,6 +429,11 @@ _bfd_elf_discard_section_eh_frame (abfd, info, sec, ehdrsec,
}
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;
@@ -550,10 +478,9 @@ _bfd_elf_discard_section_eh_frame (abfd, info, sec, ehdrsec,
+ ((buf - ehbuf + per_width - 1)
& ~((bfd_size_type) per_width - 1)));
ENSURE_NO_RELOCS (buf);
- rel = GET_RELOC (buf);
/* Ensure we have a reloc here, against
a global symbol. */
- if (rel != NULL)
+ if (GET_RELOC (buf) != NULL)
{
unsigned long r_symndx;
@@ -591,10 +518,16 @@ _bfd_elf_discard_section_eh_frame (abfd, info, sec, ehdrsec,
/* 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;
@@ -621,17 +554,15 @@ _bfd_elf_discard_section_eh_frame (abfd, info, sec, ehdrsec,
goto free_no_table;
ENSURE_NO_RELOCS (buf);
- rel = GET_RELOC (buf);
- if (rel == NULL)
+ 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 discarded section, it should
+ /* 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;
- memset (rel, 0, sizeof (*rel));
}
else
{
@@ -640,16 +571,15 @@ _bfd_elf_discard_section_eh_frame (abfd, info, sec, ehdrsec,
&& cie.make_relative == 0)
|| (cie.fde_encoding & 0xf0) == DW_EH_PE_aligned))
{
- /* If shared library uses absolute pointers
+ /* 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;
+ hdr_info->table = FALSE;
}
cie_usage_count++;
hdr_info->fde_count++;
}
- cookie->rel = rel;
if (cie.lsda_encoding != DW_EH_PE_omit)
{
unsigned int dummy;
@@ -672,7 +602,7 @@ _bfd_elf_discard_section_eh_frame (abfd, info, sec, ehdrsec,
}
elf_section_data (sec)->sec_info = sec_info;
- elf_section_data (sec)->sec_info_type = ELF_INFO_TYPE_EH_FRAME;
+ sec->sec_info_type = ELF_INFO_TYPE_EH_FRAME;
/* Ok, now we can assign new offsets. */
offset = 0;
@@ -730,47 +660,36 @@ free_no_table:
free (ehbuf);
if (sec_info)
free (sec_info);
- hdr_info->table = false;
+ hdr_info->table = FALSE;
hdr_info->last_cie.hdr.length = 0;
- return false;
+ 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. */
-boolean
-_bfd_elf_discard_section_eh_frame_hdr (abfd, info, sec)
- bfd *abfd;
- struct bfd_link_info *info;
- asection *sec;
+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;
- unsigned int ptr_size;
-
- ptr_size = (elf_elfheader (abfd)->e_ident[EI_CLASS]
- == ELFCLASS64) ? 8 : 4;
+ asection *sec;
- if ((elf_section_data (sec)->sec_info_type
- != ELF_INFO_TYPE_EH_FRAME_HDR)
- || ! info->eh_frame_hdr)
- {
- _bfd_strip_section_from_output (info, sec);
- return false;
- }
+ htab = elf_hash_table (info);
+ hdr_info = &htab->eh_info;
+ sec = hdr_info->hdr_sec;
+ if (sec == NULL)
+ return FALSE;
- hdr_info = (struct eh_frame_hdr_info *)
- elf_section_data (sec)->sec_info;
- if (hdr_info->strip)
- 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 = true;
- return true;
+ elf_tdata (abfd)->eh_frame_hdr = sec;
+ return TRUE;
}
/* This function is called from size_dynamic_sections.
@@ -778,25 +697,24 @@ _bfd_elf_discard_section_eh_frame_hdr (abfd, info, sec)
because later on it is too late for calling _bfd_strip_section_from_output,
since dynamic symbol table has been sized. */
-boolean
-_bfd_elf_maybe_strip_eh_frame_hdr (info)
- struct bfd_link_info *info;
+bfd_boolean
+_bfd_elf_maybe_strip_eh_frame_hdr (struct bfd_link_info *info)
{
- asection *sec, *o;
+ asection *o;
bfd *abfd;
+ struct elf_link_hash_table *htab;
struct eh_frame_hdr_info *hdr_info;
- sec = bfd_get_section_by_name (elf_hash_table (info)->dynobj, ".eh_frame_hdr");
- if (sec == NULL || bfd_is_abs_section (sec->output_section))
- return true;
-
- hdr_info
- = bfd_zmalloc (sizeof (struct eh_frame_hdr_info));
- if (hdr_info == NULL)
- return false;
+ htab = elf_hash_table (info);
+ hdr_info = &htab->eh_info;
+ if (hdr_info->hdr_sec == NULL)
+ return TRUE;
- elf_section_data (sec)->sec_info = hdr_info;
- elf_section_data (sec)->sec_info_type = ELF_INFO_TYPE_EH_FRAME_HDR;
+ 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)
@@ -811,12 +729,13 @@ _bfd_elf_maybe_strip_eh_frame_hdr (info)
if (abfd == NULL)
{
- _bfd_strip_section_from_output (info, sec);
- hdr_info->strip = true;
+ _bfd_strip_section_from_output (info, hdr_info->hdr_sec);
+ hdr_info->hdr_sec = NULL;
+ return TRUE;
}
- else
- hdr_info->table = true;
- return true;
+
+ hdr_info->table = TRUE;
+ return TRUE;
}
/* Adjust an address in the .eh_frame section. Given OFFSET within
@@ -825,18 +744,16 @@ _bfd_elf_maybe_strip_eh_frame_hdr (info)
or to offset with dynamic relocation which is no longer needed. */
bfd_vma
-_bfd_elf_eh_frame_section_offset (output_bfd, sec, offset)
- bfd *output_bfd ATTRIBUTE_UNUSED;
- asection *sec;
- bfd_vma offset;
+_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 (elf_section_data (sec)->sec_info_type != ELF_INFO_TYPE_EH_FRAME)
+ if (sec->sec_info_type != ELF_INFO_TYPE_EH_FRAME)
return offset;
- sec_info = (struct eh_frame_sec_info *)
- elf_section_data (sec)->sec_info;
+ sec_info = elf_section_data (sec)->sec_info;
if (offset >= sec->_raw_size)
return offset - (sec->_cooked_size - sec->_raw_size);
@@ -873,9 +790,8 @@ _bfd_elf_eh_frame_section_offset (output_bfd, sec, offset)
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)))
+ && (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
@@ -885,13 +801,14 @@ _bfd_elf_eh_frame_section_offset (output_bfd, sec, offset)
/* Write out .eh_frame section. This is called with the relocated
contents. */
-boolean
-_bfd_elf_write_section_eh_frame (abfd, sec, ehdrsec, contents)
- bfd *abfd;
- asection *sec, *ehdrsec;
- bfd_byte *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;
@@ -902,26 +819,17 @@ _bfd_elf_write_section_eh_frame (abfd, sec, ehdrsec, contents)
ptr_size = (elf_elfheader (sec->owner)->e_ident[EI_CLASS]
== ELFCLASS64) ? 8 : 4;
- if (elf_section_data (sec)->sec_info_type != ELF_INFO_TYPE_EH_FRAME)
- return bfd_set_section_contents (abfd, sec->output_section,
- contents,
- (file_ptr) sec->output_offset,
- sec->_raw_size);
- sec_info = (struct eh_frame_sec_info *)
- elf_section_data (sec)->sec_info;
- hdr_info = NULL;
- if (ehdrsec
- && (elf_section_data (ehdrsec)->sec_info_type
- == ELF_INFO_TYPE_EH_FRAME_HDR))
- {
- hdr_info = (struct eh_frame_hdr_info *)
- elf_section_data (ehdrsec)->sec_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;
- }
+ 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)
@@ -1005,7 +913,9 @@ _bfd_elf_write_section_eh_frame (abfd, sec, ehdrsec, contents)
{
bfd_vma value;
- value = read_value (abfd, buf, per_width);
+ 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);
@@ -1034,14 +944,16 @@ _bfd_elf_write_section_eh_frame (abfd, sec, ehdrsec, contents)
unsigned int width;
buf = contents + sec_info->entry[i].offset;
- /* Skip length. */
+ /* 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);
+ 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)
@@ -1085,7 +997,9 @@ _bfd_elf_write_section_eh_frame (abfd, sec, ehdrsec, contents)
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);
+ 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)
@@ -1121,6 +1035,42 @@ _bfd_elf_write_section_eh_frame (abfd, sec, ehdrsec, contents)
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);
@@ -1133,12 +1083,10 @@ _bfd_elf_write_section_eh_frame (abfd, sec, ehdrsec, contents)
VMA of FDE initial location. */
static int
-vma_compare (a, b)
- const PTR a;
- const PTR b;
+vma_compare (const void *a, const void *b)
{
- struct eh_frame_array_ent *p = (struct eh_frame_array_ent *) a;
- struct eh_frame_array_ent *q = (struct eh_frame_array_ent *) 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)
@@ -1166,55 +1114,58 @@ vma_compare (a, b)
fde_count x [encoded] initial_loc, fde
(array of encoded pairs containing
FDE initial_location field and FDE address,
- sorted by increasing initial_loc) */
+ sorted by increasing initial_loc). */
-boolean
-_bfd_elf_write_section_eh_frame_hdr (abfd, sec)
- bfd *abfd;
- asection *sec;
+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;
- unsigned int ptr_size;
+ asection *sec;
bfd_byte *contents;
asection *eh_frame_sec;
bfd_size_type size;
+ bfd_boolean retval;
+ bfd_vma encoded_eh_frame;
- ptr_size = (elf_elfheader (sec->owner)->e_ident[EI_CLASS]
- == ELFCLASS64) ? 8 : 4;
-
- BFD_ASSERT (elf_section_data (sec)->sec_info_type
- == ELF_INFO_TYPE_EH_FRAME_HDR);
- hdr_info = (struct eh_frame_hdr_info *)
- elf_section_data (sec)->sec_info;
- if (hdr_info->strip)
- return true;
+ 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;
+ return FALSE;
eh_frame_sec = bfd_get_section_by_name (abfd, ".eh_frame");
if (eh_frame_sec == NULL)
- return false;
+ {
+ free (contents);
+ return FALSE;
+ }
memset (contents, 0, EH_FRAME_HDR_SIZE);
- contents[0] = 1; /* Version */
- contents[1] = DW_EH_PE_pcrel | DW_EH_PE_sdata4; /* .eh_frame offset */
+ 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 */
+ 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, eh_frame_sec->vma - sec->output_section->vma - 4,
- contents + 4);
+ bfd_put_32 (abfd, encoded_eh_frame, contents + 4);
+
if (contents[2] != DW_EH_PE_omit)
{
unsigned int i;
@@ -1234,7 +1185,35 @@ _bfd_elf_write_section_eh_frame_hdr (abfd, sec)
}
}
- return bfd_set_section_contents (abfd, sec->output_section,
- contents, (file_ptr) sec->output_offset,
- sec->_cooked_size);
+ 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;
}
OpenPOWER on IntegriCloud