This is the mail archive of the binutils@sources.redhat.com 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]

Re: PATCH: Fix removed sections (Re: 2.12.90.0.12 Kernel Miscompile)


On Thu, Jul 04, 2002 at 12:28:48PM +0930, Alan Modra wrote:
>   /* It would be nice to strip .branch_lt from the output if the
>      section is empty, but it's too late.  If we strip sections here,
>      the dynamic symbol table is corrupted since the section symbol
>      for the stripped section isn't written.  */
> 
> bfd/ChangeLog
> 	* section.c (_bfd_strip_section_from_output): Remove unnecessary
> 	link order code.  Don't actually remove the output section here;
> 	Just set a flag for the linker to do so.

Ironic that I should have a comment about dynamic symbol table
corruption here, when that's exactly what the above patch does.
_bfd_elf_link_renumber_dynsyms trundles over the output bfd sections,
so not actually removing them until later means we calculate the wrong
number of dynsyms.  I still like the idea of delaying the actual
stripping though, so..

bfd/ChangeLog
	* section.c (_bfd_strip_section_from_output):  Remove unnecessary
	link order code.  Don't actually remove the output section here;
	Just set a flag for the linker to do so.
	* elflink.c (_bfd_elf_link_renumber_dynsyms): Test for removed
	sections when setting up output section dynsyms.

ld/ChangeLog
	* ldlang.c (strip_excluded_output_sections): New function.
	(lang_process): Call it.
	(lang_size_sections_1): Revert 2002-06-10 change.

Oh, and the section.c patch is changed a little as I don't see the
point in allowing _bfd_strip_section_from_output to accept NULL info.

-- 
Alan Modra
IBM OzLabs - Linux Technology Centre

