This is the mail archive of the binutils@sources.redhat.com mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[patch] Arm to thumb stubs


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

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]