This is the mail archive of the
binutils@sources.redhat.com
mailing list for the binutils project.
[patch] Arm to thumb stubs
- From: Paul Brook <paul at codesourcery dot com>
- To: binutils at sources dot redhat dot com
- Date: Thu, 7 Apr 2005 18:08:53 +0100
- Subject: [patch] Arm to thumb stubs
- Organization: CodeSourcery
The current linker generated arm to thumb interworking stubs use the absolute
address of the target function. Obviously this doesn't work in PIC
environments (eg. Linux shared libraries and SymbianOS executables).
The attached patch implements a PIC version of these stubs.
Tested with cross to arm-none-eabi.
Ok?
Paul
2005-04-07 Paul Brook <paul@codesourcery.com>
* elf32-arm.c (ARM2THUMB_GLUE_SIZE): Rename...
(ARM2THUMB_STATIC_GLUE_SIZE): ... to this.
(ARM2THUMB_PIC_GLUE_SIZE): Define.
(a2t1p_ldr_insn, a2t2p_add_pc_insn, a2t3p_bx_r12_insn): Add.
(elf32_arm_to_thumb_stub): Create PIC stubs.
(record_arm_to_thumb_glue): Use different stub size for relocatable
images.
Index: bfd/elf32-arm.c
===================================================================
RCS file: /var/cvsroot/src-cvs/src/bfd/elf32-arm.c,v
retrieving revision 1.22.2.3.2.4
diff -u -p -r1.22.2.3.2.4 elf32-arm.c
--- bfd/elf32-arm.c 30 Mar 2005 17:28:23 -0000 1.22.2.3.2.4
+++ bfd/elf32-arm.c 7 Apr 2005 16:17:46 -0000
@@ -1636,20 +1636,35 @@ find_arm_glue (struct bfd_link_info *lin
return myh;
}
-/* ARM->Thumb glue:
+/* ARM->Thumb glue (static images):
.arm
__func_from_arm:
ldr r12, __func_addr
bx r12
__func_addr:
- .word func @ behave as if you saw a ARM_32 reloc. */
+ .word func @ behave as if you saw a ARM_32 reloc.
-#define ARM2THUMB_GLUE_SIZE 12
+ (relocatable images)
+ .arm
+ __func_from_arm:
+ ldr r12, __func_offset
+ add r12, r12, pc
+ bx r12
+ __func_offset:
+ .word func - .
+ */
+
+#define ARM2THUMB_STATIC_GLUE_SIZE 12
static const insn32 a2t1_ldr_insn = 0xe59fc000;
static const insn32 a2t2_bx_r12_insn = 0xe12fff1c;
static const insn32 a2t3_func_addr_insn = 0x00000001;
+#define ARM2THUMB_PIC_GLUE_SIZE 16
+static const insn32 a2t1p_ldr_insn = 0xe59fc004;
+static const insn32 a2t2p_add_pc_insn = 0xe08cc00f;
+static const insn32 a2t3p_bx_r12_insn = 0xe12fff1c;
+
/* Thumb->ARM: Thumb->(non-interworking aware) ARM
.thumb .thumb
@@ -1769,7 +1784,10 @@ record_arm_to_thumb_glue (struct bfd_lin
free (tmp_name);
- globals->arm_glue_size += ARM2THUMB_GLUE_SIZE;
+ if ((link_info->shared || globals->root.is_relocatable_executable))
+ globals->arm_glue_size += ARM2THUMB_PIC_GLUE_SIZE;
+ else
+ globals->arm_glue_size += ARM2THUMB_STATIC_GLUE_SIZE;
return;
}
@@ -2342,15 +2360,39 @@ elf32_arm_to_thumb_stub (struct bfd_link
--my_offset;
myh->root.u.def.value = my_offset;
- bfd_put_32 (output_bfd, (bfd_vma) a2t1_ldr_insn,
- s->contents + my_offset);
+ if ((info->shared || globals->root.is_relocatable_executable))
+ {
+ /* For relocatable objects we can't use absolute addresses,
+ so construct the address from a relative offset. */
+ /* TODO: If the offset is small it's probably worth
+ constructing the address with adds. */
+ bfd_put_32 (output_bfd, (bfd_vma) a2t1p_ldr_insn,
+ s->contents + my_offset);
+ bfd_put_32 (output_bfd, (bfd_vma) a2t2p_add_pc_insn,
+ s->contents + my_offset + 4);
+ bfd_put_32 (output_bfd, (bfd_vma) a2t3p_bx_r12_insn,
+ s->contents + my_offset + 8);
+ /* Adjust the offset by 4 for the position of the add,
+ and 8 for the pipeline offset. */
+ ret_offset = (val - (s->output_offset
+ + s->output_section->vma
+ + my_offset + 12))
+ | 1;
+ bfd_put_32 (output_bfd, ret_offset,
+ s->contents + my_offset + 12);
+ }
+ else
+ {
+ bfd_put_32 (output_bfd, (bfd_vma) a2t1_ldr_insn,
+ s->contents + my_offset);
- bfd_put_32 (output_bfd, (bfd_vma) a2t2_bx_r12_insn,
- s->contents + my_offset + 4);
+ bfd_put_32 (output_bfd, (bfd_vma) a2t2_bx_r12_insn,
+ s->contents + my_offset + 4);
- /* It's a thumb address. Add the low order bit. */
- bfd_put_32 (output_bfd, val | a2t3_func_addr_insn,
- s->contents + my_offset + 8);
+ /* It's a thumb address. Add the low order bit. */
+ bfd_put_32 (output_bfd, val | a2t3_func_addr_insn,
+ s->contents + my_offset + 8);
+ }
}
BFD_ASSERT (my_offset <= globals->arm_glue_size);