aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bfd/ChangeLog5
-rw-r--r--bfd/elf32-arm.c81
-rw-r--r--ld/testsuite/ChangeLog6
-rw-r--r--ld/testsuite/ld-arm/arm-elf.exp3
-rw-r--r--ld/testsuite/ld-arm/thumb2-b-interwork.d19
-rw-r--r--ld/testsuite/ld-arm/thumb2-b-interwork.s20
6 files changed, 76 insertions, 58 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index 73c6a77..9027887 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -1,3 +1,8 @@
+2008-03-08 Paul Brook <paul@codesourcery.com>
+
+ * elf32-arm.c (insert_thumb_branch): Rewrite.
+ (elf32_thumb_to_arm_stub): Use new insert_thumb_branch.
+
2008-03-07 Paul Brook <paul@codesourcery.com>
* elf32-arm.c (elf32_arm_howto_table_1): Fix bitmasks for MOVW and
diff --git a/bfd/elf32-arm.c b/bfd/elf32-arm.c
index 687d9cd..6764e67 100644
--- a/bfd/elf32-arm.c
+++ b/bfd/elf32-arm.c
@@ -4070,58 +4070,29 @@ bfd_elf32_arm_set_target_relocs (struct bfd *output_bfd,
elf_arm_tdata (output_bfd)->no_enum_size_warning = no_enum_warn;
}
-/* The thumb form of a long branch is a bit finicky, because the offset
- encoding is split over two fields, each in it's own instruction. They
- can occur in any order. So given a thumb form of long branch, and an
- offset, insert the offset into the thumb branch and return finished
- instruction.
-
- It takes two thumb instructions to encode the target address. Each has
- 11 bits to invest. The upper 11 bits are stored in one (identified by
- H-0.. see below), the lower 11 bits are stored in the other (identified
- by H-1).
-
- Combine together and shifted left by 1 (it's a half word address) and
- there you have it.
-
- Op: 1111 = F,
- H-0, upper address-0 = 000
- Op: 1111 = F,
- H-1, lower address-0 = 800
-
- They can be ordered either way, but the arm tools I've seen always put
- the lower one first. It probably doesn't matter. krk@cygnus.com
-
- XXX: Actually the order does matter. The second instruction (H-1)
- moves the computed address into the PC, so it must be the second one
- in the sequence. The problem, however is that whilst little endian code
- stores the instructions in HI then LOW order, big endian code does the
- reverse. nickc@cygnus.com. */
-
-#define LOW_HI_ORDER 0xF800F000
-#define HI_LOW_ORDER 0xF000F800
-
-static insn32
-insert_thumb_branch (insn32 br_insn, int rel_off)
-{
- unsigned int low_bits;
- unsigned int high_bits;
-
- BFD_ASSERT ((rel_off & 1) != 1);
-
- rel_off >>= 1; /* Half word aligned address. */
- low_bits = rel_off & 0x000007FF; /* The bottom 11 bits. */
- high_bits = (rel_off >> 11) & 0x000007FF; /* The top 11 bits. */
-
- if ((br_insn & LOW_HI_ORDER) == LOW_HI_ORDER)
- br_insn = LOW_HI_ORDER | (low_bits << 16) | high_bits;
- else if ((br_insn & HI_LOW_ORDER) == HI_LOW_ORDER)
- br_insn = HI_LOW_ORDER | (high_bits << 16) | low_bits;
- else
- /* FIXME: abort is probably not the right call. krk@cygnus.com */
- abort (); /* Error - not a valid branch instruction form. */
+/* Replace the target offset of a Thumb bl or b.w instruction. */
- return br_insn;
+static void
+insert_thumb_branch (bfd *abfd, long int offset, bfd_byte *insn)
+{
+ bfd_vma upper;
+ bfd_vma lower;
+ int reloc_sign;
+
+ BFD_ASSERT ((offset & 1) == 0);
+
+ upper = bfd_get_16 (abfd, insn);
+ lower = bfd_get_16 (abfd, insn + 2);
+ reloc_sign = (offset < 0) ? 1 : 0;
+ upper = (upper & ~(bfd_vma) 0x7ff)
+ | ((offset >> 12) & 0x3ff)
+ | (reloc_sign << 10);
+ lower = (lower & ~(bfd_vma) 0x2fff)
+ | (((!((offset >> 23) & 1)) ^ reloc_sign) << 13)
+ | (((!((offset >> 22) & 1)) ^ reloc_sign) << 11)
+ | ((offset >> 1) & 0x7ff);
+ bfd_put_16 (abfd, upper, insn);
+ bfd_put_16 (abfd, lower, insn + 2);
}
@@ -4170,7 +4141,6 @@ elf32_thumb_to_arm_stub (struct bfd_link_info * info,
{
asection * s = 0;
bfd_vma my_offset;
- unsigned long int tmp;
long int ret_offset;
struct elf_link_hash_entry * myh;
struct elf32_arm_link_hash_table * globals;
@@ -4251,12 +4221,7 @@ elf32_thumb_to_arm_stub (struct bfd_link_info * info,
/* Biassing for PC-relative addressing. */
- 8;
- tmp = bfd_get_32 (input_bfd, hit_data
- - input_section->vma);
-
- bfd_put_32 (output_bfd,
- (bfd_vma) insert_thumb_branch (tmp, ret_offset),
- hit_data - input_section->vma);
+ insert_thumb_branch (input_bfd, ret_offset, hit_data - input_section->vma);
return TRUE;
}
diff --git a/ld/testsuite/ChangeLog b/ld/testsuite/ChangeLog
index a30eba9..329d6fb 100644
--- a/ld/testsuite/ChangeLog
+++ b/ld/testsuite/ChangeLog
@@ -1,3 +1,9 @@
+2008-03-08 Paul Brook <paul@codesourcery.com>
+
+ * ld-arm/arm-elf.exp (armeabitests): Add thumb2-b-interwork.
+ * ld-arm/thumb2-b-interwork.d: New test.
+ * ld-arm/thumb2-b-interwork.s: New test.
+
2008-03-07 Paul Brook <paul@codesourcery.com>
* ld-arm/arm-elf.exp (armelftests): Add movw-merge and arm-app-movw.
diff --git a/ld/testsuite/ld-arm/arm-elf.exp b/ld/testsuite/ld-arm/arm-elf.exp
index 7c6ee21..81b9f75 100644
--- a/ld/testsuite/ld-arm/arm-elf.exp
+++ b/ld/testsuite/ld-arm/arm-elf.exp
@@ -209,6 +209,9 @@ set armeabitests {
{"Thumb-2 BL" "-Ttext 0x1000 --section-start .foo=0x1001000" "" {thumb2-bl.s}
{{objdump -dr thumb2-bl.d}}
"thumb2-bl"}
+ {"Thumb-2 Interworked branch" "-T arm.ld" "" {thumb2-b-interwork.s}
+ {{objdump -dr thumb2-b-interwork.d}}
+ "thumb2-b-interwork"}
}
run_ld_link_tests $armeabitests
diff --git a/ld/testsuite/ld-arm/thumb2-b-interwork.d b/ld/testsuite/ld-arm/thumb2-b-interwork.d
new file mode 100644
index 0000000..00bc4d4
--- /dev/null
+++ b/ld/testsuite/ld-arm/thumb2-b-interwork.d
@@ -0,0 +1,19 @@
+
+.*thumb2-b-interwork: file format elf32-.*arm
+
+Disassembly of section .text:
+
+00008000 <_start>:
+ 8000: f000 b802 b.w 8008 <__bar_from_thumb>
+
+00008004 <bar>:
+ 8004: e12fff1e bx lr
+Disassembly of section .glue_7t:
+
+00008008 <__bar_from_thumb>:
+ 8008: 4778 bx pc
+ 800a: 46c0 nop \(mov r8, r8\)
+
+0000800c <__bar_change_to_arm>:
+ 800c: eafffffc b 8004 <bar>
+
diff --git a/ld/testsuite/ld-arm/thumb2-b-interwork.s b/ld/testsuite/ld-arm/thumb2-b-interwork.s
new file mode 100644
index 0000000..4452a8f
--- /dev/null
+++ b/ld/testsuite/ld-arm/thumb2-b-interwork.s
@@ -0,0 +1,20 @@
+@ Test to ensure that a Thumb-2 B.W can branch to an ARM funtion.
+
+ .arch armv7-a
+ .global _start
+ .syntax unified
+ .text
+ .thumb_func
+
+_start:
+ b.w bar
+
+@ Put this in a separate section to force the assembler to generate a reloc
+
+ .arm
+ .section .after, "xa"
+ .global bar
+ .type bar, %function
+bar:
+ bx lr
+