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

2.10.91: Incorrect creation of function stubs by elf32-mips


Hi,

 "MIPS ABI Supplement, 3rd Edition", figure 5-9 on page 5-10 states that
only if there are no relocations related to taking a function's address a
symbol can have a stub associated and thus lazy binding enabled.  This is
a reasonable requirement as otherwise a function pointer will have
different values depending on which module it was obtained in and whether
the final binding already happened or not.  As a result lazy binding
becomes non-transparent to the program.

 On page 4-20 the specification further clarifies how to distinguish
whether there are relocations related to taking a function's address or
not.  It reserves three special relocation types, namely R_MIPS_CALL16,
R_MIPS_CALL_HI16 and R_MIPS_CALL_LO16 for the purpose of loading the jump
register ($25 or t9) when performing position-independent function calls. 
An occurence of any these relocations does not count as taking a
function's address as the contents of the jump register are not used for
accessing pointers in a compliant code.  The relocations otherwise behave
in the same way as R_MIPS_GOT16, R_MIPS_GOT_HI16 and R_MIPS_GOT_LO16,
respectively.  Any but these CALL relocations are treated as related to
taking a function's address. 

 Unfortunately BFD does not obey the above rules and builds stubs even if
there are relocations related to taking a function's address.  The
following patch fixes it.

bfd/ChangeLog:

2000-11-05  Maciej W. Rozycki  <macro@ds2.pg.gda.pl>

	* elf32-mips.c (struct mips_elf_link_hash_entry): Added no_fn_stub
	member to mark symbols that have non-CALL relocations against
	them.
	(mips_elf_link_hash_newfunc): Initialize no_fn_stub.
	(mips_elf_calculate_relocation): Handle R_MIPS_CALL16 like
	R_MIPS_GOT16.
	(_bfd_mips_elf_check_relocs): Set no_fn_stub for a symbol if a
	non-CALL relocation against it is encountered.
	(_bfd_mips_elf_copy_indirect_symbol): Merge no_fn_stub as well.
	(_bfd_mips_elf_adjust_dynamic_symbol): Only create a stub if
	no_fn_stub is not set.

  Maciej

-- 
+  Maciej W. Rozycki, Technical University of Gdansk, Poland   +
+--------------------------------------------------------------+
+        e-mail: macro@ds2.pg.gda.pl, PGP key available        +

diff -up --recursive --new-file binutils.macro/bfd/elf32-mips.c binutils/bfd/elf32-mips.c
--- binutils.macro/bfd/elf32-mips.c	Sun Oct 15 03:25:28 2000
+++ binutils/bfd/elf32-mips.c	Sun Nov  5 21:42:45 2000
@@ -79,6 +79,12 @@ struct mips_elf_link_hash_entry
      section) against this symbol.  */
   unsigned int min_dyn_reloc_index;
 
+  /* We must not create a stub for a symbol that has relocations
+     related to taking the function's address, i.e. any but
+     R_MIPS_CALL*16 ones -- see "MIPS ABI Supplement, 3rd Edition",
+     p. 4-20.  */
+  boolean no_fn_stub;
+
   /* If there is a stub that 32 bit functions should use to call this
      16 bit function, this points to the section containing the stub.  */
   asection *fn_stub;
@@ -3891,6 +3897,7 @@ mips_elf_link_hash_newfunc (entry, table
       ret->esym.ifd = -2;
       ret->possibly_dynamic_relocs = 0;
       ret->min_dyn_reloc_index = 0;
+      ret->no_fn_stub = false;
       ret->fn_stub = NULL;
       ret->need_fn_stub = false;
       ret->call_stub = NULL;
@@ -6157,7 +6164,7 @@ mips_elf_calculate_relocation (abfd, 
 				 symbol + addend, sgot->contents + g);
 	    }
 	}
-      else if (r_type == R_MIPS_GOT16)
+      else if (r_type == R_MIPS_GOT16 || r_type == R_MIPS_CALL16)
 	/* There's no need to create a local GOT entry here; the
 	   calculation for a local GOT16 entry does not involve G.  */
 	break;
@@ -6325,6 +6332,7 @@ mips_elf_calculate_relocation (abfd, 
       break;
       
     case R_MIPS_GOT16:
+    case R_MIPS_CALL16:
       if (local_p)
 	{
 	  boolean forced;
@@ -6347,7 +6355,6 @@ mips_elf_calculate_relocation (abfd, 
 
       /* Fall through.  */
 
-    case R_MIPS_CALL16:
     case R_MIPS_GOT_DISP:
       value = g;
       overflowed_p = mips_elf_overflow_p (value, 16);
@@ -7662,10 +7669,10 @@ _bfd_mips_elf_check_relocs (abfd, info, 
 	  /* 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.  Similar comments apply to R_MIPS_GOT16.  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.
+	     the segment.  Similar comments apply to R_MIPS_GOT16 and
+	     R_MIPS_CALL16.  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
@@ -7797,6 +7804,25 @@ _bfd_mips_elf_check_relocs (abfd, info, 
 	  break;
 	}
 
+      /* We must not create a stub for a symbol that has relocations
+         related to taking the function's address.  */
+      switch (r_type)
+	{
+	default:
+	  if (h != NULL)
+	    {
+	      struct mips_elf_link_hash_entry *mh;
+
+	      mh = (struct mips_elf_link_hash_entry *) h;
+	      mh->no_fn_stub = true;
+	    }
+	  break;
+	case R_MIPS_CALL16:
+	case R_MIPS_CALL_HI16:
+	case R_MIPS_CALL_LO16:
+	  break;
+	}
+
       /* If this reloc is not a 16 bit call, and it has a global
          symbol, then we will need the fn_stub if there is one.
          References from a stub section do not count. */
@@ -7932,6 +7958,8 @@ _bfd_mips_elf_copy_indirect_symbol (dir,
       || (indmips->min_dyn_reloc_index != 0
           && indmips->min_dyn_reloc_index < dirmips->min_dyn_reloc_index))
     dirmips->min_dyn_reloc_index = indmips->min_dyn_reloc_index;
+  if (indmips->no_fn_stub)
+    dirmips->no_fn_stub = true;
 }
 
 /* Adjust a symbol defined by a dynamic object and referenced by a
@@ -7972,8 +8000,9 @@ _bfd_mips_elf_adjust_dynamic_symbol (inf
     mips_elf_allocate_dynamic_relocations (dynobj, 
 					   hmips->possibly_dynamic_relocs);
 
-  /* For a function, create a stub, if needed. */
-  if ((h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT) != 0)
+  /* For a function create a stub, if allowed.  */
+  if (! hmips->no_fn_stub
+      && (h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT) != 0)
     {
       if (! elf_hash_table (info)->dynamic_sections_created)
 	return true;


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