This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH 3/7] Fix --gc-sections for C++ MIPS ELF


I imagine this might be the most controversial of the changes.
_bfd_elf_get_eh_frame_sec_info currently has three loops:

  - The main parsing loop.  It grows memory as needed and stores
    stores CIE offsets rather than CIE pointers in the FDEs' cie_inf
    fields.  It decides on the fly whether to keep an FDE or not.

  - A pass over the CIEs.  If a CIE is needed by at least one
    to-be-kept FDE, the pass tries to merge the CIE with one
    that is already in the global pool, adding a new CIE to the
    pool on failure.  The pass also copies some information
    from the temporary CIE structure to the eh_cie_fde.

  - A loop over the to-be-kept entries that assigns final offsets.
    It also points each to-be-kept FDE at its final CIE.

If we're going to parse .eh_frame earlier than we do now, we can't
always discard FDEs and CIEs on the fly; we need a separate pass
that lives _outside_ the parsing routines.  And that in turn means
that the parsing routines don't know for sure whether a CIE is
needed or not.  We could get around this by keeping the extended
CIE information around and leaving the discard routines to merge CIEs,
but I think it would be better to merge all CIEs upfront.  Both approaches
should give the same results: it's just a bookkeeping issue.

Also, later patches need to construct chains of eh_cie_fde entries,
so it would be better if we didn't dynamically grow the sec_info
structure in the main parsing loop.

