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]

MIPS patch for relocateable output



This patch contains some additional tweaks to elflink.h to deal with
multiple relocation sections.  It also restores the ld -r behavior in
the MIPS back-end present before my recent changes.  (Except that that
support was somewhat broken, I think; it apparently assigned GP a
non-zero value for a relocateable object.)

With this patch, there are no unexpeted failures on IRIX6.
Furthermore, with Ian's help, I believe that there are no (known)
issues in the MIPS back-end, relative to when I started my work.  My
inspection did not real any further missing functionality, although I 
may still have missed something.

OK to check in?

Sat Jul 17 02:28:28 1999  Mark P. Mitchell  <mark@codesourcery.com>

	* elflink.h (elf_link_adjust_relocs): New function.
	(elf_bfd_final_link): Use it.
	(elf_link_input_bfd): Deal with the fact that there can be 
	two relocation sections for a single section.
	(elf_reloc_link_order): Likewise.

	* elf32-mips.c (_bfd_mips_elf_final_link): Don't set GP for 
	a relocateable object.
	(_bfd_mips_elf_relocate_section): Handle relocateable links.

Index: elflink.h
===================================================================
RCS file: /cvs/binutils/binutils/bfd/elflink.h,v
retrieving revision 1.17
diff -c -p -r1.17 elflink.h
*** elflink.h	1999/07/16 08:10:27	1.17
--- elflink.h	1999/07/17 08:34:45
*************** static void elf_link_output_relocs
*** 56,61 ****
--- 56,64 ----
    PARAMS ((bfd *, asection *, Elf_Internal_Shdr *, Elf_Internal_Rela *));
  static boolean elf_link_size_reloc_section
    PARAMS ((bfd *, Elf_Internal_Shdr *, asection *));
+ static void elf_link_adjust_relocs 
+   PARAMS ((bfd *, Elf_Internal_Shdr *, unsigned int, 
+ 	   struct elf_link_hash_entry **));
  
  /* Given an ELF BFD, add symbols to the global hash table as
     appropriate.  */
*************** elf_link_size_reloc_section (abfd, rel_h
*** 3782,3787 ****
--- 3785,3839 ----
    return true;
  }
  
+ /* When performing a relocateable link, the input relocations are
+    preserved.  But, if they reference global symbols, the indices
+    referenced must be updated.  Update all the relocations in
+    REL_HDR (there are COUNT of them), using the data in REL_HASH.  */
+ 
+ static void
+ elf_link_adjust_relocs (abfd, rel_hdr, count, rel_hash)
+      bfd *abfd;
+      Elf_Internal_Shdr *rel_hdr;
+      unsigned int count;
+      struct elf_link_hash_entry **rel_hash;
+ {
+   unsigned int i;
+ 
+   for (i = 0; i < count; i++, rel_hash++)
+     {
+       if (*rel_hash == NULL)
+ 	continue;
+ 
+       BFD_ASSERT ((*rel_hash)->indx >= 0);
+ 
+       if (rel_hdr->sh_entsize == sizeof (Elf_External_Rel))
+ 	{
+ 	  Elf_External_Rel *erel;
+ 	  Elf_Internal_Rel irel;
+ 	  
+ 	  erel = (Elf_External_Rel *) rel_hdr->contents + i;
+ 	  elf_swap_reloc_in (abfd, erel, &irel);
+ 	  irel.r_info = ELF_R_INFO ((*rel_hash)->indx,
+ 				    ELF_R_TYPE (irel.r_info));
+ 	  elf_swap_reloc_out (abfd, &irel, erel);
+ 	}
+       else
+ 	{
+ 	  Elf_External_Rela *erela;
+ 	  Elf_Internal_Rela irela;
+ 	  
+ 	  BFD_ASSERT (rel_hdr->sh_entsize
+ 		      == sizeof (Elf_External_Rela));
+ 	  
+ 	  erela = (Elf_External_Rela *) rel_hdr->contents + i;
+ 	  elf_swap_reloca_in (abfd, erela, &irela);
+ 	  irela.r_info = ELF_R_INFO ((*rel_hash)->indx,
+ 				     ELF_R_TYPE (irela.r_info));
+ 	  elf_swap_reloca_out (abfd, &irela, erela);
+ 	}
+     }
+ }
+ 
  /* Do the final step of an ELF link.  */
  
  boolean
