gas/
[deliverable/binutils-gdb.git] / bfd / elf32-arm.c
index 3fc47a9fa6ae009ad4c9f6e5be248ba9d92fd214..cbde697360b069c35c0d8c37d829204e39cd15a5 100644 (file)
@@ -6,7 +6,7 @@
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
 
    This program is distributed in the hope that it will be useful,
    (at your option) any later version.
 
    This program is distributed in the hope that it will be useful,
@@ -16,7 +16,8 @@
 
    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
 
    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
-   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
+   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+   MA 02110-1301, USA.  */
 
 #include "sysdep.h"
 #include "bfd.h"
 
 #include "sysdep.h"
 #include "bfd.h"
@@ -2064,22 +2065,6 @@ _arm_elf_section_data;
 /* The size of the thread control block.  */
 #define TCB_SIZE       8
 
 /* The size of the thread control block.  */
 #define TCB_SIZE       8
 
-#define NUM_KNOWN_ATTRIBUTES 32
-
-typedef struct aeabi_attribute
-{
-  int type;
-  unsigned int i;
-  char *s;
-} aeabi_attribute;
-
-typedef struct aeabi_attribute_list
-{
-  struct aeabi_attribute_list *next;
-  int tag;
-  aeabi_attribute attr;
-} aeabi_attribute_list;
-
 struct elf32_arm_obj_tdata
 {
   struct elf_obj_tdata root;
 struct elf32_arm_obj_tdata
 {
   struct elf_obj_tdata root;
@@ -2087,9 +2072,6 @@ struct elf32_arm_obj_tdata
   /* tls_type for each local got entry.  */
   char *local_got_tls_type;
 
   /* tls_type for each local got entry.  */
   char *local_got_tls_type;
 
-  aeabi_attribute known_eabi_attributes[NUM_KNOWN_ATTRIBUTES];
-  aeabi_attribute_list *other_eabi_attributes;
-
   /* Zero to warn when linking objects with incompatible enum sizes.  */
   int no_enum_size_warning;
 };
   /* Zero to warn when linking objects with incompatible enum sizes.  */
   int no_enum_size_warning;
 };
@@ -2147,6 +2129,10 @@ struct elf32_arm_link_hash_entry
        so that we can emit the Thumb trampoline only if needed.  */
     bfd_signed_vma plt_thumb_refcount;
 
        so that we can emit the Thumb trampoline only if needed.  */
     bfd_signed_vma plt_thumb_refcount;
 
+    /* Some references from Thumb code may be eliminated by BL->BLX
+       conversion, so record them separately.  */
+    bfd_signed_vma plt_maybe_thumb_refcount;
+
     /* Since PLT entries have variable size if the Thumb prologue is
        used, we need to record the index into .got.plt instead of
        recomputing it from the PLT offset.  */
     /* Since PLT entries have variable size if the Thumb prologue is
        used, we need to record the index into .got.plt instead of
        recomputing it from the PLT offset.  */
@@ -2285,6 +2271,7 @@ elf32_arm_link_hash_newfunc (struct bfd_hash_entry * entry,
       ret->relocs_copied = NULL;
       ret->tls_type = GOT_UNKNOWN;
       ret->plt_thumb_refcount = 0;
       ret->relocs_copied = NULL;
       ret->tls_type = GOT_UNKNOWN;
       ret->plt_thumb_refcount = 0;
+      ret->plt_maybe_thumb_refcount = 0;
       ret->plt_got_offset = -1;
       ret->export_glue = NULL;
     }
       ret->plt_got_offset = -1;
       ret->export_glue = NULL;
     }
