This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
Thumb-2 interworked b.w
- From: Paul Brook <paul at codesourcery dot com>
- To: binutils at sourceware dot org
- Date: Sat, 8 Mar 2008 14:56:58 +0000
- Subject: Thumb-2 interworked b.w
The ARM linker contains logic to generate interworking veneers for Thumb-2 b.w
instructions. However the code that populates these veneers
(insert_thumb_branch) aborts when this happens. The code in
insert_thumb_branch and many of the supporting comments are at best confused,
at worst completely wrong, so I've rewritten the whole thing.
Tested on arm-none-eabi.
Applied to CVS head.
Paul
2008-03-08 Paul Brook <paul@codesourcery.com>
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.
Index: bfd/elf32-arm.c
===================================================================
RCS file: /var/cvsroot/src-cvs/src/bfd/elf32-arm.c,v
retrieving revision 1.137
diff -u -p -r1.137 elf32-arm.c
--- bfd/elf32-arm.c 8 Mar 2008 01:20:38 -0000 1.137
+++ bfd/elf32-arm.c 8 Mar 2008 13:58:25 -0000
@@ -4070,58 +4070,29 @@ bfd_elf32_arm_set_target_relocs (struct
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
{
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
/* 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: ld/testsuite/ld-arm/arm-elf.exp
===================================================================
RCS file: /var/cvsroot/src-cvs/src/ld/testsuite/ld-arm/arm-elf.exp,v
retrieving revision 1.33
diff -u -p -r1.33 arm-elf.exp
--- ld/testsuite/ld-arm/arm-elf.exp 8 Mar 2008 01:20:39 -0000 1.33
+++ ld/testsuite/ld-arm/arm-elf.exp 8 Mar 2008 13:58:41 -0000
@@ -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
Index: ld/testsuite/ld-arm/thumb2-b-interwork.d
===================================================================
RCS file: ld/testsuite/ld-arm/thumb2-b-interwork.d
diff -N ld/testsuite/ld-arm/thumb2-b-interwork.d
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ ld/testsuite/ld-arm/thumb2-b-interwork.d 6 Mar 2008 20:30:34 -0000
@@ -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>
+
Index: ld/testsuite/ld-arm/thumb2-b-interwork.s
===================================================================
RCS file: ld/testsuite/ld-arm/thumb2-b-interwork.s
diff -N ld/testsuite/ld-arm/thumb2-b-interwork.s
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ ld/testsuite/ld-arm/thumb2-b-interwork.s 6 Mar 2008 20:30:34 -0000
@@ -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
+