linux-mips-fnet
[Top] [All Lists]

Re: MIPS/ELF linker

To: ralf@uni-koblenz.de
Subject: Re: MIPS/ELF linker
From: Mark Mitchell <mark@codesourcery.com>
Date: Sun, 01 Aug 1999 14:05:59 -0700
Cc: ralf@gnu.org, binutils@sourceware.cygnus.com, thockin@cobaltnet.com, linux@engr.sgi.com, linux-mips@fnet.fr, linux-mips@vger.rutgers.edu
In-reply-to: <19990801012203.U12249@uni-koblenz.de>
Organization: CodeSourcery, LLC
References: <19990731233150.Q12249@uni-koblenz.de> <19990731152842N.mitchell@codesourcery.com> <19990801012203.U12249@uni-koblenz.de>
Sender: mitchell@codesourcery.com
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

<Prev in Thread] Current Thread [Next in Thread>