This is the mail archive of the binutils-cvs@sourceware.org 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]

[binutils-gdb] MIPS/BFD: Enable local R_MIPS_26 overflow detection


https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=7743482350c9c97484a429070db7d994a643a9eb

commit 7743482350c9c97484a429070db7d994a643a9eb
Author: Maciej W. Rozycki <macro@imgtec.com>
Date:   Sat May 28 10:30:22 2016 +0100

    MIPS/BFD: Enable local R_MIPS_26 overflow detection
    
    The original MIPS SVR4 psABI defines the calculation for the R_MIPS_26
    relocation in a complex way, as follows[1]:
    
    Name        Value Field    Symbol   Calculation
    R_MIPS_26     4   T-targ26 local    (((A << 2) | \
                                          (P & 0xf0000000)) + S) >> 2
                  4   T-targ26 external (sign-extend(A << 2) + S) >> 2
    
    This is further clarified, by correcting typos (already applied in the
    excerpt above) in the 64-bit psABI extension[2].  A note is included in
    both documents to specify that for the purpose of relocation processing
    a local symbol is one with binding STB_LOCAL and type STT_SECTION, and
    otherwise, a symbol is external.
    
    We have both calculations implemented for the R_MIPS_26 relocation, and
    by extension also for the R_MIPS16_26 and R_MICROMIPS_26_S1 relocations,
    from now on collectively called jump relocations.  However our code uses
    a different condition to tell local and external symbols apart, that is
    it only checks for the STB_LOCAL binding and ignores the symbol type,
    however for REL relocations only.  The external calculation is used for
    all RELA jump relocations.
    
    In reality the difference matters for jump relocations referring local
    MIPS16 and, as from recent commit 44d3da233815 ("MIPS/GAS: Treat local
    jump relocs the same no matter if REL or RELA"), also local microMIPS
    symbols.  Such relocations are not converted to refer to corresponding
    section symbols instead and retain the original local symbol reference.
    
    It can be inferred from the relocation calculation definitions that the
    addend is effectively unsigned for the local case and explicitly signed
    for the external case.  With the REL relocation format it makes sense
    given the limited range provided for by the field being relocated: the
    use of an unsigned addend expands the range by one bit for the local
    case, because a negative offset from a section symbol makes no sense,
    and any usable negative offset from the original local symbol will have
    worked out positive if converted to a section-relative reference.  In
    the external case a signed addend gives more flexibility as offsets both
    negative and positive can be used with a symbol.  Any such offsets will
    typically have a small value.
    
    The inclusion of the (P & 0xf0000000) component, ORed in the calculation
    in the local case, seems questionable as bits 31:28 are not included in
    the relocatable field and are masked out as the relocation is applied.
    Their value is therefore irrelevant for output processing, the relocated
    field ends up the same regardless of their value.  They could be used
    for overflow detection, however this is precluded by adding them to bits
    31:28 of the symbol referred, as the sum will not correspond to the
    value calculated by the processor at run time whenever bits 31:28 of the
    symbol referred are not all zeros, even though it is valid as long they
    are the same as bits 31:28 of P.
    
    We deal with this problem by ignoring any overflow resulting from the
    local calculation.  This however makes us miss genuine overflow cases,
    where 31:28 of the symbol referred are different from bits 31:28 of P,
    and non-functional code is produced.
    
    Given the situation, for the purpose of overflow detection we can change
    our code to follow the original psABI and only treat the in-place addend
    as unsigned in the section symbol case, permitting jumps to offsets
    128MiB and above into section.  Sections so large may be uncommon, but
    still a reasonable use case.  On the other hand such large offsets from
    regular local symbols are not expected and it makes sense to support
    (possibly small) negative offsets instead, also in consistency with what
    we do for global symbols.
    
    Drop the (P & 0xf0000000) component then, treat the addend as signed
    with local non-section symbols and also detect an overflow in the result
    of such calculation with local symbols.  NB it does not affect the value
    computed for the relocatable field, it only affects overflow detection.
    
    References:
    
    [1] "SYSTEM V APPLICATION BINARY INTERFACE, MIPS RISC Processor
        Supplement, 3rd Edition", Figure 4-11: "Relocation Types", p. 4-19
        <http://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf>
    
    [2] "64-bit ELF Object File Specification, Draft Version 2.5", Table 32
        "Relocation Types", p. 45
        <http://techpubs.sgi.com/library/manuals/4000/007-4658-001/pdf/007-4658-001.pdf>
    
    	bfd/
    	* elfxx-mips.c (mips_elf_calculate_relocation): <R_MIPS16_26>
    	<R_MIPS_26, R_MICROMIPS_26_S1>: Drop the region bits of the
    	reloc location from calculation, treat the addend as signed with
    	local non-section symbols and enable overflow detection.
    
    	ld/
    	* testsuite/ld-mips-elf/jal-global-overflow-0.d: New test.
    	* testsuite/ld-mips-elf/jal-global-overflow-1.d: New test.
    	* testsuite/ld-mips-elf/jal-local-overflow-0.d: New test.
    	* testsuite/ld-mips-elf/jal-local-overflow-1.d: New test.
    	* testsuite/ld-mips-elf/jal-global-overflow.s: New test source.
    	* testsuite/ld-mips-elf/jal-local-overflow.s: New test source.
    	* testsuite/ld-mips-elf/mips-elf.exp: Run the new tests.

Diff:
---
 bfd/ChangeLog                                    |  7 +++++
 bfd/elfxx-mips.c                                 | 17 ++++++-----
 ld/ChangeLog                                     | 10 +++++++
 ld/testsuite/ld-mips-elf/jal-global-overflow-0.d | 20 +++++++++++++
 ld/testsuite/ld-mips-elf/jal-global-overflow-1.d |  8 +++++
 ld/testsuite/ld-mips-elf/jal-global-overflow.s   | 37 ++++++++++++++++++++++++
 ld/testsuite/ld-mips-elf/jal-local-overflow-0.d  |  6 ++++
 ld/testsuite/ld-mips-elf/jal-local-overflow-1.d  |  8 +++++
 ld/testsuite/ld-mips-elf/jal-local-overflow.s    | 35 ++++++++++++++++++++++
 ld/testsuite/ld-mips-elf/mips-elf.exp            |  6 ++++
 10 files changed, 146 insertions(+), 8 deletions(-)

diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index 4ce81a6..fa83823 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -1,3 +1,10 @@
+2016-05-28  Maciej W. Rozycki  <macro@imgtec.com>
+
+	* elfxx-mips.c (mips_elf_calculate_relocation): <R_MIPS16_26>
+	<R_MIPS_26, R_MICROMIPS_26_S1>: Drop the region bits of the
+	reloc location from calculation, treat the addend as signed with
+	local non-section symbols and enable overflow detection.
+
 2016-05-28  Alan Modra  <amodra@gmail.com>
 
 	* aoutx.h: Adjust linker callback calls throughout file,
diff --git a/bfd/elfxx-mips.c b/bfd/elfxx-mips.c
index 5143fcb..d519090 100644
--- a/bfd/elfxx-mips.c
+++ b/bfd/elfxx-mips.c
@@ -5247,6 +5247,9 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
   /* TRUE if the symbol referred to by this relocation is a local
      symbol.  */
   bfd_boolean local_p, was_local_p;
+  /* TRUE if the symbol referred to by this relocation is a section
+     symbol.  */
+  bfd_boolean section_p = FALSE;
   /* TRUE if the symbol referred to by this relocation is "_gp_disp".  */
   bfd_boolean gp_disp_p = FALSE;
   /* TRUE if the symbol referred to by this relocation is
@@ -5302,12 +5305,12 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
       sym = local_syms + r_symndx;
       sec = local_sections[r_symndx];
 
+      section_p = ELF_ST_TYPE (sym->st_info) == STT_SECTION;
+
       symbol = sec->output_section->vma + sec->output_offset;
-      if (ELF_ST_TYPE (sym->st_info) != STT_SECTION
-	  || (sec->flags & SEC_MERGE))
+      if (!section_p || (sec->flags & SEC_MERGE))
 	symbol += sym->st_value;
-      if ((sec->flags & SEC_MERGE)
-	  && ELF_ST_TYPE (sym->st_info) == STT_SECTION)
+      if ((sec->flags & SEC_MERGE) && section_p)
 	{
 	  addend = _bfd_elf_rel_local_sym (abfd, sym, &sec, addend);
 	  addend -= symbol;
@@ -5773,9 +5776,7 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
 	/* Shift is 2, unusually, for microMIPS JALX.  */
 	shift = (!*cross_mode_jump_p && r_type == R_MICROMIPS_26_S1) ? 1 : 2;
 
-	if (was_local_p)
-	  value = addend | ((p + 4) & (0xfc000000 << shift));
-	else if (howto->partial_inplace)
+	if (howto->partial_inplace && !section_p)
 	  value = _bfd_mips_elf_sign_extend (addend, 26 + shift);
 	else
 	  value = addend;
@@ -5787,7 +5788,7 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
 	  return bfd_reloc_outofrange;
 
 	value >>= shift;
-	if (!was_local_p && h->root.root.type != bfd_link_hash_undefweak)
+	if (was_local_p || h->root.root.type != bfd_link_hash_undefweak)
 	  overflowed_p = (value >> 26) != ((p + 4) >> (26 + shift));
 	value &= howto->dst_mask;
       }
