[patch] MIPS gas problems with gcc's explicit relocs

Maciej W. Rozycki macro@ds2.pg.gda.pl
Fri May 28 19:00:00 GMT 2004


Hello,

 The recent addition of explicit relocation generation to gcc triggered 
failures for inline assembly under certain conditions.  Example: given the 
following program:

$ cat dlac.c
extern void *foo;
void *bar(void)
{
	void *result;
	asm("dla\t%0,%1" : "=r" (result) : "m" (foo));
	return result;
}

I get:

$ mips64el-linux-gcc -mno-abicalls -S -o dlac.s dlac.c
$ cat dlac.s
	.file	1 "dlac.c"
	.section .mdebug.abi64
	.previous
	.text
	.align	2
	.align	2
	.globl	bar
	.ent	bar
	.type	bar, @function
bar:
	.frame	$fp,32,$31		# vars= 16, regs= 1/0, args= 0, gp= 0
	.mask	0x40000000,-16
	.fmask	0x00000000,0
	daddiu	$sp,$sp,-32
	sd	$fp,16($sp)
	move	$fp,$sp
	lui	$2,%highest(foo)
	daddiu	$2,$2,%higher(foo)
	dsll	$2,$2,16
	daddiu	$2,$2,%hi(foo)
	dsll	$2,$2,16
#APP
	dla	$2,%lo(foo)($2)
#NO_APP
	sd	$2,0($fp)
	ld	$2,0($fp)
	move	$sp,$fp
	ld	$fp,16($sp)
	daddiu	$sp,$sp,32
	j	$31
	.end	bar
	.ident	"GCC: (GNU) 3.5.0 20040522 (experimental)"

which fails to be assembled by gas due to a reloc operator used in the
second operand of "dla":