@@ -2440,6 +2427,8 @@ elf32_arm_copy_indirect_symbol (struct bfd_link_info *info,
       /* Copy over PLT info.  */
       edir->plt_thumb_refcount += eind->plt_thumb_refcount;
       eind->plt_thumb_refcount = 0;
       /* Copy over PLT info.  */
       edir->plt_thumb_refcount += eind->plt_thumb_refcount;
       eind->plt_thumb_refcount = 0;
+      edir->plt_maybe_thumb_refcount += eind->plt_maybe_thumb_refcount;
+      eind->plt_maybe_thumb_refcount = 0;
 
       if (dir->got.refcount <= 0)
        {
 
       if (dir->got.refcount <= 0)
        {
@@ -2531,9 +2520,10 @@ find_thumb_glue (struct bfd_link_info *link_info,
   hash = elf_link_hash_lookup
     (&(hash_table)->root, tmp_name, FALSE, FALSE, TRUE);
 
   hash = elf_link_hash_lookup
     (&(hash_table)->root, tmp_name, FALSE, FALSE, TRUE);
 
-  if (hash == NULL)
-    asprintf (error_message, _("unable to find THUMB glue '%s' for '%s'"),
-             tmp_name, name);
+  if (hash == NULL
+      && asprintf (error_message, _("unable to find THUMB glue '%s' for '%s'"),
+                  tmp_name, name) == -1)
+    *error_message = (char *) bfd_errmsg (bfd_error_system_call);
 
   free (tmp_name);
 
 
   free (tmp_name);
 
@@ -2564,9 +2554,10 @@ find_arm_glue (struct bfd_link_info *link_info,
   myh = elf_link_hash_lookup
     (&(hash_table)->root, tmp_name, FALSE, FALSE, TRUE);
 
   myh = elf_link_hash_lookup
     (&(hash_table)->root, tmp_name, FALSE, FALSE, TRUE);
 
-  if (myh == NULL)
-    asprintf (error_message, _("unable to find ARM glue '%s' for '%s'"),
-             tmp_name, name);
+  if (myh == NULL
+      && asprintf (error_message, _("unable to find ARM glue '%s' for '%s'"),
+                  tmp_name, name) == -1)
+    *error_message = (char *) bfd_errmsg (bfd_error_system_call);
 
   free (tmp_name);
 
 
   free (tmp_name);
 
@@ -2582,6 +2573,13 @@ find_arm_glue (struct bfd_link_info *link_info,
    __func_addr:
    .word func    @ behave as if you saw a ARM_32 reloc.  
 
    __func_addr:
    .word func    @ behave as if you saw a ARM_32 reloc.  
 
+   (v5t static images)
+   .arm
+   __func_from_arm:
+   ldr pc, __func_addr
+   __func_addr:
+   .word func    @ behave as if you saw a ARM_32 reloc.  
+
    (relocatable images)
    .arm
    __func_from_arm:
    (relocatable images)
    .arm
    __func_from_arm:
@@ -2597,6 +2595,10 @@ static const insn32 a2t1_ldr_insn = 0xe59fc000;
 static const insn32 a2t2_bx_r12_insn = 0xe12fff1c;
 static const insn32 a2t3_func_addr_insn = 0x00000001;
 
 static const insn32 a2t2_bx_r12_insn = 0xe12fff1c;
 static const insn32 a2t3_func_addr_insn = 0x00000001;
 
+#define ARM2THUMB_V5_STATIC_GLUE_SIZE 8
+static const insn32 a2t1v5_ldr_insn = 0xe51ff004;
+static const insn32 a2t2v5_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;
 #define ARM2THUMB_PIC_GLUE_SIZE 16
 static const insn32 a2t1p_ldr_insn = 0xe59fc004;
 static const insn32 a2t2p_add_pc_insn = 0xe08cc00f;
@@ -2745,6 +2747,8 @@ record_arm_to_thumb_glue (struct bfd_link_info * link_info,
   if (link_info->shared || globals->root.is_relocatable_executable
       || globals->pic_veneer)
     size = ARM2THUMB_PIC_GLUE_SIZE;
   if (link_info->shared || globals->root.is_relocatable_executable
       || globals->pic_veneer)
     size = ARM2THUMB_PIC_GLUE_SIZE;
+  else if (globals->use_blx)
+    size = ARM2THUMB_V5_STATIC_GLUE_SIZE;
   else
     size = ARM2THUMB_STATIC_GLUE_SIZE;
 
   else
     size = ARM2THUMB_STATIC_GLUE_SIZE;
 
@@ -3090,7 +3094,8 @@ bfd_elf32_arm_get_bfd_for_interworking (bfd *abfd, struct bfd_link_info *info)
 
 static void check_use_blx(struct elf32_arm_link_hash_table *globals)
 {
 
 static void check_use_blx(struct elf32_arm_link_hash_table *globals)
 {
-  if (elf32_arm_get_eabi_attr_int (globals->obfd, Tag_CPU_arch) > 2)
+  if (bfd_elf_get_obj_attr_int (globals->obfd, OBJ_ATTR_PROC,
+                               Tag_CPU_arch) > 2)
     globals->use_blx = 1;
 }
 
     globals->use_blx = 1;
 }
 
@@ -3166,7 +3171,8 @@ bfd_elf32_arm_process_before_allocation (bfd *abfd,
              && r_type != R_ARM_PLT32
              && r_type != R_ARM_CALL
              && r_type != R_ARM_JUMP24
              && r_type != R_ARM_PLT32
              && r_type != R_ARM_CALL
              && r_type != R_ARM_JUMP24
-             && r_type != R_ARM_THM_CALL)
+             && r_type != R_ARM_THM_CALL
+             && r_type != R_ARM_THM_JUMP24)
            continue;
 
          /* Get the section contents if we haven't done so already.  */
            continue;
 
          /* Get the section contents if we haven't done so already.  */
@@ -3220,10 +3226,13 @@ bfd_elf32_arm_process_before_allocation (bfd *abfd,
              break;
 
            case R_ARM_THM_CALL:
              break;
 
            case R_ARM_THM_CALL:
+           case R_ARM_THM_JUMP24:
              /* This one is a call from thumb code.  We look
                 up the target of the call.  If it is not a thumb
                  target, we insert glue.  */
              /* This one is a call from thumb code.  We look
                 up the target of the call.  If it is not a thumb
                  target, we insert glue.  */
-             if (ELF_ST_TYPE (h->type) != STT_ARM_TFUNC && !globals->use_blx)
+             if (ELF_ST_TYPE (h->type) != STT_ARM_TFUNC
+                 && !(globals->use_blx && r_type == R_ARM_THM_CALL)
+                 && h->root.type != bfd_link_hash_undefweak)
                record_thumb_to_arm_glue (link_info, h);
              break;
 
                record_thumb_to_arm_glue (link_info, h);
              break;
 
@@ -3307,7 +3316,7 @@ void
 bfd_elf32_arm_set_vfp11_fix (bfd *obfd, struct bfd_link_info *link_info)
 {
   struct elf32_arm_link_hash_table *globals = elf32_arm_hash_table (link_info);
 bfd_elf32_arm_set_vfp11_fix (bfd *obfd, struct bfd_link_info *link_info)
 {
   struct elf32_arm_link_hash_table *globals = elf32_arm_hash_table (link_info);
-  aeabi_attribute *out_attr = elf32_arm_tdata (obfd)->known_eabi_attributes;
+  obj_attribute *out_attr = elf_known_obj_attributes_proc (obfd);
   
   /* We assume that ARMv7+ does not need the VFP11 denorm erratum fix.  */
   if (out_attr[Tag_CPU_arch].i >= TAG_CPU_ARCH_V7)
   
   /* We assume that ARMv7+ does not need the VFP11 denorm erratum fix.  */
   if (out_attr[Tag_CPU_arch].i >= TAG_CPU_ARCH_V7)
@@ -4187,6 +4196,15 @@ elf32_arm_create_thumb_stub (struct bfd_link_info * info,
          bfd_put_32 (output_bfd, ret_offset,
                      s->contents + my_offset + 12);
        }
          bfd_put_32 (output_bfd, ret_offset,
                      s->contents + my_offset + 12);
        }
+      else if (globals->use_blx)
+       {
+         put_arm_insn (globals, output_bfd, (bfd_vma) a2t1v5_ldr_insn,
+                       s->contents + my_offset);
+
+         /* It's a thumb address.  Add the low order bit.  */
+         bfd_put_32 (output_bfd, val | a2t2v5_func_addr_insn,
+                     s->contents + my_offset + 4);
+       }
       else
        {
          put_arm_insn (globals, output_bfd, (bfd_vma) a2t1_ldr_insn,
       else
        {
          put_arm_insn (globals, output_bfd, (bfd_vma) a2t1_ldr_insn,
@@ -4465,7 +4483,8 @@ identify_add_or_sub(bfd_vma insn)
 
 static int using_thumb2 (struct elf32_arm_link_hash_table *globals)
 {
 
 static int using_thumb2 (struct elf32_arm_link_hash_table *globals)
 {
-  int arch = elf32_arm_get_eabi_attr_int (globals->obfd, Tag_CPU_arch);
+  int arch = bfd_elf_get_obj_attr_int (globals->obfd, OBJ_ATTR_PROC,
+                                      Tag_CPU_arch);
   return arch == TAG_CPU_ARCH_V6T2 || arch >= TAG_CPU_ARCH_V7;
 }
 
   return arch == TAG_CPU_ARCH_V6T2 || arch >= TAG_CPU_ARCH_V7;
 }
 
@@ -4790,40 +4809,43 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
          signed_addend = value;
          signed_addend >>= howto->rightshift;
 
          signed_addend = value;
          signed_addend >>= howto->rightshift;
 
-         /* It is not an error for an undefined weak reference to be
-            out of range.  Any program that branches to such a symbol
-            is going to crash anyway, so there is no point worrying
-            about getting the destination exactly right.  */
-         if (! h || h->root.type != bfd_link_hash_undefweak)
+         /* A branch to an undefined weak symbol is turned into a jump to
+            the next instruction.  */
+         if (h && h->root.type == bfd_link_hash_undefweak)
+           {
+             value = (bfd_get_32 (input_bfd, hit_data) & 0xf0000000)
+                     | 0x0affffff;
+           }
+         else
            {
              /* Perform a signed range check.  */
              if (   signed_addend >   ((bfd_signed_vma)  (howto->dst_mask >> 1))
                  || signed_addend < - ((bfd_signed_vma) ((howto->dst_mask + 1) >> 1)))
                return bfd_reloc_overflow;
            {
              /* Perform a signed range check.  */
              if (   signed_addend >   ((bfd_signed_vma)  (howto->dst_mask >> 1))
                  || signed_addend < - ((bfd_signed_vma) ((howto->dst_mask + 1) >> 1)))
                return bfd_reloc_overflow;
-           }
 
 
-         addend = (value & 2);
+             addend = (value & 2);
 
 
-         value = (signed_addend & howto->dst_mask)
-           | (bfd_get_32 (input_bfd, hit_data) & (~ howto->dst_mask));
+             value = (signed_addend & howto->dst_mask)
+               | (bfd_get_32 (input_bfd, hit_data) & (~ howto->dst_mask));
 
 
-         /* Set the H bit in the BLX instruction.  */
-         if (sym_flags == STT_ARM_TFUNC)
-           {
-             if (addend)
-               value |= (1 << 24);
-             else
-               value &= ~(bfd_vma)(1 << 24);
-           }
-         if (r_type == R_ARM_CALL)
-           {
-             /* Select the correct instruction (BL or BLX).  */
+             /* Set the H bit in the BLX instruction.  */
              if (sym_flags == STT_ARM_TFUNC)
              if (sym_flags == STT_ARM_TFUNC)
-               value |= (1 << 28);
-             else
                {
                {
-                 value &= ~(bfd_vma)(1 << 28);
-                 value |= (1 << 24);
+                 if (addend)
+                   value |= (1 << 24);
+                 else
+                   value &= ~(bfd_vma)(1 << 24);
+               }
+             if (r_type == R_ARM_CALL)
+               {
+                 /* Select the correct instruction (BL or BLX).  */
+                 if (sym_flags == STT_ARM_TFUNC)
+                   value |= (1 << 28);
+                 else
+                   {
+                     value &= ~(bfd_vma)(1 << 28);
+                     value |= (1 << 24);
+                   }
                }
            }
          break;
                }
            }
          break;
@@ -4986,6 +5008,7 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
 
     case R_ARM_THM_XPC22:
     case R_ARM_THM_CALL:
 
     case R_ARM_THM_XPC22:
     case R_ARM_THM_CALL:
+    case R_ARM_THM_JUMP24:
       /* Thumb BL (branch long instruction).  */
       {
        bfd_vma relocation;
       /* Thumb BL (branch long instruction).  */
       {
        bfd_vma relocation;
@@ -5000,6 +5023,15 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
        int bitsize;
        int thumb2 = using_thumb2 (globals);
 
        int bitsize;
        int thumb2 = using_thumb2 (globals);
 
+       /* A branch to an undefined weak symbol is turned into a jump to
+          the next instruction.  */
+       if (h && h->root.type == bfd_link_hash_undefweak)
+         {
+           bfd_put_16 (input_bfd, 0xe000, hit_data);
+           bfd_put_16 (input_bfd, 0xbf00, hit_data + 2);
+           return bfd_reloc_ok;
+         }
+
        /* Fetch the addend.  We use the Thumb-2 encoding (backwards compatible
            with Thumb-1) involving the J1 and J2 bits.  */
        if (globals->use_rel)
        /* Fetch the addend.  We use the Thumb-2 encoding (backwards compatible
            with Thumb-1) involving the J1 and J2 bits.  */
        if (globals->use_rel)
@@ -5040,7 +5072,7 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
                && (h == NULL || splt == NULL
                    || h->plt.offset == (bfd_vma) -1))
              {
                && (h == NULL || splt == NULL
                    || h->plt.offset == (bfd_vma) -1))
              {
-               if (globals->use_blx)
+               if (globals->use_blx && r_type == R_ARM_THM_CALL)
                  {
                    /* Convert BL to BLX.  */
                    lower_insn = (lower_insn & ~0x1000) | 0x0800;
                  {
                    /* Convert BL to BLX.  */
                    lower_insn = (lower_insn & ~0x1000) | 0x0800;
@@ -5053,7 +5085,8 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
                else
                  return bfd_reloc_dangerous;
              }
                else
                  return bfd_reloc_dangerous;
              }
-           else if (sym_flags == STT_ARM_TFUNC && globals->use_blx)
+           else if (sym_flags == STT_ARM_TFUNC && globals->use_blx
+                    && r_type == R_ARM_THM_CALL)
              {
                /* Make sure this is a BL.  */
                lower_insn |= 0x1800;
              {
                /* Make sure this is a BL.  */
                lower_insn |= 0x1800;
@@ -5066,7 +5099,7 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
            value = (splt->output_section->vma
                     + splt->output_offset
                     + h->plt.offset);
            value = (splt->output_section->vma
                     + splt->output_offset
                     + h->plt.offset);
-           if (globals->use_blx)
+           if (globals->use_blx && r_type == R_ARM_THM_CALL)
              {
                /* If the Thumb BLX instruction is available, convert the
                   BL to a BLX instruction to call the ARM-mode PLT entry.  */
              {
                /* If the Thumb BLX instruction is available, convert the
                   BL to a BLX instruction to call the ARM-mode PLT entry.  */
@@ -5106,7 +5139,7 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
        if (signed_check > reloc_signed_max || signed_check < reloc_signed_min)
          overflow = TRUE;
 
        if (signed_check > reloc_signed_max || signed_check < reloc_signed_min)
          overflow = TRUE;
 
-       if ((lower_insn & 0x1800) == 0x0800)
+       if ((lower_insn & 0x5000) == 0x4000)
          /* For a BLX instruction, make sure that the relocation is rounded up
             to a word boundary.  This follows the semantics of the instruction
             which specifies that bit 1 of the target address will come from bit
          /* For a BLX instruction, make sure that the relocation is rounded up
             to a word boundary.  This follows the semantics of the instruction
             which specifies that bit 1 of the target address will come from bit
@@ -5133,79 +5166,6 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
       }
       break;
 
       }
       break;
 
-    case R_ARM_THM_JUMP24:
-      /* Thumb32 unconditional branch instruction.  */
-      {
-       bfd_vma relocation;
-       bfd_boolean overflow = FALSE;
-       bfd_vma upper_insn = bfd_get_16 (input_bfd, hit_data);
-       bfd_vma lower_insn = bfd_get_16 (input_bfd, hit_data + 2);
-       bfd_signed_vma reloc_signed_max = ((1 << (howto->bitsize - 1)) - 1) >> howto->rightshift;
-       bfd_signed_vma reloc_signed_min = ~ reloc_signed_max;
-       bfd_vma check;
-       bfd_signed_vma signed_check;
-
-       /* Need to refetch the addend, reconstruct the top three bits, and glue the
-          two pieces together.  */
-       if (globals->use_rel)
-         {
-           bfd_vma S  = (upper_insn & 0x0400) >> 10;
-           bfd_vma hi = (upper_insn & 0x03ff);
-           bfd_vma I1 = (lower_insn & 0x2000) >> 13;
-           bfd_vma I2 = (lower_insn & 0x0800) >> 11;
-           bfd_vma lo = (lower_insn & 0x07ff);
-
-           I1 = !(I1 ^ S);
-           I2 = !(I2 ^ S);
-           S  = !S;
-
-           signed_addend = (S << 24) | (I1 << 23) | (I2 << 22) | (hi << 12) | (lo << 1);
-           signed_addend -= (1 << 24); /* Sign extend.  */
-         }
-
-       /* ??? Should handle interworking?  GCC might someday try to
-          use this for tail calls.  */
-
-       relocation = value + signed_addend;
-       relocation -= (input_section->output_section->vma
-                      + input_section->output_offset
-                      + rel->r_offset);
-
-       check = relocation >> howto->rightshift;
-
-       /* If this is a signed value, the rightshift just dropped
-          leading 1 bits (assuming twos complement).  */
-       if ((bfd_signed_vma) relocation >= 0)
-         signed_check = check;
-       else
-         signed_check = check | ~((bfd_vma) -1 >> howto->rightshift);
-
-       /* Assumes two's complement.  */
-       if (signed_check > reloc_signed_max || signed_check < reloc_signed_min)
-         overflow = TRUE;
-
-       /* Put RELOCATION back into the insn.  */
-       {
-         bfd_vma S  = (relocation & 0x01000000) >> 24;
-         bfd_vma I1 = (relocation & 0x00800000) >> 23;
-         bfd_vma I2 = (relocation & 0x00400000) >> 22;
-         bfd_vma hi = (relocation & 0x003ff000) >> 12;
-         bfd_vma lo = (relocation & 0x00000ffe) >>  1;
-
-         I1 = !(I1 ^ S);
-         I2 = !(I2 ^ S);
-
-         upper_insn = (upper_insn & (bfd_vma) 0xf800) | (S << 10) | hi;
-         lower_insn = (lower_insn & (bfd_vma) 0xd000) | (I1 << 13) | (I2 << 11) | lo;
-       }
-
-       /* Put the relocated value back in the object file:  */
-       bfd_put_16 (input_bfd, upper_insn, hit_data);
-       bfd_put_16 (input_bfd, lower_insn, hit_data + 2);
-
-       return (overflow ? bfd_reloc_overflow : bfd_reloc_ok);
-      }
-
     case R_ARM_THM_JUMP19:
       /* Thumb32 conditional branch instruction.  */
       {
     case R_ARM_THM_JUMP19:
       /* Thumb32 conditional branch instruction.  */
       {
@@ -5213,9 +5173,8 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
        bfd_boolean overflow = FALSE;
        bfd_vma upper_insn = bfd_get_16 (input_bfd, hit_data);
        bfd_vma lower_insn = bfd_get_16 (input_bfd, hit_data + 2);
        bfd_boolean overflow = FALSE;
        bfd_vma upper_insn = bfd_get_16 (input_bfd, hit_data);
        bfd_vma lower_insn = bfd_get_16 (input_bfd, hit_data + 2);
-       bfd_signed_vma reloc_signed_max = ((1 << (howto->bitsize - 1)) - 1) >> howto->rightshift;
-       bfd_signed_vma reloc_signed_min = ~ reloc_signed_max;
-       bfd_vma check;
+       bfd_signed_vma reloc_signed_max = 0xffffe;
+       bfd_signed_vma reloc_signed_min = -0x100000;
        bfd_signed_vma signed_check;
 
        /* Need to refetch the addend, reconstruct the top three bits,
        bfd_signed_vma signed_check;
 
        /* Need to refetch the addend, reconstruct the top three bits,
@@ -5223,20 +5182,31 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
        if (globals->use_rel)
          {
            bfd_vma S     = (upper_insn & 0x0400) >> 10;
        if (globals->use_rel)
          {
            bfd_vma S     = (upper_insn & 0x0400) >> 10;
-           bfd_vma upper = (upper_insn & 0x001f);
+           bfd_vma upper = (upper_insn & 0x003f);
            bfd_vma J1    = (lower_insn & 0x2000) >> 13;
            bfd_vma J2    = (lower_insn & 0x0800) >> 11;
            bfd_vma lower = (lower_insn & 0x07ff);
 
            bfd_vma J1    = (lower_insn & 0x2000) >> 13;
            bfd_vma J2    = (lower_insn & 0x0800) >> 11;
            bfd_vma lower = (lower_insn & 0x07ff);
 
-           upper |= J2 << 6;
-           upper |= J1 << 7;
-           upper |= ~S << 8;
+           upper |= J1 << 6;
+           upper |= J2 << 7;
+           upper |= (!S) << 8;
            upper -= 0x0100; /* Sign extend.  */
 
            addend = (upper << 12) | (lower << 1);
            signed_addend = addend;
          }
 
            upper -= 0x0100; /* Sign extend.  */
 
            addend = (upper << 12) | (lower << 1);
            signed_addend = addend;
          }
 
+       /* Handle calls via the PLT.  */
+       if (h != NULL && splt != NULL && h->plt.offset != (bfd_vma) -1)
+         {
+           value = (splt->output_section->vma
+                    + splt->output_offset
+                    + h->plt.offset);
+           /* Target the Thumb stub before the ARM PLT entry.  */
+           value -= PLT_THUMB_STUB_SIZE;
+           *unresolved_reloc_p = FALSE;
+         }
+
        /* ??? Should handle interworking?  GCC might someday try to
           use this for tail calls.  */
 
        /* ??? Should handle interworking?  GCC might someday try to
           use this for tail calls.  */
 
@@ -5244,17 +5214,8 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
        relocation -= (input_section->output_section->vma
                       + input_section->output_offset
                       + rel->r_offset);
        relocation -= (input_section->output_section->vma
                       + input_section->output_offset
                       + rel->r_offset);
+       signed_check = (bfd_signed_vma) relocation;
 
 
-       check = relocation >> howto->rightshift;
-
-       /* If this is a signed value, the rightshift just dropped
-          leading 1 bits (assuming twos complement).  */
-       if ((bfd_signed_vma) relocation >= 0)
-         signed_check = check;
-       else
-         signed_check = check | ~((bfd_vma) -1 >> howto->rightshift);
-
-       /* Assumes two's complement.  */
        if (signed_check > reloc_signed_max || signed_check < reloc_signed_min)
          overflow = TRUE;
 
        if (signed_check > reloc_signed_max || signed_check < reloc_signed_min)
          overflow = TRUE;
 
@@ -5266,7 +5227,7 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
          bfd_vma hi = (relocation & 0x0003f000) >> 12;
          bfd_vma lo = (relocation & 0x00000ffe) >>  1;
 
          bfd_vma hi = (relocation & 0x0003f000) >> 12;
          bfd_vma lo = (relocation & 0x00000ffe) >>  1;
 
-         upper_insn = (upper_insn & 0xfb30) | (S << 10) | hi;
+         upper_insn = (upper_insn & 0xfbc0) | (S << 10) | hi;
          lower_insn = (lower_insn & 0xd000) | (J1 << 13) | (J2 << 11) | lo;
        }
 
          lower_insn = (lower_insn & 0xd000) | (J1 << 13) | (J2 << 11) | lo;
        }
 
@@ -6248,194 +6209,6 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
     }
 }
 
     }
 }
 
-
-static int
-uleb128_size (unsigned int i)
-{
-  int size;
-  size = 1;
-  while (i >= 0x80)
-    {
-      i >>= 7;
-      size++;
-    }
-  return size;
-}
-
-/* Return TRUE if the attribute has the default value (0/"").  */
-static bfd_boolean
-is_default_attr (aeabi_attribute *attr)
-{
-  if ((attr->type & 1) && attr->i != 0)
-    return FALSE;
-  if ((attr->type & 2) && attr->s && *attr->s)
-    return FALSE;
-
-  return TRUE;
-}
-
-/* Return the size of a single attribute.  */
-static bfd_vma
-eabi_attr_size(int tag, aeabi_attribute *attr)
-{
-  bfd_vma size;
-
-  if (is_default_attr (attr))
-    return 0;
-
-  size = uleb128_size (tag);
-  if (attr->type & 1)
-    size += uleb128_size (attr->i);
-  if (attr->type & 2)
-    size += strlen ((char *)attr->s) + 1;
-  return size;
-}
-  
-/* Returns the size of the eabi object attributess section.  */
-bfd_vma
-elf32_arm_eabi_attr_size (bfd *abfd)
-{
-  bfd_vma size;
-  aeabi_attribute *attr;
-  aeabi_attribute_list *list;
-  int i;
-
-  attr = elf32_arm_tdata (abfd)->known_eabi_attributes;
-  size = 16; /* 'A' <size> "aeabi" 0x1 <size>.  */
-  for (i = 4; i < NUM_KNOWN_ATTRIBUTES; i++)
-    size += eabi_attr_size (i, &attr[i]);
-
-  for (list = elf32_arm_tdata (abfd)->other_eabi_attributes;
-       list;
-       list = list->next)
-    size += eabi_attr_size (list->tag, &list->attr);
-
-  return size;
-}
-
-static bfd_byte *
-write_uleb128 (bfd_byte *p, unsigned int val)
-{
-  bfd_byte c;
-  do
-    {
-      c = val & 0x7f;
-      val >>= 7;
-      if (val)
-       c |= 0x80;
-      *(p++) = c;
-    }
-  while (val);
-  return p;
-}
-
-/* Write attribute ATTR to butter P, and return a pointer to the following
-   byte.  */
-static bfd_byte *
-write_eabi_attribute (bfd_byte *p, int tag, aeabi_attribute *attr)
-{
-  /* Suppress default entries.  */
-  if (is_default_attr(attr))
-    return p;
-
-  p = write_uleb128 (p, tag);
-  if (attr->type & 1)
-    p = write_uleb128 (p, attr->i);
-  if (attr->type & 2)
-    {
-      int len;
-
-      len = strlen (attr->s) + 1;
-      memcpy (p, attr->s, len);
-      p += len;
-    }
-
-  return p;
-}
-
-/* Write the contents of the eabi attributes section to p.  */
-void
-elf32_arm_set_eabi_attr_contents (bfd *abfd, bfd_byte *contents, bfd_vma size)
-{
-  bfd_byte *p;
-  aeabi_attribute *attr;
-  aeabi_attribute_list *list;
-  int i;
-
-  p = contents;
-  *(p++) = 'A';
-  bfd_put_32 (abfd, size - 1, p);
-  p += 4;
-  memcpy (p, "aeabi", 6);
-  p += 6;
-  *(p++) = Tag_File;
-  bfd_put_32 (abfd, size - 11, p);
-  p += 4;
-
-  attr = elf32_arm_tdata (abfd)->known_eabi_attributes;
-  for (i = 4; i < NUM_KNOWN_ATTRIBUTES; i++)
-    p = write_eabi_attribute (p, i, &attr[i]);
-
-  for (list = elf32_arm_tdata (abfd)->other_eabi_attributes;
-       list;
-       list = list->next)
-    p = write_eabi_attribute (p, list->tag, &list->attr);
-}
-
-/* Override final_link to handle EABI object attribute sections.  */
-
-static bfd_boolean
-elf32_arm_bfd_final_link (bfd *abfd, struct bfd_link_info *info)
-{
-  asection *o;
-  struct bfd_link_order *p;
-  asection *attr_section = NULL;
-  bfd_byte *contents;
-  bfd_vma size = 0;
-
-  /* elf32_arm_merge_private_bfd_data will already have merged the
-     object attributes.  Remove the input sections from the link, and set
-     the contents of the output secton.  */
-  for (o = abfd->sections; o != NULL; o = o->next)
-    {
-      if (strcmp (o->name, ".ARM.attributes") == 0)
-       {
-         for (p = o->map_head.link_order; p != NULL; p = p->next)
-           {
-             asection *input_section;
-
-             if (p->type != bfd_indirect_link_order)
-               continue;
-             input_section = p->u.indirect.section;
-             /* Hack: reset the SEC_HAS_CONTENTS flag so that
-                elf_link_input_bfd ignores this section.  */
-             input_section->flags &= ~SEC_HAS_CONTENTS;
-           }
-           
-         size = elf32_arm_eabi_attr_size (abfd);
-         bfd_set_section_size (abfd, o, size);
-         attr_section = o;
-         /* Skip this section later on.  */
-         o->map_head.link_order = NULL;
-       }
-    }
-  /* Invoke the ELF linker to do all the work.  */
-  if (!bfd_elf_final_link (abfd, info))
-    return FALSE;
-
-  if (attr_section)
-    {
-      contents = bfd_malloc(size);
-      if (contents == NULL)
-       return FALSE;
-      elf32_arm_set_eabi_attr_contents (abfd, contents, size);
-      bfd_set_section_contents (abfd, attr_section, contents, 0, size);
-      free (contents);
-    }
-  return TRUE;
-}
-
-
 /* Add INCREMENT to the reloc (of type HOWTO) at ADDRESS.  */
 static void
 arm_add_to_rel (bfd *              abfd,
 /* Add INCREMENT to the reloc (of type HOWTO) at ADDRESS.  */
 static void
 arm_add_to_rel (bfd *              abfd,
@@ -6445,7 +6218,8 @@ arm_add_to_rel (bfd *              abfd,
 {
   bfd_signed_vma addend;
 
 {
   bfd_signed_vma addend;
 
-  if (howto->type == R_ARM_THM_CALL)
+  if (howto->type == R_ARM_THM_CALL
+      || howto->type == R_ARM_THM_JUMP24)
     {
       int upper_insn, lower_insn;
       int upper, lower;
     {
       int upper_insn, lower_insn;
       int upper, lower;
@@ -6770,130 +6544,6 @@ elf32_arm_relocate_section (bfd *                  output_bfd,
   return TRUE;
 }
 
   return TRUE;
 }
 
-/* Allocate/find an object attribute.  */
-static aeabi_attribute *
-elf32_arm_new_eabi_attr (bfd *abfd, int tag)
-{
-  aeabi_attribute *attr;
-  aeabi_attribute_list *list;
-  aeabi_attribute_list *p;
-  aeabi_attribute_list **lastp;
-
-
-  if (tag < NUM_KNOWN_ATTRIBUTES)
-    {
-      /* Knwon tags are preallocated.  */
-      attr = &elf32_arm_tdata (abfd)->known_eabi_attributes[tag];
-    }
-  else
-    {
-      /* Create a new tag.  */
-      list = (aeabi_attribute_list *)
-       bfd_alloc (abfd, sizeof (aeabi_attribute_list));
-      memset (list, 0, sizeof (aeabi_attribute_list));
-      list->tag = tag;
-      /* Keep the tag list in order.  */
-      lastp = &elf32_arm_tdata (abfd)->other_eabi_attributes;
-      for (p = *lastp; p; p = p->next)
-       {
-         if (tag < p->tag)
-           break;
-         lastp = &p->next;
-       }
-      list->next = *lastp;
-      *lastp = list;
-      attr = &list->attr;
-    }
-
-  return attr;
-}
-
-int
-elf32_arm_get_eabi_attr_int (bfd *abfd, int tag)
-{
-  aeabi_attribute_list *p;
-
-  if (tag < NUM_KNOWN_ATTRIBUTES)
-    {
-      /* Knwon tags are preallocated.  */
-      return elf32_arm_tdata (abfd)->known_eabi_attributes[tag].i;
-    }
-  else
-    {
-      for (p = elf32_arm_tdata (abfd)->other_eabi_attributes;
-          p;
-          p = p->next)
-       {
-         if (tag == p->tag)
-           return p->attr.i;
-         if (tag < p->tag)
-           break;
-       }
-      return 0;
-    }
-}
-
-void
-elf32_arm_add_eabi_attr_int (bfd *abfd, int tag, unsigned int i)
-{
-  aeabi_attribute *attr;
-
-  attr = elf32_arm_new_eabi_attr (abfd, tag);
-  attr->type = 1;
-  attr->i = i;
-}
-
-static char *
-attr_strdup (bfd *abfd, const char * s)
-{
-  char * p;
-  int len;
-  
-  len = strlen (s) + 1;
-  p = (char *)bfd_alloc(abfd, len);
-  return memcpy (p, s, len);
-}
-
-void
-elf32_arm_add_eabi_attr_string (bfd *abfd, int tag, const char *s)
-{
-  aeabi_attribute *attr;
-
-  attr = elf32_arm_new_eabi_attr (abfd, tag);
-  attr->type = 2;
-  attr->s = attr_strdup (abfd, s);
-}
-
-void
-elf32_arm_add_eabi_attr_compat (bfd *abfd, unsigned int i, const char *s)
-{
-  aeabi_attribute_list *list;
-  aeabi_attribute_list *p;
-  aeabi_attribute_list **lastp;
-
-  list = (aeabi_attribute_list *)
-    bfd_alloc (abfd, sizeof (aeabi_attribute_list));
-  memset (list, 0, sizeof (aeabi_attribute_list));
-  list->tag = Tag_compatibility;
-  list->attr.type = 3;
-  list->attr.i = i;
-  list->attr.s = attr_strdup (abfd, s);
-
-  lastp = &elf32_arm_tdata (abfd)->other_eabi_attributes;
-  for (p = *lastp; p; p = p->next)
-    {
-      int cmp;
-      if (p->tag != Tag_compatibility)
-       break;
-      cmp = strcmp(s, p->attr.s);
-      if (cmp < 0 || (cmp == 0 && i < p->attr.i))
-       break;
-      lastp = &p->next;
-    }
-  list->next = *lastp;
-  *lastp = list;
-}
-
 /* Set the right machine number.  */
 
 static bfd_boolean
 /* Set the right machine number.  */
 
 static bfd_boolean
@@ -6944,49 +6594,6 @@ elf32_arm_set_private_flags (bfd *abfd, flagword flags)
   return TRUE;
 }
 
   return TRUE;
 }
 
-/* Copy the eabi object attribute from IBFD to OBFD.  */
-static void
-copy_eabi_attributes (bfd *ibfd, bfd *obfd)
-{
-  aeabi_attribute *in_attr;
-  aeabi_attribute *out_attr;
-  aeabi_attribute_list *list;
-  int i;
-
-  in_attr = &elf32_arm_tdata (ibfd)->known_eabi_attributes[4];
-  out_attr = &elf32_arm_tdata (obfd)->known_eabi_attributes[4];
-  for (i = 4; i < NUM_KNOWN_ATTRIBUTES; i++)
-    {
-      out_attr->i = in_attr->i;
-      if (in_attr->s && *in_attr->s)
-       out_attr->s = attr_strdup (obfd, in_attr->s);
-      in_attr++;
-      out_attr++;
-    }
-
-  for (list = elf32_arm_tdata (ibfd)->other_eabi_attributes;
-       list;
-       list = list->next)
-    {
-      in_attr = &list->attr;
-      switch (in_attr->type)
-       {
-       case 1:
-         elf32_arm_add_eabi_attr_int (obfd, list->tag, in_attr->i);
-         break;
-       case 2:
-         elf32_arm_add_eabi_attr_string (obfd, list->tag, in_attr->s);
-         break;
-       case 3:
-         elf32_arm_add_eabi_attr_compat (obfd, in_attr->i, in_attr->s);
-         break;
-       default:
-         abort();
-       }
-    }
-}
-
-
 /* Copy backend specific data from one object module to another.  */
 
 static bfd_boolean
 /* Copy backend specific data from one object module to another.  */
 
 static bfd_boolean
@@ -7038,8 +6645,8 @@ elf32_arm_copy_private_bfd_data (bfd *ibfd, bfd *obfd)
   elf_elfheader (obfd)->e_ident[EI_OSABI] =
     elf_elfheader (ibfd)->e_ident[EI_OSABI];
 
   elf_elfheader (obfd)->e_ident[EI_OSABI] =
     elf_elfheader (ibfd)->e_ident[EI_OSABI];
 
-  /* Copy EABI object attributes.  */
-  copy_eabi_attributes (ibfd, obfd);
+  /* Copy object attributes.  */
+  _bfd_elf_copy_obj_attributes (ibfd, obfd);
 
   return TRUE;
 }
 
   return TRUE;
 }
@@ -7071,34 +6678,48 @@ enum
   AEABI_enum_forced_wide
 };
 
   AEABI_enum_forced_wide
 };
 
+/* Determine whether an object attribute tag takes an integer, a
+   string or both.  */
+static int
+elf32_arm_obj_attrs_arg_type (int tag)
+{
+  if (tag == Tag_compatibility)
+    return 3;
+  else if (tag == 4 || tag == 5)
+    return 2;
+  else if (tag < 32)
+    return 1;
+  else
+    return (tag & 1) != 0 ? 2 : 1;
+}
+
 /* Merge EABI object attributes from IBFD into OBFD.  Raise an error if there
    are conflicting attributes.  */
 static bfd_boolean
 elf32_arm_merge_eabi_attributes (bfd *ibfd, bfd *obfd)
 {
 /* Merge EABI object attributes from IBFD into OBFD.  Raise an error if there
    are conflicting attributes.  */
 static bfd_boolean
 elf32_arm_merge_eabi_attributes (bfd *ibfd, bfd *obfd)
 {
-  aeabi_attribute *in_attr;
-  aeabi_attribute *out_attr;
-  aeabi_attribute_list *in_list;
-  aeabi_attribute_list *out_list;
+  obj_attribute *in_attr;
+  obj_attribute *out_attr;
+  obj_attribute_list *in_list;
   /* Some tags have 0 = don't care, 1 = strong requirement,
      2 = weak requirement.  */
   static const int order_312[3] = {3, 1, 2};
   int i;
 
   /* Some tags have 0 = don't care, 1 = strong requirement,
      2 = weak requirement.  */
   static const int order_312[3] = {3, 1, 2};
   int i;
 
-  if (!elf32_arm_tdata (obfd)->known_eabi_attributes[0].i)
+  if (!elf_known_obj_attributes_proc (obfd)[0].i)
     {
       /* This is the first object.  Copy the attributes.  */
     {
       /* This is the first object.  Copy the attributes.  */
-      copy_eabi_attributes (ibfd, obfd);
+      _bfd_elf_copy_obj_attributes (ibfd, obfd);
 
       /* Use the Tag_null value to indicate the attributes have been
         initialized.  */
 
       /* Use the Tag_null value to indicate the attributes have been
         initialized.  */
-      elf32_arm_tdata (obfd)->known_eabi_attributes[0].i = 1;
+      elf_known_obj_attributes_proc (obfd)[0].i = 1;
 
       return TRUE;
     }
 
 
       return TRUE;
     }
 
-  in_attr = elf32_arm_tdata (ibfd)->known_eabi_attributes;
-  out_attr = elf32_arm_tdata (obfd)->known_eabi_attributes;
+  in_attr = elf_known_obj_attributes_proc (ibfd);
+  out_attr = elf_known_obj_attributes_proc (obfd);
   /* This needs to happen before Tag_ABI_FP_number_model is merged.  */
   if (in_attr[Tag_ABI_VFP_args].i != out_attr[Tag_ABI_VFP_args].i)
     {
   /* This needs to happen before Tag_ABI_FP_number_model is merged.  */
   if (in_attr[Tag_ABI_VFP_args].i != out_attr[Tag_ABI_VFP_args].i)
     {
@@ -7114,7 +6735,7 @@ elf32_arm_merge_eabi_attributes (bfd *ibfd, bfd *obfd)
        }
     }
 
        }
     }
 
-  for (i = 4; i < NUM_KNOWN_ATTRIBUTES; i++)
+  for (i = 4; i < NUM_KNOWN_OBJ_ATTRIBUTES; i++)
     {
       /* Merge this attribute with existing attributes.  */
       switch (i)
     {
       /* Merge this attribute with existing attributes.  */
       switch (i)
@@ -7126,7 +6747,7 @@ elf32_arm_merge_eabi_attributes (bfd *ibfd, bfd *obfd)
             name is non-NULL.  */
          if (in_attr[Tag_CPU_arch].i > out_attr[Tag_CPU_arch].i
              && in_attr[i].s)
             name is non-NULL.  */
          if (in_attr[Tag_CPU_arch].i > out_attr[Tag_CPU_arch].i
              && in_attr[i].s)
-           out_attr[i].s = attr_strdup(obfd, in_attr[i].s);
+           out_attr[i].s = _bfd_elf_attr_strdup (obfd, in_attr[i].s);
          break;
 
        case Tag_ABI_optimization_goals:
          break;
 
        case Tag_ABI_optimization_goals:
@@ -7266,63 +6887,33 @@ elf32_arm_merge_eabi_attributes (bfd *ibfd, bfd *obfd)
        default: /* All known attributes should be explicitly covered.   */
          abort ();
        }
        default: /* All known attributes should be explicitly covered.   */
          abort ();
        }
-    }
 
 
-  in_list = elf32_arm_tdata (ibfd)->other_eabi_attributes;
-  out_list = elf32_arm_tdata (ibfd)->other_eabi_attributes;
-  while (in_list && in_list->tag == Tag_compatibility)
-    {
-      in_attr = &in_list->attr;
-      if (in_attr->i == 0)
-       continue;
-      if (in_attr->i == 1)
-       {
-         _bfd_error_handler
-           (_("ERROR: %B: Must be processed by '%s' toolchain"),
-            ibfd, in_attr->s);
-         return FALSE;
-       }
-      if (!out_list || out_list->tag != Tag_compatibility
-         || strcmp (in_attr->s, out_list->attr.s) != 0)
-       {
-         /* Add this compatibility tag to the output.  */
-         elf32_arm_add_eabi_attr_compat (obfd, in_attr->i, in_attr->s);
-         continue;
-       }
-      out_attr = &out_list->attr;
-      /* Check all the input tags with the same identifier.  */
-      for (;;)
-       {
-         if (out_list->tag != Tag_compatibility
-             || in_attr->i != out_attr->i
-             || strcmp (in_attr->s, out_attr->s) != 0)
-           {
-             _bfd_error_handler
-               (_("ERROR: %B: Incompatible object tag '%s':%d"),
-                ibfd, in_attr->s, in_attr->i);
-             return FALSE;
-           }
-         in_list = in_list->next;
-         if (in_list->tag != Tag_compatibility
-             || strcmp (in_attr->s, in_list->attr.s) != 0)
+      if (in_attr[i].type && !out_attr[i].type)
+       switch (in_attr[i].type)
+         {
+         case 1:
+           if (out_attr[i].i)
+             out_attr[i].type = 1;
            break;
            break;
-         in_attr = &in_list->attr;
-         out_list = out_list->next;
-         if (out_list)
-           out_attr = &out_list->attr;
-       }
 
 
-      /* Check the output doesn't have extra tags with this identifier.  */
-      if (out_list && out_list->tag == Tag_compatibility
-         && strcmp (in_attr->s, out_list->attr.s) == 0)
-       {
-         _bfd_error_handler
-           (_("ERROR: %B: Incompatible object tag '%s':%d"),
-            ibfd, in_attr->s, out_list->attr.i);
-         return FALSE;
-       }
+         case 2:
+           if (out_attr[i].s)
+             out_attr[i].type = 2;
+           break;
+
+         default:
+           abort ();
+         }
     }
 
     }
 
+  /* Merge Tag_compatibility attributes and any common GNU ones.  */
+  _bfd_elf_merge_object_attributes (ibfd, obfd);
+
+  /* Check for any attributes not known on ARM.  */
+  in_list = elf_other_obj_attributes_proc (ibfd);
+  while (in_list && in_list->tag == Tag_compatibility)
+    in_list = in_list->next;
+
   for (; in_list; in_list = in_list->next)
     {
       if ((in_list->tag & 128) < 64)
   for (; in_list; in_list = in_list->next)
     {
       if ((in_list->tag & 128) < 64)
@@ -7762,6 +7353,8 @@ elf32_arm_gc_sweep_hook (bfd *                     abfd,
   sym_hashes = elf_sym_hashes (abfd);
   local_got_refcounts = elf_local_got_refcounts (abfd);
 
   sym_hashes = elf_sym_hashes (abfd);
   local_got_refcounts = elf_local_got_refcounts (abfd);
 
+  check_use_blx(globals);
+
   relend = relocs + sec->reloc_count;
   for (rel = relocs; rel < relend; rel++)
     {
   relend = relocs + sec->reloc_count;
   for (rel = relocs; rel < relend; rel++)
     {
@@ -7812,6 +7405,8 @@ elf32_arm_gc_sweep_hook (bfd *                     abfd,
        case R_ARM_JUMP24:
        case R_ARM_PREL31:
        case R_ARM_THM_CALL:
        case R_ARM_JUMP24:
        case R_ARM_PREL31:
        case R_ARM_THM_CALL:
+       case R_ARM_THM_JUMP24:
+       case R_ARM_THM_JUMP19:
        case R_ARM_MOVW_ABS_NC:
        case R_ARM_MOVT_ABS:
        case R_ARM_MOVW_PREL_NC:
        case R_ARM_MOVW_ABS_NC:
        case R_ARM_MOVT_ABS:
        case R_ARM_MOVW_PREL_NC:
@@ -7833,7 +7428,11 @@ elf32_arm_gc_sweep_hook (bfd *                     abfd,
              if (h->plt.refcount > 0)
                {
                  h->plt.refcount -= 1;
              if (h->plt.refcount > 0)
                {
                  h->plt.refcount -= 1;
-                 if (ELF32_R_TYPE (rel->r_info) == R_ARM_THM_CALL)
+                 if (r_type == R_ARM_THM_CALL)
+                   eh->plt_maybe_thumb_refcount--;
+
+                 if (r_type == R_ARM_THM_JUMP24
+                     || r_type == R_ARM_THM_JUMP19)
                    eh->plt_thumb_refcount--;
                }
 
                    eh->plt_thumb_refcount--;
                }
 
@@ -7874,7 +7473,6 @@ elf32_arm_check_relocs (bfd *abfd, struct bfd_link_info *info,
 {
   Elf_Internal_Shdr *symtab_hdr;
   struct elf_link_hash_entry **sym_hashes;
 {
   Elf_Internal_Shdr *symtab_hdr;
   struct elf_link_hash_entry **sym_hashes;
-  struct elf_link_hash_entry **sym_hashes_end;
   const Elf_Internal_Rela *rel;
   const Elf_Internal_Rela *rel_end;
   bfd *dynobj;
   const Elf_Internal_Rela *rel;
   const Elf_Internal_Rela *rel_end;
   bfd *dynobj;
@@ -7902,11 +7500,6 @@ elf32_arm_check_relocs (bfd *abfd, struct bfd_link_info *info,
 
   symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
   sym_hashes = elf_sym_hashes (abfd);
 
   symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
   sym_hashes = elf_sym_hashes (abfd);
-  sym_hashes_end = sym_hashes
-    + symtab_hdr->sh_size / sizeof (Elf32_External_Sym);
-
-  if (!elf_bad_symtab (abfd))
-    sym_hashes_end -= symtab_hdr->sh_info;
 
   rel_end = relocs + sec->reloc_count;
   for (rel = relocs; rel < rel_end; rel++)
 
   rel_end = relocs + sec->reloc_count;
   for (rel = relocs; rel < rel_end; rel++)
@@ -8035,6 +7628,8 @@ elf32_arm_check_relocs (bfd *abfd, struct bfd_link_info *info,
          case R_ARM_JUMP24:
          case R_ARM_PREL31:
          case R_ARM_THM_CALL:
          case R_ARM_JUMP24:
          case R_ARM_PREL31:
          case R_ARM_THM_CALL:
+         case R_ARM_THM_JUMP24:
+         case R_ARM_THM_JUMP19:
          case R_ARM_MOVW_ABS_NC:
          case R_ARM_MOVT_ABS:
          case R_ARM_MOVW_PREL_NC:
          case R_ARM_MOVW_ABS_NC:
          case R_ARM_MOVT_ABS:
          case R_ARM_MOVW_PREL_NC:
@@ -8062,14 +7657,23 @@ elf32_arm_check_relocs (bfd *abfd, struct bfd_link_info *info,
                if (r_type != R_ARM_ABS32
                     && r_type != R_ARM_REL32
                     && r_type != R_ARM_ABS32_NOI
                if (r_type != R_ARM_ABS32
                     && r_type != R_ARM_REL32
                     && r_type != R_ARM_ABS32_NOI
-                    && r_type != R_ARM_REL32_NOI)
+                    && r_type != R_ARM_REL32_NOI
+                    && r_type != R_ARM_ABS12)
                  h->needs_plt = 1;
 
                /* If we create a PLT entry, this relocation will reference
                   it, even if it's an ABS32 relocation.  */
                h->plt.refcount += 1;
 
                  h->needs_plt = 1;
 
                /* If we create a PLT entry, this relocation will reference
                   it, even if it's an ABS32 relocation.  */
                h->plt.refcount += 1;
 
+               /* It's too early to use htab->use_blx here, so we have to
+                  record possible blx references separately from
+                  relocs that definitely need a thumb stub.  */
+
                if (r_type == R_ARM_THM_CALL)
                if (r_type == R_ARM_THM_CALL)
+                 eh->plt_maybe_thumb_refcount += 1;
+
+               if (r_type == R_ARM_THM_JUMP24
+                   || r_type == R_ARM_THM_JUMP19)
                  eh->plt_thumb_refcount += 1;
              }
 
                  eh->plt_thumb_refcount += 1;
              }
 
@@ -8187,7 +7791,9 @@ elf32_arm_check_relocs (bfd *abfd, struct bfd_link_info *info,
         /* This relocation describes which C++ vtable entries are actually
            used.  Record for later use during GC.  */
         case R_ARM_GNU_VTENTRY:
         /* This relocation describes which C++ vtable entries are actually
            used.  Record for later use during GC.  */
         case R_ARM_GNU_VTENTRY:
-          if (!bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_offset))
+          BFD_ASSERT (h != NULL);
+          if (h != NULL
+              && !bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_offset))
             return FALSE;
           break;
         }
             return FALSE;
           break;
         }
@@ -8386,7 +7992,6 @@ elf32_arm_adjust_dynamic_symbol (struct bfd_link_info * info,
 {
   bfd * dynobj;
   asection * s;
 {
   bfd * dynobj;
   asection * s;
-  unsigned int power_of_two;
   struct elf32_arm_link_hash_entry * eh;
   struct elf32_arm_link_hash_table *globals;
 
   struct elf32_arm_link_hash_entry * eh;
   struct elf32_arm_link_hash_table *globals;
 
@@ -8421,6 +8026,7 @@ elf32_arm_adjust_dynamic_symbol (struct bfd_link_info * info,
             linkage table, and we can just do a PC24 reloc instead.  */
          h->plt.offset = (bfd_vma) -1;
          eh->plt_thumb_refcount = 0;
             linkage table, and we can just do a PC24 reloc instead.  */
          h->plt.offset = (bfd_vma) -1;
          eh->plt_thumb_refcount = 0;
+         eh->plt_maybe_thumb_refcount = 0;
          h->needs_plt = 0;
        }
 
          h->needs_plt = 0;
        }
 
@@ -8435,6 +8041,7 @@ elf32_arm_adjust_dynamic_symbol (struct bfd_link_info * info,
         the link may change h->type.  So fix it now.  */
       h->plt.offset = (bfd_vma) -1;
       eh->plt_thumb_refcount = 0;
         the link may change h->type.  So fix it now.  */
       h->plt.offset = (bfd_vma) -1;
       eh->plt_thumb_refcount = 0;
+      eh->plt_maybe_thumb_refcount = 0;
     }
 
   /* If this is a weak symbol, and there is a real definition, the
     }
 
   /* If this is a weak symbol, and there is a real definition, the
@@ -8499,28 +8106,7 @@ elf32_arm_adjust_dynamic_symbol (struct bfd_link_info * info,
       h->needs_copy = 1;
     }
 
       h->needs_copy = 1;
     }
 
-  /* We need to figure out the alignment required for this symbol.  I
-     have no idea how ELF linkers handle this.  */
-  power_of_two = bfd_log2 (h->size);
-  if (power_of_two > 3)
-    power_of_two = 3;
-
-  /* Apply the required alignment.  */
-  s->size = BFD_ALIGN (s->size, (bfd_size_type) (1 << power_of_two));
-  if (power_of_two > bfd_get_section_alignment (dynobj, s))
-    {
-      if (! bfd_set_section_alignment (dynobj, s, power_of_two))
-       return FALSE;
-    }
-
-  /* Define the symbol as being at this point in the section.  */
-  h->root.u.def.section = s;
-  h->root.u.def.value = s->size;
-
-  /* Increment the section size to make room for the symbol.  */
-  s->size += h->size;
-
-  return TRUE;
+  return _bfd_elf_adjust_dynamic_copy (h, s);
 }
 
 /* Allocate space in .plt, .got and associated reloc sections for
 }
 
 /* Allocate space in .plt, .got and associated reloc sections for
@@ -8533,6 +8119,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
   struct elf32_arm_link_hash_table *htab;
   struct elf32_arm_link_hash_entry *eh;
   struct elf32_arm_relocs_copied *p;
   struct elf32_arm_link_hash_table *htab;
   struct elf32_arm_link_hash_entry *eh;
   struct elf32_arm_relocs_copied *p;
+  bfd_signed_vma thumb_refs;
 
   eh = (struct elf32_arm_link_hash_entry *) h;
 
 
   eh = (struct elf32_arm_link_hash_entry *) h;
 
@@ -8574,7 +8161,11 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
 
          /* If we will insert a Thumb trampoline before this PLT, leave room
             for it.  */
 
          /* If we will insert a Thumb trampoline before this PLT, leave room
             for it.  */
-         if (!htab->use_blx && eh->plt_thumb_refcount > 0)
+         thumb_refs = eh->plt_thumb_refcount;
+         if (!htab->use_blx)
+           thumb_refs += eh->plt_maybe_thumb_refcount;
+
+         if (thumb_refs > 0)
            {
              h->plt.offset += PLT_THUMB_STUB_SIZE;
              s->size += PLT_THUMB_STUB_SIZE;
            {
              h->plt.offset += PLT_THUMB_STUB_SIZE;
              s->size += PLT_THUMB_STUB_SIZE;
@@ -9248,7 +8839,7 @@ elf32_arm_finish_dynamic_symbol (bfd * output_bfd, struct bfd_link_info * info,
              unsigned int i;
              bfd_vma val;
 
              unsigned int i;
              bfd_vma val;
 
-             for (i = 0; i != htab->plt_entry_size / 4; i++)
+             for (i = 0; i != htab->plt_entry_size / 4; i++, ptr += 4)
                {
                  val = elf32_arm_vxworks_exec_plt_entry[i];
                  if (i == 2)
                {
                  val = elf32_arm_vxworks_exec_plt_entry[i];
                  if (i == 2)
@@ -9283,6 +8874,7 @@ elf32_arm_finish_dynamic_symbol (bfd * output_bfd, struct bfd_link_info * info,
            }
          else
            {
            }
          else
            {
+             bfd_signed_vma thumb_refs;
              /* Calculate the displacement between the PLT slot and the
                 entry in the GOT.  The eight-byte offset accounts for the
                 value produced by adding to pc in the first instruction
              /* Calculate the displacement between the PLT slot and the
                 entry in the GOT.  The eight-byte offset accounts for the
                 value produced by adding to pc in the first instruction
@@ -9291,7 +8883,11 @@ elf32_arm_finish_dynamic_symbol (bfd * output_bfd, struct bfd_link_info * info,
 
              BFD_ASSERT ((got_displacement & 0xf0000000) == 0);
 
 
              BFD_ASSERT ((got_displacement & 0xf0000000) == 0);
 
-             if (!htab->use_blx && eh->plt_thumb_refcount > 0)
+             thumb_refs = eh->plt_thumb_refcount;
+             if (!htab->use_blx)
+               thumb_refs += eh->plt_maybe_thumb_refcount;
+
+             if (thumb_refs > 0)
                {
                  put_thumb_insn (htab, output_bfd,
                                  elf32_arm_plt_thumb_stub[0], ptr - 4);
                {
                  put_thumb_insn (htab, output_bfd,
                                  elf32_arm_plt_thumb_stub[0], ptr - 4);
@@ -9795,125 +9391,9 @@ elf32_arm_fake_sections (bfd * abfd, Elf_Internal_Shdr * hdr, asection * sec)
       hdr->sh_type = SHT_ARM_EXIDX;
       hdr->sh_flags |= SHF_LINK_ORDER;
     }
       hdr->sh_type = SHT_ARM_EXIDX;
       hdr->sh_flags |= SHF_LINK_ORDER;
     }
-  else if (strcmp(name, ".ARM.attributes") == 0)
-    {
-      hdr->sh_type = SHT_ARM_ATTRIBUTES;
-    }
   return TRUE;
 }
 
   return TRUE;
 }
 
-/* Parse an Arm EABI attributes section.  */
-static void
-elf32_arm_parse_attributes (bfd *abfd, Elf_Internal_Shdr * hdr)
-{
-  bfd_byte *contents;
-  bfd_byte *p;
-  bfd_vma len;
-
-  contents = bfd_malloc (hdr->sh_size);
-  if (!contents)
-    return;
-  if (!bfd_get_section_contents (abfd, hdr->bfd_section, contents, 0,
-                                hdr->sh_size))
-    {
-      free (contents);
-      return;
-    }
-  p = contents;
-  if (*(p++) == 'A')
-    {
-      len = hdr->sh_size - 1;
-      while (len > 0)
-       {
-         int namelen;
-         bfd_vma section_len;
-
-         section_len = bfd_get_32 (abfd, p);
-         p += 4;
-         if (section_len > len)
-           section_len = len;
-         len -= section_len;
-         namelen = strlen ((char *)p) + 1;
-         section_len -= namelen + 4;
-         if (strcmp((char *)p, "aeabi") != 0)
-           {
-             /* Vendor section.  Ignore it.  */
-             p += namelen + section_len;
-           }
-         else
-           {
-             p += namelen;
-             while (section_len > 0)
-               {
-                 int tag;
-                 unsigned int n;
-                 unsigned int val;
-                 bfd_vma subsection_len;
-                 bfd_byte *end;
-
-                 tag = read_unsigned_leb128 (abfd, p, &n);
-                 p += n;
-                 subsection_len = bfd_get_32 (abfd, p);
-                 p += 4;
-                 if (subsection_len > section_len)
-                   subsection_len = section_len;
-                 section_len -= subsection_len;
-                 subsection_len -= n + 4;
-                 end = p + subsection_len;
-                 switch (tag)
-                   {
-                   case Tag_File:
-                     while (p < end)
-                       {
-                         bfd_boolean is_string;
-
-                         tag = read_unsigned_leb128 (abfd, p, &n);
-                         p += n;
-                         if (tag == 4 || tag == 5)
-                           is_string = 1;
-                         else if (tag < 32)
-                           is_string = 0;
-                         else
-                           is_string = (tag & 1) != 0;
-                         if (tag == Tag_compatibility)
-                           {
-                             val = read_unsigned_leb128 (abfd, p, &n);
-                             p += n;
-                             elf32_arm_add_eabi_attr_compat (abfd, val,
-                                                             (char *)p);
-                             p += strlen ((char *)p) + 1;
-                           }
-                         else if (is_string)
-                           {
-                             elf32_arm_add_eabi_attr_string (abfd, tag,
-                                                             (char *)p);
-                             p += strlen ((char *)p) + 1;
-                           }
-                         else
-                           {
-                             val = read_unsigned_leb128 (abfd, p, &n);
-                             p += n;
-                             elf32_arm_add_eabi_attr_int (abfd, tag, val);
-                           }
-                       }
-                     break;
-                   case Tag_Section:
-                   case Tag_Symbol:
-                     /* Don't have anywhere convenient to attach these.
-                        Fall through for now.  */
-                   default:
-                     /* Ignore things we don't kow about.  */
-                     p += subsection_len;
-                     subsection_len = 0;
-                     break;
-                   }
-               }
-           }
-       }
-    }
-  free (contents);
-}
-
 /* Handle an ARM specific section when reading an object file.  This is
    called when bfd_section_from_shdr finds a section with an unknown
    type.  */
 /* Handle an ARM specific section when reading an object file.  This is
    called when bfd_section_from_shdr finds a section with an unknown
    type.  */
@@ -9943,8 +9423,6 @@ elf32_arm_section_from_shdr (bfd *abfd,
   if (! _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex))
     return FALSE;
 
   if (! _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex))
     return FALSE;
 
-  if (hdr->sh_type == SHT_ARM_ATTRIBUTES)
-    elf32_arm_parse_attributes(abfd, hdr);
   return TRUE;
 }
 
   return TRUE;
 }
 
@@ -10054,8 +9532,8 @@ typedef struct
 {
   void *finfo;
   struct bfd_link_info *info;
 {
   void *finfo;
   struct bfd_link_info *info;
-  int plt_shndx;
-  bfd_vma plt_offset;
+  asection *sec;
+  int sec_shndx;
   bfd_boolean (*func) (void *, const char *, Elf_Internal_Sym *,
                       asection *, struct elf_link_hash_entry *);
 } output_arch_syminfo;
   bfd_boolean (*func) (void *, const char *, Elf_Internal_Sym *,
                       asection *, struct elf_link_hash_entry *);
 } output_arch_syminfo;
@@ -10080,12 +9558,14 @@ elf32_arm_ouput_plt_map_sym (output_arch_syminfo *osi,
   Elf_Internal_Sym sym;
 
   htab = elf32_arm_hash_table (osi->info);
   Elf_Internal_Sym sym;
 
   htab = elf32_arm_hash_table (osi->info);
-  sym.st_value = osi->plt_offset + offset;
+  sym.st_value = osi->sec->output_section->vma
+                + osi->sec->output_offset
+                + offset;
   sym.st_size = 0;
   sym.st_other = 0;
   sym.st_info = ELF_ST_INFO (STB_LOCAL, STT_NOTYPE);
   sym.st_size = 0;
   sym.st_other = 0;
   sym.st_info = ELF_ST_INFO (STB_LOCAL, STT_NOTYPE);
-  sym.st_shndx = osi->plt_shndx;
-  if (!osi->func (osi->finfo, names[type], &sym, htab->splt, NULL))
+  sym.st_shndx = osi->sec_shndx;
+  if (!osi->func (osi->finfo, names[type], &sym, osi->sec, NULL))
     return FALSE;
   return TRUE;
 }
     return FALSE;
   return TRUE;
 }
@@ -10137,10 +9617,13 @@ elf32_arm_output_plt_map (struct elf_link_hash_entry *h, void *inf)
     }
   else
     {
     }
   else
     {
-      bfd_boolean thumb_stub;
+      bfd_signed_vma thumb_refs;
 
 
-      thumb_stub = eh->plt_thumb_refcount > 0 && !htab->use_blx;
-      if (thumb_stub)
+      thumb_refs = eh->plt_thumb_refcount;
+      if (!htab->use_blx)
+       thumb_refs += eh->plt_maybe_thumb_refcount;
+
+      if (thumb_refs > 0)
        {
          if (!elf32_arm_ouput_plt_map_sym (osi, ARM_MAP_THUMB, addr - 4))
            return FALSE;
        {
          if (!elf32_arm_ouput_plt_map_sym (osi, ARM_MAP_THUMB, addr - 4))
            return FALSE;
@@ -10154,7 +9637,7 @@ elf32_arm_output_plt_map (struct elf_link_hash_entry *h, void *inf)
       /* A three-word PLT with no Thumb thunk contains only Arm code, 
         so only need to output a mapping symbol for the first PLT entry and
         entries with thumb thunks.  */
       /* A three-word PLT with no Thumb thunk contains only Arm code, 
         so only need to output a mapping symbol for the first PLT entry and
         entries with thumb thunks.  */
-      if (thumb_stub || addr == 20)
+      if (thumb_refs > 0 || addr == 20)
        {
          if (!elf32_arm_ouput_plt_map_sym (osi, ARM_MAP_ARM, addr))
            return FALSE;
        {
          if (!elf32_arm_ouput_plt_map_sym (osi, ARM_MAP_ARM, addr))
            return FALSE;
@@ -10166,7 +9649,7 @@ elf32_arm_output_plt_map (struct elf_link_hash_entry *h, void *inf)
 }
 
 
 }
 
 
-/* Output mapping symbols for the PLT.  */
+/* Output mapping symbols for linker generated sections.  */
 
 static bfd_boolean
 elf32_arm_output_arch_local_syms (bfd *output_bfd,
 
 static bfd_boolean
 elf32_arm_output_arch_local_syms (bfd *output_bfd,
@@ -10178,19 +9661,63 @@ elf32_arm_output_arch_local_syms (bfd *output_bfd,
 {
   output_arch_syminfo osi;
   struct elf32_arm_link_hash_table *htab;
 {
   output_arch_syminfo osi;
   struct elf32_arm_link_hash_table *htab;
+  bfd_vma offset;
+  bfd_size_type size;
 
   htab = elf32_arm_hash_table (info);
 
   htab = elf32_arm_hash_table (info);
-  if (!htab->splt || htab->splt->size == 0)
-    return TRUE;
-
   check_use_blx(htab);
   check_use_blx(htab);
+
   osi.finfo = finfo;
   osi.info = info;
   osi.func = func;
   osi.finfo = finfo;
   osi.info = info;
   osi.func = func;
-  osi.plt_shndx = _bfd_elf_section_from_bfd_section (output_bfd,
-      htab->splt->output_section);
-  osi.plt_offset = htab->splt->output_section->vma;
+  
+  /* ARM->Thumb glue.  */
+  if (htab->arm_glue_size > 0)
+    {
+      osi.sec = bfd_get_section_by_name (htab->bfd_of_glue_owner,
+                                        ARM2THUMB_GLUE_SECTION_NAME);
+
+      osi.sec_shndx = _bfd_elf_section_from_bfd_section
+         (output_bfd, osi.sec->output_section);
+      if (info->shared || htab->root.is_relocatable_executable
+         || htab->pic_veneer)
+       size = ARM2THUMB_PIC_GLUE_SIZE;
+      else if (htab->use_blx)
+       size = ARM2THUMB_V5_STATIC_GLUE_SIZE;
+      else
+       size = ARM2THUMB_STATIC_GLUE_SIZE;
+
+      for (offset = 0; offset < htab->arm_glue_size; offset += size)
+       {
+         elf32_arm_ouput_plt_map_sym (&osi, ARM_MAP_ARM, offset);
+         elf32_arm_ouput_plt_map_sym (&osi, ARM_MAP_DATA, offset + size - 4);
+       }
+    }
+
+  /* Thumb->ARM glue.  */
+  if (htab->thumb_glue_size > 0)
+    {
+      osi.sec = bfd_get_section_by_name (htab->bfd_of_glue_owner,
+                                        THUMB2ARM_GLUE_SECTION_NAME);
+
+      osi.sec_shndx = _bfd_elf_section_from_bfd_section
+         (output_bfd, osi.sec->output_section);
+      size = THUMB2ARM_GLUE_SIZE;
+
+      for (offset = 0; offset < htab->thumb_glue_size; offset += size)
+       {
+         elf32_arm_ouput_plt_map_sym (&osi, ARM_MAP_THUMB, offset);
+         elf32_arm_ouput_plt_map_sym (&osi, ARM_MAP_ARM, offset + 4);
+       }
+    }
+
+  /* Finally, output mapping symbols for the PLT.  */
+  if (!htab->splt || htab->splt->size == 0)
+    return TRUE;
 
 
+  osi.sec_shndx = _bfd_elf_section_from_bfd_section (output_bfd,
+      htab->splt->output_section);
+  osi.sec = htab->splt;
   /* Output mapping symbols for the plt header.  SymbianOS does not have a
      plt header.  */
   if (htab->vxworks_p)
   /* Output mapping symbols for the plt header.  SymbianOS does not have a
      plt header.  */
   if (htab->vxworks_p)
@@ -10245,8 +9772,22 @@ elf32_arm_new_section_hook (bfd *abfd, asection *sec)
 static int
 elf32_arm_compare_mapping (const void * a, const void * b)
 {
 static int
 elf32_arm_compare_mapping (const void * a, const void * b)
 {
-  return ((const elf32_arm_section_map *) a)->vma
-        > ((const elf32_arm_section_map *) b)->vma;
+  const elf32_arm_section_map *amap = (const elf32_arm_section_map *) a;
+  const elf32_arm_section_map *bmap = (const elf32_arm_section_map *) b;
+
+  if (amap->vma > bmap->vma)
+    return 1;
+  else if (amap->vma < bmap->vma)
+    return -1;
+  else if (amap->type > bmap->type)
+    /* Ensure results do not depend on the host qsort for objects with
+       multiple mapping symbols at the same address by sorting on type
+       after vma.  */
+    return 1;
+  else if (amap->type < bmap->type)
+    return -1;
+  else
+    return 0;
 }
 
 
 }
 
 
@@ -10588,6 +10129,7 @@ const struct elf_size_info elf32_arm_size_info = {
   ELFCLASS32, EV_CURRENT,
   bfd_elf32_write_out_phdrs,
   bfd_elf32_write_shdrs_and_ehdr,
   ELFCLASS32, EV_CURRENT,
   bfd_elf32_write_out_phdrs,
   bfd_elf32_write_shdrs_and_ehdr,
+  bfd_elf32_checksum_contents,
   bfd_elf32_write_relocs,
   elf32_arm_swap_symbol_in,
   elf32_arm_swap_symbol_out,
   bfd_elf32_write_relocs,
   elf32_arm_swap_symbol_in,
   elf32_arm_swap_symbol_out,
@@ -10626,7 +10168,6 @@ const struct elf_size_info elf32_arm_size_info = {
 #define bfd_elf32_bfd_is_target_special_symbol elf32_arm_is_target_special_symbol
 #define bfd_elf32_close_and_cleanup             elf32_arm_close_and_cleanup
 #define bfd_elf32_bfd_free_cached_info          elf32_arm_bfd_free_cached_info
 #define bfd_elf32_bfd_is_target_special_symbol elf32_arm_is_target_special_symbol
 #define bfd_elf32_close_and_cleanup             elf32_arm_close_and_cleanup
 #define bfd_elf32_bfd_free_cached_info          elf32_arm_bfd_free_cached_info
-#define bfd_elf32_bfd_final_link               elf32_arm_bfd_final_link
 
 #define elf_backend_get_symbol_type             elf32_arm_get_symbol_type
 #define elf_backend_gc_mark_hook                elf32_arm_gc_mark_hook
 
 #define elf_backend_get_symbol_type             elf32_arm_get_symbol_type
 #define elf_backend_gc_mark_hook                elf32_arm_gc_mark_hook
@@ -10671,6 +10212,15 @@ const struct elf_size_info elf32_arm_size_info = {
 
 #define elf_backend_got_header_size    12
 
 
 #define elf_backend_got_header_size    12
 
+#undef elf_backend_obj_attrs_vendor
+#define elf_backend_obj_attrs_vendor   "aeabi"
+#undef elf_backend_obj_attrs_section
+#define elf_backend_obj_attrs_section  ".ARM.attributes"
+#undef elf_backend_obj_attrs_arg_type
+#define elf_backend_obj_attrs_arg_type elf32_arm_obj_attrs_arg_type
+#undef elf_backend_obj_attrs_section_type
+#define elf_backend_obj_attrs_section_type     SHT_ARM_ATTRIBUTES
+
 #include "elf32-target.h"
 
 /* VxWorks Targets */
 #include "elf32-target.h"
 
 /* VxWorks Targets */
This page took 0.042591 seconds and 4 git commands to generate.