MIPS/BFD: Actually produce short microMIPS LA25 stubs
authorMaciej W. Rozycki <macro@imgtec.com>
Wed, 10 Aug 2016 19:44:03 +0000 (20:44 +0100)
committerMaciej W. Rozycki <macro@imgtec.com>
Wed, 10 Aug 2016 21:22:50 +0000 (22:22 +0100)
For the case where a function which requires an LA25 stub is at the
beginning of a section we use a short sequence comprised of a LUI/ADDIU
instruction pair only and prepended to the associated function rather
than using a trailing jump to reach the function.  This works by
checking for the offset into section of the function symbol being 0.

This is however never the case for microMIPS function symbols, which
have the ISA bit set.  Consequently the short LA25 sequence is never
produced for microMIPS functions, like with the following example:

$ cat la25a.s
.abicalls

.global f1
.ent f1
f1:
.set noreorder
.cpload $25
.set reorder
.option pic0
jal f2
.option pic2
jr $31
.end f1

.global f2
.ent f2
f2:
jr $31
.end f2
$ cat la25b.s
.abicalls
.option pic0

.global __start
.ent __start
__start:
jal f1
jal f2
.end __start
$ as -mmicromips -32 -EB -o la25a.o la25a.s
$ as -mmicromips -32 -EB -o la25b.o la25b.s
$ ld -melf32btsmip -o la25 la25a.o la25b.o
$ objdump -d la25

la25:     file format elf32-tradbigmips

Disassembly of section .text:

004000d0 <.pic.f2>:
  4000d0: 41b9 0040  lui t9,0x40
  4000d4: d420 0083  j 400106 <f2>
  4000d8: 3339 0107  addiu t9,t9,263
  4000dc: 0000 0000  nop

004000e0 <.pic.f1>:
  4000e0: 41b9 0040  lui t9,0x40
  4000e4: d420 0078  j 4000f0 <f1>
  4000e8: 3339 00f1  addiu t9,t9,241
  4000ec: 0000 0000  nop

004000f0 <f1>:
  4000f0: 41bc 0002  lui gp,0x2
  4000f4: 339c 801f  addiu gp,gp,-32737
  4000f8: 033c e150  addu gp,gp,t9
  4000fc: f420 0083  jal 400106 <f2>
  400100: 0000 0000  nop
  400104: 45bf       jrc ra

00400106 <f2>:
  400106: 45bf       jrc ra
...

00400110 <__start>:
  400110: f420 0070  jal 4000e0 <.pic.f1>
  400114: 0000 0000  nop
  400118: f420 0068  jal 4000d0 <.pic.f2>
  40011c: 0000 0000  nop
$

where `.pic.f1' could omit the trailing jump and the filler NOP and just
fall through to `f1'.

Correct the problem by masking out the ISA bit from microMIPS functions,
which fixes the earlier example:

$ objdump -d la25

la25:     file format elf32-tradbigmips

Disassembly of section .text:

004000d0 <.pic.f2>:
  4000d0: 41b9 0040  lui t9,0x40
  4000d4: d420 0083  j 400106 <f2>
  4000d8: 3339 0107  addiu t9,t9,263
...

004000e8 <.pic.f1>:
  4000e8: 41b9 0040  lui t9,0x40
  4000ec: 3339 00f1  addiu t9,t9,241

004000f0 <f1>:
  4000f0: 41bc 0002  lui gp,0x2
  4000f4: 339c 801f  addiu gp,gp,-32737
  4000f8: 033c e150  addu gp,gp,t9
  4000fc: f420 0083  jal 400106 <f2>
  400100: 0000 0000  nop
  400104: 45bf       jrc ra

00400106 <f2>:
  400106: 45bf       jrc ra
...

00400110 <__start>:
  400110: f420 0074  jal 4000e8 <.pic.f1>
  400114: 0000 0000  nop
  400118: f420 0068  jal 4000d0 <.pic.f2>
  40011c: 0000 0000  nop
$

There is no need to do anything for MIPS16 functions, because if any
LA25 stub has been generated for such a function, then it is only
required for an associated call thunk only, which is regular MIPS code
and the address of which, with the ISA bit clear, is returned by
`mips_elf_get_la25_target'.

This problem has been there since the beginning of microMIPS support:

commit df58fc944dbc6d5efd8d3826241b64b6af22f447
Author: Richard Sandiford <rdsandiford@googlemail.com>
Date:   Sun Jul 24 14:20:15 2011 +0000

<https://sourceware.org/ml/binutils/2011-07/msg00198.html>, ("MIPS:
microMIPS ASE support").

bfd/
* elfxx-mips.c (mips_elf_add_la25_stub): Clear the ISA bit of
the stub address retrieved if associated with a microMIPS
function.

bfd/ChangeLog
bfd/elfxx-mips.c

index 3ddafcb..303d97b 100644 (file)
@@ -1,5 +1,11 @@
 2016-08-10  Maciej W. Rozycki  <macro@imgtec.com>
 
+       * elfxx-mips.c (mips_elf_add_la25_stub): Clear the ISA bit of
+       the stub address retrieved if associated with a microMIPS
+       function.
+
+2016-08-10  Maciej W. Rozycki  <macro@imgtec.com>
+
        * elfxx-mips.c (mips_elf_create_stub_symbol): For a microMIPS
        stub also add STO_MICROMIPS annotation.
 
index 6690428..ffc524f 100644 (file)
@@ -1964,6 +1964,8 @@ mips_elf_add_la25_stub (struct bfd_link_info *info,
   /* Prefer to use LUI/ADDIU stubs if the function is at the beginning
      of the section and if we would need no more than 2 nops.  */
   value = mips_elf_get_la25_target (stub, &s);
+  if (ELF_ST_IS_MICROMIPS (stub->h->root.other))
+    value &= ~1;
   use_trampoline_p = (value != 0 || s->alignment_power > 4);
 
   h->la25_stub = stub;