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: R_MIPS_CALL* relocation fixes


Hi,

 The following changes were discussed back in November 2000 here.  In
short, we currently make stubs for all functions even if there are
relocations related to taking a function's address.  This renders lazy
binding visible to programs.

 The patch to gas is not a perfect one -- we discussed "%call", "%call_hi" 
and "%call_lo" operators to designate symbol references that could be
assigned one of R_MIPS_CALL* relocations.  This would require gcc changes
and surely cannot be performed in short term.  I'm also thinking of
detecting common "la $25,symbol; jr/jalr $25" sequences in PIC code as
well.  I hope I will be able to provide these changes by the 2.12 release
but for now, I'm asking to include the patch anyway.  It does not make
things worse than they are now (all functions get stubs) and it improves
performance after BFD is fixed (no functions get stubs with gcc). 

bfd/ChangeLog:

2001-01-18  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.

gas/ChangeLog:

2001-01-18  Maciej W. Rozycki  <macro@ds2.pg.gda.pl>

	* config/tc-mips.c (macro): For M_LA_AB emit a
	BFD_RELOC_MIPS_CALL16 relocation or a
	BFD_RELOC_MIPS_CALL_HI16/BFD_RELOC_MIPS_CALL_LO16 pair instead of
	BFD_RELOC_MIPS_GOT16 and
	BFD_RELOC_MIPS_GOT_HI16/BFD_RELOC_MIPS_GOT_LO16, respectively for
	loading the jump register when generating SVR4_PIC code.

  Maciej

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

binutils-2.10.91-20010116-mips-call_reloc.patch
diff -up --recursive --new-file binutils.macro/bfd/elf32-mips.c binutils/bfd/elf32-mips.c
--- binutils.macro/bfd/elf32-mips.c	Wed Dec 13 04:26:02 2000
+++ binutils/bfd/elf32-mips.c	Thu Jan 18 22:54:41 2001
@@ -80,6 +80,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;
@@ -3955,6 +3961,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;
@@ -6225,7 +6232,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;
@@ -6393,6 +6400,7 @@ mips_elf_calculate_relocation (abfd,
       break;
 
     case R_MIPS_GOT16:
+    case R_MIPS_CALL16:
       if (local_p)
 	{
 	  boolean forced;
@@ -6415,7 +6423,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);
@@ -7728,10 +7735,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
@@ -7863,6 +7870,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.  */
@@ -7998,6 +8024,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
@@ -8038,8 +8066,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;
diff -up --recursive --new-file binutils.macro/gas/config/tc-mips.c binutils/gas/config/tc-mips.c
--- binutils.macro/gas/config/tc-mips.c	Fri Dec 29 04:26:01 2000
+++ binutils/gas/config/tc-mips.c	Thu Jan 18 22:51:14 2001
@@ -4213,9 +4213,13 @@ macro (ip)
 	}
       else if (mips_pic == SVR4_PIC && ! mips_big_got)
 	{
+	  int lw_reloc_type = (int) BFD_RELOC_MIPS_GOT16;
+
 	  /* If this is a reference to an external symbol, and there
 	     is no constant, we want
 	       lw	$tempreg,<sym>($gp)	(BFD_RELOC_MIPS_GOT16)
+	     or if tempreg is PIC_CALL_REG
+	       lw	$tempreg,<sym>($gp)	(BFD_RELOC_MIPS_CALL16)
 	     For a local symbol, we want
 	       lw	$tempreg,<sym>($gp)	(BFD_RELOC_MIPS_GOT16)
 	       nop
@@ -4242,9 +4246,11 @@ macro (ip)
 	  expr1.X_add_number = offset_expr.X_add_number;
 	  offset_expr.X_add_number = 0;
 	  frag_grow (32);
+	  if (expr1.X_add_number == 0 && tempreg == PIC_CALL_REG)
+	    lw_reloc_type = (int) BFD_RELOC_MIPS_CALL16;
 	  macro_build ((char *) NULL, &icnt, &offset_expr,
 		       dbl ? "ld" : "lw",
-		       "t,o(b)", tempreg, (int) BFD_RELOC_MIPS_GOT16, GP);
+		       "t,o(b)", tempreg, lw_reloc_type, GP);
 	  if (expr1.X_add_number == 0)
 	    {
 	      int off;
@@ -4350,12 +4356,18 @@ macro (ip)
       else if (mips_pic == SVR4_PIC)
 	{
 	  int gpdel;
+	  int lui_reloc_type = (int) BFD_RELOC_MIPS_GOT_HI16;
+	  int lw_reloc_type = (int) BFD_RELOC_MIPS_GOT_LO16;
 
 	  /* This is the large GOT case.  If this is a reference to an
 	     external symbol, and there is no constant, we want
 	       lui	$tempreg,<sym>		(BFD_RELOC_MIPS_GOT_HI16)
 	       addu	$tempreg,$tempreg,$gp
 	       lw	$tempreg,<sym>($tempreg) (BFD_RELOC_MIPS_GOT_LO16)
+	     or if tempreg is PIC_CALL_REG
+	       lui	$tempreg,<sym>		(BFD_RELOC_MIPS_CALL_HI16)
+	       addu	$tempreg,$tempreg,$gp
+	       lw	$tempreg,<sym>($tempreg) (BFD_RELOC_MIPS_CALL_LO16)
 	     For a local symbol, we want
 	       lw	$tempreg,<sym>($gp)	(BFD_RELOC_MIPS_GOT16)
 	       nop
@@ -4394,8 +4406,13 @@ macro (ip)
 	    gpdel = 4;
 	  else
 	    gpdel = 0;
+	  if (expr1.X_add_number == 0 && tempreg == PIC_CALL_REG)
+	    {
+	      lui_reloc_type = (int) BFD_RELOC_MIPS_CALL_HI16;
+	      lw_reloc_type = (int) BFD_RELOC_MIPS_CALL_LO16;
+	    }
 	  macro_build ((char *) NULL, &icnt, &offset_expr, "lui", "t,u",
-		       tempreg, (int) BFD_RELOC_MIPS_GOT_HI16);
+		       tempreg, lui_reloc_type);
 	  macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
 		       ((bfd_arch_bits_per_address (stdoutput) == 32
 			 || ! ISA_HAS_64BIT_REGS (mips_opts.isa))
@@ -4403,8 +4420,7 @@ macro (ip)
 		       "d,v,t", tempreg, tempreg, GP);
 	  macro_build ((char *) NULL, &icnt, &offset_expr,
 		       dbl ? "ld" : "lw",
-		       "t,o(b)", tempreg, (int) BFD_RELOC_MIPS_GOT_LO16,
-		       tempreg);
+		       "t,o(b)", tempreg, lw_reloc_type, tempreg);
 	  if (expr1.X_add_number == 0)
 	    {
 	      int off;


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