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]

Fix handling of local MIPS16 floating-point stubs


This patch fixes two problems with MIPS16 floating-point stubs
for local symbols:

  1. The linker would never use stubs for calls from MIPS16 code
     to non-MIPS16 code.  (The opposite direction works.)

  2. gas would reduce relocations against non-MIPS16 local functions to
     relocations against section symbols.  It did this both for MIPS16
     jal relocations and relocations in the stubs.

The patch fixes (1) by refactoring the test in
mips_elf_calculation_relocation.  It fixes (2) by recording whether
a function symbol is the target of a MIPS16 jal; if so, no relocations
against the symbol will be reduced.  See the patch for a justification.

Tested on mips{,el}-elf, mipsisa64{,el}-elf, mips{,el}-linux-gnu
and mips64{,el}-linux-gnu.  OK to install?

Richard


bfd/
	* elfxx-mips.c (mips_elf_calculate_relocation): Allow local stubs
	to be used for calls from MIPS16 code.

gas/
	* config/tc-mips.h (TC_SYMFIELD_TYPE): New.
	* config/tc-mips.c (append_insn): Record which symbols have
	R_MIPS16_26 relocations against them.
	(mips_fix_adjustable): Don't reduce relocations against such symbols.

ld/testsuite/
	* ld-mips-elf/mips16-local-stubs-1.s,
	* ld-mips-elf/mips16-local-stubs-1.d: New tests.
	* ld-mips-elf/mips-elf.exp: Run them.

