2008-03-08 Paul Brook <paul@codesourcery.com>
authorPaul Brook <paul@codesourcery.com>
Sat, 8 Mar 2008 14:58:14 +0000 (14:58 +0000)
committerPaul Brook <paul@codesourcery.com>
Sat, 8 Mar 2008 14:58:14 +0000 (14:58 +0000)
bfd/
* elf32-arm.c (insert_thumb_branch): Rewrite.
(elf32_thumb_to_arm_stub): Use new insert_thumb_branch.

ld/testsuite/
* 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.

bfd/ChangeLog
bfd/elf32-arm.c
ld/testsuite/ChangeLog
ld/testsuite/ld-arm/arm-elf.exp
ld/testsuite/ld-arm/thumb2-b-interwork.d [new file with mode: 0644]
ld/testsuite/ld-arm/thumb2-b-interwork.s [new file with mode: 0644]

index 73c6a77..9027887 100644 (file)
@@ -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
index 687d9cd..6764e67 100644 (file)
@@ -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;
 }
index a30eba9..329d6fb 100644 (file)
@@ -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.
index 7c6ee21..81b9f75 100644 (file)
@@ -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 (file)
index 0000000..00bc4d4
--- /dev/null
@@ -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 (file)
index 0000000..4452a8f
--- /dev/null
@@ -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
+