This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
Fix linking of .gpdword on MIPS
- From: Richard Sandiford <rsandifo at nildram dot co dot uk>
- To: binutils at sourceware dot org
- Date: Mon, 26 Feb 2007 22:47:28 +0000
- Subject: Fix linking of .gpdword on MIPS
I did my first MIPS GNU/Linux testing for a long time (actually a "build
world" in order to test a dl-machine.h patch) and I found that n64 was
basically unusable; every switch statement segfaulted. It turned out
to be fallout from:
2006-11-02 Daniel Jacobowitz <dan@codesourcery.com>
* libbfd-in.h (_bfd_clear_contents): New prototype.
* reloc.c (_bfd_clear_contents): New.
* libbfd.h: Regenerated.
* elf32-arm.c (elf32_arm_final_link_relocate): Use
_bfd_clear_contents.
* elf32-d10v.c (elf32_d10v_relocate_section): Likewise.
* elf32-hppa.c (elf32_hppa_relocate_section): Likewise.
* elf32-i386.c (elf_i386_relocate_section): Likewise.
* elf32-ppc.c (ppc_elf_relocate_section): Likewise.
* elf32-s390.c (elf_s390_relocate_section): Likewise.
* elf32-sh.c (sh_elf_relocate_section): Likewise.
* elf32-xtensa.c (elf_xtensa_relocate_section): Likewise.
* elf64-ppc.c (ppc64_elf_relocate_section): Likewise.
* elf64-s390.c (elf_s390_relocate_section): Likewise.
* elf64-x86-64.c (elf64_x86_64_relocate_section): Likewise.
* elfxx-sparc.c (_bfd_sparc_elf_relocate_section): Likewise.
* elfxx-ia64.c (elfNN_ia64_relocate_section): Set value to
zero for discarded symbols.
* elfxx-mips.c (mips_elf_calculate_relocation): Likewise.
The patch ignores the addend on a relocation against symbol 0,
on the basis that:
/* r_symndx will be zero only for relocs against symbols
from removed linkonce sections, or sections discarded by
a linker script. */
But that isn't true on MIPS; r_symndx is also zero the second
and subsequent entries in a composite relocation, when the addend
is carried over from the result of the previous relocations.
Are we really confident that this is the only exception, and that true
relocations against symbol zero will not reach here? If so, I think
the patch below is the correct fix. If not, it seems dangerous to
explicitly ignore what I understand to be correct semantics,
and treat S + A as zero simply because S is zero.
Patch tested on mips64-linux-gnu (binutils). I'll do another build
world with it to make sure that the problem is fixed.
There are no linker tests for gpword and gpdword at present, so the
patch adds one of each. The n32 version doesn't need a composite
relocation and works fine already.
Richard
bfd/
* elfxx-mips.c (mips_elf_calculate_relocation): Replace
save_addend with two new arguments, first_in_sequence and
last_in_sequence. Only treat zero symbols specially if
first_in_sequence. Replace use of !save_addend with
last_in_sequence.
(_bfd_mips_elf_relocate_section): Update caller accordingly.
Replace use_save_addend_p with first_in_sequence and
last_in_sequence.
ld/testsuite/
* ld-mips-elf/gpword-n32.d, ld-mips-elf/gpword-n32.ld,
* ld-mips-elf/gpword-n32.s, ld-mips-elf/gpdword-n64.d,
* ld-mips-elf/gpdword-n64.ld, ld-mips-elf/gpdword-n64.s: New tests.
* ld-mips-elf/mips-elf.exp: Run them.
Index: bfd/elfxx-mips.c
===================================================================
RCS file: /cvs/src/src/bfd/elfxx-mips.c,v
retrieving revision 1.195
diff -u -p -r1.195 elfxx-mips.c
--- bfd/elfxx-mips.c 20 Feb 2007 12:35:19 -0000 1.195
+++ bfd/elfxx-mips.c 26 Feb 2007 22:23:25 -0000
@@ -3862,6 +3862,12 @@ is_gott_symbol (struct bfd_link_info *in
REQUIRE_JALXP indicates whether or not the opcode used with this
relocation must be JALX.
+ MIPS relocations are generally composite, with one of more
+ relocations being combined to produce a single field adjustment.
+ FIRST_IN_SEQUENCE is true if this relocation is the first or only
+ reloc in the composite sequence; likewise LAST_IN_SEQUENCE for the
+ last or only reloc.
+
This function returns bfd_reloc_continue if the caller need take no
further action regarding this relocation, bfd_reloc_notsupported if
something goes dramatically wrong, bfd_reloc_overflow if an
@@ -3876,7 +3882,8 @@ mips_elf_calculate_relocation (bfd *abfd
Elf_Internal_Sym *local_syms,
asection **local_sections, bfd_vma *valuep,
const char **namep, bfd_boolean *require_jalxp,
- bfd_boolean save_addend)
+ bfd_boolean first_in_sequence,
+ bfd_boolean last_in_sequence)
{
/* The eventual value we will return. */
bfd_vma value;
@@ -4323,7 +4330,7 @@ mips_elf_calculate_relocation (bfd *abfd
input_section))
return bfd_reloc_undefined;
}
- else if (r_symndx == 0)
+ else if (first_in_sequence && r_symndx == 0)
/* r_symndx will be zero only for relocs against symbols
from removed linkonce sections, or sections discarded by
a linker script. */
@@ -4499,7 +4506,7 @@ mips_elf_calculate_relocation (bfd *abfd
case R_MIPS_GPREL32:
value = (addend + symbol + gp0 - gp);
- if (!save_addend)
+ if (last_in_sequence)
value &= howto->dst_mask;
break;
@@ -7743,7 +7750,8 @@ _bfd_mips_elf_relocate_section (bfd *out
Elf_Internal_Rela *rel;
const Elf_Internal_Rela *relend;
bfd_vma addend = 0;
- bfd_boolean use_saved_addend_p = FALSE;
+ bfd_boolean first_in_sequence = TRUE;
+ bfd_boolean last_in_sequence;
const struct elf_backend_data *bed;
bed = get_elf_backend_data (output_bfd);
@@ -7784,7 +7792,7 @@ _bfd_mips_elf_relocate_section (bfd *out
(input_bfd, input_section,
rel - relocs)));
- if (!use_saved_addend_p)
+ if (first_in_sequence)
{
Elf_Internal_Shdr *rel_hdr;
@@ -7966,9 +7974,9 @@ _bfd_mips_elf_relocate_section (bfd *out
if (rel + 1 < relend
&& rel->r_offset == rel[1].r_offset
&& ELF_R_TYPE (input_bfd, rel[1].r_info) != R_MIPS_NONE)
- use_saved_addend_p = TRUE;
+ last_in_sequence = FALSE;
else
- use_saved_addend_p = FALSE;
+ last_in_sequence = TRUE;
/* Figure out what value we are supposed to relocate. */
switch (mips_elf_calculate_relocation (output_bfd, input_bfd,
@@ -7976,7 +7984,8 @@ _bfd_mips_elf_relocate_section (bfd *out
addend, howto, local_syms,
local_sections, &value,
&name, &require_jalx,
- use_saved_addend_p))
+ first_in_sequence,
+ last_in_sequence))
{
case bfd_reloc_continue:
/* There's nothing to do. */
@@ -7996,11 +8005,9 @@ _bfd_mips_elf_relocate_section (bfd *out
return FALSE;
case bfd_reloc_overflow:
- if (use_saved_addend_p)
- /* Ignore overflow until we reach the last relocation for
- a given location. */
- ;
- else
+ /* Ignore overflow until we reach the last relocation for
+ a given location. */
+ if (last_in_sequence)
{
BFD_ASSERT (name != NULL);
if (! ((*info->callbacks->reloc_overflow)
@@ -8019,8 +8026,10 @@ _bfd_mips_elf_relocate_section (bfd *out
}
/* If we've got another relocation for the address, keep going
- until we reach the last one. */
- if (use_saved_addend_p)
+ until we reach the last one. Set FIRST_IN_SEQUENE as
+ appropriate for the next relocation. */
+ first_in_sequence = last_in_sequence;
+ if (!first_in_sequence)
{
addend = value;
continue;
Index: ld/testsuite/ld-mips-elf/gpword-n32.d
===================================================================
RCS file: ld/testsuite/ld-mips-elf/gpword-n32.d
diff -N ld/testsuite/ld-mips-elf/gpword-n32.d
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ ld/testsuite/ld-mips-elf/gpword-n32.d 26 Feb 2007 22:23:25 -0000
@@ -0,0 +1,11 @@
+#name: MIPS .gpword (n32)
+#source: gpword-n32.s
+#as: -n32 -KPIC -EB
+#ld: -melf32btsmipn32 -Tgpword-n32.ld
+#objdump: -sj.rodata
+
+.*file format .*
+
+Contents of section \.rodata:
+ 55560000 bcdd8010 .*
+
Index: ld/testsuite/ld-mips-elf/gpword-n32.ld
===================================================================
RCS file: ld/testsuite/ld-mips-elf/gpword-n32.ld
diff -N ld/testsuite/ld-mips-elf/gpword-n32.ld
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ ld/testsuite/ld-mips-elf/gpword-n32.ld 26 Feb 2007 22:23:25 -0000
@@ -0,0 +1,14 @@
+SECTIONS
+{
+ . = 0x12340000;
+ .stuff : { *(.stuff) }
+
+ . = 0x55550000;
+ .text : { *(.text) }
+
+ . = ALIGN (0x10000);
+ _gp = . + 0x7ff0;
+ .rodata : { *(.rodata) }
+
+ /DISCARD/ : { *(.reginfo) }
+}
Index: ld/testsuite/ld-mips-elf/gpword-n32.s
===================================================================
RCS file: ld/testsuite/ld-mips-elf/gpword-n32.s
diff -N ld/testsuite/ld-mips-elf/gpword-n32.s
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ ld/testsuite/ld-mips-elf/gpword-n32.s 26 Feb 2007 22:23:25 -0000
@@ -0,0 +1,10 @@
+ .globl _start
+_start:
+ jr $31
+
+ .section .stuff
+A:
+ nop
+
+ .section .rodata
+ .gpword A
Index: ld/testsuite/ld-mips-elf/gpdword-n64.d
===================================================================
RCS file: ld/testsuite/ld-mips-elf/gpdword-n64.d
diff -N ld/testsuite/ld-mips-elf/gpdword-n64.d
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ ld/testsuite/ld-mips-elf/gpdword-n64.d 26 Feb 2007 22:23:25 -0000
@@ -0,0 +1,10 @@
+#name: MIPS .gpdword (n64)
+#source: gpdword-n64.s
+#as: -64 -KPIC -EB
+#ld: -melf64btsmip -Tgpdword-n64.ld
+#objdump: -sj.rodata
+
+.*file format .*
+
+Contents of section \.rodata:
+ 240010000 fffffffe cffe8010 .*
Index: ld/testsuite/ld-mips-elf/gpdword-n64.ld
===================================================================
RCS file: ld/testsuite/ld-mips-elf/gpdword-n64.ld
diff -N ld/testsuite/ld-mips-elf/gpdword-n64.ld
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ ld/testsuite/ld-mips-elf/gpdword-n64.ld 26 Feb 2007 22:23:25 -0000
@@ -0,0 +1,14 @@
+SECTIONS
+{
+ . = 0x110000000;
+ .stuff : { *(.stuff) }
+
+ . = 0x240000000;
+ .text : { *(.text) }
+
+ . = ALIGN (0x10000);
+ _gp = . + 0x7ff0;
+ .rodata : { *(.rodata) }
+
+ /DISCARD/ : { *(.reginfo) }
+}
Index: ld/testsuite/ld-mips-elf/gpdword-n64.s
===================================================================
RCS file: ld/testsuite/ld-mips-elf/gpdword-n64.s
diff -N ld/testsuite/ld-mips-elf/gpdword-n64.s
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ ld/testsuite/ld-mips-elf/gpdword-n64.s 26 Feb 2007 22:23:25 -0000
@@ -0,0 +1,10 @@
+ .globl _start
+_start:
+ jr $31
+
+ .section .stuff
+A:
+ nop
+
+ .section .rodata
+ .gpdword A
Index: ld/testsuite/ld-mips-elf/mips-elf.exp
===================================================================
RCS file: /cvs/src/src/ld/testsuite/ld-mips-elf/mips-elf.exp,v
retrieving revision 1.41
diff -u -p -r1.41 mips-elf.exp
--- ld/testsuite/ld-mips-elf/mips-elf.exp 2 Nov 2006 15:20:31 -0000 1.41
+++ ld/testsuite/ld-mips-elf/mips-elf.exp 26 Feb 2007 22:23:25 -0000
@@ -87,6 +87,8 @@ if { $linux_gnu } {
run_dump_test "rel32-o32"
run_dump_test "rel32-n32"
run_dump_test "rel64"
+ run_dump_test "gpword-n32"
+ run_dump_test "gpdword-n64"
}
if { $embedded_elf } {