diff --git a/ld/ChangeLog b/ld/ChangeLog
index fde9553..13fb745 100644
--- a/ld/ChangeLog
+++ b/ld/ChangeLog
@@ -1,3 +1,13 @@
+2016-05-28  Maciej W. Rozycki  <macro@imgtec.com>
+
+	* testsuite/ld-mips-elf/jal-global-overflow-0.d: New test.
+	* testsuite/ld-mips-elf/jal-global-overflow-1.d: New test.
+	* testsuite/ld-mips-elf/jal-local-overflow-0.d: New test.
+	* testsuite/ld-mips-elf/jal-local-overflow-1.d: New test.
+	* testsuite/ld-mips-elf/jal-global-overflow.s: New test source.
+	* testsuite/ld-mips-elf/jal-local-overflow.s: New test source.
+	* testsuite/ld-mips-elf/mips-elf.exp: Run the new tests.
+
 2016-05-28  Alan Modra  <amodra@gmail.com>
 
 	* ldmain.c (multiple_definition, multiple_common, add_to_set,
diff --git a/ld/testsuite/ld-mips-elf/jal-global-overflow-0.d b/ld/testsuite/ld-mips-elf/jal-global-overflow-0.d
new file mode 100644
index 0000000..f02bfea
--- /dev/null
+++ b/ld/testsuite/ld-mips-elf/jal-global-overflow-0.d
@@ -0,0 +1,20 @@
+#name: MIPS JAL to global symbol overflow 0
+#source: jal-global-overflow.s
+#as: -EB -32
+#ld: -EB -Ttext 0x20000000 -e 0x20000000
+#objdump: -dr --prefix-addresses --show-raw-insn
+
+.*: +file format .*mips.*
+
+Disassembly of section \.text:
+	\.\.\.
+[0-9a-f]+ <[^>]*> 0c001000 	jal	20004000 <bar>
+[0-9a-f]+ <[^>]*> 00000027 	nor	zero,zero,zero
+[0-9a-f]+ <[^>]*> 0c000800 	jal	20002000 <foo>
+[0-9a-f]+ <[^>]*> 00000027 	nor	zero,zero,zero
+	\.\.\.
+[0-9a-f]+ <[^>]*> 0c000800 	jal	20002000 <foo>
+[0-9a-f]+ <[^>]*> 00000027 	nor	zero,zero,zero
+[0-9a-f]+ <[^>]*> 0c001000 	jal	20004000 <bar>
+[0-9a-f]+ <[^>]*> 00000027 	nor	zero,zero,zero
+	\.\.\.
diff --git a/ld/testsuite/ld-mips-elf/jal-global-overflow-1.d b/ld/testsuite/ld-mips-elf/jal-global-overflow-1.d
new file mode 100644
index 0000000..da6e750
--- /dev/null
+++ b/ld/testsuite/ld-mips-elf/jal-global-overflow-1.d
@@ -0,0 +1,8 @@
+#name: MIPS JAL to global symbol overflow 1
+#source: jal-global-overflow.s
+#as: -EB -32
+#ld: -EB -Ttext 0x1fffd000 -e 0x1fffd000
+#error: \A[^\n]*: In function `foo':\n
+#error:   \(\.text\+0x2000\): relocation truncated to fit: R_MIPS_26 against `abar'\n
+#error:   [^\n]*: In function `bar':\n
+#error:   \(\.text\+0x4000\): relocation truncated to fit: R_MIPS_26 against `afoo'\Z
diff --git a/ld/testsuite/ld-mips-elf/jal-global-overflow.s b/ld/testsuite/ld-mips-elf/jal-global-overflow.s
new file mode 100644
index 0000000..a67d0bf
--- /dev/null
+++ b/ld/testsuite/ld-mips-elf/jal-global-overflow.s
@@ -0,0 +1,37 @@
+	.text
+	.set	noreorder
+	.org	0x2000
+
+	.align	4
+	.globl	foo
+	.ent	foo
+foo:
+	jal	abar - 8
+	 nor	$0, $0
+
+	.globl	afoo
+	.aent	afoo
+afoo:
+	jal	afoo - 8
+	 nor	$0, $0
+	.end	foo
+
+	.org	0x4000
+
+	.align	4
+	.globl	bar
+	.ent	bar
+bar:
+	jal	afoo - 8
+	 nor	$0, $0
+
+	.globl	abar
+	.aent	abar
+abar:
+	jal	abar - 8
+	 nor	$0, $0
+	.end	bar
+
+# Force some (non-delay-slot) zero bytes, to make 'objdump' print ...
+	.align	4, 0
+	.space	16
diff --git a/ld/testsuite/ld-mips-elf/jal-local-overflow-0.d b/ld/testsuite/ld-mips-elf/jal-local-overflow-0.d
new file mode 100644
index 0000000..592b2ae
--- /dev/null
+++ b/ld/testsuite/ld-mips-elf/jal-local-overflow-0.d
@@ -0,0 +1,6 @@
+#name: MIPS JAL to local symbol overflow 0
+#source: jal-local-overflow.s
+#as: -EB -32
+#ld: -EB -Ttext 0x20000000 -e 0x20000000
+#objdump: -dr --prefix-addresses --show-raw-insn
+#dump: jal-global-overflow-0.d
diff --git a/ld/testsuite/ld-mips-elf/jal-local-overflow-1.d b/ld/testsuite/ld-mips-elf/jal-local-overflow-1.d
new file mode 100644
index 0000000..869df0e
--- /dev/null
+++ b/ld/testsuite/ld-mips-elf/jal-local-overflow-1.d
@@ -0,0 +1,8 @@
+#name: MIPS JAL to local symbol overflow 1
+#source: jal-local-overflow.s
+#as: -EB -32
+#ld: -EB -Ttext 0x1fffd000 -e 0x1fffd000
+#error: \A[^\n]*: In function `foo':\n
+#error:   \(\.text\+0x2000\): relocation truncated to fit: R_MIPS_26 against `.text'\n
+#error:   [^\n]*: In function `bar':\n
+#error:   \(\.text\+0x4000\): relocation truncated to fit: R_MIPS_26 against `.text'\Z
diff --git a/ld/testsuite/ld-mips-elf/jal-local-overflow.s b/ld/testsuite/ld-mips-elf/jal-local-overflow.s
new file mode 100644
index 0000000..9b22f67
--- /dev/null
+++ b/ld/testsuite/ld-mips-elf/jal-local-overflow.s
@@ -0,0 +1,35 @@
+	.text
+	.set	noreorder
+	.org	0x2000
+
+	.align	4
+	.globl	foo
+	.ent	foo
+foo:
+	jal	abar - 8
+	 nor	$0, $0
+
+	.aent	afoo
+afoo:
+	jal	afoo - 8
+	 nor	$0, $0
+	.end	foo
+
+	.org	0x4000
+
+	.align	4
+	.globl	bar
+	.ent	bar
+bar:
+	jal	afoo - 8
+	 nor	$0, $0
+
+	.aent	abar
+abar:
+	jal	abar - 8
+	 nor	$0, $0
+	.end	bar
+
+# Force some (non-delay-slot) zero bytes, to make 'objdump' print ...
+	.align	4, 0
+	.space	16
diff --git a/ld/testsuite/ld-mips-elf/mips-elf.exp b/ld/testsuite/ld-mips-elf/mips-elf.exp
index 3fa151a..f8c8b09 100644
--- a/ld/testsuite/ld-mips-elf/mips-elf.exp
+++ b/ld/testsuite/ld-mips-elf/mips-elf.exp
@@ -493,6 +493,12 @@ if {$linux_gnu} {
 
 run_dump_test "jaloverflow"
 run_dump_test "jaloverflow-2"
+
+run_dump_test "jal-global-overflow-0" [list [list ld $abi_ldflags(o32)]]
+run_dump_test "jal-global-overflow-1" [list [list ld $abi_ldflags(o32)]]
+run_dump_test "jal-local-overflow-0" [list [list ld $abi_ldflags(o32)]]
+run_dump_test "jal-local-overflow-1" [list [list ld $abi_ldflags(o32)]]
+
 run_dump_test "undefweak-overflow" [list [list as $abi_asflags(o32)] \
 					 [list ld $abi_ldflags(o32)]]


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