# 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);