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]

[PATCH] MIPS/GAS: Fix NewABI reloc handling with the LD/SD macro


Hi,

 Regrettably my changes:

	opcodes/
	* mips-opc.c (mips_builtin_opcodes): Move M_LD_OB and M_SD_OB 
	macros before their corresponding MIPS III hardware instructions.

	gas/
	* config/tc-mips.c (macro)[M_LD_OB, M_SD_OB]: Handle 64-bit ABIs.

(patch 02/15 of the recent long series) to make the LD/SD macro behave 
consistently on o32 regressed the handling of relocations on NewABI 
targets.  Which of course shows our lack of test coverage there, but I 
should have caught that regardless. :(

 Considering the following (not necessarily sensible) program:

$ cat ld-n64.s
	lui	$2, %got_hi(foo)
	ld	$31, %got_lo(foo)($2)
	lui	$3, %hi(%neg(%gp_rel(bar)))
	ld	$16, %lo(%neg(%gp_rel(bar)))($3)

We used to and should get the following output:

$ mips64-linux-as -64 -o ld-n64.o ld-n64.s
$ mips64-linux-objdump -dr ld-n64.o

ld-n64.o:     file format elf64-tradbigmips


Disassembly of section .text:

0000000000000000 <.text>:
   0:	3c020000 	lui	v0,0x0
			0: R_MIPS_GOT_HI16	foo
			0: R_MIPS_NONE	*ABS*
			0: R_MIPS_NONE	*ABS*
   4:	dc5f0000 	ld	ra,0(v0)
			4: R_MIPS_GOT_LO16	foo
			4: R_MIPS_NONE	*ABS*
			4: R_MIPS_NONE	*ABS*
   8:	3c030000 	lui	v1,0x0
			8: R_MIPS_GPREL16	bar
			8: R_MIPS_SUB	*ABS*
			8: R_MIPS_HI16	*ABS*
   c:	dc700000 	ld	s0,0(v1)
			c: R_MIPS_GPREL16	bar
			c: R_MIPS_SUB	*ABS*
			c: R_MIPS_LO16	*ABS*

Instead we get this:

$ mips64-linux-as -64 -o ld-n64-bad.o ld-n64.s
$ mips64-linux-objdump -dr ld-n64-bad.o

ld-n64-bad.o:     file format elf64-tradbigmips


Disassembly of section .text:

0000000000000000 <.text>:
   0:	3c020000 	lui	v0,0x0
			0: R_MIPS_GOT_HI16	foo
			0: R_MIPS_NONE	*ABS*
			0: R_MIPS_NONE	*ABS*
   4:	dc5f0000 	ld	ra,0(v0)
			4: R_MIPS_LO16	foo
			4: R_MIPS_NONE	*ABS*
			4: R_MIPS_NONE	*ABS*
   8:	3c030000 	lui	v1,0x0
			8: R_MIPS_GPREL16	bar
			8: R_MIPS_SUB	*ABS*
			8: R_MIPS_HI16	*ABS*
   c:	dc700000 	ld	s0,0(v1)
			c: R_MIPS_LO16	bar
			c: R_MIPS_NONE	*ABS*
			c: R_MIPS_NONE	*ABS*

The problem is with the change in place M_LD_OB and M_SD_OB macros take 
precedence over the corresponding hardware instructions and our macros 
generally have no support for reloc operators.

 All the infrastructure is in place though and here is my proposal to fix 
the problem.  A side effect is these macros now handle relocations other 
than LO16 even on o32.  While easily doable I think it makes no sense to 
insist on the previous behaviour of these macros on o32 -- I think where 
the address offset is hardware-expressable (i.e. matches the "o(b)" 
format) it makes perfect sense to respect percent-ops even in macros.  
What do you think?

 Tested with the usual set of targets: mips-linux, mips64-linux, 
mipstx39-elf, mipsisa64-elf and mips-ecoff targets and their respective 
little-endian counterparts.  At least a smoke test for the regression 
caused here would be a good idea; I'll think of something.

2010-10-24  Maciej W. Rozycki  <macro@linux-mips.org>

	gas/
	* config/tc-mips.c (macro)[M_LD_OB, M_SD_OB]: Use any offset
	reloc supplied.

 OK to apply?

  Maciej

binutils-2.20.51-20100925-mips-gas-ld-reloc.patch
Index: binutils-2.20.51/gas/config/tc-mips.c
===================================================================
--- binutils-2.20.51.orig/gas/config/tc-mips.c
+++ binutils-2.20.51/gas/config/tc-mips.c
@@ -4822,7 +4822,8 @@ macro (struct mips_cl_insn *ip)
   int call = 0;
   int off;
   offsetT maxnum;
-  bfd_reloc_code_real_type r;
+  bfd_reloc_code_real_type r[3]
+    = {BFD_RELOC_UNUSED, BFD_RELOC_UNUSED, BFD_RELOC_UNUSED};
   int hold_mips_optimize;
 
   gas_assert (! mips_opts.mips16);
@@ -7026,7 +7027,7 @@ macro (struct mips_cl_insn *ip)
 	      break;
 	    }
 	  breg = mips_gp_register;
-	  r = BFD_RELOC_MIPS_LITERAL;
+	  r[0] = BFD_RELOC_MIPS_LITERAL;
 	  goto dob;
 	}
       else
@@ -7049,23 +7050,23 @@ macro (struct mips_cl_insn *ip)
 	      break;
 	    }
 	  breg = AT;
-	  r = BFD_RELOC_LO16;
+	  r[0] = BFD_RELOC_LO16;
 	  goto dob;
 	}
 
     case M_L_DOB:
       /* Even on a big endian machine $fn comes before $fn+1.  We have
 	 to adjust when loading from memory.  */
-      r = BFD_RELOC_LO16;
+      r[0] = BFD_RELOC_LO16;
     dob:
       gas_assert (mips_opts.isa == ISA_MIPS1);
       macro_build (&offset_expr, "lwc1", "T,o(b)",
-		   target_big_endian ? treg + 1 : treg, r, breg);
+		   target_big_endian ? treg + 1 : treg, r[0], breg);
       /* FIXME: A possible overflow which I don't know how to deal
 	 with.  */
       offset_expr.X_add_number += 4;
       macro_build (&offset_expr, "lwc1", "T,o(b)",
-		   target_big_endian ? treg : treg + 1, r, breg);
+		   target_big_endian ? treg : treg + 1, r[0], breg);
       break;
 
     case M_L_DAB:
@@ -7350,12 +7351,20 @@ macro (struct mips_cl_insn *ip)
     case M_SD_OB:
       s = HAVE_64BIT_GPRS ? "sd" : "sw";
     sd_ob:
-      macro_build (&offset_expr, s, "t,o(b)", treg, BFD_RELOC_LO16, breg);
+      r[0] = BFD_RELOC_LO16;
+      if (offset_expr.X_op == O_symbol)
+	{
+	  r[0] = offset_reloc[0];
+	  r[1] = offset_reloc[1];
+	  r[2] = offset_reloc[2];
+	}
+      macro_build (&offset_expr, s, "t,o(b)", treg,
+		   -1, r[0], r[1], r[2], breg);
       if (!HAVE_64BIT_GPRS)
 	{
 	  offset_expr.X_add_number += 4;
 	  macro_build (&offset_expr, s, "t,o(b)", treg + 1,
-		       BFD_RELOC_LO16, breg);
+		       -1, r[0], r[1], r[2], breg);
 	}
       break;
 


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