This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
Re: ARM/thumb interworking confuses unwinder
- From: Christophe LYON <christophe dot lyon at st dot com>
- To: binutils at sourceware dot org
- Date: Thu, 07 Aug 2008 15:17:11 +0200
- Subject: Re: ARM/thumb interworking confuses unwinder
- References: <4887E088.3050401@eCosCentric.com> <48887952.5090801@st.com> <48887B21.3070804@eCosCentric.com> <20080724130500.GA23244@caradoc.them.org>
Hi,
Here is attached a patch that should fix Jonathan's issue: we now catch
"short" call sequences, so the faulty stub shouldn't be generated in the
code you are handling.
But it does not address the lack of unwind information for the stubs
that use lr.
I don't know about the non-interworking-aware ones. I suspect they're
just broken; we'd have to generate new unwind information for them.
I don't know how to do that; are there other examples in GNU ld that
could serve me as a basis?
The comment at "Thumb->(non-interworking aware) ARM" is totally
mangled, I see... can't quite work out what it's saying.
I tried to reformat it in the attached patch.
Christophe.
2008-08-07 Christophe Lyon <christophe.lyon@st.com>
bfd/
* elf32-arm.c (arm_thumb_arm_v4t_short_branch_stub): Define.
(elf32_arm_stub_type): Add arm_thumb_arm_v4t_stub_short_branch.
(arm_type_of_stub): Handle armv4t short branches. Update
prototype.
(arm_stub_is_thumb): Handle arm_thumb_arm_v4t_stub_short_branch.
(arm_build_one_stub): Likewise.
(arm_size_one_stub): Likewise.
(elf32_arm_size_stubs): Use new arm_type_of_stub prototype.
(arm_map_one_stub): Handle arm_thumb_arm_v4t_stub_short_branch.
ld/testsuite/
* ld-arm/arm-elf.exp: Add farcall-thumb-arm-short test.
* ld-arm/farcall-group2.s: Fix comment.
* ld-arm/farcall-thumb-arm-short.d: New test.
* ld-arm/farcall-thumb-arm-short.s: New test.
diff --exclude=CVS --exclude='*~' -Naur binutils-cvs-ref/src/bfd/elf32-arm.c binutils-cvs/src/bfd/elf32-arm.c
--- binutils-cvs-ref/src/bfd/elf32-arm.c 2008-07-28 08:46:31.000000000 +0200
+++ binutils-cvs/src/bfd/elf32-arm.c 2008-08-07 14:45:32.000000000 +0200
@@ -2044,6 +2044,13 @@
0x00000000, /* dcd R_ARM_ABS32(X) */
};
+static const bfd_vma arm_thumb_arm_v4t_short_branch_stub[] =
+ {
+ 0x46c04778, /* bx pc */
+ /* nop */
+ 0xea000000, /* b (X) */
+ };
+
static const bfd_vma arm_pic_long_branch_stub[] =
{
0xe59fc000, /* ldr r12, [pc] */
@@ -2062,6 +2069,7 @@
arm_thumb_v4t_stub_long_branch,
arm_thumb_thumb_stub_long_branch,
arm_thumb_arm_v4t_stub_long_branch,
+ arm_thumb_arm_v4t_stub_short_branch,
arm_stub_pic_long_branch,
};
@@ -2737,6 +2745,7 @@
{
case arm_thumb_thumb_stub_long_branch:
case arm_thumb_arm_v4t_stub_long_branch:
+ case arm_thumb_arm_v4t_stub_short_branch:
return TRUE;
case arm_stub_none:
BFD_FAIL ();
@@ -2755,7 +2764,10 @@
const Elf_Internal_Rela *rel,
unsigned char st_type,
struct elf32_arm_link_hash_entry *hash,
- bfd_vma destination)
+ bfd_vma destination,
+ asection* sym_sec,
+ bfd* input_bfd,
+ const char* name)
{
bfd_vma location;
bfd_signed_vma branch_offset;
@@ -2825,6 +2837,16 @@
else
{
/* Thumb to arm. */
+ if (sym_sec != NULL
+ && sym_sec->owner != NULL
+ && !INTERWORK_FLAG (sym_sec->owner))
+ {
+ (*_bfd_error_handler)
+ (_("%B(%s): warning: interworking not enabled.\n"
+ " first occurrence: %B: thumb call to arm"),
+ sym_sec->owner, input_bfd, name);
+ }
+
stub_type = (info->shared | globals->pic_veneer)
? ((globals->use_blx)
? arm_stub_pic_long_branch
@@ -2832,6 +2854,13 @@
: (globals->use_blx)
? arm_stub_long_branch
: arm_thumb_arm_v4t_stub_long_branch;
+
+ /* Handle v4t short branches */
+ if ( (stub_type == arm_thumb_arm_v4t_stub_long_branch)
+ && (branch_offset <= THM_MAX_FWD_BRANCH_OFFSET)
+ && (branch_offset >= THM_MAX_BWD_BRANCH_OFFSET)) {
+ stub_type = arm_thumb_arm_v4t_stub_short_branch;
+ }
}
}
}
@@ -2840,6 +2869,17 @@
if (st_type == STT_ARM_TFUNC)
{
/* Arm to thumb. */
+
+ if (sym_sec != NULL
+ && sym_sec->owner != NULL
+ && !INTERWORK_FLAG (sym_sec->owner))
+ {
+ (*_bfd_error_handler)
+ (_("%B(%s): warning: interworking not enabled.\n"
+ " first occurrence: %B: thumb call to arm"),
+ sym_sec->owner, input_bfd, name);
+ }
+
/* We have an extra 2-bytes reach because of the mode change
(bit 24 (H) of BLX encoding). */
if (branch_offset > (ARM_MAX_FWD_BRANCH_OFFSET + 2)
@@ -3097,6 +3137,10 @@
template = arm_thumb_arm_v4t_long_branch_stub;
template_size = (sizeof (arm_thumb_arm_v4t_long_branch_stub) / sizeof (bfd_vma)) * 4;
break;
+ case arm_thumb_arm_v4t_stub_short_branch:
+ template = arm_thumb_arm_v4t_short_branch_stub;
+ template_size = (sizeof(arm_thumb_arm_v4t_short_branch_stub) / sizeof (bfd_vma)) * 4;
+ break;
case arm_stub_pic_long_branch:
template = arm_pic_long_branch_stub;
template_size = (sizeof (arm_pic_long_branch_stub) / sizeof (bfd_vma)) * 4;
@@ -3146,6 +3190,19 @@
stub_bfd, stub_sec, stub_sec->contents,
stub_entry->stub_offset + 16, sym_value, 0);
break;
+ case arm_thumb_arm_v4t_stub_short_branch:
+ {
+ long int rel_offset;
+ static const insn32 t2a3_b_insn = 0xea000000;
+
+ rel_offset = sym_value - (stub_addr + 8 + 4);
+
+ put_arm_insn (globals, stub_bfd,
+ (bfd_vma) t2a3_b_insn | ((rel_offset >> 2) & 0x00FFFFFF),
+ loc + 4);
+ }
+ break;
+
case arm_stub_pic_long_branch:
/* We want the value relative to the address 8 bytes from the
start of the stub. */
@@ -3196,6 +3253,10 @@
template = arm_thumb_arm_v4t_long_branch_stub;
template_size = (sizeof (arm_thumb_arm_v4t_long_branch_stub) / sizeof (bfd_vma)) * 4;
break;
+ case arm_thumb_arm_v4t_stub_short_branch:
+ template = arm_thumb_arm_v4t_short_branch_stub;
+ template_size = (sizeof(arm_thumb_arm_v4t_short_branch_stub) / sizeof (bfd_vma)) * 4;
+ break;
case arm_stub_pic_long_branch:
template = arm_pic_long_branch_stub;
template_size = (sizeof (arm_pic_long_branch_stub) / sizeof (bfd_vma)) * 4;
@@ -3602,7 +3663,8 @@
/* Determine what (if any) linker stub is needed. */
stub_type = arm_type_of_stub (info, section, irela, st_type,
- hash, destination);
+ hash, destination, sym_sec,
+ input_bfd, sym_name);
if (stub_type == arm_stub_none)
continue;
@@ -3847,17 +3909,17 @@
.thumb .thumb
.align 2 .align 2
- __func_from_thumb: __func_from_thumb:
+__func_from_thumb: __func_from_thumb:
bx pc push {r6, lr}
nop ldr r6, __func_addr
- .arm mov lr, pc
- __func_change_to_arm: bx r6
- b func .arm
- __func_back_to_thumb:
- ldmia r13! {r6, lr}
- bx lr
- __func_addr:
- .word func */
+ .arm mov lr, pc
+__func_change_to_arm: bx r6
+ b func .arm
+ __func_back_to_thumb:
+ ldmia r13! {r6, lr}
+ bx lr
+ __func_addr:
+ .word func */
#define THUMB2ARM_GLUE_SIZE 8
static const insn16 t2a1_bx_pc_insn = 0x4778;
@@ -11276,6 +11338,12 @@
if (!elf32_arm_output_map_sym (osi, ARM_MAP_DATA, addr + 16))
return FALSE;
break;
+ case arm_thumb_arm_v4t_stub_short_branch:
+ if (!elf32_arm_output_stub_sym (osi, stub_name, addr | 1, 8))
+ return FALSE;
+ if (!elf32_arm_output_map_sym (osi, ARM_MAP_ARM, addr + 4))
+ return FALSE;
+ break;
case arm_stub_pic_long_branch:
if (!elf32_arm_output_stub_sym (osi, stub_name, addr, 12))
return FALSE;
diff --exclude=CVS --exclude='*~' -Naur binutils-cvs-ref/src/ld/testsuite/ld-arm/arm-elf.exp binutils-cvs/src/ld/testsuite/ld-arm/arm-elf.exp
--- binutils-cvs-ref/src/ld/testsuite/ld-arm/arm-elf.exp 2008-07-18 22:49:12.000000000 +0200
+++ binutils-cvs/src/ld/testsuite/ld-arm/arm-elf.exp 2008-08-07 14:46:24.000000000 +0200
@@ -207,7 +207,7 @@
{"Thumb-2 BL" "-Ttext 0x1000 --section-start .foo=0x1001000" "" {thumb2-bl.s}
{{objdump -dr thumb2-bl.d}}
"thumb2-bl"}
-
+
{"ARMv4 interworking" "-static -T arm.ld --fix-v4bx-interworking" "--fix-v4bx -meabi=4" {armv4-bx.s}
{{objdump -d armv4-bx.d}}
"armv4-bx"}
@@ -260,6 +260,9 @@
{"Thumb-ARM farcall" "-Ttext 0x1000 --section-start .foo=0x2001014" "-W" {farcall-thumb-arm.s}
{{objdump -d farcall-thumb-arm.d}}
"farcall-thumb-arm"}
+ {"Thumb-ARM (short) call" "-Ttext 0x1000 --section-start .foo=0x0002014" "-W" {farcall-thumb-arm-short.s}
+ {{objdump -d farcall-thumb-arm-short.d}}
+ "farcall-thumb-arm-short"}
{"Thumb-ARM farcall with BLX" "-Ttext 0x1000 --section-start .foo=0x2001014" "-W -march=armv5t" {farcall-thumb-arm.s}
{{objdump -d farcall-thumb-arm-blx.d}}
"farcall-thumb-arm-blx"}
diff --exclude=CVS --exclude='*~' -Naur binutils-cvs-ref/src/ld/testsuite/ld-arm/farcall-group2.s binutils-cvs/src/ld/testsuite/ld-arm/farcall-group2.s
--- binutils-cvs-ref/src/ld/testsuite/ld-arm/farcall-group2.s 2008-05-23 16:16:16.000000000 +0200
+++ binutils-cvs/src/ld/testsuite/ld-arm/farcall-group2.s 2008-08-07 10:48:15.000000000 +0200
@@ -1,10 +1,7 @@
-
@ Test to ensure that ARM calls exceeding 32Mb generate stubs.
-@ We will place the section .foo at 0x2000.
-
.text
-myfunc:
+myfunc:
bl bar3
bl bar4
bl bar5
diff --exclude=CVS --exclude='*~' -Naur binutils-cvs-ref/src/ld/testsuite/ld-arm/farcall-thumb-arm-short.d binutils-cvs/src/ld/testsuite/ld-arm/farcall-thumb-arm-short.d
--- binutils-cvs-ref/src/ld/testsuite/ld-arm/farcall-thumb-arm-short.d 1970-01-01 01:00:00.000000000 +0100
+++ binutils-cvs/src/ld/testsuite/ld-arm/farcall-thumb-arm-short.d 2008-08-06 13:48:05.000000000 +0200
@@ -0,0 +1,14 @@
+.*: file format .*
+
+Disassembly of section .text:
+
+00001000 <__bar_from_thumb>:
+ 1000: 4778 bx pc
+ 1002: 46c0 nop \(mov r8, r8\)
+ 1004: ea000402 b 2014 <bar>
+00001008 <_start>:
+ 1008: f7ff fffa bl 1000 <__bar_from_thumb>
+Disassembly of section .foo:
+
+00002014 <bar>:
+ 2014: e12fff1e bx lr
diff --exclude=CVS --exclude='*~' -Naur binutils-cvs-ref/src/ld/testsuite/ld-arm/farcall-thumb-arm-short.s binutils-cvs/src/ld/testsuite/ld-arm/farcall-thumb-arm-short.s
--- binutils-cvs-ref/src/ld/testsuite/ld-arm/farcall-thumb-arm-short.s 1970-01-01 01:00:00.000000000 +0100
+++ binutils-cvs/src/ld/testsuite/ld-arm/farcall-thumb-arm-short.s 2008-08-06 13:38:48.000000000 +0200
@@ -0,0 +1,21 @@
+@ Test to ensure that a Thumb to ARM call within 4Mb does not generate a stub.
+
+ .global _start
+ .syntax unified
+
+@ We will place the section .text at 0x1000.
+
+ .text
+ .thumb_func
+_start:
+ bl bar
+
+@ We will place the section .foo at 0x2014.
+
+ .section .foo, "xa"
+
+ .arm
+ .type bar, %function
+bar:
+ bx lr
+