Index: bfd/elflink.c
===================================================================
RCS file: /cvs/src/src/bfd/elflink.c,v
retrieving revision 1.25
diff -u -p -r1.25 elflink.c
--- bfd/elflink.c	25 Jun 2002 09:40:43 -0000	1.25
+++ bfd/elflink.c	4 Jul 2002 14:21:54 -0000
@@ -357,7 +357,8 @@ _bfd_elf_link_renumber_dynsyms (output_b
     {
       asection *p;
       for (p = output_bfd->sections; p ; p = p->next)
-	elf_section_data (p)->dynindx = ++dynsymcount;
+	if ((p->flags & SEC_EXCLUDE) == 0)
+	  elf_section_data (p)->dynindx = ++dynsymcount;
     }
 
   if (elf_hash_table (info)->dynlocal)
Index: bfd/section.c
===================================================================
RCS file: /cvs/src/src/bfd/section.c,v
retrieving revision 1.49
diff -c -p -r1.49 section.c
*** bfd/section.c	25 Jun 2002 09:40:44 -0000	1.49
--- bfd/section.c	4 Jul 2002 14:22:50 -0000
*************** SYNOPSIS
*** 1301,1380 ****
  
  DESCRIPTION
  	Remove @var{section} from the output.  If the output section
! 	becomes empty, remove it from the output bfd.  @var{info} may
! 	be NULL; if it is not, it is used to decide whether the output
! 	section is empty.
  */
  void
  _bfd_strip_section_from_output (info, s)
       struct bfd_link_info *info;
       asection *s;
  {
!   asection **spp, *os;
!   struct bfd_link_order *p, *pp;
!   boolean keep_os;
  
!   /* Excise the input section from the link order.
  
!      FIXME: For all calls that I can see to this function, the link
!      orders have not yet been set up.  So why are we checking them? --
!      Ian */
    os = s->output_section;
! 
!   /* Handle a section that wasn't output.  */
!   if (os == NULL)
      return;
  
!   for (p = os->link_order_head, pp = NULL; p != NULL; pp = p, p = p->next)
!     if (p->type == bfd_indirect_link_order
! 	&& p->u.indirect.section == s)
!       {
! 	if (pp)
! 	  pp->next = p->next;
! 	else
! 	  os->link_order_head = p->next;
! 	if (!p->next)
! 	  os->link_order_tail = pp;
! 	break;
!       }
! 
!   keep_os = os->link_order_head != NULL;
! 
!   if (! keep_os && info != NULL)
!     {
!       bfd *abfd;
!       for (abfd = info->input_bfds; abfd != NULL; abfd = abfd->link_next)
! 	{
! 	  asection *is;
! 	  for (is = abfd->sections; is != NULL; is = is->next)
! 	    {
! 	      if (is != s && is->output_section == os
! 		  && (is->flags & SEC_EXCLUDE) == 0)
! 		break;
! 	    }
! 	  if (is != NULL)
! 	    break;
! 	}
!       if (abfd != NULL)
! 	keep_os = true;
!     }
! 
!   /* If the output section is empty, remove it too.  Careful about sections
!      that have been discarded in the link script -- they are mapped to
!      bfd_abs_section, which has no owner.  */
!   if (!keep_os && os->owner != NULL)
!     {
!       for (spp = &os->owner->sections; *spp; spp = &(*spp)->next)
! 	if (*spp == os)
! 	  {
! 	    bfd_section_list_remove (os->owner, spp);
! 	    os->flags |= SEC_EXCLUDE;
! 	    os->owner->section_count--;
! 	    break;
! 	  }
!     }
! 
!   s->flags |= SEC_EXCLUDE;
  }
  
  /*
--- 1301,1340 ----
  
  DESCRIPTION
  	Remove @var{section} from the output.  If the output section
! 	becomes empty, remove it from the output bfd.
! 
! 	This function won't actually do anything except twiddle flags
! 	if called too late in the linking process, when it's not safe
! 	to remove sections.
  */
  void
  _bfd_strip_section_from_output (info, s)
       struct bfd_link_info *info;
       asection *s;
  {
!   asection *os;
!   asection *is;
!   bfd *abfd;
  
!   s->flags |= SEC_EXCLUDE;
  
!   /* If the section wasn't assigned to an output section, or the
!      section has been discarded by the linker script, there's nothing
!      more to do.  */
    os = s->output_section;
!   if (os == NULL || os->owner == NULL)
      return;
  
!   /* If the output section has other (non-excluded) input sections, we
!      can't remove it.  */
!   for (abfd = info->input_bfds; abfd != NULL; abfd = abfd->link_next)
!     for (is = abfd->sections; is != NULL; is = is->next)
!       if (is->output_section == os && (is->flags & SEC_EXCLUDE) == 0)
! 	return;
! 
!   /* If the output section is empty, flag it for removal too.
!      See ldlang.c:strip_excluded_output_sections for the action.  */
!   os->flags |= SEC_EXCLUDE;
  }
  
  /*
Index: ld/ldlang.c
===================================================================
RCS file: /cvs/src/src/ld/ldlang.c,v
retrieving revision 1.91
diff -u -p -r1.91 ldlang.c
--- ld/ldlang.c	1 Jul 2002 08:07:29 -0000	1.91
+++ ld/ldlang.c	4 Jul 2002 02:44:23 -0000
@@ -97,6 +97,7 @@ static void lang_place_undefineds PARAMS
 static void map_input_to_output_sections
   PARAMS ((lang_statement_union_type *, const char *,
 	   lang_output_section_statement_type *));
+static void strip_excluded_output_sections PARAMS ((void));
 static void print_output_section_statement
   PARAMS ((lang_output_section_statement_type *));
 static void print_assignment
@@ -2161,6 +2162,41 @@ map_input_to_output_sections (s, target,
     }
 }
 
+/* An output section might have been removed after its statement was
+   added.  For example, ldemul_before_allocation can remove dynamic
+   sections if they turn out to be not needed.  Clean them up here.  */
+
+static void
+strip_excluded_output_sections ()
+{
+  lang_statement_union_type *u;
+
+  for (u = lang_output_section_statement.head;
+       u != NULL;
+       u = u->output_section_statement.next)
+    {
+      lang_output_section_statement_type *os;
+      asection *s;
+
+      os = &u->output_section_statement;
+      s = os->bfd_section;
+      if (s != NULL && (s->flags & SEC_EXCLUDE) != 0)
+	{
+	  asection **p;
+
+	  os->bfd_section = NULL;
+
+	  for (p = &output_bfd->sections; *p; p = &(*p)->next)
+	    if (*p == s)
+	      {
+		bfd_section_list_remove (output_bfd, p);
+		output_bfd->section_count--;
+		break;
+	      }
+	}
+    }
+}
+
 static void
 print_output_section_statement (output_section_statement)
      lang_output_section_statement_type *output_section_statement;
@@ -2903,14 +2939,6 @@ lang_size_sections_1 (s, output_section_
 	      /* This section was never actually created.  */
 	      break;
 
-	    /* The section might have been removed after its statement was
-	       added.  For example, ldemul_before_allocation can remove
-	       dynamic sections if they turn out not to be needed.  */
-	    if (!link_info.relocateable
-		&& (bfd_get_section_flags (output_bfd, os->bfd_section)
-		    & SEC_EXCLUDE) != 0)
-	      break;
-
 	    /* If this is a COFF shared library section, use the size and
 	       address from the input section.  FIXME: This is COFF
 	       specific; it would be cleaner if there were some other way
@@ -4251,6 +4279,9 @@ lang_process ()
   /* Do anything special before sizing sections.  This is where ELF
      and other back-ends size dynamic sections.  */
   ldemul_before_allocation ();
+
+  if (!link_info.relocateable)
+    strip_excluded_output_sections ();
 
   /* We must record the program headers before we try to fix the
      section positions, since they will affect SIZEOF_HEADERS.  */


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