This patch splits out the parsing code into a separate function
with two loops:

  - A simple pass over the section contents to count the CIEs and FDEs.
    Once we know how many there are, we can allocate the necessary
    memory upfront.

  - The main parsing loop.  It adds all CIEs to the global pool,
    if we're using such a pool, and uses a new eh_cie_fde u.cie.merged
    field to point to the representative of each CIE group.  (We don't
    know at this stage whether we'll keep that representative or not.)
    It points each FDE's u.fde.cie_inf field at the _local_ CIE,
    so that later patches can use the same reloc cookie to mark
    CIEs and FDEs; the u.cie.merged field then points to the CIE's
    group representative.

The EH discard routine then uses the cached section information.
It also has two loops:

  - A pass over the FDEs to decide which we need to keep.

  - A loop over the to-be-kept entries that assigns final offsets.

In the worst case, that's 4 O(n) loops rather than 3.  However,
the second of the original three loops only looked at CIEs, so it was
probably less expensive than the other 6 loops in the average case.
>From that point of view, this patch could slow things down.

FWIW, the final patch in the series gets rid of offsets_adjusted,
thus saving a pass over the .eh_frames there.  I don't know if that's
enough mitigation.

The CIE marking code might look a little more convoluted than necessary.
The idea is to make sure that we only look at u.cie.merged when
removed == 1, which leads indirectly to the offsets_adjusted patch.

The u.cie.merged comment gets better in a later patch (or so I hope).

Richard


bfd/
	* elf-bfd.h (eh_cie_fde): Add u.cie.  Document how u.fde.cie_inf
	changes when removed == 0.
	(eh_frame_hdr_info): Add parsed_eh_frames.
	(_bfd_elf_begin_eh_frame_parsing): Declare.
	(_bfd_elf_parse_eh_frame): Declare.
	(_bfd_elf_end_eh_frame_parsing): Declare.
	* elf-eh-frame.c (_bfd_elf_begin_eh_frame_parsing): New function.
	(_bfd_elf_parse_eh_frame): New function, split out from
	_bfd_elf_discard_section_eh_frame.  Make a first pass through the
	buffer to calculate the number of entries and CIEs.  Allocate memory
	for them before the main loop.  Replace current extended cie
	representation with a pair of pointers, one to the local eh_cie_fde
	and one to the full struct cie.  Allocate a separate array of struct
	cies if not merging.  Merge CIEs during the main loop and set up each
	u.cie.merged field.  Point an FDE's cie_inf field directly at the
	local CIE.  Initially assume that all entries should be removed.
	(_bfd_elf_end_eh_frame_parsing): New function.
	(_bfd_elf_discard_section_eh_frame): Assume that the section has
	already been parsed.  Use a separate pass to mark entries that
	need to be kept.  Use the u.cie.merged field to track a CIE's
	group representative.
	* elflink.c (bfd_elf_discard_info): Call _bfd_elf_parse_eh_frame
	before _bfd_elf_discard_section_eh_frame.  Wrap loop with calls to
	_bfd_elf_begin_eh_frame_parsing and _bfd_elf_end_eh_frame_parsing.

Index: bfd/elf-bfd.h
===================================================================
*** bfd/elf-bfd.h	2007-12-02 17:01:08.000000000 +0000
--- bfd/elf-bfd.h	2007-12-02 17:21:33.000000000 +0000
*************** struct eh_cie_fde
*** 266,274 ****
  {
    union {
      struct {
!       /* The CIE that we have chosen to use for this FDE.  */
        struct eh_cie_fde *cie_inf;
      } fde;
    } u;
    unsigned int reloc_index;
    unsigned int size;
--- 266,287 ----
  {
    union {
      struct {
!       /* If REMOVED == 1, this is the CIE that the FDE originally used.
! 	 The CIE belongs to the same .eh_frame input section as the FDE.
! 
! 	 If REMOVED == 0, this is the CIE that we have chosen to use for
! 	 the output FDE.  The CIE's REMOVED field is also 0, but the CIE
! 	 might belong to a different .eh_frame input section from the FDE.  */
        struct eh_cie_fde *cie_inf;
      } fde;
+     struct {
+       /* In general, equivalent CIEs are grouped together, with one CIE
+ 	 representing all the others in a group.  If REMOVED == 0,
+ 	 this CIE is the group representative.  If REMOVED == 1,
+ 	 following this pointer brings us "closer" to the CIE's group
+ 	 representative, and reapplying always gives the representative.  */
+       struct eh_cie_fde *merged;
+     } cie;
    } u;
    unsigned int reloc_index;
    unsigned int size;
*************** struct eh_frame_hdr_info
*** 308,313 ****
--- 321,328 ----
    asection *hdr_sec;
    unsigned int fde_count, array_count;
    struct eh_frame_array_ent *array;
+   /* TRUE if all .eh_frames have been parsd.  */
+   bfd_boolean parsed_eh_frames;
    /* 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.  */
*************** #define _bfd_elf_minisymbol_to_symbol _b
*** 1723,1728 ****
--- 1738,1750 ----
  extern void _bfd_elf_strtab_finalize
    (struct elf_strtab_hash *);
  
+ extern void _bfd_elf_begin_eh_frame_parsing
+   (struct bfd_link_info *info);
+ extern void _bfd_elf_parse_eh_frame
+   (bfd *, struct bfd_link_info *, asection *, struct elf_reloc_cookie *);
+ extern void _bfd_elf_end_eh_frame_parsing
+   (struct bfd_link_info *info);
+ 
  extern bfd_boolean _bfd_elf_discard_section_eh_frame
    (bfd *, struct bfd_link_info *, asection *,
     bfd_boolean (*) (bfd_vma, void *), struct elf_reloc_cookie *);
Index: bfd/elf-eh-frame.c
===================================================================
*** bfd/elf-eh-frame.c	2007-12-02 17:01:08.000000000 +0000
--- bfd/elf-eh-frame.c	2007-12-02 17:03:27.000000000 +0000
*************** skip_non_nops (bfd_byte *buf, bfd_byte *
*** 431,446 ****
    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							\
--- 431,456 ----
    return last;
  }
  
! /* Called before calling _bfd_elf_parse_eh_frame on every input bfd's
!    .eh_frame section.  */
  
! void
! _bfd_elf_begin_eh_frame_parsing (struct bfd_link_info *info)
! {
!   struct eh_frame_hdr_info *hdr_info;
! 
!   hdr_info = &elf_hash_table (info)->eh_info;
!   if (!hdr_info->parsed_eh_frames && !info->relocatable)
!     hdr_info->cies = htab_try_create (1, cie_hash, cie_eq, free);
! }
! 
! /* Try to parse .eh_frame section SEC, which belongs to ABFD.  Store the
!    information in the section's sec_info field on success.  COOKIE
!    describes the relocations in SEC.  */
! 
! void
! _bfd_elf_parse_eh_frame (bfd *abfd, struct bfd_link_info *info,
! 			 asection *sec, struct elf_reloc_cookie *cookie)
  {
  #define REQUIRE(COND)					\
    do							\
*************** #define REQUIRE(COND)					\
*** 448,492 ****
        goto free_no_table;				\
    while (0)
  
!   bfd_byte *ehbuf = NULL, *buf;
    bfd_byte *last_fde;
!   struct eh_cie_fde *ent, *this_inf;
    unsigned int hdr_length, hdr_id;
    struct extended_cie
      {
!       struct cie cie;
!       unsigned int offset;
!       unsigned int usage_count;
!       unsigned int entry;
      } *ecies = NULL, *ecie;
!   unsigned int ecie_count = 0, ecie_alloced = 0;
!   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 offset;
    unsigned int ptr_size;
!   unsigned int entry_alloced;
  
    if (sec->size == 0)
      {
        /* This file does not contain .eh_frame information.  */
!       return FALSE;
      }
  
    if (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;
- 
-   if (hdr_info->cies == NULL && !info->relocatable)
-     hdr_info->cies = htab_try_create (1, cie_hash, cie_eq, free);
- 
    /* Read the frame unwind information from abfd.  */
  
    REQUIRE (bfd_malloc_and_get_section (abfd, sec, &ehbuf));
--- 458,499 ----
        goto free_no_table;				\
    while (0)
  
!   bfd_byte *ehbuf = NULL, *buf, *end;
    bfd_byte *last_fde;
!   struct eh_cie_fde *this_inf;
    unsigned int hdr_length, hdr_id;
    struct extended_cie
      {
!       struct cie *cie;
!       struct eh_cie_fde *local_cie;
      } *ecies = NULL, *ecie;
!   unsigned int ecie_count;
!   struct cie *cie, *local_cies = NULL, tmp_cie;
    struct elf_link_hash_table *htab;
    struct eh_frame_hdr_info *hdr_info;
    struct eh_frame_sec_info *sec_info = NULL;
    unsigned int ptr_size;
!   unsigned int num_cies;
!   unsigned int num_entries;
! 
!   htab = elf_hash_table (info);
!   hdr_info = &htab->eh_info;
!   if (hdr_info->parsed_eh_frames)
!     return;
  
    if (sec->size == 0)
      {
        /* This file does not contain .eh_frame information.  */
!       return;
      }
  
    if (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;
      }
  
    /* Read the frame unwind information from abfd.  */
  
    REQUIRE (bfd_malloc_and_get_section (abfd, sec, &ehbuf));
*************** #define REQUIRE(COND)					\
*** 497,503 ****
      {
        /* Empty .eh_frame section.  */
        free (ehbuf);
!       return FALSE;
      }
  
    /* If .eh_frame section size doesn't fit into int, we cannot handle
--- 504,510 ----
      {
        /* Empty .eh_frame section.  */
        free (ehbuf);
!       return;
      }
  
    /* If .eh_frame section size doesn't fit into int, we cannot handle
*************** #define REQUIRE(COND)					\
*** 508,519 ****
  	      ->elf_backend_eh_frame_address_size (abfd, sec));
    REQUIRE (ptr_size != 0);
  
    buf = ehbuf;
    sec_info = bfd_zmalloc (sizeof (struct eh_frame_sec_info)
! 			  + 99 * sizeof (struct eh_cie_fde));
    REQUIRE (sec_info);
  
!   entry_alloced = 100;
  
  #define ENSURE_NO_RELOCS(buf)				\
    REQUIRE (!(cookie->rel < cookie->relend		\
--- 515,561 ----
  	      ->elf_backend_eh_frame_address_size (abfd, sec));
    REQUIRE (ptr_size != 0);
  
+   /* Go through the section contents and work out how many FDEs and
+      CIEs there are.  */
    buf = ehbuf;
+   end = ehbuf + sec->size;
+   num_cies = 0;
+   num_entries = 0;
+   while (buf != end)
+     {
+       num_entries++;
+ 
+       /* Read the length of the entry.  */
+       REQUIRE (skip_bytes (&buf, end, 4));
+       hdr_length = bfd_get_32 (abfd, buf - 4);
+ 
+       /* 64-bit .eh_frame is not supported.  */
+       REQUIRE (hdr_length != 0xffffffff);
+       if (hdr_length == 0)
+ 	break;
+ 
+       REQUIRE (skip_bytes (&buf, end, 4));
+       hdr_id = bfd_get_32 (abfd, buf - 4);
+       if (hdr_id == 0)
+ 	num_cies++;
+ 
+       REQUIRE (skip_bytes (&buf, end, hdr_length - 4));
+     }
+ 
    sec_info = bfd_zmalloc (sizeof (struct eh_frame_sec_info)
! 			  + (num_entries - 1) * sizeof (struct eh_cie_fde));
    REQUIRE (sec_info);
  
!   ecies = bfd_zmalloc (num_cies * sizeof (*ecies));
!   REQUIRE (ecies);
! 
!   /* If we're not merging CIE entries (such as for a relocatable link),
!      we need to have a "struct cie" for each CIE in this section.  */
!   if (hdr_info->cies == NULL)
!     {
!       local_cies = bfd_zmalloc (num_cies * sizeof (*local_cies));
!       REQUIRE (local_cies);
!     }
  
  #define ENSURE_NO_RELOCS(buf)				\
    REQUIRE (!(cookie->rel < cookie->relend		\
*************** #define GET_RELOC(buf)					\
*** 533,571 ****
  	== (bfd_size_type) ((buf) - ehbuf)))		\
     ? cookie->rel : NULL)
  
!   for (;;)
      {
        char *aug;
!       bfd_byte *start, *end, *insns, *insns_end;
        bfd_size_type length;
        unsigned int set_loc_count;
  
-       if (sec_info->count == entry_alloced)
- 	{
- 	  sec_info = bfd_realloc (sec_info,
- 				  sizeof (struct eh_frame_sec_info)
- 				  + ((entry_alloced + 99)
- 				     * sizeof (struct eh_cie_fde)));
- 	  REQUIRE (sec_info);
- 
- 	  memset (&sec_info->entry[entry_alloced], 0,
- 		  100 * sizeof (struct eh_cie_fde));
- 	  entry_alloced += 100;
- 	}
- 
        this_inf = sec_info->entry + sec_info->count;
        last_fde = buf;
  
-       if ((bfd_size_type) (buf - ehbuf) == sec->size)
- 	break;
- 
        /* 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;
--- 575,596 ----
  	== (bfd_size_type) ((buf) - ehbuf)))		\
     ? cookie->rel : NULL)
  
!   buf = ehbuf;
!   ecie_count = 0;
!   while ((bfd_size_type) (buf - ehbuf) != sec->size)
      {
        char *aug;
!       bfd_byte *start, *insns, *insns_end;
        bfd_size_type length;
        unsigned int set_loc_count;
  
        this_inf = sec_info->entry + sec_info->count;
        last_fde = buf;
  
        /* Read the length of the entry.  */
        REQUIRE (skip_bytes (&buf, ehbuf + sec->size, 4));
        hdr_length = bfd_get_32 (abfd, buf - 4);
  
        /* 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;
*************** #define GET_RELOC(buf)					\
*** 594,612 ****
  	  /* CIE  */
  	  this_inf->cie = 1;
  
! 	  if (ecie_count == ecie_alloced)
  	    {
! 	      ecies = bfd_realloc (ecies,
! 				   (ecie_alloced + 20) * sizeof (*ecies));
! 	      REQUIRE (ecies);
! 	      memset (&ecies[ecie_alloced], 0, 20 * sizeof (*ecies));
! 	      ecie_alloced += 20;
  	    }
! 
! 	  cie = &ecies[ecie_count].cie;
! 	  ecies[ecie_count].offset = this_inf->offset;
! 	  ecies[ecie_count++].entry = sec_info->count;
  	  cie->length = hdr_length;
  	  start = buf;
  	  REQUIRE (read_byte (&buf, end, &cie->version));
  
--- 619,637 ----
  	  /* CIE  */
  	  this_inf->cie = 1;
  
! 	  /* If we're merging CIEs, construct the struct cie in TMP_CIE;
! 	     we'll enter it into the global pool later.  Otherwise point
! 	     CIE to one of the section-local cie structures.  */
! 	  if (local_cies)
! 	    cie = local_cies + ecie_count;
! 	  else
  	    {
! 	      cie = &tmp_cie;
! 	      memset (cie, 0, sizeof (*cie));
  	    }
! 	  cie->cie_inf = this_inf;
  	  cie->length = hdr_length;
+ 	  cie->output_sec = sec->output_section;
  	  start = buf;
  	  REQUIRE (read_byte (&buf, end, &cie->version));
  
*************** #define GET_RELOC(buf)					\
*** 788,835 ****
  	  insns = buf;
  	  buf += initial_insn_length;
  	  ENSURE_NO_RELOCS (buf);
  	}
        else
  	{
  	  /* Find the corresponding CIE.  */
  	  unsigned int cie_offset = this_inf->offset + 4 - hdr_id;
  	  for (ecie = ecies; ecie < ecies + ecie_count; ++ecie)
! 	    if (cie_offset == ecie->offset)
  	      break;
  
  	  /* Ensure this FDE references one of the CIEs in this input
  	     section.  */
  	  REQUIRE (ecie != ecies + ecie_count);
! 	  cie = &ecie->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;
- 		  (*info->callbacks->einfo)
- 		    (_("%P: fde encoding in %B(%A) prevents .eh_frame_hdr"
- 		       " table being created.\n"), abfd, sec);
- 		}
- 	      ecie->usage_count++;
- 	      hdr_info->fde_count++;
- 	      this_inf->u.fde.cie_inf = (void *) (ecie - ecies);
- 	    }
- 
  	  /* Skip the initial location and address range.  */
  	  start = buf;
  	  length = get_DW_EH_PE_width (cie->fde_encoding, ptr_size);
--- 813,841 ----
  	  insns = buf;
  	  buf += initial_insn_length;
  	  ENSURE_NO_RELOCS (buf);
+ 
+ 	  this_inf->make_relative = cie->make_relative;
+ 	  this_inf->make_lsda_relative = cie->make_lsda_relative;
+ 	  this_inf->per_encoding_relative
+ 	    = (cie->per_encoding & 0x70) == DW_EH_PE_pcrel;
  	}
        else
  	{
  	  /* Find the corresponding CIE.  */
  	  unsigned int cie_offset = this_inf->offset + 4 - hdr_id;
  	  for (ecie = ecies; ecie < ecies + ecie_count; ++ecie)
! 	    if (cie_offset == ecie->local_cie->offset)
  	      break;
  
  	  /* Ensure this FDE references one of the CIEs in this input
  	     section.  */
  	  REQUIRE (ecie != ecies + ecie_count);
! 	  cie = ecie->cie;
! 	  this_inf->u.fde.cie_inf = ecie->local_cie;
  
  	  ENSURE_NO_RELOCS (buf);
  	  REQUIRE (GET_RELOC (buf));
  
  	  /* Skip the initial location and address range.  */
  	  start = buf;
  	  length = get_DW_EH_PE_width (cie->fde_encoding, ptr_size);
*************** #define GET_RELOC(buf)					\
*** 901,990 ****
  	    }
  	}
  
        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;
  
