bfd/
[deliverable/binutils-gdb.git] / bfd / elf32-arm.c
index ed877f7ce3fa4013083789b95ab5214872826a9a..c81d7eab089cac8303c15bbf008e126a9debcb58 100644 (file)
@@ -1,6 +1,6 @@
 /* 32-bit ELF support for ARM
-   Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
-   Free Software Foundation, Inc.
+   Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
+   2008 Free Software Foundation, Inc.
 
    This file is part of BFD, the Binary File Descriptor library.
 
 #include "elf-vxworks.h"
 #include "elf/arm.h"
 
-#ifndef NUM_ELEM
-#define NUM_ELEM(a)  (sizeof (a) / (sizeof (a)[0]))
-#endif
-
 /* Return the relocation section associated with NAME.  HTAB is the
    bfd's elf32_arm_link_hash_entry.  */
 #define RELOC_SECTION(HTAB, NAME) \
@@ -696,8 +692,8 @@ static reloc_howto_type elf32_arm_howto_table_1[] =
         bfd_elf_generic_reloc, /* special_function */
         "R_ARM_MOVW_ABS_NC",   /* name */
         FALSE,                 /* partial_inplace */
-        0x0000ffff,            /* src_mask */
-        0x0000ffff,            /* dst_mask */
+        0x000f0fff,            /* src_mask */
+        0x000f0fff,            /* dst_mask */
         FALSE),                /* pcrel_offset */
 
   HOWTO (R_ARM_MOVT_ABS,       /* type */
@@ -710,8 +706,8 @@ static reloc_howto_type elf32_arm_howto_table_1[] =
         bfd_elf_generic_reloc, /* special_function */
         "R_ARM_MOVT_ABS",      /* name */
         FALSE,                 /* partial_inplace */
-        0x0000ffff,            /* src_mask */
-        0x0000ffff,            /* dst_mask */
+        0x000f0fff,            /* src_mask */
+        0x000f0fff,            /* dst_mask */
         FALSE),                /* pcrel_offset */
 
   HOWTO (R_ARM_MOVW_PREL_NC,   /* type */
@@ -724,8 +720,8 @@ static reloc_howto_type elf32_arm_howto_table_1[] =
         bfd_elf_generic_reloc, /* special_function */
         "R_ARM_MOVW_PREL_NC",  /* name */
         FALSE,                 /* partial_inplace */
-        0x0000ffff,            /* src_mask */
-        0x0000ffff,            /* dst_mask */
+        0x000f0fff,            /* src_mask */
+        0x000f0fff,            /* dst_mask */
         TRUE),                 /* pcrel_offset */
 
   HOWTO (R_ARM_MOVT_PREL,      /* type */
@@ -738,8 +734,8 @@ static reloc_howto_type elf32_arm_howto_table_1[] =
         bfd_elf_generic_reloc, /* special_function */
         "R_ARM_MOVT_PREL",     /* name */
         FALSE,                 /* partial_inplace */
-        0x0000ffff,            /* src_mask */
-        0x0000ffff,            /* dst_mask */
+        0x000f0fff,            /* src_mask */
+        0x000f0fff,            /* dst_mask */
         TRUE),                 /* pcrel_offset */
 
   HOWTO (R_ARM_THM_MOVW_ABS_NC,        /* type */
@@ -1668,11 +1664,11 @@ static reloc_howto_type elf32_arm_howto_table_2[4] =
 static reloc_howto_type *
 elf32_arm_howto_from_type (unsigned int r_type)
 {
-  if (r_type < NUM_ELEM (elf32_arm_howto_table_1))
+  if (r_type < ARRAY_SIZE (elf32_arm_howto_table_1))
     return &elf32_arm_howto_table_1[r_type];
 
   if (r_type >= R_ARM_RREL32
-      && r_type < R_ARM_RREL32 + NUM_ELEM (elf32_arm_howto_table_2))
+      && r_type < R_ARM_RREL32 + ARRAY_SIZE (elf32_arm_howto_table_2))
     return &elf32_arm_howto_table_2[r_type - R_ARM_RREL32];
 
   return NULL;
@@ -1773,7 +1769,8 @@ static const struct elf32_arm_reloc_map elf32_arm_reloc_map[] =
     {BFD_RELOC_ARM_LDRS_SB_G2, R_ARM_LDRS_SB_G2},
     {BFD_RELOC_ARM_LDC_SB_G0, R_ARM_LDC_SB_G0},
     {BFD_RELOC_ARM_LDC_SB_G1, R_ARM_LDC_SB_G1},
-    {BFD_RELOC_ARM_LDC_SB_G2, R_ARM_LDC_SB_G2}
+    {BFD_RELOC_ARM_LDC_SB_G2, R_ARM_LDC_SB_G2},
+    {BFD_RELOC_ARM_V4BX,            R_ARM_V4BX}
   };
 
 static reloc_howto_type *
@@ -1781,7 +1778,7 @@ elf32_arm_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
                             bfd_reloc_code_real_type code)
 {
   unsigned int i;
-  for (i = 0; i < NUM_ELEM (elf32_arm_reloc_map); i ++)
+  for (i = 0; i < ARRAY_SIZE (elf32_arm_reloc_map); i ++)
     if (elf32_arm_reloc_map[i].bfd_reloc_val == code)
       return elf32_arm_howto_from_type (elf32_arm_reloc_map[i].elf_reloc_val);
 
@@ -1794,18 +1791,12 @@ elf32_arm_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
 {
   unsigned int i;
 
-  for (i = 0;
-       i < (sizeof (elf32_arm_howto_table_1)
-           / sizeof (elf32_arm_howto_table_1[0]));
-       i++)
+  for (i = 0; i < ARRAY_SIZE (elf32_arm_howto_table_1); i++)
     if (elf32_arm_howto_table_1[i].name != NULL
        && strcasecmp (elf32_arm_howto_table_1[i].name, r_name) == 0)
       return &elf32_arm_howto_table_1[i];
 
-  for (i = 0;
-       i < (sizeof (elf32_arm_howto_table_2)
-           / sizeof (elf32_arm_howto_table_2[0]));
-       i++)
+  for (i = 0; i < ARRAY_SIZE (elf32_arm_howto_table_2); i++)
     if (elf32_arm_howto_table_2[i].name != NULL
        && strcasecmp (elf32_arm_howto_table_2[i].name, r_name) == 0)
       return &elf32_arm_howto_table_2[i];
@@ -1813,7 +1804,8 @@ elf32_arm_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
   return NULL;
 }
 
-/* Support for core dump NOTE sections */
+/* Support for core dump NOTE sections.  */
+
 static bfd_boolean
 elf32_arm_nabi_grok_prstatus (bfd *abfd, Elf_Internal_Note *note)
 {
@@ -1862,7 +1854,6 @@ elf32_arm_nabi_grok_psinfo (bfd *abfd, Elf_Internal_Note *note)
   /* Note that for some reason, a spurious space is tacked
      onto the end of the args in some (at least one anyway)
      implementations, so strip it off if it exists.  */
-
   {
     char *command = elf_tdata (abfd)->core_command;
     int n = strlen (command);
@@ -1904,6 +1895,9 @@ typedef unsigned short int insn16;
 #define VFP11_ERRATUM_VENEER_SECTION_NAME ".vfp11_veneer"
 #define VFP11_ERRATUM_VENEER_ENTRY_NAME   "__vfp11_veneer_%x"
 
+#define ARM_BX_GLUE_SECTION_NAME ".v4_bx"
+#define ARM_BX_GLUE_ENTRY_NAME   "__bx_r%d"
+
 /* The name of the dynamic interpreter.  This is put in the .interp
    section.  */
 #define ELF_DYNAMIC_INTERPRETER     "/usr/lib/ld.so.1"
@@ -2000,12 +1994,104 @@ static const bfd_vma elf32_arm_plt_thumb_stub [] =
 
 /* The entries in a PLT when using a DLL-based target with multiple
    address spaces.  */
-static const bfd_vma elf32_arm_symbian_plt_entry [] = 
+static const bfd_vma elf32_arm_symbian_plt_entry [] =
   {
     0xe51ff004,         /* ldr   pc, [pc, #-4] */
     0x00000000,         /* dcd   R_ARM_GLOB_DAT(X) */
   };
 
+#define ARM_MAX_FWD_BRANCH_OFFSET  ((((1 << 23) - 1) << 2) + 8)
+#define ARM_MAX_BWD_BRANCH_OFFSET  ((-((1 << 23) << 2)) + 8)
+#define THM_MAX_FWD_BRANCH_OFFSET  ((1 << 22) -2 + 4)
+#define THM_MAX_BWD_BRANCH_OFFSET  (-(1 << 22) + 4)
+#define THM2_MAX_FWD_BRANCH_OFFSET (((1 << 24) - 2) + 4)
+#define THM2_MAX_BWD_BRANCH_OFFSET (-(1 << 24) + 4)
+
+static const bfd_vma arm_long_branch_stub[] =
+  {
+    0xe51ff004,         /* ldr   pc, [pc, #-4] */
+    0x00000000,         /* dcd   R_ARM_ABS32(X) */
+  };
+
+static const bfd_vma arm_thumb_v4t_long_branch_stub[] =
+  {
+    0xe59fc000,         /* ldr   ip, [pc, #0] */
+    0xe12fff1c,         /* bx    ip */
+    0x00000000,         /* dcd   R_ARM_ABS32(X) */
+  };
+
+static const bfd_vma arm_thumb_thumb_long_branch_stub[] =
+  {
+    0x4e02b540,         /* push {r6, lr} */
+                        /* ldr  r6, [pc, #8] */
+    0xe7fe46fe,         /* mov  lr, pc */
+                        /* b.n  r6 */
+    0xbf00bd40,         /* pop  {r6, pc} */
+                        /* nop */
+    0x00000000,         /* dcd  R_ARM_ABS32(X) */
+  };
+
+static const bfd_vma arm_thumb_arm_v4t_long_branch_stub[] =
+  {
+    0x4e03b540,         /* push {r6, lr} */
+                        /* ldr  r6, [pc, #12] */
+    0x473046fe,         /* mov  lr, pc */
+                        /* bx   r6 */
+    0xe8bd4040,         /* pop  {r6, pc} */
+    0xe12fff1e,         /* bx   lr */
+    0x00000000,         /* dcd  R_ARM_ABS32(X) */
+  };
+
+static const bfd_vma arm_pic_long_branch_stub[] =
+  {
+    0xe59fc000,         /* ldr   r12, [pc] */
+    0xe08ff00c,         /* add   pc, pc, ip */
+    0x00000000,         /* dcd   R_ARM_ABS32(X) */
+  };
+
+/* Section name for stubs is the associated section name plus this
+   string.  */
+#define STUB_SUFFIX ".stub"
+
+enum elf32_arm_stub_type
+{
+  arm_stub_none,
+  arm_stub_long_branch,
+  arm_thumb_v4t_stub_long_branch,
+  arm_thumb_thumb_stub_long_branch,
+  arm_thumb_arm_v4t_stub_long_branch,
+  arm_stub_pic_long_branch,
+};
+
+struct elf32_arm_stub_hash_entry
+{
+  /* Base hash table entry structure.  */
+  struct bfd_hash_entry root;
+
+  /* The stub section.  */
+  asection *stub_sec;
+
+  /* Offset within stub_sec of the beginning of this stub.  */
+  bfd_vma stub_offset;
+
+  /* Given the symbol's value and its section we can determine its final
+     value when building the stubs (so the stub knows where to jump).  */
+  bfd_vma target_value;
+  asection *target_section;
+
+  enum elf32_arm_stub_type stub_type;
+
+  /* The symbol table entry, if any, that this was derived from.  */
+  struct elf32_arm_link_hash_entry *h;
+
+  /* Destination symbol type (STT_ARM_TFUNC, ...) */
+  unsigned char st_type;
+
+  /* Where this stub is being called from, or, in the case of combined
+     stub sections, the first input section in the group.  */
+  asection *id_sec;
+};
+
 /* Used to build a map of a section.  This is required for mixed-endian
    code/data.  */
 
@@ -2065,7 +2151,7 @@ _arm_elf_section_data;
 /* The size of the thread control block.  */
 #define TCB_SIZE       8
 
-struct elf32_arm_obj_tdata
+struct elf_arm_obj_tdata
 {
   struct elf_obj_tdata root;
 
@@ -2076,23 +2162,22 @@ struct elf32_arm_obj_tdata
   int no_enum_size_warning;
 };
 
-#define elf32_arm_tdata(abfd) \
-  ((struct elf32_arm_obj_tdata *) (abfd)->tdata.any)
+#define elf_arm_tdata(bfd) \
+  ((struct elf_arm_obj_tdata *) (bfd)->tdata.any)
 
-#define elf32_arm_local_got_tls_type(abfd) \
-  (elf32_arm_tdata (abfd)->local_got_tls_type)
+#define elf32_arm_local_got_tls_type(bfd) \
+  (elf_arm_tdata (bfd)->local_got_tls_type)
+
+#define is_arm_elf(bfd) \
+  (bfd_get_flavour (bfd) == bfd_target_elf_flavour \
+   && elf_tdata (bfd) != NULL \
+   && elf_object_id (bfd) == ARM_ELF_TDATA)
 
 static bfd_boolean
 elf32_arm_mkobject (bfd *abfd)
 {
-  if (abfd->tdata.any == NULL)
-    {
-      bfd_size_type amt = sizeof (struct elf32_arm_obj_tdata);
-      abfd->tdata.any = bfd_zalloc (abfd, amt);
-      if (abfd->tdata.any == NULL)
-       return FALSE;
-    }
-  return bfd_elf_mkobject (abfd);
+  return bfd_elf_allocate_object (abfd, sizeof (struct elf_arm_obj_tdata),
+                                 ARM_ELF_TDATA);
 }
 
 /* The ARM linker needs to keep track of the number of relocs that it
@@ -2129,6 +2214,10 @@ struct elf32_arm_link_hash_entry
        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.  */
@@ -2143,6 +2232,10 @@ struct elf32_arm_link_hash_entry
     /* The symbol marking the real symbol location for exported thumb
        symbols with Arm stubs.  */
     struct elf_link_hash_entry *export_glue;
+
+  /* A pointer to the most recently used stub hash entry against this
+     symbol. */
+  struct elf32_arm_stub_hash_entry *stub_cache;
   };
 
 /* Traverse an arm ELF linker hash table.  */
@@ -2156,90 +2249,130 @@ struct elf32_arm_link_hash_entry
 #define elf32_arm_hash_table(info) \
   ((struct elf32_arm_link_hash_table *) ((info)->hash))
 
+#define arm_stub_hash_lookup(table, string, create, copy) \
+  ((struct elf32_arm_stub_hash_entry *) \
+   bfd_hash_lookup ((table), (string), (create), (copy)))
+
 /* ARM ELF linker hash table.  */
 struct elf32_arm_link_hash_table
-  {
-    /* The main hash table.  */
-    struct elf_link_hash_table root;
+{
+  /* The main hash table.  */
+  struct elf_link_hash_table root;
 
-    /* The size in bytes of the section containing the Thumb-to-ARM glue.  */
-    bfd_size_type thumb_glue_size;
+  /* The size in bytes of the section containing the Thumb-to-ARM glue.  */
+  bfd_size_type thumb_glue_size;
 
-    /* The size in bytes of the section containing the ARM-to-Thumb glue.  */
-    bfd_size_type arm_glue_size;
+  /* The size in bytes of the section containing the ARM-to-Thumb glue.  */
+  bfd_size_type arm_glue_size;
 
-    /* The size in bytes of the section containing glue for VFP11 erratum
-       veneers.  */
-    bfd_size_type vfp11_erratum_glue_size;
+  /* The size in bytes of section containing the ARMv4 BX veneers.  */
+  bfd_size_type bx_glue_size;
 
-    /* An arbitrary input BFD chosen to hold the glue sections.  */
-    bfd * bfd_of_glue_owner;
+  /* Offsets of ARMv4 BX veneers.  Bit1 set if present, and Bit0 set when
+     veneer has been populated.  */
+  bfd_vma bx_glue_offset[15];
 
-    /* Nonzero to output a BE8 image.  */
-    int byteswap_code;
+  /* The size in bytes of the section containing glue for VFP11 erratum
+     veneers.  */
+  bfd_size_type vfp11_erratum_glue_size;
 
-    /* Zero if R_ARM_TARGET1 means R_ARM_ABS32.
-       Nonzero if R_ARM_TARGET1 means R_ARM_REL32.  */
-    int target1_is_rel;
+  /* An arbitrary input BFD chosen to hold the glue sections.  */
+  bfd * bfd_of_glue_owner;
 
-    /* The relocation to use for R_ARM_TARGET2 relocations.  */
-    int target2_reloc;
+  /* Nonzero to output a BE8 image.  */
+  int byteswap_code;
 
-    /* Nonzero to fix BX instructions for ARMv4 targets.  */
-    int fix_v4bx;
+  /* Zero if R_ARM_TARGET1 means R_ARM_ABS32.
+     Nonzero if R_ARM_TARGET1 means R_ARM_REL32.  */
+  int target1_is_rel;
 
-    /* Nonzero if the ARM/Thumb BLX instructions are available for use.  */
-    int use_blx;
+  /* The relocation to use for R_ARM_TARGET2 relocations.  */
+  int target2_reloc;
 
-    /* What sort of code sequences we should look for which may trigger the
-       VFP11 denorm erratum.  */
-    bfd_arm_vfp11_fix vfp11_fix;
+  /* 0 = Ignore R_ARM_V4BX.
+     1 = Convert BX to MOV PC.
+     2 = Generate v4 interworing stubs.  */
+  int fix_v4bx;
 
-    /* Global counter for the number of fixes we have emitted.  */
-    int num_vfp11_fixes;
+  /* Nonzero if the ARM/Thumb BLX instructions are available for use.  */
+  int use_blx;
 
-    /* Nonzero to force PIC branch veneers.  */
-    int pic_veneer;
+  /* What sort of code sequences we should look for which may trigger the
+     VFP11 denorm erratum.  */
+  bfd_arm_vfp11_fix vfp11_fix;
 
-    /* The number of bytes in the initial entry in the PLT.  */
-    bfd_size_type plt_header_size;
+  /* Global counter for the number of fixes we have emitted.  */
+  int num_vfp11_fixes;
 
-    /* The number of bytes in the subsequent PLT etries.  */
-    bfd_size_type plt_entry_size;
+  /* Nonzero to force PIC branch veneers.  */
+  int pic_veneer;
 
-    /* True if the target system is VxWorks.  */
-    int vxworks_p;
+  /* The number of bytes in the initial entry in the PLT.  */
+  bfd_size_type plt_header_size;
 
-    /* True if the target system is Symbian OS.  */
-    int symbian_p;
+  /* The number of bytes in the subsequent PLT etries.  */
+  bfd_size_type plt_entry_size;
 
-    /* True if the target uses REL relocations.  */
-    int use_rel;
+  /* True if the target system is VxWorks.  */
+  int vxworks_p;
 
-    /* Short-cuts to get to dynamic linker sections.  */
-    asection *sgot;
-    asection *sgotplt;
-    asection *srelgot;
-    asection *splt;
-    asection *srelplt;
-    asection *sdynbss;
-    asection *srelbss;
+  /* True if the target system is Symbian OS.  */
+  int symbian_p;
 
-    /* The (unloaded but important) VxWorks .rela.plt.unloaded section.  */
-    asection *srelplt2;
+  /* True if the target uses REL relocations.  */
+  int use_rel;
 
-    /* Data for R_ARM_TLS_LDM32 relocations.  */
-    union {
-      bfd_signed_vma refcount;
-      bfd_vma offset;
-    } tls_ldm_got;
-    
-    /* Small local sym to section mapping cache.  */
-    struct sym_sec_cache sym_sec;
+  /* Short-cuts to get to dynamic linker sections.  */
+  asection *sgot;
+  asection *sgotplt;
+  asection *srelgot;
+  asection *splt;
+  asection *srelplt;
+  asection *sdynbss;
+  asection *srelbss;
 
-    /* For convenience in allocate_dynrelocs.  */
-    bfd * obfd;
-  };
+  /* The (unloaded but important) VxWorks .rela.plt.unloaded section.  */
+  asection *srelplt2;
+
+  /* Data for R_ARM_TLS_LDM32 relocations.  */
+  union
+  {
+    bfd_signed_vma refcount;
+    bfd_vma offset;
+  } tls_ldm_got;
+
+  /* Small local sym to section mapping cache.  */
+  struct sym_sec_cache sym_sec;
+
+  /* For convenience in allocate_dynrelocs.  */
+  bfd * obfd;
+
+  /* The stub hash table.  */
+  struct bfd_hash_table stub_hash_table;
+
+  /* Linker stub bfd.  */
+  bfd *stub_bfd;
+
+  /* Linker call-backs.  */
+  asection * (*add_stub_section) (const char *, asection *);
+  void (*layout_sections_again) (void);
+
+  /* Array to keep track of which stub sections have been created, and
+     information on stub grouping.  */
+  struct map_stub
+  {
+    /* This is the section to which stubs in the group will be
+       attached.  */
+    asection *link_sec;
+    /* The stub section.  */
+    asection *stub_sec;
+  } *stub_group;
+
+  /* Assorted information used by elf32_arm_size_stubs.  */
+  unsigned int bfd_count;
+  int top_index;
+  asection **input_list;
+};
 
 /* Create an entry in an ARM ELF linker hash table.  */
 
@@ -2253,7 +2386,7 @@ elf32_arm_link_hash_newfunc (struct bfd_hash_entry * entry,
 
   /* Allocate the structure if it has not already been allocated by a
      subclass.  */
-  if (ret == (struct elf32_arm_link_hash_entry *) NULL)
+  if (ret == NULL)
     ret = bfd_hash_allocate (table, sizeof (struct elf32_arm_link_hash_entry));
   if (ret == NULL)
     return (struct bfd_hash_entry *) ret;
@@ -2267,13 +2400,53 @@ 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->plt_maybe_thumb_refcount = 0;
       ret->plt_got_offset = -1;
       ret->export_glue = NULL;
+
+      ret->stub_cache = NULL;
     }
 
   return (struct bfd_hash_entry *) ret;
 }
 
+/* Initialize an entry in the stub hash table.  */
+
+static struct bfd_hash_entry *
+stub_hash_newfunc (struct bfd_hash_entry *entry,
+                  struct bfd_hash_table *table,
+                  const char *string)
+{
+  /* Allocate the structure if it has not already been allocated by a
+     subclass.  */
+  if (entry == NULL)
+    {
+      entry = bfd_hash_allocate (table,
+                                sizeof (struct elf32_arm_stub_hash_entry));
+      if (entry == NULL)
+       return entry;
+    }
+
+  /* Call the allocation method of the superclass.  */
+  entry = bfd_hash_newfunc (entry, table, string);
+  if (entry != NULL)
+    {
+      struct elf32_arm_stub_hash_entry *eh;
+
+      /* Initialize the local fields.  */
+      eh = (struct elf32_arm_stub_hash_entry *) entry;
+      eh->stub_sec = NULL;
+      eh->stub_offset = 0;
+      eh->target_value = 0;
+      eh->target_section = NULL;
+      eh->stub_type = arm_stub_none;
+      eh->h = NULL;
+      eh->id_sec = NULL;
+    }
+
+  return entry;
+}
+
 /* Return true if NAME is the name of the relocation section associated
    with S.  */
 
@@ -2365,7 +2538,7 @@ elf32_arm_create_dynamic_sections (bfd *dynobj, struct bfd_link_info *info)
        }
     }
 
