This is the mail archive of the binutils@sourceware.cygnus.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]

Re: MIPS/ELF linker



Ralf sent me another test-case in private email that pointed up a
problem in the way that we were handling relocations when there are
both REL and RELA relocations for a single section.  The bottom line
is that the attempt I took at a conservative approach (allocating too
many relocations and then ignoring some of them) is ugly; this patch
attempts to fix that problem, and seems to fix Ralf's test-case.

OK to check in?

--
Mark Mitchell                   mark@codesourcery.com
CodeSourcery, LLC               http://www.codesourcery.com

1999-08-01  Mark Mitchell  <mark@codesourcery.com>

	* elflink.h (elf_link_size_reloc_section): Use the counts in the
	elf-section data to allocate just the right amount of relocation
	space.  Don't allocate the hash space twice.
	(elf_bfd_final_link): Calculate the amount of space to allocate in
	each relocation section.

Index: elflink.h
===================================================================
RCS file: /cvs/binutils/binutils/bfd/elflink.h,v
retrieving revision 1.21
diff -c -p -r1.21 elflink.h
*** elflink.h	1999/07/30 21:34:44	1.21
--- elflink.h	1999/08/01 20:47:14
*************** elf_link_size_reloc_section (abfd, rel_h
*** 3761,3794 ****
       asection *o;
  {
    register struct elf_link_hash_entry **p, **pend;
  
!   /* We are overestimating the size required for the relocation
!      sections, in the case that we are using both REL and RELA
!      relocations for a single section.  In that case, RELOC_COUNT will
!      be the total number of relocations required, and we allocate
!      space for that many REL relocations as well as that many RELA
!      relocations.  This approximation is wasteful of disk space.
!      However, until we keep track of how many of each kind of
!      relocation is required, it's difficult to calculate the right
!      value.  */
!   rel_hdr->sh_size = rel_hdr->sh_entsize * o->reloc_count;
  
    /* The contents field must last into write_object_contents, so we
       allocate it with bfd_alloc rather than malloc.  */
    rel_hdr->contents = (PTR) bfd_alloc (abfd, rel_hdr->sh_size);
    if (rel_hdr->contents == NULL && rel_hdr->sh_size != 0)
-     return false;
- 
-   p = ((struct elf_link_hash_entry **)
-        bfd_malloc (o->reloc_count
- 		   * sizeof (struct elf_link_hash_entry *)));
-   if (p == NULL && o->reloc_count != 0)
      return false;
! 
!   elf_section_data (o)->rel_hashes = p;
!   pend = p + o->reloc_count;
!   for (; p < pend; p++)
!     *p = NULL;
  
    return true;
  }
--- 3761,3798 ----
       asection *o;
  {
    register struct elf_link_hash_entry **p, **pend;
+   unsigned reloc_count;
  
!   /* Figure out how many relocations there will be.  */
!   if (rel_hdr == &elf_section_data (o)->rel_hdr)
!     reloc_count = elf_section_data (o)->rel_count;
!   else
!     reloc_count = elf_section_data (o)->rel_count2;
! 
!   /* That allows us to calculate the size of the section.  */
!   rel_hdr->sh_size = rel_hdr->sh_entsize * reloc_count;
  
    /* The contents field must last into write_object_contents, so we
       allocate it with bfd_alloc rather than malloc.  */
    rel_hdr->contents = (PTR) bfd_alloc (abfd, rel_hdr->sh_size);
    if (rel_hdr->contents == NULL && rel_hdr->sh_size != 0)
      return false;
!   
!   /* We only allocate one set of hash entries, so we only do it the
!      first time we are called.  */
!   if (elf_section_data (o)->rel_hashes == NULL)
!     {
!       p = ((struct elf_link_hash_entry **)
! 	   bfd_malloc (o->reloc_count
! 		       * sizeof (struct elf_link_hash_entry *)));
!       if (p == NULL && o->reloc_count != 0)
! 	return false;
! 
!       elf_section_data (o)->rel_hashes = p;
!       pend = p + o->reloc_count;
!       for (; p < pend; p++)
! 	*p = NULL;
!     }
  
    return true;
  }
*************** elf_bfd_final_link (abfd, info)
*** 3997,4002 ****
--- 4001,4030 ----
    if (! _bfd_elf_compute_section_file_positions (abfd, info))
      goto error_return;
  
+   /* Figure out how many relocations we will have in each section.
+      Just using RELOC_COUNT isn't good enough since that doesn't
+      maintain a separate value for REL vs. RELA relocations.  */
+   if (info->relocateable)
+     for (sub = info->input_bfds; sub != NULL; sub = sub->link_next)
+       for (o = sub->sections; o != NULL; o = o->next)
+ 	{
+ 	  asection* output_section = o->output_section;
+ 
+ 	  if (output_section && (o->flags & SEC_RELOC) != 0)
+ 	    {
+ 	      struct bfd_elf_section_data *esdi 
+ 		= elf_section_data (o);
+ 	      struct bfd_elf_section_data *esdo 
+ 		= elf_section_data (output_section);
+ 
+ 	      esdo->rel_count += (esdi->rel_hdr.sh_size 
+ 				  / esdi->rel_hdr.sh_entsize);
+ 	      if (esdi->rel_hdr2)
+ 		esdo->rel_count2 += (esdi->rel_hdr2->sh_size 
+ 				     / esdi->rel_hdr2->sh_entsize);
+ 	    }
+ 	}
+ 
    /* That created the reloc sections.  Set their sizes, and assign
       them file positions, and allocate some buffers.  */
    for (o = abfd->sections; o != NULL; o = o->next)
*************** elf_bfd_final_link (abfd, info)
*** 4014,4019 ****
--- 4042,4052 ----
  					       o))
  	    goto error_return;
  	}