!   /* Look at all CIEs in this section and determine which can be
!      removed as unused, which can be merged with previous duplicate
!      CIEs and which need to be kept.  */
!   for (ecie = ecies; ecie < ecies + ecie_count; ++ecie)
!     {
!       if (ecie->usage_count == 0)
! 	{
! 	  sec_info->entry[ecie->entry].removed = 1;
! 	  continue;
! 	}
!       ecie->cie.output_sec = sec->output_section;
!       ecie->cie.cie_inf = sec_info->entry + ecie->entry;
!       cie_compute_hash (&ecie->cie);
!       if (hdr_info->cies != NULL)
! 	{
! 	  void **loc = htab_find_slot_with_hash (hdr_info->cies, &ecie->cie,
! 						 ecie->cie.hash, INSERT);
! 	  if (loc != NULL)
! 	    {
! 	      if (*loc != HTAB_EMPTY_ENTRY)
! 		{
! 		  sec_info->entry[ecie->entry].removed = 1;
! 		  ecie->cie.cie_inf = ((struct cie *) *loc)->cie_inf;
! 		  continue;
! 		}
  
! 	      *loc = malloc (sizeof (struct cie));
! 	      if (*loc == NULL)
! 		*loc = HTAB_DELETED_ENTRY;
! 	      else
! 		memcpy (*loc, &ecie->cie, sizeof (struct cie));
! 	    }
! 	}
!       ecie->cie.cie_inf->make_relative = ecie->cie.make_relative;
!       ecie->cie.cie_inf->make_lsda_relative = ecie->cie.make_lsda_relative;
!       ecie->cie.cie_inf->per_encoding_relative
! 	= (ecie->cie.per_encoding & 0x70) == DW_EH_PE_pcrel;
      }
  
