Allow stubs without associated input section in ARM backend
[binutils-gdb.git] / bfd / elf32-arm.c
index 583db4d3573db14039f907251bcdd078e292531f..e1ee67315f84f59ea11d62015e8ffa0e0530ebcf 100644 (file)
@@ -1,5 +1,5 @@
 /* 32-bit ELF support for ARM
-   Copyright (C) 1998-2015 Free Software Foundation, Inc.
+   Copyright (C) 1998-2016 Free Software Foundation, Inc.
 
    This file is part of BFD, the Binary File Descriptor library.
 
@@ -2632,11 +2632,12 @@ enum elf32_arm_stub_type
 {
   arm_stub_none,
   DEF_STUBS
-  /* Note the first a8_veneer type.  */
-  arm_stub_a8_veneer_lwm = arm_stub_a8_veneer_b_cond
 };
 #undef DEF_STUB
 
+/* Note the first a8_veneer type.  */
+const unsigned arm_stub_a8_veneer_lwm = arm_stub_a8_veneer_b_cond;
+
 typedef struct
 {
   const insn_sequence* template_sequence;
@@ -2666,8 +2667,12 @@ struct elf32_arm_stub_hash_entry
   bfd_vma target_value;
   asection *target_section;
 
-  /* Offset to apply to relocation referencing target_value.  */
-  bfd_vma target_addend;
+  /* Same as above but for the source of the branch to the stub.  Used for
+     Cortex-A8 erratum workaround to patch it to branch to the stub.  As
+     such, source section does not need to be recorded since Cortex-A8 erratum
+     workaround stubs are only generated when both source and target are in the
+     same section.  */
+  bfd_vma source_value;
 
   /* The instruction which caused this stub to be generated (only valid for
      Cortex-A8 erratum workaround stubs at present).  */
@@ -2836,7 +2841,7 @@ struct a8_erratum_fix
   bfd *input_bfd;
   asection *section;
   bfd_vma offset;
-  bfd_vma addend;
+  bfd_vma target_offset;
   unsigned long orig_insn;
   char *stub_name;
   enum elf32_arm_stub_type stub_type;
@@ -3158,7 +3163,8 @@ struct elf32_arm_link_hash_table
   bfd *stub_bfd;
 
   /* Linker call-backs.  */
-  asection * (*add_stub_section) (const char *, asection *, unsigned int);
+  asection * (*add_stub_section) (const char *, asection *, asection *,
+                                 unsigned int);
   void (*layout_sections_again) (void);
 
   /* Array to keep track of which stub sections have been created, and
@@ -3413,9 +3419,9 @@ stub_hash_newfunc (struct bfd_hash_entry *entry,
       eh = (struct elf32_arm_stub_hash_entry *) entry;
       eh->stub_sec = NULL;
       eh->stub_offset = 0;
+      eh->source_value = 0;
       eh->target_value = 0;
       eh->target_section = NULL;
-      eh->target_addend = 0;
       eh->orig_insn = 0;
       eh->stub_type = arm_stub_none;
       eh->stub_size = 0;
@@ -3504,20 +3510,23 @@ create_ifunc_sections (struct bfd_link_info *info)
 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;
+  int arch;
+  int profile = bfd_elf_get_obj_attr_int (globals->obfd, OBJ_ATTR_PROC,
+                                         Tag_CPU_arch_profile);
 
-  if (arch == TAG_CPU_ARCH_V6_M || arch == TAG_CPU_ARCH_V6S_M)
-    return TRUE;
+  if (profile)
+    return profile == 'M';
 
-  if (arch != TAG_CPU_ARCH_V7 && arch != TAG_CPU_ARCH_V7E_M)
-    return FALSE;
+  arch = bfd_elf_get_obj_attr_int (globals->obfd, OBJ_ATTR_PROC, Tag_CPU_arch);
 
-  profile = bfd_elf_get_obj_attr_int (globals->obfd, OBJ_ATTR_PROC,
-                                     Tag_CPU_arch_profile);
+  if (arch == TAG_CPU_ARCH_V6_M
+      || arch == TAG_CPU_ARCH_V6S_M
+      || arch == TAG_CPU_ARCH_V7E_M
+      || arch == TAG_CPU_ARCH_V8M_BASE
+      || arch == TAG_CPU_ARCH_V8M_MAIN)
+    return TRUE;
 
-  return profile == 'M';
+  return FALSE;
 }
 
 /* Determine if we're dealing with a Thumb-2 object.  */
@@ -3572,6 +3581,9 @@ elf32_arm_create_dynamic_sections (bfd *dynobj, struct bfd_link_info *info)
          htab->plt_entry_size
            = 4 * ARRAY_SIZE (elf32_arm_vxworks_exec_plt_entry);
        }