+ 
+       /* Now, reset REL_COUNT and REL_COUNT2 so that we can use them
+ 	 to count upwards while actually outputting the relocations. */
+       elf_section_data (o)->rel_count = 0;
+       elf_section_data (o)->rel_count2 = 0;
      }
  
    _bfd_elf_assign_file_positions_for_relocs (abfd);
Index: elf32-mips.c
===================================================================
RCS file: /cvs/binutils/binutils/bfd/elf32-mips.c,v
retrieving revision 1.36
diff -c -p -r1.36 elf32-mips.c
*** elf32-mips.c	1999/07/29 22:20:26	1.36
--- elf32-mips.c	1999/08/01 20:47:18
*************** mips_elf_calculate_relocation (abfd, 
*** 5870,5875 ****
--- 5870,5881 ----
  	  else
  	    symbol = h->root.root.u.def.value;
  	}
+       else if (h->root.root.type == bfd_link_hash_undefweak)
+ 	/* We allow relocations against undefined weak symbols, giving
+ 	   it the value zero, so that you can undefined weak functions
+ 	   and check to see if they exist by looking at their
+ 	   addresses.  */
+ 	symbol = 0;
        else
  	{
  	  (*info->callbacks->undefined_symbol)
*************** _bfd_mips_elf_relocate_section (output_b
*** 6637,6644 ****
  
  	case bfd_reloc_undefined:
  	  /* mips_elf_calculate_relocation already called the
!              undefined_symbol callback.  */
! 	  break;
  
  	case bfd_reloc_notsupported:
  	  abort ();
--- 6643,6652 ----
  
  	case bfd_reloc_undefined:
  	  /* mips_elf_calculate_relocation already called the
!              undefined_symbol callback.  There's no real point in
! 	     trying to perform the relocation at this point, so we
! 	     just skip ahead to the next relocation.  */
! 	  continue;
  
  	case bfd_reloc_notsupported:
  	  abort ();
*************** _bfd_mips_elf_check_relocs (abfd, info, 
*** 7331,7344 ****
  
        if (!h && (r_type == R_MIPS_CALL_LO16
  		 || r_type == R_MIPS_GOT_LO16
! 		 || r_type == R_MIPS_GOT_DISP))
  	{
  	  /* We may need a local GOT entry for this relocation.  We
! 	     don't count R_MIPS_HI16 or R_MIPS_GOT16 relocations
! 	     because they are always followed by a R_MIPS_LO16
! 	     relocation for the value.  We don't R_MIPS_GOT_PAGE
! 	     because we can estimate the maximum number of pages
! 	     needed by looking at the size of the segment.
  
  	     This estimation is very conservative since we can merge
  	     duplicate entries in the GOT.  In order to be less
--- 7339,7353 ----
  
        if (!h && (r_type == R_MIPS_CALL_LO16
  		 || r_type == R_MIPS_GOT_LO16
! 		 || r_type == R_MIPS_GOT_DISP
! 		 || r_type == R_MIPS_GOT16))
  	{
  	  /* We may need a local GOT entry for this relocation.  We
! 	     don't count R_MIPS_GOT_PAGE because we can estimate the
! 	     maximum number of pages needed by looking at the size of
! 	     the segment.  We don't count R_MIPS_GOT_HI16, or
! 	     R_MIPS_CALL_HI16 because these are always followed by an
! 	     R_MIPS_GOT_LO16 or R_MIPS_CALL_LO16.
  
  	     This estimation is very conservative since we can merge
  	     duplicate entries in the GOT.  In order to be less

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