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

	Backport from mainline.
	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.
diff --git a/ChangeLog.csl b/ChangeLog.csl
index c5adb77..6ccbea3 100644
--- a/ChangeLog.csl
+++ b/ChangeLog.csl
@@ -1,3 +1,29 @@
+2006-08-18  Paul Brook  <paul@codesourcery.com>
+
+	Backport from mainline.
+	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.
+
 2006-08-18  Julian Brown  <julian@codesourcery.com>
 
 	libiberty/
diff --git a/bfd/elf32-arm.c b/bfd/elf32-arm.c
index 9768d8c..64aa5c5 100644
--- a/bfd/elf32-arm.c
+++ b/bfd/elf32-arm.c
@@ -2089,6 +2089,10 @@
 #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 @@
       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 @@
   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 @@
     {
       /* 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 @@
   else
     globals->arm_glue_size += ARM2THUMB_STATIC_GLUE_SIZE;
 
-  return;
+  return myh;
 }
 
 static void
@@ -3191,30 +3198,25 @@
   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 @@
   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 @@
 
   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 @@
   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 @@
   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 @@
   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 @@
 
 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 @@
      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
diff --git a/ld/emultempl/armelf.em b/ld/emultempl/armelf.em
index bd74ab5..17fc522 100644
--- a/ld/emultempl/armelf.em
+++ b/ld/emultempl/armelf.em
@@ -103,9 +103,6 @@
 {
   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 @@
     }
   /* 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  */
   {
diff --git a/ld/testsuite/ld-arm/arm-elf.exp b/ld/testsuite/ld-arm/arm-elf.exp
index e8e6a85..eee3204 100644
--- a/ld/testsuite/ld-arm/arm-elf.exp
+++ b/ld/testsuite/ld-arm/arm-elf.exp
@@ -77,7 +77,11 @@
     {"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}}