!   /* Ok, now we can assign new offsets.  */
!   offset = 0;
    for (ent = sec_info->entry; ent < sec_info->entry + sec_info->count; ++ent)
!     if (!ent->removed)
        {
! 	if (!ent->cie)
  	  {
! 	    ecie = ecies + (bfd_hostptr_t) ent->u.fde.cie_inf;
! 	    ent->u.fde.cie_inf = ecie->cie.cie_inf;
  	  }
  	ent->new_offset = offset;
  	offset += size_of_output_cie_fde (ent, ptr_size);
        }
  
-   /* Resize the sec as needed.  */
    sec->rawsize = sec->size;
    sec->size = offset;
- 
-   free (ehbuf);
-   if (ecies)
-     free (ecies);
    return offset != sec->rawsize;
- 
- free_no_table:
-   (*info->callbacks->einfo)
-     (_("%P: error in %B(%A); no .eh_frame_hdr table will be created.\n"),
-      abfd, sec);
-   if (ehbuf)
-     free (ehbuf);
-   if (sec_info)
-     free (sec_info);
-   if (ecies)
-     free (ecies);
-   hdr_info->table = FALSE;
-   return FALSE;
- 
- #undef REQUIRE
  }
  
  /* This function is called for .eh_frame_hdr section after
--- 907,1061 ----
  	    }
  	}
  
+       this_inf->removed = 1;
        this_inf->fde_encoding = cie->fde_encoding;
        this_inf->lsda_encoding = cie->lsda_encoding;
+       if (this_inf->cie)
+ 	{
+ 	  /* We have now finished constructing the struct cie.  */
+ 	  if (hdr_info->cies != NULL)
+ 	    {
+ 	      /* See if we can merge this CIE with an earlier one.  */
+ 	      void **loc;
+ 
+ 	      cie_compute_hash (cie);
+ 	      loc = htab_find_slot_with_hash (hdr_info->cies, cie,
+ 					      cie->hash, INSERT);
+ 	      REQUIRE (loc);
+ 	      if (*loc == HTAB_EMPTY_ENTRY)
+ 		{
+ 		  *loc = malloc (sizeof (struct cie));
+ 		  REQUIRE (*loc);
+ 		  memcpy (*loc, cie, sizeof (struct cie));
+ 		}
+ 	      cie = (struct cie *) *loc;
+ 	    }
+ 	  this_inf->u.cie.merged = cie->cie_inf;
+ 	  ecies[ecie_count].cie = cie;
+ 	  ecies[ecie_count++].local_cie = this_inf;
+ 	}
        sec_info->count++;
      }
