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]

wrong bss/sbss section choosen when multiple commons merged


I've gotten this bug report from both Intel and SGI.  They are both trying
to compile large Fortran programs using GNU ld on an ia64-linux system.

If I have in the first file:
	.common foo, 4, 4
and in the second file
	.common foo, 400000, 4
then ld puts foo in sbss instead of bss.  This can cause short data section
overflow.  If I switch the order of the files, then foo ends up in bss where
I expect.

This seems to be a generic ld problem.  I can reproduce the same problem
with a mips-elf ld.

The problem seems to be in bfd_generic_link_add_one_symbol, case BIG, which
handles merging of two common symbols.  It knows that it needs to take the
size of the larger one, but it doesn't do anything about the section.  It
just takes the section allocated to the first symbol.  This is wrong for
targets where different sized common symbols are put in different sections.

I tried adding code to use the section of the larger symbol.  I copied the
code that is used in the COM case to set the section.  This seems to work
OK for my testcase.  I haven't tried to extensively test this patch yet.

I looking for comments as to whether this seems to be the right fix.
If using the section of the larger symbol isn't portable, then I could add
a new hook for this.  I'm not sure if the (section != h->u.c.p->section)
check makes sense at this point.

2001-04-18  Jim Wilson  <wilson@redhat.com>

	* linker.c (_bfd_generic_link_add_one_symbol, case BIG): Use
	the section of the larger symbol.

Index: linker.c
===================================================================
RCS file: /cvs/src/src/bfd/linker.c,v
retrieving revision 1.6
diff -p -r1.6 linker.c
*** linker.c	2001/01/03 19:26:07	1.6
--- linker.c	2001/04/19 01:18:41
*************** _bfd_generic_link_add_one_symbol (info, 
*** 1698,1704 ****
  	case BIG:
  	  /* We have found a common definition for a symbol which
  	     already had a common definition.  Use the maximum of the
! 	     two sizes.  */
  	  BFD_ASSERT (h->type == bfd_link_hash_common);
  	  if (! ((*info->callbacks->multiple_common)
  		 (info, h->root.string,
--- 1698,1704 ----
  	case BIG:
  	  /* We have found a common definition for a symbol which
  	     already had a common definition.  Use the maximum of the
! 	     two sizes.  Use the section from the larger symbol.  */
  	  BFD_ASSERT (h->type == bfd_link_hash_common);
  	  if (! ((*info->callbacks->multiple_common)
  		 (info, h->root.string,
*************** _bfd_generic_link_add_one_symbol (info, 
*** 1717,1722 ****
--- 1717,1744 ----
  	      if (power > 4)
  		power = 4;
  	      h->u.c.p->alignment_power = power;
+ 
+ 	      /* Some systems have special treatment for small commons,
+ 		 hence we want to select the section used by the larger
+ 		 symbol.  This make sure the symbol does not go in a
+ 		 small common section if it is now too large.  */
+ 	      if (section != h->u.c.p->section)
+ 		{
+ 		  if (section == bfd_com_section_ptr)
+ 		    {
+ 		      h->u.c.p->section
+ 			= bfd_make_section_old_way (abfd, "COMMON");
+ 		      h->u.c.p->section->flags = SEC_ALLOC;
+ 		    }
+ 		  else if (section->owner != abfd)
+ 		    {
+ 		      h->u.c.p->section
+ 			= bfd_make_section_old_way (abfd, section->name);
+ 		      h->u.c.p->section->flags = SEC_ALLOC;
+ 		    }
+ 		  else
+ 		    h->u.c.p->section = section;
+ 		}
  	    }
  	  break;
  


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