Fix 'call8: call target out of range' xtensa ld relaxation bug
authorSterling Augustine <augustine.sterling@gmail.com>
Tue, 25 Jan 2011 21:59:13 +0000 (13:59 -0800)
committerMax Filippov <jcmvbkbc@gmail.com>
Mon, 22 Sep 2014 23:41:35 +0000 (03:41 +0400)
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.

bfd/ChangeLog
bfd/elf32-xtensa.c

index 2fc0e1e977652f782ee4f85e15818f56310a6bf0..d8559ea30c20221183be1d6afa46c24aabb49318 100644 (file)
@@ -1,3 +1,10 @@
+2014-09-23  Sterling Augustine  <augustine.sterling@gmail.com>
+
+       * 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.
+
 2014-09-22  Alan Modra  <amodra@gmail.com>
 
        * elf-eh-frame.c (_bfd_elf_write_section_eh_frame_hdr): Don't return
index 09862e3c2ca876ca23ebcc3a405788819763f837..e32496aa0c345b85ba2a518d6fe327f296c0a9df 100644 (file)
@@ -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);