2010-03-22 Doug Kwan <dougkwan@google.com>
authorDoug Kwan <dougkwan@google.com>
Mon, 22 Mar 2010 22:48:05 +0000 (22:48 +0000)
committerDoug Kwan <dougkwan@google.com>
Mon, 22 Mar 2010 22:48:05 +0000 (22:48 +0000)
* arm.cc (Arm_relocate_functions::abs8,
Arm_relocate_functions::abs16): Use correct check for overflow
specified in the ARM ELF specs.
(Arm_relocate_functions): thumb_branch_common.  Handle bit 1 of branch
target of a BLX instruction specially.
(Reloc_stub::stub_type_for_reloc): Ditto.
(Relocate::relocate): Use symbolic names instead of numeric relocation
codes to report error.
(Target_arm::do_relox): Reduce default stub-group size for Cortex-A8
workaround.
* testsuite/Makefile.am (check_DATA): add thumb_blx_in_range.stdout,
thumb_blx_out_of_range.stdout, thumb2_blx_in_range.stdout and
thumb2_blx_out_of_range.stdout
(thumb_bl_out_of_range, thumb_bl_out_of_range.o,
thumb2_bl_out_of_range, thumb2_bl_out_of_range.o): Fix dependenices.
(thumb_blx_in_range.stdout, thumb_blx_in_range, thumb_blx_in_range.o,
thumb_blx_out_of_range.stdout, thumb_blx_out_of_range,
thumb_blx_out_of_range.o, thumb2_blx_in_range.stdout,
thumb2_blx_in_range, thumb2_blx_in_range.o,
thumb2_blx_out_of_range.stdout, thumb2_blx_out_of_range,
thumb2_blx_out_of_range.o): New rules.
  (MOSTLYCLEANFILES): Add thumb_blx_in_range, thumb_blx_out_of_range,
thumb2_blx_in_range and thumb2_blx_out_of_range.
* testsuite/Makefile.in: Regenerate.
* arm_branch_in_range.sh: Add tests for THUMB BLX.
* testsuite/thumb_blx_in_range.s: New file.
* testsuite/thumb_blx_out_of_range.s: New file.

gold/ChangeLog
gold/arm.cc
gold/testsuite/Makefile.am
gold/testsuite/Makefile.in
gold/testsuite/arm_branch_in_range.sh
gold/testsuite/thumb_blx_in_range.s [new file with mode: 0644]
gold/testsuite/thumb_blx_out_of_range.s [new file with mode: 0644]

index f3d475a79010a286131e120733657bb404ea282b..1f24452c0922c8c636d0b71f7576561cdf6cbcd6 100644 (file)
@@ -1,3 +1,33 @@
+2010-03-22  Doug Kwan  <dougkwan@google.com>
+
+       * arm.cc (Arm_relocate_functions::abs8,
+       Arm_relocate_functions::abs16): Use correct check for overflow
+       specified in the ARM ELF specs.
+       (Arm_relocate_functions): thumb_branch_common.  Handle bit 1 of branch
+       target of a BLX instruction specially.
+       (Reloc_stub::stub_type_for_reloc): Ditto.
+       (Relocate::relocate): Use symbolic names instead of numeric relocation
+       codes to report error.
+       (Target_arm::do_relox): Reduce default stub-group size for Cortex-A8
+       workaround.
+       * testsuite/Makefile.am (check_DATA): add thumb_blx_in_range.stdout,
+       thumb_blx_out_of_range.stdout, thumb2_blx_in_range.stdout and
+       thumb2_blx_out_of_range.stdout
+       (thumb_bl_out_of_range, thumb_bl_out_of_range.o,
+       thumb2_bl_out_of_range, thumb2_bl_out_of_range.o): Fix dependenices.
+       (thumb_blx_in_range.stdout, thumb_blx_in_range, thumb_blx_in_range.o,
+       thumb_blx_out_of_range.stdout, thumb_blx_out_of_range,
+       thumb_blx_out_of_range.o, thumb2_blx_in_range.stdout,
+       thumb2_blx_in_range, thumb2_blx_in_range.o,
+       thumb2_blx_out_of_range.stdout, thumb2_blx_out_of_range,
+       thumb2_blx_out_of_range.o): New rules.
+       (MOSTLYCLEANFILES): Add thumb_blx_in_range, thumb_blx_out_of_range,
+       thumb2_blx_in_range and thumb2_blx_out_of_range.
+       * testsuite/Makefile.in: Regenerate.
+       * arm_branch_in_range.sh: Add tests for THUMB BLX.
+       * testsuite/thumb_blx_in_range.s: New file.
+       * testsuite/thumb_blx_out_of_range.s: New file.
+
 2010-03-22  Rafael Espindola  <espindola@google.com>
 
        * archive.cc (Should_include): Move to archive.h.