Index: bfd/elfxx-mips.c
===================================================================
RCS file: /cvs/src/src/bfd/elfxx-mips.c,v
retrieving revision 1.207
diff -u -p -r1.207 elfxx-mips.c
--- bfd/elfxx-mips.c	31 May 2007 20:22:56 -0000	1.207
+++ bfd/elfxx-mips.c	20 Jun 2007 12:12:34 -0000
@@ -4092,8 +4092,7 @@ mips_elf_calculate_relocation (bfd *abfd
   /* If this is a 16-bit call to a 32- or 64-bit function with a stub, we
      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 != 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))
Index: gas/config/tc-mips.h
===================================================================
RCS file: /cvs/src/src/gas/config/tc-mips.h,v
retrieving revision 1.46
diff -u -p -r1.46 tc-mips.h
--- gas/config/tc-mips.h	11 Sep 2006 02:32:50 -0000	1.46
+++ gas/config/tc-mips.h	20 Jun 2007 12:12:35 -0000
@@ -61,6 +61,9 @@ extern void mips_handle_align (struct fr
 struct insn_label_list;
 #define TC_SEGMENT_INFO_TYPE struct insn_label_list *
 
+/* This field is nonzero if the symbol is the target of a MIPS16 jump.  */
+#define TC_SYMFIELD_TYPE int
+
 /* Tell assembler that we have an itbl_mips.h header file to include.  */
 #define HAVE_ITBL_CPU
 
Index: gas/config/tc-mips.c
===================================================================
RCS file: /cvs/src/src/gas/config/tc-mips.c,v
retrieving revision 1.368
diff -u -p -r1.368 tc-mips.c
--- gas/config/tc-mips.c	18 May 2007 19:03:53 -0000	1.368
+++ gas/config/tc-mips.c	20 Jun 2007 12:12:38 -0000
@@ -2792,6 +2792,11 @@ append_insn (struct mips_cl_insn *ip, ex
 				     reloc_type[0] == BFD_RELOC_16_PCREL_S2,
 				     reloc_type[0]);
 
+	  /* Tag symbols that have a R_MIPS16_26 relocation against them.  */
+	  if (reloc_type[0] == BFD_RELOC_MIPS16_JMP
+	      && ip->fixp[0]->fx_addsy)
+	    *symbol_get_tc (ip->fixp[0]->fx_addsy) = 1;
+
 	  /* These relocations can have an addend that won't fit in
 	     4 octets for 64bit assembly.  */
 	  if (HAVE_64BIT_GPRS
@@ -13612,11 +13617,50 @@ mips_fix_adjustable (fixS *fixp)
     return 0;
 
 #ifdef OBJ_ELF
-  /* Don't adjust relocations against mips16 symbols, so that the linker
-     can find them if it needs to set up a stub.  */
+  /* R_MIPS16_26 relocations against non-MIPS16 functions might resolve
+     to a floating-point stub.  The same is true for non-R_MIPS16_26
+     relocations against MIPS16 functions; in this case, the stub becomes
+     the function's canonical address.
+
+     Floating-point stubs are stored in unique .mips16.call.* or
+     .mips16.fn.* sections.  If a stub T for function F is in section S,
+     the first relocation in section S must be against F; this is how the
+     linker determines the target function.  All relocations that might
+     resolve to T must also be against F.  We therefore have the following
+     restrictions, which are given in an intentionally-redundant way:
+
+       1. We cannot reduce R_MIPS16_26 relocations against non-MIPS16
+	  symbols.
+
+       2. We cannot reduce a stub's relocations against non-MIPS16 symbols
+	  if that stub might be used.
+
+       3. We cannot reduce non-R_MIPS16_26 relocations against MIPS16
+	  symbols.
+
+       4. We cannot reduce a stub's relocations against MIPS16 symbols if
+	  that stub might be used.
+
+     There is a further restriction:
+
+       5. We cannot reduce R_MIPS16_26 relocations against MIPS16 symbols
+	  on targets with in-place addends; the relocation field cannot
+	  encode the low bit.
+
+     For simplicity, we deal with (3)-(5) by not reducing _any_ relocation
+     against a MIPS16 symbol.
+
+     We deal with (1)-(2) by saying that, if there's a R_MIPS16_26
+     relocation against some symbol R, no relocation against R may be
+     reduced.  (Note that this deals with (2) as well as (1) because
+     relocations against global symbols will never be reduced on ELF
+     targets.)  This approach is a little simpler than trying to detect
+     stub sections, and gives the "all or nothing" per-symbol consistency
+     that we have for MIPS16 symbols.  */
   if (IS_ELF
-      && S_GET_OTHER (fixp->fx_addsy) == STO_MIPS16
-      && fixp->fx_subsy == NULL)
+      && fixp->fx_subsy == NULL
+      && (S_GET_OTHER (fixp->fx_addsy) == STO_MIPS16
+	  || *symbol_get_tc (fixp->fx_addsy)))
     return 0;
 #endif
 
Index: ld/testsuite/ld-mips-elf/mips16-local-stubs-1.s
===================================================================
RCS file: ld/testsuite/ld-mips-elf/mips16-local-stubs-1.s
diff -N ld/testsuite/ld-mips-elf/mips16-local-stubs-1.s
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ ld/testsuite/ld-mips-elf/mips16-local-stubs-1.s	20 Jun 2007 12:12:38 -0000
@@ -0,0 +1,49 @@
+	.macro	makestub,type,func,section
+	.text
+	.set	\type
+	.type	\func,@function
+	.ent	\func
+\func:
+	jr	$31
+	.end	\func
+
+	.section \section,"ax",@progbits
+	.set	nomips16
+	.type	stub_for_\func,@function
+	.ent	stub_for_\func
+stub_for_\func:
+	.set	noat
+	la	$1,\func
+	jr	$1
+	.set	at
+	.end	stub_for_\func
+	.endm
+
+	.macro	makestubs,id
+	makestub nomips16,f\id,.mips16.call.F\id
+	makestub nomips16,g\id,.mips16.call.fp.G\id
+	makestub mips16,h\id,.mips16.fn.H\id
+	.endm
+
+	.macro	makecaller,type,func
+	.text
+	.set	\type
+	.globl	\func
+	.type	\func,@function
+	.ent	\func
+\func:
+	jal	f1
+	jal	f2
+	jal	g1
+	jal	g2
+	jal	h1
+	jal	h2
+	.end	\func
+	.endm
+
+	makestubs 1
+	makestubs 2
+	makestubs 3
+
+	makecaller nomips16,caller1
+	makecaller mips16,caller2
Index: ld/testsuite/ld-mips-elf/mips16-local-stubs-1.d
===================================================================
RCS file: ld/testsuite/ld-mips-elf/mips16-local-stubs-1.d
diff -N ld/testsuite/ld-mips-elf/mips16-local-stubs-1.d
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ ld/testsuite/ld-mips-elf/mips16-local-stubs-1.d	20 Jun 2007 12:12:38 -0000
@@ -0,0 +1,114 @@
+#name: MIPS16 interlinking for local functions 1
+#source: mips16-local-stubs-1.s
+#as: -mips4
+#ld: -Ttext 0x20000000 -e caller1
+#objdump: -dr
+#...
+Disassembly of section \.text:
+
+20000000 <f1>:
+20000000:	03e00008 	jr	ra
+20000004:	00000000 	nop
+
+20000008 <g1>:
+20000008:	03e00008 	jr	ra
+2000000c:	00000000 	nop
+
+20000010 <h1>:
+20000010:	e820      	jr	ra
+20000012:	6500      	nop
+
+20000014 <f2>:
+20000014:	03e00008 	jr	ra
+20000018:	00000000 	nop
+
+2000001c <g2>:
+2000001c:	03e00008 	jr	ra
+20000020:	00000000 	nop
+
+20000024 <h2>:
+20000024:	e820      	jr	ra
+20000026:	6500      	nop
+
+20000028 <f3>:
+20000028:	03e00008 	jr	ra
+2000002c:	00000000 	nop
+
+20000030 <g3>:
+20000030:	03e00008 	jr	ra
+20000034:	00000000 	nop
+
+20000038 <h3>:
+20000038:	e820      	jr	ra
+2000003a:	6500      	nop
+
+2000003c <caller1>:
+2000003c:	0c000000 	jal	20000000 <f1>
+20000040:	00000000 	nop
+20000044:	0c000005 	jal	20000014 <f2>
+20000048:	00000000 	nop
+2000004c:	0c000002 	jal	20000008 <g1>
+20000050:	00000000 	nop
+20000054:	0c000007 	jal	2000001c <g2>
+20000058:	00000000 	nop
+2000005c:	0c000024 	jal	20000090 <stub_for_h1>
+20000060:	00000000 	nop
+20000064:	0c000028 	jal	200000a0 <stub_for_h2>
+20000068:	00000000 	nop
+
+2000006c <caller2>:
+2000006c:	1c00 0030 	jalx	200000c0 <stub_for_f1>
+20000070:	6500      	nop
+20000072:	1c00 0038 	jalx	200000e0 <stub_for_f2>
+20000076:	6500      	nop
+20000078:	1c00 0034 	jalx	200000d0 <stub_for_g1>
+2000007c:	6500      	nop
+2000007e:	1c00 003c 	jalx	200000f0 <stub_for_g2>
+20000082:	6500      	nop
+20000084:	1800 0004 	jal	20000010 <h1>
+20000088:	6500      	nop
+2000008a:	1800 0009 	jal	20000024 <h2>
+2000008e:	6500      	nop
+
+20000090 <stub_for_h1>:
+20000090:	3c012000 	lui	at,0x2000
+20000094:	24210011 	addiu	at,at,17
+20000098:	00200008 	jr	at
+2000009c:	00000000 	nop
+
+200000a0 <stub_for_h2>:
+200000a0:	3c012000 	lui	at,0x2000
+200000a4:	24210025 	addiu	at,at,37
+200000a8:	00200008 	jr	at
+200000ac:	00000000 	nop
+
+# This isn't actually called, but is referenced from the .pdr section.
+200000b0 <stub_for_h3>:
+200000b0:	3c012000 	lui	at,0x2000
+200000b4:	24210039 	addiu	at,at,57
+200000b8:	00200008 	jr	at
+200000bc:	00000000 	nop
+
+200000c0 <stub_for_f1>:
+200000c0:	3c012000 	lui	at,0x2000
+200000c4:	24210000 	addiu	at,at,0
+200000c8:	00200008 	jr	at
+200000cc:	00000000 	nop
+
+200000d0 <stub_for_g1>:
+200000d0:	3c012000 	lui	at,0x2000
+200000d4:	24210008 	addiu	at,at,8
+200000d8:	00200008 	jr	at
+200000dc:	00000000 	nop
+
+200000e0 <stub_for_f2>:
+200000e0:	3c012000 	lui	at,0x2000
+200000e4:	24210014 	addiu	at,at,20
+200000e8:	00200008 	jr	at
+200000ec:	00000000 	nop
+
+200000f0 <stub_for_g2>:
+200000f0:	3c012000 	lui	at,0x2000
+200000f4:	2421001c 	addiu	at,at,28
+200000f8:	00200008 	jr	at
+200000fc:	00000000 	nop
Index: ld/testsuite/ld-mips-elf/mips-elf.exp
===================================================================
RCS file: /cvs/src/src/ld/testsuite/ld-mips-elf/mips-elf.exp,v
retrieving revision 1.42
diff -u -p -r1.42 mips-elf.exp
--- ld/testsuite/ld-mips-elf/mips-elf.exp	12 Apr 2007 19:26:09 -0000	1.42
+++ ld/testsuite/ld-mips-elf/mips-elf.exp	20 Jun 2007 12:12:38 -0000
@@ -269,3 +269,5 @@ set mips16_intermix_test {
 }
 
 run_ld_link_tests $mips16_intermix_test
+
+run_dump_test "mips16-local-stubs-1"


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