From 7fc39194f8fb48914c995f8ec3826d50086f1ec0 Mon Sep 17 00:00:00 2001
From: Sterling Augustine <augustine.sterling@gmail.com>
Date: Tue, 25 Jan 2011 13:59:13 -0800
Subject: [PATCH] Fix 'call8: call target out of range' xtensa ld relaxation
 bug

During link-time relaxation distance between cross-section call site and
its target may grow, producing 'call target out of range' error for
relaxed calls. Be more conservative when calculating whether or not a
callx can be converted to a straight call.

2014-09-23  Sterling Augustine  <augustine.sterling@gmail.com>

bfd/
    * elf32-xtensa.c (is_resolvable_asm_expansion): for cross-section
    call relaxation use furthermost addresses where call source and
    destination can be to check whether it's in the range of a direct
    call.

Signed-off-by: Max Filippov <jcmvbkbc@gmail.com>
---
 bfd/elf32-xtensa.c | 41 +++++++++++++++++++++++++++++++++++++----
 1 file changed, 37 insertions(+), 4 deletions(-)

diff --git a/bfd/elf32-xtensa.c b/bfd/elf32-xtensa.c
index 09862e3..e32496a 100644
--- a/bfd/elf32-xtensa.c
+++ b/bfd/elf32-xtensa.c
@@ -7124,10 +7124,43 @@ is_resolvable_asm_expansion (bfd *abfd,
 	  || is_reloc_sym_weak (abfd, irel)))
     return FALSE;
 
-  self_address = (sec->output_section->vma
-		  + sec->output_offset + irel->r_offset + 3);
-  dest_address = (target_sec->output_section->vma
-		  + target_sec->output_offset + target_offset);
+  if (target_sec->output_section != sec->output_section)
+    {
+      /* If the two sections are sufficiently far away that relaxation
+	 might take the call out of range, we can't simplify.  For
+	 example, a positive displacement call into another memory
+	 could get moved to a lower address due to literal removal,
+	 but the destination won't move, and so the displacment might
+	 get larger.
+
+	 If the displacement is negative, assume the destination could
+	 move as far back as the start of the output section.  The
+	 self_address will be at least as far into the output section
+	 as it is prior to relaxation.
+
+	 If the displacement is postive, assume the destination will be in
+	 it's pre-relaxed location (because relaxation only makes sections
+	 smaller).  The self_address could go all the way to the beginning
+	 of the output section.  */
+
+      dest_address = target_sec->output_section->vma;
+      self_address = sec->output_section->vma;
+
+      if (sec->output_section->vma > target_sec->output_section->vma)
+	self_address += sec->output_offset + irel->r_offset + 3;
+      else
+	dest_address += bfd_get_section_limit (abfd, target_sec->output_section);
+      /* Call targets should be four-byte aligned.  */
+      dest_address = (dest_address + 3) & ~3;
+    }
+  else
+    {
+
+      self_address = (sec->output_section->vma
+		      + sec->output_offset + irel->r_offset + 3);
+      dest_address = (target_sec->output_section->vma
+		      + target_sec->output_offset + target_offset);
+    }
 
   *is_reachable_p = pcrel_reloc_fits (direct_call_opcode, 0,
 				      self_address, dest_address);
-- 
1.8.1.4

