/* .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"
static int get_DW_EH_PE_width
PARAMS ((int, int));
static bfd_vma read_value
- PARAMS ((bfd *, bfd_byte *, int));
+ PARAMS ((bfd *, bfd_byte *, int, 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));
+ PARAMS ((const PTR, const PTR));
/* Helper function for reading uleb128 encoded data. */
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)
+read_value (abfd, buf, width, is_signed)
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
/* 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_boolean
_bfd_elf_discard_section_eh_frame (abfd, info, sec,
reloc_symbol_deleted_p, cookie)
bfd *abfd;
struct bfd_link_info *info;
asection *sec;
- boolean (*reloc_symbol_deleted_p) PARAMS ((bfd_vma, PTR));
+ bfd_boolean (*reloc_symbol_deleted_p) PARAMS ((bfd_vma, PTR));
struct elf_reloc_cookie *cookie;
{
bfd_byte *ehbuf = NULL, *buf;
if (sec->_raw_size == 0)
{
/* This file does not contain .eh_frame information. */
- return false;
+ return FALSE;
}
if ((sec->output_section != NULL
{
/* At least one of the sections is being discarded from the
link, so we should just ignore them. */
- return false;
+ return FALSE;
}
htab = elf_hash_table (info);
{
/* Empty .eh_frame section. */
free (ehbuf);
- return false;
+ return FALSE;
}
/* If .eh_frame section size doesn't fit into int, we cannot handle
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->relocateable
+ if ((!info->relocatable
&& cie_compare (&cie, &hdr_info->last_cie) == 0)
|| cie_usage_count == 0)
{
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++;
}
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;
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_boolean
_bfd_elf_discard_section_eh_frame_hdr (abfd, info)
bfd *abfd;
struct bfd_link_info *info;
hdr_info = &htab->eh_info;
sec = hdr_info->hdr_sec;
if (sec == NULL)
- return false;
+ return FALSE;
sec->_cooked_size = EH_FRAME_HDR_SIZE;
if (hdr_info->table)
/* Request program headers to be recalculated. */
elf_tdata (abfd)->program_header_size = 0;
elf_tdata (abfd)->eh_frame_hdr = sec;
- return true;
+ return TRUE;
}
/* This function is called from size_dynamic_sections.
because later on it is too late for calling _bfd_strip_section_from_output,
since dynamic symbol table has been sized. */
-boolean
+bfd_boolean
_bfd_elf_maybe_strip_eh_frame_hdr (info)
struct bfd_link_info *info;
{
htab = elf_hash_table (info);
hdr_info = &htab->eh_info;
if (hdr_info->hdr_sec == NULL)
- return true;
+ return TRUE;
if (bfd_is_abs_section (hdr_info->hdr_sec->output_section))
{
hdr_info->hdr_sec = NULL;
- return true;
+ return TRUE;
}
abfd = NULL;
{
_bfd_strip_section_from_output (info, hdr_info->hdr_sec);
hdr_info->hdr_sec = NULL;
- return true;
+ return TRUE;
}
- hdr_info->table = true;
- return true;
+ hdr_info->table = TRUE;
+ return TRUE;
}
/* Adjust an address in the .eh_frame section. Given OFFSET within
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;
/* Write out .eh_frame section. This is called with the relocated
contents. */
-boolean
+bfd_boolean
_bfd_elf_write_section_eh_frame (abfd, info, sec, contents)
bfd *abfd;
struct bfd_link_info *info;
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)
+ if (sec->sec_info_type != ELF_INFO_TYPE_EH_FRAME)
return bfd_set_section_contents (abfd, sec->output_section,
contents,
(file_ptr) sec->output_offset,
{
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);
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)
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)
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_boolean
_bfd_elf_write_section_eh_frame_hdr (abfd, info)
bfd *abfd;
struct bfd_link_info *info;
bfd_byte *contents;
asection *eh_frame_sec;
bfd_size_type size;
+ bfd_boolean retval;
htab = elf_hash_table (info);
hdr_info = &htab->eh_info;
sec = hdr_info->hdr_sec;
if (sec == NULL)
- return true;
+ 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] = DW_EH_PE_pcrel | DW_EH_PE_sdata4; /* .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
{
}
}
- 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;
}