From a2c7281b72172647cccb72d921839f5034b2d381 Mon Sep 17 00:00:00 2001 From: Doug Kwan Date: Mon, 22 Mar 2010 22:48:05 +0000 Subject: [PATCH] 2010-03-22 Doug Kwan * 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 | 30 ++++++++++++++++ gold/arm.cc | 58 +++++++++++++++++++++--------- gold/testsuite/Makefile.am | 52 +++++++++++++++++++++++---- gold/testsuite/Makefile.in | 54 +++++++++++++++++++++++++--- gold/testsuite/arm_branch_in_range.sh | 9 ++++- gold/testsuite/thumb_blx_in_range.s | 64 +++++++++++++++++++++++++++++++++ gold/testsuite/thumb_blx_out_of_range.s | 61 +++++++++++++++++++++++++++++++ 7 files changed, 300 insertions(+), 28 deletions(-) create mode 100644 gold/testsuite/thumb_blx_in_range.s create mode 100644 gold/testsuite/thumb_blx_out_of_range.s diff --git a/gold/ChangeLog b/gold/ChangeLog index f3d475a..1f24452 100644 --- a/gold/ChangeLog +++ b/gold/ChangeLog @@ -1,3 +1,33 @@ +2010-03-22 Doug Kwan + + * 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 * archive.cc (Should_include): Move to archive.h. diff --git a/gold/arm.cc b/gold/arm.cc index 016b2cc..890646e 100644 --- a/gold/arm.cc +++ b/gold/arm.cc @@ -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(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(x); + return ((signed_x < -32768 || signed_x > 65535) ? This::STATUS_OVERFLOW : This::STATUS_OKAY); } @@ -3831,11 +3837,16 @@ Arm_relocate_functions::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::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::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::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(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(destination) - location; if (target_is_thumb) { // Arm to thumb. @@ -8562,16 +8583,16 @@ Target_arm::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::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); diff --git a/gold/testsuite/Makefile.am b/gold/testsuite/Makefile.am index a083bc4..b115283 100644 --- a/gold/testsuite/Makefile.am +++ b/gold/testsuite/Makefile.am @@ -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 \ diff --git a/gold/testsuite/Makefile.in b/gold/testsuite/Makefile.in index d21b32b..061c627 100644 --- a/gold/testsuite/Makefile.in +++ b/gold/testsuite/Makefile.in @@ -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 diff --git a/gold/testsuite/arm_branch_in_range.sh b/gold/testsuite/arm_branch_in_range.sh index b676770..43b50c6 100755 --- a/gold/testsuite/arm_branch_in_range.sh +++ b/gold/testsuite/arm_branch_in_range.sh @@ -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 index 0000000..bd2d060 --- /dev/null +++ b/gold/testsuite/thumb_blx_in_range.s @@ -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 index 0000000..fc5beb5 --- /dev/null +++ b/gold/testsuite/thumb_blx_out_of_range.s @@ -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 -- 2.7.4