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 1/7] Fix --gc-sections for C++ MIPS ELF


The discard routines store some relocation information in a structure
called elf_reloc_cookie, which the .eh_frame parser uses to check that
the relocs are as expected.  If we're going to parse .eh_frame earlier,
it would be good to have cookies at that stage too.

_bfd_elf_gc_mark uses the same information that you get from an
elf_reloc_cookie, but stores it in separate variables.  This first
patch therefore splits out the cookie initialisation and finalisation
routines from bfd_elf_discard_info and uses them in _bfd_elf_gc_mark as
well.  The patch also splits out parts of _bfd_elf_gc_mark so that they
can be reused in later patches.

The patch fixes a potential memory leak, although it probably never
occured in practice.  _bfd_elf_gc_mark behaves as though it could be
the first routine to set symtab_hdr->contents:

      if (isym != NULL && symtab_hdr->contents != (unsigned char *) isym)
	{
	  if (! info->keep_memory)
	    free (isym);
	  else
	    symtab_hdr->contents = (unsigned char *) isym;
	}

but it does this after a loop that involves recursive calls to
_bfd_elf_gc_mark.  If one of those recursive calls was for the
same input bfd, that call would still see a null contents field,
and would therefore create a second copy of the memory.  I avoided
this by putting the symtab_hdr->contents assignment in the
initialisation code instead.

Richard


bfd/
	* elf-bfd.h (_bfd_elf_gc_mark_rsec, _bfd_elf_gc_mark_reloc): Declare.
	(_bfd_elf_gc_mark): Use elf_gc_mark_hook_fn.
	* elflink.c (init_reloc_cookie, fini_reloc_cookie)
	(init_reloc_cookie_rels, fini_reloc_cookie_rels): New functions,
	split out from...
	(bfd_elf_discard_info): ...here.
	(init_reloc_cookie_for_section): New function.
	(fini_reloc_cookie_for_section): Likewise.
	(_bfd_elf_gc_mark_rsec, _bfd_elf_gc_mark_reloc): New functions,
	split out from...
	(_bfd_elf_gc_mark): ...here.  Use init_reloc_cookie_for_section
	and fini_reloc_cookie_for_section.

