Hi, A libffcall bug report [1] made me aware of an incompatible change in the MIPS ISAs. Namely, for jumping to an address given in a register, starting with mips32r6, the existing 'jr' instruction does not work any more: it produces an 'illegal instruction'.
There are many documents of the MIPS ISAs, and before 2014 they described two instructions JR and JALR: JR <rs> jumps to the address in register <rs> JALR <rd>,<rs> jumps to the address in register <rs> and puts the old PC + 8 into register <rd> In particular, JR <rs> [SPECIAL, rs, 00000, 00000, hint, 001000] is equivalent to JALR $0,<rs> [SPECIAL, rs, 00000, 00000, hint, 001001] (because writing to $0 is a no-op). In the documents that consider the MIPS32 R6 architecture, such as [2] from 2014 - look at the descriptions of JR and JALR - you see that - in order to get the effect of JR, the bit pattern of JALR with destination $0 has to be used, - in the JALR instruction, the destination $0 is no longer allowed; this is merely a hint for the disassembler. You can see that the GNU assembler has been adjusted. First, see the different bit patterns: $ cat foo.s .text j $25 nop jal $0,$25 nop # Assemble this using binutils 2.16.1: $ mips64-linux-as -32 -o foo.o foo.s $ mips64-linux-objdump --disassemble foo.o foo.o: file format elf32-tradbigmips Disassembly of section .text: 00000000 <.text>: 0: 03200008 jr t9 4: 00000000 nop 8: 03200009 jalr zero,t9 c: 00000000 nop ... # Now, see how a newer GNU assembler (binutils 2.27) and option -mips32r6 # produce a different result: $ mips64-linux-as -32 -mips32r6 -o foo.o foo.s $ mips64-linux-objdump --disassemble foo.o [binutils 2.16.1] foo.o: file format elf32-tradbigmips Disassembly of section .text: 00000000 <.text>: 0: 03200009 jalr zero,t9 4: 00000000 nop 8: 03200009 jalr zero,t9 c: 00000000 nop ... $ mips64-linux-objdump --disassemble foo.o [binutils 2.27] foo.o: file format elf32-tradbigmips Disassembly of section .text: 00000000 <.text>: 0: 03200009 jr t9 4: 00000000 nop 8: 03200009 jr t9 c: 00000000 nop ... Note that the JALR $0,<rs> instruction can be used on all architectures; I verified this by looking at old MIPS ISA documentations from 1995, and by looking at the source code of QEMU. Find attached a fix for GNU guile, that mirrors the one I submitted for GNU lightning [3] (untested). Bruno [1] https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=925129 [2] http://hades.mech.northwestern.edu/images/1/16/MIPS32_Architecture_Volume_II-A_Instruction_Set.pdf [3] https://lists.gnu.org/archive/html/lightning/2019-08/msg00010.html
diff --git a/libguile/lightening/lightening/mips-cpu.c b/libguile/lightening/lightening/mips-cpu.c index 7ab58b8..704a2cd 100644 --- a/libguile/lightening/lightening/mips-cpu.c +++ b/libguile/lightening/lightening/mips-cpu.c @@ -379,7 +379,11 @@ static void _nop(jit_state_t*,int32_t); # define BGTZ(rs,im) hrri(MIPS_BGTZ,rs,_ZERO_REGNO,im) # define BNE(rs,rt,im) hrri(MIPS_BNE,rs,rt,im) # define JALR(r0) hrrrit(MIPS_SPECIAL,r0,0,_RA_REGNO,0,MIPS_JALR) -# define JR(r0) hrrrit(MIPS_SPECIAL,r0,0,0,0,MIPS_JR) +# if 1 /* supports MIPS32 R6 */ +# define JR(r0) hrrrit(MIPS_SPECIAL,r0,0,0,0,MIPS_JALR) +# else /* does not support MIPS32 R6 */ +# define JR(r0) hrrrit(MIPS_SPECIAL,r0,0,0,0,MIPS_JR) +# endif # define J(i0) hi(MIPS_J,i0) # define MOVZ(rd,rs,rt) hrrrit(0,rs,rt,rd,0,MIPS_MOVZ) # define comr(r0,r1) xori(r0,r1,-1)