+
+      if (elf_elfheader (dynobj))
+       elf_elfheader (dynobj)->e_ident[EI_CLASS] = ELFCLASS32;
     }
   else
     {
@@ -4133,6 +4145,7 @@ elf32_arm_create_or_find_stub_sec (asection **link_sec_p, asection *section,
 {
   asection *link_sec;
   asection *stub_sec;
+  asection *out_sec;
 
   link_sec = htab->stub_group[section->id].link_sec;
   BFD_ASSERT (link_sec != NULL);
@@ -4155,7 +4168,8 @@ elf32_arm_create_or_find_stub_sec (asection **link_sec_p, asection *section,
 
          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,
+         out_sec = link_sec->output_section;
+         stub_sec = (*htab->add_stub_section) (s_name, out_sec, link_sec,
                                                htab->nacl_p ? 4 : 3);
          if (stub_sec == NULL)
            return NULL;
@@ -4191,6 +4205,8 @@ elf32_arm_add_stub (const char *stub_name,
                                     TRUE, FALSE);
   if (stub_entry == NULL)
     {
+      if (section == NULL)
+       section = stub_sec;
       (*_bfd_error_handler) (_("%s: cannot create stub entry %s"),
                             section->owner,
                             stub_name);
@@ -4235,7 +4251,7 @@ put_thumb_insn (struct elf32_arm_link_hash_table * htab,
 
 static void
 put_thumb2_insn (struct elf32_arm_link_hash_table * htab,
-                bfd * output_bfd, bfd_vma val, void * ptr)
+                bfd * output_bfd, bfd_vma val, bfd_byte * ptr)
 {
   /* T2 instructions are 16-bit streamed.  */
   if (htab->byteswap_code != bfd_little_endian (output_bfd))
@@ -4444,65 +4460,36 @@ arm_build_one_stub (struct bfd_hash_entry *gen_entry,
   BFD_ASSERT (nrelocs != 0 && nrelocs <= MAXRELOCS);
 
   for (i = 0; i < nrelocs; i++)
-    if (template_sequence[stub_reloc_idx[i]].r_type == R_ARM_THM_JUMP24
-       || template_sequence[stub_reloc_idx[i]].r_type == R_ARM_THM_JUMP19
-       || template_sequence[stub_reloc_idx[i]].r_type == R_ARM_THM_CALL
-       || template_sequence[stub_reloc_idx[i]].r_type == R_ARM_THM_XPC22)
-      {
-       Elf_Internal_Rela rel;
-       bfd_boolean unresolved_reloc;
-       char *error_message;
-       enum arm_st_branch_type branch_type
-         = (template_sequence[stub_reloc_idx[i]].r_type != R_ARM_THM_XPC22
-            ? ST_BRANCH_TO_THUMB : ST_BRANCH_TO_ARM);
-       bfd_vma points_to = sym_value + stub_entry->target_addend;
-
-       rel.r_offset = stub_entry->stub_offset + stub_reloc_offset[i];
-       rel.r_info = ELF32_R_INFO (0,
-                                  template_sequence[stub_reloc_idx[i]].r_type);
-       rel.r_addend = template_sequence[stub_reloc_idx[i]].reloc_addend;
-
-       if (stub_entry->stub_type == arm_stub_a8_veneer_b_cond && i == 0)
-         /* The first relocation in the elf32_arm_stub_a8_veneer_b_cond[]
-            template should refer back to the instruction after the original
-            branch.  */
-         points_to = sym_value;
-
-       /* There may be unintended consequences if this is not true.  */
-       BFD_ASSERT (stub_entry->h == NULL);
-
-       /* Note: _bfd_final_link_relocate doesn't handle these relocations
-          properly.  We should probably use this function unconditionally,
-          rather than only for certain relocations listed in the enclosing
-          conditional, for the sake of consistency.  */
-       elf32_arm_final_link_relocate (elf32_arm_howto_from_type
-           (template_sequence[stub_reloc_idx[i]].r_type),
-         stub_bfd, info->output_bfd, stub_sec, stub_sec->contents, &rel,
-         points_to, info, stub_entry->target_section, "", STT_FUNC,
-         branch_type, (struct elf_link_hash_entry *) stub_entry->h,
-         &unresolved_reloc, &error_message);
-      }
-    else
-      {
-       Elf_Internal_Rela rel;
-       bfd_boolean unresolved_reloc;
-       char *error_message;
-       bfd_vma points_to = sym_value + stub_entry->target_addend
-         + template_sequence[stub_reloc_idx[i]].reloc_addend;
-
-       rel.r_offset = stub_entry->stub_offset + stub_reloc_offset[i];
-       rel.r_info = ELF32_R_INFO (0,
-                                  template_sequence[stub_reloc_idx[i]].r_type);
-       rel.r_addend = 0;
-
-       elf32_arm_final_link_relocate (elf32_arm_howto_from_type
-           (template_sequence[stub_reloc_idx[i]].r_type),
-         stub_bfd, info->output_bfd, stub_sec, stub_sec->contents, &rel,
-         points_to, info, stub_entry->target_section, "", STT_FUNC,
-         stub_entry->branch_type,
-         (struct elf_link_hash_entry *) stub_entry->h, &unresolved_reloc,
-         &error_message);
-      }
+    {
+      Elf_Internal_Rela rel;
+      bfd_boolean unresolved_reloc;
+      char *error_message;
+      bfd_vma points_to =
+       sym_value + template_sequence[stub_reloc_idx[i]].reloc_addend;
+
+      rel.r_offset = stub_entry->stub_offset + stub_reloc_offset[i];
+      rel.r_info = ELF32_R_INFO (0,
+                                template_sequence[stub_reloc_idx[i]].r_type);
+      rel.r_addend = 0;
+
+      if (stub_entry->stub_type == arm_stub_a8_veneer_b_cond && i == 0)
+       /* The first relocation in the elf32_arm_stub_a8_veneer_b_cond[]
+          template should refer back to the instruction after the original
+          branch.  We use target_section as Cortex-A8 erratum workaround stubs
+          are only generated when both source and target are in the same
+          section.  */
+       points_to = stub_entry->target_section->output_section->vma
+                   + stub_entry->target_section->output_offset
+                   + stub_entry->source_value;
+
+      elf32_arm_final_link_relocate (elf32_arm_howto_from_type
+         (template_sequence[stub_reloc_idx[i]].r_type),
+          stub_bfd, info->output_bfd, stub_sec, stub_sec->contents, &rel,
+          points_to, info, stub_entry->target_section, "", STT_FUNC,
+          stub_entry->branch_type,
+          (struct elf_link_hash_entry *) stub_entry->h, &unresolved_reloc,
+          &error_message);
+    }
 
   return TRUE;
 #undef MAXRELOCS
@@ -5095,7 +5082,8 @@ cortex_a8_erratum_scan (bfd *input_bfd,
                          a8_fixes[num_a8_fixes].input_bfd = input_bfd;
                          a8_fixes[num_a8_fixes].section = section;
                          a8_fixes[num_a8_fixes].offset = i;
-                         a8_fixes[num_a8_fixes].addend = offset;
+                         a8_fixes[num_a8_fixes].target_offset =
+                           target - base_vma;
                          a8_fixes[num_a8_fixes].orig_insn = insn;
                          a8_fixes[num_a8_fixes].stub_name = stub_name;
                          a8_fixes[num_a8_fixes].stub_type = stub_type;
@@ -5124,6 +5112,103 @@ cortex_a8_erratum_scan (bfd *input_bfd,
   return FALSE;
 }
 
+/* Create or update a stub entry depending on whether the stub can already be
+   found in HTAB.  The stub is identified by:
+   - its type STUB_TYPE
+   - its source branch (note that several can share the same stub) whose
+     section and relocation (if any) are given by SECTION and IRELA
+     respectively
+   - its target symbol whose input section, hash, name, value and branch type
+     are given in SYM_SEC, HASH, SYM_NAME, SYM_VALUE and BRANCH_TYPE
+     respectively
+
+   If found, the value of the stub's target symbol is updated from SYM_VALUE
+   and *NEW_STUB is set to FALSE.  Otherwise, *NEW_STUB is set to
+   TRUE and the stub entry is initialized.
+
+   Returns whether the stub could be successfully created or updated, or FALSE
+   if an error occured.  */
+
+static bfd_boolean
+elf32_arm_create_stub (struct elf32_arm_link_hash_table *htab,
+                      enum elf32_arm_stub_type stub_type, asection *section,
+                      Elf_Internal_Rela *irela, asection *sym_sec,
+                      struct elf32_arm_link_hash_entry *hash, char *sym_name,
+                      bfd_vma sym_value, enum arm_st_branch_type branch_type,
+                      bfd_boolean *new_stub)
+{
+  const asection *id_sec;
+  char *stub_name;
+  struct elf32_arm_stub_hash_entry *stub_entry;
+  unsigned int r_type;
+
+  BFD_ASSERT (stub_type != arm_stub_none);
+  *new_stub = FALSE;
+
+  BFD_ASSERT (irela);
+  BFD_ASSERT (section);
+
+  /* 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, stub_type);
+  if (!stub_name)
+    return FALSE;
+
+  stub_entry = arm_stub_hash_lookup (&htab->stub_hash_table, stub_name, FALSE,
+                                    FALSE);
+  /* The proper stub has already been created, just update its value.  */
+  if (stub_entry != NULL)
+    {
+      free (stub_name);
+      stub_entry->target_value = sym_value;
+      return TRUE;
+    }
+
+  stub_entry = elf32_arm_add_stub (stub_name, section, htab);
+  if (stub_entry == NULL)
+    {
+      free (stub_name);
+      return FALSE;
+    }
+
+  stub_entry->target_value = sym_value;
+  stub_entry->target_section = sym_sec;
+  stub_entry->stub_type = stub_type;
+  stub_entry->h = hash;
+  stub_entry->branch_type = branch_type;
+
+  if (sym_name == NULL)
+    sym_name = "unnamed";
+  stub_entry->output_name = (char *)
+    bfd_alloc (htab->stub_bfd, sizeof (THUMB2ARM_GLUE_ENTRY_NAME)
+                               + strlen (sym_name));
+  if (stub_entry->output_name == NULL)
+    {
+      free (stub_name);
+      return FALSE;
+    }
+
+  /* For historical reasons, use the existing names for ARM-to-Thumb and
+     Thumb-to-ARM stubs.  */
+  r_type = ELF32_R_TYPE (irela->r_info);
+  if ((r_type == (unsigned int) R_ARM_THM_CALL
+      || r_type == (unsigned int) R_ARM_THM_JUMP24
+      || r_type == (unsigned int) R_ARM_THM_JUMP19)
+      && branch_type == ST_BRANCH_TO_ARM)
+    sprintf (stub_entry->output_name, THUMB2ARM_GLUE_ENTRY_NAME, sym_name);
+  else if ((r_type == (unsigned int) R_ARM_CALL
+            || r_type == (unsigned int) R_ARM_JUMP24)
+           && branch_type == ST_BRANCH_TO_THUMB)
+    sprintf (stub_entry->output_name, ARM2THUMB_GLUE_ENTRY_NAME, sym_name);
+  else
+    sprintf (stub_entry->output_name, STUB_ENTRY_NAME, sym_name);
+
+  *new_stub = TRUE;
+  return TRUE;
+}
+
 /* 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
@@ -5136,6 +5221,7 @@ elf32_arm_size_stubs (bfd *output_bfd,
                      struct bfd_link_info *info,
                      bfd_signed_vma group_size,
                      asection * (*add_stub_section) (const char *, asection *,
+                                                     asection *,
                                                      unsigned int),
                      void (*layout_sections_again) (void))
 {
@@ -5267,14 +5353,11 @@ elf32_arm_size_stubs (bfd *output_bfd,
                {
                  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;
                  const char *sym_name;
-                 char *stub_name;
-                 const asection *id_sec;
                  unsigned char st_type;
                  enum arm_st_branch_type branch_type;
                  bfd_boolean created_stub = FALSE;
@@ -5288,7 +5371,13 @@ elf32_arm_size_stubs (bfd *output_bfd,
                    error_ret_free_internal:
                      if (elf_section_data (section)->relocs == NULL)
                        free (internal_relocs);
-                     goto error_ret_free_local;
+                   /* Fall through.  */
+                   error_ret_free_local:
+                     if (local_syms != NULL
+                         && (symtab_hdr->contents
+                             != (unsigned char *) local_syms))
+                       free (local_syms);
+                     return FALSE;
                    }
 
                  hash = NULL;
@@ -5457,6 +5546,8 @@ elf32_arm_size_stubs (bfd *output_bfd,
 
                  do
                    {
+                     bfd_boolean new_stub;
+
                      /* Determine what (if any) linker stub is needed.  */
                      stub_type = arm_type_of_stub (info, section, irela,
                                                    st_type, &branch_type,
@@ -5465,74 +5556,20 @@ elf32_arm_size_stubs (bfd *output_bfd,
                      if (stub_type == arm_stub_none)
                        break;
 
-                     /* 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, stub_type);
-                     if (!stub_name)
-                       goto error_ret_free_internal;
-
                      /* We've either created a stub for this reloc already,
                         or we are about to.  */
-                     created_stub = TRUE;
-
-                     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);
-                         stub_entry->target_value = sym_value;
-                         break;
-                       }
-
-                     stub_entry = elf32_arm_add_stub (stub_name, section,
-                                                      htab);
-                     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->branch_type = branch_type;
-
-                     if (sym_name == NULL)
-                       sym_name = "unnamed";
-                     stub_entry->output_name = (char *)
-                         bfd_alloc (htab->stub_bfd,
-                                    sizeof (THUMB2ARM_GLUE_ENTRY_NAME)
-                                    + strlen (sym_name));
-                     if (stub_entry->output_name == NULL)
-                       {
-                         free (stub_name);
-                         goto error_ret_free_internal;
-                       }
+                     created_stub =
+                       elf32_arm_create_stub (htab, stub_type, section, irela,
+                                              sym_sec, hash,
+                                              (char *) sym_name, sym_value,
+                                              branch_type, &new_stub);
 
-                     /* For historical reasons, use the existing names for
-                        ARM-to-Thumb and Thumb-to-ARM stubs.  */
-                     if ((r_type == (unsigned int) R_ARM_THM_CALL
-                          || r_type == (unsigned int) R_ARM_THM_JUMP24
-                           || r_type == (unsigned int) R_ARM_THM_JUMP19)
-                         && branch_type == ST_BRANCH_TO_ARM)
-                       sprintf (stub_entry->output_name,
-                                THUMB2ARM_GLUE_ENTRY_NAME, sym_name);
-                     else if ((r_type == (unsigned int) R_ARM_CALL
-                              || r_type == (unsigned int) R_ARM_JUMP24)
-                              && branch_type == ST_BRANCH_TO_THUMB)
-                       sprintf (stub_entry->output_name,
-                                ARM2THUMB_GLUE_ENTRY_NAME, sym_name);
+                     if (!created_stub)
+                       goto error_ret_free_internal;
+                     else if (!new_stub)
+                       break;
                      else
-                       sprintf (stub_entry->output_name, STUB_ENTRY_NAME,
-                                sym_name);
-
-                     stub_changed = TRUE;
+                       stub_changed = TRUE;
                    }
                  while (0);
 
@@ -5668,9 +5705,9 @@ elf32_arm_size_stubs (bfd *output_bfd,
          stub_entry->stub_offset = 0;
          stub_entry->id_sec = link_sec;
          stub_entry->stub_type = a8_fixes[i].stub_type;
+         stub_entry->source_value = a8_fixes[i].offset;
          stub_entry->target_section = a8_fixes[i].section;
-         stub_entry->target_value = a8_fixes[i].offset;
-         stub_entry->target_addend = a8_fixes[i].addend;
+         stub_entry->target_value = a8_fixes[i].target_offset;
          stub_entry->orig_insn = a8_fixes[i].orig_insn;
          stub_entry->branch_type = a8_fixes[i].branch_type;
 
@@ -5694,9 +5731,6 @@ elf32_arm_size_stubs (bfd *output_bfd,
       htab->num_a8_erratum_fixes = 0;
     }
   return TRUE;
-
- error_ret_free_local:
-  return FALSE;
 }
 
 /* Build all the stubs associated with the current output file.  The
@@ -7433,18 +7467,21 @@ is_thumb2_vldm (const insn32 insn)
 {
   /* A6.5 Extension register load or store instruction
      A7.7.229
-     We look only for the 32-bit registers case since the DP (64-bit
-     registers) are not supported for STM32L4XX
+     We look for SP 32-bit and DP 64-bit registers.
+     Encoding T1 VLDM{mode}<c> <Rn>{!}, <list>
+     <list> is consecutive 64-bit registers
+     1110 - 110P - UDW1 - rrrr - vvvv - 1011 - iiii - iiii
      Encoding T2 VLDM{mode}<c> <Rn>{!}, <list>
      <list> is consecutive 32-bit registers
      1110 - 110P - UDW1 - rrrr - vvvv - 1010 - iiii - iiii
      if P==0 && U==1 && W==1 && Rn=1101 VPOP
      if PUW=010 || PUW=011 || PUW=101 VLDM.  */
   return
-    ((insn & 0xfe100f00) == 0xec100a00)
+    (((insn & 0xfe100f00) == 0xec100b00) ||
+     ((insn & 0xfe100f00) == 0xec100a00))
     && /* (IA without !).  */
     (((((insn << 7) >> 28) & 0xd) == 0x4)
-     /* (IA with !), includes VPOP (when reg number is SP).  */     
+     /* (IA with !), includes VPOP (when reg number is SP).  */
      || ((((insn << 7) >> 28) & 0xd) == 0x5)
      /* (DB with !).  */
      || ((((insn << 7) >> 28) & 0xd) == 0x9));
@@ -7461,19 +7498,19 @@ static bfd_boolean
 stm32l4xx_need_create_replacing_stub (const insn32 insn,
                                      bfd_arm_stm32l4xx_fix stm32l4xx_fix)
 {
-  int nb_regs = 0;
+  int nb_words = 0;
 
   /* The field encoding the register list is the same for both LDMIA
      and LDMDB encodings.  */
   if (is_thumb2_ldmia (insn) || is_thumb2_ldmdb (insn))
-    nb_regs = popcount (insn & 0x0000ffff);
+    nb_words = popcount (insn & 0x0000ffff);
   else if (is_thumb2_vldm (insn))
-   nb_regs = (insn & 0xff);
+   nb_words = (insn & 0xff);
 
   /* DEFAULT mode accounts for the real bug condition situation,
      ALL mode inserts stubs for each LDM/VLDM instruction (testing).  */
   return
-    (stm32l4xx_fix == BFD_ARM_STM32L4XX_FIX_DEFAULT) ? nb_regs > 8 :
+    (stm32l4xx_fix == BFD_ARM_STM32L4XX_FIX_DEFAULT) ? nb_words > 8 :
     (stm32l4xx_fix == BFD_ARM_STM32L4XX_FIX_ALL) ? TRUE : FALSE;
 }
 
@@ -11737,6 +11774,18 @@ elf32_arm_fix_exidx_coverage (asection **text_section_order,
        /* An error?  */
        continue;
 
+      if (last_unwind_type > 0)
+       {
+         unsigned int first_word = bfd_get_32 (ibfd, contents);
+         /* Add cantunwind if first unwind item does not match section
+            start.  */
+         if (first_word != sec->vma)
+           {
+             insert_cantunwind_after (last_text_sec, last_exidx_sec);
+             last_unwind_type = 0;
+           }
+       }
+
       for (j = 0; j < hdr->sh_size; j += 8)
        {
          unsigned int second_word = bfd_get_32 (ibfd, contents + j + 4);
@@ -12275,6 +12324,47 @@ tag_cpu_arch_combine (bfd *ibfd, int oldtag, int *secondary_compat_out,
       T(V8),           /* V7E_M.  */
       T(V8)            /* V8.  */
     };
+  const int v8m_baseline[] =
+    {
+      -1,              /* PRE_V4.  */
+      -1,              /* V4.  */
+      -1,              /* V4T.  */
+      -1,              /* V5T.  */
+      -1,              /* V5TE.  */
+      -1,              /* V5TEJ.  */
+      -1,              /* V6.  */
+      -1,              /* V6KZ.  */
+      -1,              /* V6T2.  */
+      -1,              /* V6K.  */
+      -1,              /* V7.  */
+      T(V8M_BASE),     /* V6_M.  */
+      T(V8M_BASE),     /* V6S_M.  */
+      -1,              /* V7E_M.  */
+      -1,              /* V8.  */
+      -1,
+      T(V8M_BASE)      /* V8-M BASELINE.  */
+    };
+  const int v8m_mainline[] =
+    {
+      -1,              /* PRE_V4.  */
+      -1,              /* V4.  */
+      -1,              /* V4T.  */
+      -1,              /* V5T.  */
+      -1,              /* V5TE.  */
+      -1,              /* V5TEJ.  */
+      -1,              /* V6.  */
+      -1,              /* V6KZ.  */
+      -1,              /* V6T2.  */
+      -1,              /* V6K.  */
+      T(V8M_MAIN),     /* V7.  */
+      T(V8M_MAIN),     /* V6_M.  */
+      T(V8M_MAIN),     /* V6S_M.  */
+      T(V8M_MAIN),     /* V7E_M.  */
+      -1,              /* V8.  */
+      -1,
+      T(V8M_MAIN),     /* V8-M BASELINE.  */
+      T(V8M_MAIN)      /* V8-M MAINLINE.  */
+    };
   const int v4t_plus_v6_m[] =
     {
       -1,              /* PRE_V4.  */
@@ -12292,6 +12382,9 @@ tag_cpu_arch_combine (bfd *ibfd, int oldtag, int *secondary_compat_out,
       T(V6S_M),                /* V6S_M.  */
       T(V7E_M),                /* V7E_M.  */
       T(V8),           /* V8.  */
+      -1,              /* Unused.  */
+      T(V8M_BASE),     /* V8-M BASELINE.  */
+      T(V8M_MAIN),     /* V8-M MAINLINE.  */
       T(V4T_PLUS_V6_M) /* V4T plus V6_M.  */
     };
   const int *comb[] =
@@ -12303,6 +12396,9 @@ tag_cpu_arch_combine (bfd *ibfd, int oldtag, int *secondary_compat_out,
       v6s_m,
       v7e_m,
       v8,
+      NULL,
+      v8m_baseline,
+      v8m_mainline,
       /* Pseudo-architecture.  */
       v4t_plus_v6_m
     };
@@ -12335,7 +12431,7 @@ tag_cpu_arch_combine (bfd *ibfd, int oldtag, int *secondary_compat_out,
   if (tagh <= TAG_CPU_ARCH_V6KZ)
     return result;
 
-  result = comb[tagh - T(V6T2)][tagl];
+  result = comb[tagh - T(V6T2)] ? comb[tagh - T(V6T2)][tagl] : -1;
 
   /* Use Tag_CPU_arch == V4T and Tag_also_compatible_with (Tag_CPU_arch V6_M)
      as the canonical version.  */
@@ -12518,7 +12614,10 @@ elf32_arm_merge_eabi_attributes (bfd *ibfd, bfd *obfd)
                "ARM v7",
                "ARM v6-M",
                "ARM v6S-M",
-               "ARM v8"
+               "ARM v8",
+               "",
+               "ARM v8-M.baseline",
+               "ARM v8-M.mainline",
            };
 
            /* Merge Tag_CPU_arch and Tag_also_compatible_with.  */
@@ -12663,6 +12762,31 @@ elf32_arm_merge_eabi_attributes (bfd *ibfd, bfd *obfd)
                }
            }
          break;
+
+       case Tag_DSP_extension:
+         /* No need to change output value if any of:
+            - pre (<=) ARMv5T input architecture (do not have DSP)
+            - M input profile not ARMv7E-M and do not have DSP.  */
+         if (in_attr[Tag_CPU_arch].i <= 3
+             || (in_attr[Tag_CPU_arch_profile].i == 'M'
+                 && in_attr[Tag_CPU_arch].i != 13
+                 && in_attr[i].i == 0))
+           ; /* Do nothing.  */
+         /* Output value should be 0 if DSP part of architecture, ie.
+            - post (>=) ARMv5te architecture output
+            - A, R or S profile output or ARMv7E-M output architecture.  */
+         else if (out_attr[Tag_CPU_arch].i >= 4
+                  && (out_attr[Tag_CPU_arch_profile].i == 'A'
+                      || out_attr[Tag_CPU_arch_profile].i == 'R'
+                      || out_attr[Tag_CPU_arch_profile].i == 'S'
+                      || out_attr[Tag_CPU_arch].i == 13))
+           out_attr[i].i = 0;
+         /* Otherwise, DSP instructions are added and not part of output
+            architecture.  */
+         else
+           out_attr[i].i = 1;
+         break;
+
        case Tag_FP_arch:
            {
              /* Tag_ABI_HardFP_use is handled along with Tag_FP_arch since
@@ -13548,6 +13672,8 @@ elf32_arm_check_relocs (bfd *abfd, struct bfd_link_info *info,
                may_need_local_target_p = TRUE;
                break;
              }
+           else goto jump_over;
+             
            /* Fall through.  */
 
          case R_ARM_MOVW_ABS_NC:
@@ -13567,6 +13693,7 @@ elf32_arm_check_relocs (bfd *abfd, struct bfd_link_info *info,
            /* Fall through.  */
          case R_ARM_ABS32:
          case R_ARM_ABS32_NOI:
+       jump_over:
            if (h != NULL && bfd_link_executable (info))
              {
                h->pointer_equality_needed = 1;
@@ -14038,11 +14165,13 @@ elf32_arm_adjust_dynamic_symbol (struct bfd_link_info * info,
   s = bfd_get_linker_section (dynobj, ".dynbss");
   BFD_ASSERT (s != NULL);
 
-  /* We must generate a R_ARM_COPY reloc to tell the dynamic linker to
-     copy the initial value out of the dynamic object and into the
-     runtime process image.  We need to remember the offset into the
+  /* If allowed, we must generate a R_ARM_COPY reloc to tell the dynamic
+     linker to copy the initial value out of the dynamic object and into
+     the runtime process image.  We need to remember the offset into the
      .rel(a).bss section we are going to use.  */
-  if ((h->root.u.def.section->flags & SEC_ALLOC) != 0 && h->size != 0)
+  if (info->nocopyreloc == 0
+      && (h->root.u.def.section->flags & SEC_ALLOC) != 0
+      && h->size != 0)
     {
       asection *srel;
 
@@ -15482,6 +15611,8 @@ elf32_arm_reloc_type_class (const struct bfd_link_info *info ATTRIBUTE_UNUSED,
       return reloc_class_plt;
     case R_ARM_COPY:
       return reloc_class_copy;
+    case R_ARM_IRELATIVE:
+      return reloc_class_ifunc;
     default:
       return reloc_class_normal;
     }
@@ -16171,7 +16302,7 @@ make_branch_to_a8_stub (struct bfd_hash_entry *gen_entry,
   bfd_vma veneered_insn_loc, veneer_entry_loc;
   bfd_signed_vma branch_offset;
   bfd *abfd;
-  unsigned int target;
+  unsigned int loc;
 
   stub_entry = (struct elf32_arm_stub_hash_entry *) gen_entry;
   data = (struct a8_branch_to_stub_data *) in_arg;
@@ -16182,9 +16313,11 @@ make_branch_to_a8_stub (struct bfd_hash_entry *gen_entry,
 
   contents = data->contents;
 
+  /* We use target_section as Cortex-A8 erratum workaround stubs are only
+     generated when both source and target are in the same section.  */
   veneered_insn_loc = stub_entry->target_section->output_section->vma
                      + stub_entry->target_section->output_offset
-                     + stub_entry->target_value;
+                     + stub_entry->source_value;
 
   veneer_entry_loc = stub_entry->stub_sec->output_section->vma
                     + stub_entry->stub_sec->output_offset
@@ -16196,7 +16329,7 @@ make_branch_to_a8_stub (struct bfd_hash_entry *gen_entry,
   branch_offset = veneer_entry_loc - veneered_insn_loc - 4;
 
   abfd = stub_entry->target_section->owner;
-  target = stub_entry->target_value;
+  loc = stub_entry->source_value;
 
   /* We attempt to avoid this condition by setting stubs_always_after_branch
      in elf32_arm_size_stubs if we've enabled the Cortex-A8 erratum workaround.
@@ -16257,8 +16390,8 @@ make_branch_to_a8_stub (struct bfd_hash_entry *gen_entry,
       return FALSE;
     }
 
-  bfd_put_16 (abfd, (branch_insn >> 16) & 0xffff, &contents[target]);
-  bfd_put_16 (abfd, branch_insn & 0xffff, &contents[target + 2]);
+  bfd_put_16 (abfd, (branch_insn >> 16) & 0xffff, &contents[loc]);
+  bfd_put_16 (abfd, branch_insn & 0xffff, &contents[loc + 2]);
 
   return TRUE;
 }
@@ -16354,30 +16487,31 @@ create_instruction_sub (int target_reg, int source_reg, int value)
 }
 
 static inline bfd_vma
-create_instruction_vldmia (int base_reg, int wback, int num_regs,
+create_instruction_vldmia (int base_reg, int is_dp, int wback, int num_words,
                           int first_reg)
 {
   /* A8.8.332 VLDM (A8-922)
-     VLMD{MODE} Rn{!}, {list} (Encoding T2).  */
-  bfd_vma patched_inst = 0xec900a00
+     VLMD{MODE} Rn{!}, {list} (Encoding T1 or T2).  */
+  bfd_vma patched_inst = (is_dp ? 0xec900b00 : 0xec900a00)
     | (/*W=*/wback << 21)
     | (base_reg << 16)
-    | (num_regs & 0x000000ff)
-    | (((unsigned)first_reg>>1) & 0x0000000f) << 12
+    | (num_words & 0x000000ff)
+    | (((unsigned)first_reg >> 1) & 0x0000000f) << 12
     | (first_reg & 0x00000001) << 22;
 
   return patched_inst;
 }
 
 static inline bfd_vma
-create_instruction_vldmdb (int base_reg, int num_regs, int first_reg)
+create_instruction_vldmdb (int base_reg, int is_dp, int num_words,
+                          int first_reg)
 {
   /* A8.8.332 VLDM (A8-922)
-     VLMD{MODE} Rn!, {} (Encoding T2).  */
-  bfd_vma patched_inst = 0xed300a00
+     VLMD{MODE} Rn!, {} (Encoding T1 or T2).  */
+  bfd_vma patched_inst = (is_dp ? 0xed300b00 : 0xed300a00)
     | (base_reg << 16)
-    | (num_regs & 0x000000ff)
-    | (((unsigned)first_reg>>1) & 0x0000000f) << 12
+    | (num_words & 0x000000ff)
+    | (((unsigned)first_reg >>1 ) & 0x0000000f) << 12
     | (first_reg & 0x00000001) << 22;
 
   return patched_inst;
@@ -16857,15 +16991,15 @@ stm32l4xx_create_replacing_stub_vldm (struct elf32_arm_link_hash_table * htab,
                                      const bfd_byte *const initial_insn_addr,
                                      bfd_byte *const base_stub_contents)
 {
-  int num_regs = ((unsigned int)initial_insn << 24) >> 24;
+  int num_words = ((unsigned int) initial_insn << 24) >> 24;
   bfd_byte *current_stub_contents = base_stub_contents;
 
   BFD_ASSERT (is_thumb2_vldm (initial_insn));
 
   /* In BFD_ARM_STM32L4XX_FIX_ALL mode we may have to deal with
-     smaller than 8 registers load sequences that do not cause the
+     smaller than 8 words load sequences that do not cause the
      hardware issue.  */
-  if (num_regs <= 8)
+  if (num_words <= 8)
     {
       /* Untouched instruction.  */
       current_stub_contents =
@@ -16880,28 +17014,30 @@ stm32l4xx_create_replacing_stub_vldm (struct elf32_arm_link_hash_table * htab,
     }
   else
     {
+      bfd_boolean is_dp = /* DP encoding. */
+       (initial_insn & 0xfe100f00) == 0xec100b00;
       bfd_boolean is_ia_nobang = /* (IA without !).  */
        (((initial_insn << 7) >> 28) & 0xd) == 0x4;
       bfd_boolean is_ia_bang = /* (IA with !) - includes VPOP.  */
        (((initial_insn << 7) >> 28) & 0xd) == 0x5;
       bfd_boolean is_db_bang = /* (DB with !).  */
        (((initial_insn << 7) >> 28) & 0xd) == 0x9;
-      int base_reg = ((unsigned int)initial_insn << 12) >> 28;
+      int base_reg = ((unsigned int) initial_insn << 12) >> 28;
       /* d = UInt (Vd:D);.  */
-      int first_reg = ((((unsigned int)initial_insn << 16) >> 28) << 1)
+      int first_reg = ((((unsigned int) initial_insn << 16) >> 28) << 1)
        | (((unsigned int)initial_insn << 9) >> 31);
 
-      /* Compute the number of 8-register chunks needed to split.  */
-      int chunks = (num_regs%8) ? (num_regs/8 + 1) : (num_regs/8);
+      /* Compute the number of 8-words chunks needed to split.  */
+      int chunks = (num_words % 8) ? (num_words / 8 + 1) : (num_words / 8);
       int chunk;
 
       /* The test coverage has been done assuming the following
         hypothesis that exactly one of the previous is_ predicates is
         true.  */
-      BFD_ASSERT ((is_ia_nobang ^ is_ia_bang ^ is_db_bang) &&
-                 !(is_ia_nobang & is_ia_bang & is_db_bang));
+      BFD_ASSERT (    (is_ia_nobang ^ is_ia_bang ^ is_db_bang)
+                 && !(is_ia_nobang & is_ia_bang & is_db_bang));
 
-      /* We treat the cutting of the register in one pass for all
+      /* We treat the cutting of the words in one pass for all
         cases, then we emit the adjustments:
 
         vldm rx, {...}
@@ -16914,29 +17050,34 @@ stm32l4xx_create_replacing_stub_vldm (struct elf32_arm_link_hash_table * htab,
 
         vldmd rx!, {...}
         -> vldmb rx!, {8_words_or_less} for each needed 8_word.  */
-      for (chunk = 0; chunk<chunks; ++chunk)
+      for (chunk = 0; chunk < chunks; ++chunk)
        {
+         bfd_vma new_insn = 0;
+
          if (is_ia_nobang || is_ia_bang)
            {
-             current_stub_contents =
-               push_thumb2_insn32 (htab, output_bfd, current_stub_contents,
-                                   create_instruction_vldmia
-                                   (base_reg,
-                                    /*wback= .  */1,
-                                    chunks - (chunk + 1) ?
-                                    8 : num_regs - chunk * 8,
-                                    first_reg + chunk * 8));
+             new_insn = create_instruction_vldmia
+               (base_reg,
+                is_dp,
+                /*wback= .  */1,
+                chunks - (chunk + 1) ?
+                8 : num_words - chunk * 8,
+                first_reg + chunk * 8);
            }
          else if (is_db_bang)
            {
-             current_stub_contents =
-               push_thumb2_insn32 (htab, output_bfd, current_stub_contents,
-                                   create_instruction_vldmdb
-                                   (base_reg,
-                                    chunks - (chunk + 1) ?
-                                    8 : num_regs - chunk * 8,
-                                    first_reg + chunk * 8));
+             new_insn = create_instruction_vldmdb
+               (base_reg,
+                is_dp,
+                chunks - (chunk + 1) ?
+                8 : num_words - chunk * 8,
+                first_reg + chunk * 8);
            }
+
+         if (new_insn)
+           current_stub_contents =
+             push_thumb2_insn32 (htab, output_bfd, current_stub_contents,
+                                 new_insn);
        }
 
       /* Only this case requires the base register compensation
@@ -16946,7 +17087,7 @@ stm32l4xx_create_replacing_stub_vldm (struct elf32_arm_link_hash_table * htab,
          current_stub_contents =
            push_thumb2_insn32 (htab, output_bfd, current_stub_contents,
                                create_instruction_sub
-                               (base_reg, base_reg, 4*num_regs));
+                               (base_reg, base_reg, 4*num_words));
        }
 
       /* B initial_insn_addr+4.  */
@@ -17772,16 +17913,6 @@ elf32_arm_get_synthetic_symtab (bfd *abfd,
   return n;
 }
 
-static const struct bfd_elf_special_section
-elf32_arm_special_sections[] =
-{
-/* Catch sections with .text.noread prefix and apply allocate, execute and
-   noread section attributes.  */
-  { STRING_COMMA_LEN (".text.noread"),  -2, SHT_PROGBITS,
-    SHF_ALLOC + SHF_EXECINSTR + SHF_ARM_NOREAD },
-  { NULL,                            0, 0, 0,                  0 }
-};
-
 static bfd_boolean
 elf32_arm_section_flags (flagword *flags, const Elf_Internal_Shdr * hdr)
 {
@@ -17807,6 +17938,100 @@ elf32_arm_count_additional_relocs (asection *sec)
   return arm_data->additional_reloc_count;
 }
 
+/* Called to set the sh_flags, sh_link and sh_info fields of OSECTION which
+   has a type >= SHT_LOOS.  Returns TRUE if these fields were initialised 
+   FALSE otherwise.  ISECTION is the best guess matching section from the
+   input bfd IBFD, but it might be NULL.  */
+
+static bfd_boolean
+elf32_arm_copy_special_section_fields (const bfd *ibfd ATTRIBUTE_UNUSED,
+                                      bfd *obfd ATTRIBUTE_UNUSED,
+                                      const Elf_Internal_Shdr *isection ATTRIBUTE_UNUSED,
+                                      Elf_Internal_Shdr *osection)
+{
+  switch (osection->sh_type)
+    {
+    case SHT_ARM_EXIDX:
+      {
+       Elf_Internal_Shdr **oheaders = elf_elfsections (obfd);
+       Elf_Internal_Shdr **iheaders = elf_elfsections (ibfd);
+       unsigned i = 0;
+
+       osection->sh_flags = SHF_ALLOC | SHF_LINK_ORDER;
+       osection->sh_info = 0;
+
+       /* The sh_link field must be set to the text section associated with
+          this index section.  Unfortunately the ARM EHABI does not specify
+          exactly how to determine this association.  Our caller does try
+          to match up OSECTION with its corresponding input section however
+          so that is a good first guess.  */
+       if (isection != NULL
+           && osection->bfd_section != NULL
+           && isection->bfd_section != NULL
+           && isection->bfd_section->output_section != NULL
+           && isection->bfd_section->output_section == osection->bfd_section
+           && iheaders != NULL
+           && isection->sh_link > 0
+           && isection->sh_link < elf_numsections (ibfd)
+           && iheaders[isection->sh_link]->bfd_section != NULL
+           && iheaders[isection->sh_link]->bfd_section->output_section != NULL
+           )
+         {
+           for (i = elf_numsections (obfd); i-- > 0;)
+             if (oheaders[i]->bfd_section
+                 == iheaders[isection->sh_link]->bfd_section->output_section)
+               break;
+         }
+           
+       if (i == 0)
+         {
+           /* Failing that we have to find a matching section ourselves.  If
+              we had the output section name available we could compare that
+              with input section names.  Unfortunately we don't.  So instead
+              we use a simple heuristic and look for the nearest executable
+              section before this one.  */
+           for (i = elf_numsections (obfd); i-- > 0;)
+             if (oheaders[i] == osection)
+               break;
+           if (i == 0)
+             break;
+
+           while (i-- > 0)
+             if (oheaders[i]->sh_type == SHT_PROGBITS
+                 && (oheaders[i]->sh_flags & (SHF_ALLOC | SHF_EXECINSTR))
+                 == (SHF_ALLOC | SHF_EXECINSTR))
+               break;
+         }
+
+       if (i)
+         {
+           osection->sh_link = i;
+           /* If the text section was part of a group
+              then the index section should be too.  */
+           if (oheaders[i]->sh_flags & SHF_GROUP)
+             osection->sh_flags |= SHF_GROUP;
+           return TRUE;
+         }
+      }
+      break;
+
+    case SHT_ARM_PREEMPTMAP:
+      osection->sh_flags = SHF_ALLOC;
+      break;
+
+    case SHT_ARM_ATTRIBUTES:
+    case SHT_ARM_DEBUGOVERLAY:
+    case SHT_ARM_OVERLAYSECTION:
+    default:
+      break;
+    }
+
+  return FALSE;
+}
+
+#undef  elf_backend_copy_special_section_fields
+#define elf_backend_copy_special_section_fields elf32_arm_copy_special_section_fields
+
 #define ELF_ARCH                       bfd_arch_arm
 #define ELF_TARGET_ID                  ARM_ELF_DATA
 #define ELF_MACHINE_CODE               EM_ARM
@@ -17886,8 +18111,6 @@ elf32_arm_count_additional_relocs (asection *sec)
 #define elf_backend_obj_attrs_order            elf32_arm_obj_attrs_order
 #define elf_backend_obj_attrs_handle_unknown   elf32_arm_obj_attrs_handle_unknown
 
-#undef  elf_backend_special_sections
-#define elf_backend_special_sections           elf32_arm_special_sections
 #undef elf_backend_section_flags
 #define elf_backend_section_flags              elf32_arm_section_flags
 #undef elf_backend_lookup_section_flags_hook
@@ -17971,6 +18194,7 @@ elf32_arm_nacl_plt_sym_val (bfd_vma i, const asection *plt,
 #undef bfd_elf32_get_synthetic_symtab
 #undef  elf_backend_plt_sym_val
 #define elf_backend_plt_sym_val                        elf32_arm_nacl_plt_sym_val
+#undef  elf_backend_copy_special_section_fields
 
 #undef ELF_MINPAGESIZE
 #undef ELF_COMMONPAGESIZE
@@ -18390,7 +18614,6 @@ elf32_arm_symbian_plt_sym_val (bfd_vma i, const asection *plt,
   return plt->vma + 4 * ARRAY_SIZE (elf32_arm_symbian_plt_entry) * i;
 }
 
-
 #undef  elf32_bed
 #define elf32_bed elf32_arm_symbian_bed