Index: bfd/elf-bfd.h
===================================================================
*** bfd/elf-bfd.h	2007-12-02 16:59:44.000000000 +0000
--- bfd/elf-bfd.h	2007-12-02 16:59:46.000000000 +0000
*************** extern void _bfd_elf_set_osabi (bfd * , 
*** 1971,1980 ****
    (asection *, struct bfd_link_info *, Elf_Internal_Rela *,
     struct elf_link_hash_entry *, Elf_Internal_Sym *);
  
  extern bfd_boolean _bfd_elf_gc_mark
!   (struct bfd_link_info *, asection *,
!    asection * (*) (asection *, struct bfd_link_info *, Elf_Internal_Rela *,
! 		   struct elf_link_hash_entry *, Elf_Internal_Sym *));
  
  extern bfd_boolean bfd_elf_gc_common_finalize_got_offsets
    (bfd *, struct bfd_link_info *);
--- 1971,1986 ----
    (asection *, struct bfd_link_info *, Elf_Internal_Rela *,
     struct elf_link_hash_entry *, Elf_Internal_Sym *);
  
+ extern asection *_bfd_elf_gc_mark_rsec
+   (struct bfd_link_info *, asection *, elf_gc_mark_hook_fn,
+    struct elf_reloc_cookie *);
+ 
+ extern bfd_boolean _bfd_elf_gc_mark_reloc
+   (struct bfd_link_info *, asection *, elf_gc_mark_hook_fn,
+    struct elf_reloc_cookie *, bfd_boolean);
+ 
  extern bfd_boolean _bfd_elf_gc_mark
!   (struct bfd_link_info *, asection *, elf_gc_mark_hook_fn);
  
  extern bfd_boolean bfd_elf_gc_common_finalize_got_offsets
    (bfd *, struct bfd_link_info *);
Index: bfd/elflink.c
===================================================================
*** bfd/elflink.c	2007-12-02 16:59:44.000000000 +0000
--- bfd/elflink.c	2007-12-02 17:01:03.000000000 +0000
*************** bfd_elf_final_link (bfd *abfd, struct bf
*** 10940,10945 ****
--- 10940,11078 ----
    return FALSE;
  }
  
+ /* Initialize COOKIE for input bfd ABFD.  */
+ 
+ static bfd_boolean
+ init_reloc_cookie (struct elf_reloc_cookie *cookie,
+ 		   struct bfd_link_info *info, bfd *abfd)
+ {
+   Elf_Internal_Shdr *symtab_hdr;
+   const struct elf_backend_data *bed;
+ 
+   bed = get_elf_backend_data (abfd);
+   symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
+ 
+   cookie->abfd = abfd;
+   cookie->sym_hashes = elf_sym_hashes (abfd);
+   cookie->bad_symtab = elf_bad_symtab (abfd);
+   if (cookie->bad_symtab)
+     {
+       cookie->locsymcount = symtab_hdr->sh_size / bed->s->sizeof_sym;
+       cookie->extsymoff = 0;
+     }
+   else
+     {
+       cookie->locsymcount = symtab_hdr->sh_info;
+       cookie->extsymoff = symtab_hdr->sh_info;
+     }
+ 
+   if (bed->s->arch_size == 32)
+     cookie->r_sym_shift = 8;
+   else
+     cookie->r_sym_shift = 32;
+ 
+   cookie->locsyms = (Elf_Internal_Sym *) symtab_hdr->contents;
+   if (cookie->locsyms == NULL && cookie->locsymcount != 0)
+     {
+       cookie->locsyms = bfd_elf_get_elf_syms (abfd, symtab_hdr,
+ 					      cookie->locsymcount, 0,
+ 					      NULL, NULL, NULL);
+       if (cookie->locsyms == NULL)
+ 	{
+ 	  info->callbacks->einfo (_("%P%X: can not read symbols: %E\n"));
+ 	  return FALSE;
+ 	}
+       if (info->keep_memory)
+ 	symtab_hdr->contents = (bfd_byte *) cookie->locsyms;
+     }
+   return TRUE;
+ }
+ 
+ /* Free the memory allocated by init_reloc_cookie, if appropriate.  */
+ 
+ static void
+ fini_reloc_cookie (struct elf_reloc_cookie *cookie, bfd *abfd)
+ {
+   Elf_Internal_Shdr *symtab_hdr;
+ 
+   symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
+   if (cookie->locsyms != NULL
+       && symtab_hdr->contents != (unsigned char *) cookie->locsyms)
+     free (cookie->locsyms);
+ }
+ 
+ /* Initialize the relocation information in COOKIE for input section SEC
+    of input bfd ABFD.  */
+ 
+ static bfd_boolean
+ init_reloc_cookie_rels (struct elf_reloc_cookie *cookie,
+ 			struct bfd_link_info *info, bfd *abfd,
+ 			asection *sec)
+ {
+   const struct elf_backend_data *bed;
+ 
+   if (sec->reloc_count == 0)
+     {
+       cookie->rels = NULL;
+       cookie->relend = NULL;
+     }
+   else
+     {
+       bed = get_elf_backend_data (abfd);
+ 
+       cookie->rels = _bfd_elf_link_read_relocs (abfd, sec, NULL, NULL,
+ 						info->keep_memory);
+       if (cookie->rels == NULL)
+ 	return FALSE;
+       cookie->rel = cookie->rels;
+       cookie->relend = (cookie->rels
+ 			+ sec->reloc_count * bed->s->int_rels_per_ext_rel);
+     }
+   cookie->rel = cookie->rels;
+   return TRUE;
+ }
+ 
+ /* Free the memory allocated by init_reloc_cookie_rels,
+    if appropriate.  */
+ 
+ static void
+ fini_reloc_cookie_rels (struct elf_reloc_cookie *cookie,
+ 			asection *sec)
+ {
+   if (cookie->rels && elf_section_data (sec)->relocs != cookie->rels)
+     free (cookie->rels);
+ }
+ 
+ /* Initialize the whole of COOKIE for input section SEC.  */
+ 
+ static bfd_boolean
+ init_reloc_cookie_for_section (struct elf_reloc_cookie *cookie,
+ 			       struct bfd_link_info *info,
+ 			       asection *sec)
+ {
+   if (!init_reloc_cookie (cookie, info, sec->owner))
+     goto error1;
+   if (!init_reloc_cookie_rels (cookie, info, sec->owner, sec))
+     goto error2;
+   return TRUE;
+ 
+  error2:
+   fini_reloc_cookie (cookie, sec->owner);
+  error1:
+   return FALSE;
+ }
+ 
+ /* Free the memory allocated by init_reloc_cookie_for_section,
+    if appropriate.  */
+ 
+ static void
+ fini_reloc_cookie_for_section (struct elf_reloc_cookie *cookie,
+ 			       asection *sec)
+ {
+   fini_reloc_cookie_rels (cookie, sec);
+   fini_reloc_cookie (cookie, sec->owner);
+ }
+ 
  /* Garbage collect unused sections.  */
  
  /* Default gc_mark_hook.  */
*************** _bfd_elf_gc_mark_hook (asection *sec,
*** 10972,10977 ****
--- 11105,11167 ----
    return NULL;
  }
  
+ /* COOKIE->rel describes a relocation against section SEC, which is
+    a section we've decided to keep.  Return the section that contains
+    the relocation symbol, or NULL if no section contains it.  */
+ 
+ asection *
+ _bfd_elf_gc_mark_rsec (struct bfd_link_info *info, asection *sec,
+ 		       elf_gc_mark_hook_fn gc_mark_hook,
+ 		       struct elf_reloc_cookie *cookie)
+ {
+   unsigned long r_symndx;
+   struct elf_link_hash_entry *h;
+ 
+   r_symndx = cookie->rel->r_info >> cookie->r_sym_shift;
+   if (r_symndx == 0)
+     return NULL;
+ 
+   if (r_symndx >= cookie->locsymcount
+       || ELF_ST_BIND (cookie->locsyms[r_symndx].st_info) != STB_LOCAL)
+     {
+       h = cookie->sym_hashes[r_symndx - cookie->extsymoff];
+       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;
+       return (*gc_mark_hook) (sec, info, cookie->rel, h, NULL);
+     }
+ 
+   return (*gc_mark_hook) (sec, info, cookie->rel, NULL,
+ 			  &cookie->locsyms[r_symndx]);
+ }
+ 
+ /* COOKIE->rel describes a relocation against section SEC, which is
+    a section we've decided to keep.  Mark the section that contains
+    the relocation symbol.  IS_EH is true if the mark comes from
+    .eh_frame.  */
+ 
+ bfd_boolean
+ _bfd_elf_gc_mark_reloc (struct bfd_link_info *info,
+ 			asection *sec,
+ 			elf_gc_mark_hook_fn gc_mark_hook,
+ 			struct elf_reloc_cookie *cookie,
+ 			bfd_boolean is_eh)
+ {
+   asection *rsec;
+ 
+   rsec = _bfd_elf_gc_mark_rsec (info, sec, gc_mark_hook, cookie);
+   if (rsec && !rsec->gc_mark)
+     {
+       if (bfd_get_flavour (rsec->owner) != bfd_target_elf_flavour)
+ 	rsec->gc_mark = 1;
+       else if (is_eh)
+ 	rsec->gc_mark_from_eh = 1;
+       else if (!_bfd_elf_gc_mark (info, rsec, gc_mark_hook))
+ 	return FALSE;
+     }
+   return TRUE;
+ }
+ 
  /* The mark phase of garbage collection.  For a given section, mark
     it and any sections in this section's group, and all the sections
     which define symbols to which it refers.  */
*************** _bfd_elf_gc_mark (struct bfd_link_info *
*** 10998,11100 ****
    is_eh = strcmp (sec->name, ".eh_frame") == 0;
    if ((sec->flags & SEC_RELOC) != 0 && sec->reloc_count > 0)
      {
!       Elf_Internal_Rela *relstart, *rel, *relend;
!       Elf_Internal_Shdr *symtab_hdr;
!       struct elf_link_hash_entry **sym_hashes;
!       size_t nlocsyms;
!       size_t extsymoff;
!       bfd *input_bfd = sec->owner;
!       const struct elf_backend_data *bed = get_elf_backend_data (input_bfd);
!       Elf_Internal_Sym *isym = NULL;
!       int r_sym_shift;
  
!       symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
!       sym_hashes = elf_sym_hashes (input_bfd);
! 
!       /* Read the local symbols.  */
!       if (elf_bad_symtab (input_bfd))
! 	{
! 	  nlocsyms = symtab_hdr->sh_size / bed->s->sizeof_sym;
! 	  extsymoff = 0;
! 	}
        else
- 	extsymoff = nlocsyms = symtab_hdr->sh_info;
- 
-       isym = (Elf_Internal_Sym *) symtab_hdr->contents;
-       if (isym == NULL && nlocsyms != 0)
- 	{
- 	  isym = bfd_elf_get_elf_syms (input_bfd, symtab_hdr, nlocsyms, 0,
- 				       NULL, NULL, NULL);
- 	  if (isym == NULL)
- 	    return FALSE;
- 	}
- 
-       /* Read the relocations.  */
-       relstart = _bfd_elf_link_read_relocs (input_bfd, sec, NULL, NULL,
- 					    info->keep_memory);
-       if (relstart == NULL)
- 	{
- 	  ret = FALSE;
- 	  goto out1;
- 	}
-       relend = relstart + sec->reloc_count * bed->s->int_rels_per_ext_rel;
- 
-       if (bed->s->arch_size == 32)
- 	r_sym_shift = 8;
-       else
- 	r_sym_shift = 32;
- 
-       for (rel = relstart; rel < relend; rel++)
- 	{
- 	  unsigned long r_symndx;
- 	  asection *rsec;
- 	  struct elf_link_hash_entry *h;
- 
- 	  r_symndx = rel->r_info >> r_sym_shift;
- 	  if (r_symndx == 0)
- 	    continue;
- 
- 	  if (r_symndx >= nlocsyms
- 	      || ELF_ST_BIND (isym[r_symndx].st_info) != STB_LOCAL)
- 	    {
- 	      h = sym_hashes[r_symndx - extsymoff];
- 	      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;
- 	      rsec = (*gc_mark_hook) (sec, info, rel, h, NULL);
- 	    }
- 	  else
- 	    {
- 	      rsec = (*gc_mark_hook) (sec, info, rel, NULL, &isym[r_symndx]);
- 	    }
- 
- 	  if (rsec && !rsec->gc_mark)
- 	    {
- 	      if (bfd_get_flavour (rsec->owner) != bfd_target_elf_flavour)
- 		rsec->gc_mark = 1;
- 	      else if (is_eh)
- 		rsec->gc_mark_from_eh = 1;
- 	      else if (!_bfd_elf_gc_mark (info, rsec, gc_mark_hook))
- 		{
- 		  ret = FALSE;
- 		  goto out2;
- 		}
- 	    }
- 	}
- 
-     out2:
-       if (elf_section_data (sec)->relocs != relstart)
- 	free (relstart);
-     out1:
-       if (isym != NULL && symtab_hdr->contents != (unsigned char *) isym)
  	{
! 	  if (! info->keep_memory)
! 	    free (isym);
! 	  else
! 	    symtab_hdr->contents = (unsigned char *) isym;
  	}
      }
- 
    return ret;
  }
  
--- 11188,11209 ----
    is_eh = strcmp (sec->name, ".eh_frame") == 0;
    if ((sec->flags & SEC_RELOC) != 0 && sec->reloc_count > 0)
      {
!       struct elf_reloc_cookie cookie;
  
!       if (!init_reloc_cookie_for_section (&cookie, info, sec))
! 	ret = FALSE;
        else
  	{
! 	  for (; cookie.rel < cookie.relend; cookie.rel++)
! 	    if (!_bfd_elf_gc_mark_reloc (info, sec, gc_mark_hook,
! 					 &cookie, is_eh))
! 	      {
! 		ret = FALSE;
! 		break;
! 	      }
! 	  fini_reloc_cookie_for_section (&cookie, sec);
  	}
      }
    return ret;
  }
  