*************** elf_bfd_final_link (abfd, info)
*** 4267,4309 ****
  
        if ((o->flags & SEC_RELOC) == 0)
  	continue;
- 
-       rel_hash = elf_section_data (o)->rel_hashes;
-       rel_hdr = &elf_section_data (o)->rel_hdr;
-       BFD_ASSERT (elf_section_data (o)->rel_count == o->reloc_count);
-       for (i = 0; i < o->reloc_count; i++, rel_hash++)
- 	{
- 	  if (*rel_hash == NULL)
- 	    continue;
- 
- 	  BFD_ASSERT ((*rel_hash)->indx >= 0);
- 
- 	  if (rel_hdr->sh_entsize == sizeof (Elf_External_Rel))
- 	    {
- 	      Elf_External_Rel *erel;
- 	      Elf_Internal_Rel irel;
- 
- 	      erel = (Elf_External_Rel *) rel_hdr->contents + i;
- 	      elf_swap_reloc_in (abfd, erel, &irel);
- 	      irel.r_info = ELF_R_INFO ((*rel_hash)->indx,
- 					ELF_R_TYPE (irel.r_info));
- 	      elf_swap_reloc_out (abfd, &irel, erel);
- 	    }
- 	  else
- 	    {
- 	      Elf_External_Rela *erela;
- 	      Elf_Internal_Rela irela;
- 
- 	      BFD_ASSERT (rel_hdr->sh_entsize
- 			  == sizeof (Elf_External_Rela));
  
! 	      erela = (Elf_External_Rela *) rel_hdr->contents + i;
! 	      elf_swap_reloca_in (abfd, erela, &irela);
! 	      irela.r_info = ELF_R_INFO ((*rel_hash)->indx,
! 					 ELF_R_TYPE (irela.r_info));
! 	      elf_swap_reloca_out (abfd, &irela, erela);
! 	    }
! 	}
  
        /* Set the reloc_count field to 0 to prevent write_relocs from
  	 trying to swap the relocs out itself.  */
--- 4319,4333 ----
  
        if ((o->flags & SEC_RELOC) == 0)
  	continue;
  
!       elf_link_adjust_relocs (abfd, &elf_section_data (o)->rel_hdr, 
! 			      elf_section_data (o)->rel_count,
! 			      elf_section_data (o)->rel_hashes);
!       if (elf_section_data (o)->rel_hdr2 != NULL)
! 	elf_link_adjust_relocs (abfd, elf_section_data (o)->rel_hdr2,
! 				elf_section_data (o)->rel_count2,
! 				(elf_section_data (o)->rel_hashes 
! 				 + elf_section_data (o)->rel_count));
  
        /* Set the reloc_count field to 0 to prevent write_relocs from
  	 trying to swap the relocs out itself.  */
