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]

Re: Dynamic section symbols, ignored output sections


On Sat, Oct 21, 2006 at 09:41:54PM +0200, Jakub Jelinek wrote:
> On Tue, Oct 17, 2006 at 10:54:27PM +0930, Alan Modra wrote:
> > This patch does all of the above, plus adjusts the ld testsuite for
> > the changes.
> 
> Thanks a lot for this, seems to work fine here.
> 
> Only a minor nit, IMHO using the preceeding section isn't always
> the best choice.

Yes, I was lazy.

>  E.g. .init_array etc. sections usually start the
> RW segment (unless there is .tdata or .tbss) and those are often zero sized,
> yet contain __init_array_{start,end} etc. symbols.  With current CVS
> binutils those symbols are attached to the preceeding section, which
> is typically in the RX segment many KBs/MBs away, while there is
> usually a section right after the removed .init_array which is kept.
> The following patch prefers to use the next section if symbol's value
> is not within the preceeding section (or equal to its end) and if
> there is a following section that starts at vma equal to symbol value.
> Is this ok for trunk or do you prefer to always choose the preceeding
> section?

Hmm.  I prefer something different.  :-)  What we really want is to
choose a section in the same segment as the removed section would
have been if it was kept.  Also, I think it a good idea to avoid
changing a symbol from a TLS section to non-TLS and vice versa.
We can make a reasonable guess about section to segment mapping from
the section flags.

	* linker.c (fix_syms): Choose best of previous and next
	section based on section flags and vma.

Index: bfd/linker.c
===================================================================
RCS file: /cvs/src/src/bfd/linker.c,v
retrieving revision 1.55
diff -u -p -r1.55 linker.c
--- bfd/linker.c	17 Oct 2006 13:41:47 -0000	1.55
+++ bfd/linker.c	23 Oct 2006 02:32:09 -0000
@@ -3092,25 +3092,62 @@ fix_syms (struct bfd_link_hash_entry *h,
 	  && (s->output_section->flags & SEC_EXCLUDE) != 0
 	  && bfd_section_removed_from_list (obfd, s->output_section))
 	{
-	  asection *op;
-	  for (op = s->output_section->prev; op != NULL; op = op->prev)
+	  asection *op, *op1;
+
+	  h->u.def.value += s->output_offset + s->output_section->vma;
+
+	  /* Find preceding kept section.  */
+	  for (op1 = s->output_section->prev; op1 != NULL; op1 = op1->prev)
+	    if ((op1->flags & SEC_EXCLUDE) == 0
+		&& !bfd_section_removed_from_list (obfd, op1))
+	      break;
+
+	  /* Find following kept section.  Start at prev->next because
+	     other sections may have been added after S was removed.  */
+	  if (s->output_section->prev != NULL)
+	    op = s->output_section->prev->next;
+	  else
+	    op = s->output_section->owner->sections;
+	  for (; op != NULL; op = op->next)
 	    if ((op->flags & SEC_EXCLUDE) == 0
 		&& !bfd_section_removed_from_list (obfd, op))
 	      break;
-	  if (op == NULL)
+
+	  /* Choose better of two sections, based on flags.  The idea
+	     is to choose a section that will be in the same segment
+	     as S would have been if it was kept.  */
+	  if (op1 == NULL)
 	    {
-	      if (s->output_section->prev != NULL)
-		op = s->output_section->prev->next;
-	      else
-		op = s->output_section->owner->sections;
-	      for (; op != NULL; op = op->next)
-		if ((op->flags & SEC_EXCLUDE) == 0
-		    && !bfd_section_removed_from_list (obfd, op))
-		  break;
 	      if (op == NULL)
 		op = bfd_abs_section_ptr;
 	    }
-	  h->u.def.value += s->output_offset + s->output_section->vma;
+	  else if (op == NULL)
+	    op = op1;
+	  else if (((op1->flags ^ op->flags)
+		    & (SEC_ALLOC | SEC_THREAD_LOCAL)) != 0)
+	    {
+	      if (((op->flags ^ s->flags)
+		   & (SEC_ALLOC | SEC_THREAD_LOCAL)) != 0)
+		op = op1;
+	    }
+	  else if (((op1->flags ^ op->flags) & SEC_READONLY) != 0)
+	    {
+	      if (((op->flags ^ s->flags) & SEC_READONLY) != 0)
+		op = op1;
+	    }
+	  else if (((op1->flags ^ op->flags) & SEC_CODE) != 0)
+	    {
+	      if (((op->flags ^ s->flags) & SEC_CODE) != 0)
+		op = op1;
+	    }
+	  else
+	    {
+	      /* Flags we care about are the same.  Prefer the following
+		 section if that will result in a positive valued sym.  */
+	      if (h->u.def.value < op->vma)
+		op = op1;
+	    }
+
 	  h->u.def.value -= op->vma;
 	  h->u.def.section = op;
 	}

-- 
Alan Modra
IBM OzLabs - Linux Technology Centre


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