*************** bfd_elf_discard_info (bfd *output_bfd, s
*** 11777,11786 ****
  {
    struct elf_reloc_cookie cookie;
    asection *stab, *eh;
-   Elf_Internal_Shdr *symtab_hdr;
    const struct elf_backend_data *bed;
    bfd *abfd;
-   unsigned int count;
    bfd_boolean ret = FALSE;
  
    if (info->traditional_format
--- 11886,11893 ----
*************** bfd_elf_discard_info (bfd *output_bfd, s
*** 11819,11913 ****
  	  && bed->elf_backend_discard_info == NULL)
  	continue;
  
!       symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
!       cookie.abfd = abfd;
!       cookie.sym_hashes = elf_sym_hashes (abfd);
!       cookie.bad_symtab = elf_bad_symtab (abfd);
!       if (cookie.bad_symtab)
! 	{
! 	  cookie.locsymcount = symtab_hdr->sh_size / bed->s->sizeof_sym;
! 	  cookie.extsymoff = 0;
! 	}
!       else
! 	{
! 	  cookie.locsymcount = symtab_hdr->sh_info;
! 	  cookie.extsymoff = symtab_hdr->sh_info;
! 	}
! 
!       if (bed->s->arch_size == 32)
! 	cookie.r_sym_shift = 8;
!       else
! 	cookie.r_sym_shift = 32;
! 
!       cookie.locsyms = (Elf_Internal_Sym *) symtab_hdr->contents;
!       if (cookie.locsyms == NULL && cookie.locsymcount != 0)
! 	{
! 	  cookie.locsyms = bfd_elf_get_elf_syms (abfd, symtab_hdr,
! 						 cookie.locsymcount, 0,
! 						 NULL, NULL, NULL);
! 	  if (cookie.locsyms == NULL)
! 	    {
! 	      info->callbacks->einfo (_("%P%X: can not read symbols: %E\n"));
! 	      return FALSE;
! 	    }
! 	}
  
!       if (stab != NULL)
  	{
! 	  cookie.rels = NULL;
! 	  count = stab->reloc_count;
! 	  if (count != 0)
! 	    cookie.rels = _bfd_elf_link_read_relocs (abfd, stab, NULL, NULL,
! 						     info->keep_memory);
! 	  if (cookie.rels != NULL)
! 	    {
! 	      cookie.rel = cookie.rels;
! 	      cookie.relend = cookie.rels;
! 	      cookie.relend += count * bed->s->int_rels_per_ext_rel;
! 	      if (_bfd_discard_section_stabs (abfd, stab,
! 					      elf_section_data (stab)->sec_info,
! 					      bfd_elf_reloc_symbol_deleted_p,
! 					      &cookie))
! 		ret = TRUE;
! 	      if (elf_section_data (stab)->relocs != cookie.rels)
! 		free (cookie.rels);
! 	    }
  	}
  
!       if (eh != NULL)
  	{
- 	  cookie.rels = NULL;
- 	  count = eh->reloc_count;
- 	  if (count != 0)
- 	    cookie.rels = _bfd_elf_link_read_relocs (abfd, eh, NULL, NULL,
- 						     info->keep_memory);
- 	  cookie.rel = cookie.rels;
- 	  cookie.relend = cookie.rels;
- 	  if (cookie.rels != NULL)
- 	    cookie.relend += count * bed->s->int_rels_per_ext_rel;
- 
  	  if (_bfd_elf_discard_section_eh_frame (abfd, info, eh,
  						 bfd_elf_reloc_symbol_deleted_p,
  						 &cookie))
  	    ret = TRUE;
! 
! 	  if (cookie.rels != NULL
! 	      && elf_section_data (eh)->relocs != cookie.rels)
! 	    free (cookie.rels);
  	}
  
        if (bed->elf_backend_discard_info != NULL
  	  && (*bed->elf_backend_discard_info) (abfd, &cookie, info))
  	ret = TRUE;
  
!       if (cookie.locsyms != NULL
! 	  && symtab_hdr->contents != (unsigned char *) cookie.locsyms)
! 	{
! 	  if (! info->keep_memory)
! 	    free (cookie.locsyms);
! 	  else
! 	    symtab_hdr->contents = (unsigned char *) cookie.locsyms;
! 	}
      }
  
    if (info->eh_frame_hdr
--- 11926,11961 ----
  	  && bed->elf_backend_discard_info == NULL)
  	continue;
  
!       if (!init_reloc_cookie (&cookie, info, abfd))
! 	return FALSE;
  
!       if (stab != NULL
! 	  && stab->reloc_count > 0
! 	  && init_reloc_cookie_rels (&cookie, info, abfd, stab))
  	{
! 	  if (_bfd_discard_section_stabs (abfd, stab,
! 					  elf_section_data (stab)->sec_info,
! 					  bfd_elf_reloc_symbol_deleted_p,
! 					  &cookie))
! 	    ret = TRUE;
! 	  fini_reloc_cookie_rels (&cookie, stab);
  	}
  
!       if (eh != NULL
! 	  && init_reloc_cookie_rels (&cookie, info, abfd, eh))
  	{
  	  if (_bfd_elf_discard_section_eh_frame (abfd, info, eh,
  						 bfd_elf_reloc_symbol_deleted_p,
  						 &cookie))
  	    ret = TRUE;
! 	  fini_reloc_cookie_rels (&cookie, eh);
  	}
  
        if (bed->elf_backend_discard_info != NULL
  	  && (*bed->elf_backend_discard_info) (abfd, &cookie, info))
  	ret = TRUE;
  
!       fini_reloc_cookie (&cookie, abfd);
      }
  
    if (info->eh_frame_hdr


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