Automatic date update in version.in
[deliverable/binutils-gdb.git] / bfd / elf32-arm.c
index 881f2cf783ef50f79d566c4ea5dc68b845e4f44d..d35d609c65218f185ca267d79533644378834ca6 100644 (file)
@@ -1,5 +1,5 @@
 /* 32-bit ELF support for ARM
-   Copyright (C) 1998-2018 Free Software Foundation, Inc.
+   Copyright (C) 1998-2019 Free Software Foundation, Inc.
 
    This file is part of BFD, the Binary File Descriptor library.
 
@@ -22,7 +22,6 @@
 #include <limits.h>
 
 #include "bfd.h"
-#include "bfd_stdint.h"
 #include "libiberty.h"
 #include "libbfd.h"
 #include "elf-bfd.h"
@@ -56,7 +55,7 @@
    ? bfd_elf32_swap_reloc_out \
    : bfd_elf32_swap_reloca_out)
 
-#define elf_info_to_howto              0
+#define elf_info_to_howto              NULL
 #define elf_info_to_howto_rel          elf32_arm_info_to_howto
 
 #define ARM_ELF_ABI_VERSION            0
@@ -1743,10 +1742,50 @@ static reloc_howto_type elf32_arm_howto_table_1[] =
         0x00000000,            /* src_mask.  */
         0x00000000,            /* dst_mask.  */
         FALSE),                /* pcrel_offset.  */
+  /* Relocations for Armv8.1-M Mainline.  */
+  HOWTO (R_ARM_THM_BF16,       /* type.  */
+        0,                     /* rightshift.  */
+        1,                     /* size (0 = byte, 1 = short, 2 = long).  */
+        16,                    /* bitsize.  */
+        TRUE,                  /* pc_relative.  */
+        0,                     /* bitpos.  */
+        complain_overflow_dont,/* do not complain_on_overflow.  */
+        bfd_elf_generic_reloc, /* special_function.  */
+        "R_ARM_THM_BF16",      /* name.  */
+        FALSE,                 /* partial_inplace.  */
+        0x001f0ffe,            /* src_mask.  */
+        0x001f0ffe,            /* dst_mask.  */
+        TRUE),                 /* pcrel_offset.  */
+  HOWTO (R_ARM_THM_BF12,       /* type.  */
+        0,                     /* rightshift.  */
+        1,                     /* size (0 = byte, 1 = short, 2 = long).  */
+        12,                    /* bitsize.  */
+        TRUE,                  /* pc_relative.  */
+        0,                     /* bitpos.  */
+        complain_overflow_dont,/* do not complain_on_overflow.  */
+        bfd_elf_generic_reloc, /* special_function.  */
+        "R_ARM_THM_BF12",      /* name.  */
+        FALSE,                 /* partial_inplace.  */
+        0x00010ffe,            /* src_mask.  */
+        0x00010ffe,            /* dst_mask.  */
+        TRUE),                 /* pcrel_offset.  */
+  HOWTO (R_ARM_THM_BF18,       /* type.  */
+        0,                     /* rightshift.  */
+        1,                     /* size (0 = byte, 1 = short, 2 = long).  */
+        18,                    /* bitsize.  */
+        TRUE,                  /* pc_relative.  */
+        0,                     /* bitpos.  */
+        complain_overflow_dont,/* do not complain_on_overflow.  */
+        bfd_elf_generic_reloc, /* special_function.  */
+        "R_ARM_THM_BF18",      /* name.  */
+        FALSE,                 /* partial_inplace.  */
+        0x007f0ffe,            /* src_mask.  */
+        0x007f0ffe,            /* dst_mask.  */
+        TRUE),                 /* pcrel_offset.  */
 };
 
 /* 160 onwards: */
-static reloc_howto_type elf32_arm_howto_table_2[1] =
+static reloc_howto_type elf32_arm_howto_table_2[8] =
 {
   HOWTO (R_ARM_IRELATIVE,      /* type */
         0,                     /* rightshift */
@@ -1760,7 +1799,98 @@ static reloc_howto_type elf32_arm_howto_table_2[1] =
         TRUE,                  /* partial_inplace */
         0xffffffff,            /* src_mask */
         0xffffffff,            /* dst_mask */
-        FALSE)                 /* pcrel_offset */
+        FALSE),                /* pcrel_offset */
+  HOWTO (R_ARM_GOTFUNCDESC,    /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        32,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_bitfield,/* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_ARM_GOTFUNCDESC",   /* name */
+        FALSE,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0xffffffff,            /* dst_mask */
+        FALSE),                /* pcrel_offset */
+  HOWTO (R_ARM_GOTOFFFUNCDESC, /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        32,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_bitfield,/* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_ARM_GOTOFFFUNCDESC",/* name */
+        FALSE,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0xffffffff,            /* dst_mask */
+        FALSE),                /* pcrel_offset */
+  HOWTO (R_ARM_FUNCDESC,       /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        32,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_bitfield,/* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_ARM_FUNCDESC",      /* name */
+        FALSE,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0xffffffff,            /* dst_mask */
+        FALSE),                /* pcrel_offset */
+  HOWTO (R_ARM_FUNCDESC_VALUE, /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        64,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_bitfield,/* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_ARM_FUNCDESC_VALUE",/* name */
+        FALSE,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0xffffffff,            /* dst_mask */
+        FALSE),                /* pcrel_offset */
+  HOWTO (R_ARM_TLS_GD32_FDPIC, /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        32,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_bitfield,/* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_ARM_TLS_GD32_FDPIC",/* name */
+        FALSE,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0xffffffff,            /* dst_mask */
+        FALSE),                /* pcrel_offset */
+  HOWTO (R_ARM_TLS_LDM32_FDPIC,        /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        32,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_bitfield,/* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_ARM_TLS_LDM32_FDPIC",/* name */
+        FALSE,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0xffffffff,            /* dst_mask */
+        FALSE),                /* pcrel_offset */
+  HOWTO (R_ARM_TLS_IE32_FDPIC, /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        32,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_bitfield,/* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_ARM_TLS_IE32_FDPIC",/* name */
+        FALSE,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0xffffffff,            /* dst_mask */
+        FALSE),                /* pcrel_offset */
 };
 
 /* 249-255 extended, currently unused, relocations:  */
@@ -1829,7 +1959,8 @@ elf32_arm_howto_from_type (unsigned int r_type)
   if (r_type < ARRAY_SIZE (elf32_arm_howto_table_1))
     return &elf32_arm_howto_table_1[r_type];
 
-  if (r_type == R_ARM_IRELATIVE)
+  if (r_type >= R_ARM_IRELATIVE
+      && r_type < R_ARM_IRELATIVE + ARRAY_SIZE (elf32_arm_howto_table_2))
     return &elf32_arm_howto_table_2[r_type - R_ARM_IRELATIVE];
 
   if (r_type >= R_ARM_RREL32
@@ -1839,14 +1970,22 @@ elf32_arm_howto_from_type (unsigned int r_type)
   return NULL;
 }
 
-static void
-elf32_arm_info_to_howto (bfd * abfd ATTRIBUTE_UNUSED, arelent * bfd_reloc,
+static bfd_boolean
+elf32_arm_info_to_howto (bfd * abfd, arelent * bfd_reloc,
                         Elf_Internal_Rela * elf_reloc)
 {
   unsigned int r_type;
 
   r_type = ELF32_R_TYPE (elf_reloc->r_info);
-  bfd_reloc->howto = elf32_arm_howto_from_type (r_type);
+  if ((bfd_reloc->howto = elf32_arm_howto_from_type (r_type)) == NULL)
+    {
+      /* xgettext:c-format */
+      _bfd_error_handler (_("%pB: unsupported relocation type %#x"),
+                         abfd, r_type);
+      bfd_set_error (bfd_error_bad_value);
+      return FALSE;
+    }
+  return TRUE;
 }
 
 struct elf32_arm_reloc_map
@@ -1905,6 +2044,13 @@ static const struct elf32_arm_reloc_map elf32_arm_reloc_map[] =
     {BFD_RELOC_ARM_TLS_IE32,        R_ARM_TLS_IE32},
     {BFD_RELOC_ARM_TLS_LE32,        R_ARM_TLS_LE32},
     {BFD_RELOC_ARM_IRELATIVE,       R_ARM_IRELATIVE},
+    {BFD_RELOC_ARM_GOTFUNCDESC,      R_ARM_GOTFUNCDESC},
+    {BFD_RELOC_ARM_GOTOFFFUNCDESC,   R_ARM_GOTOFFFUNCDESC},
+    {BFD_RELOC_ARM_FUNCDESC,         R_ARM_FUNCDESC},
+    {BFD_RELOC_ARM_FUNCDESC_VALUE,   R_ARM_FUNCDESC_VALUE},
+    {BFD_RELOC_ARM_TLS_GD32_FDPIC,   R_ARM_TLS_GD32_FDPIC},
+    {BFD_RELOC_ARM_TLS_LDM32_FDPIC,  R_ARM_TLS_LDM32_FDPIC},
+    {BFD_RELOC_ARM_TLS_IE32_FDPIC,   R_ARM_TLS_IE32_FDPIC},
     {BFD_RELOC_VTABLE_INHERIT,      R_ARM_GNU_VTINHERIT},
     {BFD_RELOC_VTABLE_ENTRY,        R_ARM_GNU_VTENTRY},
     {BFD_RELOC_ARM_MOVW,            R_ARM_MOVW_ABS_NC},
@@ -1947,7 +2093,10 @@ static const struct elf32_arm_reloc_map elf32_arm_reloc_map[] =
     {BFD_RELOC_ARM_THUMB_ALU_ABS_G3_NC, R_ARM_THM_ALU_ABS_G3_NC},
     {BFD_RELOC_ARM_THUMB_ALU_ABS_G2_NC, R_ARM_THM_ALU_ABS_G2_NC},
     {BFD_RELOC_ARM_THUMB_ALU_ABS_G1_NC, R_ARM_THM_ALU_ABS_G1_NC},
-    {BFD_RELOC_ARM_THUMB_ALU_ABS_G0_NC, R_ARM_THM_ALU_ABS_G0_NC}
+    {BFD_RELOC_ARM_THUMB_ALU_ABS_G0_NC, R_ARM_THM_ALU_ABS_G0_NC},
+    {BFD_RELOC_ARM_THUMB_BF17, R_ARM_THM_BF16},
+    {BFD_RELOC_ARM_THUMB_BF13, R_ARM_THM_BF12},
+    {BFD_RELOC_ARM_THUMB_BF19, R_ARM_THM_BF18}
   };
 
 static reloc_howto_type *
