This is the mail archive of the binutils@sources.redhat.com 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: 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


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