-  if (!htab->splt 
+  if (!htab->splt
       || !htab->srelplt
       || !htab->sdynbss
       || (!info->shared && !htab->srelbss))
@@ -2422,6 +2595,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;
+      edir->plt_maybe_thumb_refcount += eind->plt_maybe_thumb_refcount;
+      eind->plt_maybe_thumb_refcount = 0;
 
       if (dir->got.refcount <= 0)
        {
@@ -2463,6 +2638,8 @@ elf32_arm_link_hash_table_create (bfd *abfd)
   ret->srelplt2 = NULL;
   ret->thumb_glue_size = 0;
   ret->arm_glue_size = 0;
+  ret->bx_glue_size = 0;
+  memset (ret->bx_glue_offset, 0, sizeof (ret->bx_glue_offset));
   ret->vfp11_fix = BFD_ARM_VFP11_FIX_NONE;
   ret->vfp11_erratum_glue_size = 0;
   ret->num_vfp11_fixes = 0;
@@ -2486,156 +2663,1208 @@ elf32_arm_link_hash_table_create (bfd *abfd)
   ret->obfd = abfd;
   ret->tls_ldm_got.refcount = 0;
 
+  if (!bfd_hash_table_init (&ret->stub_hash_table, stub_hash_newfunc,
+                           sizeof (struct elf32_arm_stub_hash_entry)))
+    {
+      free (ret);
+      return NULL;
+    }
+
   return &ret->root.root;
 }
 
-/* Locate the Thumb encoded calling stub for NAME.  */
+/* Free the derived linker hash table.  */
 
-static struct elf_link_hash_entry *
-find_thumb_glue (struct bfd_link_info *link_info,
-                const char *name,
-                char **error_message)
+static void
+elf32_arm_hash_table_free (struct bfd_link_hash_table *hash)
 {
-  char *tmp_name;
-  struct elf_link_hash_entry *hash;
-  struct elf32_arm_link_hash_table *hash_table;
+  struct elf32_arm_link_hash_table *ret
+    = (struct elf32_arm_link_hash_table *) hash;
 
-  /* We need a pointer to the armelf specific hash table.  */
-  hash_table = elf32_arm_hash_table (link_info);
+  bfd_hash_table_free (&ret->stub_hash_table);
+  _bfd_generic_link_hash_table_free (hash);
+}
 
-  tmp_name = bfd_malloc ((bfd_size_type) strlen (name)
-                        + strlen (THUMB2ARM_GLUE_ENTRY_NAME) + 1);
+/* Determine if we're dealing with a Thumb only architecture.  */
 
-  BFD_ASSERT (tmp_name);
+static bfd_boolean
+using_thumb_only (struct elf32_arm_link_hash_table *globals)
+{
+  int arch = bfd_elf_get_obj_attr_int (globals->obfd, OBJ_ATTR_PROC,
+                                      Tag_CPU_arch);
+  int profile;
 
-  sprintf (tmp_name, THUMB2ARM_GLUE_ENTRY_NAME, name);
+  if (arch != TAG_CPU_ARCH_V7)
+    return FALSE;
 
-  hash = elf_link_hash_lookup
-    (&(hash_table)->root, tmp_name, FALSE, FALSE, TRUE);
+  profile = bfd_elf_get_obj_attr_int (globals->obfd, OBJ_ATTR_PROC,
+                                     Tag_CPU_arch_profile);
 
-  if (hash == NULL)
-    asprintf (error_message, _("unable to find THUMB glue '%s' for '%s'"),
-             tmp_name, name);
+  return profile == 'M';
+}
 
-  free (tmp_name);
+/* Determine if we're dealing with a Thumb-2 object.  */
 
-  return hash;
+static bfd_boolean
+using_thumb2 (struct elf32_arm_link_hash_table *globals)
+{
+  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;
 }
 
-/* Locate the ARM encoded calling stub for NAME.  */
+/* Determine the type of stub needed, if any, for a call.  */
 
-static struct elf_link_hash_entry *
-find_arm_glue (struct bfd_link_info *link_info,
-              const char *name,
-              char **error_message)
+static enum elf32_arm_stub_type
+arm_type_of_stub (struct bfd_link_info *info,
+                 asection *input_sec,
+                 const Elf_Internal_Rela *rel,
+                 unsigned char st_type,
+                 struct elf32_arm_link_hash_entry *hash,
+                 bfd_vma destination)
 {
-  char *tmp_name;
-  struct elf_link_hash_entry *myh;
-  struct elf32_arm_link_hash_table *hash_table;
+  bfd_vma location;
+  bfd_signed_vma branch_offset;
+  unsigned int r_type;
+  struct elf32_arm_link_hash_table * globals;
+  int thumb2;
+  int thumb_only;
+  enum elf32_arm_stub_type stub_type = arm_stub_none;
 
-  /* We need a pointer to the elfarm specific hash table.  */
-  hash_table = elf32_arm_hash_table (link_info);
+  globals = elf32_arm_hash_table (info);
 
-  tmp_name = bfd_malloc ((bfd_size_type) strlen (name)
-                        + strlen (ARM2THUMB_GLUE_ENTRY_NAME) + 1);
+  thumb_only = using_thumb_only (globals);
 
-  BFD_ASSERT (tmp_name);
+  thumb2 = using_thumb2 (globals);
 
-  sprintf (tmp_name, ARM2THUMB_GLUE_ENTRY_NAME, name);
+  /* Determine where the call point is.  */
+  location = (input_sec->output_offset
+             + input_sec->output_section->vma
+             + rel->r_offset);
 
-  myh = elf_link_hash_lookup
-    (&(hash_table)->root, tmp_name, FALSE, FALSE, TRUE);
+  branch_offset = (bfd_signed_vma)(destination - location);
 
-  if (myh == NULL)
-    asprintf (error_message, _("unable to find ARM glue '%s' for '%s'"),
-             tmp_name, name);
+  r_type = ELF32_R_TYPE (rel->r_info);
 
-  free (tmp_name);
+  /* If the call will go through a PLT entry then we do not need
+     glue.  */
+  if (globals->splt != NULL && hash->root.plt.offset != (bfd_vma) -1)
+    return stub_type;
 
-  return myh;
+  if (r_type == R_ARM_THM_CALL)
+    {
+      if ((!thumb2
+           && (branch_offset > THM_MAX_FWD_BRANCH_OFFSET
+               || (branch_offset < THM_MAX_BWD_BRANCH_OFFSET)))
+         || (thumb2
+             && (branch_offset > THM2_MAX_FWD_BRANCH_OFFSET
+                 || (branch_offset < THM2_MAX_BWD_BRANCH_OFFSET)))
+         || ((st_type != STT_ARM_TFUNC) && !globals->use_blx))
+       {
+         if (st_type == STT_ARM_TFUNC)
+           {
+             /* Thumb to thumb.  */
+             if (!thumb_only)
+               {
+                 stub_type = (info->shared | globals->pic_veneer)
+                   ? ((globals->use_blx)
+                      ? arm_stub_pic_long_branch
+                      : arm_stub_none)
+                   : (globals->use_blx)
+                   ? arm_stub_long_branch
+                   : arm_stub_none;
+               }
+             else
+               {
+                 stub_type = (info->shared | globals->pic_veneer)
+                   ? arm_stub_none
+                   : (globals->use_blx)
+                   ? arm_thumb_thumb_stub_long_branch
+                   : arm_stub_none;
+               }
+           }
+         else
+           {
+             /* Thumb to arm.  */
+             stub_type = (info->shared | globals->pic_veneer)
+               ? ((globals->use_blx)
+                  ? arm_stub_pic_long_branch
+                  : arm_stub_none)
+               : (globals->use_blx)
+               ? arm_stub_long_branch
+               : arm_thumb_arm_v4t_stub_long_branch;
+           }
+       }
+    }
+  else if (r_type == R_ARM_CALL)
+    {
+      if (st_type == STT_ARM_TFUNC)
+       {
+         /* Arm to thumb.  */
+         /* We have an extra 2-bytes reach because of the mode change
+            (bit 24 (H) of BLX encoding).  */
+         if (branch_offset > (ARM_MAX_FWD_BRANCH_OFFSET + 2)
+             || (branch_offset < ARM_MAX_BWD_BRANCH_OFFSET)
+             || !globals->use_blx)
+           {
+             stub_type = (info->shared | globals->pic_veneer)
+               ? arm_stub_pic_long_branch
+               : (globals->use_blx)
+               ? arm_stub_long_branch
+               : arm_thumb_v4t_stub_long_branch;
+           }
+       }
+      else
+       {
+         /* Arm to arm.  */
+         if (branch_offset > ARM_MAX_FWD_BRANCH_OFFSET
+             || (branch_offset < ARM_MAX_BWD_BRANCH_OFFSET))
+           {
+             stub_type = (info->shared | globals->pic_veneer)
+               ? arm_stub_pic_long_branch
+               : arm_stub_long_branch;
+           }
+       }
+    }
+
+  return stub_type;
 }
 
-/* ARM->Thumb glue (static images):
+/* Build a name for an entry in the stub hash table.  */
 
-   .arm
-   __func_from_arm:
-   ldr r12, __func_addr
-   bx  r12
-   __func_addr:
-   .word func    @ behave as if you saw a ARM_32 reloc.  
+static char *
+elf32_arm_stub_name (const asection *input_section,
+                    const asection *sym_sec,
+                    const struct elf32_arm_link_hash_entry *hash,
+                    const Elf_Internal_Rela *rel)
+{
+  char *stub_name;
+  bfd_size_type len;
 
-   (v5t static images)
-   .arm
-   __func_from_arm:
-   ldr pc, __func_addr
-   __func_addr:
-   .word func    @ behave as if you saw a ARM_32 reloc.  
+  if (hash)
+    {
+      len = 8 + 1 + strlen (hash->root.root.root.string) + 1 + 8 + 1;
+      stub_name = bfd_malloc (len);
+      if (stub_name != NULL)
+       sprintf (stub_name, "%08x_%s+%x",
+                input_section->id & 0xffffffff,
+                hash->root.root.root.string,
+                (int) rel->r_addend & 0xffffffff);
+    }
+  else
+    {
+      len = 8 + 1 + 8 + 1 + 8 + 1 + 8 + 1;
+      stub_name = bfd_malloc (len);
+      if (stub_name != NULL)
+       sprintf (stub_name, "%08x_%x:%x+%x",
+                input_section->id & 0xffffffff,
+                sym_sec->id & 0xffffffff,
+                (int) ELF32_R_SYM (rel->r_info) & 0xffffffff,
+                (int) rel->r_addend & 0xffffffff);
+    }
 
-   (relocatable images)
-   .arm
-   __func_from_arm:
-   ldr r12, __func_offset
-   add r12, r12, pc
-   bx  r12
-   __func_offset:
-   .word func - .
-   */
+  return stub_name;
+}
 
-#define ARM2THUMB_STATIC_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;
+/* Look up an entry in the stub hash.  Stub entries are cached because
+   creating the stub name takes a bit of time.  */
 
-#define ARM2THUMB_V5_STATIC_GLUE_SIZE 8
-static const insn32 a2t1v5_ldr_insn = 0xe51ff004;
-static const insn32 a2t2v5_func_addr_insn = 0x00000001;
+static struct elf32_arm_stub_hash_entry *
+elf32_arm_get_stub_entry (const asection *input_section,
+                         const asection *sym_sec,
+                         struct elf_link_hash_entry *hash,
+                         const Elf_Internal_Rela *rel,
+                         struct elf32_arm_link_hash_table *htab)
+{
+  struct elf32_arm_stub_hash_entry *stub_entry;
+  struct elf32_arm_link_hash_entry *h = (struct elf32_arm_link_hash_entry *) hash;
+  const asection *id_sec;
 
-#define ARM2THUMB_PIC_GLUE_SIZE 16
-static const insn32 a2t1p_ldr_insn = 0xe59fc004;
-static const insn32 a2t2p_add_pc_insn = 0xe08cc00f;
-static const insn32 a2t3p_bx_r12_insn = 0xe12fff1c;
+  if ((input_section->flags & SEC_CODE) == 0)
+    return NULL;
 
-/* Thumb->ARM:                          Thumb->(non-interworking aware) ARM
+  /* If this input section is part of a group of sections sharing one
+     stub section, then use the id of the first section in the group.
+     Stub names need to include a section id, as there may well be
+     more than one stub used to reach say, printf, and we need to
+     distinguish between them.  */
+  id_sec = htab->stub_group[input_section->id].link_sec;
 
-   .thumb                               .thumb
-   .align 2                             .align 2
-   __func_from_thumb:              __func_from_thumb:
-   bx pc                                push {r6, lr}
-   nop                                  ldr  r6, __func_addr
-   .arm                                         mov  lr, pc
-   __func_change_to_arm:                        bx   r6
-   b func                       .arm
-   __func_back_to_thumb:
-   ldmia r13! {r6, lr}
-   bx    lr
-   __func_addr:
-   .word        func  */
+  if (h != NULL && h->stub_cache != NULL
+      && h->stub_cache->h == h
+      && h->stub_cache->id_sec == id_sec)
+    {
+      stub_entry = h->stub_cache;
+    }
+  else
+    {
+      char *stub_name;
 
-#define THUMB2ARM_GLUE_SIZE 8
-static const insn16 t2a1_bx_pc_insn = 0x4778;
-static const insn16 t2a2_noop_insn = 0x46c0;
-static const insn32 t2a3_b_insn = 0xea000000;
+      stub_name = elf32_arm_stub_name (id_sec, sym_sec, h, rel);
+      if (stub_name == NULL)
+       return NULL;
 
-#define VFP11_ERRATUM_VENEER_SIZE 8
+      stub_entry = arm_stub_hash_lookup (&htab->stub_hash_table,
+                                       stub_name, FALSE, FALSE);
+      if (h != NULL)
+       h->stub_cache = stub_entry;
 
-#ifndef ELFARM_NABI_C_INCLUDED
-bfd_boolean
-bfd_elf32_arm_allocate_interworking_sections (struct bfd_link_info * info)
-{
-  asection * s;
-  bfd_byte * foo;
-  struct elf32_arm_link_hash_table * globals;
+      free (stub_name);
+    }
 
-  globals = elf32_arm_hash_table (info);
+  return stub_entry;
+}
 
-  BFD_ASSERT (globals != NULL);
+static void elf32_arm_stub_add_mapping_symbol (struct bfd_link_info * link_info,
+                                              asection *stub_sec,
+                                              char* name,
+                                              bfd_vma val)
+{
+  struct bfd_link_hash_entry * bh = NULL;
+  struct elf_link_hash_entry * myh;
 
-  if (globals->arm_glue_size != 0)
-    {
-      BFD_ASSERT (globals->bfd_of_glue_owner != NULL);
+  _bfd_generic_link_add_one_symbol (link_info,
+                                   stub_sec->owner, name,
+                                   BSF_LOCAL, stub_sec, stub_sec->size + val,
+                                   NULL, TRUE, FALSE, &bh);
 
-      s = bfd_get_section_by_name (globals->bfd_of_glue_owner,
-                                  ARM2THUMB_GLUE_SECTION_NAME);
+  myh = (struct elf_link_hash_entry *) bh;
+  myh->type = ELF_ST_INFO (STB_LOCAL, STT_NOTYPE);
+  myh->forced_local = 1;
+}
+
+/* Add a new stub entry to the stub hash.  Not all fields of the new
+   stub entry are initialised.  */
+
+static struct elf32_arm_stub_hash_entry *
+elf32_arm_add_stub (const char *stub_name,
+                   asection *section,
+                   struct elf32_arm_link_hash_table *htab,
+                   struct bfd_link_info * link_info,
+                   enum elf32_arm_stub_type stub_type)
+{
+  asection *link_sec;
+  asection *stub_sec;
+  struct elf32_arm_stub_hash_entry *stub_entry;
+
+  link_sec = htab->stub_group[section->id].link_sec;
+  stub_sec = htab->stub_group[section->id].stub_sec;
+  if (stub_sec == NULL)
+    {
+      stub_sec = htab->stub_group[link_sec->id].stub_sec;
+      if (stub_sec == NULL)
+       {
+         size_t namelen;
+         bfd_size_type len;
+         char *s_name;
+
+         namelen = strlen (link_sec->name);
+         len = namelen + sizeof (STUB_SUFFIX);
+         s_name = bfd_alloc (htab->stub_bfd, len);
+         if (s_name == NULL)
+           return NULL;
+
+         memcpy (s_name, link_sec->name, namelen);
+         memcpy (s_name + namelen, STUB_SUFFIX, sizeof (STUB_SUFFIX));
+         stub_sec = (*htab->add_stub_section) (s_name, link_sec);
+         if (stub_sec == NULL)
+           return NULL;
+         htab->stub_group[link_sec->id].stub_sec = stub_sec;
+       }
+      htab->stub_group[section->id].stub_sec = stub_sec;
+    }
+
+  /* Enter this entry into the linker stub hash table.  */
+  stub_entry = arm_stub_hash_lookup (&htab->stub_hash_table, stub_name,
+                                    TRUE, FALSE);
+  if (stub_entry == NULL)
+    {
+      (*_bfd_error_handler) (_("%s: cannot create stub entry %s"),
+                            section->owner,
+                            stub_name);
+      return NULL;
+    }
+
+  stub_entry->stub_sec = stub_sec;
+  stub_entry->stub_offset = 0;
+  stub_entry->id_sec = link_sec;
+
+  switch (stub_type)
+    {
+    case arm_stub_long_branch:
+      elf32_arm_stub_add_mapping_symbol (link_info, stub_sec, "$a", 0);
+      elf32_arm_stub_add_mapping_symbol (link_info, stub_sec, "$d", 4);
+      break;
+    case arm_thumb_v4t_stub_long_branch:
+      elf32_arm_stub_add_mapping_symbol (link_info, stub_sec, "$a", 0);
+      elf32_arm_stub_add_mapping_symbol (link_info, stub_sec, "$d", 8);
+      break;
+    case arm_thumb_thumb_stub_long_branch:
+      elf32_arm_stub_add_mapping_symbol (link_info, stub_sec, "$t", 0);
+      elf32_arm_stub_add_mapping_symbol (link_info, stub_sec, "$d", 12);
+      break;
+    case arm_thumb_arm_v4t_stub_long_branch:
+      elf32_arm_stub_add_mapping_symbol (link_info, stub_sec, "$t", 0);
+      elf32_arm_stub_add_mapping_symbol (link_info, stub_sec, "$a", 8);
+      elf32_arm_stub_add_mapping_symbol (link_info, stub_sec, "$d", 16);
+      break;
+    case arm_stub_pic_long_branch:
+      elf32_arm_stub_add_mapping_symbol (link_info, stub_sec, "$a", 0);
+      elf32_arm_stub_add_mapping_symbol (link_info, stub_sec, "$d", 8);
+      break;
+    default:
+      BFD_FAIL ();
+  }
+
+  return stub_entry;
+}
+
+/* Store an Arm insn into an output section not processed by
+   elf32_arm_write_section.  */
+
+static void
+put_arm_insn (struct elf32_arm_link_hash_table *htab,
+            bfd * output_bfd, bfd_vma val, void * ptr)
+{
+  if (htab->byteswap_code != bfd_little_endian (output_bfd))
+    bfd_putl32 (val, ptr);
+  else
+    bfd_putb32 (val, ptr);
+}
+
+/* Store a 16-bit Thumb insn into an output section not processed by
+   elf32_arm_write_section.  */
+
+static void
+put_thumb_insn (struct elf32_arm_link_hash_table *htab,
+              bfd * output_bfd, bfd_vma val, void * ptr)
+{
+  if (htab->byteswap_code != bfd_little_endian (output_bfd))
+    bfd_putl16 (val, ptr);
+  else
+    bfd_putb16 (val, ptr);
+}
+
+static bfd_boolean
+arm_build_one_stub (struct bfd_hash_entry *gen_entry,
+                   void * in_arg)
+{
+  struct elf32_arm_stub_hash_entry *stub_entry;
+  struct bfd_link_info *info;
+  struct elf32_arm_link_hash_table *htab;
+  asection *stub_sec;
+  bfd *stub_bfd;
+  bfd_vma stub_addr;
+  bfd_byte *loc;
+  bfd_vma sym_value;
+  int template_size;
+  int size;
+  const bfd_vma *template;
+  int i;
+  struct elf32_arm_link_hash_table * globals;
+
+  /* Massage our args to the form they really have.  */
+  stub_entry = (struct elf32_arm_stub_hash_entry *) gen_entry;
+  info = (struct bfd_link_info *) in_arg;
+
+  globals = elf32_arm_hash_table (info);
+
+  htab = elf32_arm_hash_table (info);
+  stub_sec = stub_entry->stub_sec;
+
+  /* Make a note of the offset within the stubs for this entry.  */
+  stub_entry->stub_offset = stub_sec->size;
+  loc = stub_sec->contents + stub_entry->stub_offset;
+
+  stub_bfd = stub_sec->owner;
+
+  /* This is the address of the start of the stub.  */
+  stub_addr = stub_sec->output_section->vma + stub_sec->output_offset
+    + stub_entry->stub_offset;
+
+  /* This is the address of the stub destination.  */
+  sym_value = (stub_entry->target_value
+              + stub_entry->target_section->output_offset
+              + stub_entry->target_section->output_section->vma);
+
+  switch (stub_entry->stub_type)
+    {
+    case arm_stub_long_branch:
+      template = arm_long_branch_stub;
+      template_size = (sizeof (arm_long_branch_stub) / sizeof (bfd_vma)) * 4;
+      break;
+    case arm_thumb_v4t_stub_long_branch:
+      template =  arm_thumb_v4t_long_branch_stub;
+      template_size = (sizeof (arm_thumb_v4t_long_branch_stub) / sizeof (bfd_vma)) * 4;
+      break;
+    case arm_thumb_thumb_stub_long_branch:
+      template =  arm_thumb_thumb_long_branch_stub;
+      template_size = (sizeof (arm_thumb_thumb_long_branch_stub) / sizeof (bfd_vma)) * 4;
+      break;
+    case arm_thumb_arm_v4t_stub_long_branch:
+      template =  arm_thumb_arm_v4t_long_branch_stub;
+      template_size = (sizeof (arm_thumb_arm_v4t_long_branch_stub) / sizeof (bfd_vma)) * 4;
+      break;
+    case arm_stub_pic_long_branch:
+      template = arm_pic_long_branch_stub;
+      template_size = (sizeof (arm_pic_long_branch_stub) / sizeof (bfd_vma)) * 4;
+      break;
+    default:
+      BFD_FAIL ();
+      return FALSE;
+    }
+
+  size = 0;
+  for (i = 0; i < (template_size / 4); i++)
+    {
+      /* A 0 pattern is a placeholder, every other pattern is an
+        instruction.  */
+      if (template[i] != 0)
+       put_arm_insn (globals, stub_bfd, template[i], loc + size);
+      else
+       bfd_put_32 (stub_bfd, template[i], loc + size);
+
+      size += 4;
+    }
+  stub_sec->size += size;
+
+  /* Destination is Thumb. Force bit 0 to 1 to reflect this.  */
+  if (stub_entry->st_type == STT_ARM_TFUNC)
+    sym_value |= 1;
+
+  switch (stub_entry->stub_type)
+    {
+    case arm_stub_long_branch:
+      _bfd_final_link_relocate (elf32_arm_howto_from_type (R_ARM_ABS32),
+                               stub_bfd, stub_sec, stub_sec->contents + 4,
+                               stub_entry->stub_offset, sym_value, 0);
+      break;
+    case arm_thumb_v4t_stub_long_branch:
+      _bfd_final_link_relocate (elf32_arm_howto_from_type (R_ARM_ABS32),
+                               stub_bfd, stub_sec, stub_sec->contents + 8,
+                               stub_entry->stub_offset, sym_value, 0);
+      break;
+    case arm_thumb_thumb_stub_long_branch:
+      _bfd_final_link_relocate (elf32_arm_howto_from_type (R_ARM_ABS32),
+                               stub_bfd, stub_sec, stub_sec->contents + 12,
+                               stub_entry->stub_offset, sym_value, 0);
+      break;
+    case arm_thumb_arm_v4t_stub_long_branch:
+      _bfd_final_link_relocate (elf32_arm_howto_from_type (R_ARM_ABS32),
+                               stub_bfd, stub_sec, stub_sec->contents + 20,
+                               stub_entry->stub_offset, sym_value, 0);
+      break;
+    case arm_stub_pic_long_branch:
+      /* We want the value relative to the address 8 bytes from the
+        start of the stub.  */
+      sym_value -= stub_addr + 8;
+
+      _bfd_final_link_relocate (elf32_arm_howto_from_type (R_ARM_ABS32),
+                               stub_bfd, stub_sec, stub_sec->contents + 8,
+                               stub_entry->stub_offset, sym_value, 0);
+      break;
+    default:
+      break;
+    }
+
+  return TRUE;
+}
+
+/* As above, but don't actually build the stub.  Just bump offset so
+   we know stub section sizes.  */
+
+static bfd_boolean
+arm_size_one_stub (struct bfd_hash_entry *gen_entry,
+                  void * in_arg)
+{
+  struct elf32_arm_stub_hash_entry *stub_entry;
+  struct elf32_arm_link_hash_table *htab;
+  const bfd_vma *template;
+  int template_size;
+  int size;
+  int i;
+
+  /* Massage our args to the form they really have.  */
+  stub_entry = (struct elf32_arm_stub_hash_entry *) gen_entry;
+  htab = (struct elf32_arm_link_hash_table *) in_arg;
+
+  switch (stub_entry->stub_type)
+    {
+    case arm_stub_long_branch:
+      template =  arm_long_branch_stub;
+      template_size = (sizeof (arm_long_branch_stub) / sizeof (bfd_vma)) * 4;
+      break;
+    case arm_thumb_v4t_stub_long_branch:
+      template =  arm_thumb_v4t_long_branch_stub;
+      template_size = (sizeof (arm_thumb_v4t_long_branch_stub) / sizeof (bfd_vma)) * 4;
+      break;
+    case arm_thumb_thumb_stub_long_branch:
+      template =  arm_thumb_thumb_long_branch_stub;
+      template_size = (sizeof (arm_thumb_thumb_long_branch_stub) / sizeof (bfd_vma)) * 4;
+      break;
+    case arm_thumb_arm_v4t_stub_long_branch:
+      template =  arm_thumb_arm_v4t_long_branch_stub;
+      template_size = (sizeof (arm_thumb_arm_v4t_long_branch_stub) / sizeof (bfd_vma)) * 4;
+      break;
+    case arm_stub_pic_long_branch:
+      template = arm_pic_long_branch_stub;
+      template_size = (sizeof (arm_pic_long_branch_stub) / sizeof (bfd_vma)) * 4;
+      break;
+    default:
+      BFD_FAIL ();
+      return FALSE;
+      break;
+    }
+
+  size = 0;
+  for (i = 0; i < (template_size / 4); i++)
+      size += 4;
+  size = (size + 7) & ~7;
+  stub_entry->stub_sec->size += size;
+  return TRUE;
+}
+
+/* External entry points for sizing and building linker stubs.  */
+
+/* Set up various things so that we can make a list of input sections
+   for each output section included in the link.  Returns -1 on error,
+   0 when no stubs will be needed, and 1 on success.  */
+
+int
+elf32_arm_setup_section_lists (bfd *output_bfd,
+                              struct bfd_link_info *info)
+{
+  bfd *input_bfd;
+  unsigned int bfd_count;
+  int top_id, top_index;
+  asection *section;
+  asection **input_list, **list;
+  bfd_size_type amt;
+  struct elf32_arm_link_hash_table *htab = elf32_arm_hash_table (info);
+
+  if (! is_elf_hash_table (htab))
+    return 0;
+
+  /* Count the number of input BFDs and find the top input section id.  */
+  for (input_bfd = info->input_bfds, bfd_count = 0, top_id = 0;
+       input_bfd != NULL;
+       input_bfd = input_bfd->link_next)
+    {
+      bfd_count += 1;
+      for (section = input_bfd->sections;
+          section != NULL;
+          section = section->next)
+       {
+         if (top_id < section->id)
+           top_id = section->id;
+       }
+    }
+  htab->bfd_count = bfd_count;
+
+  amt = sizeof (struct map_stub) * (top_id + 1);
+  htab->stub_group = bfd_zmalloc (amt);
+  if (htab->stub_group == NULL)
+    return -1;
+
+  /* We can't use output_bfd->section_count here to find the top output
+     section index as some sections may have been removed, and
+     _bfd_strip_section_from_output doesn't renumber the indices.  */
+  for (section = output_bfd->sections, top_index = 0;
+       section != NULL;
+       section = section->next)
+    {
+      if (top_index < section->index)
+       top_index = section->index;
+    }
+
+  htab->top_index = top_index;
+  amt = sizeof (asection *) * (top_index + 1);
+  input_list = bfd_malloc (amt);
+  htab->input_list = input_list;
+  if (input_list == NULL)
+    return -1;
+
+  /* For sections we aren't interested in, mark their entries with a
+     value we can check later.  */
+  list = input_list + top_index;
+  do
+    *list = bfd_abs_section_ptr;
+  while (list-- != input_list);
+
+  for (section = output_bfd->sections;
+       section != NULL;
+       section = section->next)
+    {
+      if ((section->flags & SEC_CODE) != 0)
+       input_list[section->index] = NULL;
+    }
+
+  return 1;
+}
+
+/* The linker repeatedly calls this function for each input section,
+   in the order that input sections are linked into output sections.
+   Build lists of input sections to determine groupings between which
+   we may insert linker stubs.  */
+
+void
+elf32_arm_next_input_section (struct bfd_link_info *info,
+                             asection *isec)
+{
+  struct elf32_arm_link_hash_table *htab = elf32_arm_hash_table (info);
+
+  if (isec->output_section->index <= htab->top_index)
+    {
+      asection **list = htab->input_list + isec->output_section->index;
+
+      if (*list != bfd_abs_section_ptr)
+       {
+         /* Steal the link_sec pointer for our list.  */
+#define PREV_SEC(sec) (htab->stub_group[(sec)->id].link_sec)
+         /* This happens to make the list in reverse order,
+            which is what we want.  */
+         PREV_SEC (isec) = *list;
+         *list = isec;
+       }
+    }
+}
+
+/* See whether we can group stub sections together.  Grouping stub
+   sections may result in fewer stubs.  More importantly, we need to
+   put all .init* and .fini* stubs at the beginning of the .init or
+   .fini output sections respectively, because glibc splits the
+   _init and _fini functions into multiple parts.  Putting a stub in
+   the middle of a function is not a good idea.  */
+
+static void
+group_sections (struct elf32_arm_link_hash_table *htab,
+               bfd_size_type stub_group_size,
+               bfd_boolean stubs_always_before_branch)
+{
+  asection **list = htab->input_list + htab->top_index;
+
+  do
+    {
+      asection *tail = *list;
+
+      if (tail == bfd_abs_section_ptr)
+       continue;
+
+      while (tail != NULL)
+       {
+         asection *curr;
+         asection *prev;
+         bfd_size_type total;
+
+         curr = tail;
+         total = tail->size;
+         while ((prev = PREV_SEC (curr)) != NULL
+                && ((total += curr->output_offset - prev->output_offset)
+                    < stub_group_size))
+           curr = prev;
+
+         /* OK, the size from the start of CURR to the end is less
+            than stub_group_size and thus can be handled by one stub
+            section.  (or the tail section is itself larger than
+            stub_group_size, in which case we may be toast.)
+            We should really be keeping track of the total size of
+            stubs added here, as stubs contribute to the final output
+            section size. */
+         do
+           {
+             prev = PREV_SEC (tail);
+             /* Set up this stub group.  */
+             htab->stub_group[tail->id].link_sec = curr;
+           }
+         while (tail != curr && (tail = prev) != NULL);
+
+         /* But wait, there's more!  Input sections up to stub_group_size
+            bytes before the stub section can be handled by it too.  */
+         if (!stubs_always_before_branch)
+           {
+             total = 0;
+             while (prev != NULL
+                    && ((total += tail->output_offset - prev->output_offset)
+                        < stub_group_size))
+               {
+                 tail = prev;
+                 prev = PREV_SEC (tail);
+                 htab->stub_group[tail->id].link_sec = curr;
+               }
+           }
+         tail = prev;
+       }
+    }
+  while (list-- != htab->input_list);
+
+  free (htab->input_list);
+#undef PREV_SEC
+}
+
+/* Determine and set the size of the stub section for a final link.
+
+   The basic idea here is to examine all the relocations looking for
+   PC-relative calls to a target that is unreachable with a "bl"
+   instruction.  */
+
+bfd_boolean
+elf32_arm_size_stubs (bfd *output_bfd,
+                     bfd *stub_bfd,
+                     struct bfd_link_info *info,
+                     bfd_signed_vma group_size,
+                     asection * (*add_stub_section) (const char *, asection *),
+                     void (*layout_sections_again) (void))
+{
+  bfd_size_type stub_group_size;
+  bfd_boolean stubs_always_before_branch;
+  bfd_boolean stub_changed = 0;
+  struct elf32_arm_link_hash_table *htab = elf32_arm_hash_table (info);
+
+  /* Propagate mach to stub bfd, because it may not have been
+     finalized when we created stub_bfd.  */
+  bfd_set_arch_mach (stub_bfd, bfd_get_arch (output_bfd),
+                    bfd_get_mach (output_bfd));
+
+  /* Stash our params away.  */
+  htab->stub_bfd = stub_bfd;
+  htab->add_stub_section = add_stub_section;
+  htab->layout_sections_again = layout_sections_again;
+  stubs_always_before_branch = group_size < 0;
+  if (group_size < 0)
+    stub_group_size = -group_size;
+  else
+    stub_group_size = group_size;
+
+  if (stub_group_size == 1)
+    {
+      /* Default values.  */
+      /* Thumb branch range is +-4MB has to be used as the default
+        maximum size (a given section can contain both ARM and Thumb
+        code, so the worst case has to be taken into account).
+
+        This value is 24K less than that, which allows for 2025
+        12-byte stubs.  If we exceed that, then we will fail to link.
+        The user will have to relink with an explicit group size
+        option.  */
+      stub_group_size = 4170000;
+    }
+
+  group_sections (htab, stub_group_size, stubs_always_before_branch);
+
+  while (1)
+    {
+      bfd *input_bfd;
+      unsigned int bfd_indx;
+      asection *stub_sec;
+
+      for (input_bfd = info->input_bfds, bfd_indx = 0;
+          input_bfd != NULL;
+          input_bfd = input_bfd->link_next, bfd_indx++)
+       {
+         Elf_Internal_Shdr *symtab_hdr;
+         asection *section;
+         Elf_Internal_Sym *local_syms = NULL;
+
+         /* We'll need the symbol table in a second.  */
+         symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
+         if (symtab_hdr->sh_info == 0)
+           continue;
+
+         /* Walk over each section attached to the input bfd.  */
+         for (section = input_bfd->sections;
+              section != NULL;
+              section = section->next)
+           {
+             Elf_Internal_Rela *internal_relocs, *irelaend, *irela;
+
+             /* If there aren't any relocs, then there's nothing more
+                to do.  */
+             if ((section->flags & SEC_RELOC) == 0
+                 || section->reloc_count == 0
+                 || (section->flags & SEC_CODE) == 0)
+               continue;
+
+             /* If this section is a link-once section that will be
+                discarded, then don't create any stubs.  */
+             if (section->output_section == NULL
+                 || section->output_section->owner != output_bfd)
+               continue;
+
+             /* Get the relocs.  */
+             internal_relocs
+               = _bfd_elf_link_read_relocs (input_bfd, section, NULL,
+                                            NULL, info->keep_memory);
+             if (internal_relocs == NULL)
+               goto error_ret_free_local;
+
+             /* Now examine each relocation.  */
+             irela = internal_relocs;
+             irelaend = irela + section->reloc_count;
+             for (; irela < irelaend; irela++)
+               {
+                 unsigned int r_type, r_indx;
+                 enum elf32_arm_stub_type stub_type;
+                 struct elf32_arm_stub_hash_entry *stub_entry;
+                 asection *sym_sec;
+                 bfd_vma sym_value;
+                 bfd_vma destination;
+                 struct elf32_arm_link_hash_entry *hash;
+                 char *stub_name;
+                 const asection *id_sec;
+                 unsigned char st_type;
+
+                 r_type = ELF32_R_TYPE (irela->r_info);
+                 r_indx = ELF32_R_SYM (irela->r_info);
+
+                 if (r_type >= (unsigned int) R_ARM_max)
+                   {
+                     bfd_set_error (bfd_error_bad_value);
+                   error_ret_free_internal:
+                     if (elf_section_data (section)->relocs == NULL)
+                       free (internal_relocs);
+                     goto error_ret_free_local;
+                   }
+
+                 /* Only look for stubs on call instructions.  */
+                 if ((r_type != (unsigned int) R_ARM_CALL)
+                     && (r_type != (unsigned int) R_ARM_THM_CALL))
+                   continue;
+
+                 /* Now determine the call target, its name, value,
+                    section.  */
+                 sym_sec = NULL;
+                 sym_value = 0;
+                 destination = 0;
+                 hash = NULL;
+                 if (r_indx < symtab_hdr->sh_info)
+                   {
+                     /* It's a local symbol.  */
+                     Elf_Internal_Sym *sym;
+                     Elf_Internal_Shdr *hdr;
+
+                     if (local_syms == NULL)
+                       {
+                         local_syms
+                           = (Elf_Internal_Sym *) symtab_hdr->contents;
+                         if (local_syms == NULL)
+                           local_syms
+                             = bfd_elf_get_elf_syms (input_bfd, symtab_hdr,
+                                                     symtab_hdr->sh_info, 0,
+                                                     NULL, NULL, NULL);
+                         if (local_syms == NULL)
+                           goto error_ret_free_internal;
+                       }
+
+                     sym = local_syms + r_indx;
+                     hdr = elf_elfsections (input_bfd)[sym->st_shndx];
+                     sym_sec = hdr->bfd_section;
+                     if (ELF_ST_TYPE (sym->st_info) != STT_SECTION)
+                       sym_value = sym->st_value;
+                     destination = (sym_value + irela->r_addend
+                                    + sym_sec->output_offset
+                                    + sym_sec->output_section->vma);
+                     st_type = ELF_ST_TYPE (sym->st_info);
+                   }
+                 else
+                   {
+                     /* It's an external symbol.  */
+                     int e_indx;
+
+                     e_indx = r_indx - symtab_hdr->sh_info;
+                     hash = ((struct elf32_arm_link_hash_entry *)
+                             elf_sym_hashes (input_bfd)[e_indx]);
+
+                     while (hash->root.root.type == bfd_link_hash_indirect
+                            || hash->root.root.type == bfd_link_hash_warning)
+                       hash = ((struct elf32_arm_link_hash_entry *)
+                               hash->root.root.u.i.link);
+
+                     if (hash->root.root.type == bfd_link_hash_defined
+                         || hash->root.root.type == bfd_link_hash_defweak)
+                       {
+                         sym_sec = hash->root.root.u.def.section;
+                         sym_value = hash->root.root.u.def.value;
+                         if (sym_sec->output_section != NULL)
+                           destination = (sym_value + irela->r_addend
+                                          + sym_sec->output_offset
+                                          + sym_sec->output_section->vma);
+                       }
+                     else if (hash->root.root.type == bfd_link_hash_undefweak
+                              || hash->root.root.type == bfd_link_hash_undefined)
+                       /* For a shared library, these will need a PLT stub,
+                          which is treated separately.
+                          For absolute code, they cannot be handled.  */
+                       continue;
+                     else
+                       {
+                         bfd_set_error (bfd_error_bad_value);
+                         goto error_ret_free_internal;
+                       }
+                     st_type = ELF_ST_TYPE (hash->root.type);
+                   }
+
+                 /* Determine what (if any) linker stub is needed.  */
+                 stub_type = arm_type_of_stub (info, section, irela, st_type,
+                                               hash, destination);
+                 if (stub_type == arm_stub_none)
+                   continue;
+
+                 /* Support for grouping stub sections.  */
+                 id_sec = htab->stub_group[section->id].link_sec;
+
+                 /* Get the name of this stub.  */
+                 stub_name = elf32_arm_stub_name (id_sec, sym_sec, hash, irela);
+                 if (!stub_name)
+                   goto error_ret_free_internal;
+
+                 stub_entry = arm_stub_hash_lookup (&htab->stub_hash_table,
+                                                   stub_name,
+                                                   FALSE, FALSE);
+                 if (stub_entry != NULL)
+                   {
+                     /* The proper stub has already been created.  */
+                     free (stub_name);
+                     continue;
+                   }
+
+                 stub_entry = elf32_arm_add_stub (stub_name, section, htab, info, stub_type);
+                 if (stub_entry == NULL)
+                   {
+                     free (stub_name);
+                     goto error_ret_free_internal;
+                   }
+
+                 stub_entry->target_value = sym_value;
+                 stub_entry->target_section = sym_sec;
+                 stub_entry->stub_type = stub_type;
+                 stub_entry->h = hash;
+                 stub_entry->st_type = st_type;
+                 stub_changed = TRUE;
+               }
+
+             /* We're done with the internal relocs, free them.  */
+             if (elf_section_data (section)->relocs == NULL)
+               free (internal_relocs);
+           }
+       }
+
+      if (!stub_changed)
+       break;
+
+      /* OK, we've added some stubs.  Find out the new size of the
+        stub sections.  */
+      for (stub_sec = htab->stub_bfd->sections;
+          stub_sec != NULL;
+          stub_sec = stub_sec->next)
+       stub_sec->size = 0;
+
+      bfd_hash_traverse (&htab->stub_hash_table, arm_size_one_stub, htab);
+
+      /* Ask the linker to do its stuff.  */
+      (*htab->layout_sections_again) ();
+      stub_changed = FALSE;
+    }
+
+  return TRUE;
+
+ error_ret_free_local:
+  return FALSE;
+}
+
+/* Build all the stubs associated with the current output file.  The
+   stubs are kept in a hash table attached to the main linker hash
+   table.  We also set up the .plt entries for statically linked PIC
+   functions here.  This function is called via arm_elf_finish in the
+   linker.  */
+
+bfd_boolean
+elf32_arm_build_stubs (struct bfd_link_info *info)
+{
+  asection *stub_sec;
+  struct bfd_hash_table *table;
+  struct elf32_arm_link_hash_table *htab;
+
+  htab = elf32_arm_hash_table (info);
+
+  for (stub_sec = htab->stub_bfd->sections;
+       stub_sec != NULL;
+       stub_sec = stub_sec->next)
+    {
+      bfd_size_type size;
+
+      /* Ignore non-stub sections */
+      if (!strstr (stub_sec->name, STUB_SUFFIX))
+       continue;
+
+      /* Allocate memory to hold the linker stubs.  */
+      size = stub_sec->size;
+      stub_sec->contents = bfd_zalloc (htab->stub_bfd, size);
+      if (stub_sec->contents == NULL && size != 0)
+       return FALSE;
+      stub_sec->size = 0;
+    }
+
+  /* Build the stubs as directed by the stub hash table.  */
+  table = &htab->stub_hash_table;
+  bfd_hash_traverse (table, arm_build_one_stub, info);
+
+  return TRUE;
+}
+
+/* Locate the Thumb encoded calling stub for NAME.  */
+
+static struct elf_link_hash_entry *
+find_thumb_glue (struct bfd_link_info *link_info,
+                const char *name,
+                char **error_message)
+{
+  char *tmp_name;
+  struct elf_link_hash_entry *hash;
+  struct elf32_arm_link_hash_table *hash_table;
+
+  /* We need a pointer to the armelf specific hash table.  */
+  hash_table = elf32_arm_hash_table (link_info);
+
+  tmp_name = bfd_malloc ((bfd_size_type) strlen (name)
+                        + strlen (THUMB2ARM_GLUE_ENTRY_NAME) + 1);
+
+  BFD_ASSERT (tmp_name);
+
+  sprintf (tmp_name, THUMB2ARM_GLUE_ENTRY_NAME, name);
+
+  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) == -1)
+    *error_message = (char *) bfd_errmsg (bfd_error_system_call);
+
+  free (tmp_name);
+
+  return hash;
+}
+
+/* Locate the ARM encoded calling stub for NAME.  */
+
+static struct elf_link_hash_entry *
+find_arm_glue (struct bfd_link_info *link_info,
+              const char *name,
+              char **error_message)
+{
+  char *tmp_name;
+  struct elf_link_hash_entry *myh;
+  struct elf32_arm_link_hash_table *hash_table;
+
+  /* We need a pointer to the elfarm specific hash table.  */
+  hash_table = elf32_arm_hash_table (link_info);
+
+  tmp_name = bfd_malloc ((bfd_size_type) strlen (name)
+                        + strlen (ARM2THUMB_GLUE_ENTRY_NAME) + 1);
+
+  BFD_ASSERT (tmp_name);
+
+  sprintf (tmp_name, ARM2THUMB_GLUE_ENTRY_NAME, name);
+
+  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) == -1)
+    *error_message = (char *) bfd_errmsg (bfd_error_system_call);
+
+  free (tmp_name);
+
+  return myh;
+}
+
+/* ARM->Thumb glue (static images):
+
+   .arm
+   __func_from_arm:
+   ldr r12, __func_addr
+   bx  r12
+   __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:
+   ldr r12, __func_offset
+   add r12, r12, pc
+   bx  r12
+   __func_offset:
+   .word func - .
+   */
+
+#define ARM2THUMB_STATIC_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_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;
+static const insn32 a2t3p_bx_r12_insn = 0xe12fff1c;
+
+/* Thumb->ARM:                          Thumb->(non-interworking aware) ARM
+
+   .thumb                               .thumb
+   .align 2                             .align 2
+   __func_from_thumb:              __func_from_thumb:
+   bx pc                                push {r6, lr}
+   nop                                  ldr  r6, __func_addr
+   .arm                                         mov  lr, pc
+   __func_change_to_arm:                        bx   r6
+   b func                       .arm
+   __func_back_to_thumb:
+   ldmia r13! {r6, lr}
+   bx    lr
+   __func_addr:
+   .word        func  */
+
+#define THUMB2ARM_GLUE_SIZE 8
+static const insn16 t2a1_bx_pc_insn = 0x4778;
+static const insn16 t2a2_noop_insn = 0x46c0;
+static const insn32 t2a3_b_insn = 0xea000000;
+
+#define VFP11_ERRATUM_VENEER_SIZE 8
+
+#define ARM_BX_VENEER_SIZE 12
+static const insn32 armbx1_tst_insn = 0xe3100001;
+static const insn32 armbx2_moveq_insn = 0x01a0f000;
+static const insn32 armbx3_bx_insn = 0xe12fff10;
+
+#ifndef ELFARM_NABI_C_INCLUDED
+bfd_boolean
+bfd_elf32_arm_allocate_interworking_sections (struct bfd_link_info * info)
+{
+  asection * s;
+  bfd_byte * foo;
+  struct elf32_arm_link_hash_table * globals;
+
+  globals = elf32_arm_hash_table (info);
+
+  BFD_ASSERT (globals != NULL);
+
+  if (globals->arm_glue_size != 0)
+    {
+      BFD_ASSERT (globals->bfd_of_glue_owner != NULL);
+
+      s = bfd_get_section_by_name (globals->bfd_of_glue_owner,
+                                  ARM2THUMB_GLUE_SECTION_NAME);
 
       BFD_ASSERT (s != NULL);
 
@@ -2659,28 +3888,44 @@ bfd_elf32_arm_allocate_interworking_sections (struct bfd_link_info * info)
       BFD_ASSERT (s->size == globals->thumb_glue_size);
       s->contents = foo;
     }
-  
+
   if (globals->vfp11_erratum_glue_size != 0)
     {
       BFD_ASSERT (globals->bfd_of_glue_owner != NULL);
-      
+
       s = bfd_get_section_by_name
         (globals->bfd_of_glue_owner, VFP11_ERRATUM_VENEER_SECTION_NAME);
-      
+
       BFD_ASSERT (s != NULL);
-      
+
       foo = bfd_alloc (globals->bfd_of_glue_owner,
                       globals->vfp11_erratum_glue_size);
-      
+
       BFD_ASSERT (s->size == globals->vfp11_erratum_glue_size);
       s->contents = foo;
     }
 
+  if (globals->bx_glue_size != 0)
+    {
+      BFD_ASSERT (globals->bfd_of_glue_owner != NULL);
+
+      s = bfd_get_section_by_name (globals->bfd_of_glue_owner,
+                                  ARM_BX_GLUE_SECTION_NAME);
+
+      BFD_ASSERT (s != NULL);
+
+      foo = bfd_alloc (globals->bfd_of_glue_owner, globals->bx_glue_size);
+
+      BFD_ASSERT (s->size == globals->bx_glue_size);
+      s->contents = foo;
+    }
+
   return TRUE;
 }
 
 /* Allocate space and symbols for calling a Thumb function from Arm mode.
-   returns the symbol identifying teh stub.  */
+   returns the symbol identifying the stub.  */
+
 static struct elf_link_hash_entry *
 record_arm_to_thumb_glue (struct bfd_link_info * link_info,
                          struct elf_link_hash_entry * h)
