binutils_2.16: patch thumb trampoline and glue code generation
authorJohn Bowler <jbowler@nslu2-linux.org>
Thu, 22 Sep 2005 19:36:38 +0000 (19:36 +0000)
committerOpenEmbedded Project <openembedded-devel@lists.openembedded.org>
Thu, 22 Sep 2005 19:36:38 +0000 (19:36 +0000)
This patch fixes problems with the ARM thumb specific code generation.  It
also adds debugging to bfd/elf32-arm.c to detect ref counting problems -
one error message can fire in theory in the absence of thumb support if
a union refcount field is used to refcount when it is set to something else.
The error should be ignorable, in that the code should not have changed in
effect.

packages/binutils/binutils-2.16/binutils-2.16-thumb-glue.patch [new file with mode: 0644]
packages/binutils/binutils-2.16/binutils-2.16-thumb-trampoline.patch [new file with mode: 0644]
packages/binutils/binutils_2.16.bb

diff --git a/packages/binutils/binutils-2.16/binutils-2.16-thumb-glue.patch b/packages/binutils/binutils-2.16/binutils-2.16-thumb-glue.patch
new file mode 100644 (file)
index 0000000..59d8035
--- /dev/null
@@ -0,0 +1,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);
diff --git a/packages/binutils/binutils-2.16/binutils-2.16-thumb-trampoline.patch b/packages/binutils/binutils-2.16/binutils-2.16-thumb-trampoline.patch
new file mode 100644 (file)
index 0000000..a4f90a7
--- /dev/null
@@ -0,0 +1,292 @@
+--- 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),
index 046f2c1..bb66ca6 100644 (file)
@@ -3,7 +3,7 @@ HOMEPAGE = "http://www.gnu.org/software/binutils/"
 SECTION = "devel"
 LICENSE = "GPL"
 MAINTAINER = "Gerald Britton <gbritton@doomcom.org>"
-PR = "r2"
+PR = "r3"
 
 SRC_URI = \
     "http://ftp.gnu.org/gnu/binutils/binutils-${PV}.tar.bz2 \
@@ -15,6 +15,10 @@ SRC_URI = \
 # uclibc patches
 SRC_URI += "file://binutils-2.16-linux-uclibc.patch;patch=1"
 
+# thumb support patches
+SRC_URI += "file://binutils-2.16-thumb-trampoline.patch;patch=1"
+SRC_URI += "file://binutils-2.16-thumb-glue.patch;patch=1"
+
 #to be removed:
 # this patch does not seem to do anything any longer
 #SRC_URI += "file://binutils-2.15.90.0.3-uclibc-200-build_modules.patch;patch=1"