@@ -2061,13 +2210,24 @@ elf32_arm_nabi_write_core_note (bfd *abfd, char *buf, int *bufsiz,
 
     case NT_PRPSINFO:
       {
-       char data[124];
+       char data[124] ATTRIBUTE_NONSTRING;
        va_list ap;
 
        va_start (ap, note_type);
        memset (data, 0, sizeof (data));
        strncpy (data + 28, va_arg (ap, const char *), 16);
+#if GCC_VERSION == 8000 || GCC_VERSION == 8001
+       DIAGNOSTIC_PUSH;
+       /* GCC 8.0 and 8.1 warn about 80 equals destination size with
+          -Wstringop-truncation:
+          https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85643
+        */
+       DIAGNOSTIC_IGNORE_STRINGOP_TRUNCATION;
+#endif
        strncpy (data + 44, va_arg (ap, const char *), 80);
+#if GCC_VERSION == 8000 || GCC_VERSION == 8001
+       DIAGNOSTIC_POP;
+#endif
        va_end (ap);
 
        return elfcore_write_note (abfd, buf, bufsiz,
@@ -2144,6 +2304,9 @@ typedef unsigned short int insn16;
    section.  */
 #define ELF_DYNAMIC_INTERPRETER     "/usr/lib/ld.so.1"
 
+/* FDPIC default stack size.  */
+#define DEFAULT_STACK_SIZE 0x8000
+
 static const unsigned long tls_trampoline [] =
 {
   0xe08e0000,          /* add r0, lr, r0 */
@@ -2164,6 +2327,38 @@ static const unsigned long dl_tlsdesc_lazy_trampoline [] =
   0x00000018, /* 4:   .word  _GLOBAL_OFFSET_TABLE_ - 2b - 8 */
 };
 
+/* ARM FDPIC PLT entry.  */
+/* The last 5 words contain PLT lazy fragment code and data.  */
+static const bfd_vma elf32_arm_fdpic_plt_entry [] =
+  {
+    0xe59fc008,    /* ldr     r12, .L1 */
+    0xe08cc009,    /* add     r12, r12, r9 */
+    0xe59c9004,    /* ldr     r9, [r12, #4] */
+    0xe59cf000,    /* ldr     pc, [r12] */
+    0x00000000,    /* L1.     .word   foo(GOTOFFFUNCDESC) */
+    0x00000000,    /* L1.     .word   foo(funcdesc_value_reloc_offset) */
+    0xe51fc00c,    /* ldr     r12, [pc, #-12] */
+    0xe92d1000,    /* push    {r12} */
+    0xe599c004,    /* ldr     r12, [r9, #4] */
+    0xe599f000,    /* ldr     pc, [r9] */
+  };
+
+/* Thumb FDPIC PLT entry.  */
+/* The last 5 words contain PLT lazy fragment code and data.  */
+static const bfd_vma elf32_arm_fdpic_thumb_plt_entry [] =
+  {
+    0xc00cf8df,    /* ldr.w   r12, .L1 */
+    0x0c09eb0c,    /* add.w   r12, r12, r9 */
+    0x9004f8dc,    /* ldr.w   r9, [r12, #4] */
+    0xf000f8dc,    /* ldr.w   pc, [r12] */
+    0x00000000,    /* .L1     .word   foo(GOTOFFFUNCDESC) */
+    0x00000000,    /* .L2     .word   foo(funcdesc_value_reloc_offset) */
+    0xc008f85f,    /* ldr.w   r12, .L2 */
+    0xcd04f84d,    /* push    {r12} */
+    0xc004f8d9,    /* ldr.w   r12, [r9, #4] */
+    0xf000f8d9,    /* ldr.w   pc, [r9] */
+  };
+
 #ifdef FOUR_WORD_PLT
 
 /* The first entry in a procedure linkage table looks like
@@ -2936,6 +3131,13 @@ struct arm_local_iplt_info
   struct elf_dyn_relocs *dyn_relocs;
 };
 
+/* Structure to handle FDPIC support for local functions.  */
+struct fdpic_local {
+  unsigned int funcdesc_cnt;
+  unsigned int gotofffuncdesc_cnt;
+  int funcdesc_offset;
+};
+
 struct elf_arm_obj_tdata
 {
   struct elf_obj_tdata root;
@@ -2954,6 +3156,9 @@ struct elf_arm_obj_tdata
 
   /* Zero to warn when linking objects with incompatible wchar_t sizes.  */
   int no_wchar_size_warning;
+
+  /* Maintains FDPIC counters and funcdesc info.  */
+  struct fdpic_local *local_fdpic_cnts;
 };
 
 #define elf_arm_tdata(bfd) \
@@ -2968,6 +3173,9 @@ struct elf_arm_obj_tdata
 #define elf32_arm_local_iplt(bfd) \
   (elf_arm_tdata (bfd)->local_iplt)
 
+#define elf32_arm_local_fdpic_cnts(bfd) \
+  (elf_arm_tdata (bfd)->local_fdpic_cnts)
+
 #define is_arm_elf(bfd) \
   (bfd_get_flavour (bfd) == bfd_target_elf_flavour \
    && elf_tdata (bfd) != NULL \
@@ -2982,6 +3190,15 @@ elf32_arm_mkobject (bfd *abfd)
 
 #define elf32_arm_hash_entry(ent) ((struct elf32_arm_link_hash_entry *)(ent))
 
+/* Structure to handle FDPIC support for extern functions.  */
+struct fdpic_global {
+  unsigned int gotofffuncdesc_cnt;
+  unsigned int gotfuncdesc_cnt;
+  unsigned int funcdesc_cnt;
+  int funcdesc_offset;
+  int gotfuncdesc_offset;
+};
+
 /* Arm ELF linker hash entry.  */
 struct elf32_arm_link_hash_entry
 {
@@ -3017,6 +3234,9 @@ struct elf32_arm_link_hash_entry
   /* A pointer to the most recently used stub hash entry against this
      symbol.  */
   struct elf32_arm_stub_hash_entry *stub_cache;
+
+  /* Counter for FDPIC relocations against this symbol.  */
+  struct fdpic_global fdpic_cnts;
 };
 
 /* Traverse an arm ELF linker hash table.  */
@@ -3142,7 +3362,7 @@ struct elf32_arm_link_hash_table
   int nacl_p;
 
   /* True if the target uses REL relocations.  */
-  int use_rel;
+  bfd_boolean use_rel;
 
   /* Nonzero if import library must be a secure gateway import library
      as per ARMv8-M Security Extensions.  */
@@ -3174,7 +3394,7 @@ struct elf32_arm_link_hash_table
   /* Offset in .plt section of tls_arm_trampoline.  */
   bfd_vma tls_trampoline;
 
-  /* Data for R_ARM_TLS_LDM32 relocations.  */
+  /* Data for R_ARM_TLS_LDM32/R_ARM_TLS_LDM32_FDPIC relocations.  */
   union
   {
     bfd_signed_vma refcount;
@@ -3220,8 +3440,25 @@ struct elf32_arm_link_hash_table
   unsigned int bfd_count;
   unsigned int top_index;
   asection **input_list;
+
+  /* True if the target system uses FDPIC. */
+  int fdpic_p;
+
+  /* Fixup section. Used for FDPIC.  */
+  asection *srofixup;
 };
 
+/* Add an FDPIC read-only fixup.  */
+static void
+arm_elf_add_rofixup (bfd *output_bfd, asection *srofixup, bfd_vma offset)
+{
+  bfd_vma fixup_offset;
+
+  fixup_offset = srofixup->reloc_count++ * 4;
+  BFD_ASSERT (fixup_offset < srofixup->size);
+  bfd_put_32 (output_bfd, offset, srofixup->contents + fixup_offset);
+}
+
 static inline int
 ctz (unsigned int mask)
 {
@@ -3259,6 +3496,57 @@ elf32_arm_popcount (unsigned int mask)
 #endif
 }
 
+static void elf32_arm_add_dynreloc (bfd *output_bfd, struct bfd_link_info *info,
+                                   asection *sreloc, Elf_Internal_Rela *rel);
+
+static void
+arm_elf_fill_funcdesc(bfd *output_bfd,
+                     struct bfd_link_info *info,
+                     int *funcdesc_offset,
+                     int dynindx,
+                     int offset,
+                     bfd_vma addr,
+                     bfd_vma dynreloc_value,
+                     bfd_vma seg)
+{
+  if ((*funcdesc_offset & 1) == 0)
+    {
+      struct elf32_arm_link_hash_table *globals = elf32_arm_hash_table (info);
+      asection *sgot = globals->root.sgot;
+
+      if (bfd_link_pic(info))
+       {
+         asection *srelgot = globals->root.srelgot;
+         Elf_Internal_Rela outrel;
+
+         outrel.r_info = ELF32_R_INFO (dynindx, R_ARM_FUNCDESC_VALUE);
+         outrel.r_offset = sgot->output_section->vma + sgot->output_offset + offset;
+         outrel.r_addend = 0;
+
+         elf32_arm_add_dynreloc (output_bfd, info, srelgot, &outrel);
+         bfd_put_32 (output_bfd, addr, sgot->contents + offset);
+         bfd_put_32 (output_bfd, seg, sgot->contents + offset + 4);
+       }
+      else
+       {
+         struct elf_link_hash_entry *hgot = globals->root.hgot;
+         bfd_vma got_value = hgot->root.u.def.value
+           + hgot->root.u.def.section->output_section->vma
+           + hgot->root.u.def.section->output_offset;
+
+         arm_elf_add_rofixup(output_bfd, globals->srofixup,
+                             sgot->output_section->vma + sgot->output_offset
+                             + offset);
+         arm_elf_add_rofixup(output_bfd, globals->srofixup,
+                             sgot->output_section->vma + sgot->output_offset
+                             + offset + 4);
+         bfd_put_32 (output_bfd, dynreloc_value, sgot->contents + offset);
+         bfd_put_32 (output_bfd, got_value, sgot->contents + offset + 4);
+       }
+      *funcdesc_offset |= 1;
+    }
+}
+
 /* Create an entry in an ARM ELF linker hash table.  */
 
 static struct bfd_hash_entry *
@@ -3294,6 +3582,12 @@ elf32_arm_link_hash_newfunc (struct bfd_hash_entry * entry,
       ret->export_glue = NULL;
 
       ret->stub_cache = NULL;
+
+      ret->fdpic_cnts.gotofffuncdesc_cnt = 0;
+      ret->fdpic_cnts.gotfuncdesc_cnt = 0;
+      ret->fdpic_cnts.funcdesc_cnt = 0;
+      ret->fdpic_cnts.funcdesc_offset = -1;
+      ret->fdpic_cnts.gotfuncdesc_offset = -1;
     }
 
   return (struct bfd_hash_entry *) ret;
@@ -3315,11 +3609,15 @@ elf32_arm_allocate_local_sym_info (bfd *abfd)
       size = num_syms * (sizeof (bfd_signed_vma)
                         + sizeof (struct arm_local_iplt_info *)
                         + sizeof (bfd_vma)
-                        + sizeof (char));
+                        + sizeof (char)
+                        + sizeof (struct fdpic_local));
       data = bfd_zalloc (abfd, size);
       if (data == NULL)
        return FALSE;
 
+      elf32_arm_local_fdpic_cnts (abfd) = (struct fdpic_local *) data;
+      data += num_syms * sizeof (struct fdpic_local);
+
       elf_local_got_refcounts (abfd) = (bfd_signed_vma *) data;
       data += num_syms * sizeof (bfd_signed_vma);
 
@@ -3391,6 +3689,8 @@ elf32_arm_get_plt_info (bfd *abfd, struct elf32_arm_link_hash_table *globals,
   return TRUE;
 }
 
+static bfd_boolean using_thumb_only (struct elf32_arm_link_hash_table *globals);
+
 /* Return true if the PLT described by ARM_PLT requires a Thumb stub
    before it.  */
 
@@ -3401,8 +3701,9 @@ elf32_arm_plt_needs_thumb_stub_p (struct bfd_link_info *info,
   struct elf32_arm_link_hash_table *htab;
 
   htab = elf32_arm_hash_table (info);
-  return (arm_plt->thumb_refcount != 0
-         || (!htab->use_blx && arm_plt->maybe_thumb_refcount != 0));
+
+  return (!using_thumb_only(htab) && (arm_plt->thumb_refcount != 0
+         || (!htab->use_blx && arm_plt->maybe_thumb_refcount != 0)));
 }
 
 /* Return a pointer to the head of the dynamic reloc list that should
@@ -3501,6 +3802,16 @@ create_got_section (bfd *dynobj, struct bfd_link_info *info)
   if (! _bfd_elf_create_got_section (dynobj, info))
     return FALSE;
 
+  /* Also create .rofixup.  */
+  if (htab->fdpic_p)
+    {
+      htab->srofixup = bfd_make_section_with_flags (dynobj, ".rofixup",
+                                                   (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS
+                                                    | SEC_IN_MEMORY | SEC_LINKER_CREATED | SEC_READONLY));
+      if (htab->srofixup == NULL || ! bfd_set_section_alignment (dynobj, htab->srofixup, 2))
+       return FALSE;
+    }
+
   return TRUE;
 }
 
@@ -3567,13 +3878,14 @@ using_thumb_only (struct elf32_arm_link_hash_table *globals)
   arch = bfd_elf_get_obj_attr_int (globals->obfd, OBJ_ATTR_PROC, Tag_CPU_arch);
 
   /* Force return logic to be reviewed for each new architecture.  */
-  BFD_ASSERT (arch <= TAG_CPU_ARCH_V8M_MAIN);
+  BFD_ASSERT (arch <= TAG_CPU_ARCH_V8_1M_MAIN);
 
   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)
+      || arch == TAG_CPU_ARCH_V8M_MAIN
+      || arch == TAG_CPU_ARCH_V8_1M_MAIN)
     return TRUE;
 
   return FALSE;
@@ -3594,14 +3906,15 @@ using_thumb2 (struct elf32_arm_link_hash_table *globals)
   arch = bfd_elf_get_obj_attr_int (globals->obfd, OBJ_ATTR_PROC, Tag_CPU_arch);
 
   /* Force return logic to be reviewed for each new architecture.  */
