This is the mail archive of the
binutils@sourceware.cygnus.com
mailing list for the binutils project.
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