This is the mail archive of the binutils@sourceware.org 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]
Other format: [Raw text]

[PATCH] Handle mixing mips16/mips32 functions in BFD


Hello All,

this patch add support for mixing mips16 and mips32 code in the
same source file.

I lacks some assembler-based testcase :-)
Otherwise ok?


Thiemo


2006-07-25  Thiemo Seufer  <ths@mips.com>
            David Ung  <davidu@mips.com>

	* elf-bfd.h (local_call_stubs): New member.
	* elfxx-mips.c (mips_elf_calculate_relocation): Handle local
	mips16 call stubs.
	(_bfd_mips_elf_check_relocs): Handle call stubs for code which
	mixes mips16 and mips32 functions.


Index: bfd/elf-bfd.h
===================================================================
RCS file: /cvs/src/src/bfd/elf-bfd.h,v
retrieving revision 1.211
diff -u -p -r1.211 elf-bfd.h
--- bfd/elf-bfd.h	10 Jul 2006 21:40:22 -0000	1.211
+++ bfd/elf-bfd.h	24 Jul 2006 11:21:00 -0000
@@ -1339,6 +1339,7 @@ struct elf_obj_tdata
      MIPS ELF linker.  FIXME: We should figure out some way to only
      include this field for a MIPS ELF target.  */
   asection **local_stubs;
+  asection **local_call_stubs;
 
   /* Used to determine if PT_GNU_EH_FRAME segment header should be
      created.  */