index 016b2cce3b580f674649ae5071884749289c2b22..890646e7ba25efd04f2538cb435e9b3abcf66b41 100644 (file)
@@ -2985,7 +2985,10 @@ class Arm_relocate_functions : public Relocate_functions<32, big_endian>
     Reltype x = psymval->value(object, addend);
     val = utils::bit_select(val, x, 0xffU);
     elfcpp::Swap<8, big_endian>::writeval(wv, val);
-    return (utils::has_signed_unsigned_overflow<8>(x)
+
+    // R_ARM_ABS8 permits signed or unsigned results.
+    int signed_x = static_cast<int32_t>(x);
+    return ((signed_x < -128 || signed_x > 255)
            ? This::STATUS_OVERFLOW
            : This::STATUS_OKAY);
   }
@@ -3004,7 +3007,10 @@ class Arm_relocate_functions : public Relocate_functions<32, big_endian>
     Reltype x = psymval->value(object, addend);
     val = utils::bit_select(val, x << 6, 0x7e0U);
     elfcpp::Swap<16, big_endian>::writeval(wv, val);
-    return (utils::has_overflow<5>(x)
+
+    // R_ARM_ABS16 permits signed or unsigned results.
+    int signed_x = static_cast<int32_t>(x);
+    return ((signed_x < -32768 || signed_x > 65535)
            ? This::STATUS_OVERFLOW
            : This::STATUS_OKAY);
   }
