From fe152e64f65de9cfb6f2059b76be98712baa7b56 Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Wed, 10 Aug 2016 20:44:03 +0100 Subject: [PATCH] MIPS/BFD: Actually produce short microMIPS LA25 stubs 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 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 4000e8: 3339 00f1 addiu t9,t9,241 4000ec: 0000 0000 nop 004000f0 : 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 400100: 0000 0000 nop 400104: 45bf jrc ra 00400106 : 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 4000d8: 3339 0107 addiu t9,t9,263 ... 004000e8 <.pic.f1>: 4000e8: 41b9 0040 lui t9,0x40 4000ec: 3339 00f1 addiu t9,t9,241 004000f0 : 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 400100: 0000 0000 nop 400104: 45bf jrc ra 00400106 : 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 Date: Sun Jul 24 14:20:15 2011 +0000 , ("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 | 6 ++++++ bfd/elfxx-mips.c | 2 ++ 2 files changed, 8 insertions(+) diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 3ddafcb09d..303d97b912 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,9 @@ +2016-08-10 Maciej W. Rozycki + + * 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 * elfxx-mips.c (mips_elf_create_stub_symbol): For a microMIPS diff --git a/bfd/elfxx-mips.c b/bfd/elfxx-mips.c index 6690428c64..ffc524fc0d 100644 --- a/bfd/elfxx-mips.c +++ b/bfd/elfxx-mips.c @@ -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;