Index: bfd/elfxx-mips.c
===================================================================
RCS file: /cvs/src/src/bfd/elfxx-mips.c,v
retrieving revision 1.175
diff -u -p -r1.175 elfxx-mips.c
--- bfd/elfxx-mips.c	18 Jul 2006 08:56:44 -0000	1.175
+++ bfd/elfxx-mips.c	24 Jul 2006 11:21:01 -0000
@@ -4082,33 +4085,41 @@ mips_elf_calculate_relocation (bfd *abfd
      need to redirect the call to the stub.  */
   else if (r_type == R_MIPS16_26 && !info->relocatable
 	   && h != NULL
-	   && (h->call_stub != NULL || h->call_fp_stub != NULL)
+	   && ((h->call_stub != NULL || h->call_fp_stub != NULL)
+	       || (local_p
+		   && elf_tdata (input_bfd)->local_call_stubs != NULL
+		   && elf_tdata (input_bfd)->local_call_stubs[r_symndx] != NULL))
 	   && !target_is_16_bit_code_p)
     {
-      /* If both call_stub and call_fp_stub are defined, we can figure
-	 out which one to use by seeing which one appears in the input
-	 file.  */
-      if (h->call_stub != NULL && h->call_fp_stub != NULL)
+      if (local_p)
+	sec = elf_tdata (input_bfd)->local_call_stubs[r_symndx];
+      else
 	{
-	  asection *o;
-
-	  sec = NULL;
-	  for (o = input_bfd->sections; o != NULL; o = o->next)
-	    {
-	      if (strncmp (bfd_get_section_name (input_bfd, o),
-			   CALL_FP_STUB, sizeof CALL_FP_STUB - 1) == 0)
+	  /* If both call_stub and call_fp_stub are defined, we can figure
+	     out which one to use by checking which one appears in the input
+	     file.  */
+	  if (h->call_stub != NULL && h->call_fp_stub != NULL)
+	    {
+	      asection *o;
+	      
+	      sec = NULL;
+	      for (o = input_bfd->sections; o != NULL; o = o->next)
 		{
-		  sec = h->call_fp_stub;
-		  break;
+		  if (strncmp (bfd_get_section_name (input_bfd, o),
+			       CALL_FP_STUB, sizeof CALL_FP_STUB - 1) == 0)
+		    {
+		      sec = h->call_fp_stub;
+		      break;
+		    }
 		}
+	      if (sec == NULL)
+		sec = h->call_stub;
 	    }
-	  if (sec == NULL)
+	  else if (h->call_stub != NULL)
 	    sec = h->call_stub;
+	  else
+	    sec = h->call_fp_stub;
 	}
-      else if (h->call_stub != NULL)
-	sec = h->call_stub;
-      else
-	sec = h->call_fp_stub;
 
       BFD_ASSERT (sec->size > 0);
       symbol = sec->output_section->vma + sec->output_offset;
@@ -6233,42 +6244,112 @@ _bfd_mips_elf_check_relocs (bfd *abfd, s
       if (r_symndx < extsymoff
 	  || sym_hashes[r_symndx - extsymoff] == NULL)
 	{
-	  /* This stub was actually built for a static symbol defined
-	     in the same file.  We assume that all static symbols in
-	     mips16 code are themselves mips16, so we can simply
-	     discard this stub.  Since this function is called before
-	     the linker maps input sections to output sections, we can
-	     easily discard it by setting the SEC_EXCLUDE flag.  */
-	  sec->flags |= SEC_EXCLUDE;
-	  return TRUE;
-	}
+	  asection *o;
 
-      h = ((struct mips_elf_link_hash_entry *)
-	   sym_hashes[r_symndx - extsymoff]);
+	  /* This stub is for a local symbol.  This stub will only be
+             needed if there is some relocation (R_MIPS16_26) in this BFD
+             that refers to this symbol.  */
+	  for (o = abfd->sections; o != NULL; o = o->next)
+	    {
+	      Elf_Internal_Rela *sec_relocs;
+	      const Elf_Internal_Rela *r, *rend;
+
+	      /* We can ignore stub sections when looking for relocs.  */
+	      if ((o->flags & SEC_RELOC) == 0
+		  || o->reloc_count == 0
+		  || strncmp (bfd_get_section_name (abfd, o), FN_STUB,
+			      sizeof FN_STUB - 1) == 0
+		  || strncmp (bfd_get_section_name (abfd, o), CALL_STUB,
+			      sizeof CALL_STUB - 1) == 0
+		  || strncmp (bfd_get_section_name (abfd, o), CALL_FP_STUB,
+			      sizeof CALL_FP_STUB - 1) == 0)
+		continue;
 
-      /* H is the symbol this stub is for.  */
+	      sec_relocs
+		= _bfd_elf_link_read_relocs (abfd, o, NULL, NULL,
+					     info->keep_memory);
+	      if (sec_relocs == NULL)
+		return FALSE;
 
-      if (strncmp (name, CALL_FP_STUB, sizeof CALL_FP_STUB - 1) == 0)
-	loc = &h->call_fp_stub;
-      else
-	loc = &h->call_stub;
+	      rend = sec_relocs + o->reloc_count;
+	      for (r = sec_relocs; r < rend; r++)
+		if (ELF_R_SYM (abfd, r->r_info) == r_symndx
+		    && ELF_R_TYPE (abfd, r->r_info) == R_MIPS16_26)
+		    break;
+
+	      if (elf_section_data (o)->relocs != sec_relocs)
+		free (sec_relocs);
+
+	      if (r < rend)
+		break;
+	    }
+
+	  if (o == NULL)
+	    {
+	      /* There is no non-call reloc for this stub, so we do
+                 not need it.  Since this function is called before
+                 the linker maps input sections to output sections, we
+                 can easily discard it by setting the SEC_EXCLUDE
+                 flag.  */
+	      sec->flags |= SEC_EXCLUDE;
+	      return TRUE;
+	    }
+
+	  /* Record this stub in an array of local symbol call_stubs for
+             this BFD.  */
+	  if (elf_tdata (abfd)->local_call_stubs == NULL)
+	    {
+	      unsigned long symcount;
+	      asection **n;
+	      bfd_size_type amt;
+
+	      if (elf_bad_symtab (abfd))
+		symcount = NUM_SHDR_ENTRIES (symtab_hdr);
+	      else
+		symcount = symtab_hdr->sh_info;
+	      amt = symcount * sizeof (asection *);
+	      n = bfd_zalloc (abfd, amt);
+	      if (n == NULL)
+		return FALSE;
+	      elf_tdata (abfd)->local_call_stubs = n;
+	    }
+
+	  elf_tdata (abfd)->local_call_stubs[r_symndx] = sec;
 
-      /* If we already have an appropriate stub for this function, we
-	 don't need another one, so we can discard this one.  Since
-	 this function is called before the linker maps input sections
-	 to output sections, we can easily discard it by setting the
-	 SEC_EXCLUDE flag.  We can also discard this section if we
-	 happen to already know that this is a mips16 function; it is
-	 not necessary to check this here, as it is checked later, but
-	 it is slightly faster to check now.  */
-      if (*loc != NULL || h->root.other == STO_MIPS16)
+	  /* We don't need to set mips16_stubs_seen in this case.
+             That flag is used to see whether we need to look through
+             the global symbol table for stubs.  We don't need to set
+             it here, because we just have a local stub.  */
+	}
+      else
 	{
-	  sec->flags |= SEC_EXCLUDE;
-	  return TRUE;
+	  h = ((struct mips_elf_link_hash_entry *)
+	       sym_hashes[r_symndx - extsymoff]);
+	  
+	  /* H is the symbol this stub is for.  */
+	  
+	  if (strncmp (name, CALL_FP_STUB, sizeof CALL_FP_STUB - 1) == 0)
+	    loc = &h->call_fp_stub;
+	  else
+	    loc = &h->call_stub;
+	  
+	  /* If we already have an appropriate stub for this function, we
+	     don't need another one, so we can discard this one.  Since
+	     this function is called before the linker maps input sections
+	     to output sections, we can easily discard it by setting the
+	     SEC_EXCLUDE flag.  We can also discard this section if we
+	     happen to already know that this is a mips16 function; it is
+	     not necessary to check this here, as it is checked later, but
+	     it is slightly faster to check now.  */
+	  if (*loc != NULL || h->root.other == STO_MIPS16)
+	    {
+	      sec->flags |= SEC_EXCLUDE;
+	      return TRUE;
+	    }
+	  
+	  *loc = sec;
+	  mips_elf_hash_table (info)->mips16_stubs_seen = TRUE;
 	}
-
-      *loc = sec;
-      mips_elf_hash_table (info)->mips16_stubs_seen = TRUE;
     }
 
   if (dynobj == NULL)


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