+   BFD_ASSERT (sec_info->count == num_entries);
+   BFD_ASSERT (ecie_count == num_cies);
  
    elf_section_data (sec)->sec_info = sec_info;
    sec->sec_info_type = ELF_INFO_TYPE_EH_FRAME;
+   goto success;
  
!  free_no_table:
!   (*info->callbacks->einfo)
!     (_("%P: error in %B(%A); no .eh_frame_hdr table will be created.\n"),
!      abfd, sec);
!   hdr_info->table = FALSE;
!   if (sec_info)
!     free (sec_info);
!  success:
!   if (ehbuf)
!     free (ehbuf);
!   if (ecies)
!     free (ecies);
!   if (local_cies)
!     free (local_cies);
! #undef REQUIRE
! }
  
! /* Finish a pass over all .eh_frame sections.  */
! 
! void
! _bfd_elf_end_eh_frame_parsing (struct bfd_link_info *info)
! {
!   struct eh_frame_hdr_info *hdr_info;
! 
!   hdr_info = &elf_hash_table (info)->eh_info;
!   if (hdr_info->cies != NULL)
!     {
!       htab_delete (hdr_info->cies);
!       hdr_info->cies = NULL;
      }
+   hdr_info->parsed_eh_frames = TRUE;
+ }
  