*************** elf_link_input_bfd (finfo, input_bfd)
*** 5224,5230 ****
  	      irelaend = 
  		irela + o->reloc_count * bed->s->int_rels_per_ext_rel;
  	      rel_hash = (elf_section_data (o->output_section)->rel_hashes
! 			  + elf_section_data (o->output_section)->rel_count);
  	      for (; irela < irelaend; irela++, rel_hash++)
  		{
  		  unsigned long r_symndx;
--- 5248,5255 ----
  	      irelaend = 
  		irela + o->reloc_count * bed->s->int_rels_per_ext_rel;
  	      rel_hash = (elf_section_data (o->output_section)->rel_hashes
! 			  + elf_section_data (o->output_section)->rel_count
! 			  + elf_section_data (o->output_section)->rel_count2);
  	      for (; irela < irelaend; irela++, rel_hash++)
  		{
  		  unsigned long r_symndx;
*************** elf_reloc_link_order (output_bfd, info, 
*** 5414,5420 ****
  
    /* Figure out the symbol index.  */
    rel_hash_ptr = (elf_section_data (output_section)->rel_hashes
! 		  + elf_section_data (output_section)->rel_count);
    if (link_order->type == bfd_section_reloc_link_order)
      {
        indx = link_order->u.reloc.p->u.section->target_index;
--- 5439,5446 ----
  
    /* Figure out the symbol index.  */
    rel_hash_ptr = (elf_section_data (output_section)->rel_hashes
! 		  + elf_section_data (output_section)->rel_count
! 		  + elf_section_data (output_section)->rel_count2);
    if (link_order->type == bfd_section_reloc_link_order)
      {
        indx = link_order->u.reloc.p->u.section->target_index;
Index: elf32-mips.c
===================================================================
RCS file: /cvs/binutils/binutils/bfd/elf32-mips.c,v
retrieving revision 1.29
diff -c -p -r1.29 elf32-mips.c
*** elf32-mips.c	1999/07/16 19:09:22	1.29
--- elf32-mips.c	1999/07/17 08:34:46
*************** _bfd_mips_elf_final_link (abfd, info)
*** 4388,4407 ****
  	elf_gp (abfd) = (h->u.def.value
  			 + h->u.def.section->output_section->vma
  			 + h->u.def.section->output_offset);
-       else if (info->relocateable)
- 	{
- 	  bfd_vma lo;
- 
- 	  /* Find the GP-relative section with the lowest offset.  */
- 	  lo = (bfd_vma) -1;
- 	  for (o = abfd->sections; o != (asection *) NULL; o = o->next)
- 	    if (o->vma < lo 
- 		&& (elf_section_data (o)->this_hdr.sh_flags & SHF_MIPS_GPREL))
- 	      lo = o->vma;
- 
- 	  /* And calculate GP relative to that.  */
- 	  elf_gp (abfd) = lo + ELF_MIPS_GP_OFFSET (abfd);
- 	}
        else
  	{
  	  /* If the relocate_section function needs to do a reloc
--- 4388,4393 ----
*************** _bfd_mips_elf_relocate_section (output_b
*** 6429,6435 ****
       Elf_Internal_Sym *local_syms;
       asection **local_sections;
  {
!   const Elf_Internal_Rela *rel;
    const Elf_Internal_Rela *relend;
    bfd_vma addend;
    bfd_vma last_hi16_addend;
--- 6415,6421 ----
       Elf_Internal_Sym *local_syms;
       asection **local_sections;
  {
!   Elf_Internal_Rela *rel;
    const Elf_Internal_Rela *relend;
    bfd_vma addend;
    bfd_vma last_hi16_addend;
*************** _bfd_mips_elf_relocate_section (output_b
*** 6445,6454 ****
        bfd_vma value;
        reloc_howto_type *howto;
        boolean require_jalx;
  
        /* Find the relocation howto for this relocation.  */
!       if (ELF32_R_TYPE (rel->r_info) == R_MIPS_64
! 	  && !ABI_64_P (output_bfd))
  	/* Some 32-bit code uses R_MIPS_64.  In particular, people use
  	   64-bit code, but make sure all their addresses are in the 
  	   lowermost or uppermost 32-bit section of the 64-bit address
--- 6431,6443 ----
        bfd_vma value;
        reloc_howto_type *howto;
        boolean require_jalx;
+       /* True if the relocation is a RELA relocation, rather than a
+          REL relocation.  */
+       boolean rela_relocation_p = true;
+       int r_type = ELF32_R_TYPE (rel->r_info);
  
        /* Find the relocation howto for this relocation.  */
!       if (r_type == R_MIPS_64 && !ABI_64_P (output_bfd))
  	/* Some 32-bit code uses R_MIPS_64.  In particular, people use
  	   64-bit code, but make sure all their addresses are in the 
  	   lowermost or uppermost 32-bit section of the 64-bit address
*************** _bfd_mips_elf_relocate_section (output_b
*** 6457,6463 ****
  	   stored value is sign-extended to 64 bits.  */
  	howto = elf_mips_howto_table + R_MIPS_32;
        else
! 	howto = elf_mips_howto_table + ELF32_R_TYPE (rel->r_info);
  
        if (!use_saved_addend_p)
  	{
--- 6446,6452 ----
  	   stored value is sign-extended to 64 bits.  */
  	howto = elf_mips_howto_table + R_MIPS_32;
        else
! 	howto = elf_mips_howto_table + r_type;
  
        if (!use_saved_addend_p)
  	{
*************** _bfd_mips_elf_relocate_section (output_b
*** 6476,6483 ****
  	    rel_hdr = elf_section_data (input_section)->rel_hdr2;
  	  if (rel_hdr->sh_entsize == MIPS_ELF_REL_SIZE (input_bfd))
  	    {
! 	      int r_type = ELF32_R_TYPE (rel->r_info);
  
  	      addend = mips_elf_obtain_contents (howto, 
  						 rel,
  						 input_bfd,
--- 6465,6474 ----
  	    rel_hdr = elf_section_data (input_section)->rel_hdr2;
  	  if (rel_hdr->sh_entsize == MIPS_ELF_REL_SIZE (input_bfd))
  	    {
! 	      /* Note that this is a REL relocation.  */
! 	      rela_relocation_p = false;
  
+ 	      /* Get the addend, which is stored in the input file.  */
  	      addend = mips_elf_obtain_contents (howto, 
  						 rel,
  						 input_bfd,
*************** _bfd_mips_elf_relocate_section (output_b
*** 6533,6545 ****
  	    addend = rel->r_addend;
  	}
  
        /* In the N32 and 64-bit ABIs there may be multiple consecutive
  	 relocations for the same offset.  In that case we are
  	 supposed to treat the output of each relocation as the addend
  	 for the next.  */
        if (rel + 1 < relend 
  	  && rel->r_offset == rel[1].r_offset
! 	  && ELF32_R_TYPE (rel[1].r_info) != R_MIPS_NONE)
  	use_saved_addend_p = true;
        else
  	use_saved_addend_p = false;
--- 6524,6586 ----
  	    addend = rel->r_addend;
  	}
  
+       if (info->relocateable)
+ 	{
+ 	  Elf_Internal_Sym *sym;
+ 	  unsigned long r_symndx;
+ 
+ 	  /* Since we're just relocating, all we need to do is copy
+ 	     the relocations back out to the object file, unless they're 
+ 	     against a section symbol, in which case we need to adjust 
+ 	     by the section offset.  */
+ 
+ 	  if (!mips_elf_local_relocation_p (input_bfd, rel, local_sections))
+ 	    /* A non-local relocation is never against a section.  */
+ 	    continue;
+ 
+ 	  r_symndx = ELF32_R_SYM (rel->r_info);
+ 	  sym = local_syms + r_symndx;
+ 	  if (ELF_ST_TYPE (sym->st_info) != STT_SECTION)
+ 	    continue;
+ 
+ 	  /* Adjust the addend appropriately.  */
+ 	  addend += local_sections[r_symndx]->output_offset;
+ 
+ 	  /* If the relocation is for a R_MIPS_HI16 or R_MIPS_GOT16,
+ 	     then we only want to write out the high-order 16 bits.
+ 	     The subsequent R_MIPS_LO16 will handle the low-order bits.  */
+ 	  if (r_type == R_MIPS_HI16 || r_type == R_MIPS_GOT16)
+ 	    addend >>= 16;
+ 
+ 	  if (rela_relocation_p)
+ 	    /* If this is a RELA relocation, just update the addend.
+                We have to cast away constness for REL.  */
+ 	    rel->r_addend = addend;
+ 	  else
+ 	    {
+ 	      /* Otherwise, we have to write the value back out.  Note
+ 		 that we use the source mask, rather than the
+ 		 destination mask because the place to which we are
+ 		 writing will be source of the addend in the final
+ 		 link.  */
+ 	      addend &= howto->src_mask;
+ 	      if (!mips_elf_perform_relocation (info, howto, rel, addend,
+ 						input_bfd,  input_section, 
+ 						contents, false))
+ 		return false;
+ 	    }
+ 
+ 	  /* Go on to the next relocation.  */
+ 	  continue;
+ 	}
+ 
        /* In the N32 and 64-bit ABIs there may be multiple consecutive
  	 relocations for the same offset.  In that case we are
  	 supposed to treat the output of each relocation as the addend
  	 for the next.  */
        if (rel + 1 < relend 
  	  && rel->r_offset == rel[1].r_offset
! 	  && r_type != R_MIPS_NONE)
  	use_saved_addend_p = true;
        else
  	use_saved_addend_p = false;
*************** _bfd_mips_elf_relocate_section (output_b
*** 6602,6609 ****
  	  continue;
  	}
  
!       if (ELF32_R_TYPE (rel->r_info) == R_MIPS_64
! 	  && !ABI_64_P (output_bfd))
  	/* See the comment above about using R_MIPS_64 in the 32-bit
  	   ABI.  Until now, we've been using the HOWTO for R_MIPS_32;
  	   that calculated the right value.  Now, however, we
--- 6643,6649 ----
  	  continue;
  	}
  
!       if (r_type == R_MIPS_64 && !ABI_64_P (output_bfd))
  	/* See the comment above about using R_MIPS_64 in the 32-bit
  	   ABI.  Until now, we've been using the HOWTO for R_MIPS_32;
  	   that calculated the right value.  Now, however, we


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