$ mips64el-linux-gcc -mno-abicalls -c -o dlac.o dlac.s
dlac.s: Assembler messages:
dlac.s:23: Error: bad expression
dlac.s:23: Error: illegal operands `dla'

 Here's a patch that adds handling of such reloc operators to "la" and 
related macros, implementing the expected behavior.  The above program 
gets assembled to:

$ mips64el-linux-objdump -Sr dlac.o

dlac.o:     file format elf64-tradlittlemips

Disassembly of section .text:

0000000000000000 <bar>:
   0:	67bdffe0 	daddiu	sp,sp,-32
   4:	ffbe0010 	sd	s8,16(sp)
   8:	03a0f02d 	move	s8,sp
   c:	3c020000 	lui	v0,0x0
			c: R_MIPS_HIGHEST	foo
			c: R_MIPS_NONE	*ABS*
			c: R_MIPS_NONE	*ABS*
  10:	64420000 	daddiu	v0,v0,0
			10: R_MIPS_HIGHER	foo
			10: R_MIPS_NONE	*ABS*
			10: R_MIPS_NONE	*ABS*
  14:	00021438 	dsll	v0,v0,0x10
  18:	64420000 	daddiu	v0,v0,0
			18: R_MIPS_HI16	foo
			18: R_MIPS_NONE	*ABS*
			18: R_MIPS_NONE	*ABS*
  1c:	00021438 	dsll	v0,v0,0x10
  20:	64420000 	daddiu	v0,v0,0
			20: R_MIPS_LO16	foo
			20: R_MIPS_NONE	*ABS*
			20: R_MIPS_NONE	*ABS*
  24:	ffc20000 	sd	v0,0(s8)
  28:	dfc20000 	ld	v0,0(s8)
  2c:	03c0e82d 	move	sp,s8
  30:	dfbe0010 	ld	s8,16(sp)
  34:	03e00008 	jr	ra
  38:	67bd0020 	daddiu	sp,sp,32
  3c:	00000000 	nop

gas/ChangeLog:
2004-05-28  Maciej W. Rozycki  <macro@ds2.pg.gda.pl>

	* config/tc-mips.c (append_insn): Handle constant expressions with 
	no associated relocation.
	(macro): Handle reloc operators in operands of load address 
	macros.
	(mips_ip): Cancel the expression after use for the Q format 
	specifier.
	(parse_relocation): Return no relocation for unsupported 
	operators.
	(my_getSmallExpression): Return no relocation if no relocation 
	operators are used.

gas/testsuite/ChangeLog:
2004-05-28  Maciej W. Rozycki  <macro@ds2.pg.gda.pl>

	* gas/mips/elf-rel20.d: New test for reloc operators with "la".
	* gas/mips/elf-rel20.s: Source for the new test.
	* gas/mips/mips.exp: Run the new test.

opcodes/ChangeLog:
2004-05-28  Maciej W. Rozycki  <macro@ds2.pg.gda.pl>

	* mips-opc.c (mips_builtin_opcodes): Handle reloc operators in 
	operands of load address macros.

 A few notes:

1. I handle "dla", "dlca", "la" and "lca" the same way for symmetry and
simplicity.  The reloc used overrides the macro name for GOT vs CALL
relocations.  I see no point in making it more complicated.  Ditto about
reloc operators of a dubious use here -- they're all handled as with
load/store instructions.

2. I feel the changes to use BFD_RELOC_UNUSED when no relocation is to be 
used are the Right Thing -- I see no point in pretending a BFD_RELOC_LO16 
relocation was used.  The change appears safe, except a small bug had to 
be corrected in MDMX support code.

3. The change was tested for the mips64el-linux target -- no regressions
in the testsuite.  A testcase is included.

 OK to apply?

  Maciej

-- 
+  Maciej W. Rozycki, Technical University of Gdansk, Poland   +
+--------------------------------------------------------------+
+        e-mail: macro@ds2.pg.gda.pl, PGP key available        +

binutils-2.15.91-20040527-mips-la-reloc.patch
diff -up --recursive --new-file binutils-2.15.91-20040527.macro/gas/config/tc-mips.c binutils-2.15.91-20040527/gas/config/tc-mips.c
--- binutils-2.15.91-20040527.macro/gas/config/tc-mips.c	2004-05-21 03:25:26.000000000 +0000
+++ binutils-2.15.91-20040527/gas/config/tc-mips.c	2004-05-28 14:38:52.000000000 +0000
@@ -2079,7 +2079,7 @@ append_insn (struct mips_cl_insn *ip, ex
     }
 
   fixp[0] = fixp[1] = fixp[2] = NULL;
-  if (address_expr != NULL && *reloc_type < BFD_RELOC_UNUSED)
+  if (address_expr != NULL)
     {
       if (address_expr->X_op == O_constant)
 	{
@@ -2112,6 +2112,7 @@ append_insn (struct mips_cl_insn *ip, ex
 	      ip->insn_opcode |= (address_expr->X_add_number >> 16) & 0xffff;
 	      break;
 
+	    case BFD_RELOC_UNUSED:
 	    case BFD_RELOC_LO16:
 	    case BFD_RELOC_MIPS_GOT_DISP:
 	      ip->insn_opcode |= address_expr->X_add_number & 0xffff;
@@ -2147,7 +2148,7 @@ append_insn (struct mips_cl_insn *ip, ex
 	      internalError ();
 	    }
 	}
-      else
+      else if (*reloc_type < BFD_RELOC_UNUSED)
 	need_reloc:
 	{
 	  reloc_howto_type *howto;
@@ -4869,6 +4870,15 @@ macro (struct mips_cl_insn *ip)
 	  return;
 	}
 
+      if (offset_expr.X_op == O_symbol
+	  && *offset_reloc != BFD_RELOC_UNUSED)
+	{
+	  macro_build (&offset_expr,
+		       (dbl || HAVE_64BIT_ADDRESSES) ? "daddiu" : "addiu",
+		       "t,r,j", treg, sreg, *offset_reloc);
+	  return;
+	}
+
       if (treg == breg)
 	{
 	  tempreg = AT;
@@ -8596,6 +8606,7 @@ do_msbd:
 			  ip->insn_opcode |= (imm_expr.X_add_number
 					      << (OP_SH_VSEL +
 						  (is_qh ? 2 : 1)));
+			  imm_expr.X_op = O_absent;
 			  if (*s != ']')
 			    as_warn(_("Expecting ']' found '%s'"), s);
 			  else
@@ -9809,7 +9820,7 @@ parse_relocation (char **str, bfd_reloc_
 	  {
 	    as_bad ("relocation %s isn't supported by the current ABI",
 		    percent_op[i].str);
-	    *reloc = BFD_RELOC_LO16;
+	    *reloc = BFD_RELOC_UNUSED;
 	  }
 	return TRUE;
       }
@@ -9821,8 +9832,7 @@ parse_relocation (char **str, bfd_reloc_
    expression in *EP and the relocations in the array starting
    at RELOC.  Return the number of relocation operators used.
 
-   On exit, EXPR_END points to the first character after the expression.
-   If no relocation operators are used, RELOC[0] is set to BFD_RELOC_LO16.  */
+   On exit, EXPR_END points to the first character after the expression.  */
 
 static size_t
 my_getSmallExpression (expressionS *ep, bfd_reloc_code_real_type *reloc,
@@ -9868,9 +9878,7 @@ my_getSmallExpression (expressionS *ep, 
 
   expr_end = str;
 
-  if (reloc_index == 0)
-    reloc[0] = BFD_RELOC_LO16;
-  else
+  if (reloc_index != 0)
     {
       prev_reloc_op_frag = frag_now;
       for (i = 0; i < reloc_index; i++)
diff -up --recursive --new-file binutils-2.15.91-20040527.macro/gas/testsuite/gas/mips/elf-rel20.d binutils-2.15.91-20040527/gas/testsuite/gas/mips/elf-rel20.d
--- binutils-2.15.91-20040527.macro/gas/testsuite/gas/mips/elf-rel20.d	1970-01-01 00:00:00.000000000 +0000
+++ binutils-2.15.91-20040527/gas/testsuite/gas/mips/elf-rel20.d	2004-05-28 15:48:29.000000000 +0000
@@ -0,0 +1,31 @@
+#objdump: -dr --prefix-addresses -mmips:3000
+#name: MIPS ELF reloc 20
+#as: -march=mips2 -mabi=32
+#source: elf-rel20.s
+
+# Test relocations on the la macro.
+
+.*: +file format .*mips.*
+
+Disassembly of section .text:
+[0-9a-f]+ <[^>]*> lui	a0,0x0
+[ 	]*[0-9a-f]+: R_MIPS_CALL_HI16	gfunc
+[0-9a-f]+ <[^>]*> addu	a0,a0,gp
+[0-9a-f]+ <[^>]*> addiu	t9,a0,0
+[ 	]*[0-9a-f]+: R_MIPS_CALL_LO16	gfunc
+[0-9a-f]+ <[^>]*> lui	a0,0x0
+[ 	]*[0-9a-f]+: R_MIPS_GOT_HI16	gvar
+[0-9a-f]+ <[^>]*> addu	a0,a0,gp
+[0-9a-f]+ <[^>]*> addiu	a1,a0,0
+[ 	]*[0-9a-f]+: R_MIPS_GOT_LO16	gvar
+[0-9a-f]+ <[^>]*> lw	a0,0\(gp\)
+[ 	]*[0-9a-f]+: R_MIPS_GOT16	.data
+[0-9a-f]+ <[^>]*> addiu	a1,a0,0
+[ 	]*[0-9a-f]+: R_MIPS_LO16	.data
+[0-9a-f]+ <[^>]*> addiu	t9,gp,0
+[ 	]*[0-9a-f]+: R_MIPS_CALL16	gfunc
+[0-9a-f]+ <[^>]*> addiu	a0,gp,0
+[ 	]*[0-9a-f]+: R_MIPS_GOT_DISP	gvar
+[0-9a-f]+ <[^>]*> addiu	a0,gp,0
+[ 	]*[0-9a-f]+: R_MIPS_GPREL16	gvar
+	...
diff -up --recursive --new-file binutils-2.15.91-20040527.macro/gas/testsuite/gas/mips/elf-rel20.s binutils-2.15.91-20040527/gas/testsuite/gas/mips/elf-rel20.s
--- binutils-2.15.91-20040527.macro/gas/testsuite/gas/mips/elf-rel20.s	1970-01-01 00:00:00.000000000 +0000
+++ binutils-2.15.91-20040527/gas/testsuite/gas/mips/elf-rel20.s	2004-05-28 15:35:20.000000000 +0000
@@ -0,0 +1,28 @@
+	.ent	foo
+foo:
+	# Check various forms of paired relocations.
+
+	lui	$4,%call_hi(gfunc)
+	addu	$4,$4,$gp
+	la	$25,%call_lo(gfunc)($4)
+
+	lui	$4,%got_hi(gvar)
+	addu	$4,$4,$gp
+	la	$5,%got_lo(gvar)($4)
+
+	lw	$4,%got(lvar)($28)
+	la	$5,%lo(lvar)($4)
+
+	# Check individual relocations.
+
+	la	$25,%call16(gfunc)($28)
+
+	la	$4,%got_disp(gvar)($28)
+
+	la	$4,%gp_rel(gvar)($28)
+
+	.space	64
+	.end	foo
+
+	.data
+lvar:	.word	1,2
diff -up --recursive --new-file binutils-2.15.91-20040527.macro/gas/testsuite/gas/mips/mips.exp binutils-2.15.91-20040527/gas/testsuite/gas/mips/mips.exp
--- binutils-2.15.91-20040527.macro/gas/testsuite/gas/mips/mips.exp	2004-05-12 03:25:38.000000000 +0000
+++ binutils-2.15.91-20040527/gas/testsuite/gas/mips/mips.exp	2004-05-28 15:52:39.000000000 +0000
@@ -660,6 +660,7 @@ if { [istarget mips*-*-*] } then {
 	    run_dump_test "elf-rel18"
 	}
 	run_dump_test "elf-rel19"
+	run_dump_test "elf-rel20"
 
 	if { !$no_mips16 } {
 	    run_dump_test "${tmips}mips${el}16-e"
diff -up --recursive --new-file binutils-2.15.91-20040527.macro/opcodes/mips-opc.c binutils-2.15.91-20040527/opcodes/mips-opc.c
--- binutils-2.15.91-20040527.macro/opcodes/mips-opc.c	2003-11-19 04:25:23.000000000 +0000
+++ binutils-2.15.91-20040527/opcodes/mips-opc.c	2004-05-28 10:35:19.000000000 +0000
@@ -516,7 +516,9 @@ const struct mips_opcode mips_builtin_op
 {"divu",    "z,t",      0x0000001b, 0xffe0ffff, RD_s|RD_t|WR_HILO,      I1      },
 {"divu",    "d,v,t",	0,    (int) M_DIVU_3,	INSN_MACRO,		I1	},
 {"divu",    "d,v,I",	0,    (int) M_DIVU_3I,	INSN_MACRO,		I1	},
+{"dla",     "t,o(b)",	0,    (int) M_DLA_AB,	INSN_MACRO,		I3	},
 {"dla",     "t,A(b)",	0,    (int) M_DLA_AB,	INSN_MACRO,		I3	},
+{"dlca",    "t,o(b)",	0,    (int) M_DLA_AB,	INSN_MACRO,		I3	},
 {"dlca",    "t,A(b)",	0,    (int) M_DLCA_AB,	INSN_MACRO,		I3	},
 {"dli",     "t,j",      0x24000000, 0xffe00000, WR_t,			I3	}, /* addiu */
 {"dli",	    "t,i",	0x34000000, 0xffe00000, WR_t,			I3	}, /* ori */
@@ -636,11 +638,13 @@ const struct mips_opcode mips_builtin_op
    will match first).  */
 {"jal",     "a",	0x0c000000, 0xfc000000,	UBD|WR_31,		I1	},
 {"jalx",    "a",	0x74000000, 0xfc000000, UBD|WR_31,		I16     },
+{"la",      "t,o(b)",	0,    (int) M_LA_AB,	INSN_MACRO,		I1	},
 {"la",      "t,A(b)",	0,    (int) M_LA_AB,	INSN_MACRO,		I1	},
 {"lb",      "t,o(b)",	0x80000000, 0xfc000000,	LDD|RD_b|WR_t,		I1	},
 {"lb",      "t,A(b)",	0,    (int) M_LB_AB,	INSN_MACRO,		I1	},
 {"lbu",     "t,o(b)",	0x90000000, 0xfc000000,	LDD|RD_b|WR_t,		I1	},
 {"lbu",     "t,A(b)",	0,    (int) M_LBU_AB,	INSN_MACRO,		I1	},
+{"lca",     "t,o(b)",	0,    (int) M_LA_AB,	INSN_MACRO,		I1	},
 {"lca",     "t,A(b)",	0,    (int) M_LCA_AB,	INSN_MACRO,		I1	},
 {"ld",	    "t,o(b)",   0xdc000000, 0xfc000000, WR_t|RD_b,		I3	},
 {"ld",      "t,o(b)",	0,    (int) M_LD_OB,	INSN_MACRO,		I1	},



More information about the Binutils mailing list