! /* 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)
! {
!   struct eh_cie_fde *ent, *cie, *merged;
!   struct eh_frame_sec_info *sec_info;
!   struct eh_frame_hdr_info *hdr_info;
!   unsigned int ptr_size, offset;
! 
!   sec_info = (struct eh_frame_sec_info *) elf_section_data (sec)->sec_info;
!   if (sec_info == NULL)
!     return FALSE;
! 
!   hdr_info = &elf_hash_table (info)->eh_info;
    for (ent = sec_info->entry; ent < sec_info->entry + sec_info->count; ++ent)
!     if (!ent->cie)
        {
! 	cookie->rel = cookie->rels + ent->reloc_index;
! 	BFD_ASSERT (cookie->rel < cookie->relend
! 		    && cookie->rel->r_offset == ent->offset + 8);
! 	if (!(*reloc_symbol_deleted_p) (ent->offset + 8, cookie))
  	  {
! 	    if (info->shared
! 		&& (((ent->fde_encoding & 0xf0) == DW_EH_PE_absptr
! 		     && ent->u.fde.cie_inf->make_relative == 0)
! 		    || (ent->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;
! 		(*info->callbacks->einfo)
! 		  (_("%P: fde encoding in %B(%A) prevents .eh_frame_hdr"
! 		     " table being created.\n"), abfd, sec);
! 	      }
! 	    ent->removed = 0;
! 	    hdr_info->fde_count++;
! 
! 	    cie = ent->u.fde.cie_inf;
! 	    if (cie->removed)
! 	      {
! 		merged = cie->u.cie.merged;
! 		if (!merged->removed)
! 		  /* We have decided to keep the group representative.  */
! 		  ent->u.fde.cie_inf = merged;
! 		else if (merged->u.cie.merged != merged)
! 		  /* We didn't keep the original group representative,
! 		     but we did keep an alternative.  */
! 		  ent->u.fde.cie_inf = merged->u.cie.merged;
! 		else
! 		  {
! 		    /* Make the local CIE represent the merged group.  */
! 		    merged->u.cie.merged = cie;
! 		    cie->removed = 0;
! 		  }
! 	      }
  	  }