-  BFD_ASSERT (arch <= TAG_CPU_ARCH_V8M_MAIN);
+  BFD_ASSERT (arch <= TAG_CPU_ARCH_V8_1M_MAIN);
 
   return (arch == TAG_CPU_ARCH_V6T2
          || arch == TAG_CPU_ARCH_V7
          || arch == TAG_CPU_ARCH_V7E_M
          || arch == TAG_CPU_ARCH_V8
          || arch == TAG_CPU_ARCH_V8R
-         || arch == TAG_CPU_ARCH_V8M_MAIN);
+         || arch == TAG_CPU_ARCH_V8M_MAIN
+         || arch == TAG_CPU_ARCH_V8_1M_MAIN);
 }
 
 /* Determine whether Thumb-2 BL instruction is available.  */
@@ -3613,7 +3926,7 @@ using_thumb2_bl (struct elf32_arm_link_hash_table *globals)
     bfd_elf_get_obj_attr_int (globals->obfd, OBJ_ATTR_PROC, Tag_CPU_arch);
 
   /* Force return logic to be reviewed for each new architecture.  */
-  BFD_ASSERT (arch <= TAG_CPU_ARCH_V8M_MAIN);
+  BFD_ASSERT (arch <= TAG_CPU_ARCH_V8_1M_MAIN);
 
   /* Architecture was introduced after ARMv6T2 (eg. ARMv6-M).  */
   return (arch == TAG_CPU_ARCH_V6T2
@@ -3678,6 +3991,14 @@ elf32_arm_create_dynamic_sections (bfd *dynobj, struct bfd_link_info *info)
       htab->obfd = saved_obfd;
     }
 
