This is the mail archive of the binutils@sourceware.org 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 v4t Thumb shared libraries.


The current arm-linux PLT sequence ends with the equivalent of

ldr pc, [ip]

This sequence is not interworking safe on armv4t hardware. To enable use of 
Thumb in shared libraries there are two options:

a) Use a new PLT sequence. Because we only have one scratch register and the 
requirements of the lazy resolver this means doubling the size of all PLT, 
entries and probably breaks prelinking.

b) Make sure that all functions exported from shared libraries are entered in 
Arm mode, inserting stubs as neccessary, thus avoiding the whole issue. This 
also means that prelinking and applications which do not use Thumb are 
uneffected.

The attached patch implements (b).  It reuses the existing infrastructure for 
generating arm->thumb stubs.

Ok?

Paul

2006-08-17  Paul Brook  <paul@codesourcery.com>

	bfd/
	* elf32-arm.c (elf32_arm_link_hash_entry): Add export_glue.
	(elf32_arm_link_hash_newfunc): Initialize export_glue.
	(record_arm_to_thumb_glue): Return stub symbol.
	(elf32_arm_create_thumb_stub): New function.
	(elf32_arm_to_thumb_stub): Use it.
	(elf32_arm_to_thumb_export_stub): New function.
	(elf32_arm_begin_write_processing): New function.
	(allocate_dynrelocs): Allocate Arm stubs.
	(elf_backend_begin_write_processing): Define.
	(elf32_arm_symbian_begin_write_processing): Remove ATTRIBUTE_UNUSED.
	Call elf32_arm_begin_write_processing.

	ld/
	* emultempl/armelf.em (arm_elf_before_allocation): Call
	gld${EMULATION_NAME}_before_allocation after setting interworking bfd.

	ld/testsuite/
	* ld-arm/arm-elf.exp (armelftests): Add armthumb-lib.so.  Add
	-use-blx to mixed-lib.so
	* ld-arm/armthumb-lib.d: New file.
	* ld-arm/armthumb-lib.sym: New file.
Index: bfd/elf32-arm.c
===================================================================
RCS file: /var/cvsroot/src-cvs/src/bfd/elf32-arm.c,v
retrieving revision 1.70.2.7
diff -u -p -r1.70.2.7 elf32-arm.c
--- bfd/elf32-arm.c	19 Jun 2006 14:22:33 -0000	1.70.2.7
+++ bfd/elf32-arm.c	17 Aug 2006 15:29:54 -0000
@@ -2089,6 +2089,10 @@ struct elf32_arm_link_hash_entry
 #define GOT_TLS_GD	2
 #define GOT_TLS_IE	4
     unsigned char tls_type;
+
+    /* The symbol marking the real symbol location for exported thumb
+       symbols with Arm stubs.  */
+    struct elf_link_hash_entry *export_glue;
   };
 
 /* Traverse an arm ELF linker hash table.  */
@@ -2200,6 +2204,7 @@ elf32_arm_link_hash_newfunc (struct bfd_
       ret->tls_type = GOT_UNKNOWN;
       ret->plt_thumb_refcount = 0;
       ret->plt_got_offset = -1;
+      ret->export_glue = NULL;
     }
 
   return (struct bfd_hash_entry *) ret;
@@ -2578,7 +2583,9 @@ bfd_elf32_arm_allocate_interworking_sect
   return TRUE;
 }
 
