This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
[PATCH] MIPS/GAS: Fix NewABI reloc handling with the LD/SD macro
- From: "Maciej W. Rozycki" <macro at linux-mips dot org>
- To: Richard Sandiford <rdsandiford at googlemail dot com>
- Cc: binutils at sourceware dot org
- Date: Sun, 24 Oct 2010 15:32:41 +0100 (BST)
- Subject: [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;