@@ -2827,6 +4072,64 @@ record_thumb_to_arm_glue (struct bfd_link_info *link_info,
 }
 
 
+/* Allocate space for ARMv4 BX veneers.  */
+
+static void
+record_arm_bx_glue (struct bfd_link_info * link_info, int reg)
+{
+  asection * s;
+  struct elf32_arm_link_hash_table *globals;
+  char *tmp_name;
+  struct elf_link_hash_entry *myh;
+  struct bfd_link_hash_entry *bh;
+  bfd_vma val;
+
+  /* BX PC does not need a veneer.  */
+  if (reg == 15)
+    return;
+
+  globals = elf32_arm_hash_table (link_info);
+
+  BFD_ASSERT (globals != NULL);
+  BFD_ASSERT (globals->bfd_of_glue_owner != NULL);
+
+  /* Check if this veneer has already been allocated.  */
+  if (globals->bx_glue_offset[reg])
+    return;
+
+  s = bfd_get_section_by_name
+    (globals->bfd_of_glue_owner, ARM_BX_GLUE_SECTION_NAME);
+
+  BFD_ASSERT (s != NULL);
+
+  /* Add symbol for veneer.  */
+  tmp_name = bfd_malloc ((bfd_size_type) strlen (ARM_BX_GLUE_ENTRY_NAME) + 1);
+
+  BFD_ASSERT (tmp_name);
+
+  sprintf (tmp_name, ARM_BX_GLUE_ENTRY_NAME, reg);
+
+  myh = elf_link_hash_lookup
+    (&(globals)->root, tmp_name, FALSE, FALSE, FALSE);
+
+  BFD_ASSERT (myh == NULL);
+
+  bh = NULL;
+  val = globals->bx_glue_size;
+  _bfd_generic_link_add_one_symbol (link_info, globals->bfd_of_glue_owner,
+                                    tmp_name, BSF_FUNCTION | BSF_LOCAL, s, val,
+                                    NULL, TRUE, FALSE, &bh);
+
+  myh = (struct elf_link_hash_entry *) bh;
+  myh->type = ELF_ST_INFO (STB_LOCAL, STT_FUNC);
+  myh->forced_local = 1;
+
+  s->size += ARM_BX_VENEER_SIZE;
+  globals->bx_glue_offset[reg] = globals->bx_glue_size | 2;
+  globals->bx_glue_size += ARM_BX_VENEER_SIZE;
+}
+
+
 /* Add an entry to the code/data map for section SEC.  */
 
 static void
