This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
Fix handling of local MIPS16 floating-point stubs
- From: Richard Sandiford <richard at codesourcery dot com>
- To: binutils at sourceware dot org
- Date: Wed, 20 Jun 2007 13:15:01 +0100
- Subject: 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"