77 lines
2.5 KiB
Diff
77 lines
2.5 KiB
Diff
# The ARM->Thumb glue uses an ldr of the target function address, this
|
|
# simply doesn't work for PIC code, changed to use 4 word PIC glue
|
|
#
|
|
--- binutils-2.16/.pc/binutils-2.16-thumb-glue.patch/bfd/elf32-arm.c 2005-09-18 03:52:15.465165051 -0700
|
|
+++ binutils-2.16/bfd/elf32-arm.c 2005-09-18 03:52:33.546302825 -0700
|
|
@@ -1493,19 +1493,20 @@
|
|
return myh;
|
|
}
|
|
|
|
-/* ARM->Thumb glue:
|
|
+/* ARM->Thumb glue (PIC version):
|
|
|
|
.arm
|
|
__func_from_arm:
|
|
ldr r12, __func_addr
|
|
+ add r12, r12, pc @ pc is __func_addr, so r12 is func
|
|
bx r12
|
|
__func_addr:
|
|
- .word func @ behave as if you saw a ARM_32 reloc. */
|
|
+ .word func-.+1 @ offset to actual function, low bit set */
|
|
|
|
-#define ARM2THUMB_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_GLUE_SIZE 16
|
|
+static const insn32 a2t1_ldr_insn = 0xe59fc004;
|
|
+static const insn32 a2t2_add_r12_insn = 0xe08fc00c;
|
|
+static const insn32 a2t3_bx_r12_insn = 0xe12fff1c;
|
|
|
|
/* Thumb->ARM: Thumb->(non-interworking aware) ARM
|
|
|
|
@@ -2187,6 +2188,8 @@
|
|
|
|
if ((my_offset & 0x01) == 0x01)
|
|
{
|
|
+ long int ret_offset;
|
|
+
|
|
if (sym_sec != NULL
|
|
&& sym_sec->owner != NULL
|
|
&& !INTERWORK_FLAG (sym_sec->owner))
|
|
@@ -2203,12 +2206,31 @@
|
|
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,
|
|
+ bfd_put_32 (output_bfd, (bfd_vma) a2t2_add_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,
|
|
+ bfd_put_32 (output_bfd, (bfd_vma) a2t3_bx_r12_insn,
|
|
s->contents + my_offset + 8);
|
|
+
|
|
+ /* Calculate the offset to the actual function. */
|
|
+ ret_offset =
|
|
+ /* Address of destination of the stub. */
|
|
+ ((bfd_signed_vma) val)
|
|
+ - ((bfd_signed_vma)
|
|
+ /* Offset from the start of the current section
|
|
+ to the start of the stubs. */
|
|
+ (s->output_offset
|
|
+ /* Offset of the start of this stub from the start of the stubs. */
|
|
+ + my_offset
|
|
+ /* Address of the start of the current section. */
|
|
+ + s->output_section->vma)
|
|
+ /* The word is 12 bytes into the stub. */
|
|
+ + 12
|
|
+ /* The destination is a thumb function so the bottom bit must be set. */
|
|
+ - 1);
|
|
+
|
|
+ bfd_put_32 (output_bfd, (bfd_vma) ret_offset,
|
|
+ s->contents + my_offset + 12);
|
|
}
|
|
|
|
BFD_ASSERT (my_offset <= globals->arm_glue_size);
|