+       }
+ 
+   ptr_size = (get_elf_backend_data (sec->owner)
+ 	      ->elf_backend_eh_frame_address_size (sec->owner, sec));
+   offset = 0;
+   for (ent = sec_info->entry; ent < sec_info->entry + sec_info->count; ++ent)
+     if (!ent->removed)
+       {
  	ent->new_offset = offset;
  	offset += size_of_output_cie_fde (ent, ptr_size);
        }
  
    sec->rawsize = sec->size;
    sec->size = offset;
    return offset != sec->rawsize;
  }
  
  /* This function is called for .eh_frame_hdr section after
*************** _bfd_elf_discard_section_eh_frame_hdr (b
*** 1001,1012 ****
    htab = elf_hash_table (info);
    hdr_info = &htab->eh_info;
  
-   if (hdr_info->cies != NULL)
-     {
-       htab_delete (hdr_info->cies);
-       hdr_info->cies = NULL;
-     }
- 
    sec = hdr_info->hdr_sec;
    if (sec == NULL)
      return FALSE;
--- 1072,1077 ----
Index: bfd/elflink.c
===================================================================
*** bfd/elflink.c	2007-12-02 17:01:03.000000000 +0000
--- bfd/elflink.c	2007-12-02 17:03:27.000000000 +0000
*************** bfd_elf_discard_info (bfd *output_bfd, s
*** 11894,11899 ****
--- 11894,11900 ----
        || !is_elf_hash_table (info->hash))
      return FALSE;
  
+   _bfd_elf_begin_eh_frame_parsing (info);
    for (abfd = info->input_bfds; abfd != NULL; abfd = abfd->link_next)
      {
        if (bfd_get_flavour (abfd) != bfd_target_elf_flavour)
*************** bfd_elf_discard_info (bfd *output_bfd, s
*** 11944,11949 ****
--- 11945,11951 ----
        if (eh != NULL
  	  && init_reloc_cookie_rels (&cookie, info, abfd, eh))
  	{
+ 	  _bfd_elf_parse_eh_frame (abfd, info, eh, &cookie);
  	  if (_bfd_elf_discard_section_eh_frame (abfd, info, eh,
  						 bfd_elf_reloc_symbol_deleted_p,
  						 &cookie))
*************** bfd_elf_discard_info (bfd *output_bfd, s
*** 11957,11962 ****
--- 11959,11965 ----
  
        fini_reloc_cookie (&cookie, abfd);
      }
+   _bfd_elf_end_eh_frame_parsing (info);
  
    if (info->eh_frame_hdr
        && !info->relocatable


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]