-static void
+/* Allocate space and symbols for calling a Thumb function from Arm mode.
+   returns the symbol identifying teh stub.  */
+static struct elf_link_hash_entry *
 record_arm_to_thumb_glue (struct bfd_link_info * link_info,
 			  struct elf_link_hash_entry * h)
 {
@@ -2613,7 +2620,7 @@ record_arm_to_thumb_glue (struct bfd_lin
     {
       /* We've already seen this guy.  */
       free (tmp_name);
-      return;
+      return myh;
     }
 
   /* The only trick here is using hash_table->arm_glue_size as the value.
@@ -2636,7 +2643,7 @@ record_arm_to_thumb_glue (struct bfd_lin
   else
     globals->arm_glue_size += ARM2THUMB_STATIC_GLUE_SIZE;
 
-  return;
+  return myh;
 }
 
 static void
@@ -3191,30 +3198,25 @@ elf32_thumb_to_arm_stub (struct bfd_link
   return TRUE;
 }
 
-/* Arm code calling a Thumb function.  */
+/* Populate an Arm to Thumb stub.  Returns the stub symbol.  */
 
-static int
-elf32_arm_to_thumb_stub (struct bfd_link_info * info,
-			 const char *           name,
-			 bfd *                  input_bfd,
-			 bfd *                  output_bfd,
-			 asection *             input_section,
-			 bfd_byte *             hit_data,
-			 asection *             sym_sec,
-			 bfd_vma                offset,
-			 bfd_signed_vma         addend,
-			 bfd_vma                val)
+static struct elf_link_hash_entry *
+elf32_arm_create_thumb_stub (struct bfd_link_info * info,
+			     const char *           name,
+			     bfd *                  input_bfd,
+			     bfd *                  output_bfd,
+			     asection *             sym_sec,
+			     bfd_vma                val,
+			     asection		    *s)
 {
-  unsigned long int tmp;
   bfd_vma my_offset;
-  asection * s;
   long int ret_offset;
   struct elf_link_hash_entry * myh;
   struct elf32_arm_link_hash_table * globals;
 
   myh = find_arm_glue (info, name, input_bfd);
   if (myh == NULL)
-    return FALSE;
+    return NULL;
 
   globals = elf32_arm_hash_table (info);
 
@@ -3222,11 +3224,6 @@ elf32_arm_to_thumb_stub (struct bfd_link
   BFD_ASSERT (globals->bfd_of_glue_owner != NULL);
 
   my_offset = myh->root.u.def.value;
-  s = bfd_get_section_by_name (globals->bfd_of_glue_owner,
-			       ARM2THUMB_GLUE_SECTION_NAME);
-  BFD_ASSERT (s != NULL);
-  BFD_ASSERT (s->contents != NULL);
-  BFD_ASSERT (s->output_section != NULL);
 
   if ((my_offset & 0x01) == 0x01)
     {
@@ -3280,6 +3277,47 @@ elf32_arm_to_thumb_stub (struct bfd_link
 
   BFD_ASSERT (my_offset <= globals->arm_glue_size);
 
+  return myh;
+}
+
+/* Arm code calling a Thumb function.  */
+
+static int
+elf32_arm_to_thumb_stub (struct bfd_link_info * info,
+			 const char *           name,
+			 bfd *                  input_bfd,
+			 bfd *                  output_bfd,
+			 asection *             input_section,
+			 bfd_byte *             hit_data,
+			 asection *             sym_sec,
+			 bfd_vma                offset,
+			 bfd_signed_vma         addend,
+			 bfd_vma                val)
+{
+  unsigned long int tmp;
+  bfd_vma my_offset;
+  asection * s;
+  long int ret_offset;
+  struct elf_link_hash_entry * myh;
+  struct elf32_arm_link_hash_table * globals;
+
+  globals = elf32_arm_hash_table (info);
+
+  BFD_ASSERT (globals != NULL);
+  BFD_ASSERT (globals->bfd_of_glue_owner != NULL);
+
+  s = bfd_get_section_by_name (globals->bfd_of_glue_owner,
+			       ARM2THUMB_GLUE_SECTION_NAME);
+  BFD_ASSERT (s != NULL);
+  BFD_ASSERT (s->contents != NULL);
+  BFD_ASSERT (s->output_section != NULL);
+
+  myh = elf32_arm_create_thumb_stub (info, name, input_bfd, output_bfd,
+				     sym_sec, val, s);
+  if (!myh)
+    return FALSE;
+
+  my_offset = myh->root.u.def.value;
   tmp = bfd_get_32 (input_bfd, hit_data);
   tmp = tmp & 0xFF000000;
 
@@ -3299,6 +3337,63 @@ elf32_arm_to_thumb_stub (struct bfd_link
   return TRUE;
 }
 
+/* Populate Arm stub for an exported Thumb function.  */
+
+static bfd_boolean
+elf32_arm_to_thumb_export_stub (struct elf_link_hash_entry *h, void * inf)
+{
+  struct bfd_link_info * info = (struct bfd_link_info *) inf;
+  asection * s;
+  struct elf_link_hash_entry * myh;
+  struct elf32_arm_link_hash_entry *eh;
+  struct elf32_arm_link_hash_table * globals;
+  asection *sec;
+  bfd_vma val;
+
+  eh = elf32_arm_hash_entry(h);
+  /* Allocate stubs for exported Thumb functions on v4t.  */
+  if (eh->export_glue == NULL)
+    return TRUE;
+
+  globals = elf32_arm_hash_table (info);
+
+  BFD_ASSERT (globals != NULL);
+  BFD_ASSERT (globals->bfd_of_glue_owner != NULL);
+
+  s = bfd_get_section_by_name (globals->bfd_of_glue_owner,
+			       ARM2THUMB_GLUE_SECTION_NAME);
+  BFD_ASSERT (s != NULL);
+  BFD_ASSERT (s->contents != NULL);
+  BFD_ASSERT (s->output_section != NULL);
+
+  sec = eh->export_glue->root.u.def.section;
+  val = eh->export_glue->root.u.def.value + sec->output_offset
+	+ sec->output_section->vma;
+  myh = elf32_arm_create_thumb_stub (info, h->root.root.string,
+				     h->root.u.def.section->owner,
+				     globals->obfd, sec, val, s);
+  BFD_ASSERT (myh);
+  return TRUE;
+}
+
+/* Generate Arm stubs for exported Thumb symbols.  */
+static void
+elf32_arm_begin_write_processing (bfd *abfd ATTRIBUTE_UNUSED, 
+				  struct bfd_link_info *link_info)
+{
+  struct elf32_arm_link_hash_table * globals;
+
+  if (!link_info)
+    return;
+
+  globals = elf32_arm_hash_table (link_info);
+  if (globals->use_blx)
+    return;
+
+  elf_link_hash_traverse (&globals->root, elf32_arm_to_thumb_export_stub,
+			  link_info);
+}
+
 /* Some relocations map to different relocations depending on the
    target.  Return the real relocation.  */
 static int
@@ -7462,6 +7557,36 @@ allocate_dynrelocs (struct elf_link_hash
   else
     h->got.offset = (bfd_vma) -1;
 
+  /* Allocate stubs for exported Thumb functions on v4t.  */
+  if (!htab->use_blx && h->dynindx != -1
+      && ELF_ST_TYPE (h->type) == STT_ARM_TFUNC
+      && ELF_ST_VISIBILITY (h->other) == STV_DEFAULT)
+    {
+      struct elf_link_hash_entry * th;
+      struct bfd_link_hash_entry * bh;
+      struct elf_link_hash_entry * myh;
+      char name[1024];
+      asection *s;
+      bh = NULL;
+      /* Create a new symbol to regist the real location of the function.  */
+      s = h->root.u.def.section;
+      sprintf(name, "__real_%s", h->root.root.string);
+      _bfd_generic_link_add_one_symbol (info, s->owner,
+					name, BSF_GLOBAL, s,
+					h->root.u.def.value,
+					NULL, TRUE, FALSE, &bh);
+
+      myh = (struct elf_link_hash_entry *) bh;
+      myh->type = ELF_ST_INFO (STB_LOCAL, STT_ARM_TFUNC);
+      myh->forced_local = 1;
+      eh->export_glue = myh;
+      th = record_arm_to_thumb_glue (info, h);
+      /* Point the symbol at the stub.  */
+      h->type = ELF_ST_INFO (ELF_ST_BIND (h->type), STT_FUNC);
+      h->root.u.def.section = th->root.u.def.section;
+      h->root.u.def.value = th->root.u.def.value & ~1;
+    }
+
   if (eh->relocs_copied == NULL)
     return TRUE;
 
@@ -9304,6 +9429,8 @@ const struct elf_size_info elf32_arm_siz
   elf32_arm_additional_program_headers
 #define elf_backend_output_arch_local_syms \
   elf32_arm_output_arch_local_syms
+#define elf_backend_begin_write_processing \
+    elf32_arm_begin_write_processing
 
 #define elf_backend_can_refcount    1
 #define elf_backend_can_gc_sections 1
@@ -9445,8 +9572,7 @@ elf32_arm_symbian_special_sections[] =
 
 static void
 elf32_arm_symbian_begin_write_processing (bfd *abfd, 
-					  struct bfd_link_info *link_info
-					    ATTRIBUTE_UNUSED)
+					  struct bfd_link_info *link_info)
 {
   /* BPABI objects are never loaded directly by an OS kernel; they are
      processed by a postlinker first, into an OS-specific format.  If
@@ -9457,6 +9583,7 @@ elf32_arm_symbian_begin_write_processing
      recognize that the program headers should not be mapped into any
      loadable segment.  */
   abfd->flags &= ~D_PAGED;
+  elf32_arm_begin_write_processing(abfd, link_info);
 }
 
 static bfd_boolean
Index: ld/emultempl/armelf.em
===================================================================
RCS file: /var/cvsroot/src-cvs/src/ld/emultempl/armelf.em,v
retrieving revision 1.49
diff -u -p -r1.49 armelf.em
--- ld/emultempl/armelf.em	7 Feb 2006 03:50:20 -0000	1.49
+++ ld/emultempl/armelf.em	17 Aug 2006 15:29:54 -0000
@@ -103,9 +103,6 @@ arm_elf_before_allocation (void)
 {
   bfd *tem;
 
-  /* Call the standard elf routine.  */
-  gld${EMULATION_NAME}_before_allocation ();
-
   if (link_info.input_bfds != NULL)
     {
       /* The interworking bfd must be the last one in the link.  */
@@ -126,6 +123,9 @@ arm_elf_before_allocation (void)
     }
   /* We should be able to set the size of the interworking stub section.  */
 
+  /* Call the standard elf routine.  */
+  gld${EMULATION_NAME}_before_allocation ();
+
   /* Here we rummage through the found bfds to collect glue information.  */
   /* FIXME: should this be based on a command line option? krk@cygnus.com  */
   {
Index: ld/testsuite/ld-arm/arm-elf.exp
===================================================================
RCS file: /var/cvsroot/src-cvs/src/ld/testsuite/ld-arm/arm-elf.exp,v
retrieving revision 1.11.2.5
diff -u -p -r1.11.2.5 arm-elf.exp
--- ld/testsuite/ld-arm/arm-elf.exp	19 Jun 2006 14:22:33 -0000	1.11.2.5
+++ ld/testsuite/ld-arm/arm-elf.exp	17 Aug 2006 17:21:24 -0000
@@ -77,7 +77,11 @@ set armelftests {
     {"Non-pcrel function reference" "tmpdir/arm-lib.so" "" {arm-app-abs32.s}
      {{objdump -fdw arm-app-abs32.d} {objdump -Rw arm-app-abs32.r}}
      "arm-app-abs32"}
-    {"Mixed ARM/Thumb shared library" "-shared -T arm-lib.ld" ""
+    {"Thumb shared library with ARM entry points" "-shared -T arm-lib.ld" ""
+     {mixed-lib.s}
+     {{objdump -fdw armthumb-lib.d} {readelf -Ds armthumb-lib.sym}}
+     "armthumb-lib.so"}
+    {"Mixed ARM/Thumb shared library" "-shared -T arm-lib.ld -use-blx" ""
      {mixed-lib.s}
      {{objdump -fdw mixed-lib.d} {objdump -Rw mixed-lib.r}
       {readelf -Ds mixed-lib.sym}}
Index: ld/testsuite/ld-arm/armthumb-lib.d
===================================================================
RCS file: ld/testsuite/ld-arm/armthumb-lib.d
diff -N ld/testsuite/ld-arm/armthumb-lib.d
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ ld/testsuite/ld-arm/armthumb-lib.d	17 Aug 2006 17:23:20 -0000
@@ -0,0 +1,44 @@
+
+tmpdir/armthumb-lib.so:     file format elf32-(little|big)arm
+architecture: arm, flags 0x00000150:
+HAS_SYMS, DYNAMIC, D_PAGED
+start address 0x.*
+
+Disassembly of section .plt:
+
+.* <.plt>:
+ .*:	e52de004 	str	lr, \[sp, #-4\]!
+ .*:	e59fe004 	ldr	lr, \[pc, #4\]	; .* <\.plt\+0x10>
+ .*:	e08fe00e 	add	lr, pc, lr
+ .*:	e5bef008 	ldr	pc, \[lr, #8\]!
+ .*:	.*
+ .*:	e28fc6.* 	add	ip, pc, #.*	; 0x.*
+ .*:	e28cca.* 	add	ip, ip, #.*	; 0x.*
+ .*:	e5bcf.* 	ldr	pc, \[ip, #.*\]!
+Disassembly of section .text:
+
+.* <lib_func1>:
+ .*:	e1a0c00d 	mov	ip, sp
+ .*:	e92dd800 	stmdb	sp!, {fp, ip, lr, pc}
+ .*:	ebfffff. 	bl	.* <.text-0x..>
+ .*:	e89d6800 	ldmia	sp, {fp, sp, lr}
+ .*:	e12fff1e 	bx	lr
+ .*:	e1a00000 	nop			\(mov r0,r0\)
+ .*:	e1a00000 	nop			\(mov r0,r0\)
+ .*:	e1a00000 	nop			\(mov r0,r0\)
+
+.* <__real_lib_func2>:
+ .*:	4770      	bx	lr
+ .*:	46c0      	nop			\(mov r8, r8\)
+ .*:	46c0      	nop			\(mov r8, r8\)
+ .*:	46c0      	nop			\(mov r8, r8\)
+ .*:	46c0      	nop			\(mov r8, r8\)
+ .*:	46c0      	nop			\(mov r8, r8\)
+ .*:	46c0      	nop			\(mov r8, r8\)
+ .*:	46c0      	nop			\(mov r8, r8\)
+
+.* <lib_func2>:
+ .*:	e59fc004 	ldr	ip, \[pc, #4\]	; 33c <lib_func2\+0xc>
+ .*:	e08cc00f 	add	ip, ip, pc
+ .*:	e12fff1c 	bx	ip
+ .*:	ffffffe5 	.*
Index: ld/testsuite/ld-arm/armthumb-lib.sym
===================================================================
RCS file: ld/testsuite/ld-arm/armthumb-lib.sym
diff -N ld/testsuite/ld-arm/armthumb-lib.sym
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ ld/testsuite/ld-arm/armthumb-lib.sym	17 Aug 2006 16:51:35 -0000
@@ -0,0 +1,18 @@
+
+Symbol table for image:
+  Num Buc:    Value  Size   Type   Bind Vis      Ndx Name
+   ..  ..: ........     0  NOTYPE GLOBAL DEFAULT ABS _edata
+   ..  ..: .......0    20    FUNC GLOBAL DEFAULT   6 lib_func1
+   ..  ..: .......0     2    FUNC GLOBAL DEFAULT   6 lib_func2
+   ..  ..: ........     0  NOTYPE GLOBAL DEFAULT ABS _bss_end__
+   ..  ..: ........     0  NOTYPE GLOBAL DEFAULT ABS __bss_end__
+   ..  ..: ........     0  NOTYPE GLOBAL DEFAULT ABS _stack
+   ..  ..: ........     4  OBJECT GLOBAL DEFAULT   9 data_obj
+   ..  ..: ........     0  NOTYPE GLOBAL DEFAULT ABS __bss_start__
+   ..  ..: ........     0  NOTYPE GLOBAL DEFAULT ABS __bss_start
+   ..  ..: ........     0  NOTYPE GLOBAL DEFAULT ABS _end
+   ..  ..: 00000000     0  NOTYPE GLOBAL DEFAULT UND app_func2
+   ..  ..: ........     0  NOTYPE GLOBAL DEFAULT ABS __exidx_end
+   ..  ..: ........     0  NOTYPE GLOBAL DEFAULT   9 __data_start
+   ..  ..: ........     0  NOTYPE GLOBAL DEFAULT ABS __end__
+   ..  ..: ........     0  NOTYPE GLOBAL DEFAULT ABS __exidx_start

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