--- binutils-2.16/.pc/binutils-2.16-thumb-trampoline.patch/bfd/elf32-arm.c	2005-05-02 12:43:06.000000000 -0700
+++ binutils-2.16/bfd/elf32-arm.c	2005-09-19 22:58:49.834931044 -0700
@@ -24,6 +24,8 @@
 #include "libbfd.h"
 #include "elf-bfd.h"
 
+#define NOTE_DEBUG 0
+
 #ifndef NUM_ELEM
 #define NUM_ELEM(a)  (sizeof (a) / (sizeof (a)[0]))
 #endif
@@ -1127,6 +1129,10 @@
        used, we need to record the index into .got.plt instead of
        recomputing it from the PLT offset.  */
     bfd_signed_vma plt_got_offset;
+
+    /* This is used to sanity check that the Thumb trampoline space
+       really was allocated.  */
+    int accomodate_trampoline;
   };
 
 /* Traverse an arm ELF linker hash table.  */
@@ -1219,9 +1225,15 @@
 				     table, string));
   if (ret != NULL)
     {
+#if NOTE_DEBUG
+      _bfd_error_handler(
+		_("NOTE: %x(%s): New hash entry (plt refcount %d)"),
+		ret, string, ret->root.plt.refcount);
+#endif
       ret->relocs_copied = NULL;
       ret->plt_thumb_refcount = 0;
       ret->plt_got_offset = -1;
+      ret->accomodate_trampoline = 0;
     }
 
   return (struct bfd_hash_entry *) ret;
@@ -1335,16 +1347,38 @@
       eind->relocs_copied = NULL;
     }
 
-  /* If the direct symbol already has an associated PLT entry, the
-     indirect symbol should not.  If it doesn't, swap refcount information
-     from the indirect symbol.  */
-  if (edir->plt_thumb_refcount == 0)
+  if (ind->root.type == bfd_link_hash_indirect)
     {
-      edir->plt_thumb_refcount = eind->plt_thumb_refcount;
-      eind->plt_thumb_refcount = 0;
+      bfd_signed_vma tmp;
+      bfd_signed_vma lowest_valid = bed->can_refcount;
+
+      /* If the direct symbol already has an associated PLT entry, the
+	 indirect symbol should not.  If it doesn't, swap refcount information
+	 from the indirect symbol.  */
+#if NOTE_DEBUG
+      _bfd_error_handler(_("NOTE: %x(%s,%d,%d) <== %x(%s,%d,%d)"),
+	dir, dir->root.root.string, dir->plt.refcount, edir->plt_thumb_refcount, 
+	ind, ind->root.root.string, ind->plt.refcount, eind->plt_thumb_refcount);
+#endif
+    
+      /* Copy over the global and procedure linkage table refcount entries.
+	 These may have been already set up by a check_relocs routine.  This
+	 code duplicates that for the plt refcount in elf.c
+	 _bfd_elf_link_hash_copy_indirect  */
+      tmp = dir->plt.refcount;
+      /* this obfuscated test evaluates to bed->can_refcount && plt.refcount == 0
+       * || plt.refcount < 0.
+       */
+      if (tmp < lowest_valid)
+	{
+	  tmp = edir->plt_thumb_refcount;
+	  edir->plt_thumb_refcount = eind->plt_thumb_refcount;
+	  eind->plt_thumb_refcount = tmp;
+	  BFD_ASSERT(eind->accomodate_trampoline == 0);
+	}
+      else
+	BFD_ASSERT (eind->plt_thumb_refcount == 0);
     }
-  else
-    BFD_ASSERT (eind->plt_thumb_refcount == 0);
 
   _bfd_elf_link_hash_copy_indirect (bed, dir, ind);
 }
@@ -2060,7 +2094,7 @@
 	  (*_bfd_error_handler)
 	    (_("%B(%s): warning: interworking not enabled.\n"
 	       "  first occurrence: %B: thumb call to arm"),
-	     sym_sec->owner, input_bfd, name);
+	     sym_sec->owner, name, input_bfd);
 
 	  return FALSE;
 	}
@@ -2165,7 +2199,7 @@
 	  (*_bfd_error_handler)
 	    (_("%B(%s): warning: interworking not enabled.\n"
 	       "  first occurrence: %B: arm call to thumb"),
-	     sym_sec->owner, input_bfd, name);
+	     sym_sec->owner, name, input_bfd);
 	}
 
       --my_offset;