+  if (htab->fdpic_p) {
+    htab->plt_header_size = 0;
+    if (info->flags & DF_BIND_NOW)
+      htab->plt_entry_size = 4 * (ARRAY_SIZE(elf32_arm_fdpic_plt_entry) - 5);
+    else
+      htab->plt_entry_size = 4 * ARRAY_SIZE(elf32_arm_fdpic_plt_entry);
+  }
+
   if (!htab->root.splt
       || !htab->root.srelplt
       || !htab->root.sdynbss
@@ -3740,6 +4061,11 @@ elf32_arm_copy_indirect_symbol (struct bfd_link_info *info,
       edir->plt.noncall_refcount += eind->plt.noncall_refcount;
       eind->plt.noncall_refcount = 0;
 
+      /* Copy FDPIC counters.  */
+      edir->fdpic_cnts.gotofffuncdesc_cnt += eind->fdpic_cnts.gotofffuncdesc_cnt;
+      edir->fdpic_cnts.gotfuncdesc_cnt += eind->fdpic_cnts.gotfuncdesc_cnt;
+      edir->fdpic_cnts.funcdesc_cnt += eind->fdpic_cnts.funcdesc_cnt;
+
       /* We should only allocate a function to .iplt once the final
         symbol information is known.  */
       BFD_ASSERT (!eind->is_iplt);
@@ -3796,8 +4122,9 @@ elf32_arm_link_hash_table_create (bfd *abfd)
   ret->plt_header_size = 20;
   ret->plt_entry_size = elf32_arm_use_long_plt_entry ? 16 : 12;
 #endif
-  ret->use_rel = 1;
+  ret->use_rel = TRUE;
   ret->obfd = abfd;
+  ret->fdpic_p = 0;
 
   if (!bfd_hash_table_init (&ret->stub_hash_table, stub_hash_newfunc,
                            sizeof (struct elf32_arm_stub_hash_entry)))
@@ -3819,7 +4146,7 @@ arch_has_arm_nop (struct elf32_arm_link_hash_table *globals)
                                             Tag_CPU_arch);
 
   /* Force return logic to be reviewed for each new architecture.  */
-  BFD_ASSERT (arch <= TAG_CPU_ARCH_V8M_MAIN);
+  BFD_ASSERT (arch <= TAG_CPU_ARCH_V8_1M_MAIN);
 
   return (arch == TAG_CPU_ARCH_V6T2
          || arch == TAG_CPU_ARCH_V6K
@@ -6166,7 +6493,8 @@ elf32_arm_size_stubs (bfd *output_bfd,
          asection *section;
          Elf_Internal_Sym *local_syms = NULL;
 
-         if (!is_arm_elf (input_bfd))
+         if (!is_arm_elf (input_bfd)
+             || (elf_dyn_lib_class (input_bfd) & DYN_AS_NEEDED) != 0)
            continue;
 
          num_a8_relocs = 0;
@@ -6894,7 +7222,7 @@ arm_allocate_glue_section_space (bfd * abfd, bfd_size_type size, const char * na
   s = bfd_get_linker_section (abfd, name);
   BFD_ASSERT (s != NULL);
 
-  contents = (bfd_byte *) bfd_alloc (abfd, size);
+  contents = (bfd_byte *) bfd_zalloc (abfd, size);
 
   BFD_ASSERT (s->size == size);
   s->contents = contents;
@@ -8704,7 +9032,9 @@ bfd_elf32_arm_set_target_params (struct bfd *output_bfd,
     return;
 
   globals->target1_is_rel = params->target1_is_rel;
-  if (strcmp (params->target2_type, "rel") == 0)
+  if (globals->fdpic_p)
+    globals->target2_reloc = R_ARM_GOT32;
+  else if (strcmp (params->target2_type, "rel") == 0)
     globals->target2_reloc = R_ARM_REL32;
   else if (strcmp (params->target2_type, "abs") == 0)
     globals->target2_reloc = R_ARM_ABS32;
@@ -8719,7 +9049,10 @@ bfd_elf32_arm_set_target_params (struct bfd *output_bfd,
   globals->use_blx |= params->use_blx;
   globals->vfp11_fix = params->vfp11_denorm_fix;
   globals->stm32l4xx_fix = params->stm32l4xx_fix;
-  globals->pic_veneer = params->pic_veneer;
+  if (globals->fdpic_p)
+    globals->pic_veneer = 1;
+  else
+    globals->pic_veneer = params->pic_veneer;
   globals->fix_cortex_a8 = params->fix_cortex_a8;
   globals->fix_arm1176 = params->fix_arm1176;
   globals->cmse_implib = params->cmse_implib;
@@ -9205,8 +9538,22 @@ elf32_arm_allocate_plt_entry (struct bfd_link_info *info,
       splt = htab->root.splt;
       sgotplt = htab->root.sgotplt;
 
-      /* Allocate room for an R_JUMP_SLOT relocation in .rel.plt.  */
-      elf32_arm_allocate_dynrelocs (info, htab->root.srelplt, 1);
+    if (htab->fdpic_p)
+      {
+       /* Allocate room for R_ARM_FUNCDESC_VALUE.  */
+       /* For lazy binding, relocations will be put into .rel.plt, in
+          .rel.got otherwise.  */
+       /* FIXME: today we don't support lazy binding so put it in .rel.got */
+       if (info->flags & DF_BIND_NOW)
+         elf32_arm_allocate_dynrelocs (info, htab->root.srelgot, 1);
+       else
+         elf32_arm_allocate_dynrelocs (info, htab->root.srelplt, 1);
+      }
+    else
+      {
+       /* Allocate room for an R_JUMP_SLOT relocation in .rel.plt.  */
+       elf32_arm_allocate_dynrelocs (info, htab->root.srelplt, 1);
+      }
 
       /* If this is the first .plt entry, make room for the special
         first entry.  */
@@ -9230,7 +9577,11 @@ elf32_arm_allocate_plt_entry (struct bfd_link_info *info,
        arm_plt->got_offset = sgotplt->size;
       else
        arm_plt->got_offset = sgotplt->size - 8 * htab->num_tls_desc;
-      sgotplt->size += 4;
+      if (htab->fdpic_p)
+       /* Function descriptor takes 64 bits in GOT.  */
+       sgotplt->size += 8;
+      else
+       sgotplt->size += 4;
     }
 }
 
@@ -9339,7 +9690,11 @@ elf32_arm_populate_plt_entry (bfd *output_bfd, struct bfd_link_info *info,
         in all the symbols for which we are making plt entries.
         After the reserved .got.plt entries, all symbols appear in
         the same order as in .plt.  */
-      plt_index = (got_offset - got_header_size) / 4;
+      if (htab->fdpic_p)
+       /* Function descriptor takes 8 bytes.  */
+       plt_index = (got_offset - got_header_size) / 8;
+      else
+       plt_index = (got_offset - got_header_size) / 4;
 
       /* Calculate the address of the GOT entry.  */
       got_address = (sgot->output_section->vma
@@ -9447,6 +9802,41 @@ elf32_arm_populate_plt_entry (bfd *output_bfd, struct bfd_link_info *info,
                        | (tail_displacement & 0x00ffffff),
                        ptr + 12);
        }
+      else if (htab->fdpic_p)
+       {
+         const bfd_vma *plt_entry = using_thumb_only(htab)
+           ? elf32_arm_fdpic_thumb_plt_entry
+           : elf32_arm_fdpic_plt_entry;
+
+         /* Fill-up Thumb stub if needed.  */
+         if (elf32_arm_plt_needs_thumb_stub_p (info, arm_plt))
+           {
+             put_thumb_insn (htab, output_bfd,
+                             elf32_arm_plt_thumb_stub[0], ptr - 4);
+             put_thumb_insn (htab, output_bfd,
+                             elf32_arm_plt_thumb_stub[1], ptr - 2);
+           }
+         /* As we are using 32 bit instructions even for the Thumb
+            version, we have to use 'put_arm_insn' instead of
+            'put_thumb_insn'.  */
+         put_arm_insn(htab, output_bfd, plt_entry[0], ptr + 0);
+         put_arm_insn(htab, output_bfd, plt_entry[1], ptr + 4);
+         put_arm_insn(htab, output_bfd, plt_entry[2], ptr + 8);
+         put_arm_insn(htab, output_bfd, plt_entry[3], ptr + 12);
+         bfd_put_32 (output_bfd, got_offset, ptr + 16);
+
+         if (!(info->flags & DF_BIND_NOW))
+           {
+             /* funcdesc_value_reloc_offset.  */
+             bfd_put_32 (output_bfd,
+                         htab->root.srelplt->reloc_count * RELOC_SIZE (htab),
+                         ptr + 20);
+             put_arm_insn(htab, output_bfd, plt_entry[6], ptr + 24);
+             put_arm_insn(htab, output_bfd, plt_entry[7], ptr + 28);
+             put_arm_insn(htab, output_bfd, plt_entry[8], ptr + 32);
+             put_arm_insn(htab, output_bfd, plt_entry[9], ptr + 36);
+           }
+       }
       else if (using_thumb_only (htab))
        {
          /* PR ld/16017: Generate thumb only PLT entries.  */
@@ -9557,22 +9947,61 @@ elf32_arm_populate_plt_entry (bfd *output_bfd, struct bfd_link_info *info,
        }
       else
        {
-         rel.r_info = ELF32_R_INFO (dynindx, R_ARM_JUMP_SLOT);
-         initial_got_entry = (splt->output_section->vma
-                              + splt->output_offset);
+         /* For FDPIC we will have to resolve a R_ARM_FUNCDESC_VALUE
+            used by PLT entry.  */
+         if (htab->fdpic_p)
+           {
+             rel.r_info = ELF32_R_INFO (dynindx, R_ARM_FUNCDESC_VALUE);
+             initial_got_entry = 0;
+           }
+         else
+           {
+             rel.r_info = ELF32_R_INFO (dynindx, R_ARM_JUMP_SLOT);
+             initial_got_entry = (splt->output_section->vma
+                                  + splt->output_offset);
+           }
        }
 
       /* Fill in the entry in the global offset table.  */
       bfd_put_32 (output_bfd, initial_got_entry,
                  sgot->contents + got_offset);
+
+      if (htab->fdpic_p && !(info->flags & DF_BIND_NOW))
+       {
+         /* Setup initial funcdesc value.  */
+         /* FIXME: we don't support lazy binding because there is a
+            race condition between both words getting written and
+            some other thread attempting to read them. The ARM
+            architecture does not have an atomic 64 bit load/store
+            instruction that could be used to prevent it; it is
+            recommended that threaded FDPIC applications run with the
+            LD_BIND_NOW environment variable set.  */
+         bfd_put_32(output_bfd, plt_address + 0x18,
+                    sgot->contents + got_offset);
+         bfd_put_32(output_bfd, -1 /*TODO*/,
+                    sgot->contents + got_offset + 4);
+       }
     }
 
   if (dynindx == -1)
     elf32_arm_add_dynreloc (output_bfd, info, srel, &rel);
   else
     {
-      loc = srel->contents + plt_index * RELOC_SIZE (htab);
-      SWAP_RELOC_OUT (htab) (output_bfd, &rel, loc);
+      if (htab->fdpic_p)
+       {
+         /* For FDPIC we put PLT relocationss into .rel.got when not
+            lazy binding otherwise we put them in .rel.plt.  For now,
+            we don't support lazy binding so put it in .rel.got.  */
+         if (info->flags & DF_BIND_NOW)
+           elf32_arm_add_dynreloc(output_bfd, info, htab->root.srelgot, &rel);
+         else
+           elf32_arm_add_dynreloc(output_bfd, info, htab->root.srelplt, &rel);
+       }
+      else
+       {
+         loc = srel->contents + plt_index * RELOC_SIZE (htab);
+         SWAP_RELOC_OUT (htab) (output_bfd, &rel, loc);
+       }
     }
 
   return TRUE;
@@ -10078,7 +10507,8 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
         relocations are copied into the output file to be resolved at
         run time.  */
       if ((bfd_link_pic (info)
-          || globals->root.is_relocatable_executable)
+          || globals->root.is_relocatable_executable
+          || globals->fdpic_p)
          && (input_section->flags & SEC_ALLOC)
          && !(globals->vxworks_p
               && strcmp (input_section->output_section->name,
@@ -10099,6 +10529,7 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
        {
          Elf_Internal_Rela outrel;
          bfd_boolean skip, relocate;
+         int isrofixup = 0;
 
          if ((r_type == R_ARM_REL32 || r_type == R_ARM_REL32_NOI)
              && !h->def_regular)
@@ -10154,7 +10585,8 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
              int symbol;
 
              /* This symbol is local, or marked to become local.  */
-             BFD_ASSERT (r_type == R_ARM_ABS32 || r_type == R_ARM_ABS32_NOI);
+             BFD_ASSERT (r_type == R_ARM_ABS32 || r_type == R_ARM_ABS32_NOI
+                         || (globals->fdpic_p && !bfd_link_pic(info)));
              if (globals->symbian_p)
                {
                  asection *osec;
@@ -10200,6 +10632,8 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
                   must use an R_ARM_IRELATIVE relocation to obtain the
                   correct run-time address.  */
                outrel.r_info = ELF32_R_INFO (symbol, R_ARM_IRELATIVE);
+             else if (globals->fdpic_p && !bfd_link_pic(info))
+               isrofixup = 1;
              else
                outrel.r_info = ELF32_R_INFO (symbol, R_ARM_RELATIVE);
              if (globals->use_rel)
@@ -10208,7 +10642,10 @@ elf32_arm_final_link_relocate (reloc_howto_type *          howto,
                outrel.r_addend += dynreloc_value;
            }
 
-         elf32_arm_add_dynreloc (output_bfd, info, sreloc, &outrel);
+         if (isrofixup)
+           arm_elf_add_rofixup(output_bfd, globals->srofixup, outrel.r_offset);
+         else
+           elf32_arm_add_dynreloc (output_bfd, info, sreloc, &outrel);
 
          /* If this reloc is against an external symbol, we do not want to
             fiddle with the addend.  Otherwise, we need to include the symbol
@@ -10512,7 +10949,7 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
 
        /* PR 21523: Use an absolute value.  The user of this reloc will
           have already selected an ADD or SUB insn appropriately.  */
-       value = labs (relocation);
+       value = llabs (relocation);
 
        if (value >= 0x1000)
          return bfd_reloc_overflow;
@@ -11084,8 +11521,10 @@ elf32_arm_final_link_relocate (reloc_howto_type *          howto,
          else
            {
              Elf_Internal_Rela outrel;
+             int isrofixup = 0;
 
-             if (h->dynindx != -1 && !SYMBOL_REFERENCES_LOCAL (info, h))
+             if (((h->dynindx != -1) || globals->fdpic_p)
+                 && !SYMBOL_REFERENCES_LOCAL (info, h))
                {
                  /* If the symbol doesn't resolve locally in a static
                     object, we have an undefined reference.  If the
@@ -11109,27 +11548,38 @@ elf32_arm_final_link_relocate (reloc_howto_type *         howto,
                               || h->root.type != bfd_link_hash_undefweak))
                    outrel.r_info = ELF32_R_INFO (0, R_ARM_RELATIVE);
                  else
-                   outrel.r_info = 0;
+                   {
+                     outrel.r_info = 0;
+                     if (globals->fdpic_p)
+                       isrofixup = 1;
+                   }
                  outrel.r_addend = dynreloc_value;
                }
 
              /* The GOT entry is initialized to zero by default.
                 See if we should install a different value.  */
              if (outrel.r_addend != 0
-                 && (outrel.r_info == 0 || globals->use_rel))
+                 && (globals->use_rel || outrel.r_info == 0))
                {
                  bfd_put_32 (output_bfd, outrel.r_addend,
                              sgot->contents + off);
                  outrel.r_addend = 0;
                }
 
-             if (outrel.r_info != 0)
+             if (isrofixup)
+               arm_elf_add_rofixup (output_bfd,
+                                    elf32_arm_hash_table(info)->srofixup,
+                                    sgot->output_section->vma
+                                    + sgot->output_offset + off);
+
+             else if (outrel.r_info != 0)
                {
                  outrel.r_offset = (sgot->output_section->vma
                                     + sgot->output_offset
                                     + off);
                  elf32_arm_add_dynreloc (output_bfd, info, srelgot, &outrel);
                }
+
              h->got.offset |= 1;
            }
          value = sgot->output_offset + off;
@@ -11150,21 +11600,37 @@ elf32_arm_final_link_relocate (reloc_howto_type *         howto,
            off &= ~1;
          else
            {
-             if (globals->use_rel)
-               bfd_put_32 (output_bfd, dynreloc_value, sgot->contents + off);
+             Elf_Internal_Rela outrel;
+             int isrofixup = 0;
 
-             if (bfd_link_pic (info) || dynreloc_st_type == STT_GNU_IFUNC)
+             if (dynreloc_st_type == STT_GNU_IFUNC)
+               outrel.r_info = ELF32_R_INFO (0, R_ARM_IRELATIVE);
+             else if (bfd_link_pic (info))
+               outrel.r_info = ELF32_R_INFO (0, R_ARM_RELATIVE);
+             else
                {
-                 Elf_Internal_Rela outrel;
+                 outrel.r_info = 0;
+                 if (globals->fdpic_p)
+                   isrofixup = 1;
+               }
 
+             /* The GOT entry is initialized to zero by default.
+                See if we should install a different value.  */
+             if (globals->use_rel || outrel.r_info == 0)
+               bfd_put_32 (output_bfd, dynreloc_value, sgot->contents + off);
+
+             if (isrofixup)
+               arm_elf_add_rofixup (output_bfd,
+                                    globals->srofixup,
+                                    sgot->output_section->vma
+                                    + sgot->output_offset + off);
+
+             else if (outrel.r_info != 0)
+               {
                  outrel.r_addend = addend + dynreloc_value;
                  outrel.r_offset = (sgot->output_section->vma
                                     + sgot->output_offset
                                     + off);
-                 if (dynreloc_st_type == STT_GNU_IFUNC)
-                   outrel.r_info = ELF32_R_INFO (0, R_ARM_IRELATIVE);
-                 else
-                   outrel.r_info = ELF32_R_INFO (0, R_ARM_RELATIVE);
                  elf32_arm_add_dynreloc (output_bfd, info, srelgot, &outrel);
                }
 
@@ -11188,6 +11654,7 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
                                       rel->r_addend);
 
     case R_ARM_TLS_LDM32:
+    case R_ARM_TLS_LDM32_FDPIC:
       {
        bfd_vma off;
 
@@ -11226,18 +11693,32 @@ elf32_arm_final_link_relocate (reloc_howto_type *         howto,
            globals->tls_ldm_got.offset |= 1;
          }
 
-       value = sgot->output_section->vma + sgot->output_offset + off
-         - (input_section->output_section->vma + input_section->output_offset + rel->r_offset);
+       if (r_type == R_ARM_TLS_LDM32_FDPIC)
+         {
+           bfd_put_32(output_bfd,
+                      globals->root.sgot->output_offset + off,
+                      contents + rel->r_offset);
+
+           return bfd_reloc_ok;
+         }
+       else
+         {
+           value = sgot->output_section->vma + 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,
-                                        contents, rel->r_offset, value,
-                                        rel->r_addend);
+           return _bfd_final_link_relocate (howto, input_bfd, input_section,
+                                            contents, rel->r_offset, value,
+                                            rel->r_addend);
+         }
       }
 
     case R_ARM_TLS_CALL:
     case R_ARM_THM_TLS_CALL:
     case R_ARM_TLS_GD32:
+    case R_ARM_TLS_GD32_FDPIC:
     case R_ARM_TLS_IE32:
+    case R_ARM_TLS_IE32_FDPIC:
     case R_ARM_TLS_GOTDESC:
     case R_ARM_TLS_DESCSEQ:
     case R_ARM_THM_TLS_DESCSEQ:
@@ -11425,7 +11906,7 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
              local_got_offsets[r_symndx] |= 1;
          }
 
-       if ((tls_type & GOT_TLS_GD) && r_type != R_ARM_TLS_GD32)
+       if ((tls_type & GOT_TLS_GD) && r_type != R_ARM_TLS_GD32 && r_type != R_ARM_TLS_GD32_FDPIC)
          off += 8;
        else if (tls_type & GOT_TLS_GDESC)
          off = offplt;
@@ -11584,9 +12065,23 @@ elf32_arm_final_link_relocate (reloc_howto_type *          howto,
                   - (input_section->output_section->vma
                      + input_section->output_offset + rel->r_offset));
 
-       return _bfd_final_link_relocate (howto, input_bfd, input_section,
-                                        contents, rel->r_offset, value,
-                                        rel->r_addend);
+       if (globals->fdpic_p && (r_type == R_ARM_TLS_GD32_FDPIC ||
+                                r_type == R_ARM_TLS_IE32_FDPIC))
+         {
+           /* For FDPIC relocations, resolve to the offset of the GOT
+              entry from the start of GOT.  */
+           bfd_put_32(output_bfd,
+                      globals->root.sgot->output_offset + off,
+                      contents + rel->r_offset);
+
+           return bfd_reloc_ok;
+         }
+       else
+         {
+           return _bfd_final_link_relocate (howto, input_bfd, input_section,
+                                            contents, rel->r_offset, value,
+                                            rel->r_addend);
+         }
       }
 
     case R_ARM_TLS_LE32:
@@ -12168,27 +12663,388 @@ elf32_arm_final_link_relocate (reloc_howto_type *        howto,
        *unresolved_reloc_p = FALSE;
        return bfd_reloc_ok;
 
-    default:
-      return bfd_reloc_notsupported;
-    }
-}
+    case R_ARM_GOTOFFFUNCDESC:
+      {
+       if (h == NULL)
+         {
+           struct fdpic_local *local_fdpic_cnts = elf32_arm_local_fdpic_cnts(input_bfd);
+           int dynindx = elf_section_data (sym_sec->output_section)->dynindx;
+           int offset = local_fdpic_cnts[r_symndx].funcdesc_offset & ~1;
+           bfd_vma addr = dynreloc_value - sym_sec->output_section->vma;
+           bfd_vma seg = -1;
+
+           if (bfd_link_pic(info) && dynindx == 0)
+             abort();
+
+           /* Resolve relocation.  */
+           bfd_put_32(output_bfd, (offset + sgot->output_offset)
+                      , contents + rel->r_offset);
+           /* Emit R_ARM_FUNCDESC_VALUE or two fixups on funcdesc if
+              not done yet.  */
+           arm_elf_fill_funcdesc(output_bfd, info,
+                                 &local_fdpic_cnts[r_symndx].funcdesc_offset,
+                                 dynindx, offset, addr, dynreloc_value, seg);
+         }
+       else
+         {
+           int dynindx;
+           int offset = eh->fdpic_cnts.funcdesc_offset & ~1;
+           bfd_vma addr;
+           bfd_vma seg = -1;
 
-/* Add INCREMENT to the reloc (of type HOWTO) at ADDRESS.  */
-static void
-arm_add_to_rel (bfd *             abfd,
-               bfd_byte *         address,
-               reloc_howto_type * howto,
-               bfd_signed_vma     increment)
-{
-  bfd_signed_vma addend;
+           /* For static binaries, sym_sec can be null.  */
+           if (sym_sec)
+             {
+               dynindx = elf_section_data (sym_sec->output_section)->dynindx;
+               addr = dynreloc_value - sym_sec->output_section->vma;
+             }
+           else
+             {
+               dynindx = 0;
+               addr = 0;
+             }
 
-  if (howto->type == R_ARM_THM_CALL
-      || howto->type == R_ARM_THM_JUMP24)
-    {
-      int upper_insn, lower_insn;
-      int upper, lower;
+           if (bfd_link_pic(info) && dynindx == 0)
+             abort();
+
+           /* This case cannot occur since funcdesc is allocated by
+              the dynamic loader so we cannot resolve the relocation.  */
+           if (h->dynindx != -1)
+             abort();
+
+           /* Resolve relocation.  */
+           bfd_put_32(output_bfd, (offset + sgot->output_offset),
+                      contents + rel->r_offset);
+           /* Emit R_ARM_FUNCDESC_VALUE on funcdesc if not done yet.  */
+           arm_elf_fill_funcdesc(output_bfd, info,
+                                 &eh->fdpic_cnts.funcdesc_offset,
+                                 dynindx, offset, addr, dynreloc_value, seg);
+         }
+      }
+      *unresolved_reloc_p = FALSE;
+      return bfd_reloc_ok;
 
-      upper_insn = bfd_get_16 (abfd, address);
+    case R_ARM_GOTFUNCDESC:
+      {
+       if (h != NULL)
+         {
+           Elf_Internal_Rela outrel;
+
+           /* Resolve relocation.  */
+           bfd_put_32(output_bfd, ((eh->fdpic_cnts.gotfuncdesc_offset & ~1)
+                                   + sgot->output_offset),
+                      contents + rel->r_offset);
+           /* Add funcdesc and associated R_ARM_FUNCDESC_VALUE.  */
+           if(h->dynindx == -1)
+             {
+               int dynindx;
+               int offset = eh->fdpic_cnts.funcdesc_offset & ~1;
+               bfd_vma addr;
+               bfd_vma seg = -1;
+
+               /* For static binaries sym_sec can be null.  */
+               if (sym_sec)
+                 {
+                   dynindx = elf_section_data (sym_sec->output_section)->dynindx;
+                   addr = dynreloc_value - sym_sec->output_section->vma;
+                 }
+               else
+                 {
+                   dynindx = 0;
+                   addr = 0;
+                 }
+
+               /* Emit R_ARM_FUNCDESC_VALUE on funcdesc if not done yet.  */
+               arm_elf_fill_funcdesc(output_bfd, info,
+                                     &eh->fdpic_cnts.funcdesc_offset,
+                                     dynindx, offset, addr, dynreloc_value, seg);
+             }
+
+           /* Add a dynamic relocation on GOT entry if not already done.  */
+           if ((eh->fdpic_cnts.gotfuncdesc_offset & 1) == 0)
+             {
+               if (h->dynindx == -1)
+                 {
+                   outrel.r_info = ELF32_R_INFO (0, R_ARM_RELATIVE);
+                   if (h->root.type == bfd_link_hash_undefweak)
+                     bfd_put_32(output_bfd, 0, sgot->contents
+                                + (eh->fdpic_cnts.gotfuncdesc_offset & ~1));
+                   else
+                     bfd_put_32(output_bfd, sgot->output_section->vma
+                                + sgot->output_offset
+                                + (eh->fdpic_cnts.funcdesc_offset & ~1),
+                                sgot->contents
+                                + (eh->fdpic_cnts.gotfuncdesc_offset & ~1));
+                 }
+               else
+                 {
+                   outrel.r_info = ELF32_R_INFO (h->dynindx, R_ARM_FUNCDESC);
+                 }
+               outrel.r_offset = sgot->output_section->vma
+                 + sgot->output_offset
+                 + (eh->fdpic_cnts.gotfuncdesc_offset & ~1);
+               outrel.r_addend = 0;
+               if (h->dynindx == -1 && !bfd_link_pic(info))
+                 if (h->root.type == bfd_link_hash_undefweak)
+                   arm_elf_add_rofixup(output_bfd, globals->srofixup, -1);
+                 else
+                   arm_elf_add_rofixup(output_bfd, globals->srofixup,
+                                       outrel.r_offset);
+               else
+                 elf32_arm_add_dynreloc (output_bfd, info, srelgot, &outrel);
+               eh->fdpic_cnts.gotfuncdesc_offset |= 1;
+             }
+         }
+       else
+         {
+           /* Such relocation on static function should not have been
+              emitted by the compiler.  */
+           abort();
+         }
+      }
+      *unresolved_reloc_p = FALSE;
+      return bfd_reloc_ok;
+
+    case R_ARM_FUNCDESC:
+      {
+       if (h == NULL)
+         {
+           struct fdpic_local *local_fdpic_cnts = elf32_arm_local_fdpic_cnts(input_bfd);
+           Elf_Internal_Rela outrel;
+           int dynindx = elf_section_data (sym_sec->output_section)->dynindx;
+           int offset = local_fdpic_cnts[r_symndx].funcdesc_offset & ~1;
+           bfd_vma addr = dynreloc_value - sym_sec->output_section->vma;
+           bfd_vma seg = -1;
+
+           if (bfd_link_pic(info) && dynindx == 0)
+             abort();
+
+           /* Replace static FUNCDESC relocation with a
+              R_ARM_RELATIVE dynamic relocation or with a rofixup for
+              executable.  */
+           outrel.r_info = ELF32_R_INFO (0, R_ARM_RELATIVE);
+           outrel.r_offset = input_section->output_section->vma
+             + input_section->output_offset + rel->r_offset;
+           outrel.r_addend = 0;
+           if (bfd_link_pic(info))
+             elf32_arm_add_dynreloc (output_bfd, info, srelgot, &outrel);
+           else
+             arm_elf_add_rofixup(output_bfd, globals->srofixup, outrel.r_offset);
+
+           bfd_put_32 (input_bfd, sgot->output_section->vma
+                       + sgot->output_offset + offset, hit_data);
+
+           /* Emit R_ARM_FUNCDESC_VALUE on funcdesc if not done yet.  */
+           arm_elf_fill_funcdesc(output_bfd, info,
+                                 &local_fdpic_cnts[r_symndx].funcdesc_offset,
+                                 dynindx, offset, addr, dynreloc_value, seg);
+         }
+       else
+         {
+           if (h->dynindx == -1)
+             {
+               int dynindx;
+               int offset = eh->fdpic_cnts.funcdesc_offset & ~1;
+               bfd_vma addr;
+               bfd_vma seg = -1;
+               Elf_Internal_Rela outrel;
+
+               /* For static binaries sym_sec can be null.  */
+               if (sym_sec)
+                 {
+                   dynindx = elf_section_data (sym_sec->output_section)->dynindx;
+                   addr = dynreloc_value - sym_sec->output_section->vma;
+                 }
+               else
+                 {
+                   dynindx = 0;
+                   addr = 0;
+                 }
+
+               if (bfd_link_pic(info) && dynindx == 0)
+                 abort();
+
+               /* Replace static FUNCDESC relocation with a
+                  R_ARM_RELATIVE dynamic relocation.  */
+               outrel.r_info = ELF32_R_INFO (0, R_ARM_RELATIVE);
+               outrel.r_offset = input_section->output_section->vma
+                 + input_section->output_offset + rel->r_offset;
+               outrel.r_addend = 0;
+               if (bfd_link_pic(info))
+                 elf32_arm_add_dynreloc (output_bfd, info, srelgot, &outrel);
+               else
+                 arm_elf_add_rofixup(output_bfd, globals->srofixup, outrel.r_offset);
+
+               bfd_put_32 (input_bfd, sgot->output_section->vma
+                           + sgot->output_offset + offset, hit_data);
+
+               /* Emit R_ARM_FUNCDESC_VALUE on funcdesc if not done yet.  */
+               arm_elf_fill_funcdesc(output_bfd, info,
+                                     &eh->fdpic_cnts.funcdesc_offset,
+                                     dynindx, offset, addr, dynreloc_value, seg);
+             }
+           else
+             {
+               Elf_Internal_Rela outrel;
+
+               /* Add a dynamic relocation.  */
+               outrel.r_info = ELF32_R_INFO (h->dynindx, R_ARM_FUNCDESC);
+               outrel.r_offset = input_section->output_section->vma
+                 + input_section->output_offset + rel->r_offset;
+               outrel.r_addend = 0;
+               elf32_arm_add_dynreloc (output_bfd, info, srelgot, &outrel);
+             }
+         }
+      }
+      *unresolved_reloc_p = FALSE;
+      return bfd_reloc_ok;
+
+    case R_ARM_THM_BF16:
+      {
+       bfd_vma relocation;
+       bfd_vma upper_insn = bfd_get_16 (input_bfd, hit_data);
+       bfd_vma lower_insn = bfd_get_16 (input_bfd, hit_data + 2);
+
+       if (globals->use_rel)
+         {
+           bfd_vma immA  = (upper_insn & 0x001f);
+           bfd_vma immB  = (lower_insn & 0x07fe) >> 1;
+           bfd_vma immC  = (lower_insn & 0x0800) >> 11;
+           addend  = (immA << 12);
+           addend |= (immB << 2);
+           addend |= (immC << 1);
+           addend |= 1;
+           /* Sign extend.  */
+           signed_addend = (addend & 0x10000) ? addend - (1 << 17) : addend;
+         }
+
+       relocation  = value + signed_addend;
+       relocation -= (input_section->output_section->vma
+                      + input_section->output_offset
+                      + rel->r_offset);
+
+       /* Put RELOCATION back into the insn.  */
+       {
+         bfd_vma immA = (relocation & 0x0001f000) >> 12;
+         bfd_vma immB = (relocation & 0x00000ffc) >> 2;
+         bfd_vma immC = (relocation & 0x00000002) >> 1;
+
+         upper_insn = (upper_insn & 0xffe0) | immA;
+         lower_insn = (lower_insn & 0xf001) | (immC << 11) | (immB << 1);
+       }
+
+       /* 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 bfd_reloc_ok;
+      }
+
+    case R_ARM_THM_BF12:
+      {
+       bfd_vma relocation;
+       bfd_vma upper_insn = bfd_get_16 (input_bfd, hit_data);
+       bfd_vma lower_insn = bfd_get_16 (input_bfd, hit_data + 2);
+
+       if (globals->use_rel)
+         {
+           bfd_vma immA  = (upper_insn & 0x0001);
+           bfd_vma immB  = (lower_insn & 0x07fe) >> 1;
+           bfd_vma immC  = (lower_insn & 0x0800) >> 11;
+           addend  = (immA << 12);
+           addend |= (immB << 2);
+           addend |= (immC << 1);
+           addend |= 1;
+           /* Sign extend.  */
+           addend = (addend & 0x1000) ? addend - (1 << 13) : addend;
+           signed_addend = addend;
+         }
+
+       relocation  = value + signed_addend;
+       relocation -= (input_section->output_section->vma
+                      + input_section->output_offset
+                      + rel->r_offset);
+
+       /* Put RELOCATION back into the insn.  */
+       {
+         bfd_vma immA = (relocation & 0x00001000) >> 12;
+         bfd_vma immB = (relocation & 0x00000ffc) >> 2;
+         bfd_vma immC = (relocation & 0x00000002) >> 1;
+
+         upper_insn = (upper_insn & 0xfffe) | immA;
+         lower_insn = (lower_insn & 0xf001) | (immC << 11) | (immB << 1);
+       }
+
+       /* 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 bfd_reloc_ok;
+      }
+
+    case R_ARM_THM_BF18:
+      {
+       bfd_vma relocation;
+       bfd_vma upper_insn = bfd_get_16 (input_bfd, hit_data);
+       bfd_vma lower_insn = bfd_get_16 (input_bfd, hit_data + 2);
+
+       if (globals->use_rel)
+         {
+           bfd_vma immA  = (upper_insn & 0x007f);
+           bfd_vma immB  = (lower_insn & 0x07fe) >> 1;
+           bfd_vma immC  = (lower_insn & 0x0800) >> 11;
+           addend  = (immA << 12);
+           addend |= (immB << 2);
+           addend |= (immC << 1);
+           addend |= 1;
+           /* Sign extend.  */
+           addend = (addend & 0x40000) ? addend - (1 << 19) : addend;
+           signed_addend = addend;
+         }
+
+       relocation  = value + signed_addend;
+       relocation -= (input_section->output_section->vma
+                      + input_section->output_offset
+                      + rel->r_offset);
+
+       /* Put RELOCATION back into the insn.  */
+       {
+         bfd_vma immA = (relocation & 0x0007f000) >> 12;
+         bfd_vma immB = (relocation & 0x00000ffc) >> 2;
+         bfd_vma immC = (relocation & 0x00000002) >> 1;
+
+         upper_insn = (upper_insn & 0xff80) | immA;
+         lower_insn = (lower_insn & 0xf001) | (immC << 11) | (immB << 1);
+       }
+
+       /* 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 bfd_reloc_ok;
+      }
+
+    default:
+      return bfd_reloc_notsupported;
+    }
+}
+
+/* Add INCREMENT to the reloc (of type HOWTO) at ADDRESS.  */
+static void
+arm_add_to_rel (bfd *             abfd,
+               bfd_byte *         address,
+               reloc_howto_type * howto,
+               bfd_signed_vma     increment)
+{
+  bfd_signed_vma addend;
+
+  if (howto->type == R_ARM_THM_CALL
+      || howto->type == R_ARM_THM_JUMP24)
+    {
+      int upper_insn, lower_insn;
+      int upper, lower;
+
+      upper_insn = bfd_get_16 (abfd, address);
       lower_insn = bfd_get_16 (abfd, address + 2);
       upper = upper_insn & 0x7ff;
       lower = lower_insn & 0x7ff;
@@ -12249,13 +13105,16 @@ arm_add_to_rel (bfd *            abfd,
 
 #define IS_ARM_TLS_RELOC(R_TYPE)       \
   ((R_TYPE) == R_ARM_TLS_GD32          \
+   || (R_TYPE) == R_ARM_TLS_GD32_FDPIC  \
    || (R_TYPE) == R_ARM_TLS_LDO32      \
    || (R_TYPE) == R_ARM_TLS_LDM32      \
+   || (R_TYPE) == R_ARM_TLS_LDM32_FDPIC        \
    || (R_TYPE) == R_ARM_TLS_DTPOFF32   \
    || (R_TYPE) == R_ARM_TLS_DTPMOD32   \
    || (R_TYPE) == R_ARM_TLS_TPOFF32    \
    || (R_TYPE) == R_ARM_TLS_LE32       \
    || (R_TYPE) == R_ARM_TLS_IE32       \
+   || (R_TYPE) == R_ARM_TLS_IE32_FDPIC \
    || IS_ARM_TLS_GNU_RELOC (R_TYPE))
 
 /* Specific set of relocations for the gnu tls dialect.  */
@@ -12966,6 +13825,7 @@ bfd_arm_get_mach_from_attributes (bfd * abfd)
 
   switch (arch)
     {
+    case TAG_CPU_ARCH_PRE_V4: return bfd_mach_arm_3M;
     case TAG_CPU_ARCH_V4: return bfd_mach_arm_4;
     case TAG_CPU_ARCH_V4T: return bfd_mach_arm_4T;
     case TAG_CPU_ARCH_V5T: return bfd_mach_arm_5T;
@@ -13003,7 +13863,40 @@ bfd_arm_get_mach_from_attributes (bfd * abfd)
        return bfd_mach_arm_5TE;
       }
 
+    case TAG_CPU_ARCH_V5TEJ:
+       return bfd_mach_arm_5TEJ;
+    case TAG_CPU_ARCH_V6:
+       return bfd_mach_arm_6;
+    case TAG_CPU_ARCH_V6KZ:
+       return bfd_mach_arm_6KZ;
+    case TAG_CPU_ARCH_V6T2:
+       return bfd_mach_arm_6T2;
+    case TAG_CPU_ARCH_V6K:
+       return bfd_mach_arm_6K;
+    case TAG_CPU_ARCH_V7:
+       return bfd_mach_arm_7;
+    case TAG_CPU_ARCH_V6_M:
+       return bfd_mach_arm_6M;
+    case TAG_CPU_ARCH_V6S_M:
+       return bfd_mach_arm_6SM;
+    case TAG_CPU_ARCH_V7E_M:
+       return bfd_mach_arm_7EM;
+    case TAG_CPU_ARCH_V8:
+       return bfd_mach_arm_8;
+    case TAG_CPU_ARCH_V8R:
+       return bfd_mach_arm_8R;
+    case TAG_CPU_ARCH_V8M_BASE:
+       return bfd_mach_arm_8M_BASE;
+    case TAG_CPU_ARCH_V8M_MAIN:
+       return bfd_mach_arm_8M_MAIN;
+    case TAG_CPU_ARCH_V8_1M_MAIN:
+       return bfd_mach_arm_8_1M_MAIN;
+
     default:
+      /* Force entry to be added for any new known Tag_CPU_arch value.  */
+      BFD_ASSERT (arch > MAX_TAG_CPU_ARCH);
+
+      /* Unknown Tag_CPU_arch value.  */
       return bfd_mach_arm_unknown;
     }
 }
@@ -13410,6 +14303,31 @@ tag_cpu_arch_combine (bfd *ibfd, int oldtag, int *secondary_compat_out,
       T(V8M_MAIN),     /* V8-M BASELINE.  */
       T(V8M_MAIN)      /* V8-M MAINLINE.  */
     };
+  const int v8_1m_mainline[] =
+    {
+      -1,              /* PRE_V4.  */
+      -1,              /* V4.  */
+      -1,              /* V4T.  */
+      -1,              /* V5T.  */
+      -1,              /* V5TE.  */
+      -1,              /* V5TEJ.  */
+      -1,              /* V6.  */
+      -1,              /* V6KZ.  */
+      -1,              /* V6T2.  */
+      -1,              /* V6K.  */
+      T(V8_1M_MAIN),   /* V7.  */
+      T(V8_1M_MAIN),   /* V6_M.  */
+      T(V8_1M_MAIN),   /* V6S_M.  */
+      T(V8_1M_MAIN),   /* V7E_M.  */
+      -1,              /* V8.  */
+      -1,              /* V8R.  */
+      T(V8_1M_MAIN),   /* V8-M BASELINE.  */
+      T(V8_1M_MAIN),   /* V8-M MAINLINE.  */
+      -1,              /* Unused (18).  */
+      -1,              /* Unused (19).  */
+      -1,              /* Unused (20).  */
+      T(V8_1M_MAIN)    /* V8.1-M MAINLINE.  */
+    };
   const int v4t_plus_v6_m[] =
     {
       -1,              /* PRE_V4.  */
@@ -13430,6 +14348,10 @@ tag_cpu_arch_combine (bfd *ibfd, int oldtag, int *secondary_compat_out,
       -1,              /* V8R.  */
       T(V8M_BASE),     /* V8-M BASELINE.  */
       T(V8M_MAIN),     /* V8-M MAINLINE.  */
+      -1,              /* Unused (18).  */
+      -1,              /* Unused (19).  */
+      -1,              /* Unused (20).  */
+      T(V8_1M_MAIN),   /* V8.1-M MAINLINE.  */
       T(V4T_PLUS_V6_M) /* V4T plus V6_M.  */
     };
   const int *comb[] =
@@ -13444,6 +14366,10 @@ tag_cpu_arch_combine (bfd *ibfd, int oldtag, int *secondary_compat_out,
       v8r,
       v8m_baseline,
       v8m_mainline,
+      NULL,
+      NULL,
+      NULL,
+      v8_1m_mainline,
       /* Pseudo-architecture.  */
       v4t_plus_v6_m
     };
@@ -13724,6 +14650,7 @@ elf32_arm_merge_eabi_attributes (bfd *ibfd, struct bfd_link_info *info)
        case Tag_CPU_unaligned_access:
        case Tag_T2EE_use:
        case Tag_MPextension_use:
+       case Tag_MVE_arch:
          /* Use the largest value specified.  */
          if (in_attr[i].i > out_attr[i].i)
            out_attr[i].i = in_attr[i].i;
@@ -14268,7 +15195,13 @@ elf32_arm_print_private_bfd_data (bfd *abfd, void * ptr)
   if (flags & EF_ARM_RELEXEC)
     fprintf (file, _(" [relocatable executable]"));
 
-  flags &= ~EF_ARM_RELEXEC;
+  if (flags & EF_ARM_PIC)
+    fprintf (file, _(" [position independent]"));
+
+  if (elf_elfheader (abfd)->e_ident[EI_OSABI] == ELFOSABI_ARM_FDPIC)
+    fprintf (file, _(" [FDPIC ABI supplement]"));
+
+  flags &= ~ (EF_ARM_RELEXEC | EF_ARM_PIC);
 
   if (flags)
     fprintf (file, _("<Unrecognised flag bits set>"));
@@ -14424,10 +15357,60 @@ elf32_arm_check_relocs (bfd *abfd, struct bfd_link_info *info,
       r_type = elf32_arm_tls_transition (info, r_type, h);
       switch (r_type)
        {
+       case R_ARM_GOTOFFFUNCDESC:
+         {
+           if (h == NULL)
+             {
+               if (!elf32_arm_allocate_local_sym_info (abfd))
+                 return FALSE;
+               elf32_arm_local_fdpic_cnts(abfd)[r_symndx].gotofffuncdesc_cnt += 1;
+               elf32_arm_local_fdpic_cnts(abfd)[r_symndx].funcdesc_offset = -1;
+             }
+           else
+             {
+               eh->fdpic_cnts.gotofffuncdesc_cnt++;
+             }
+         }
+         break;
+
+       case R_ARM_GOTFUNCDESC:
+         {
+           if (h == NULL)
+             {
+               /* Such a relocation is not supposed to be generated
+                  by gcc on a static function. */
+               /* Anyway if needed it could be handled.  */
+               abort();
+             }
+           else
+             {
+               eh->fdpic_cnts.gotfuncdesc_cnt++;
+             }
+         }
+         break;
+
+       case R_ARM_FUNCDESC:
+         {
+           if (h == NULL)
+             {
+               if (!elf32_arm_allocate_local_sym_info (abfd))
+                 return FALSE;
+               elf32_arm_local_fdpic_cnts(abfd)[r_symndx].funcdesc_cnt += 1;
+               elf32_arm_local_fdpic_cnts(abfd)[r_symndx].funcdesc_offset = -1;
+             }
+           else
+             {
+               eh->fdpic_cnts.funcdesc_cnt++;
+             }
+         }
+         break;
+
          case R_ARM_GOT32:
          case R_ARM_GOT_PREL:
          case R_ARM_TLS_GD32:
+         case R_ARM_TLS_GD32_FDPIC:
          case R_ARM_TLS_IE32:
+         case R_ARM_TLS_IE32_FDPIC:
          case R_ARM_TLS_GOTDESC:
          case R_ARM_TLS_DESCSEQ:
          case R_ARM_THM_TLS_DESCSEQ:
@@ -14440,8 +15423,10 @@ elf32_arm_check_relocs (bfd *abfd, struct bfd_link_info *info,
              switch (r_type)
                {
                case R_ARM_TLS_GD32: tls_type = GOT_TLS_GD; break;
+               case R_ARM_TLS_GD32_FDPIC: tls_type = GOT_TLS_GD; break;
 
                case R_ARM_TLS_IE32: tls_type = GOT_TLS_IE; break;
+               case R_ARM_TLS_IE32_FDPIC: tls_type = GOT_TLS_IE; break;
 
                case R_ARM_TLS_GOTDESC:
                case R_ARM_TLS_CALL: case R_ARM_THM_TLS_CALL:
@@ -14499,7 +15484,8 @@ elf32_arm_check_relocs (bfd *abfd, struct bfd_link_info *info,
            /* Fall through.  */
 
          case R_ARM_TLS_LDM32:
-           if (r_type == R_ARM_TLS_LDM32)
+         case R_ARM_TLS_LDM32_FDPIC:
+           if (r_type == R_ARM_TLS_LDM32 || r_type == R_ARM_TLS_LDM32_FDPIC)
                htab->tls_ldm_got.refcount++;
            /* Fall through.  */
 
@@ -14565,7 +15551,8 @@ elf32_arm_check_relocs (bfd *abfd, struct bfd_link_info *info,
          case R_ARM_THM_MOVT_PREL:
 
            /* Should the interworking branches be listed here?  */
-           if ((bfd_link_pic (info) || htab->root.is_relocatable_executable)
+           if ((bfd_link_pic (info) || htab->root.is_relocatable_executable
+                || htab->fdpic_p)
                && (sec->flags & SEC_ALLOC) != 0)
              {
                if (h == NULL
@@ -14599,9 +15586,7 @@ 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:
-         BFD_ASSERT (h != NULL);
-         if (h != NULL
-             && !bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_offset))
+         if (!bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_offset))
            return FALSE;
          break;
        }
@@ -14718,6 +15703,18 @@ elf32_arm_check_relocs (bfd *abfd, struct bfd_link_info *info,
          if (elf32_arm_howto_from_type (r_type)->pc_relative)
            p->pc_count += 1;
          p->count += 1;
+         if (h == NULL && htab->fdpic_p && !bfd_link_pic(info)
+             && r_type != R_ARM_ABS32 && r_type != R_ARM_ABS32_NOI) {
+           /* Here we only support R_ARM_ABS32 and R_ARM_ABS32_NOI
+              that will become rofixup.  */
+           /* This is due to the fact that we suppose all will become rofixup.  */
+           fprintf(stderr, "FDPIC does not yet support %d relocation to become dynamic for executable\n", r_type);
+           _bfd_error_handler
+             (_("FDPIC does not yet support %s relocation"
+                " to become dynamic for executable"),
+              elf32_arm_howto_table_1[r_type].name);
+           abort();
+         }
        }
     }
 
@@ -15380,7 +16377,7 @@ allocate_dynrelocs_for_symbol (struct elf_link_hash_entry *h, void * inf)
 
       /* Make sure this symbol is output as a dynamic symbol.
         Undefined weak syms won't yet be marked as dynamic.  */
-      if (h->dynindx == -1 && !h->forced_local
+      if (htab->root.dynamic_sections_created && h->dynindx == -1 && !h->forced_local
          && h->root.type == bfd_link_hash_undefweak)
        {
          if (! bfd_elf_link_record_dynamic_symbol (info, h))
@@ -15415,15 +16412,17 @@ allocate_dynrelocs_for_symbol (struct elf_link_hash_entry *h, void * inf)
 
              if (tls_type & GOT_TLS_GD)
                {
-                 /* R_ARM_TLS_GD32 needs 2 consecutive GOT slots.  If
-                    the symbol is both GD and GDESC, got.offset may
-                    have been overwritten.  */
+                 /* R_ARM_TLS_GD32 and R_ARM_TLS_GD32_FDPIC need two
+                    consecutive GOT slots.  If the symbol is both GD
+                    and GDESC, got.offset may have been
+                    overwritten.  */
                  h->got.offset = s->size;
                  s->size += 8;
                }
 
              if (tls_type & GOT_TLS_IE)
-               /* R_ARM_TLS_IE32 needs one GOT slot.  */
+               /* R_ARM_TLS_IE32/R_ARM_TLS_IE32_FDPIC need one GOT
+                  slot.  */
                s->size += 4;
            }
 
@@ -15460,7 +16459,8 @@ allocate_dynrelocs_for_symbol (struct elf_link_hash_entry *h, void * inf)
              if ((tls_type & GOT_TLS_GD) && indx != 0)
                elf32_arm_allocate_dynrelocs (info, htab->root.srelgot, 1);
            }
-         else if (indx != -1 && !SYMBOL_REFERENCES_LOCAL (info, h))
+         else if (((indx != -1) || htab->fdpic_p)
+                  && !SYMBOL_REFERENCES_LOCAL (info, h))
            {
              if (htab->root.dynamic_sections_created)
                /* Reserve room for the GOT entry's R_ARM_GLOB_DAT relocation.  */
@@ -15477,11 +16477,110 @@ allocate_dynrelocs_for_symbol (struct elf_link_hash_entry *h, void * inf)
                       || h->root.type != bfd_link_hash_undefweak))
            /* Reserve room for the GOT entry's R_ARM_RELATIVE relocation.  */
            elf32_arm_allocate_dynrelocs (info, htab->root.srelgot, 1);
+         else if (htab->fdpic_p && tls_type == GOT_NORMAL)
+           /* Reserve room for rofixup for FDPIC executable.  */
+           /* TLS relocs do not need space since they are completely
+              resolved.  */
+           htab->srofixup->size += 4;
        }
     }
   else
     h->got.offset = (bfd_vma) -1;
 
+  /* FDPIC support.  */
+  if (eh->fdpic_cnts.gotofffuncdesc_cnt > 0)
+    {
+      /* Symbol musn't be exported.  */
+      if (h->dynindx != -1)
+       abort();
+
+      /* We only allocate one function descriptor with its associated relocation.  */
+      if (eh->fdpic_cnts.funcdesc_offset == -1)
+       {
+         asection *s = htab->root.sgot;
+
+         eh->fdpic_cnts.funcdesc_offset = s->size;
+         s->size += 8;
+         /* We will add an R_ARM_FUNCDESC_VALUE relocation or two rofixups.  */
+         if (bfd_link_pic(info))
+           elf32_arm_allocate_dynrelocs (info, htab->root.srelgot, 1);
+         else
+           htab->srofixup->size += 8;
+       }
+    }
+
+  if (eh->fdpic_cnts.gotfuncdesc_cnt > 0)
+    {
+      asection *s = htab->root.sgot;
+
+      if (htab->root.dynamic_sections_created && h->dynindx == -1
+         && !h->forced_local)
+       if (! bfd_elf_link_record_dynamic_symbol (info, h))
+         return FALSE;
+
+      if (h->dynindx == -1)
+       {
+         /* We only allocate one function descriptor with its associated relocation. q */
+         if (eh->fdpic_cnts.funcdesc_offset == -1)
+           {
+
+             eh->fdpic_cnts.funcdesc_offset = s->size;
+             s->size += 8;
+             /* We will add an R_ARM_FUNCDESC_VALUE relocation or two rofixups.  */
+             if (bfd_link_pic(info))
+               elf32_arm_allocate_dynrelocs (info, htab->root.srelgot, 1);
+             else
+               htab->srofixup->size += 8;
+           }
+       }
+
+      /* Add one entry into the GOT and a R_ARM_FUNCDESC or
+        R_ARM_RELATIVE/rofixup relocation on it.  */
+      eh->fdpic_cnts.gotfuncdesc_offset = s->size;
+      s->size += 4;
+      if (h->dynindx == -1 && !bfd_link_pic(info))
+       htab->srofixup->size += 4;
+      else
+       elf32_arm_allocate_dynrelocs (info, htab->root.srelgot, 1);
+    }
+
+  if (eh->fdpic_cnts.funcdesc_cnt > 0)
+    {
+      if (htab->root.dynamic_sections_created && h->dynindx == -1
+         && !h->forced_local)
+       if (! bfd_elf_link_record_dynamic_symbol (info, h))
+         return FALSE;
+
+      if (h->dynindx == -1)
+       {
+         /* We only allocate one function descriptor with its associated relocation.  */
+         if (eh->fdpic_cnts.funcdesc_offset == -1)
+           {
+             asection *s = htab->root.sgot;
+
+             eh->fdpic_cnts.funcdesc_offset = s->size;
+             s->size += 8;
+             /* We will add an R_ARM_FUNCDESC_VALUE relocation or two rofixups.  */
+             if (bfd_link_pic(info))
+               elf32_arm_allocate_dynrelocs (info, htab->root.srelgot, 1);
+             else
+               htab->srofixup->size += 8;
+           }
+       }
+      if (h->dynindx == -1 && !bfd_link_pic(info))
+       {
+         /* For FDPIC executable we replace R_ARM_RELATIVE with a rofixup.  */
+         htab->srofixup->size += 4 * eh->fdpic_cnts.funcdesc_cnt;
+       }
+      else
+       {
+         /* Will need one dynamic reloc per reference. will be either
+            R_ARM_FUNCDESC or R_ARM_RELATIVE for hidden symbols.  */
+         elf32_arm_allocate_dynrelocs (info, htab->root.srelgot,
+                                       eh->fdpic_cnts.funcdesc_cnt);
+       }
+    }
+
   /* Allocate stubs for exported Thumb functions on v4t.  */
   if (!htab->use_blx && h->dynindx != -1
       && h->def_regular
@@ -15524,7 +16623,7 @@ allocate_dynrelocs_for_symbol (struct elf_link_hash_entry *h, void * inf)
      space for pc-relative relocs that have become local due to symbol
      visibility changes.  */
 
-  if (bfd_link_pic (info) || htab->root.is_relocatable_executable)
+  if (bfd_link_pic (info) || htab->root.is_relocatable_executable || htab->fdpic_p)
     {
       /* Relocs that use pc_count are PC-relative forms, which will appear
         on something like ".long foo - ." or "movw REG, foo - .".  We want
@@ -15571,7 +16670,7 @@ allocate_dynrelocs_for_symbol (struct elf_link_hash_entry *h, void * inf)
 
          /* Make sure undefined weak symbols are output as a dynamic
             symbol in PIEs.  */
-         else if (h->dynindx == -1
+         else if (htab->root.dynamic_sections_created && h->dynindx == -1
                   && !h->forced_local)
            {
              if (! bfd_elf_link_record_dynamic_symbol (info, h))
@@ -15627,10 +16726,15 @@ allocate_dynrelocs_for_symbol (struct elf_link_hash_entry *h, void * inf)
   for (p = eh->dyn_relocs; p != NULL; p = p->next)
     {
       asection *sreloc = elf_section_data (p->sec)->sreloc;
+
       if (h->type == STT_GNU_IFUNC
          && eh->plt.noncall_refcount == 0
          && SYMBOL_REFERENCES_LOCAL (info, h))
        elf32_arm_allocate_irelocs (info, sreloc, p->count);
+      else if (h->dynindx != -1 && (!bfd_link_pic(info) || !info->symbolic || !h->def_regular))
+       elf32_arm_allocate_dynrelocs (info, sreloc, p->count);
+      else if (htab->fdpic_p && !bfd_link_pic(info))
+       htab->srofixup->size += 4 * p->count;
       else
        elf32_arm_allocate_dynrelocs (info, sreloc, p->count);
     }
@@ -15662,6 +16766,7 @@ maybe_set_textrel (struct elf_link_hash_entry *h, void *info_p)
       /* Not an error, just cut short the traversal.  */
       return FALSE;
     }
+
   return TRUE;
 }
 
@@ -15725,6 +16830,7 @@ elf32_arm_size_dynamic_sections (bfd * output_bfd ATTRIBUTE_UNUSED,
       asection *srel;
       bfd_boolean is_vxworks = htab->vxworks_p;
       unsigned int symndx;
+      struct fdpic_local *local_fdpic_cnts;
 
       if (! is_arm_elf (ibfd))
        continue;
@@ -15754,7 +16860,10 @@ elf32_arm_size_dynamic_sections (bfd * output_bfd ATTRIBUTE_UNUSED,
              else if (p->count != 0)
                {
                  srel = elf_section_data (p->sec)->sreloc;
-                 elf32_arm_allocate_dynrelocs (info, srel, p->count);
+                 if (htab->fdpic_p && !bfd_link_pic(info))
+                   htab->srofixup->size += 4 * p->count;
+                 else
+                   elf32_arm_allocate_dynrelocs (info, srel, p->count);
                  if ((p->sec->output_section->flags & SEC_READONLY) != 0)
                    info->flags |= DF_TEXTREL;
                }
@@ -15771,15 +16880,54 @@ elf32_arm_size_dynamic_sections (bfd * output_bfd ATTRIBUTE_UNUSED,
       local_iplt_ptr = elf32_arm_local_iplt (ibfd);
       local_tls_type = elf32_arm_local_got_tls_type (ibfd);
       local_tlsdesc_gotent = elf32_arm_local_tlsdesc_gotent (ibfd);
+      local_fdpic_cnts = elf32_arm_local_fdpic_cnts (ibfd);
       symndx = 0;
       s = htab->root.sgot;
       srel = htab->root.srelgot;
       for (; local_got < end_local_got;
           ++local_got, ++local_iplt_ptr, ++local_tls_type,
-          ++local_tlsdesc_gotent, ++symndx)
+          ++local_tlsdesc_gotent, ++symndx, ++local_fdpic_cnts)
        {
          *local_tlsdesc_gotent = (bfd_vma) -1;
          local_iplt = *local_iplt_ptr;
+
+         /* FDPIC support.  */
+         if (local_fdpic_cnts->gotofffuncdesc_cnt > 0)
+           {
+             if (local_fdpic_cnts->funcdesc_offset == -1)
+               {
+                 local_fdpic_cnts->funcdesc_offset = s->size;
+                 s->size += 8;
+
+                 /* We will add an R_ARM_FUNCDESC_VALUE relocation or two rofixups.  */
+                 if (bfd_link_pic(info))
+                   elf32_arm_allocate_dynrelocs (info, srel, 1);
+                 else
+                   htab->srofixup->size += 8;
+               }
+           }
+
+         if (local_fdpic_cnts->funcdesc_cnt > 0)
+           {
+             if (local_fdpic_cnts->funcdesc_offset == -1)
+               {
+                 local_fdpic_cnts->funcdesc_offset = s->size;
+                 s->size += 8;
+
+                 /* We will add an R_ARM_FUNCDESC_VALUE relocation or two rofixups.  */
+                 if (bfd_link_pic(info))
+                   elf32_arm_allocate_dynrelocs (info, srel, 1);
+                 else
+                   htab->srofixup->size += 8;
+               }
+
+             /* We will add n R_ARM_RELATIVE relocations or n rofixups.  */
+             if (bfd_link_pic(info))
+               elf32_arm_allocate_dynrelocs (info, srel, local_fdpic_cnts->funcdesc_cnt);
+             else
+               htab->srofixup->size += 4 * local_fdpic_cnts->funcdesc_cnt;
+           }
+
          if (local_iplt != NULL)
            {
              struct elf_dyn_relocs *p;
@@ -15854,13 +17002,15 @@ elf32_arm_size_dynamic_sections (bfd * output_bfd ATTRIBUTE_UNUSED,
                  && (local_iplt == NULL
                      || local_iplt->arm.noncall_refcount == 0))
                elf32_arm_allocate_irelocs (info, srel, 1);
-             else if (bfd_link_pic (info) || output_bfd->flags & DYNAMIC)
+             else if (bfd_link_pic (info) || output_bfd->flags & DYNAMIC || htab->fdpic_p)
                {
-                 if ((bfd_link_pic (info) && !(*local_tls_type & GOT_TLS_GDESC))
-                     || *local_tls_type & GOT_TLS_GD)
+                 if ((bfd_link_pic (info) && !(*local_tls_type & GOT_TLS_GDESC)))
                    elf32_arm_allocate_dynrelocs (info, srel, 1);
+                 else if (htab->fdpic_p && *local_tls_type & GOT_NORMAL)
+                   htab->srofixup->size += 4;
 
-                 if (bfd_link_pic (info) && *local_tls_type & GOT_TLS_GDESC)
+                 if ((bfd_link_pic (info) || htab->fdpic_p)
+                     && *local_tls_type & GOT_TLS_GDESC)
                    {
                      elf32_arm_allocate_dynrelocs (info,
                                                    htab->root.srelplt, 1);
@@ -15876,7 +17026,7 @@ elf32_arm_size_dynamic_sections (bfd * output_bfd ATTRIBUTE_UNUSED,
   if (htab->tls_ldm_got.refcount > 0)
     {
       /* Allocate two GOT entries and one dynamic relocation (if necessary)
-        for R_ARM_TLS_LDM32 relocations.  */
+        for R_ARM_TLS_LDM32/R_ARM_TLS_LDM32_FDPIC relocations.  */
       htab->tls_ldm_got.offset = htab->root.sgot->size;
       htab->root.sgot->size += 8;
       if (bfd_link_pic (info))
@@ -15885,6 +17035,11 @@ elf32_arm_size_dynamic_sections (bfd * output_bfd ATTRIBUTE_UNUSED,
   else
     htab->tls_ldm_got.offset = -1;
 
+  /* At the very end of the .rofixup section is a pointer to the GOT,
+     reserve space for it. */
+  if (htab->fdpic_p && htab->srofixup != NULL)
+    htab->srofixup->size += 4;
+
   /* Allocate global sym .plt and .got entries, and space for global
      sym dynamic relocs.  */
   elf_link_hash_traverse (& htab->root, allocate_dynrelocs_for_symbol, info);
@@ -15975,7 +17130,8 @@ elf32_arm_size_dynamic_sections (bfd * output_bfd ATTRIBUTE_UNUSED,
               && s != htab->root.iplt
               && s != htab->root.igotplt
               && s != htab->root.sdynbss
-              && s != htab->root.sdynrelro)
+              && s != htab->root.sdynrelro
+              && s != htab->srofixup)
        {
          /* It's not one of our sections, so don't allocate space.  */
          continue;
@@ -16081,6 +17237,9 @@ elf32_arm_always_size_sections (bfd *output_bfd,
                                struct bfd_link_info *info)
 {
   asection *tls_sec;
+  struct elf32_arm_link_hash_table *htab;
+
+  htab = elf32_arm_hash_table (info);
 
   if (bfd_link_relocatable (info))
     return TRUE;
@@ -16113,6 +17272,12 @@ elf32_arm_always_size_sections (bfd *output_bfd,
          (*bed->elf_backend_hide_symbol) (info, tlsbase, TRUE);
        }
     }
+
+  if (htab->fdpic_p && !bfd_link_relocatable (info)
+      && !bfd_elf_stack_segment_size (output_bfd, info,
+                                     "__stacksize", DEFAULT_STACK_SIZE))
+    return FALSE;
+
   return TRUE;
 }
 
@@ -16197,10 +17362,10 @@ elf32_arm_finish_dynamic_symbol (bfd * output_bfd,
     }
 
   /* Mark _DYNAMIC and _GLOBAL_OFFSET_TABLE_ as absolute.  On VxWorks,
-     the _GLOBAL_OFFSET_TABLE_ symbol is not absolute: it is relative
-     to the ".got" section.  */
+     and for FDPIC, the _GLOBAL_OFFSET_TABLE_ symbol is not absolute:
+     it is relative to the ".got" section.  */
   if (h == htab->root.hdynamic
-      || (!htab->vxworks_p && h == htab->root.hgot))
+      || (!htab->fdpic_p && !htab->vxworks_p && h == htab->root.hgot))
     sym->st_shndx = SHN_ABS;
 
   return TRUE;
@@ -16607,6 +17772,21 @@ elf32_arm_finish_dynamic_sections (bfd * output_bfd, struct bfd_link_info * info
       elf_section_data (sgot->output_section)->this_hdr.sh_entsize = 4;
     }
 
+  /* At the very end of the .rofixup section is a pointer to the GOT.  */
+  if (htab->fdpic_p && htab->srofixup != NULL)
+    {
+      struct elf_link_hash_entry *hgot = htab->root.hgot;
+
+      bfd_vma got_value = hgot->root.u.def.value
+       + hgot->root.u.def.section->output_section->vma
+       + hgot->root.u.def.section->output_offset;
+
+      arm_elf_add_rofixup(output_bfd, htab->srofixup, got_value);
+
+      /* Make sure we allocated and generated the same number of fixups.  */
+      BFD_ASSERT (htab->srofixup->reloc_count * 4 == htab->srofixup->size);
+    }
+
   return TRUE;
 }
 
@@ -16630,6 +17810,9 @@ elf32_arm_post_process_headers (bfd * abfd, struct bfd_link_info * link_info ATT
       globals = elf32_arm_hash_table (link_info);
       if (globals != NULL && globals->byteswap_code)
        i_ehdrp->e_flags |= EF_ARM_BE8;
+
+      if (globals->fdpic_p)
+       i_ehdrp->e_ident[EI_OSABI] |= ELFOSABI_ARM_FDPIC;
     }
 
   if (EF_ARM_EABI_VERSION (i_ehdrp->e_flags) == EF_ARM_EABI_VER5
@@ -16858,6 +18041,23 @@ elf32_arm_output_plt_map_1 (output_arch_syminfo *osi,
       if (!elf32_arm_output_map_sym (osi, ARM_MAP_ARM, addr))
        return FALSE;
     }
+  else if (htab->fdpic_p)
+    {
+      enum map_symbol_type type = using_thumb_only(htab)
+       ? ARM_MAP_THUMB
+       : ARM_MAP_ARM;
+
+      if (elf32_arm_plt_needs_thumb_stub_p (osi->info, arm_plt))
+       if (!elf32_arm_output_map_sym (osi, ARM_MAP_THUMB, addr - 4))
+         return FALSE;
+      if (!elf32_arm_output_map_sym (osi, type, addr))
+       return FALSE;
+      if (!elf32_arm_output_map_sym (osi, ARM_MAP_DATA, addr + 16))
+       return FALSE;
+      if (htab->plt_entry_size == 4 * ARRAY_SIZE(elf32_arm_fdpic_plt_entry))
+       if (!elf32_arm_output_map_sym (osi, type, addr + 24))
+         return FALSE;
+    }
   else if (using_thumb_only (htab))
     {
       if (!elf32_arm_output_map_sym (osi, ARM_MAP_THUMB, addr))
@@ -17214,7 +18414,7 @@ elf32_arm_output_arch_local_syms (bfd *output_bfd,
          if (!elf32_arm_output_map_sym (&osi, ARM_MAP_ARM, 0))
            return FALSE;
        }
-      else if (using_thumb_only (htab))
+      else if (using_thumb_only (htab) && !htab->fdpic_p)
        {
          if (!elf32_arm_output_map_sym (&osi, ARM_MAP_THUMB, 0))
            return FALSE;
@@ -17223,7 +18423,7 @@ elf32_arm_output_arch_local_syms (bfd *output_bfd,
          if (!elf32_arm_output_map_sym (&osi, ARM_MAP_THUMB, 16))
            return FALSE;
        }
-      else if (!htab->symbian_p)
+      else if (!htab->symbian_p && !htab->fdpic_p)
        {
          if (!elf32_arm_output_map_sym (&osi, ARM_MAP_ARM, 0))
            return FALSE;
@@ -18811,11 +20011,6 @@ elf32_arm_add_symbol_hook (bfd *abfd, struct bfd_link_info *info,
                           Elf_Internal_Sym *sym, const char **namep,
                           flagword *flagsp, asection **secp, bfd_vma *valp)
 {
-  if (ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC
-      && (abfd->flags & DYNAMIC) == 0
-      && bfd_get_flavour (info->output_bfd) == bfd_target_elf_flavour)
-    elf_tdata (info->output_bfd)->has_gnu_symbols |= elf_gnu_symbol_ifunc;
-
   if (elf32_arm_hash_table (info) == NULL)
     return FALSE;
 
@@ -19403,6 +20598,78 @@ elf32_arm_nacl_plt_sym_val (bfd_vma i, const asection *plt,
 #define ELF_COMMONPAGESIZE             0x1000
 
 
+/* FDPIC Targets.  */
+
+#undef  TARGET_LITTLE_SYM
+#define TARGET_LITTLE_SYM              arm_elf32_fdpic_le_vec
+#undef  TARGET_LITTLE_NAME
+#define TARGET_LITTLE_NAME             "elf32-littlearm-fdpic"
+#undef  TARGET_BIG_SYM
+#define TARGET_BIG_SYM                 arm_elf32_fdpic_be_vec
+#undef  TARGET_BIG_NAME
+#define TARGET_BIG_NAME                        "elf32-bigarm-fdpic"
+#undef elf_match_priority
+#define elf_match_priority             128
+#undef ELF_OSABI
+#define ELF_OSABI              ELFOSABI_ARM_FDPIC
+
+/* Like elf32_arm_link_hash_table_create -- but overrides
+   appropriately for FDPIC.  */
+
+static struct bfd_link_hash_table *
+elf32_arm_fdpic_link_hash_table_create (bfd *abfd)
+{
+  struct bfd_link_hash_table *ret;
+
+  ret = elf32_arm_link_hash_table_create (abfd);
+  if (ret)
+    {
+      struct elf32_arm_link_hash_table *htab = (struct elf32_arm_link_hash_table *) ret;
+
+      htab->fdpic_p = 1;
+    }
+  return ret;
+}
+
+/* We need dynamic symbols for every section, since segments can
+   relocate independently.  */
+static bfd_boolean
+elf32_arm_fdpic_omit_section_dynsym (bfd *output_bfd ATTRIBUTE_UNUSED,
+                                   struct bfd_link_info *info
+                                   ATTRIBUTE_UNUSED,
+                                   asection *p ATTRIBUTE_UNUSED)
+{
+  switch (elf_section_data (p)->this_hdr.sh_type)
+    {
+    case SHT_PROGBITS:
+    case SHT_NOBITS:
+      /* If sh_type is yet undecided, assume it could be
+        SHT_PROGBITS/SHT_NOBITS.  */
+    case SHT_NULL:
+      return FALSE;
+
+      /* There shouldn't be section relative relocations
+        against any other section.  */
+    default:
+      return TRUE;
+    }
+}
+
+#undef  elf32_bed
+#define elf32_bed                              elf32_arm_fdpic_bed
+
+#undef  bfd_elf32_bfd_link_hash_table_create
+#define bfd_elf32_bfd_link_hash_table_create   elf32_arm_fdpic_link_hash_table_create
+
+#undef elf_backend_omit_section_dynsym
+#define elf_backend_omit_section_dynsym                elf32_arm_fdpic_omit_section_dynsym
+
+#include "elf32-target.h"
+
+#undef elf_match_priority
+#undef ELF_OSABI
+#undef elf_backend_omit_section_dynsym
+
 /* VxWorks Targets.  */
 
 #undef TARGET_LITTLE_SYM
This page took 0.052385 seconds and 4 git commands to generate.