This is the mail archive of the
binutils@sources.redhat.com
mailing list for the binutils project.
[patch] MIPS: Incorrect calculation for R_MIPS_LO16 relocs
- From: "Maciej W. Rozycki" <macro at linux-mips dot org>
- To: binutils at sources dot redhat dot com
- Date: Mon, 28 Jun 2004 17:34:03 +0200 (CEST)
- Subject: [patch] MIPS: Incorrect calculation for R_MIPS_LO16 relocs
Hello,
There is a problem in BFD with calculation done for R_MIPS_LO16
relocations upon a final link when the associated symbol is placed in a
mergeable section containing strings. In this case only the low 16 bits
of the addend retrieved from the relocation itself are used -- the
corresponding high 16 bits (from either a R_MIPS_HI16 or a R_MIPS_GOT16
relocations) are not retrieved. The value is passed to
_bfd_merged_section_offset() which looks up a wrong string if the high 16
bits should be non-zero. As a result, if symbol offsets change due to
merging, the relocation is not adjusted properly to point to the new
location.
The fix it to retrieve the corresponding high 16 bits and pass a complete
addend to _bfd_merged_section_offset(). Here is a patch that does that.
The included test case illustrates the bug conditions -- with current
binutils %lo(g) doesn't point to "g" after the final link anymore. This
bug has been originally observed with the Linux kernel when built with
current gcc.
bfd/:
2004-06-28 Maciej W. Rozycki <macro@linux-mips.org>
* elfxx-mips.c (_bfd_mips_elf_relocate_section): Add high 16 bits
of the addend from a corresponding HI16 or GOT16 reloc when
processing LO16 relocs.
ld/testsuite/:
2004-06-28 Maciej W. Rozycki <macro@linux-mips.org>
* ld-mips-elf/reloc-merge-lo16.d: New test for LO16 relocations
against a symbol in a mergeable section containing strings.
* ld-mips-elf/reloc-merge-lo16.s: Source for the new test.
* ld-mips-elf/reloc-merge-lo16.ld: Linker script for the new test.
* ld-mips-elf/mips-elf.exp: Run the new test.
This should only be the problem for old ABI binaries (using rel
relocations), but the complementing code for HI16/GOT16 relocations does
no differentiation of the ABI, so neither does this.
This has been tested for the mipsel-linu-gnu target -- no new
regressions, but changes are needed for gas to deal with corner cases.
I'll send them in following mails.
OK to apply?
Maciej
binutils-2.15.91-20040625-mips-merge-lo16.patch
diff -up --recursive --new-file binutils-2.15.91-20040625.macro/bfd/elfxx-mips.c binutils-2.15.91-20040625/bfd/elfxx-mips.c
--- binutils-2.15.91-20040625.macro/bfd/elfxx-mips.c 2004-06-25 03:25:50.000000000 +0000
+++ binutils-2.15.91-20040625/bfd/elfxx-mips.c 2004-06-26 23:48:27.000000000 +0000
@@ -6135,6 +6135,7 @@ _bfd_mips_elf_relocate_section (bfd *out
Elf_Internal_Rela *rel;
const Elf_Internal_Rela *relend;
bfd_vma addend = 0;
+ bfd_vma hi16_addend = 0;
bfd_boolean use_saved_addend_p = FALSE;
const struct elf_backend_data *bed;
@@ -6245,9 +6246,22 @@ _bfd_mips_elf_relocate_section (bfd *out
addend <<= 16;
+ /* Record the high part of the original addend for
+ succeeding LO16 relocations. */
+ hi16_addend = addend;
+
/* Compute the combined addend. */
addend += l;
}
+ else if (r_type == R_MIPS_LO16)
+ {
+ /* Add the high part of the addend used for the
+ corresponding HI16 or GOT16 relocation. This is a
+ complement to the operation performed for HI16 and
+ GOT16 relocations -- see above. */
+ addend = _bfd_mips_elf_sign_extend (addend, 16);
+ addend += hi16_addend;
+ }
else if (r_type == R_MIPS16_GPREL)
{
/* The addend is scrambled in the object file. See
diff -up --recursive --new-file binutils-2.15.91-20040625.macro/ld/testsuite/ld-mips-elf/mips-elf.exp binutils-2.15.91-20040625/ld/testsuite/ld-mips-elf/mips-elf.exp
--- binutils-2.15.91-20040625.macro/ld/testsuite/ld-mips-elf/mips-elf.exp 2004-04-24 03:25:25.000000000 +0000
+++ binutils-2.15.91-20040625/ld/testsuite/ld-mips-elf/mips-elf.exp 2004-06-26 13:29:09.000000000 +0000
@@ -74,3 +74,4 @@ if $has_newabi {
}
}
run_dump_test "reloc-2"
+run_dump_test "reloc-merge-lo16"
diff -up --recursive --new-file binutils-2.15.91-20040625.macro/ld/testsuite/ld-mips-elf/reloc-merge-lo16.d binutils-2.15.91-20040625/ld/testsuite/ld-mips-elf/reloc-merge-lo16.d
--- binutils-2.15.91-20040625.macro/ld/testsuite/ld-mips-elf/reloc-merge-lo16.d 1970-01-01 00:00:00.000000000 +0000
+++ binutils-2.15.91-20040625/ld/testsuite/ld-mips-elf/reloc-merge-lo16.d 2004-06-26 16:32:48.000000000 +0000
@@ -0,0 +1,17 @@
+#name: MIPS ELF lo16 merge
+#source: reloc-merge-lo16.s
+#as: -EL -32 -march=mips1
+#ld: -melf32ltsmip -Treloc-merge-lo16.ld
+#objdump: -td --prefix-addresses --show-raw-insn -mmips:3000
+
+# Test lo16 reloc calculation with string merging.
+
+.*: +file format .*mips.*
+#...
+0+80fe70 l .rodata 0+000000 g
+0+400000 g F .text 0+000000 __start
+#...
+0+400000 <[^>]*> 3c020081 lui v0,0x81
+0+400004 <[^>]*> 2443fe70 addiu v1,v0,-400
+0+400008 <[^>]*> 2442fe70 addiu v0,v0,-400
+ \.\.\.
diff -up --recursive --new-file binutils-2.15.91-20040625.macro/ld/testsuite/ld-mips-elf/reloc-merge-lo16.ld binutils-2.15.91-20040625/ld/testsuite/ld-mips-elf/reloc-merge-lo16.ld
--- binutils-2.15.91-20040625.macro/ld/testsuite/ld-mips-elf/reloc-merge-lo16.ld 1970-01-01 00:00:00.000000000 +0000
+++ binutils-2.15.91-20040625/ld/testsuite/ld-mips-elf/reloc-merge-lo16.ld 2004-06-26 13:17:38.000000000 +0000
@@ -0,0 +1,9 @@
+ENTRY(__start)
+SECTIONS
+{
+ . = 0x0400000;
+ .text : { *(.text) }
+ . = 0x0800000;
+ .rodata : { *(.rodata.*) }
+ /DISCARD/ : { *(*) }
+}
diff -up --recursive --new-file binutils-2.15.91-20040625.macro/ld/testsuite/ld-mips-elf/reloc-merge-lo16.s binutils-2.15.91-20040625/ld/testsuite/ld-mips-elf/reloc-merge-lo16.s
--- binutils-2.15.91-20040625.macro/ld/testsuite/ld-mips-elf/reloc-merge-lo16.s 1970-01-01 00:00:00.000000000 +0000
+++ binutils-2.15.91-20040625/ld/testsuite/ld-mips-elf/reloc-merge-lo16.s 2004-06-26 16:30:43.000000000 +0000
@@ -0,0 +1,28 @@
+ .section .rodata.str1.4,"aMS", @progbits, 1
+ .macro fillstr char
+ .rept 0x3fff - \char
+ .byte \char
+ .endr
+ .byte 0
+ .endm
+ fillstr 'a'
+ fillstr 'h'
+ fillstr 'c'
+ fillstr 'd'
+ fillstr 'g'
+ fillstr 'f'
+g:
+ fillstr 'g'
+ fillstr 'h'
+
+ .text
+ .globl __start
+ .ent __start
+ .type __start, @function
+__start:
+ lui $2, %hi(g)
+ addiu $3, $2, %lo(g)
+ addiu $2, $2, %lo(g)
+ .end __start
+
+ .space 16