@@ -2834,25 +4137,28 @@ elf32_arm_section_map_add (asection *sec, char type, bfd_vma vma)
 {
   struct _arm_elf_section_data *sec_data = elf32_arm_section_data (sec);
   unsigned int newidx;
-  
+
   if (sec_data->map == NULL)
     {
       sec_data->map = bfd_malloc (sizeof (elf32_arm_section_map));
       sec_data->mapcount = 0;
       sec_data->mapsize = 1;
     }
-  
+
   newidx = sec_data->mapcount++;
-  
+
   if (sec_data->mapcount > sec_data->mapsize)
     {
       sec_data->mapsize *= 2;
-      sec_data->map = bfd_realloc (sec_data->map, sec_data->mapsize
-                                    * sizeof (elf32_arm_section_map));
+      sec_data->map = bfd_realloc_or_free (sec_data->map, sec_data->mapsize
+                                          * sizeof (elf32_arm_section_map));
+    }
+
+  if (sec_data->map)
+    {
+      sec_data->map[newidx].vma = vma;
+      sec_data->map[newidx].type = type;
     }
-  
-  sec_data->map[newidx].vma = vma;
-  sec_data->map[newidx].type = type;
 }
 
 
@@ -2875,32 +4181,32 @@ record_vfp11_erratum_veneer (struct bfd_link_info *link_info,
   struct _arm_elf_section_data *sec_data;
   int errcount;
   elf32_vfp11_erratum_list *newerr;
-  
+
   hash_table = elf32_arm_hash_table (link_info);
-  
+
   BFD_ASSERT (hash_table != NULL);
   BFD_ASSERT (hash_table->bfd_of_glue_owner != NULL);
-  
+
   s = bfd_get_section_by_name
     (hash_table->bfd_of_glue_owner, VFP11_ERRATUM_VENEER_SECTION_NAME);
-  
+
   sec_data = elf32_arm_section_data (s);
-  
+
   BFD_ASSERT (s != NULL);
-  
+
   tmp_name = bfd_malloc ((bfd_size_type) strlen
                         (VFP11_ERRATUM_VENEER_ENTRY_NAME) + 10);
-  
+
   BFD_ASSERT (tmp_name);
-  
+
   sprintf (tmp_name, VFP11_ERRATUM_VENEER_ENTRY_NAME,
           hash_table->num_vfp11_fixes);
-  
+
   myh = elf_link_hash_lookup
     (&(hash_table)->root, tmp_name, FALSE, FALSE, FALSE);
-  
+
   BFD_ASSERT (myh == NULL);
-  
+
   bh = NULL;
   val = hash_table->vfp11_erratum_glue_size;
   _bfd_generic_link_add_one_symbol (link_info, hash_table->bfd_of_glue_owner,
@@ -2914,7 +4220,7 @@ record_vfp11_erratum_veneer (struct bfd_link_info *link_info,
   /* Link veneer back to calling location.  */
   errcount = ++(sec_data->erratumcount);
   newerr = bfd_zmalloc (sizeof (elf32_vfp11_erratum_list));
-  
+
   newerr->type = VFP11_ERRATUM_ARM_VENEER;
   newerr->vma = -1;
   newerr->u.v.branch = branch;
@@ -2930,7 +4236,7 @@ record_vfp11_erratum_veneer (struct bfd_link_info *link_info,
 
   myh = elf_link_hash_lookup
     (&(hash_table)->root, tmp_name, FALSE, FALSE, FALSE);
-  
+
   if (myh != NULL)
     abort ();
 
@@ -2938,13 +4244,13 @@ record_vfp11_erratum_veneer (struct bfd_link_info *link_info,
   val = offset + 4;
   _bfd_generic_link_add_one_symbol (link_info, branch_bfd, tmp_name, BSF_LOCAL,
                                    branch_sec, val, NULL, TRUE, FALSE, &bh);
-  
+
   myh = (struct elf_link_hash_entry *) bh;
   myh->type = ELF_ST_INFO (STB_LOCAL, STT_FUNC);
   myh->forced_local = 1;
 
   free (tmp_name);
-  
+
   /* Generate a mapping symbol for the veneer section, and explicitly add an
      entry for that symbol to the code/data map for the section.  */
   if (hash_table->vfp11_erratum_glue_size == 0)
@@ -2960,18 +4266,18 @@ record_vfp11_erratum_veneer (struct bfd_link_info *link_info,
       myh = (struct elf_link_hash_entry *) bh;
       myh->type = ELF_ST_INFO (STB_LOCAL, STT_NOTYPE);
       myh->forced_local = 1;
-      
+
       /* The elf32_arm_init_maps function only cares about symbols from input
          BFDs.  We must make a note of this generated mapping symbol
          ourselves so that code byteswapping works properly in
          elf32_arm_write_section.  */
       elf32_arm_section_map_add (s, 'a', 0);
     }
-  
+
   s->size += VFP11_ERRATUM_VENEER_SIZE;
   hash_table->vfp11_erratum_glue_size += VFP11_ERRATUM_VENEER_SIZE;
   hash_table->num_vfp11_fixes++;
-  
+
   /* The offset of the veneer.  */
   return val;
 }
@@ -2991,6 +4297,10 @@ bfd_elf32_arm_add_glue_sections_to_bfd (bfd *abfd,
   if (info->relocatable)
     return TRUE;
 
+  /* linker stubs don't need glue */
+  if (!strcmp (abfd->filename, "linker stubs"))
+    return TRUE;
+
   sec = bfd_get_section_by_name (abfd, ARM2THUMB_GLUE_SECTION_NAME);
 
   if (sec == NULL)
@@ -3050,6 +4360,24 @@ bfd_elf32_arm_add_glue_sections_to_bfd (bfd *abfd,
       sec->gc_mark = 1;
     }
 
+  sec = bfd_get_section_by_name (abfd, ARM_BX_GLUE_SECTION_NAME);
+
+  if (sec == NULL)
+    {
+      flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY
+              | SEC_CODE | SEC_READONLY);
+
+      sec = bfd_make_section_with_flags (abfd,
+                                        ARM_BX_GLUE_SECTION_NAME,
+                                         flags);
+
+      if (sec == NULL
+         || !bfd_set_section_alignment (abfd, sec, 2))
+       return FALSE;
+
+      sec->gc_mark = 1;
+    }
+
   return TRUE;
 }
 
@@ -3083,7 +4411,8 @@ bfd_elf32_arm_get_bfd_for_interworking (bfd *abfd, struct bfd_link_info *info)
   return TRUE;
 }
 
-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 (bfd_elf_get_obj_attr_int (globals->obfd, OBJ_ATTR_PROC,
                                Tag_CPU_arch) > 2)
@@ -3107,13 +4436,13 @@ bfd_elf32_arm_process_before_allocation (bfd *abfd,
   if (link_info->relocatable)
     return TRUE;
 
-  /* Here we have a bfd that is to be included on the link.  We have a hook
-     to do reloc rummaging, before section sizes are nailed down.  */
+  /* Here we have a bfd that is to be included on the link.  We have a
+     hook to do reloc rummaging, before section sizes are nailed down.  */
   globals = elf32_arm_hash_table (link_info);
-  check_use_blx (globals);
 
   BFD_ASSERT (globals != NULL);
-  BFD_ASSERT (globals->bfd_of_glue_owner != NULL);
+
+  check_use_blx (globals);
 
   if (globals->byteswap_code && !bfd_big_endian (abfd))
     {
@@ -3122,6 +4451,12 @@ bfd_elf32_arm_process_before_allocation (bfd *abfd,
       return FALSE;
     }
 
+  /* PR 5398: If we have not decided to include any loadable sections in
+     the output then we will not have a glue owner bfd.  This is OK, it
+     just means that there is nothing else for us to do here.  */
+  if (globals->bfd_of_glue_owner == NULL)
+    return TRUE;
+
   /* Rummage around all the relocs and map the glue vectors.  */
   sec = abfd->sections;
 
@@ -3136,12 +4471,11 @@ bfd_elf32_arm_process_before_allocation (bfd *abfd,
       if ((sec->flags & SEC_EXCLUDE) != 0)
        continue;
 
-      symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
+      symtab_hdr = & elf_symtab_hdr (abfd);
 
       /* Load the relocs.  */
       internal_relocs
-       = _bfd_elf_link_read_relocs (abfd, sec, (void *) NULL,
-                                    (Elf_Internal_Rela *) NULL, FALSE);
+       = _bfd_elf_link_read_relocs (abfd, sec, NULL, NULL, FALSE);
 
       if (internal_relocs == NULL)
        goto error_return;
@@ -3160,9 +4494,9 @@ bfd_elf32_arm_process_before_allocation (bfd *abfd,
          /* These are the only relocation types we care about.  */
          if (   r_type != R_ARM_PC24
              && 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_JUMP24
+             && (r_type != R_ARM_V4BX || globals->fix_v4bx < 2))
            continue;
 
          /* Get the section contents if we haven't done so already.  */
@@ -3179,6 +4513,15 @@ bfd_elf32_arm_process_before_allocation (bfd *abfd,
                }
            }
 
+         if (r_type == R_ARM_V4BX)
+           {
+             int reg;
+
+             reg = bfd_get_32 (abfd, contents + irel->r_offset) & 0xf;
+             record_arm_bx_glue (link_info, reg);
+             continue;
+           }
+
          /* If the relocation is not against a symbol it cannot concern us.  */
          h = NULL;
 
@@ -3205,21 +4548,21 @@ bfd_elf32_arm_process_before_allocation (bfd *abfd,
            {
            case R_ARM_PC24:
            case R_ARM_PLT32:
-           case R_ARM_CALL:
            case R_ARM_JUMP24:
              /* This one is a call from arm code.  We need to look up
                 the target of the call.  If it is a thumb target, we
                 insert glue.  */
-             if (ELF_ST_TYPE(h->type) == STT_ARM_TFUNC
+             if (ELF_ST_TYPE (h->type) == STT_ARM_TFUNC
                  && !(r_type == R_ARM_CALL && globals->use_blx))
                record_arm_to_thumb_glue (link_info, h);
              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.  */
-             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;
@@ -3267,7 +4610,7 @@ bfd_elf32_arm_init_maps (bfd *abfd)
   if ((abfd->flags & DYNAMIC) != 0)
     return;
 
-  hdr = &elf_tdata (abfd)->symtab_hdr;
+  hdr = & elf_symtab_hdr (abfd);
   localsyms = hdr->sh_info;
 
   /* Obtain a buffer full of symbols for this BFD. The hdr->sh_info field
@@ -3285,13 +4628,13 @@ bfd_elf32_arm_init_maps (bfd *abfd)
       Elf_Internal_Sym *isym = &isymbuf[i];
       asection *sec = bfd_section_from_elf_index (abfd, isym->st_shndx);
       const char *name;
-      
+
       if (sec != NULL
           && ELF_ST_BIND (isym->st_info) == STB_LOCAL)
         {
           name = bfd_elf_string_from_elf_section (abfd,
             hdr->sh_link, isym->st_name);
-          
+
           if (bfd_is_arm_special_symbol_name (name,
                                              BFD_ARM_SPECIAL_SYM_TYPE_MAP))
             elf32_arm_section_map_add (sec, name[1], isym->st_value);
@@ -3305,7 +4648,7 @@ 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);
   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)
     {
@@ -3315,7 +4658,7 @@ bfd_elf32_arm_set_vfp11_fix (bfd *obfd, struct bfd_link_info *link_info)
         case BFD_ARM_VFP11_FIX_NONE:
           globals->vfp11_fix = BFD_ARM_VFP11_FIX_NONE;
           break;
-        
+
         default:
           /* Give a warning, but do as the user requests anyway.  */
           (*_bfd_error_handler) (_("%B: warning: selected VFP11 erratum "
@@ -3330,7 +4673,8 @@ bfd_elf32_arm_set_vfp11_fix (bfd *obfd, struct bfd_link_info *link_info)
 }
 
 
-enum bfd_arm_vfp11_pipe {
+enum bfd_arm_vfp11_pipe
+{
   VFP11_FMAC,
   VFP11_LS,
   VFP11_DS,
@@ -3345,10 +4689,10 @@ enum bfd_arm_vfp11_pipe {
 
      0...31: single-precision registers s0...s31
      32...63: double-precision registers d0...d31.
-  
+
    Although X should be zero for VFP11 (encoding d0...d15 only), we might
    encounter VFP3 instructions, so we allow the full range for DP registers.  */
-   
+
 static unsigned int
 bfd_arm_vfp11_regno (unsigned int insn, bfd_boolean is_double, unsigned int rx,
                      unsigned int x)
@@ -3377,23 +4721,23 @@ static bfd_boolean
 bfd_arm_vfp11_antidependency (unsigned int wmask, int *regs, int numregs)
 {
   int i;
-  
+
   for (i = 0; i < numregs; i++)
     {
       unsigned int reg = regs[i];
 
       if (reg < 32 && (wmask & (1 << reg)) != 0)
         return TRUE;
-      
+
       reg -= 32;
 
       if (reg >= 16)
         continue;
-      
+
       if ((wmask & (3 << (reg * 2))) != 0)
         return TRUE;
     }
-  
+
   return FALSE;
 }
 
@@ -3514,7 +4858,7 @@ bfd_arm_vfp11_insn_decode (unsigned int insn, unsigned int *destmask, int *regs,
   else if ((insn & 0x0fe00ed0) == 0x0c400a10)
     {
       unsigned int fm = bfd_arm_vfp11_regno (insn, is_double, 0, 5);
-      
+
       if ((insn & 0x100000) == 0)
        {
           if (is_double)
@@ -3532,12 +4876,12 @@ bfd_arm_vfp11_insn_decode (unsigned int insn, unsigned int *destmask, int *regs,
     {
       int fd = bfd_arm_vfp11_regno (insn, is_double, 12, 22);
       unsigned int puw = ((insn >> 21) & 0x1) | (((insn >> 23) & 3) << 1);
-      
+
       switch (puw)
         {
         case 0: /* Two-reg transfer.  We should catch these above.  */
           abort ();
-        
+
         case 2: /* fldm[sdx].  */
         case 3:
         case 5:
@@ -3551,12 +4895,12 @@ bfd_arm_vfp11_insn_decode (unsigned int insn, unsigned int *destmask, int *regs,
               bfd_arm_vfp11_write_mask (destmask, i);
           }
           break;
-        
+
         case 4: /* fld[sd].  */
         case 6:
           bfd_arm_vfp11_write_mask (destmask, fd);
           break;
-        
+
         default:
           return VFP11_BAD;
         }
@@ -3607,10 +4951,10 @@ bfd_elf32_arm_vfp11_erratum_scan (bfd *abfd, struct bfd_link_info *link_info)
   int regs[3], numregs = 0;
   struct elf32_arm_link_hash_table *globals = elf32_arm_hash_table (link_info);
   int use_vector = (globals->vfp11_fix == BFD_ARM_VFP11_FIX_VECTOR);
-  
+
   /* We use a simple FSM to match troublesome VFP11 instruction sequences.
      The states transition as follows:
-     
+
        0 -> 1 (vector) or 0 -> 2 (scalar)
            A VFP FMAC-pipeline instruction has been seen. Fill
            regs[0]..regs[numregs-1] with its input operands. Remember this
@@ -3619,37 +4963,36 @@ bfd_elf32_arm_vfp11_erratum_scan (bfd *abfd, struct bfd_link_info *link_info)
        1 -> 2
            Any instruction, except for a VFP instruction which overwrites
            regs[*].
-       
+
        1 -> 3 [ -> 0 ]  or
        2 -> 3 [ -> 0 ]
            A VFP instruction has been seen which overwrites any of regs[*].
            We must make a veneer!  Reset state to 0 before examining next
            instruction.
-       
+
        2 -> 0
            If we fail to match anything in state 2, reset to state 0 and reset
            the instruction pointer to the instruction after 'first_fmac'.
 
      If the VFP11 vector mode is in use, there must be at least two unrelated
      instructions between anti-dependent VFP11 instructions to properly avoid
-     triggering the erratum, hence the use of the extra state 1.
-  */
+     triggering the erratum, hence the use of the extra state 1.  */
 
   /* If we are only performing a partial link do not bother
      to construct any glue.  */
   if (link_info->relocatable)
     return TRUE;
 
+  /* Skip if this bfd does not correspond to an ELF image.  */
+  if (! is_arm_elf (abfd))
+    return TRUE;
+
   /* We should have chosen a fix type by the time we get here.  */
   BFD_ASSERT (globals->vfp11_fix != BFD_ARM_VFP11_FIX_DEFAULT);
 
   if (globals->vfp11_fix == BFD_ARM_VFP11_FIX_NONE)
     return TRUE;
 
-  /* Skip if this bfd does not correspond to an ELF image.  */
-  if (bfd_get_flavour (abfd) != bfd_target_elf_flavour)
-    return TRUE;
-  
   for (sec = abfd->sections; sec != NULL; sec = sec->next)
     {
       unsigned int i, span, first_fmac = 0, veneer_of_insn = 0;
@@ -3664,10 +5007,10 @@ bfd_elf32_arm_vfp11_erratum_scan (bfd *abfd, struct bfd_link_info *link_info)
         continue;
 
       sec_data = elf32_arm_section_data (sec);
-      
+
       if (sec_data->mapcount == 0)
         continue;
-      
+
       if (elf_section_data (sec)->this_hdr.contents != NULL)
        contents = elf_section_data (sec)->this_hdr.contents;
       else if (! bfd_malloc_and_get_section (abfd, sec, &contents))
@@ -3682,7 +5025,7 @@ bfd_elf32_arm_vfp11_erratum_scan (bfd *abfd, struct bfd_link_info *link_info)
           unsigned int span_end = (span == sec_data->mapcount - 1)
                                  ? sec->size : sec_data->map[span + 1].vma;
           char span_type = sec_data->map[span].type;
-          
+
           /* FIXME: Only ARM mode is supported at present.  We may need to
              support Thumb-2 mode also at some point.  */
           if (span_type != 'a')
@@ -3771,7 +5114,7 @@ bfd_elf32_arm_vfp11_erratum_scan (bfd *abfd, struct bfd_link_info *link_info)
                     case 'a':
                       newerr->type = VFP11_ERRATUM_BRANCH_TO_ARM_VENEER;
                       break;
-                    
+
                     default:
                       abort ();
                     }
@@ -3790,7 +5133,7 @@ bfd_elf32_arm_vfp11_erratum_scan (bfd *abfd, struct bfd_link_info *link_info)
               i = next_i;
             }
         }
-      
+
       if (contents != NULL
           && elf_section_data (sec)->this_hdr.contents != contents)
         free (contents);
@@ -3803,7 +5146,7 @@ error_return:
   if (contents != NULL
       && elf_section_data (sec)->this_hdr.contents != contents)
     free (contents);
-  
+
   return FALSE;
 }
 
@@ -3817,16 +5160,16 @@ bfd_elf32_arm_vfp11_fix_veneer_locations (bfd *abfd,
   asection *sec;
   struct elf32_arm_link_hash_table *globals;
   char *tmp_name;
-  
+
   if (link_info->relocatable)
     return;
 
   /* Skip if this bfd does not correspond to an ELF image.  */
-  if (bfd_get_flavour (abfd) != bfd_target_elf_flavour)
+  if (! is_arm_elf (abfd))
     return;
 
   globals = elf32_arm_hash_table (link_info);
-  
+
   tmp_name = bfd_malloc ((bfd_size_type) strlen
                           (VFP11_ERRATUM_VENEER_ENTRY_NAME) + 10);
 
@@ -3834,7 +5177,7 @@ bfd_elf32_arm_vfp11_fix_veneer_locations (bfd *abfd,
     {
       struct _arm_elf_section_data *sec_data = elf32_arm_section_data (sec);
       elf32_vfp11_erratum_list *errnode = sec_data->erratumlist;
-      
+
       for (; errnode != NULL; errnode = errnode->next)
         {
           struct elf_link_hash_entry *myh;
@@ -3881,13 +5224,13 @@ bfd_elf32_arm_vfp11_fix_veneer_locations (bfd *abfd,
 
               errnode->u.v.branch->vma = vma;
               break;
-            
+
             default:
               abort ();
             }
         }
     }
-  
+
   free (tmp_name);
 }
 
@@ -3914,103 +5257,46 @@ bfd_elf32_arm_set_target_relocs (struct bfd *output_bfd,
   else if (strcmp (target2_type, "abs") == 0)
     globals->target2_reloc = R_ARM_ABS32;
   else if (strcmp (target2_type, "got-rel") == 0)
-    globals->target2_reloc = R_ARM_GOT_PREL;
-  else
-    {
-      _bfd_error_handler (_("Invalid TARGET2 relocation type '%s'."),
-                         target2_type);
-    }
-  globals->fix_v4bx = fix_v4bx;
-  globals->use_blx |= use_blx;
-  globals->vfp11_fix = vfp11_fix;
-  globals->pic_veneer = pic_veneer;
-
-  elf32_arm_tdata (output_bfd)->no_enum_size_warning = no_enum_warn;
-}
-
-/* The thumb form of a long branch is a bit finicky, because the offset
-   encoding is split over two fields, each in it's own instruction. They
-   can occur in any order. So given a thumb form of long branch, and an
-   offset, insert the offset into the thumb branch and return finished
-   instruction.
-
-   It takes two thumb instructions to encode the target address. Each has
-   11 bits to invest. The upper 11 bits are stored in one (identified by
-   H-0.. see below), the lower 11 bits are stored in the other (identified
-   by H-1).
-
-   Combine together and shifted left by 1 (it's a half word address) and
-   there you have it.
-
-   Op: 1111 = F,
-   H-0, upper address-0 = 000
-   Op: 1111 = F,
-   H-1, lower address-0 = 800
-
-   They can be ordered either way, but the arm tools I've seen always put
-   the lower one first. It probably doesn't matter. krk@cygnus.com
-
-   XXX:  Actually the order does matter.  The second instruction (H-1)
-   moves the computed address into the PC, so it must be the second one
-   in the sequence.  The problem, however is that whilst little endian code
-   stores the instructions in HI then LOW order, big endian code does the
-   reverse.  nickc@cygnus.com.  */
-
-#define LOW_HI_ORDER      0xF800F000
-#define HI_LOW_ORDER      0xF000F800
-
-static insn32
-insert_thumb_branch (insn32 br_insn, int rel_off)
-{
-  unsigned int low_bits;
-  unsigned int high_bits;
-
-  BFD_ASSERT ((rel_off & 1) != 1);
-
-  rel_off >>= 1;                               /* Half word aligned address.  */
-  low_bits = rel_off & 0x000007FF;             /* The bottom 11 bits.  */
-  high_bits = (rel_off >> 11) & 0x000007FF;    /* The top 11 bits.  */
-
-  if ((br_insn & LOW_HI_ORDER) == LOW_HI_ORDER)
-    br_insn = LOW_HI_ORDER | (low_bits << 16) | high_bits;
-  else if ((br_insn & HI_LOW_ORDER) == HI_LOW_ORDER)
-    br_insn = HI_LOW_ORDER | (high_bits << 16) | low_bits;
-  else
-    /* FIXME: abort is probably not the right call. krk@cygnus.com  */
-    abort ();  /* Error - not a valid branch instruction form.  */
-
-  return br_insn;
-}
-
-
-/* Store an Arm insn into an output section not processed by
-   elf32_arm_write_section.  */
+    globals->target2_reloc = R_ARM_GOT_PREL;
+  else
+    {
+      _bfd_error_handler (_("Invalid TARGET2 relocation type '%s'."),
+                         target2_type);
+    }
+  globals->fix_v4bx = fix_v4bx;
+  globals->use_blx |= use_blx;
+  globals->vfp11_fix = vfp11_fix;
+  globals->pic_veneer = pic_veneer;
 
-static void
-put_arm_insn (struct elf32_arm_link_hash_table *htab,
-            bfd * output_bfd, bfd_vma val, void * ptr)
-{
-    if (htab->byteswap_code != bfd_little_endian (output_bfd))
-      bfd_putl32 (val, ptr);
-    else
-      bfd_putb32 (val, ptr);
+  BFD_ASSERT (is_arm_elf (output_bfd));
+  elf_arm_tdata (output_bfd)->no_enum_size_warning = no_enum_warn;
 }
 
-
-/* Store a 16-bit Thumb insn into an output section not processed by
-   elf32_arm_write_section.  */
+/* Replace the target offset of a Thumb bl or b.w instruction.  */
 
 static void
-put_thumb_insn (struct elf32_arm_link_hash_table *htab,
-              bfd * output_bfd, bfd_vma val, void * ptr)
+insert_thumb_branch (bfd *abfd, long int offset, bfd_byte *insn)
 {
-    if (htab->byteswap_code != bfd_little_endian (output_bfd))
-      bfd_putl16 (val, ptr);
-    else
-      bfd_putb16 (val, ptr);
+  bfd_vma upper;
+  bfd_vma lower;
+  int reloc_sign;
+
+  BFD_ASSERT ((offset & 1) == 0);
+
+  upper = bfd_get_16 (abfd, insn);
+  lower = bfd_get_16 (abfd, insn + 2);
+  reloc_sign = (offset < 0) ? 1 : 0;
+  upper = (upper & ~(bfd_vma) 0x7ff)
+         | ((offset >> 12) & 0x3ff)
+         | (reloc_sign << 10);
+  lower = (lower & ~(bfd_vma) 0x2fff)
+         | (((!((offset >> 23) & 1)) ^ reloc_sign) << 13)
+         | (((!((offset >> 22) & 1)) ^ reloc_sign) << 11)
+         | ((offset >> 1) & 0x7ff);
+  bfd_put_16 (abfd, upper, insn);
+  bfd_put_16 (abfd, lower, insn + 2);
 }
 
-
 /* Thumb code calling an ARM function.  */
 
 static int
@@ -4028,7 +5314,6 @@ elf32_thumb_to_arm_stub (struct bfd_link_info * info,
 {
   asection * s = 0;
   bfd_vma my_offset;
-  unsigned long int tmp;
   long int ret_offset;
   struct elf_link_hash_entry * myh;
   struct elf32_arm_link_hash_table * globals;
@@ -4109,12 +5394,7 @@ elf32_thumb_to_arm_stub (struct bfd_link_info * info,
     /* Biassing for PC-relative addressing.  */
     - 8;
 
-  tmp = bfd_get_32 (input_bfd, hit_data
-                   - input_section->vma);
-
-  bfd_put_32 (output_bfd,
-             (bfd_vma) insert_thumb_branch (tmp, ret_offset),
-             hit_data - input_section->vma);
+  insert_thumb_branch (input_bfd, ret_offset, hit_data - input_section->vma);
 
   return TRUE;
 }
@@ -4284,7 +5564,7 @@ elf32_arm_to_thumb_export_stub (struct elf_link_hash_entry *h, void * inf)
   bfd_vma val;
   char *error_message;
 
-  eh = elf32_arm_hash_entry(h);
+  eh = elf32_arm_hash_entry (h);
   /* Allocate stubs for exported Thumb functions on v4t.  */
   if (eh->export_glue == NULL)
     return TRUE;
@@ -4314,9 +5594,46 @@ elf32_arm_to_thumb_export_stub (struct elf_link_hash_entry *h, void * inf)
   return TRUE;
 }
 
+/* Populate ARMv4 BX veneers.  Returns the absolute adress of the veneer.  */
+
+static bfd_vma
+elf32_arm_bx_glue (struct bfd_link_info * info, int reg)
+{
+  bfd_byte *p;
+  bfd_vma glue_addr;
+  asection *s;
+  struct elf32_arm_link_hash_table *globals;
+
+  globals = elf32_arm_hash_table (info);
+
+  BFD_ASSERT (globals != NULL);
+  BFD_ASSERT (globals->bfd_of_glue_owner != NULL);
+
+  s = bfd_get_section_by_name (globals->bfd_of_glue_owner,
+                              ARM_BX_GLUE_SECTION_NAME);
+  BFD_ASSERT (s != NULL);
+  BFD_ASSERT (s->contents != NULL);
+  BFD_ASSERT (s->output_section != NULL);
+
+  BFD_ASSERT (globals->bx_glue_offset[reg] & 2);
+
+  glue_addr = globals->bx_glue_offset[reg] & ~(bfd_vma)3;
+
+  if ((globals->bx_glue_offset[reg] & 1) == 0)
+    {
+      p = s->contents + glue_addr;
+      bfd_put_32 (globals->obfd, armbx1_tst_insn + (reg << 16), p);
+      bfd_put_32 (globals->obfd, armbx2_moveq_insn + reg, p + 4);
+      bfd_put_32 (globals->obfd, armbx3_bx_insn + reg, p + 8);
+      globals->bx_glue_offset[reg] |= 1;
+    }
+
+  return glue_addr + s->output_section->vma + s->output_offset;
+}
+
 /* Generate Arm stubs for exported Thumb symbols.  */
 static void
-elf32_arm_begin_write_processing (bfd *abfd ATTRIBUTE_UNUSED, 
+elf32_arm_begin_write_processing (bfd *abfd ATTRIBUTE_UNUSED,
                                  struct bfd_link_info *link_info)
 {
   struct elf32_arm_link_hash_table * globals;
@@ -4453,8 +5770,9 @@ calculate_group_reloc_mask (bfd_vma value, int n, bfd_vma *final_residual)
 
 /* Given an ARM instruction, determine whether it is an ADD or a SUB.
    Returns 1 if it is an ADD, -1 if it is a SUB, and 0 otherwise.  */
+
 static int
-identify_add_or_sub(bfd_vma insn)
+identify_add_or_sub (bfd_vma insn)
 {
   int opcode = insn & 0x1e00000;
 
@@ -4467,15 +5785,6 @@ identify_add_or_sub(bfd_vma insn)
   return 0;
 }
 
-/* Determine if we're dealing with a Thumb-2 object.  */
-
-static int using_thumb2 (struct elf32_arm_link_hash_table *globals)
-{
-  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;
-}
-
 /* Perform a relocation as part of a final link.  */
 
 static bfd_reloc_status_type
@@ -4510,7 +5819,9 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
 
   globals = elf32_arm_hash_table (info);
 
-  /* Some relocation type map to different relocations depending on the
+  BFD_ASSERT (is_arm_elf (input_bfd));
+
+  /* Some relocation types map to different relocations depending on the
      target.  We pick the right one here.  */
   r_type = arm_real_reloc_type (globals, r_type);
   if (r_type != howto->type)
@@ -4534,7 +5845,7 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
       sgot = bfd_get_section_by_name (dynobj, ".got");
       splt = bfd_get_section_by_name (dynobj, ".plt");
     }
-  symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr;
+  symtab_hdr = & elf_symtab_hdr (input_bfd);
   sym_hashes = elf_sym_hashes (input_bfd);
   local_got_offsets = elf_local_got_offsets (input_bfd);
   r_symndx = ELF32_R_SYM (rel->r_info);
@@ -4606,6 +5917,9 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
         run time.  */
       if ((info->shared || globals->root.is_relocatable_executable)
          && (input_section->flags & SEC_ALLOC)
+         && !(elf32_arm_hash_table (info)->vxworks_p
+              && strcmp (input_section->output_section->name,
+                         ".tls_vars") == 0)
          && ((r_type != R_ARM_REL32 && r_type != R_ARM_REL32_NOI)
              || !SYMBOL_CALLS_LOCAL (info, h))
          && (h == NULL
@@ -4739,6 +6053,16 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
        case R_ARM_JUMP24:
        case R_ARM_PC24:          /* Arm B/BL instruction */
        case R_ARM_PLT32:
+         {
+         bfd_vma from;
+         bfd_signed_vma branch_offset;
+         struct elf32_arm_stub_hash_entry *stub_entry = NULL;
+
+         from = (input_section->output_section->vma
+                 + input_section->output_offset
+                 + rel->r_offset);
+         branch_offset = (bfd_signed_vma)(value - from);
+
          if (r_type == R_ARM_XPC25)
            {
              /* Check for Arm calling Arm function.  */
@@ -4750,7 +6074,7 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
                   input_bfd,
                   h ? h->root.root.string : "(local)");
            }
-         else if (r_type != R_ARM_CALL || !globals->use_blx)
+         else if (r_type != R_ARM_CALL)
            {
              /* Check for Arm calling Thumb function.  */
              if (sym_flags == STT_ARM_TFUNC)
@@ -4766,6 +6090,27 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
                }
            }
 
+         /* Check if a stub has to be inserted because the
+            destination is too far or we are changing mode */
+         if (r_type == R_ARM_CALL)
+           {
+             if (branch_offset > ARM_MAX_FWD_BRANCH_OFFSET
+                 || branch_offset < ARM_MAX_BWD_BRANCH_OFFSET
+                 || sym_flags == STT_ARM_TFUNC)
+               {
+                 /* The target is out of reach, so redirect the
+                    branch to the local stub for this function.  */
+
+                 stub_entry = elf32_arm_get_stub_entry (input_section,
+                                                        sym_sec, h,
+                                                        rel, globals);
+                 if (stub_entry != NULL)
+                   value = (stub_entry->stub_offset
+                            + stub_entry->stub_sec->output_offset
+                            + stub_entry->stub_sec->output_section->vma);
+               }
+           }
+
          /* The ARM ELF ABI says that this reloc is computed as: S - P + A
             where:
              S is the address of the symbol in the relocation.
@@ -4827,7 +6172,9 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
              if (r_type == R_ARM_CALL)
                {
                  /* Select the correct instruction (BL or BLX).  */
-                 if (sym_flags == STT_ARM_TFUNC)
+                 /* Only if we are not handling a BL to a stub. In this
+                    case, mode switching is performed by the stub. */
+                 if (sym_flags == STT_ARM_TFUNC && !stub_entry)
                    value |= (1 << 28);
                  else
                    {
@@ -4836,6 +6183,7 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
                    }
                }
            }
+         }
          break;
 
        case R_ARM_ABS32:
@@ -4996,6 +6344,7 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
 
     case R_ARM_THM_XPC22:
     case R_ARM_THM_CALL:
+    case R_ARM_THM_JUMP24:
       /* Thumb BL (branch long instruction).  */
       {
        bfd_vma relocation;
@@ -5059,7 +6408,7 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
                && (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;
@@ -5072,7 +6421,8 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
                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;
@@ -5085,7 +6435,7 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
            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.  */
@@ -5097,6 +6447,43 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
            *unresolved_reloc_p = FALSE;
          }
 
+       if (r_type == R_ARM_THM_CALL)
+         {
+           /* Check if a stub has to be inserted because the destination
+              is too far. */
+           bfd_vma from;
+           bfd_signed_vma branch_offset;
+           struct elf32_arm_stub_hash_entry *stub_entry = NULL;
+
+           from = (input_section->output_section->vma
+                   + input_section->output_offset
+                   + rel->r_offset);
+           branch_offset = (bfd_signed_vma)(value - from);
+
+           if ((!thumb2
+                && (branch_offset > THM_MAX_FWD_BRANCH_OFFSET
+                    || (branch_offset < THM_MAX_BWD_BRANCH_OFFSET)))
+               ||
+               (thumb2
+                && (branch_offset > THM2_MAX_FWD_BRANCH_OFFSET
+                    || (branch_offset < THM2_MAX_BWD_BRANCH_OFFSET))))
+             {
+               /* The target is out of reach or we are changing modes, so
+                  redirect the branch to the local stub for this
+                  function.  */
+               stub_entry = elf32_arm_get_stub_entry (input_section,
+                                                      sym_sec, h,
+                                                      rel, globals);
+               if (stub_entry != NULL)
+                 value = (stub_entry->stub_offset
+                          + stub_entry->stub_sec->output_offset
+                          + stub_entry->stub_sec->output_section->vma);
+
+               /* This call becomes a call to Arm for sure. Force BLX.  */
+               lower_insn = (lower_insn & ~0x1000) | 0x0800;
+             }
+         }
+
        relocation = value + signed_addend;
 
        relocation -= (input_section->output_section->vma
@@ -5125,7 +6512,7 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
        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
@@ -5139,7 +6526,7 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
        upper_insn = (upper_insn & ~(bfd_vma) 0x7ff)
                      | ((relocation >> 12) & 0x3ff)
                      | (reloc_sign << 10);
-       lower_insn = (lower_insn & ~(bfd_vma) 0x2fff) 
+       lower_insn = (lower_insn & ~(bfd_vma) 0x2fff)
                      | (((!((relocation >> 23) & 1)) ^ reloc_sign) << 13)
                      | (((!((relocation >> 22) & 1)) ^ reloc_sign) << 11)
                      | ((relocation >> 1) & 0x7ff);
@@ -5152,79 +6539,6 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
       }
       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.  */
       {
@@ -5255,6 +6569,17 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
            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.  */
 
@@ -5566,7 +6891,7 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
            globals->tls_ldm_got.offset |= 1;
          }
 
-       value = globals->sgot->output_section->vma + globals->sgot->output_offset + off 
+       value = globals->sgot->output_section->vma + globals->sgot->output_offset + off
          - (input_section->output_section->vma + input_section->output_offset + rel->r_offset);
 
        return _bfd_final_link_relocate (howto, input_bfd, input_section,
@@ -5724,7 +7049,7 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
 
        if ((tls_type & GOT_TLS_GD) && r_type != R_ARM_TLS_GD32)
          off += 8;
-       value = globals->sgot->output_section->vma + globals->sgot->output_offset + off 
+       value = globals->sgot->output_section->vma + globals->sgot->output_offset + off
          - (input_section->output_section->vma + input_section->output_offset + rel->r_offset);
 
        return _bfd_final_link_relocate (howto, input_bfd, input_section,
@@ -5739,29 +7064,43 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
            (_("%B(%A+0x%lx): R_ARM_TLS_LE32 relocation not permitted in shared object"),
             input_bfd, input_section,
             (long) rel->r_offset, howto->name);
-         return FALSE;   
+         return FALSE;
        }
       else
        value = tpoff (info, value);
-      
+
       return _bfd_final_link_relocate (howto, input_bfd, input_section,
                                       contents, rel->r_offset, value,
                                       rel->r_addend);
 
     case R_ARM_V4BX:
       if (globals->fix_v4bx)
-        {
-          bfd_vma insn = bfd_get_32 (input_bfd, hit_data);
+       {
+         bfd_vma insn = bfd_get_32 (input_bfd, hit_data);
 
-          /* Ensure that we have a BX instruction.  */
-          BFD_ASSERT ((insn & 0x0ffffff0) == 0x012fff10);
+         /* Ensure that we have a BX instruction.  */
+         BFD_ASSERT ((insn & 0x0ffffff0) == 0x012fff10);
 
-          /* Preserve Rm (lowest four bits) and the condition code
-             (highest four bits). Other bits encode MOV PC,Rm.  */
-          insn = (insn & 0xf000000f) | 0x01a0f000;
+         if (globals->fix_v4bx == 2 && (insn & 0xf) != 0xf)
+           {
+             /* Branch to veneer.  */
+             bfd_vma glue_addr;
+             glue_addr = elf32_arm_bx_glue (info, insn & 0xf);
+             glue_addr -= input_section->output_section->vma
+                          + input_section->output_offset
+                          + rel->r_offset + 8;
+             insn = (insn & 0xf0000000) | 0x0a000000
+                    | ((glue_addr >> 2) & 0x00ffffff);
+           }
+         else
+           {
+             /* Preserve Rm (lowest four bits) and the condition code
+                (highest four bits). Other bits encode MOV PC,Rm.  */
+             insn = (insn & 0xf000000f) | 0x01a0f000;
+           }
 
-          bfd_put_32 (input_bfd, insn, hit_data);
-        }
+         bfd_put_32 (input_bfd, insn, hit_data);
+       }
       return bfd_reloc_ok;
 
     case R_ARM_MOVW_ABS_NC:
@@ -5781,7 +7120,7 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
        if (globals->use_rel)
          {
            addend = ((insn >> 4) & 0xf000) | (insn & 0xfff);
-           signed_addend = (addend ^ 0x10000) - 0x10000;
+           signed_addend = (addend ^ 0x8000) - 0x8000;
          }
 
        value += signed_addend;
@@ -5821,7 +7160,7 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
     case R_ARM_THM_MOVT_BREL:
       {
        bfd_vma insn;
-       
+
        insn = bfd_get_16 (input_bfd, hit_data) << 16;
        insn |= bfd_get_16 (input_bfd, hit_data + 2);
 
@@ -5831,7 +7170,7 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
                   | ((insn >> 15) & 0x0800)
                   | ((insn >> 4)  & 0x0700)
                   | (insn         & 0x00ff);
-           signed_addend = (addend ^ 0x10000) - 0x10000;
+           signed_addend = (addend ^ 0x8000) - 0x8000;
          }
 
        value += signed_addend;
@@ -5907,7 +7246,7 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
             break;
 
           default:
-            abort();
+            abort ();
           }
 
         /* If REL, extract the addend from the insn.  If RELA, it will
@@ -5940,7 +7279,7 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
                   (_("%B(%A+0x%lx): Only ADD or SUB instructions are allowed for ALU group relocations"),
                   input_bfd, input_section,
                   (long) rel->r_offset, howto->name);
-                return bfd_reloc_overflow;       
+                return bfd_reloc_overflow;
              }
 
             signed_addend *= negative;
@@ -6035,7 +7374,7 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
             break;
 
           default:
-            abort();
+            abort ();
           }
 
         /* If REL, extract the addend from the insn.  If RELA, it will
@@ -6118,7 +7457,7 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
             break;
 
           default:
-            abort();
+            abort ();
           }
 
         /* If REL, extract the addend from the insn.  If RELA, it will
@@ -6201,7 +7540,7 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
             break;
 
           default:
-            abort();
+            abort ();
           }
 
         /* If REL, extract the addend from the insn.  If RELA, it will
@@ -6266,7 +7605,8 @@ arm_add_to_rel (bfd *              abfd,
 {
   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;
@@ -6341,6 +7681,7 @@ arm_add_to_rel (bfd *              abfd,
    || (R_TYPE) == R_ARM_TLS_IE32)
 
 /* Relocate an ARM ELF section.  */
+
 static bfd_boolean
 elf32_arm_relocate_section (bfd *                  output_bfd,
                            struct bfd_link_info * info,
@@ -6360,7 +7701,7 @@ elf32_arm_relocate_section (bfd *                  output_bfd,
 
   globals = elf32_arm_hash_table (info);
 
-  symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr;
+  symtab_hdr = & elf_symtab_hdr (input_bfd);
   sym_hashes = elf_sym_hashes (input_bfd);
 
   rel = relocs;
@@ -6412,34 +7753,85 @@ elf32_arm_relocate_section (bfd *                  output_bfd,
                  asection *msec;
                  bfd_vma addend, value;
 
-                 if (howto->rightshift)
+                 switch (r_type)
                    {
-                     (*_bfd_error_handler)
-                       (_("%B(%A+0x%lx): %s relocation against SEC_MERGE section"),
-                        input_bfd, input_section,
-                        (long) rel->r_offset, howto->name);
-                     return FALSE;
-                   }
+                   case R_ARM_MOVW_ABS_NC:
+                   case R_ARM_MOVT_ABS:
+                     value = bfd_get_32 (input_bfd, contents + rel->r_offset);
+                     addend = ((value & 0xf0000) >> 4) | (value & 0xfff);
+                     addend = (addend ^ 0x8000) - 0x8000;
+                     break;
 
-                 value = bfd_get_32 (input_bfd, contents + rel->r_offset);
+                   case R_ARM_THM_MOVW_ABS_NC:
+                   case R_ARM_THM_MOVT_ABS:
+                     value = bfd_get_16 (input_bfd, contents + rel->r_offset)
+                             << 16;
+                     value |= bfd_get_16 (input_bfd,
+                                          contents + rel->r_offset + 2);
+                     addend = ((value & 0xf7000) >> 4) | (value & 0xff)
+                              | ((value & 0x04000000) >> 15);
+                     addend = (addend ^ 0x8000) - 0x8000;
+                     break;
 
-                 /* Get the (signed) value from the instruction.  */
-                 addend = value & howto->src_mask;
-                 if (addend & ((howto->src_mask + 1) >> 1))
-                   {
-                     bfd_signed_vma mask;
+                   default:
+                     if (howto->rightshift
+                         || (howto->src_mask & (howto->src_mask + 1)))
+                       {
+                         (*_bfd_error_handler)
+                           (_("%B(%A+0x%lx): %s relocation against SEC_MERGE section"),
+                            input_bfd, input_section,
+                            (long) rel->r_offset, howto->name);
+                         return FALSE;
+                       }
+
+                     value = bfd_get_32 (input_bfd, contents + rel->r_offset);
 
-                     mask = -1;
-                     mask &= ~ howto->src_mask;
-                     addend |= mask;
+                     /* Get the (signed) value from the instruction.  */
+                     addend = value & howto->src_mask;
+                     if (addend & ((howto->src_mask + 1) >> 1))
+                       {
+                         bfd_signed_vma mask;
+
+                         mask = -1;
+                         mask &= ~ howto->src_mask;
+                         addend |= mask;
+                       }
+                     break;
                    }
+
                  msec = sec;
                  addend =
                    _bfd_elf_rel_local_sym (output_bfd, sym, &msec, addend)
                    - relocation;
                  addend += msec->output_section->vma + msec->output_offset;
-                 value = (value & ~ howto->dst_mask) | (addend & howto->dst_mask);
-                 bfd_put_32 (input_bfd, value, contents + rel->r_offset);
+
+                 /* Cases here must match those in the preceeding
+                    switch statement.  */
+                 switch (r_type)
+                   {
+                   case R_ARM_MOVW_ABS_NC:
+                   case R_ARM_MOVT_ABS:
+                     value = (value & 0xfff0f000) | ((addend & 0xf000) << 4)
+                             | (addend & 0xfff);
+                     bfd_put_32 (input_bfd, value, contents + rel->r_offset);
+                     break;
+
+                   case R_ARM_THM_MOVW_ABS_NC:
+                   case R_ARM_THM_MOVT_ABS:
+                     value = (value & 0xfbf08f00) | ((addend & 0xf700) << 4)
+                             | (addend & 0xff) | ((addend & 0x0800) << 15);
+                     bfd_put_16 (input_bfd, value >> 16,
+                                 contents + rel->r_offset);
+                     bfd_put_16 (input_bfd, value,
+                                 contents + rel->r_offset + 2);
+                     break;
+
+                   default:
+                     value = (value & ~ howto->dst_mask)
+                             | (addend & howto->dst_mask);
+                     bfd_put_32 (input_bfd, value, contents + rel->r_offset);
+                     break;
+                   }
                }
            }
          else
@@ -6649,8 +8041,7 @@ elf32_arm_copy_private_bfd_data (bfd *ibfd, bfd *obfd)
   flagword in_flags;
   flagword out_flags;
 
-  if (   bfd_get_flavour (ibfd) != bfd_target_elf_flavour
-      || bfd_get_flavour (obfd) != bfd_target_elf_flavour)
+  if (! is_arm_elf (ibfd) || ! is_arm_elf (obfd))
     return TRUE;
 
   in_flags  = elf_elfheader (ibfd)->e_flags;
@@ -6727,6 +8118,7 @@ enum
 
 /* Determine whether an object attribute tag takes an integer, a
    string or both.  */
+
 static int
 elf32_arm_obj_attrs_arg_type (int tag)
 {
@@ -6742,6 +8134,7 @@ elf32_arm_obj_attrs_arg_type (int tag)
 
 /* 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)
 {
@@ -6751,6 +8144,8 @@ elf32_arm_merge_eabi_attributes (bfd *ibfd, bfd *obfd)
   /* Some tags have 0 = don't care, 1 = strong requirement,
      2 = weak requirement.  */
   static const int order_312[3] = {3, 1, 2};
+  /* For use with Tag_VFP_arch.  */
+  static const int order_01243[5] = {0, 1, 2, 4, 3};
   int i;
 
   if (!elf_known_obj_attributes_proc (obfd)[0].i)
@@ -6805,7 +8200,6 @@ elf32_arm_merge_eabi_attributes (bfd *ibfd, bfd *obfd)
        case Tag_CPU_arch:
        case Tag_ARM_ISA_use:
        case Tag_THUMB_ISA_use:
-       case Tag_VFP_arch:
        case Tag_WMMX_arch:
        case Tag_NEON_arch:
          /* ??? Do NEON and WMMX conflict?  */
@@ -6833,6 +8227,11 @@ elf32_arm_merge_eabi_attributes (bfd *ibfd, bfd *obfd)
          if (in_attr[i].i)
            out_attr[i].i = in_attr[i].i;
          break;
+       case Tag_VFP_arch:
+         if (in_attr[i].i > 4 || out_attr[i].i > 4
+             || order_01243[in_attr[i].i] > order_01243[out_attr[i].i])
+           out_attr[i].i = in_attr[i].i;
+         break;
        case Tag_PCS_config:
          if (out_attr[i].i == 0)
            out_attr[i].i = in_attr[i].i;
@@ -6908,7 +8307,7 @@ elf32_arm_merge_eabi_attributes (bfd *ibfd, bfd *obfd)
                }
              else if (in_attr[i].i != AEABI_enum_forced_wide
                       && out_attr[i].i != in_attr[i].i
-                      && !elf32_arm_tdata (obfd)->no_enum_size_warning)
+                      && !elf_arm_tdata (obfd)->no_enum_size_warning)
                {
                  const char *aeabi_enum_names[] =
                    { "", "variable-size", "32-bit", "" };
@@ -7004,8 +8403,7 @@ elf32_arm_merge_private_bfd_data (bfd * ibfd, bfd * obfd)
   if (! _bfd_generic_verify_endian_match (ibfd, obfd))
     return FALSE;
 
-  if (   bfd_get_flavour (ibfd) != bfd_target_elf_flavour
-      || bfd_get_flavour (obfd) != bfd_target_elf_flavour)
+  if (! is_arm_elf (ibfd) || ! is_arm_elf (obfd))
     return TRUE;
 
   if (!elf32_arm_merge_eabi_attributes (ibfd, obfd))
@@ -7392,14 +8790,19 @@ elf32_arm_gc_sweep_hook (bfd *                     abfd,
   const Elf_Internal_Rela *rel, *relend;
   struct elf32_arm_link_hash_table * globals;
 
+  if (info->relocatable)
+    return TRUE;
+
   globals = elf32_arm_hash_table (info);
 
   elf_section_data (sec)->local_dynrel = NULL;
 
-  symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
+  symtab_hdr = & elf_symtab_hdr (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++)
     {
@@ -7450,6 +8853,8 @@ elf32_arm_gc_sweep_hook (bfd *                     abfd,
        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:
@@ -7471,7 +8876,11 @@ elf32_arm_gc_sweep_hook (bfd *                     abfd,
              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--;
                }
 
@@ -7512,17 +8921,19 @@ elf32_arm_check_relocs (bfd *abfd, struct bfd_link_info *info,
 {
   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;
   asection *sreloc;
   bfd_vma *local_got_offsets;
   struct elf32_arm_link_hash_table *htab;
+  bfd_boolean needs_plt;
 
   if (info->relocatable)
     return TRUE;
 
+  BFD_ASSERT (is_arm_elf (abfd));
+
   htab = elf32_arm_hash_table (info);
   sreloc = NULL;
 
@@ -7538,13 +8949,8 @@ elf32_arm_check_relocs (bfd *abfd, struct bfd_link_info *info,
   dynobj = elf_hash_table (info)->dynobj;
   local_got_offsets = elf_local_got_offsets (abfd);
 
-  symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
+  symtab_hdr = & elf_symtab_hdr (abfd);
   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++)
@@ -7608,9 +9014,9 @@ elf32_arm_check_relocs (bfd *abfd, struct bfd_link_info *info,
                  if (local_got_refcounts == NULL)
                    {
                      bfd_size_type size;
-                     
+
                      size = symtab_hdr->sh_info;
-                     size *= (sizeof (bfd_signed_vma) + sizeof(char));
+                     size *= (sizeof (bfd_signed_vma) + sizeof (char));
                      local_got_refcounts = bfd_zalloc (abfd, size);
                      if (local_got_refcounts == NULL)
                        return FALSE;
@@ -7663,16 +9069,21 @@ elf32_arm_check_relocs (bfd *abfd, struct bfd_link_info *info,
              break;
            /* Fall through */
 
-         case R_ARM_ABS32:
-         case R_ARM_ABS32_NOI:
-         case R_ARM_REL32:
-         case R_ARM_REL32_NOI:
          case R_ARM_PC24:
          case R_ARM_PLT32:
          case R_ARM_CALL:
          case R_ARM_JUMP24:
          case R_ARM_PREL31:
          case R_ARM_THM_CALL:
+         case R_ARM_THM_JUMP24:
+         case R_ARM_THM_JUMP19:
+           needs_plt = 1;
+           goto normal_reloc;
+
+         case R_ARM_ABS32:
+         case R_ARM_ABS32_NOI:
+         case R_ARM_REL32:
+         case R_ARM_REL32_NOI:
          case R_ARM_MOVW_ABS_NC:
          case R_ARM_MOVT_ABS:
          case R_ARM_MOVW_PREL_NC:
@@ -7681,6 +9092,9 @@ elf32_arm_check_relocs (bfd *abfd, struct bfd_link_info *info,
          case R_ARM_THM_MOVT_ABS:
          case R_ARM_THM_MOVW_PREL_NC:
          case R_ARM_THM_MOVT_PREL:
+           needs_plt = 0;
+         normal_reloc:
+
            /* Should the interworking branches be listed here?  */
            if (h != NULL)
              {
@@ -7697,18 +9111,22 @@ elf32_arm_check_relocs (bfd *abfd, struct bfd_link_info *info,
                   refers to is in a different object.  We can't tell for
                   sure yet, because something later might force the
                   symbol local.  */
-               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_ABS12)
+               if (needs_plt)
                  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)
+                 eh->plt_maybe_thumb_refcount += 1;
+
+               if (r_type == R_ARM_THM_JUMP24
+                   || r_type == R_ARM_THM_JUMP19)
                  eh->plt_thumb_refcount += 1;
              }
 
@@ -7826,7 +9244,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:
-          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;
         }
@@ -7839,8 +9259,8 @@ elf32_arm_check_relocs (bfd *abfd, struct bfd_link_info *info,
    required if the corresponding code section is marked.  */
 
 static bfd_boolean
-elf32_arm_gc_mark_extra_sections(struct bfd_link_info *info,
-                                elf_gc_mark_hook_fn gc_mark_hook)
+elf32_arm_gc_mark_extra_sections (struct bfd_link_info *info,
+                                 elf_gc_mark_hook_fn gc_mark_hook)
 {
   bfd *sub;
   Elf_Internal_Shdr **elf_shdrp;
@@ -7856,15 +9276,18 @@ elf32_arm_gc_mark_extra_sections(struct bfd_link_info *info,
        {
          asection *o;
 
-         if (bfd_get_flavour (sub) != bfd_target_elf_flavour)
+         if (! is_arm_elf (sub))
            continue;
 
          elf_shdrp = elf_elfsections (sub);
          for (o = sub->sections; o != NULL; o = o->next)
            {
              Elf_Internal_Shdr *hdr;
+
              hdr = &elf_section_data (o)->this_hdr;
-             if (hdr->sh_type == SHT_ARM_EXIDX && hdr->sh_link
+             if (hdr->sh_type == SHT_ARM_EXIDX
+                 && hdr->sh_link
+                 && hdr->sh_link < elf_numsections (sub)
                  && !o->gc_mark
                  && elf_shdrp[hdr->sh_link]->bfd_section->gc_mark)
                {
@@ -7947,7 +9370,7 @@ arm_elf_find_function (bfd *         abfd ATTRIBUTE_UNUSED,
     *functionname_ptr = bfd_asymbol_name (func);
 
   return TRUE;
-}  
+}
 
 
 /* Find the nearest line to a particular section and offset, for error
@@ -8059,6 +9482,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;
+         eh->plt_maybe_thumb_refcount = 0;
          h->needs_plt = 0;
        }
 
@@ -8073,6 +9497,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;
+      eh->plt_maybe_thumb_refcount = 0;
     }
 
   /* If this is a weak symbol, and there is a real definition, the
@@ -8150,6 +9575,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;
+  bfd_signed_vma thumb_refs;
 
   eh = (struct elf32_arm_link_hash_entry *) h;
 
@@ -8191,7 +9617,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 (!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;
@@ -8340,7 +9770,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
       bh = NULL;
       /* Create a new symbol to regist the real location of the function.  */
       s = h->root.u.def.section;
-      sprintf(name, "__real_%s", h->root.root.string);
+      sprintf (name, "__real_%s", h->root.root.string);
       _bfd_generic_link_add_one_symbol (info, s->owner,
                                        name, BSF_GLOBAL, s,
                                        h->root.u.def.value,
@@ -8389,6 +9819,19 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
            }
        }
 
+      if (elf32_arm_hash_table (info)->vxworks_p)
+       {
+         struct elf32_arm_relocs_copied **pp;
+
+         for (pp = &eh->relocs_copied; (p = *pp) != NULL; )
+           {
+             if (strcmp (p->section->output_section->name, ".tls_vars") == 0)
+               *pp = p->next;
+             else
+               pp = &p->next;
+           }
+       }
+
       /* Also discard relocs on undefined weak syms with non-default
          visibility.  */
       if (eh->relocs_copied != NULL
@@ -8540,8 +9983,9 @@ elf32_arm_size_dynamic_sections (bfd * output_bfd ATTRIBUTE_UNUSED,
       bfd_size_type locsymcount;
       Elf_Internal_Shdr *symtab_hdr;
       asection *srel;
+      bfd_boolean is_vxworks = elf32_arm_hash_table (info)->vxworks_p;
 
-      if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour)
+      if (! is_arm_elf (ibfd))
        continue;
 
       for (s = ibfd->sections; s != NULL; s = s->next)
@@ -8558,6 +10002,13 @@ elf32_arm_size_dynamic_sections (bfd * output_bfd ATTRIBUTE_UNUSED,
                     linker script /DISCARD/, so we'll be discarding
                     the relocs too.  */
                }
+             else if (is_vxworks
+                      && strcmp (p->section->output_section->name,
+                                 ".tls_vars") == 0)
+               {
+                 /* Relocations in vxworks .tls_vars sections are
+                    handled specially by the loader.  */
+               }
              else if (p->count != 0)
                {
                  srel = elf_section_data (p->section)->sreloc;
@@ -8572,7 +10023,7 @@ elf32_arm_size_dynamic_sections (bfd * output_bfd ATTRIBUTE_UNUSED,
       if (!local_got)
        continue;
 
-      symtab_hdr = &elf_tdata (ibfd)->symtab_hdr;
+      symtab_hdr = & elf_symtab_hdr (ibfd);
       locsymcount = symtab_hdr->sh_info;
       end_local_got = local_got + locsymcount;
       local_tls_type = elf32_arm_local_got_tls_type (ibfd);
@@ -8618,9 +10069,12 @@ elf32_arm_size_dynamic_sections (bfd * output_bfd ATTRIBUTE_UNUSED,
   /* Here we rummage through the found bfds to collect glue information.  */
   for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
     {
+      if (! is_arm_elf (ibfd))
+       continue;
+
       /* Initialise mapping tables for code/data.  */
       bfd_elf32_arm_init_maps (ibfd);
-      
+
       if (!bfd_elf32_arm_process_before_allocation (ibfd, info)
          || !bfd_elf32_arm_vfp11_erratum_scan (ibfd, info))
         /* xgettext:c-format */
@@ -8689,7 +10143,7 @@ elf32_arm_size_dynamic_sections (bfd * output_bfd ATTRIBUTE_UNUSED,
        continue;
 
       /* Allocate memory for the section contents.  */
-      s->contents = (bfd_byte *) bfd_zalloc (dynobj, s->size);
+      s->contents = bfd_zalloc (dynobj, s->size);
       if (s->contents == NULL)
        return FALSE;
     }
@@ -8749,6 +10203,9 @@ elf32_arm_size_dynamic_sections (bfd * output_bfd ATTRIBUTE_UNUSED,
          if (!add_dynamic_entry (DT_TEXTREL, 0))
            return FALSE;
        }
+      if (htab->vxworks_p
+         && !elf_vxworks_add_dynamic_entries (output_bfd, info))
+       return FALSE;
     }
 #undef add_dynamic_entry
 
@@ -8759,8 +10216,10 @@ elf32_arm_size_dynamic_sections (bfd * output_bfd ATTRIBUTE_UNUSED,
    dynamic sections here.  */
 
 static bfd_boolean
-elf32_arm_finish_dynamic_symbol (bfd * output_bfd, struct bfd_link_info * info,
-                                struct elf_link_hash_entry * h, Elf_Internal_Sym * sym)
+elf32_arm_finish_dynamic_symbol (bfd * output_bfd,
+                                struct bfd_link_info * info,
+                                struct elf_link_hash_entry * h,
+                                Elf_Internal_Sym * sym)
 {
   bfd * dynobj;
   struct elf32_arm_link_hash_table *htab;
@@ -8790,13 +10249,13 @@ elf32_arm_finish_dynamic_symbol (bfd * output_bfd, struct bfd_link_info * info,
       /* Fill in the entry in the procedure linkage table.  */
       if (htab->symbian_p)
        {
-         put_arm_insn (htab, output_bfd, 
+         put_arm_insn (htab, output_bfd,
                      elf32_arm_symbian_plt_entry[0],
                      splt->contents + h->plt.offset);
-         bfd_put_32 (output_bfd, 
+         bfd_put_32 (output_bfd,
                      elf32_arm_symbian_plt_entry[1],
                      splt->contents + h->plt.offset + 4);
-         
+
          /* Fill in the entry in the .rel.plt section.  */
          rel.r_offset = (splt->output_section->vma
                          + splt->output_offset
@@ -8807,7 +10266,7 @@ elf32_arm_finish_dynamic_symbol (bfd * output_bfd, struct bfd_link_info * info,
             corresponds to this symbol.  This is the index of this symbol
             in all the symbols for which we are making plt entries.  The
             first entry in the procedure linkage table is reserved.  */
-         plt_index = ((h->plt.offset - htab->plt_header_size) 
+         plt_index = ((h->plt.offset - htab->plt_header_size)
                       / htab->plt_entry_size);
        }
       else
@@ -8816,7 +10275,7 @@ elf32_arm_finish_dynamic_symbol (bfd * output_bfd, struct bfd_link_info * info,
          bfd_vma got_displacement;
          asection * sgot;
          bfd_byte * ptr;
-         
+
          sgot = bfd_get_section_by_name (dynobj, ".got.plt");
          BFD_ASSERT (sgot != NULL);
 
@@ -8900,6 +10359,7 @@ elf32_arm_finish_dynamic_symbol (bfd * output_bfd, struct bfd_link_info * info,
            }
          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
@@ -8908,7 +10368,11 @@ elf32_arm_finish_dynamic_symbol (bfd * output_bfd, struct bfd_link_info * info,
 
              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);
@@ -8938,7 +10402,7 @@ elf32_arm_finish_dynamic_symbol (bfd * output_bfd, struct bfd_link_info * info,
                      (splt->output_section->vma
                       + splt->output_offset),
                      sgot->contents + got_offset);
-         
+
          /* Fill in the entry in the .rel(a).plt section.  */
          rel.r_addend = 0;
          rel.r_offset = got_address;
@@ -8992,7 +10456,7 @@ elf32_arm_finish_dynamic_symbol (bfd * output_bfd, struct bfd_link_info * info,
       if (info->shared
          && SYMBOL_REFERENCES_LOCAL (info, h))
        {
-         BFD_ASSERT((h->got.offset & 1) != 0);
+         BFD_ASSERT ((h->got.offset & 1) != 0);
          rel.r_info = ELF32_R_INFO (0, R_ARM_RELATIVE);
          if (!htab->use_rel)
            {
@@ -9002,7 +10466,7 @@ elf32_arm_finish_dynamic_symbol (bfd * output_bfd, struct bfd_link_info * info,
        }
       else
        {
-         BFD_ASSERT((h->got.offset & 1) == 0);
+         BFD_ASSERT ((h->got.offset & 1) == 0);
          bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents + offset);
          rel.r_info = ELF32_R_INFO (h->dynindx, R_ARM_GLOB_DAT);
        }
@@ -9086,6 +10550,9 @@ elf32_arm_finish_dynamic_sections (bfd * output_bfd, struct bfd_link_info * info
              unsigned int type;
 
            default:
+             if (htab->vxworks_p
+                 && elf_vxworks_finish_dynamic_entry (output_bfd, &dyn))
+               bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon);
              break;
 
            case DT_HASH:
@@ -9137,7 +10604,7 @@ elf32_arm_finish_dynamic_sections (bfd * output_bfd, struct bfd_link_info * info
              dyn.d_un.d_val = s->size;
              bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon);
              break;
-             
+
            case DT_RELSZ:
            case DT_RELASZ:
              if (!htab->symbian_p)
@@ -9178,11 +10645,11 @@ elf32_arm_finish_dynamic_sections (bfd * output_bfd, struct bfd_link_info * info
                  dyn.d_un.d_val = 0;
                  for (i = 1; i < elf_numsections (output_bfd); i++)
                    {
-                     Elf_Internal_Shdr *hdr 
+                     Elf_Internal_Shdr *hdr
                        = elf_elfsections (output_bfd)[i];
                      if (hdr->sh_type == type)
                        {
-                         if (dyn.d_tag == DT_RELSZ 
+                         if (dyn.d_tag == DT_RELSZ
                              || dyn.d_tag == DT_RELASZ)
                            dyn.d_un.d_val += hdr->sh_size;
                          else if ((ufile_ptr) hdr->sh_offset
@@ -9210,7 +10677,7 @@ elf32_arm_finish_dynamic_sections (bfd * output_bfd, struct bfd_link_info * info
 
                  eh = elf_link_hash_lookup (elf_hash_table (info), name,
                                             FALSE, FALSE, TRUE);
-                 if (eh != (struct elf_link_hash_entry *) NULL
+                 if (eh != NULL
                      && ELF_ST_TYPE (eh->type) == STT_ARM_TFUNC)
                    {
                      dyn.d_un.d_val |= 1;
@@ -9638,10 +11105,13 @@ elf32_arm_output_plt_map (struct elf_link_hash_entry *h, void *inf)
     }
   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;
@@ -9652,10 +11122,10 @@ elf32_arm_output_plt_map (struct elf_link_hash_entry *h, void *inf)
       if (!elf32_arm_ouput_plt_map_sym (osi, ARM_MAP_DATA, addr + 12))
        return FALSE;
 #else
-      /* A three-word PLT with no Thumb thunk contains only Arm code, 
+      /* 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;
@@ -9671,11 +11141,12 @@ elf32_arm_output_plt_map (struct elf_link_hash_entry *h, void *inf)
 
 static bfd_boolean
 elf32_arm_output_arch_local_syms (bfd *output_bfd,
-    struct bfd_link_info *info,
-    void *finfo, bfd_boolean (*func) (void *, const char *,
-                                   Elf_Internal_Sym *,
-                                   asection *,
-                                   struct elf_link_hash_entry *))
+                                 struct bfd_link_info *info,
+                                 void *finfo,
+                                 bfd_boolean (*func) (void *, const char *,
+                                                      Elf_Internal_Sym *,
+                                                      asection *,
+                                                      struct elf_link_hash_entry *))
 {
   output_arch_syminfo osi;
   struct elf32_arm_link_hash_table *htab;
@@ -9683,12 +11154,12 @@ elf32_arm_output_arch_local_syms (bfd *output_bfd,
   bfd_size_type size;
 
   htab = elf32_arm_hash_table (info);
-  check_use_blx(htab);
+  check_use_blx (htab);
 
   osi.finfo = finfo;
   osi.info = info;
   osi.func = func;
-  
+
   /* ARM->Thumb glue.  */
   if (htab->arm_glue_size > 0)
     {
@@ -9729,6 +11200,18 @@ elf32_arm_output_arch_local_syms (bfd *output_bfd,
        }
     }
 
+  /* ARMv4 BX veneers.  */
+  if (htab->bx_glue_size > 0)
+    {
+      osi.sec = bfd_get_section_by_name (htab->bfd_of_glue_owner,
+                                        ARM_BX_GLUE_SECTION_NAME);
+
+      osi.sec_shndx = _bfd_elf_section_from_bfd_section
+         (output_bfd, osi.sec->output_section);
+
+      elf32_arm_ouput_plt_map_sym (&osi, ARM_MAP_ARM, 0);
+    }
+
   /* Finally, output mapping symbols for the PLT.  */
   if (!htab->splt || htab->splt->size == 0)
     return TRUE;
@@ -9790,8 +11273,22 @@ elf32_arm_new_section_hook (bfd *abfd, asection *sec)
 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;
 }
 
 
@@ -10054,7 +11551,7 @@ elf32_arm_swap_symbol_out (bfd *abfd,
           */
           newsym.st_value |= 1;
         }
-      
+
       src = &newsym;
     }
   bfd_elf32_swap_symbol_out (abfd, src, cdst, shndx);
@@ -10063,7 +11560,7 @@ elf32_arm_swap_symbol_out (bfd *abfd,
 /* Add the PT_ARM_EXIDX program header.  */
 
 static bfd_boolean
-elf32_arm_modify_segment_map (bfd *abfd, 
+elf32_arm_modify_segment_map (bfd *abfd,
                              struct bfd_link_info *info ATTRIBUTE_UNUSED)
 {
   struct elf_segment_map *m;
@@ -10111,6 +11608,7 @@ elf32_arm_additional_program_headers (bfd *abfd,
 }
 
 /* We have two function types: STT_FUNC and STT_ARM_TFUNC.  */
+
 static bfd_boolean
 elf32_arm_is_function_type (unsigned int type)
 {
@@ -10118,7 +11616,8 @@ elf32_arm_is_function_type (unsigned int type)
 }
 
 /* We use this to override swap_symbol_in and swap_symbol_out.  */
-const struct elf_size_info elf32_arm_size_info = {
+const struct elf_size_info elf32_arm_size_info =
+{
   sizeof (Elf32_External_Ehdr),
   sizeof (Elf32_External_Phdr),
   sizeof (Elf32_External_Shdr),
@@ -10164,6 +11663,7 @@ const struct elf_size_info elf32_arm_size_info = {
 #define bfd_elf32_bfd_set_private_flags                elf32_arm_set_private_flags
 #define bfd_elf32_bfd_print_private_bfd_data   elf32_arm_print_private_bfd_data
 #define bfd_elf32_bfd_link_hash_table_create    elf32_arm_link_hash_table_create
+#define bfd_elf32_bfd_link_hash_table_free      elf32_arm_hash_table_free
 #define bfd_elf32_bfd_reloc_type_lookup                elf32_arm_reloc_type_lookup
 #define bfd_elf32_bfd_reloc_name_lookup        elf32_arm_reloc_name_lookup
 #define bfd_elf32_find_nearest_line            elf32_arm_find_nearest_line
@@ -10197,49 +11697,47 @@ const struct elf_size_info elf32_arm_size_info = {
 #define elf_backend_symbol_processing          elf32_arm_symbol_processing
 #define elf_backend_size_info                  elf32_arm_size_info
 #define elf_backend_modify_segment_map         elf32_arm_modify_segment_map
-#define elf_backend_additional_program_headers \
-  elf32_arm_additional_program_headers
-#define elf_backend_output_arch_local_syms \
-  elf32_arm_output_arch_local_syms
-#define elf_backend_begin_write_processing \
-    elf32_arm_begin_write_processing
-#define elf_backend_is_function_type           elf32_arm_is_function_type 
-
-#define elf_backend_can_refcount    1
-#define elf_backend_can_gc_sections 1
-#define elf_backend_plt_readonly    1
-#define elf_backend_want_got_plt    1
-#define elf_backend_want_plt_sym    0
-#define elf_backend_may_use_rel_p   1
-#define elf_backend_may_use_rela_p  0
+#define elf_backend_additional_program_headers  elf32_arm_additional_program_headers
+#define elf_backend_output_arch_local_syms      elf32_arm_output_arch_local_syms
+#define elf_backend_begin_write_processing      elf32_arm_begin_write_processing
+#define elf_backend_is_function_type           elf32_arm_is_function_type
+
+#define elf_backend_can_refcount       1
+#define elf_backend_can_gc_sections    1
+#define elf_backend_plt_readonly       1
+#define elf_backend_want_got_plt       1
+#define elf_backend_want_plt_sym       0
+#define elf_backend_may_use_rel_p      1
+#define elf_backend_may_use_rela_p     0
 #define elf_backend_default_use_rela_p 0
 
 #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
+#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 */
+/* VxWorks Targets */
 
-#undef TARGET_LITTLE_SYM
+#undef  TARGET_LITTLE_SYM
 #define TARGET_LITTLE_SYM               bfd_elf32_littlearm_vxworks_vec
-#undef TARGET_LITTLE_NAME
+#undef  TARGET_LITTLE_NAME
 #define TARGET_LITTLE_NAME              "elf32-littlearm-vxworks"
-#undef TARGET_BIG_SYM
+#undef  TARGET_BIG_SYM
 #define TARGET_BIG_SYM                  bfd_elf32_bigarm_vxworks_vec
-#undef TARGET_BIG_NAME
+#undef  TARGET_BIG_NAME
 #define TARGET_BIG_NAME                 "elf32-bigarm-vxworks"
 
 /* Like elf32_arm_link_hash_table_create -- but overrides
    appropriately for VxWorks.  */
+
 static struct bfd_link_hash_table *
 elf32_arm_vxworks_link_hash_table_create (bfd *abfd)
 {
@@ -10254,7 +11752,7 @@ elf32_arm_vxworks_link_hash_table_create (bfd *abfd)
       htab->vxworks_p = 1;
     }
   return ret;
-}     
+}
 
 static void
 elf32_arm_vxworks_final_write_processing (bfd *abfd, bfd_boolean linker)
@@ -10263,49 +11761,46 @@ elf32_arm_vxworks_final_write_processing (bfd *abfd, bfd_boolean linker)
   elf_vxworks_final_write_processing (abfd, linker);
 }
 
-#undef elf32_bed
+#undef  elf32_bed
 #define elf32_bed elf32_arm_vxworks_bed
 
-#undef bfd_elf32_bfd_link_hash_table_create
-#define bfd_elf32_bfd_link_hash_table_create \
-  elf32_arm_vxworks_link_hash_table_create
-#undef elf_backend_add_symbol_hook
-#define elf_backend_add_symbol_hook \
-  elf_vxworks_add_symbol_hook
-#undef elf_backend_final_write_processing
-#define elf_backend_final_write_processing \
-  elf32_arm_vxworks_final_write_processing
-#undef elf_backend_emit_relocs
-#define elf_backend_emit_relocs \
-  elf_vxworks_emit_relocs
+#undef  bfd_elf32_bfd_link_hash_table_create
+#define bfd_elf32_bfd_link_hash_table_create   elf32_arm_vxworks_link_hash_table_create
+#undef  elf_backend_add_symbol_hook
+#define elf_backend_add_symbol_hook            elf_vxworks_add_symbol_hook
+#undef  elf_backend_final_write_processing
+#define elf_backend_final_write_processing     elf32_arm_vxworks_final_write_processing
+#undef  elf_backend_emit_relocs
+#define elf_backend_emit_relocs                        elf_vxworks_emit_relocs
 
-#undef elf_backend_may_use_rel_p
+#undef  elf_backend_may_use_rel_p
 #define elf_backend_may_use_rel_p      0
-#undef elf_backend_may_use_rela_p
+#undef  elf_backend_may_use_rela_p
 #define elf_backend_may_use_rela_p     1
-#undef elf_backend_default_use_rela_p
+#undef  elf_backend_default_use_rela_p
 #define elf_backend_default_use_rela_p 1
-#undef elf_backend_want_plt_sym
+#undef  elf_backend_want_plt_sym
 #define elf_backend_want_plt_sym       1
-#undef ELF_MAXPAGESIZE
+#undef  ELF_MAXPAGESIZE
 #define ELF_MAXPAGESIZE                        0x1000
 
 #include "elf32-target.h"
 
 
-/* Symbian OS Targets */
+/* Symbian OS Targets */
 
-#undef TARGET_LITTLE_SYM
+#undef  TARGET_LITTLE_SYM
 #define TARGET_LITTLE_SYM               bfd_elf32_littlearm_symbian_vec
-#undef TARGET_LITTLE_NAME
+#undef  TARGET_LITTLE_NAME
 #define TARGET_LITTLE_NAME              "elf32-littlearm-symbian"
-#undef TARGET_BIG_SYM
+#undef  TARGET_BIG_SYM
 #define TARGET_BIG_SYM                  bfd_elf32_bigarm_symbian_vec
-#undef TARGET_BIG_NAME
+#undef  TARGET_BIG_NAME
 #define TARGET_BIG_NAME                 "elf32-bigarm-symbian"
 
 /* Like elf32_arm_link_hash_table_create -- but overrides
    appropriately for Symbian OS.  */
+
 static struct bfd_link_hash_table *
 elf32_arm_symbian_link_hash_table_create (bfd *abfd)
 {
@@ -10318,15 +11813,15 @@ elf32_arm_symbian_link_hash_table_create (bfd *abfd)
        = (struct elf32_arm_link_hash_table *)ret;
       /* There is no PLT header for Symbian OS.  */
       htab->plt_header_size = 0;
-      /* The PLT entries are each three instructions.  */
-      htab->plt_entry_size = 4 * NUM_ELEM (elf32_arm_symbian_plt_entry);
+      /* The PLT entries are each one instruction and one word.  */
+      htab->plt_entry_size = 4 * ARRAY_SIZE (elf32_arm_symbian_plt_entry);
       htab->symbian_p = 1;
       /* Symbian uses armv5t or above, so use_blx is always true.  */
       htab->use_blx = 1;
       htab->root.is_relocatable_executable = 1;
     }
   return ret;
-}     
+}
 
 static const struct bfd_elf_special_section
 elf32_arm_symbian_special_sections[] =
@@ -10350,7 +11845,7 @@ elf32_arm_symbian_special_sections[] =
 };
 
 static void
-elf32_arm_symbian_begin_write_processing (bfd *abfd, 
+elf32_arm_symbian_begin_write_processing (bfd *abfd,
                                          struct bfd_link_info *link_info)
 {
   /* BPABI objects are never loaded directly by an OS kernel; they are
@@ -10362,11 +11857,11 @@ elf32_arm_symbian_begin_write_processing (bfd *abfd,
      recognize that the program headers should not be mapped into any
      loadable segment.  */
   abfd->flags &= ~D_PAGED;
-  elf32_arm_begin_write_processing(abfd, link_info);
+  elf32_arm_begin_write_processing (abfd, link_info);
 }
 
 static bfd_boolean
-elf32_arm_symbian_modify_segment_map (bfd *abfd, 
+elf32_arm_symbian_modify_segment_map (bfd *abfd,
                                      struct bfd_link_info *info)
 {
   struct elf_segment_map *m;
@@ -10395,51 +11890,61 @@ elf32_arm_symbian_modify_segment_map (bfd *abfd,
   return elf32_arm_modify_segment_map (abfd, info);
 }
 
+/* Return address for Ith PLT stub in section PLT, for relocation REL
+   or (bfd_vma) -1 if it should not be included.  */
+
+static bfd_vma
+elf32_arm_symbian_plt_sym_val (bfd_vma i, const asection *plt,
+                              const arelent *rel ATTRIBUTE_UNUSED)
+{
+  return plt->vma + 4 * ARRAY_SIZE (elf32_arm_symbian_plt_entry) * i;
+}
+
+
 #undef elf32_bed
 #define elf32_bed elf32_arm_symbian_bed
 
 /* The dynamic sections are not allocated on SymbianOS; the postlinker
    will process them and then discard them.  */
-#undef ELF_DYNAMIC_SEC_FLAGS
+#undef  ELF_DYNAMIC_SEC_FLAGS
 #define ELF_DYNAMIC_SEC_FLAGS \
   (SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED)
 
-#undef bfd_elf32_bfd_link_hash_table_create
-#define bfd_elf32_bfd_link_hash_table_create \
-  elf32_arm_symbian_link_hash_table_create
 #undef elf_backend_add_symbol_hook
-
-#undef elf_backend_special_sections
-#define elf_backend_special_sections elf32_arm_symbian_special_sections
-
-#undef elf_backend_begin_write_processing
-#define elf_backend_begin_write_processing \
-    elf32_arm_symbian_begin_write_processing
-#undef elf_backend_final_write_processing
-#define elf_backend_final_write_processing \
-  elf32_arm_final_write_processing
 #undef elf_backend_emit_relocs
 
-#undef elf_backend_modify_segment_map
+#undef  bfd_elf32_bfd_link_hash_table_create
+#define bfd_elf32_bfd_link_hash_table_create   elf32_arm_symbian_link_hash_table_create
+#undef  elf_backend_special_sections
+#define elf_backend_special_sections           elf32_arm_symbian_special_sections
+#undef  elf_backend_begin_write_processing
+#define elf_backend_begin_write_processing     elf32_arm_symbian_begin_write_processing
+#undef  elf_backend_final_write_processing
+#define elf_backend_final_write_processing     elf32_arm_final_write_processing
+
+#undef  elf_backend_modify_segment_map
 #define elf_backend_modify_segment_map elf32_arm_symbian_modify_segment_map
 
 /* There is no .got section for BPABI objects, and hence no header.  */
-#undef elf_backend_got_header_size
+#undef  elf_backend_got_header_size
 #define elf_backend_got_header_size 0
 
 /* Similarly, there is no .got.plt section.  */
-#undef elf_backend_want_got_plt
+#undef  elf_backend_want_got_plt
 #define elf_backend_want_got_plt 0
 
-#undef elf_backend_may_use_rel_p
+#undef  elf_backend_plt_sym_val
+#define elf_backend_plt_sym_val                elf32_arm_symbian_plt_sym_val
+
+#undef  elf_backend_may_use_rel_p
 #define elf_backend_may_use_rel_p      1
-#undef elf_backend_may_use_rela_p
+#undef  elf_backend_may_use_rela_p
 #define elf_backend_may_use_rela_p     0
-#undef elf_backend_default_use_rela_p
+#undef  elf_backend_default_use_rela_p
 #define elf_backend_default_use_rela_p 0
-#undef elf_backend_want_plt_sym
+#undef  elf_backend_want_plt_sym
 #define elf_backend_want_plt_sym       0
-#undef ELF_MAXPAGESIZE
+#undef  ELF_MAXPAGESIZE
 #define ELF_MAXPAGESIZE                        0x8000
 
 #include "elf32-target.h"
This page took 0.086751 seconds and 4 git commands to generate.