@@ -2481,7 +2515,7 @@
 		 instruction instead ?  */
 	      if (sym_flags != STT_ARM_TFUNC)
 		(*_bfd_error_handler)
-		  (_("\%B: Warning: Arm BLX instruction targets Arm function '%s'."),
+		  (_("%B: Warning: Arm BLX instruction targets Arm function '%s'."),
 		   input_bfd,
 		   h ? h->root.root.string : "(local)");
 	    }
@@ -2697,6 +2731,20 @@
 	/* Handle calls via the PLT.  */
 	if (h != NULL && splt != NULL && h->plt.offset != (bfd_vma) -1)
 	  {
+	    struct elf32_arm_link_hash_entry *eh;
+	    eh = (struct elf32_arm_link_hash_entry *) h;
+	    if (!eh->accomodate_trampoline)
+	      {
+		/* %B of output_bfd crashes here, so %x is used instead */
+		_bfd_error_handler(
+			_("ERROR: %B: %x(%s): missing thumb trampoline, refcount(thumb %d, plt %d) in %x at %x+%x+%x"),
+			input_bfd, h, h->root.root.string, eh->plt_thumb_refcount,
+			h->plt.refcount, output_bfd, splt->output_section->vma,
+			splt->output_offset, h->plt.offset);
+		/* The relocation would point to garbage, it gets skipped... */
+		return bfd_reloc_dangerous;
+	      }
+
 	    value = (splt->output_section->vma
 		     + splt->output_offset
 		     + h->plt.offset);
@@ -3525,8 +3573,9 @@
     {
       _bfd_error_handler
 	(_("ERROR: Source object %B has EABI version %d, but target %B has EABI version %d"),
-	 ibfd, obfd,
+	 ibfd,
 	 (in_flags & EF_ARM_EABIMASK) >> 24,
+	 obfd,
 	 (out_flags & EF_ARM_EABIMASK) >> 24);
       return FALSE;
     }
@@ -3538,8 +3587,9 @@
 	{
 	  _bfd_error_handler
 	    (_("ERROR: %B is compiled for APCS-%d, whereas target %B uses APCS-%d"),
-	     ibfd, obfd,
+	     ibfd,
 	     in_flags & EF_ARM_APCS_26 ? 26 : 32,
+	     obfd,
 	     out_flags & EF_ARM_APCS_26 ? 26 : 32);
 	  flags_compatible = FALSE;
 	}
@@ -3903,10 +3953,18 @@
 	      eh = (struct elf32_arm_link_hash_entry *) h;
 
 	      if (h->plt.refcount > 0)
+		h->plt.refcount -= 1;
+
+	      if (ELF32_R_TYPE (rel->r_info) == R_ARM_THM_PC22)
 		{
-		  h->plt.refcount -= 1;
-		  if (ELF32_R_TYPE (rel->r_info) == R_ARM_THM_PC22)
-		    eh->plt_thumb_refcount--;
+		  BFD_ASSERT (eh->plt_thumb_refcount > 0);
+		  eh->plt_thumb_refcount--;
+		  BFD_ASSERT (eh->accomodate_trampoline == 0);
+#if NOTE_DEBUG
+		  _bfd_error_handler(
+			_("NOTE: %B: %x(%s): Thumb refcount decremented to %d (plt refcount %d)"),
+			abfd, h, h->root.root.string, eh->plt_thumb_refcount, h->plt.refcount);
+#endif
 		}
 
 	      if (r_type == R_ARM_ABS32
@@ -3994,6 +4052,10 @@
         h = sym_hashes[r_symndx - symtab_hdr->sh_info];
 
       eh = (struct elf32_arm_link_hash_entry *) h;
+#if NOTE_DEBUG
+      if (h != NULL)
+	_bfd_error_handler(_("NOTE: %B: %x(%s): verify relocation"), abfd, h, h->root.root.string);
+#endif
 
       switch (r_type)
         {
@@ -4078,10 +4140,30 @@
 
 		/* If we create a PLT entry, this relocation will reference
 		   it, even if it's an ABS32 relocation.  */
-		h->plt.refcount += 1;
+		if (h->plt.refcount >= 0)
+		  h->plt.refcount += 1;
+		else
+		  {
+		    /* This happens, I suspect it happens with glue code because,
+		     * somehow, the backend data had can_refcount==0.  Expert required...
+		     */
+		    _bfd_error_handler(
+			_("WARNING: %B: %x(%s): PLT refcount was %d (set to 1)"),
+			abfd, h, h->root.root.string, h->plt.refcount);
+		    h->plt.refcount = 1;
+		  }
 
 		if (r_type == R_ARM_THM_PC22)
-		  eh->plt_thumb_refcount += 1;
+		  {
+		    eh->plt_thumb_refcount += 1;
+		    BFD_ASSERT (eh->plt_thumb_refcount <= h->plt.refcount);
+		    BFD_ASSERT (eh->accomodate_trampoline == 0);
+#if NOTE_DEBUG
+		    _bfd_error_handler(
+			_("NOTE: %B: %x(%s): Thumb refcount incremented to %d (plt refcount %d)"),
+			abfd, h, h->root.root.string, eh->plt_thumb_refcount, h->plt.refcount);
+#endif
+		  }
 	      }
 
 	    /* If we are creating a shared library or relocatable executable,
@@ -4376,8 +4458,15 @@
 	     object, or if all references were garbage collected.  In
 	     such a case, we don't actually need to build a procedure
 	     linkage table, and we can just do a PC24 reloc instead.  */
+#if NOTE_DEBUG
+	  _bfd_error_handler(
+		_("NOTE: %x(%s): Thumb refcount zeroed (plt refcount %d, thumb %d) (%s)"),
+		h, h->root.root.string, h->plt.refcount, eh->plt_thumb_refcount,
+		SYMBOL_CALLS_LOCAL (info, h) ? "local call" : "invisible");
+#endif
 	  h->plt.offset = (bfd_vma) -1;
 	  eh->plt_thumb_refcount = 0;
+	  BFD_ASSERT (eh->accomodate_trampoline == 0);
 	  h->needs_plt = 0;
 	}
 
@@ -4390,8 +4479,14 @@
 	 in check_relocs.  We can't decide accurately between function
 	 and non-function syms in check-relocs; Objects loaded later in
 	 the link may change h->type.  So fix it now.  */
+#if NOTE_DEBUG
+      _bfd_error_handler(
+		_("NOTE: %x(%s): Thumb refcount zeroed (%d, plt refcount %d)"),
+		h, h->root.root.string, eh->plt_thumb_refcount, h->plt.refcount);
+#endif
       h->plt.offset = (bfd_vma) -1;
       eh->plt_thumb_refcount = 0;
+      BFD_ASSERT (eh->accomodate_trampoline == 0);
     }
 
   /* If this is a weak symbol, and there is a real definition, the
@@ -4521,8 +4616,14 @@
 	     for it.  */
 	  if (!htab->symbian_p && eh->plt_thumb_refcount > 0)
 	    {
+#if NOTE_DEBUG
+	      _bfd_error_handler(_("NOTE: %x(%s): Thumb trampoline created at %x"),
+					h, h->root.root.string, h->plt.offset);
+#endif
 	      h->plt.offset += PLT_THUMB_STUB_SIZE;
 	      s->size += PLT_THUMB_STUB_SIZE;
+	      BFD_ASSERT (eh->accomodate_trampoline == 0);
+	      eh->accomodate_trampoline = 1;
 	    }
 
 	  /* If this symbol is not defined in a regular file, and we are
@@ -5014,10 +5115,20 @@
 
 	  if (eh->plt_thumb_refcount > 0)
 	    {
-	      bfd_put_16 (output_bfd, elf32_arm_plt_thumb_stub[0],
-			  splt->contents + h->plt.offset - 4);
-	      bfd_put_16 (output_bfd, elf32_arm_plt_thumb_stub[1],
-			  splt->contents + h->plt.offset - 2);
+	      if (eh->accomodate_trampoline == 1)
+	        {
+	          bfd_put_16 (output_bfd, elf32_arm_plt_thumb_stub[0],
+			      splt->contents + h->plt.offset - 4);
+	          bfd_put_16 (output_bfd, elf32_arm_plt_thumb_stub[1],
+			      splt->contents + h->plt.offset - 2);
+	        }
+	      else
+		{
+		  (*_bfd_error_handler) (
+			_("%B: no space for THUMB trampoline at %x[%x]"),
+			output_bfd, h->plt.offset, got_offset);
+		  return FALSE;
+		}
 	    }
 
 	  bfd_put_32 (output_bfd, elf32_arm_plt_entry[0] | ((got_displacement & 0x0ff00000) >> 20),