@@ -3831,11 +3837,16 @@ Arm_relocate_functions<big_endian>::thumb_branch_common(
  
   int32_t addend = This::thumb32_branch_offset(upper_insn, lower_insn);
   Arm_address branch_target = psymval->value(object, addend);
+
+  // For BLX, bit 1 of target address comes from bit 1 of base address.
+  bool may_use_blx = arm_target->may_use_blx();
+  if (thumb_bit == 0 && may_use_blx)
+    branch_target = utils::bit_select(branch_target, address, 0x2);
+
   int32_t branch_offset = branch_target - address;
 
   // We need a stub if the branch offset is too large or if we need
   // to switch mode.
-  bool may_use_blx = arm_target->may_use_blx();
   bool thumb2 = arm_target->using_thumb2();
   if ((!thumb2 && utils::has_overflow<23>(branch_offset))
       || (thumb2 && utils::has_overflow<25>(branch_offset))
@@ -3861,6 +3872,8 @@ Arm_relocate_functions<big_endian>::thumb_branch_common(
          gold_assert(stub != NULL);
          thumb_bit = stub->stub_template()->entry_in_thumb_mode() ? 1 : 0;
          branch_target = stub_table->address() + stub->offset() + addend;
+         if (thumb_bit == 0 && may_use_blx) 
+           branch_target = utils::bit_select(branch_target, address, 0x2);
          branch_offset = branch_target - address;
        }
     }
@@ -3881,12 +3894,12 @@ Arm_relocate_functions<big_endian>::thumb_branch_common(
       lower_insn |= 0x1000U;
     }
 
+  // For a BLX instruction, make sure that the relocation is rounded up
+  // to a word boundary.  This follows the semantics of the instruction
+  // which specifies that bit 1 of the target address will come from bit
+  // 1 of the base address.
   if ((lower_insn & 0x5000U) == 0x4000U)
-    // For a BLX instruction, make sure that the relocation is rounded up
-    // to a word boundary.  This follows the semantics of the instruction
-    // which specifies that bit 1 of the target address will come from bit
-    // 1 of the base address.
-    branch_offset = (branch_offset + 2) & ~3;
+    gold_assert((branch_offset & 3) == 0);
 
   // Put BRANCH_OFFSET back into the insn.  Assumes two's complement.
   // We use the Thumb-2 encoding, which is safe even if dealing with
@@ -3897,6 +3910,8 @@ Arm_relocate_functions<big_endian>::thumb_branch_common(
   elfcpp::Swap<16, big_endian>::writeval(wv, upper_insn);
   elfcpp::Swap<16, big_endian>::writeval(wv + 1, lower_insn);
 
+  gold_assert(!utils::has_overflow<25>(branch_offset));
+
   return ((thumb2
           ? utils::has_overflow<25>(branch_offset)
           : utils::has_overflow<23>(branch_offset))
@@ -4225,10 +4240,15 @@ Reloc_stub::stub_type_for_reloc(
       thumb_only = little_endian_target->using_thumb_only();
     }
 
-  int64_t branch_offset = (int64_t)destination - location;
-
+  int64_t branch_offset;
   if (r_type == elfcpp::R_ARM_THM_CALL || r_type == elfcpp::R_ARM_THM_JUMP24)
     {
+      // For THUMB BLX instruction, bit 1 of target comes from bit 1 of the
+      // base address (instruction address + 4).
+      if ((r_type == elfcpp::R_ARM_THM_CALL) && may_use_blx && !target_is_thumb)
+       destination = utils::bit_select(destination, location, 0x2);
+      branch_offset = static_cast<int64_t>(destination) - location;
+       
       // Handle cases where:
       // - this call goes too far (different Thumb/Thumb2 max
       //   distance)
@@ -4309,6 +4329,7 @@ Reloc_stub::stub_type_for_reloc(
           || r_type == elfcpp::R_ARM_JUMP24
           || r_type == elfcpp::R_ARM_PLT32)
     {
+      branch_offset = static_cast<int64_t>(destination) - location;
       if (target_is_thumb)
        {
          // Arm to thumb.
@@ -8562,16 +8583,16 @@ Target_arm<big_endian>::Relocate::relocate(
       break;
     case Arm_relocate_functions::STATUS_OVERFLOW:
       gold_error_at_location(relinfo, relnum, rel.get_r_offset(),
-                            _("relocation overflow in relocation %u"),
-                            r_type);
+                            _("relocation overflow in %s"),
+                            reloc_property->name().c_str());
       break;
     case Arm_relocate_functions::STATUS_BAD_RELOC:
       gold_error_at_location(
        relinfo,
        relnum,
        rel.get_r_offset(),
-       _("unexpected opcode while processing relocation %u"),
-       r_type);
+       _("unexpected opcode while processing relocation %s"),
+       reloc_property->name().c_str());
       break;
     default:
       gold_unreachable();
@@ -10297,13 +10318,18 @@ Target_arm<big_endian>::do_relax(
          // Default value.
          // Thumb branch range is +-4MB has to be used as the default
          // maximum size (a given section can contain both ARM and Thumb
-         // code, so the worst case has to be taken into account).
+         // code, so the worst case has to be taken into account).  If we are
+         // fixing cortex-a8 errata, the branch range has to be even smaller,
+         // since wide conditional branch has a range of +-1MB only.
          //
          // This value is 24K less than that, which allows for 2025
          // 12-byte stubs.  If we exceed that, then we will fail to link.
          // The user will have to relink with an explicit group size
          // option.
-         stub_group_size = 4170000;
+         if (this->fix_cortex_a8_)
+           stub_group_size = 1024276;
+         else
+           stub_group_size = 4170000;
        }
 
       group_sections(layout, stub_group_size, stubs_always_after_branch);
index a083bc4a017c477b7a1b020604e83f3cc0cb7038..b115283c493df5aab931973facf2c9aaefae15a1 100644 (file)
@@ -1488,7 +1488,9 @@ MOSTLYCLEANFILES += arm_abs_global
 check_SCRIPTS += arm_branch_in_range.sh
 check_DATA += arm_bl_in_range.stdout arm_bl_out_of_range.stdout \
        thumb_bl_in_range.stdout thumb_bl_out_of_range.stdout \
-       thumb2_bl_in_range.stdout thumb2_bl_out_of_range.stdout
+       thumb2_bl_in_range.stdout thumb2_bl_out_of_range.stdout \
+       thumb_blx_in_range.stdout thumb_blx_out_of_range.stdout \
+       thumb2_blx_in_range.stdout thumb2_blx_out_of_range.stdout
 
 arm_bl_in_range.stdout: arm_bl_in_range
        $(TEST_OBJDUMP) -D $< > $@
@@ -1520,10 +1522,10 @@ thumb_bl_in_range.o: thumb_bl_in_range.s
 thumb_bl_out_of_range.stdout: thumb_bl_out_of_range
        $(TEST_OBJDUMP) -D $< > $@
 
-thumb_bl_out_of_range: thumb_bl_in_range.o ../ld-new
+thumb_bl_out_of_range: thumb_bl_out_of_range.o ../ld-new
        ../ld-new -T $(srcdir)/thumb_branch_range.t -o $@ $<
 
-thumb_bl_out_of_range.o: thumb_bl_in_range.s
+thumb_bl_out_of_range.o: thumb_bl_out_of_range.s
        $(TEST_AS) -o $@ -march=armv5te $<
 
 thumb2_bl_in_range.stdout: thumb2_bl_in_range
@@ -1538,14 +1540,52 @@ thumb2_bl_in_range.o: thumb_bl_in_range.s
 thumb2_bl_out_of_range.stdout: thumb2_bl_out_of_range
        $(TEST_OBJDUMP) -D $< > $@
 
-thumb2_bl_out_of_range: thumb2_bl_in_range.o ../ld-new
+thumb2_bl_out_of_range: thumb2_bl_out_of_range.o ../ld-new
        ../ld-new -T $(srcdir)/thumb2_branch_range.t -o $@ $<
 
-thumb2_bl_out_of_range.o: thumb_bl_in_range.s
+thumb2_bl_out_of_range.o: thumb_bl_out_of_range.s
+       $(TEST_AS) -o $@ -march=armv7-a $<
+
+thumb_blx_in_range.stdout: thumb_blx_in_range
+       $(TEST_OBJDUMP) -D $< > $@
+
+thumb_blx_in_range: thumb_blx_in_range.o ../ld-new
+       ../ld-new -T $(srcdir)/thumb_branch_range.t -o $@ $<
+
+thumb_blx_in_range.o: thumb_blx_in_range.s
+       $(TEST_AS) -o $@ -march=armv5te $<
+
+thumb_blx_out_of_range.stdout: thumb_blx_out_of_range
+       $(TEST_OBJDUMP) -D $< > $@
+
+thumb_blx_out_of_range: thumb_blx_out_of_range.o ../ld-new
+       ../ld-new -T $(srcdir)/thumb_branch_range.t -o $@ $<
+
+thumb_blx_out_of_range.o: thumb_blx_out_of_range.s
+       $(TEST_AS) -o $@ -march=armv5te $<
+
+thumb2_blx_in_range.stdout: thumb2_blx_in_range
+       $(TEST_OBJDUMP) -D $< > $@
+
+thumb2_blx_in_range: thumb2_blx_in_range.o ../ld-new
+       ../ld-new -T $(srcdir)/thumb2_branch_range.t -o $@ $<
+
+thumb2_blx_in_range.o: thumb_blx_in_range.s
+       $(TEST_AS) -o $@ -march=armv7-a $<
+
+thumb2_blx_out_of_range.stdout: thumb2_blx_out_of_range
+       $(TEST_OBJDUMP) -D $< > $@
+
+thumb2_blx_out_of_range: thumb2_blx_out_of_range.o ../ld-new
+       ../ld-new -T $(srcdir)/thumb2_branch_range.t -o $@ $<
+
+thumb2_blx_out_of_range.o: thumb_blx_out_of_range.s
        $(TEST_AS) -o $@ -march=armv7-a $<
 
 MOSTLYCLEANFILES += arm_bl_in_range arm_bl_out_of_range thumb_bl_in_range \
-       thumb_bl_out_of_range thumb2_bl_in_range thumb2_bl_out_of_range
+       thumb_bl_out_of_range thumb2_bl_in_range thumb2_bl_out_of_range \
+       thumb_blx_in_range thumb_blx_out_of_range thumb2_blx_in_range \
+       thumb2_blx_out_of_range
 
 check_SCRIPTS += arm_fix_v4bx.sh
 check_DATA += arm_fix_v4bx.stdout arm_fix_v4bx_interworking.stdout \
index d21b32be7df4aede808593624d11d77f5d6eadb8..061c627862c979e896b4135724296a0fa29eddaf 100644 (file)
@@ -338,6 +338,10 @@ check_PROGRAMS = object_unittest$(EXEEXT) binary_unittest$(EXEEXT) \
 @DEFAULT_TARGET_ARM_TRUE@      thumb_bl_out_of_range.stdout \
 @DEFAULT_TARGET_ARM_TRUE@      thumb2_bl_in_range.stdout \
 @DEFAULT_TARGET_ARM_TRUE@      thumb2_bl_out_of_range.stdout \
+@DEFAULT_TARGET_ARM_TRUE@      thumb_blx_in_range.stdout \
+@DEFAULT_TARGET_ARM_TRUE@      thumb_blx_out_of_range.stdout \
+@DEFAULT_TARGET_ARM_TRUE@      thumb2_blx_in_range.stdout \
+@DEFAULT_TARGET_ARM_TRUE@      thumb2_blx_out_of_range.stdout \
 @DEFAULT_TARGET_ARM_TRUE@      arm_fix_v4bx.stdout \
 @DEFAULT_TARGET_ARM_TRUE@      arm_fix_v4bx_interworking.stdout \
 @DEFAULT_TARGET_ARM_TRUE@      arm_no_fix_v4bx.stdout
@@ -346,7 +350,11 @@ check_PROGRAMS = object_unittest$(EXEEXT) binary_unittest$(EXEEXT) \
 @DEFAULT_TARGET_ARM_TRUE@      thumb_bl_in_range \
 @DEFAULT_TARGET_ARM_TRUE@      thumb_bl_out_of_range \
 @DEFAULT_TARGET_ARM_TRUE@      thumb2_bl_in_range \
-@DEFAULT_TARGET_ARM_TRUE@      thumb2_bl_out_of_range arm_fix_v4bx \
+@DEFAULT_TARGET_ARM_TRUE@      thumb2_bl_out_of_range \
+@DEFAULT_TARGET_ARM_TRUE@      thumb_blx_in_range \
+@DEFAULT_TARGET_ARM_TRUE@      thumb_blx_out_of_range \
+@DEFAULT_TARGET_ARM_TRUE@      thumb2_blx_in_range \
+@DEFAULT_TARGET_ARM_TRUE@      thumb2_blx_out_of_range arm_fix_v4bx \
 @DEFAULT_TARGET_ARM_TRUE@      arm_fix_v4bx_interworking \
 @DEFAULT_TARGET_ARM_TRUE@      arm_no_fix_v4bx
 subdir = testsuite
@@ -3288,10 +3296,10 @@ uninstall-am:
 @DEFAULT_TARGET_ARM_TRUE@thumb_bl_out_of_range.stdout: thumb_bl_out_of_range
 @DEFAULT_TARGET_ARM_TRUE@      $(TEST_OBJDUMP) -D $< > $@
 
-@DEFAULT_TARGET_ARM_TRUE@thumb_bl_out_of_range: thumb_bl_in_range.o ../ld-new
+@DEFAULT_TARGET_ARM_TRUE@thumb_bl_out_of_range: thumb_bl_out_of_range.o ../ld-new
 @DEFAULT_TARGET_ARM_TRUE@      ../ld-new -T $(srcdir)/thumb_branch_range.t -o $@ $<
 
-@DEFAULT_TARGET_ARM_TRUE@thumb_bl_out_of_range.o: thumb_bl_in_range.s
+@DEFAULT_TARGET_ARM_TRUE@thumb_bl_out_of_range.o: thumb_bl_out_of_range.s
 @DEFAULT_TARGET_ARM_TRUE@      $(TEST_AS) -o $@ -march=armv5te $<
 
 @DEFAULT_TARGET_ARM_TRUE@thumb2_bl_in_range.stdout: thumb2_bl_in_range
@@ -3306,10 +3314,46 @@ uninstall-am:
 @DEFAULT_TARGET_ARM_TRUE@thumb2_bl_out_of_range.stdout: thumb2_bl_out_of_range
 @DEFAULT_TARGET_ARM_TRUE@      $(TEST_OBJDUMP) -D $< > $@
 
-@DEFAULT_TARGET_ARM_TRUE@thumb2_bl_out_of_range: thumb2_bl_in_range.o ../ld-new
+@DEFAULT_TARGET_ARM_TRUE@thumb2_bl_out_of_range: thumb2_bl_out_of_range.o ../ld-new
 @DEFAULT_TARGET_ARM_TRUE@      ../ld-new -T $(srcdir)/thumb2_branch_range.t -o $@ $<
 
-@DEFAULT_TARGET_ARM_TRUE@thumb2_bl_out_of_range.o: thumb_bl_in_range.s
+@DEFAULT_TARGET_ARM_TRUE@thumb2_bl_out_of_range.o: thumb_bl_out_of_range.s
+@DEFAULT_TARGET_ARM_TRUE@      $(TEST_AS) -o $@ -march=armv7-a $<
+
+@DEFAULT_TARGET_ARM_TRUE@thumb_blx_in_range.stdout: thumb_blx_in_range
+@DEFAULT_TARGET_ARM_TRUE@      $(TEST_OBJDUMP) -D $< > $@
+
+@DEFAULT_TARGET_ARM_TRUE@thumb_blx_in_range: thumb_blx_in_range.o ../ld-new
+@DEFAULT_TARGET_ARM_TRUE@      ../ld-new -T $(srcdir)/thumb_branch_range.t -o $@ $<
+
+@DEFAULT_TARGET_ARM_TRUE@thumb_blx_in_range.o: thumb_blx_in_range.s
+@DEFAULT_TARGET_ARM_TRUE@      $(TEST_AS) -o $@ -march=armv5te $<
+
+@DEFAULT_TARGET_ARM_TRUE@thumb_blx_out_of_range.stdout: thumb_blx_out_of_range
+@DEFAULT_TARGET_ARM_TRUE@      $(TEST_OBJDUMP) -D $< > $@
+
+@DEFAULT_TARGET_ARM_TRUE@thumb_blx_out_of_range: thumb_blx_out_of_range.o ../ld-new
+@DEFAULT_TARGET_ARM_TRUE@      ../ld-new -T $(srcdir)/thumb_branch_range.t -o $@ $<
+
+@DEFAULT_TARGET_ARM_TRUE@thumb_blx_out_of_range.o: thumb_blx_out_of_range.s
+@DEFAULT_TARGET_ARM_TRUE@      $(TEST_AS) -o $@ -march=armv5te $<
+
+@DEFAULT_TARGET_ARM_TRUE@thumb2_blx_in_range.stdout: thumb2_blx_in_range
+@DEFAULT_TARGET_ARM_TRUE@      $(TEST_OBJDUMP) -D $< > $@
+
+@DEFAULT_TARGET_ARM_TRUE@thumb2_blx_in_range: thumb2_blx_in_range.o ../ld-new
+@DEFAULT_TARGET_ARM_TRUE@      ../ld-new -T $(srcdir)/thumb2_branch_range.t -o $@ $<
+
+@DEFAULT_TARGET_ARM_TRUE@thumb2_blx_in_range.o: thumb_blx_in_range.s
+@DEFAULT_TARGET_ARM_TRUE@      $(TEST_AS) -o $@ -march=armv7-a $<
+
+@DEFAULT_TARGET_ARM_TRUE@thumb2_blx_out_of_range.stdout: thumb2_blx_out_of_range
+@DEFAULT_TARGET_ARM_TRUE@      $(TEST_OBJDUMP) -D $< > $@
+
+@DEFAULT_TARGET_ARM_TRUE@thumb2_blx_out_of_range: thumb2_blx_out_of_range.o ../ld-new
+@DEFAULT_TARGET_ARM_TRUE@      ../ld-new -T $(srcdir)/thumb2_branch_range.t -o $@ $<
+
+@DEFAULT_TARGET_ARM_TRUE@thumb2_blx_out_of_range.o: thumb_blx_out_of_range.s
 @DEFAULT_TARGET_ARM_TRUE@      $(TEST_AS) -o $@ -march=armv7-a $<
 
 @DEFAULT_TARGET_ARM_TRUE@arm_fix_v4bx.stdout: arm_fix_v4bx
index b676770013fcd647f8c7baf832ab06c685a60bc3..43b50c6a1fdc691287fc70bcfb00aa3feb151273 100755 (executable)
@@ -53,5 +53,12 @@ check thumb2_bl_in_range.stdout \
  " 2000004:    f400 d000       bl      1000008 <_backward_target>"
 check thumb2_bl_in_range.stdout \
  " 2000008:    f3ff d7ff       bl      300000a <_forward_target>"
-
+check thumb_blx_in_range.stdout \
+ " 800006:     f400 e800       blx     400008 <_backward_target>"
+check thumb_blx_in_range.stdout \
+ " 80000c:     f3ff effe       blx     c0000c <_forward_target>"
+check thumb2_blx_in_range.stdout \
+ " 2000006:    f400 c000       blx     1000008 <_backward_target>"
+check thumb2_blx_in_range.stdout \
+ " 200000c:    f3ff c7fe       blx     300000c <_forward_target>"
 exit 0
diff --git a/gold/testsuite/thumb_blx_in_range.s b/gold/testsuite/thumb_blx_in_range.s
new file mode 100644 (file)
index 0000000..bd2d060
--- /dev/null
@@ -0,0 +1,64 @@
+# thumb_blx_in_range.s
+#
+# Test THUMB/THUMB-2 blx instructions just within the branch range limits.
+# Because bit 1 of the branch target comes from the branch instruction
+# address, the branch range from PC (branch instruction address + 4) is
+# acutally -((1<<22) + 2) to ((1<<22) - 4) for THUMB and -((1<<24) + 2) to
+# ((1<<24) - 4) from THUMB2.
+
+       .syntax unified
+       .section        .text.pre,"x"
+
+# Add padding so that target is just in branch range. 
+       .space  8
+
+       .align  2
+       .global _backward_target
+       .code   32
+       .type   _backword_target, %function
+_backward_target:
+       bx      lr
+       .size   _backward_target, .-_backward_target
+       
+       .text
+
+# Define _start so that linker does not complain.
+       .global _start
+       .code   32
+       .align  2
+       .type   _start, %function
+_start:
+       bx      lr
+       .size   _start, .-_start
+
+       .global _backward_test
+       .code   16
+       .thumb_func
+       .type   _backward_test, %function
+_backward_test:
+       nop.n
+       blx     _backward_target
+       .size   _backward_test, .-_backward_test
+
+       .align  2
+       .global _forward_test
+       .code   16
+       .thumb_func
+       .type   _forward_test, %function
+_forward_test:
+       blx     _forward_target
+       .size   _forward_test, .-_forward_test
+       .code   32
+       
+       .section        .text.post,"x"
+
+# Add padding so that target is just in branch range. 
+       .space  12
+
+       .align  2
+       .global _forward_target
+       .code   32
+       .type   _forward_target, %function
+_forward_target:
+       bx      lr
+       .size   _forward_target, .-_forward_target
diff --git a/gold/testsuite/thumb_blx_out_of_range.s b/gold/testsuite/thumb_blx_out_of_range.s
new file mode 100644 (file)
index 0000000..fc5beb5
--- /dev/null
@@ -0,0 +1,61 @@
+# thumb_blx_out_of_range.s
+# Test THUMB/THUMB-2 blx instructions just out of the branch range limits.
+       .syntax unified
+
+       .section        .text.pre,"x"
+
+# Add padding so that target is just output of branch range. 
+       .space  6
+
+       .global _forward_target
+       .global _backward_target
+       .type   _backword_target, %function
+_backward_target:
+       bx      lr
+       .size   _backward_target, .-_backward_target
+       
+       .text
+
+# Define _start so that linker does not complain.
+       .align  2
+       .global _start
+       .code   32
+       .type   _start, %function
+_start:
+       bx      lr
+       .size   _start, .-_start
+
+       .global _backward_test
+       .code   16
+       .thumb_func
+       .type   _backward_test, %function
+_backward_test:
+       bl      _backward_target
+       .size   _backward_test, .-_backward_test
+
+       .align  2
+       .global _forward_test
+       .code   16
+       .thumb_func
+       .type   _forward_test, %function
+_forward_test:
+       # Bit 1 of the BLX target comes from bit 1 of branch base address,
+       # which is BLX instruction's address + 4.  We intentionally put this
+       # forward BLX at an address n*4 + 2 so that the branch offset is
+       # bumped up by 2.
+       nop.n
+       bl      _forward_target
+       .size   _forward_test, .-_forward_test
+       .code   32
+       
+       .section        .text.post,"x"
+
+# Add padding so that target is just out of branch range. 
+       .space  12
+       .align 2
+       .code   32
+       .global _forward_target
+       .type   _forward_target, %function
+_forward_target:
+       bx      lr
+       .size   _forward_target, .-_forward_target