summaryrefslogtreecommitdiff
path: root/packages/binutils/binutils-2.16/binutils-2.16-thumb-glue.patch
blob: 59d8035f7de92742974dee0e6d26cee7cfb264fe (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
# 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);