2005-10-28 Dave Brolley <brolley@redhat.com>
[deliverable/binutils-gdb.git] / bfd / elf32-arm.c
index ae52ab2a774af48b181c1fa8d9912c4bca089b70..6f220e9631beea651e7407d8673ad76dd755cb88 100644 (file)
 
    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
-   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
 
-#include "elf/arm.h"
 #include "bfd.h"
 #include "sysdep.h"
 #include "libbfd.h"
 #include "elf-bfd.h"
+#include "elf/arm.h"
 
 #ifndef NUM_ELEM
 #define NUM_ELEM(a)  (sizeof (a) / (sizeof (a)[0]))
 #define ARM_ELF_ABI_VERSION            0
 #define ARM_ELF_OS_ABI_VERSION         ELFOSABI_ARM
 
-static reloc_howto_type * elf32_arm_reloc_type_lookup
-  PARAMS ((bfd * abfd, bfd_reloc_code_real_type code));
-static bfd_boolean elf32_arm_nabi_grok_prstatus
-  PARAMS ((bfd *abfd, Elf_Internal_Note *note));
-static bfd_boolean elf32_arm_nabi_grok_psinfo
-  PARAMS ((bfd *abfd, Elf_Internal_Note *note));
-
 /* Note: code such as elf32_arm_reloc_type_lookup expect to use e.g.
    R_ARM_PC24 as an index into this, and find the R_ARM_PC24 HOWTO
    in that slot.  */
 
-static reloc_howto_type elf32_arm_howto_table[] =
+static reloc_howto_type elf32_arm_howto_table_1[] =
 {
   /* No relocation */
   HOWTO (R_ARM_NONE,           /* type */
@@ -106,7 +99,7 @@ static reloc_howto_type elf32_arm_howto_table[] =
         0xffffffff,            /* dst_mask */
         TRUE),                 /* pcrel_offset */
 
-  /* 8 bit absolute */
+  /* 8 bit absolute - R_ARM_LDR_PC_G0 in AAELF */
   HOWTO (R_ARM_PC13,           /* type */
         0,                     /* rightshift */
         0,                     /* size (0 = byte, 1 = short, 2 = long) */
@@ -194,7 +187,8 @@ static reloc_howto_type elf32_arm_howto_table[] =
         0xffffffff,            /* dst_mask */
         FALSE),                /* pcrel_offset */
 
-  HOWTO (R_ARM_THM_PC22,       /* type */
+  /* FIXME: Has two more bits of offset in Thumb32.  */
+  HOWTO (R_ARM_THM_CALL,       /* type */
         1,                     /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         23,                    /* bitsize */
@@ -202,7 +196,7 @@ static reloc_howto_type elf32_arm_howto_table[] =
         0,                     /* bitpos */
         complain_overflow_signed,/* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
-        "R_ARM_THM_PC22",      /* name */
+        "R_ARM_THM_CALL",      /* name */
         FALSE,                 /* partial_inplace */
         0x07ff07ff,            /* src_mask */
         0x07ff07ff,            /* dst_mask */
@@ -222,19 +216,19 @@ static reloc_howto_type elf32_arm_howto_table[] =
         0x000000ff,            /* dst_mask */
         TRUE),                 /* pcrel_offset */
 
-  HOWTO (R_ARM_AMP_VCALL9,     /* type */
+  HOWTO (R_ARM_BREL_ADJ,       /* type */
         1,                     /* rightshift */
         1,                     /* size (0 = byte, 1 = short, 2 = long) */
-        8,                     /* bitsize */
-        TRUE,                  /* pc_relative */
+        32,                    /* bitsize */
+        FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_signed,/* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
-        "R_ARM_AMP_VCALL9",    /* name */
+        "R_ARM_BREL_ADJ",      /* name */
         FALSE,                 /* partial_inplace */
-        0x000000ff,            /* src_mask */
-        0x000000ff,            /* dst_mask */
-        TRUE),                 /* pcrel_offset */
+        0xffffffff,            /* src_mask */
+        0xffffffff,            /* dst_mask */
+        FALSE),                /* pcrel_offset */
 
   HOWTO (R_ARM_SWI24,          /* type */
         0,                     /* rightshift */
@@ -396,7 +390,7 @@ static reloc_howto_type elf32_arm_howto_table[] =
          0xffffffff,           /* dst_mask */
          FALSE),                /* pcrel_offset */
 
-  HOWTO (R_ARM_GOTOFF,         /* type */
+  HOWTO (R_ARM_GOTOFF32,       /* type */
          0,                     /* rightshift */
          2,                     /* size (0 = byte, 1 = short, 2 = long) */
          32,                    /* bitsize */
@@ -404,7 +398,7 @@ static reloc_howto_type elf32_arm_howto_table[] =
          0,                     /* bitpos */
          complain_overflow_bitfield,/* complain_on_overflow */
          bfd_elf_generic_reloc, /* special_function */
-         "R_ARM_GOTOFF",       /* name */
+         "R_ARM_GOTOFF32",     /* name */
          TRUE,                 /* partial_inplace */
          0xffffffff,           /* src_mask */
          0xffffffff,           /* dst_mask */
@@ -441,13 +435,13 @@ static reloc_howto_type elf32_arm_howto_table[] =
   HOWTO (R_ARM_PLT32,          /* type */
          2,                     /* rightshift */
          2,                     /* size (0 = byte, 1 = short, 2 = long) */
-         26,                    /* bitsize */
+         24,                    /* bitsize */
          TRUE,                 /* pc_relative */
          0,                     /* bitpos */
          complain_overflow_bitfield,/* complain_on_overflow */
          bfd_elf_generic_reloc, /* special_function */
          "R_ARM_PLT32",                /* name */
-         TRUE,                 /* partial_inplace */
+         FALSE,                        /* partial_inplace */
          0x00ffffff,           /* src_mask */
          0x00ffffff,           /* dst_mask */
          TRUE),                        /* pcrel_offset */
@@ -480,32 +474,32 @@ static reloc_howto_type elf32_arm_howto_table[] =
         0x00ffffff,            /* dst_mask */
         TRUE),                 /* pcrel_offset */
 
-  HOWTO (R_ARM_NONE,           /* type */
-        0,                     /* rightshift */
-        0,                     /* size (0 = byte, 1 = short, 2 = long) */
-        0,                     /* bitsize */
-        FALSE,                 /* pc_relative */
+  HOWTO (R_ARM_THM_JUMP24,     /* type */
+        1,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        24,                    /* bitsize */
+        TRUE,                  /* pc_relative */
         0,                     /* bitpos */
-        complain_overflow_dont,/* complain_on_overflow */
+        complain_overflow_signed,/* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
-        "R_ARM_unknown_30",    /* name */
+        "R_ARM_THM_JUMP24",    /* name */
         FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0,                     /* dst_mask */
-        FALSE),                /* pcrel_offset */
+        0x07ff2fff,            /* src_mask */
+        0x07ff2fff,            /* dst_mask */
+        TRUE),                 /* pcrel_offset */
 
-  HOWTO (R_ARM_NONE,           /* type */
+  HOWTO (R_ARM_BASE_ABS,       /* type */
         0,                     /* rightshift */
-        0,                     /* size (0 = byte, 1 = short, 2 = long) */
-        0,                     /* bitsize */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        32,                    /* bitsize */
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont,/* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
-        "R_ARM_unknown_31",    /* name */
+        "R_ARM_BASE_ABS",      /* name */
         FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0,                     /* dst_mask */
+        0xffffffff,            /* src_mask */
+        0xffffffff,            /* dst_mask */
         FALSE),                /* pcrel_offset */
 
   HOWTO (R_ARM_ALU_PCREL7_0,   /* type */
@@ -661,275 +655,625 @@ static reloc_howto_type elf32_arm_howto_table[] =
         0x7fffffff,            /* src_mask */
         0x7fffffff,            /* dst_mask */
         TRUE),                 /* pcrel_offset */
-};
-
-static reloc_howto_type elf32_arm_tls_gd32_howto = 
-  HOWTO (R_ARM_TLS_GD32,       /* type */
-         0,                     /* rightshift */
-         2,                     /* size (0 = byte, 1 = short, 2 = long) */
-         32,                    /* bitsize */
-         FALSE,                 /* pc_relative */
-         0,                     /* bitpos */
-         complain_overflow_bitfield,/* complain_on_overflow */
-         NULL,                 /* special_function */
-         "R_ARM_TLS_GD32",     /* name */
-         TRUE,                 /* partial_inplace */
-         0xffffffff,           /* src_mask */
-         0xffffffff,           /* dst_mask */
-         FALSE);                /* pcrel_offset */
-
-static reloc_howto_type elf32_arm_tls_ldo32_howto = 
-  HOWTO (R_ARM_TLS_LDO32,      /* 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_LDO32",    /* name */
-         TRUE,                 /* partial_inplace */
-         0xffffffff,           /* src_mask */
-         0xffffffff,           /* dst_mask */
-         FALSE);                /* pcrel_offset */
-
-static reloc_howto_type elf32_arm_tls_ldm32_howto = 
-  HOWTO (R_ARM_TLS_LDM32,      /* 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",    /* name */
-         TRUE,                 /* partial_inplace */
-         0xffffffff,           /* src_mask */
-         0xffffffff,           /* dst_mask */
-         FALSE);                /* pcrel_offset */
-
-static reloc_howto_type elf32_arm_tls_le32_howto = 
-  HOWTO (R_ARM_TLS_LE32,       /* 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_LE32",     /* name */
-         TRUE,                 /* partial_inplace */
-         0xffffffff,           /* src_mask */
-         0xffffffff,           /* dst_mask */
-         FALSE);                /* pcrel_offset */
-
-static reloc_howto_type elf32_arm_tls_ie32_howto = 
-  HOWTO (R_ARM_TLS_IE32,       /* type */
-         0,                     /* rightshift */
-         2,                     /* size (0 = byte, 1 = short, 2 = long) */
-         32,                    /* bitsize */
-         FALSE,                  /* pc_relative */
-         0,                     /* bitpos */
-         complain_overflow_bitfield,/* complain_on_overflow */
-         NULL,                 /* special_function */
-         "R_ARM_TLS_IE32",     /* name */
-         TRUE,                 /* partial_inplace */
-         0xffffffff,           /* src_mask */
-         0xffffffff,           /* dst_mask */
-         FALSE);                /* pcrel_offset */
-
-  /* GNU extension to record C++ vtable hierarchy */
-static reloc_howto_type elf32_arm_vtinherit_howto =
-  HOWTO (R_ARM_GNU_VTINHERIT, /* type */
-         0,                     /* rightshift */
-         2,                     /* size (0 = byte, 1 = short, 2 = long) */
-         0,                     /* bitsize */
-         FALSE,                 /* pc_relative */
-         0,                     /* bitpos */
-         complain_overflow_dont, /* complain_on_overflow */
-         NULL,                  /* special_function */
-         "R_ARM_GNU_VTINHERIT", /* name */
-         FALSE,                 /* partial_inplace */
-         0,                     /* src_mask */
-         0,                     /* dst_mask */
-         FALSE);                /* pcrel_offset */
 
-  /* GNU extension to record C++ vtable member usage */
-static reloc_howto_type elf32_arm_vtentry_howto =
-  HOWTO (R_ARM_GNU_VTENTRY,     /* type */
-         0,                     /* rightshift */
-         2,                     /* size (0 = byte, 1 = short, 2 = long) */
-         0,                     /* bitsize */
-         FALSE,                 /* pc_relative */
-         0,                     /* bitpos */
-         complain_overflow_dont, /* complain_on_overflow */
-         _bfd_elf_rel_vtable_reloc_fn,  /* special_function */
-         "R_ARM_GNU_VTENTRY",   /* name */
-         FALSE,                 /* partial_inplace */
-         0,                     /* src_mask */
-         0,                     /* dst_mask */
-         FALSE);                /* pcrel_offset */
+  HOWTO (R_ARM_MOVW_ABS_NC,    /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        16,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont,/* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_ARM_MOVW_ABS_NC",   /* name */
+        FALSE,                 /* partial_inplace */
+        0x0000ffff,            /* src_mask */
+        0x0000ffff,            /* dst_mask */
+        FALSE),                /* pcrel_offset */
 
-  /* 12 bit pc relative */
-static reloc_howto_type elf32_arm_thm_pc11_howto =
-  HOWTO (R_ARM_THM_PC11,       /* type */
-        1,                     /* rightshift */
-        1,                     /* size (0 = byte, 1 = short, 2 = long) */
-        11,                    /* bitsize */
-        TRUE,                  /* pc_relative */
+  HOWTO (R_ARM_MOVT_ABS,       /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        16,                    /* bitsize */
+        FALSE,                 /* pc_relative */
         0,                     /* bitpos */
-        complain_overflow_signed,      /* complain_on_overflow */
+        complain_overflow_bitfield,/* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
-        "R_ARM_THM_PC11",      /* name */
+        "R_ARM_MOVT_ABS",      /* name */
         FALSE,                 /* partial_inplace */
-        0x000007ff,            /* src_mask */
-        0x000007ff,            /* dst_mask */
-        TRUE);                 /* pcrel_offset */
+        0x0000ffff,            /* src_mask */
+        0x0000ffff,            /* dst_mask */
+        FALSE),                /* pcrel_offset */
 
-  /* 12 bit pc relative */
-static reloc_howto_type elf32_arm_thm_pc9_howto =
-  HOWTO (R_ARM_THM_PC9,                /* type */
-        1,                     /* rightshift */
-        1,                     /* size (0 = byte, 1 = short, 2 = long) */
-        8,                     /* bitsize */
+  HOWTO (R_ARM_MOVW_PREL_NC,   /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        16,                    /* bitsize */
         TRUE,                  /* pc_relative */
         0,                     /* bitpos */
-        complain_overflow_signed,      /* complain_on_overflow */
+        complain_overflow_dont,/* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
-        "R_ARM_THM_PC9",       /* name */
+        "R_ARM_MOVW_PREL_NC",  /* name */
         FALSE,                 /* partial_inplace */
-        0x000000ff,            /* src_mask */
-        0x000000ff,            /* dst_mask */
-        TRUE);                 /* pcrel_offset */
+        0x0000ffff,            /* src_mask */
+        0x0000ffff,            /* dst_mask */
+        TRUE),                 /* pcrel_offset */
 
-/* Place relative GOT-indirect.  */
-static reloc_howto_type elf32_arm_got_prel =
-  HOWTO (R_ARM_GOT_PREL,       /* type */
+  HOWTO (R_ARM_MOVT_PREL,      /* type */
         0,                     /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        32,                    /* bitsize */
+        16,                    /* bitsize */
         TRUE,                  /* pc_relative */
         0,                     /* bitpos */
-        complain_overflow_dont,        /* complain_on_overflow */
+        complain_overflow_bitfield,/* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
-        "R_ARM_GOT_PREL",      /* name */
+        "R_ARM_MOVT_PREL",     /* name */
         FALSE,                 /* partial_inplace */
-        0xffffffff,            /* src_mask */
-        0xffffffff,            /* dst_mask */
-        TRUE);                 /* pcrel_offset */
+        0x0000ffff,            /* src_mask */
+        0x0000ffff,            /* dst_mask */
+        TRUE),                 /* pcrel_offset */
 
-/* Currently unused relocations.  */
-static reloc_howto_type elf32_arm_r_howto[4] =
-{
-  HOWTO (R_ARM_RREL32,         /* type */
+  HOWTO (R_ARM_THM_MOVW_ABS_NC,        /* type */
         0,                     /* rightshift */
-        0,                     /* size (0 = byte, 1 = short, 2 = long) */
-        0,                     /* bitsize */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        16,                    /* bitsize */
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont,/* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
-        "R_ARM_RREL32",        /* name */
+        "R_ARM_THM_MOVW_ABS_NC",/* name */
         FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0,                     /* dst_mask */
+        0x040f70ff,            /* src_mask */
+        0x040f70ff,            /* dst_mask */
         FALSE),                /* pcrel_offset */
 
-  HOWTO (R_ARM_RABS32,         /* type */
+  HOWTO (R_ARM_THM_MOVT_ABS,   /* type */
         0,                     /* rightshift */
-        0,                     /* size (0 = byte, 1 = short, 2 = long) */
-        0,                     /* bitsize */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        16,                    /* bitsize */
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
-        complain_overflow_dont,/* complain_on_overflow */
+        complain_overflow_bitfield,/* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
-        "R_ARM_RABS32",        /* name */
+        "R_ARM_THM_MOVT_ABS",  /* name */
         FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0,                     /* dst_mask */
+        0x040f70ff,            /* src_mask */
+        0x040f70ff,            /* dst_mask */
         FALSE),                /* pcrel_offset */
 
-  HOWTO (R_ARM_RPC24,          /* type */
+  HOWTO (R_ARM_THM_MOVW_PREL_NC,/* type */
         0,                     /* rightshift */
-        0,                     /* size (0 = byte, 1 = short, 2 = long) */
-        0,                     /* bitsize */
-        FALSE,                 /* pc_relative */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        16,                    /* bitsize */
+        TRUE,                  /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont,/* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
-        "R_ARM_RPC24",         /* name */
+        "R_ARM_THM_MOVW_PREL_NC",/* name */
         FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0,                     /* dst_mask */
-        FALSE),                /* pcrel_offset */
+        0x040f70ff,            /* src_mask */
+        0x040f70ff,            /* dst_mask */
+        TRUE),                 /* pcrel_offset */
 
-  HOWTO (R_ARM_RBASE,          /* type */
+  HOWTO (R_ARM_THM_MOVT_PREL,  /* type */
         0,                     /* rightshift */
-        0,                     /* size (0 = byte, 1 = short, 2 = long) */
-        0,                     /* bitsize */
-        FALSE,                 /* pc_relative */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        16,                    /* bitsize */
+        TRUE,                  /* pc_relative */
         0,                     /* bitpos */
-        complain_overflow_dont,/* complain_on_overflow */
+        complain_overflow_bitfield,/* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
-        "R_ARM_RBASE",         /* name */
+        "R_ARM_THM_MOVT_PREL", /* name */
         FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0,                     /* dst_mask */
-        FALSE)                 /* pcrel_offset */
-};
-
-static reloc_howto_type *
-elf32_arm_howto_from_type (unsigned int r_type)
-{
-  if (r_type < NUM_ELEM (elf32_arm_howto_table))
-    return &elf32_arm_howto_table[r_type];
-    
-  switch (r_type)
-    {
-    case R_ARM_GOT_PREL:
-      return &elf32_arm_got_prel;
-
-    case R_ARM_GNU_VTINHERIT:
-      return &elf32_arm_vtinherit_howto;
+        0x040f70ff,            /* src_mask */
+        0x040f70ff,            /* dst_mask */
+        TRUE),                 /* pcrel_offset */
 
-    case R_ARM_GNU_VTENTRY:
-      return &elf32_arm_vtentry_howto;
+  HOWTO (R_ARM_THM_JUMP19,     /* type */
+        1,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        19,                    /* bitsize */
+        TRUE,                  /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_signed,/* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_ARM_THM_JUMP19",    /* name */
+        FALSE,                 /* partial_inplace */
+        0x043f2fff,            /* src_mask */
+        0x043f2fff,            /* dst_mask */
+        TRUE),                 /* pcrel_offset */
 
-    case R_ARM_THM_PC11:
-      return &elf32_arm_thm_pc11_howto;
+  HOWTO (R_ARM_THM_JUMP6,      /* type */
+        1,                     /* rightshift */
+        1,                     /* size (0 = byte, 1 = short, 2 = long) */
+        6,                     /* bitsize */
+        TRUE,                  /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_unsigned,/* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_ARM_THM_JUMP6",     /* name */
+        FALSE,                 /* partial_inplace */
+        0x02f8,                /* src_mask */
+        0x02f8,                /* dst_mask */
+        TRUE),                 /* pcrel_offset */
 
-    case R_ARM_THM_PC9:
-      return &elf32_arm_thm_pc9_howto;
-      
-    case R_ARM_TLS_GD32:
-      return &elf32_arm_tls_gd32_howto;
-      break;
+  /* These are declared as 13-bit signed relocations because we can
+     address -4095 .. 4095(base) by altering ADDW to SUBW or vice
+     versa.  */
+  HOWTO (R_ARM_THM_ALU_PREL_11_0,/* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        13,                    /* bitsize */
+        TRUE,                  /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_signed,/* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_ARM_THM_ALU_PREL_11_0",/* name */
+        FALSE,                 /* partial_inplace */
+        0x040070ff,            /* src_mask */
+        0x040070ff,            /* dst_mask */
+        TRUE),                 /* pcrel_offset */
 
-    case R_ARM_TLS_LDO32:
-      return &elf32_arm_tls_ldo32_howto;
-      break;
+  HOWTO (R_ARM_THM_PC12,       /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        13,                    /* bitsize */
+        TRUE,                  /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_signed,/* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_ARM_THM_PC12",      /* name */
+        FALSE,                 /* partial_inplace */
+        0x040070ff,            /* src_mask */
+        0x040070ff,            /* dst_mask */
+        TRUE),                 /* pcrel_offset */
 
-    case R_ARM_TLS_LDM32:
-      return &elf32_arm_tls_ldm32_howto;
-      break;
+  HOWTO (R_ARM_ABS32_NOI,      /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        32,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont,/* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_ARM_ABS32_NOI",     /* name */
+        FALSE,                 /* partial_inplace */
+        0xffffffff,            /* src_mask */
+        0xffffffff,            /* dst_mask */
+        FALSE),                /* pcrel_offset */
 
-    case R_ARM_TLS_IE32:
-      return &elf32_arm_tls_ie32_howto;
-      break;
+  HOWTO (R_ARM_REL32_NOI,      /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        32,                    /* bitsize */
+        TRUE,                  /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont,/* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_ARM_REL32_NOI",     /* name */
+        FALSE,                 /* partial_inplace */
+        0xffffffff,            /* src_mask */
+        0xffffffff,            /* dst_mask */
+        FALSE),                /* pcrel_offset */
+};
 
-    case R_ARM_TLS_LE32:
-      return &elf32_arm_tls_le32_howto;
-      break;
+/* Relocations 57 .. 83 are the "group relocations" which we do not
+   support.  */
 
-    case R_ARM_RREL32:
-    case R_ARM_RABS32:
-    case R_ARM_RPC24:
-    case R_ARM_RBASE:
-      return &elf32_arm_r_howto[r_type - R_ARM_RREL32];
+static reloc_howto_type elf32_arm_howto_table_2[] =
+{
+  HOWTO (R_ARM_MOVW_BREL_NC,   /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        16,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont,/* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_ARM_MOVW_BREL_NC",  /* name */
+        FALSE,                 /* partial_inplace */
+        0x0000ffff,            /* src_mask */
+        0x0000ffff,            /* dst_mask */
+        FALSE),                /* pcrel_offset */
 
-    default:
-      return NULL;
-    }
+  HOWTO (R_ARM_MOVT_BREL,      /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        16,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_bitfield,/* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_ARM_MOVT_BREL",     /* name */
+        FALSE,                 /* partial_inplace */
+        0x0000ffff,            /* src_mask */
+        0x0000ffff,            /* dst_mask */
+        FALSE),                /* pcrel_offset */
+
+  HOWTO (R_ARM_MOVW_BREL,      /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        16,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont,/* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_ARM_MOVW_BREL",     /* name */
+        FALSE,                 /* partial_inplace */
+        0x0000ffff,            /* src_mask */
+        0x0000ffff,            /* dst_mask */
+        FALSE),                /* pcrel_offset */
+
+  HOWTO (R_ARM_THM_MOVW_BREL_NC,/* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        16,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont,/* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_ARM_THM_MOVW_BREL_NC",/* name */
+        FALSE,                 /* partial_inplace */
+        0x040f70ff,            /* src_mask */
+        0x040f70ff,            /* dst_mask */
+        FALSE),                /* pcrel_offset */
+
+  HOWTO (R_ARM_THM_MOVT_BREL,  /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        16,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_bitfield,/* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_ARM_THM_MOVT_BREL", /* name */
+        FALSE,                 /* partial_inplace */
+        0x040f70ff,            /* src_mask */
+        0x040f70ff,            /* dst_mask */
+        FALSE),                /* pcrel_offset */
+
+  HOWTO (R_ARM_THM_MOVW_BREL,  /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        16,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont,/* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_ARM_THM_MOVW_BREL", /* name */
+        FALSE,                 /* partial_inplace */
+        0x040f70ff,            /* src_mask */
+        0x040f70ff,            /* dst_mask */
+        FALSE),                /* pcrel_offset */
+
+  EMPTY_HOWTO (90),   /* unallocated */
+  EMPTY_HOWTO (91),
+  EMPTY_HOWTO (92),
+  EMPTY_HOWTO (93),
+
+  HOWTO (R_ARM_PLT32_ABS,      /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        32,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont,/* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_ARM_PLT32_ABS",     /* name */
+        FALSE,                 /* partial_inplace */
+        0xffffffff,            /* src_mask */
+        0xffffffff,            /* dst_mask */
+        FALSE),                /* pcrel_offset */
+
+  HOWTO (R_ARM_GOT_ABS,                /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        32,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont,/* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_ARM_GOT_ABS",       /* name */
+        FALSE,                 /* partial_inplace */
+        0xffffffff,            /* src_mask */
+        0xffffffff,            /* dst_mask */
+        FALSE),                        /* pcrel_offset */
+
+  HOWTO (R_ARM_GOT_PREL,       /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        32,                    /* bitsize */
+        TRUE,                  /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont,        /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_ARM_GOT_PREL",      /* name */
+        FALSE,                 /* partial_inplace */
+        0xffffffff,            /* src_mask */
+        0xffffffff,            /* dst_mask */
+        TRUE),                 /* pcrel_offset */
+
+  HOWTO (R_ARM_GOT_BREL12,     /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        12,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_bitfield,/* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_ARM_GOT_BREL12",    /* name */
+        FALSE,                 /* partial_inplace */
+        0x00000fff,            /* src_mask */
+        0x00000fff,            /* dst_mask */
+        FALSE),                /* pcrel_offset */
+
+  HOWTO (R_ARM_GOTOFF12,       /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        12,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_bitfield,/* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_ARM_GOTOFF12",      /* name */
+        FALSE,                 /* partial_inplace */
+        0x00000fff,            /* src_mask */
+        0x00000fff,            /* dst_mask */
+        FALSE),                /* pcrel_offset */
+
+  EMPTY_HOWTO (R_ARM_GOTRELAX),  /* reserved for future GOT-load optimizations */
+
+  /* GNU extension to record C++ vtable member usage */
+  HOWTO (R_ARM_GNU_VTENTRY,     /* type */
+         0,                     /* rightshift */
+         2,                     /* size (0 = byte, 1 = short, 2 = long) */
+         0,                     /* bitsize */
+         FALSE,                 /* pc_relative */
+         0,                     /* bitpos */
+         complain_overflow_dont, /* complain_on_overflow */
+         _bfd_elf_rel_vtable_reloc_fn,  /* special_function */
+         "R_ARM_GNU_VTENTRY",   /* name */
+         FALSE,                 /* partial_inplace */
+         0,                     /* src_mask */
+         0,                     /* dst_mask */
+         FALSE),                /* pcrel_offset */
+
+  /* GNU extension to record C++ vtable hierarchy */
+  HOWTO (R_ARM_GNU_VTINHERIT, /* type */
+         0,                     /* rightshift */
+         2,                     /* size (0 = byte, 1 = short, 2 = long) */
+         0,                     /* bitsize */
+         FALSE,                 /* pc_relative */
+         0,                     /* bitpos */
+         complain_overflow_dont, /* complain_on_overflow */
+         NULL,                  /* special_function */
+         "R_ARM_GNU_VTINHERIT", /* name */
+         FALSE,                 /* partial_inplace */
+         0,                     /* src_mask */
+         0,                     /* dst_mask */
+         FALSE),                /* pcrel_offset */
+
+  HOWTO (R_ARM_THM_JUMP11,     /* type */
+        1,                     /* rightshift */
+        1,                     /* size (0 = byte, 1 = short, 2 = long) */
+        11,                    /* bitsize */
+        TRUE,                  /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_signed,      /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_ARM_THM_JUMP11",    /* name */
+        FALSE,                 /* partial_inplace */
+        0x000007ff,            /* src_mask */
+        0x000007ff,            /* dst_mask */
+        TRUE),                 /* pcrel_offset */
+
+  HOWTO (R_ARM_THM_JUMP8,      /* type */
+        1,                     /* rightshift */
+        1,                     /* size (0 = byte, 1 = short, 2 = long) */
+        8,                     /* bitsize */
+        TRUE,                  /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_signed,      /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_ARM_THM_JUMP8",     /* name */
+        FALSE,                 /* partial_inplace */
+        0x000000ff,            /* src_mask */
+        0x000000ff,            /* dst_mask */
+        TRUE),                 /* pcrel_offset */
+
+  /* TLS relocations */
+  HOWTO (R_ARM_TLS_GD32,       /* type */
+         0,                     /* rightshift */
+         2,                     /* size (0 = byte, 1 = short, 2 = long) */
+         32,                    /* bitsize */
+         FALSE,                 /* pc_relative */
+         0,                     /* bitpos */
+         complain_overflow_bitfield,/* complain_on_overflow */
+         NULL,                 /* special_function */
+         "R_ARM_TLS_GD32",     /* name */
+         TRUE,                 /* partial_inplace */
+         0xffffffff,           /* src_mask */
+         0xffffffff,           /* dst_mask */
+         FALSE),                /* pcrel_offset */
+
+  HOWTO (R_ARM_TLS_LDM32,      /* 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",    /* name */
+         TRUE,                 /* partial_inplace */
+         0xffffffff,           /* src_mask */
+         0xffffffff,           /* dst_mask */
+         FALSE),                /* pcrel_offset */
+
+  HOWTO (R_ARM_TLS_LDO32,      /* 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_LDO32",    /* name */
+         TRUE,                 /* partial_inplace */
+         0xffffffff,           /* src_mask */
+         0xffffffff,           /* dst_mask */
+         FALSE),                /* pcrel_offset */
+
+  HOWTO (R_ARM_TLS_IE32,       /* type */
+         0,                     /* rightshift */
+         2,                     /* size (0 = byte, 1 = short, 2 = long) */
+         32,                    /* bitsize */
+         FALSE,                  /* pc_relative */
+         0,                     /* bitpos */
+         complain_overflow_bitfield,/* complain_on_overflow */
+         NULL,                 /* special_function */
+         "R_ARM_TLS_IE32",     /* name */
+         TRUE,                 /* partial_inplace */
+         0xffffffff,           /* src_mask */
+         0xffffffff,           /* dst_mask */
+         FALSE),                /* pcrel_offset */
+
+  HOWTO (R_ARM_TLS_LE32,       /* 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_LE32",     /* name */
+         TRUE,                 /* partial_inplace */
+         0xffffffff,           /* src_mask */
+         0xffffffff,           /* dst_mask */
+         FALSE),                /* pcrel_offset */
+
+  HOWTO (R_ARM_TLS_LDO12,      /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        12,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_bitfield,/* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_ARM_TLS_LDO12",     /* name */
+        FALSE,                 /* partial_inplace */
+        0x00000fff,            /* src_mask */
+        0x00000fff,            /* dst_mask */
+        FALSE),                /* pcrel_offset */
+
+  HOWTO (R_ARM_TLS_LE12,       /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        12,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_bitfield,/* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_ARM_TLS_LE12",      /* name */
+        FALSE,                 /* partial_inplace */
+        0x00000fff,            /* src_mask */
+        0x00000fff,            /* dst_mask */
+        FALSE),                /* pcrel_offset */
+
+  HOWTO (R_ARM_TLS_IE12GP,     /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        12,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_bitfield,/* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_ARM_TLS_IE12GP",    /* name */
+        FALSE,                 /* partial_inplace */
+        0x00000fff,            /* src_mask */
+        0x00000fff,            /* dst_mask */
+        FALSE),                /* pcrel_offset */
+};
+
+/* 112-127 private relocations
+   128 R_ARM_ME_TOO, obsolete
+   129-255 unallocated in AAELF.
+
+   249-255 extended, currently unused, relocations:  */
+
+static reloc_howto_type elf32_arm_howto_table_3[4] =
+{
+  HOWTO (R_ARM_RREL32,         /* type */
+        0,                     /* rightshift */
+        0,                     /* size (0 = byte, 1 = short, 2 = long) */
+        0,                     /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont,/* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_ARM_RREL32",        /* name */
+        FALSE,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0,                     /* dst_mask */
+        FALSE),                /* pcrel_offset */
+
+  HOWTO (R_ARM_RABS32,         /* type */
+        0,                     /* rightshift */
+        0,                     /* size (0 = byte, 1 = short, 2 = long) */
+        0,                     /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont,/* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_ARM_RABS32",        /* name */
+        FALSE,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0,                     /* dst_mask */
+        FALSE),                /* pcrel_offset */
+
+  HOWTO (R_ARM_RPC24,          /* type */
+        0,                     /* rightshift */
+        0,                     /* size (0 = byte, 1 = short, 2 = long) */
+        0,                     /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont,/* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_ARM_RPC24",         /* name */
+        FALSE,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0,                     /* dst_mask */
+        FALSE),                /* pcrel_offset */
+
+  HOWTO (R_ARM_RBASE,          /* type */
+        0,                     /* rightshift */
+        0,                     /* size (0 = byte, 1 = short, 2 = long) */
+        0,                     /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont,/* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_ARM_RBASE",         /* name */
+        FALSE,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0,                     /* dst_mask */
+        FALSE)                 /* pcrel_offset */
+};
+
+static reloc_howto_type *
+elf32_arm_howto_from_type (unsigned int r_type)
+{
+  if (r_type < NUM_ELEM (elf32_arm_howto_table_1))
+    return &elf32_arm_howto_table_1[r_type];
+
+  if (r_type >= R_ARM_MOVW_BREL_NC
+      && r_type < R_ARM_MOVW_BREL_NC + NUM_ELEM (elf32_arm_howto_table_2))
+    return &elf32_arm_howto_table_2[r_type - R_ARM_MOVW_BREL_NC];
+
+  if (r_type >= R_ARM_RREL32
+      && r_type < R_ARM_RREL32 + NUM_ELEM (elf32_arm_howto_table_2))
+    return &elf32_arm_howto_table_3[r_type - R_ARM_RREL32];
+
+  return NULL;
 }
 
 static void
@@ -961,12 +1305,16 @@ static const struct elf32_arm_reloc_map elf32_arm_reloc_map[] =
     {BFD_RELOC_16,                   R_ARM_ABS16},
     {BFD_RELOC_ARM_OFFSET_IMM,       R_ARM_ABS12},
     {BFD_RELOC_ARM_THUMB_OFFSET,     R_ARM_THM_ABS5},
-    {BFD_RELOC_THUMB_PCREL_BRANCH23, R_ARM_THM_PC22},
-    {BFD_RELOC_ARM_COPY,             R_ARM_COPY},
+    {BFD_RELOC_THUMB_PCREL_BRANCH25, R_ARM_THM_JUMP24},
+    {BFD_RELOC_THUMB_PCREL_BRANCH23, R_ARM_THM_CALL},
+    {BFD_RELOC_THUMB_PCREL_BRANCH12, R_ARM_THM_JUMP11},
+    {BFD_RELOC_THUMB_PCREL_BRANCH20, R_ARM_THM_JUMP19},
+    {BFD_RELOC_THUMB_PCREL_BRANCH9,  R_ARM_THM_JUMP8},
+    {BFD_RELOC_THUMB_PCREL_BRANCH7,  R_ARM_THM_JUMP6},
     {BFD_RELOC_ARM_GLOB_DAT,         R_ARM_GLOB_DAT},
     {BFD_RELOC_ARM_JUMP_SLOT,        R_ARM_JUMP_SLOT},
     {BFD_RELOC_ARM_RELATIVE,         R_ARM_RELATIVE},
-    {BFD_RELOC_ARM_GOTOFF,           R_ARM_GOTOFF},
+    {BFD_RELOC_ARM_GOTOFF,           R_ARM_GOTOFF32},
     {BFD_RELOC_ARM_GOTPC,            R_ARM_GOTPC},
     {BFD_RELOC_ARM_GOT32,            R_ARM_GOT32},
     {BFD_RELOC_ARM_PLT32,            R_ARM_PLT32},
@@ -984,58 +1332,25 @@ static const struct elf32_arm_reloc_map elf32_arm_reloc_map[] =
     {BFD_RELOC_ARM_TLS_TPOFF32,      R_ARM_TLS_TPOFF32},
     {BFD_RELOC_ARM_TLS_IE32,         R_ARM_TLS_IE32},
     {BFD_RELOC_ARM_TLS_LE32,         R_ARM_TLS_LE32},
+    {BFD_RELOC_VTABLE_INHERIT,      R_ARM_GNU_VTINHERIT},
+    {BFD_RELOC_VTABLE_ENTRY,        R_ARM_GNU_VTENTRY},
   };
 
 static reloc_howto_type *
-elf32_arm_reloc_type_lookup (abfd, code)
-     bfd *abfd ATTRIBUTE_UNUSED;
-     bfd_reloc_code_real_type code;
+elf32_arm_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
+                            bfd_reloc_code_real_type code)
 {
   unsigned int i;
+  for (i = 0; i < NUM_ELEM (elf32_arm_reloc_map); i ++)
+    if (elf32_arm_reloc_map[i].bfd_reloc_val == code)
+      return elf32_arm_howto_from_type (elf32_arm_reloc_map[i].elf_reloc_val);
 
-  switch (code)
-    {
-    case BFD_RELOC_VTABLE_INHERIT:
-      return & elf32_arm_vtinherit_howto;
-
-    case BFD_RELOC_VTABLE_ENTRY:
-      return & elf32_arm_vtentry_howto;
-
-    case BFD_RELOC_THUMB_PCREL_BRANCH12:
-      return & elf32_arm_thm_pc11_howto;
-
-    case BFD_RELOC_THUMB_PCREL_BRANCH9:
-      return & elf32_arm_thm_pc9_howto;
-
-    case BFD_RELOC_ARM_TLS_GD32:
-      return & elf32_arm_tls_gd32_howto;
-
-    case BFD_RELOC_ARM_TLS_LDO32:
-      return & elf32_arm_tls_ldo32_howto;
-
-    case BFD_RELOC_ARM_TLS_LDM32:
-      return & elf32_arm_tls_ldm32_howto;
-
-    case BFD_RELOC_ARM_TLS_IE32:
-      return & elf32_arm_tls_ie32_howto;
-
-    case BFD_RELOC_ARM_TLS_LE32:
-      return & elf32_arm_tls_le32_howto;
-
-    default:
-      for (i = 0; i < NUM_ELEM (elf32_arm_reloc_map); i ++)
-       if (elf32_arm_reloc_map[i].bfd_reloc_val == code)
-         return & elf32_arm_howto_table[elf32_arm_reloc_map[i].elf_reloc_val];
-
-      return NULL;
-   }
+  return NULL;
 }
 
 /* Support for core dump NOTE sections */
 static bfd_boolean
-elf32_arm_nabi_grok_prstatus (abfd, note)
-     bfd *abfd;
-     Elf_Internal_Note *note;
+elf32_arm_nabi_grok_prstatus (bfd *abfd, Elf_Internal_Note *note)
 {
   int offset;
   size_t size;
@@ -1065,9 +1380,7 @@ elf32_arm_nabi_grok_prstatus (abfd, note)
 }
 
 static bfd_boolean
-elf32_arm_nabi_grok_psinfo (abfd, note)
-     bfd *abfd;
-     Elf_Internal_Note *note;
+elf32_arm_nabi_grok_psinfo (bfd *abfd, Elf_Internal_Note *note)
 {
   switch (note->descsz)
     {
@@ -1202,25 +1515,45 @@ typedef struct elf32_elf_section_map
 }
 elf32_arm_section_map;
 
-struct _arm_elf_section_data
+typedef struct _arm_elf_section_data
 {
   struct bfd_elf_section_data elf;
-  int mapcount;
+  unsigned int mapcount;
   elf32_arm_section_map *map;
-};
+}
+_arm_elf_section_data;
 
 #define elf32_arm_section_data(sec) \
-  ((struct _arm_elf_section_data *) elf_section_data (sec))
+  ((_arm_elf_section_data *) elf_section_data (sec))
 
 /* The size of the thread control block.  */
 #define TCB_SIZE       8
 
+#define NUM_KNOWN_ATTRIBUTES 32
+
+typedef struct aeabi_attribute
+{
+  int type;
+  unsigned int i;
+  char *s;
+} aeabi_attribute;
+
+typedef struct aeabi_attribute_list
+{
+  struct aeabi_attribute_list *next;
+  int tag;
+  aeabi_attribute attr;
+} aeabi_attribute_list;
+
 struct elf32_arm_obj_tdata
 {
   struct elf_obj_tdata root;
 
   /* tls_type for each local got entry.  */
   char *local_got_tls_type;
+
+  aeabi_attribute known_eabi_attributes[NUM_KNOWN_ATTRIBUTES];
+  aeabi_attribute_list *other_eabi_attributes;
 };
 
 #define elf32_arm_tdata(abfd) \
@@ -1414,12 +1747,13 @@ create_got_section (bfd *dynobj, struct bfd_link_info *info)
   if (!htab->sgot || !htab->sgotplt)
     abort ();
 
-  htab->srelgot = bfd_make_section (dynobj, ".rel.got");
+  htab->srelgot = bfd_make_section_with_flags (dynobj, ".rel.got",
+                                              (SEC_ALLOC | SEC_LOAD
+                                               | SEC_HAS_CONTENTS
+                                               | SEC_IN_MEMORY
+                                               | SEC_LINKER_CREATED
+                                               | SEC_READONLY));
   if (htab->srelgot == NULL
-      || ! bfd_set_section_flags (dynobj, htab->srelgot,
-                                 (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS
-                                  | SEC_IN_MEMORY | SEC_LINKER_CREATED
-                                  | SEC_READONLY))
       || ! bfd_set_section_alignment (dynobj, htab->srelgot, 2))
     return FALSE;
   return TRUE;
@@ -1459,7 +1793,7 @@ elf32_arm_create_dynamic_sections (bfd *dynobj, struct bfd_link_info *info)
 /* Copy the extra info we tack onto an elf_link_hash_entry.  */
 
 static void
-elf32_arm_copy_indirect_symbol (const struct elf_backend_data *bed,
+elf32_arm_copy_indirect_symbol (struct bfd_link_info *info,
                                struct elf_link_hash_entry *dir,
                                struct elf_link_hash_entry *ind)
 {
@@ -1475,10 +1809,7 @@ elf32_arm_copy_indirect_symbol (const struct elf_backend_data *bed,
          struct elf32_arm_relocs_copied **pp;
          struct elf32_arm_relocs_copied *p;
 
-         if (ind->root.type == bfd_link_hash_indirect)
-           abort ();
-
-         /* Add reloc counts against the weak sym to the strong sym
+         /* Add reloc counts against the indirect sym to the direct sym
             list.  Merge any entries against the same section.  */
          for (pp = &eind->relocs_copied; (p = *pp) != NULL; )
            {
@@ -1502,16 +1833,9 @@ elf32_arm_copy_indirect_symbol (const struct elf_backend_data *bed,
       eind->relocs_copied = NULL;
     }
 
-  /* If the direct symbol already has an associated PLT entry, the
-     indirect symbol should not.  If it doesn't, swap refcount information
-     from the indirect symbol.  */
-  if (edir->plt_thumb_refcount == 0)
-    {
-      edir->plt_thumb_refcount = eind->plt_thumb_refcount;
-      eind->plt_thumb_refcount = 0;
-    }
-  else
-    BFD_ASSERT (eind->plt_thumb_refcount == 0);
+  /* Copy over PLT info.  */
+  edir->plt_thumb_refcount += eind->plt_thumb_refcount;
+  eind->plt_thumb_refcount = 0;
 
   if (ind->root.type == bfd_link_hash_indirect
       && dir->got.refcount <= 0)
@@ -1520,7 +1844,7 @@ elf32_arm_copy_indirect_symbol (const struct elf_backend_data *bed,
       eind->tls_type = GOT_UNKNOWN;
     }
 
-  _bfd_elf_link_hash_copy_indirect (bed, dir, ind);
+  _bfd_elf_link_hash_copy_indirect (info, dir, ind);
 }
 
 /* Create an ARM elf linker hash table.  */
@@ -1897,10 +2221,11 @@ bfd_elf32_arm_add_glue_sections_to_bfd (bfd *abfd,
         of this section.  */
       flags = SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_CODE | SEC_READONLY;
 
-      sec = bfd_make_section (abfd, ARM2THUMB_GLUE_SECTION_NAME);
+      sec = bfd_make_section_with_flags (abfd,
+                                        ARM2THUMB_GLUE_SECTION_NAME,
+                                        flags);
 
       if (sec == NULL
-         || !bfd_set_section_flags (abfd, sec, flags)
          || !bfd_set_section_alignment (abfd, sec, 2))
        return FALSE;
 
@@ -1916,10 +2241,11 @@ bfd_elf32_arm_add_glue_sections_to_bfd (bfd *abfd,
       flags = SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY
        | SEC_CODE | SEC_READONLY;
 
-      sec = bfd_make_section (abfd, THUMB2ARM_GLUE_SECTION_NAME);
+      sec = bfd_make_section_with_flags (abfd,
+                                        THUMB2ARM_GLUE_SECTION_NAME,
+                                        flags);
 
       if (sec == NULL
-         || !bfd_set_section_flags (abfd, sec, flags)
          || !bfd_set_section_alignment (abfd, sec, 2))
        return FALSE;
 
@@ -2027,11 +2353,9 @@ bfd_elf32_arm_process_before_allocation (bfd *abfd,
          /* These are the only relocation types we care about.  */
          if (   r_type != R_ARM_PC24
              && r_type != R_ARM_PLT32
-#ifndef OLD_ARM_ABI
              && r_type != R_ARM_CALL
              && r_type != R_ARM_JUMP24
-#endif
-             && r_type != R_ARM_THM_PC22)
+             && r_type != R_ARM_THM_CALL)
            continue;
 
          /* Get the section contents if we haven't done so already.  */
@@ -2074,10 +2398,8 @@ bfd_elf32_arm_process_before_allocation (bfd *abfd,
            {
            case R_ARM_PC24:
            case R_ARM_PLT32:
-#ifndef OLD_ARM_ABI
            case R_ARM_CALL:
            case R_ARM_JUMP24:
-#endif
              /* This one is a call from arm code.  We need to look up
                 the target of the call.  If it is a thumb target, we
                 insert glue.  */
@@ -2085,7 +2407,7 @@ bfd_elf32_arm_process_before_allocation (bfd *abfd,
                record_arm_to_thumb_glue (link_info, h);
              break;
 
-           case R_ARM_THM_PC22:
+           case R_ARM_THM_CALL:
              /* This one is a call from thumb code.  We look
                 up the target of the call.  If it is not a thumb
                  target, we insert glue.  */
@@ -2124,7 +2446,6 @@ error_return:
 #endif
 
 
-#ifndef OLD_ARM_ABI
 /* Set target relocation values needed during linking.  */
 
 void
@@ -2153,7 +2474,6 @@ bfd_elf32_arm_set_target_relocs (struct bfd_link_info *link_info,
   globals->fix_v4bx = fix_v4bx;
   globals->use_blx |= use_blx;
 }
-#endif
 
 /* The thumb form of a long branch is a bit finicky, because the offset
    encoding is split over two fields, each in it's own instruction. They
@@ -2424,8 +2744,6 @@ elf32_arm_to_thumb_stub (struct bfd_link_info * info,
   return TRUE;
 }
 
-
-#ifndef OLD_ARM_ABI
 /* Some relocations map to different relocations depending on the
    target.  Return the real relocation.  */
 static int
@@ -2447,8 +2765,6 @@ arm_real_reloc_type (struct elf32_arm_link_hash_table * globals,
       return r_type;
     }
 }
-#endif /* OLD_ARM_ABI */
-
 
 /* Return the base VMA address which should be subtracted from real addresses
    when resolving @dtpoff relocation.
@@ -2512,13 +2828,11 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
 
   globals = elf32_arm_hash_table (info);
 
-#ifndef OLD_ARM_ABI
   /* Some relocation type map to different relocations depending on the
      target.  We pick the right one here.  */
   r_type = arm_real_reloc_type (globals, r_type);
   if (r_type != howto->type)
     howto = elf32_arm_howto_from_type (r_type);
-#endif /* OLD_ARM_ABI */
 
   /* If the start address has been set, then set the EF_ARM_HASENTRY
      flag.  Setting this more than once is redundant, but the cost is
@@ -2570,12 +2884,10 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
     case R_ARM_PC24:
     case R_ARM_ABS32:
     case R_ARM_REL32:
-#ifndef OLD_ARM_ABI
     case R_ARM_CALL:
     case R_ARM_JUMP24:
     case R_ARM_XPC25:
     case R_ARM_PREL31:
-#endif
     case R_ARM_PLT32:
       /* r_symndx will be zero only for relocs against symbols
         from removed linkonce sections, or sections discarded by
@@ -2617,11 +2929,9 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
              || ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
              || h->root.type != bfd_link_hash_undefweak)
          && r_type != R_ARM_PC24
-#ifndef OLD_ARM_ABI
          && r_type != R_ARM_CALL
          && r_type != R_ARM_JUMP24
          && r_type != R_ARM_PREL31
-#endif
          && r_type != R_ARM_PLT32)
        {
          Elf_Internal_Rela outrel;
@@ -2689,7 +2999,10 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
                     the section symbol as it is convenient.  (We
                     cannot use the symbol given by "h" directly as it
                     will not appear in the dynamic symbol table.)  */
-                 symbol = elf_section_data (sym_sec->output_section)->dynindx;
+                 if (sym_sec)
+                   symbol = elf_section_data (sym_sec->output_section)->dynindx;
+                 else
+                   symbol = elf_section_data (input_section->output_section)->dynindx;
                  BFD_ASSERT (symbol != 0);
                }
              else
@@ -2716,14 +3029,11 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
        }
       else switch (r_type)
        {
-#ifndef OLD_ARM_ABI
        case R_ARM_XPC25:         /* Arm BLX instruction.  */
        case R_ARM_CALL:
        case R_ARM_JUMP24:
-#endif
        case R_ARM_PC24:          /* Arm B/BL instruction */
        case R_ARM_PLT32:
-#ifndef OLD_ARM_ABI
          if (r_type == R_ARM_XPC25)
            {
              /* Check for Arm calling Arm function.  */
@@ -2736,7 +3046,6 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
                   h ? h->root.root.string : "(local)");
            }
          else
-#endif
            {
              /* Check for Arm calling Thumb function.  */
              if (sym_flags == STT_ARM_TFUNC)
@@ -2792,14 +3101,12 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
                return bfd_reloc_overflow;
            }
 
-#ifndef OLD_ARM_ABI
          /* If necessary set the H bit in the BLX instruction.  */
          if (r_type == R_ARM_XPC25 && ((value & 2) == 2))
            value = (signed_addend & howto->dst_mask)
              | (bfd_get_32 (input_bfd, hit_data) & (~ howto->dst_mask))
              | (1 << 24);
          else
-#endif
            value = (signed_addend & howto->dst_mask)
              | (bfd_get_32 (input_bfd, hit_data) & (~ howto->dst_mask));
          break;
@@ -2816,7 +3123,6 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
          value += addend;
          break;
 
-#ifndef OLD_ARM_ABI
        case R_ARM_PREL31:
          value -= (input_section->output_section->vma
                    + input_section->output_offset + rel->r_offset);
@@ -2832,7 +3138,6 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
          if (sym_flags == STT_ARM_TFUNC)
            value |= 1;
          break;
-#endif
        }
 
       bfd_put_32 (input_bfd, value, hit_data);
@@ -2887,10 +3192,8 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
       bfd_put_16 (input_bfd, value, hit_data);
       return bfd_reloc_ok;
 
-#ifndef OLD_ARM_ABI
     case R_ARM_THM_XPC22:
-#endif
-    case R_ARM_THM_PC22:
+    case R_ARM_THM_CALL:
       /* Thumb BL (branch long instruction).  */
       {
        bfd_vma relocation;
@@ -2913,7 +3216,7 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
            addend = (upper << 12) | (lower << 1);
            signed_addend = addend;
          }
-#ifndef OLD_ARM_ABI
+
        if (r_type == R_ARM_THM_XPC22)
          {
            /* Check for Thumb to Thumb call.  */
@@ -2926,7 +3229,6 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
                 h ? h->root.root.string : "(local)");
          }
        else
-#endif
          {
            /* If it is not a call to Thumb, assume call to Arm.
               If it is a call relative to a section name, then it is not a
@@ -2986,7 +3288,6 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
        if (signed_check > reloc_signed_max || signed_check < reloc_signed_min)
          overflow = TRUE;
 
-#ifndef OLD_ARM_ABI
        if ((r_type == R_ARM_THM_XPC22
             && ((lower_insn & 0x1800) == 0x0800))
            || thumb_plt_call)
@@ -2995,7 +3296,7 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
             which specifies that bit 1 of the target address will come from bit
             1 of the base address.  */
          relocation = (relocation + 2) & ~ 3;
-#endif
+
        /* Put RELOCATION back into the insn.  */
        upper_insn = (upper_insn & ~(bfd_vma) 0x7ff) | ((relocation >> 12) & 0x7ff);
        lower_insn = (lower_insn & ~(bfd_vma) 0x7ff) | ((relocation >> 1) & 0x7ff);
@@ -3008,8 +3309,153 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
       }
       break;
 
-    case R_ARM_THM_PC11:
-    case R_ARM_THM_PC9:
+    case R_ARM_THM_JUMP24:
+      /* Thumb32 unconditional branch instruction.  */
+      {
+       bfd_vma relocation;
+       bfd_boolean overflow = FALSE;
+       bfd_vma upper_insn = bfd_get_16 (input_bfd, hit_data);
+       bfd_vma lower_insn = bfd_get_16 (input_bfd, hit_data + 2);
+       bfd_signed_vma reloc_signed_max = ((1 << (howto->bitsize - 1)) - 1) >> howto->rightshift;
+       bfd_signed_vma reloc_signed_min = ~ reloc_signed_max;
+       bfd_vma check;
+       bfd_signed_vma signed_check;
+
+       /* Need to refetch the addend, reconstruct the top three bits, and glue the
+          two pieces together.  */
+       if (globals->use_rel)
+         {
+           bfd_vma S  = (upper_insn & 0x0400) >> 10;
+           bfd_vma hi = (upper_insn & 0x03ff);
+           bfd_vma I1 = (lower_insn & 0x2000) >> 13;
+           bfd_vma I2 = (lower_insn & 0x0800) >> 11;
+           bfd_vma lo = (lower_insn & 0x07ff);
+
+           I1 = !(I1 ^ S);
+           I2 = !(I2 ^ S);
+           S  = !S;
+
+           signed_addend = (S << 24) | (I1 << 23) | (I2 << 22) | (hi << 12) | (lo << 1);
+           signed_addend -= (1 << 24); /* Sign extend.  */
+         }
+
+       /* ??? Should handle interworking?  GCC might someday try to
+          use this for tail calls.  */
+
+       relocation = value + signed_addend;
+       relocation -= (input_section->output_section->vma
+                      + input_section->output_offset
+                      + rel->r_offset);
+
+       check = relocation >> howto->rightshift;
+
+       /* If this is a signed value, the rightshift just dropped
+          leading 1 bits (assuming twos complement).  */
+       if ((bfd_signed_vma) relocation >= 0)
+         signed_check = check;
+       else
+         signed_check = check | ~((bfd_vma) -1 >> howto->rightshift);
+
+       /* Assumes two's complement.  */
+       if (signed_check > reloc_signed_max || signed_check < reloc_signed_min)
+         overflow = TRUE;
+
+       /* Put RELOCATION back into the insn.  */
+       {
+         bfd_vma S  = (relocation & 0x01000000) >> 24;
+         bfd_vma I1 = (relocation & 0x00800000) >> 23;
+         bfd_vma I2 = (relocation & 0x00400000) >> 22;
+         bfd_vma hi = (relocation & 0x003ff000) >> 12;
+         bfd_vma lo = (relocation & 0x00000ffe) >>  1;
+
+         I1 = !(I1 ^ S);
+         I2 = !(I2 ^ S);
+
+         upper_insn = (upper_insn & (bfd_vma) 0xf800) | (S << 10) | hi;
+         lower_insn = (lower_insn & (bfd_vma) 0xd000) | (I1 << 13) | (I2 << 11) | lo;
+       }
+
+       /* Put the relocated value back in the object file:  */
+       bfd_put_16 (input_bfd, upper_insn, hit_data);
+       bfd_put_16 (input_bfd, lower_insn, hit_data + 2);
+
+       return (overflow ? bfd_reloc_overflow : bfd_reloc_ok);
+      }
+
+    case R_ARM_THM_JUMP19:
+      /* Thumb32 conditional branch instruction.  */
+      {
+       bfd_vma relocation;
+       bfd_boolean overflow = FALSE;
+       bfd_vma upper_insn = bfd_get_16 (input_bfd, hit_data);
+       bfd_vma lower_insn = bfd_get_16 (input_bfd, hit_data + 2);
+       bfd_signed_vma reloc_signed_max = ((1 << (howto->bitsize - 1)) - 1) >> howto->rightshift;
+       bfd_signed_vma reloc_signed_min = ~ reloc_signed_max;
+       bfd_vma check;
+       bfd_signed_vma signed_check;
+
+       /* Need to refetch the addend, reconstruct the top three bits,
+          and squish the two 11 bit pieces together.  */
+       if (globals->use_rel)
+         {
+           bfd_vma S     = (upper_insn & 0x0400) >> 10;
+           bfd_vma upper = (upper_insn & 0x001f);
+           bfd_vma J1    = (lower_insn & 0x2000) >> 13;
+           bfd_vma J2    = (lower_insn & 0x0800) >> 11;
+           bfd_vma lower = (lower_insn & 0x07ff);
+
+           upper |= J2 << 6;
+           upper |= J1 << 7;
+           upper |= ~S << 8;
+           upper -= 0x0100; /* Sign extend.  */
+
+           addend = (upper << 12) | (lower << 1);
+           signed_addend = addend;
+         }
+
+       /* ??? Should handle interworking?  GCC might someday try to
+          use this for tail calls.  */
+
+       relocation = value + signed_addend;
+       relocation -= (input_section->output_section->vma
+                      + input_section->output_offset
+                      + rel->r_offset);
+
+       check = relocation >> howto->rightshift;
+
+       /* If this is a signed value, the rightshift just dropped
+          leading 1 bits (assuming twos complement).  */
+       if ((bfd_signed_vma) relocation >= 0)
+         signed_check = check;
+       else
+         signed_check = check | ~((bfd_vma) -1 >> howto->rightshift);
+
+       /* Assumes two's complement.  */
+       if (signed_check > reloc_signed_max || signed_check < reloc_signed_min)
+         overflow = TRUE;
+
+       /* Put RELOCATION back into the insn.  */
+       {
+         bfd_vma S  = (relocation & 0x00100000) >> 20;
+         bfd_vma J2 = (relocation & 0x00080000) >> 19;
+         bfd_vma J1 = (relocation & 0x00040000) >> 18;
+         bfd_vma hi = (relocation & 0x0003f000) >> 12;
+         bfd_vma lo = (relocation & 0x00000ffe) >>  1;
+
+         upper_insn = (upper_insn & 0xfb30) | (S << 10) | hi;
+         lower_insn = (lower_insn & 0xd000) | (J1 << 13) | (J2 << 11) | lo;
+       }
+
+       /* Put the relocated value back in the object file:  */
+       bfd_put_16 (input_bfd, upper_insn, hit_data);
+       bfd_put_16 (input_bfd, lower_insn, hit_data + 2);
+
+       return (overflow ? bfd_reloc_overflow : bfd_reloc_ok);
+      }
+
+    case R_ARM_THM_JUMP11:
+    case R_ARM_THM_JUMP8:
+    case R_ARM_THM_JUMP6:
       /* Thumb B (branch) instruction).  */
       {
        bfd_signed_vma relocation;
@@ -3017,6 +3463,10 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
        bfd_signed_vma reloc_signed_min = ~ reloc_signed_max;
        bfd_signed_vma signed_check;
 
+       /* CZB cannot jump backward.  */
+       if (r_type == R_ARM_THM_JUMP6)
+         reloc_signed_min = 0;
+
        if (globals->use_rel)
          {
            /* Need to refetch addend.  */
@@ -3042,7 +3492,11 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
 
        relocation >>= howto->rightshift;
        signed_check = relocation;
-       relocation &= howto->dst_mask;
+
+       if (r_type == R_ARM_THM_JUMP6)
+         relocation = ((relocation & 0x0020) << 4) | ((relocation & 0x001f) << 3);
+       else
+         relocation &= howto->dst_mask;
        relocation |= (bfd_get_16 (input_bfd, hit_data) & (~ howto->dst_mask));
 
        bfd_put_16 (input_bfd, relocation, hit_data);
@@ -3054,7 +3508,6 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
        return bfd_reloc_ok;
       }
 
-#ifndef OLD_ARM_ABI
     case R_ARM_ALU_PCREL7_0:
     case R_ARM_ALU_PCREL15_8:
     case R_ARM_ALU_PCREL23_15:
@@ -3080,25 +3533,12 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
        bfd_put_32 (input_bfd, value, hit_data);
       }
       return bfd_reloc_ok;
-#endif
 
     case R_ARM_GNU_VTINHERIT:
     case R_ARM_GNU_VTENTRY:
       return bfd_reloc_ok;
 
-    case R_ARM_COPY:
-      return bfd_reloc_notsupported;
-
-    case R_ARM_GLOB_DAT:
-      return bfd_reloc_notsupported;
-
-    case R_ARM_JUMP_SLOT:
-      return bfd_reloc_notsupported;
-
-    case R_ARM_RELATIVE:
-      return bfd_reloc_notsupported;
-
-    case R_ARM_GOTOFF:
+    case R_ARM_GOTOFF32:
       /* Relocation is relative to the start of the
          global offset table.  */
 
@@ -3136,9 +3576,7 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
                                       (bfd_vma) 0);
 
     case R_ARM_GOT32:
-#ifndef OLD_ARM_ABI
     case R_ARM_GOT_PREL:
-#endif
       /* Relocation is to the entry for this symbol in the
          global offset table.  */
       if (sgot == NULL)
@@ -3459,30 +3897,6 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
       return _bfd_final_link_relocate (howto, input_bfd, input_section,
                                       contents, rel->r_offset, value, (bfd_vma) 0);
 
-    case R_ARM_SBREL32:
-      return bfd_reloc_notsupported;
-
-    case R_ARM_AMP_VCALL9:
-      return bfd_reloc_notsupported;
-
-    case R_ARM_RSBREL32:
-      return bfd_reloc_notsupported;
-
-    case R_ARM_THM_RPC22:
-      return bfd_reloc_notsupported;
-
-    case R_ARM_RREL32:
-      return bfd_reloc_notsupported;
-
-    case R_ARM_RABS32:
-      return bfd_reloc_notsupported;
-
-    case R_ARM_RPC24:
-      return bfd_reloc_notsupported;
-
-    case R_ARM_RBASE:
-      return bfd_reloc_notsupported;
-
     case R_ARM_V4BX:
       if (globals->fix_v4bx)
         {
@@ -3504,6 +3918,194 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
     }
 }
 
+
+static int
+uleb128_size (unsigned int i)
+{
+  int size;
+  size = 1;
+  while (i >= 0x80)
+    {
+      i >>= 7;
+      size++;
+    }
+  return size;
+}
+
+/* Return TRUE if the attribute has the default value (0/"").  */
+static bfd_boolean
+is_default_attr (aeabi_attribute *attr)
+{
+  if ((attr->type & 1) && attr->i != 0)
+    return FALSE;
+  if ((attr->type & 2) && attr->s && *attr->s)
+    return FALSE;
+
+  return TRUE;
+}
+
+/* Return the size of a single attribute.  */
+static bfd_vma
+eabi_attr_size(int tag, aeabi_attribute *attr)
+{
+  bfd_vma size;
+
+  if (is_default_attr (attr))
+    return 0;
+
+  size = uleb128_size (tag);
+  if (attr->type & 1)
+    size += uleb128_size (attr->i);
+  if (attr->type & 2)
+    size += strlen ((char *)attr->s) + 1;
+  return size;
+}
+  
+/* Returns the size of the eabi object attributess section.  */
+bfd_vma
+elf32_arm_eabi_attr_size (bfd *abfd)
+{
+  bfd_vma size;
+  aeabi_attribute *attr;
+  aeabi_attribute_list *list;
+  int i;
+
+  attr = elf32_arm_tdata (abfd)->known_eabi_attributes;
+  size = 16; /* 'A' <size> "aeabi" 0x1 <size>.  */
+  for (i = 4; i < NUM_KNOWN_ATTRIBUTES; i++)
+    size += eabi_attr_size (i, &attr[i]);
+
+  for (list = elf32_arm_tdata (abfd)->other_eabi_attributes;
+       list;
+       list = list->next)
+    size += eabi_attr_size (list->tag, &list->attr);
+
+  return size;
+}
+
+static bfd_byte *
+write_uleb128 (bfd_byte *p, unsigned int val)
+{
+  bfd_byte c;
+  do
+    {
+      c = val & 0x7f;
+      val >>= 7;
+      if (val)
+       c |= 0x80;
+      *(p++) = c;
+    }
+  while (val);
+  return p;
+}
+
+/* Write attribute ATTR to butter P, and return a pointer to the following
+   byte.  */
+static bfd_byte *
+write_eabi_attribute (bfd_byte *p, int tag, aeabi_attribute *attr)
+{
+  /* Suppress default entries.  */
+  if (is_default_attr(attr))
+    return p;
+
+  p = write_uleb128 (p, tag);
+  if (attr->type & 1)
+    p = write_uleb128 (p, attr->i);
+  if (attr->type & 2)
+    {
+      int len;
+
+      len = strlen (attr->s) + 1;
+      memcpy (p, attr->s, len);
+      p += len;
+    }
+
+  return p;
+}
+
+/* Write the contents of the eabi attributes section to p.  */
+void
+elf32_arm_set_eabi_attr_contents (bfd *abfd, bfd_byte *contents, bfd_vma size)
+{
+  bfd_byte *p;
+  aeabi_attribute *attr;
+  aeabi_attribute_list *list;
+  int i;
+
+  p = contents;
+  *(p++) = 'A';
+  bfd_put_32 (abfd, size - 1, p);
+  p += 4;
+  memcpy (p, "aeabi", 6);
+  p += 6;
+  *(p++) = Tag_File;
+  bfd_put_32 (abfd, size - 11, p);
+  p += 4;
+
+  attr = elf32_arm_tdata (abfd)->known_eabi_attributes;
+  for (i = 4; i < NUM_KNOWN_ATTRIBUTES; i++)
+    p = write_eabi_attribute (p, i, &attr[i]);
+
+  for (list = elf32_arm_tdata (abfd)->other_eabi_attributes;
+       list;
+       list = list->next)
+    p = write_eabi_attribute (p, list->tag, &list->attr);
+}
+
+/* Override final_link to handle EABI object attribute sections.  */
+
+static bfd_boolean
+elf32_arm_bfd_final_link (bfd *abfd, struct bfd_link_info *info)
+{
+  asection *o;
+  struct bfd_link_order *p;
+  asection *attr_section = NULL;
+  bfd_byte *contents;
+  bfd_vma size = 0;
+
+  /* elf32_arm_merge_private_bfd_data will already have merged the
+     object attributes.  Remove the input sections from the link, and set
+     the contents of the output secton.  */
+  for (o = abfd->sections; o != NULL; o = o->next)
+    {
+      if (strcmp (o->name, ".ARM.attributes") == 0)
+       {
+         for (p = o->map_head.link_order; p != NULL; p = p->next)
+           {
+             asection *input_section;
+
+             if (p->type != bfd_indirect_link_order)
+               continue;
+             input_section = p->u.indirect.section;
+             /* Hack: reset the SEC_HAS_CONTENTS flag so that
+                elf_link_input_bfd ignores this section.  */
+             input_section->flags &= ~SEC_HAS_CONTENTS;
+           }
+           
+         size = elf32_arm_eabi_attr_size (abfd);
+         bfd_set_section_size (abfd, o, size);
+         attr_section = o;
+         /* Skip this section later on.  */
+         o->map_head.link_order = NULL;
+       }
+    }
+  /* Invoke the ELF linker to do all the work.  */
+  if (!bfd_elf_final_link (abfd, info))
+    return FALSE;
+
+  if (attr_section)
+    {
+      contents = bfd_malloc(size);
+      if (contents == NULL)
+       return FALSE;
+      elf32_arm_set_eabi_attr_contents (abfd, contents, size);
+      bfd_set_section_contents (abfd, attr_section, contents, 0, size);
+      free (contents);
+    }
+  return TRUE;
+}
+
+
 /* Add INCREMENT to the reloc (of type HOWTO) at ADDRESS.  */
 static void
 arm_add_to_rel (bfd *              abfd,
@@ -3513,7 +4115,7 @@ arm_add_to_rel (bfd *              abfd,
 {
   bfd_signed_vma addend;
 
-  if (howto->type == R_ARM_THM_PC22)
+  if (howto->type == R_ARM_THM_CALL)
     {
       int upper_insn, lower_insn;
       int upper, lower;
@@ -3559,10 +4161,8 @@ arm_add_to_rel (bfd *              abfd,
 
        case R_ARM_PC24:
        case R_ARM_PLT32:
-#ifndef OLD_ARM_ABI
        case R_ARM_CALL:
        case R_ARM_JUMP24:
-#endif
          addend <<= howto->size;
          addend += increment;
 
@@ -3772,9 +4372,12 @@ elf32_arm_relocate_section (bfd *                  output_bfd,
                && h->def_dynamic))
        {
          (*_bfd_error_handler)
-           (_("%B(%A+0x%lx): warning: unresolvable relocation %d against symbol `%s'"),
-            input_bfd, input_section, (long) rel->r_offset,
-            r_type, h->root.root.string);
+           (_("%B(%A+0x%lx): unresolvable %s relocation against symbol `%s'"),
+            input_bfd,
+            input_section,
+            (long) rel->r_offset,
+            howto->name,
+            h->root.root.string);
          return FALSE;
        }
 
@@ -3820,17 +4423,116 @@ elf32_arm_relocate_section (bfd *                  output_bfd,
              msg = _("internal error: unknown error");
              /* fall through */
 
-           common_error:
-             if (!((*info->callbacks->warning)
-                   (info, msg, name, input_bfd, input_section,
-                    rel->r_offset)))
-               return FALSE;
-             break;
-           }
-       }
-    }
+           common_error:
+             if (!((*info->callbacks->warning)
+                   (info, msg, name, input_bfd, input_section,
+                    rel->r_offset)))
+               return FALSE;
+             break;
+           }
+       }
+    }
+
+  return TRUE;
+}
+
+/* Allocate/find an object attribute.  */
+static aeabi_attribute *
+elf32_arm_new_eabi_attr (bfd *abfd, int tag)
+{
+  aeabi_attribute *attr;
+  aeabi_attribute_list *list;
+  aeabi_attribute_list *p;
+  aeabi_attribute_list **lastp;
+
+
+  if (tag < NUM_KNOWN_ATTRIBUTES)
+    {
+      /* Knwon tags are preallocated.  */
+      attr = &elf32_arm_tdata (abfd)->known_eabi_attributes[tag];
+    }
+  else
+    {
+      /* Create a new tag.  */
+      list = (aeabi_attribute_list *)
+       bfd_alloc (abfd, sizeof (aeabi_attribute_list));
+      memset (list, 0, sizeof (aeabi_attribute_list));
+      list->tag = tag;
+      /* Keep the tag list in order.  */
+      lastp = &elf32_arm_tdata (abfd)->other_eabi_attributes;
+      for (p = *lastp; p; p = p->next)
+       {
+         if (tag < p->tag)
+           break;
+         lastp = &p->next;
+       }
+      list->next = *lastp;
+      *lastp = list;
+      attr = &list->attr;
+    }
+
+  return attr;
+}
+
+void
+elf32_arm_add_eabi_attr_int (bfd *abfd, int tag, unsigned int i)
+{
+  aeabi_attribute *attr;
+
+  attr = elf32_arm_new_eabi_attr (abfd, tag);
+  attr->type = 1;
+  attr->i = i;
+}
+
+static char *
+attr_strdup (bfd *abfd, const char * s)
+{
+  char * p;
+  int len;
+  
+  len = strlen (s) + 1;
+  p = (char *)bfd_alloc(abfd, len);
+  return memcpy (p, s, len);
+}
+
+void
+elf32_arm_add_eabi_attr_string (bfd *abfd, int tag, const char *s)
+{
+  aeabi_attribute *attr;
+
+  attr = elf32_arm_new_eabi_attr (abfd, tag);
+  attr->type = 2;
+  attr->s = attr_strdup (abfd, s);
+}
 
-  return TRUE;
+void
+elf32_arm_add_eabi_attr_compat (bfd *abfd, unsigned int i, const char *s)
+{
+  aeabi_attribute_list *list;
+  aeabi_attribute_list *p;
+  aeabi_attribute_list **lastp;
+
+  list = (aeabi_attribute_list *)
+    bfd_alloc (abfd, sizeof (aeabi_attribute_list));
+  memset (list, 0, sizeof (aeabi_attribute_list));
+  list->tag = Tag_compatibility;
+  list->attr.type = 3;
+  list->attr.i = i;
+  list->attr.s = attr_strdup (abfd, s);
+
+  lastp = &elf32_arm_tdata (abfd)->other_eabi_attributes;
+  for (p = *lastp; p; p = p->next)
+    {
+      int cmp;
+      if (p->tag != Tag_compatibility)
+       break;
+      cmp = strcmp(s, p->attr.s);
+      if (cmp < 0 || (cmp == 0 && i < p->attr.i))
+       break;
+      lastp = &p->next;
+    }
+  list->next = *lastp;
+  *lastp = list;
 }
 
 /* Set the right machine number.  */
@@ -3883,6 +4585,49 @@ elf32_arm_set_private_flags (bfd *abfd, flagword flags)
   return TRUE;
 }
 
+/* Copy the eabi object attribute from IBFD to OBFD.  */
+static void
+copy_eabi_attributes (bfd *ibfd, bfd *obfd)
+{
+  aeabi_attribute *in_attr;
+  aeabi_attribute *out_attr;
+  aeabi_attribute_list *list;
+  int i;
+
+  in_attr = elf32_arm_tdata (ibfd)->known_eabi_attributes;
+  out_attr = elf32_arm_tdata (obfd)->known_eabi_attributes;
+  for (i = 4; i < NUM_KNOWN_ATTRIBUTES; i++)
+    {
+      out_attr->i = in_attr->i;
+      if (in_attr->s && *in_attr->s)
+       out_attr->s = attr_strdup (obfd, in_attr->s);
+      in_attr++;
+      out_attr++;
+    }
+
+  for (list = elf32_arm_tdata (ibfd)->other_eabi_attributes;
+       list;
+       list = list->next)
+    {
+      in_attr = &list->attr;
+      switch (in_attr->type)
+       {
+       case 1:
+         elf32_arm_add_eabi_attr_int (obfd, list->tag, in_attr->i);
+         break;
+       case 2:
+         elf32_arm_add_eabi_attr_string (obfd, list->tag, in_attr->s);
+         break;
+       case 3:
+         elf32_arm_add_eabi_attr_compat (obfd, in_attr->i, in_attr->s);
+         break;
+       default:
+         abort();
+       }
+    }
+}
+
+
 /* Copy backend specific data from one object module to another.  */
 
 static bfd_boolean
@@ -3934,6 +4679,289 @@ elf32_arm_copy_private_bfd_data (bfd *ibfd, bfd *obfd)
   elf_elfheader (obfd)->e_ident[EI_OSABI] =
     elf_elfheader (ibfd)->e_ident[EI_OSABI];
 
+  /* Copy EABI object attributes.  */
+  copy_eabi_attributes (ibfd, obfd);
+
+  return TRUE;
+}
+
+/* Values for Tag_ABI_PCS_R9_use.  */
+enum
+{
+  AEABI_R9_V6,
+  AEABI_R9_SB,
+  AEABI_R9_TLS,
+  AEABI_R9_unused
+};
+
+/* Values for Tag_ABI_PCS_RW_data.  */
+enum
+{
+  AEABI_PCS_RW_data_absolute,
+  AEABI_PCS_RW_data_PCrel,
+  AEABI_PCS_RW_data_SBrel,
+  AEABI_PCS_RW_data_unused
+};
+
+/* Values for Tag_ABI_enum_size.  */
+enum
+{
+  AEABI_enum_unused,
+  AEABI_enum_short,
+  AEABI_enum_wide,
+  AEABI_enum_forced_wide
+};
+
+/* Merge EABI object attributes from IBFD into OBFD.  Raise an error if there
+   are conflicting attributes.  */
+static bfd_boolean
+elf32_arm_merge_eabi_attributes (bfd *ibfd, bfd *obfd)
+{
+  aeabi_attribute *in_attr;
+  aeabi_attribute *out_attr;
+  aeabi_attribute_list *in_list;
+  aeabi_attribute_list *out_list;
+  /* Some tags have 0 = don't care, 1 = strong requirement,
+     2 = weak requirement.  */
+  static const int order_312[3] = {3, 1, 2};
+  int i;
+
+  if (!elf32_arm_tdata (ibfd)->known_eabi_attributes[0].i)
+    {
+      /* This is the first object.  Copy the attributes.  */
+      copy_eabi_attributes (ibfd, obfd);
+      return TRUE;
+    }
+
+  /* Use the Tag_null value to indicate the attributes have been
+     initialized.  */
+  elf32_arm_tdata (ibfd)->known_eabi_attributes[0].i = 1;
+
+  in_attr = elf32_arm_tdata (ibfd)->known_eabi_attributes;
+  out_attr = elf32_arm_tdata (obfd)->known_eabi_attributes;
+  /* This needs to happen before Tag_ABI_FP_number_model is merged.  */
+  if (in_attr[Tag_ABI_VFP_args].i != out_attr[Tag_ABI_VFP_args].i)
+    {
+      /* Ignore mismatches if teh object doesn't use floating point.  */
+      if (out_attr[Tag_ABI_FP_number_model].i == 0)
+       out_attr[Tag_ABI_VFP_args].i = in_attr[Tag_ABI_VFP_args].i;
+      else if (in_attr[Tag_ABI_FP_number_model].i != 0)
+       {
+         _bfd_error_handler
+           (_("ERROR: %B uses VFP register arguments, %B does not"),
+            ibfd, obfd);
+         return FALSE;
+       }
+    }
+
+  for (i = 4; i < NUM_KNOWN_ATTRIBUTES; i++)
+    {
+      /* Merge this attribute with existing attributes.  */
+      switch (i)
+       {
+       case Tag_CPU_raw_name:
+       case Tag_CPU_name:
+         /* Use whichever has the greatest architecture requirements.  */
+         if (in_attr[Tag_CPU_arch].i > out_attr[Tag_CPU_arch].i)
+           out_attr[i].s = attr_strdup(obfd, in_attr[i].s);
+         break;
+
+       case Tag_ABI_optimization_goals:
+       case Tag_ABI_FP_optimization_goals:
+         /* Use the first value seen.  */
+         break;
+
+       case Tag_CPU_arch:
+       case Tag_ARM_ISA_use:
+       case Tag_THUMB_ISA_use:
+       case Tag_VFP_arch:
+       case Tag_WMMX_arch:
+       case Tag_NEON_arch:
+         /* ??? Do NEON and WMMX conflict?  */
+       case Tag_ABI_FP_rounding:
+       case Tag_ABI_FP_denormal:
+       case Tag_ABI_FP_exceptions:
+       case Tag_ABI_FP_user_exceptions:
+       case Tag_ABI_FP_number_model:
+       case Tag_ABI_align8_preserved:
+       case Tag_ABI_HardFP_use:
+         /* Use the largest value specified.  */
+         if (in_attr[i].i > out_attr[i].i)
+           out_attr[i].i = in_attr[i].i;
+         break;
+
+       case Tag_CPU_arch_profile:
+         /* Warn if conflicting architecture profiles used.  */
+         if (out_attr[i].i && in_attr[i].i && in_attr[i].i != out_attr[i].i)
+           {
+             _bfd_error_handler
+               (_("ERROR: %B: Conflicting architecture profiles %c/%c"),
+                ibfd, in_attr[i].i, out_attr[i].i);
+             return FALSE;
+           }
+         if (in_attr[i].i)
+           out_attr[i].i = in_attr[i].i;
+         break;
+       case Tag_PCS_config:
+         if (out_attr[i].i == 0)
+           out_attr[i].i = in_attr[i].i;
+         else if (in_attr[i].i != 0 && out_attr[i].i != 0)
+           {
+             /* It's sometimes ok to mix different configs, so this is only
+                a warning.  */
+             _bfd_error_handler
+               (_("Warning: %B: Conflicting platform configuration"), ibfd);
+           }
+         break;
+       case Tag_ABI_PCS_R9_use:
+         if (out_attr[i].i != AEABI_R9_unused
+             && in_attr[i].i != AEABI_R9_unused)
+           {
+             _bfd_error_handler
+               (_("ERROR: %B: Conflicting use of R9"), ibfd);
+             return FALSE;
+           }
+         if (out_attr[i].i == AEABI_R9_unused)
+           out_attr[i].i = in_attr[i].i;
+         break;
+       case Tag_ABI_PCS_RW_data:
+         if (in_attr[i].i == AEABI_PCS_RW_data_SBrel
+             && out_attr[Tag_ABI_PCS_R9_use].i != AEABI_R9_SB
+             && out_attr[Tag_ABI_PCS_R9_use].i != AEABI_R9_unused)
+           {
+             _bfd_error_handler
+               (_("ERROR: %B: SB relative addressing conflicts with use of R9"),
+                ibfd);
+             return FALSE;
+           }
+         /* Use the smallest value specified.  */
+         if (in_attr[i].i < out_attr[i].i)
+           out_attr[i].i = in_attr[i].i;
+         break;
+       case Tag_ABI_PCS_RO_data:
+         /* Use the smallest value specified.  */
+         if (in_attr[i].i < out_attr[i].i)
+           out_attr[i].i = in_attr[i].i;
+         break;
+       case Tag_ABI_PCS_GOT_use:
+         if (in_attr[i].i > 2 || out_attr[i].i > 2
+             || order_312[in_attr[i].i] < order_312[out_attr[i].i])
+           out_attr[i].i = in_attr[i].i;
+         break;
+       case Tag_ABI_PCS_wchar_t:
+         if (out_attr[i].i && in_attr[i].i && out_attr[i].i != in_attr[i].i)
+           {
+             _bfd_error_handler
+               (_("ERROR: %B: Conflicting definitions of wchar_t"), ibfd);
+             return FALSE;
+           }
+         if (in_attr[i].i)
+           out_attr[i].i = in_attr[i].i;
+         break;
+       case Tag_ABI_align8_needed:
+         /* ??? Check against Tag_ABI_align8_preserved.  */
+         if (in_attr[i].i > 2 || out_attr[i].i > 2
+             || order_312[in_attr[i].i] < order_312[out_attr[i].i])
+           out_attr[i].i = in_attr[i].i;
+         break;
+       case Tag_ABI_enum_size:
+         if (in_attr[i].i != AEABI_enum_unused)
+           {
+             if (out_attr[i].i == AEABI_enum_unused
+                 || out_attr[i].i == AEABI_enum_forced_wide)
+               {
+                 /* The existing object is compatible with anything.
+                    Use whatever requirements the new object has.  */
+                 out_attr[i].i = in_attr[i].i;
+               }
+             else if (in_attr[i].i != AEABI_enum_forced_wide
+                      && out_attr[i].i != in_attr[i].i)
+               {
+                 _bfd_error_handler
+                   (_("ERROR: %B: Conflicting enum sizes"), ibfd);
+               }
+           }
+         break;
+       case Tag_ABI_VFP_args:
+         /* Aready done.  */
+         break;
+       case Tag_ABI_WMMX_args:
+         if (in_attr[i].i != out_attr[i].i)
+           {
+             _bfd_error_handler
+               (_("ERROR: %B uses iWMMXt register arguments, %B does not"),
+                ibfd, obfd);
+             return FALSE;
+           }
+         break;
+       default: /* All known attributes should be explicitly covered.   */
+         abort ();
+       }
+    }
+
+  in_list = elf32_arm_tdata (ibfd)->other_eabi_attributes;
+  out_list = elf32_arm_tdata (ibfd)->other_eabi_attributes;
+  while (in_list && in_list->tag == Tag_compatibility)
+    {
+      in_attr = &in_list->attr;
+      if (in_attr->i == 0)
+       continue;
+      if (in_attr->i == 1)
+       {
+         _bfd_error_handler
+           (_("ERROR: %B: Must be processed by '%s' toolchain"),
+            ibfd, in_attr->s);
+         return FALSE;
+       }
+      if (!out_list || out_list->tag != Tag_compatibility
+         || strcmp (in_attr->s, out_list->attr.s) != 0)
+       {
+         /* Add this compatibility tag to the output.  */
+         elf32_arm_add_eabi_attr_compat (obfd, in_attr->i, in_attr->s);
+         continue;
+       }
+      out_attr = &out_list->attr;
+      /* Check all the input tags with the same identifier.  */
+      for (;;)
+       {
+         if (out_list->tag != Tag_compatibility
+             || in_attr->i != out_attr->i
+             || strcmp (in_attr->s, out_attr->s) != 0)
+           {
+             _bfd_error_handler
+               (_("ERROR: %B: Incompatible object tag '%s':%d"),
+                ibfd, in_attr->s, in_attr->i);
+             return FALSE;
+           }
+         in_list = in_list->next;
+         if (in_list->tag != Tag_compatibility
+             || strcmp (in_attr->s, in_list->attr.s) != 0)
+           break;
+         in_attr = &in_list->attr;
+         out_list = out_list->next;
+         if (out_list)
+           out_attr = &out_list->attr;
+       }
+
+      /* Check the output doesn't have extra tags with this identifier.  */
+      if (out_list && out_list->tag == Tag_compatibility
+         && strcmp (in_attr->s, out_list->attr.s) == 0)
+       {
+         _bfd_error_handler
+           (_("ERROR: %B: Incompatible object tag '%s':%d"),
+            ibfd, in_attr->s, out_list->attr.i);
+         return FALSE;
+       }
+    }
+
+  for (; in_list; in_list = in_list->next)
+    {
+      if ((in_list->tag & 128) < 64)
+       _bfd_error_handler
+         (_("Warning: %B: Unknown EABI object attribute %d"),
+          ibfd, in_list->tag);
+      break;
+    }
   return TRUE;
 }
 
@@ -3956,6 +4984,9 @@ elf32_arm_merge_private_bfd_data (bfd * ibfd, bfd * obfd)
       || bfd_get_flavour (obfd) != bfd_target_elf_flavour)
     return TRUE;
 
+  if (!elf32_arm_merge_eabi_attributes (ibfd, obfd))
+    return FALSE;
+
   /* The input BFD must have had its flags initialised.  */
   /* The following seems bogus to me -- The flags are initialized in
      the assembler but I don't think an elf_flags_init field is
@@ -3998,7 +5029,7 @@ elf32_arm_merge_private_bfd_data (bfd * ibfd, bfd * obfd)
 
   /* Check to see if the input BFD actually contains any sections.  If
      not, its flags may not have been initialised either, but it
-     cannot actually cause any incompatibility.  Do not short-circuit
+     cannot actually cause any incompatiblity.  Do not short-circuit
      dynamic objects; their section list may be emptied by
     elf_link_add_object_symbols.
 
@@ -4372,15 +5403,11 @@ elf32_arm_gc_sweep_hook (bfd *                     abfd,
        }
 
       r_type = ELF32_R_TYPE (rel->r_info);
-#ifndef OLD_ARM_ABI
       r_type = arm_real_reloc_type (globals, r_type);
-#endif
       switch (r_type)
        {
        case R_ARM_GOT32:
-#ifndef OLD_ARM_ABI
        case R_ARM_GOT_PREL:
-#endif
        case R_ARM_TLS_GD32:
        case R_ARM_TLS_IE32:
          if (h != NULL)
@@ -4403,12 +5430,10 @@ elf32_arm_gc_sweep_hook (bfd *                     abfd,
        case R_ARM_REL32:
        case R_ARM_PC24:
        case R_ARM_PLT32:
-#ifndef OLD_ARM_ABI
        case R_ARM_CALL:
        case R_ARM_JUMP24:
        case R_ARM_PREL31:
-#endif
-       case R_ARM_THM_PC22:
+       case R_ARM_THM_CALL:
          /* Should the interworking branches be here also?  */
 
          if (h != NULL)
@@ -4422,7 +5447,7 @@ elf32_arm_gc_sweep_hook (bfd *                     abfd,
              if (h->plt.refcount > 0)
                {
                  h->plt.refcount -= 1;
-                 if (ELF32_R_TYPE (rel->r_info) == R_ARM_THM_PC22)
+                 if (ELF32_R_TYPE (rel->r_info) == R_ARM_THM_CALL)
                    eh->plt_thumb_refcount--;
                }
 
@@ -4504,9 +5529,7 @@ elf32_arm_check_relocs (bfd *abfd, struct bfd_link_info *info,
 
       r_symndx = ELF32_R_SYM (rel->r_info);
       r_type = ELF32_R_TYPE (rel->r_info);
-#ifndef OLD_ARM_ABI
       r_type = arm_real_reloc_type (htab, r_type);
-#endif
 
       if (r_symndx >= NUM_SHDR_ENTRIES (symtab_hdr))
        {
@@ -4518,16 +5541,19 @@ elf32_arm_check_relocs (bfd *abfd, struct bfd_link_info *info,
       if (r_symndx < symtab_hdr->sh_info)
         h = NULL;
       else
-        h = sym_hashes[r_symndx - symtab_hdr->sh_info];
+       {
+         h = sym_hashes[r_symndx - symtab_hdr->sh_info];
+         while (h->root.type == bfd_link_hash_indirect
+                || h->root.type == bfd_link_hash_warning)
+           h = (struct elf_link_hash_entry *) h->root.u.i.link;
+       }
 
       eh = (struct elf32_arm_link_hash_entry *) h;
 
       switch (r_type)
         {
          case R_ARM_GOT32:
-#ifndef OLD_ARM_ABI
          case R_ARM_GOT_PREL:
-#endif
          case R_ARM_TLS_GD32:
          case R_ARM_TLS_IE32:
            /* This symbol requires a global offset table entry.  */
@@ -4592,7 +5618,7 @@ elf32_arm_check_relocs (bfd *abfd, struct bfd_link_info *info,
                htab->tls_ldm_got.refcount++;
            /* Fall through */
 
-         case R_ARM_GOTOFF:
+         case R_ARM_GOTOFF32:
          case R_ARM_GOTPC:
            if (htab->sgot == NULL)
              {
@@ -4607,12 +5633,10 @@ elf32_arm_check_relocs (bfd *abfd, struct bfd_link_info *info,
          case R_ARM_REL32:
          case R_ARM_PC24:
          case R_ARM_PLT32:
-#ifndef OLD_ARM_ABI
          case R_ARM_CALL:
          case R_ARM_JUMP24:
          case R_ARM_PREL31:
-#endif
-         case R_ARM_THM_PC22:
+         case R_ARM_THM_CALL:
            /* Should the interworking branches be listed here?  */
            if (h != NULL)
              {
@@ -4630,20 +5654,18 @@ elf32_arm_check_relocs (bfd *abfd, struct bfd_link_info *info,
                   sure yet, because something later might force the
                   symbol local.  */
                if (r_type == R_ARM_PC24
-#ifndef OLD_ARM_ABI
                    || r_type == R_ARM_CALL
                    || r_type == R_ARM_JUMP24
                    || r_type == R_ARM_PREL31
-#endif
                    || r_type == R_ARM_PLT32
-                   || r_type == R_ARM_THM_PC22)
+                   || r_type == R_ARM_THM_CALL)
                  h->needs_plt = 1;
 
                /* If we create a PLT entry, this relocation will reference
                   it, even if it's an ABS32 relocation.  */
                h->plt.refcount += 1;
 
-               if (r_type == R_ARM_THM_PC22)
+               if (r_type == R_ARM_THM_CALL)
                  eh->plt_thumb_refcount += 1;
              }
 
@@ -4690,7 +5712,6 @@ elf32_arm_check_relocs (bfd *abfd, struct bfd_link_info *info,
                      {
                        flagword flags;
 
-                       sreloc = bfd_make_section (dynobj, name);
                        flags = (SEC_HAS_CONTENTS | SEC_READONLY
                                 | SEC_IN_MEMORY | SEC_LINKER_CREATED);
                        if ((sec->flags & SEC_ALLOC) != 0
@@ -4698,8 +5719,10 @@ elf32_arm_check_relocs (bfd *abfd, struct bfd_link_info *info,
                               relocations mapped.  */
                            && !htab->symbian_p)
                          flags |= SEC_ALLOC | SEC_LOAD;
+                       sreloc = bfd_make_section_with_flags (dynobj,
+                                                             name,
+                                                             flags);
                        if (sreloc == NULL
-                           || ! bfd_set_section_flags (dynobj, sreloc, flags)
                            || ! bfd_set_section_alignment (dynobj, sreloc, 2))
                          return FALSE;
                      }
@@ -4720,13 +5743,15 @@ elf32_arm_check_relocs (bfd *abfd, struct bfd_link_info *info,
                       easily.  Oh well.  */
 
                    asection *s;
+                   void *vpp;
+
                    s = bfd_section_from_r_symndx (abfd, &htab->sym_sec,
                                                   sec, r_symndx);
                    if (s == NULL)
                      return FALSE;
 
-                   head = ((struct elf32_arm_relocs_copied **)
-                           &elf_section_data (s)->local_dynrel);
+                   vpp = &elf_section_data (s)->local_dynrel;
+                   head = (struct elf32_arm_relocs_copied **) vpp;
                  }
 
                p = *head;
@@ -4888,6 +5913,19 @@ elf32_arm_find_nearest_line (bfd *          abfd,
   return TRUE;
 }
 
+static bfd_boolean
+elf32_arm_find_inliner_info (bfd *          abfd,
+                            const char **  filename_ptr,
+                            const char **  functionname_ptr,
+                            unsigned int * line_ptr)
+{
+  bfd_boolean found;
+  found = _bfd_dwarf2_find_inliner_info (abfd, filename_ptr,
+                                        functionname_ptr, line_ptr,
+                                        & elf_tdata (abfd)->dwarf2_find_line_info);
+  return found;
+}
+
 /* Adjust a symbol defined by a dynamic object and referenced by a
    regular object.  The current definition is in some section of the
    dynamic object, but we're not including those sections.  We have to
@@ -4980,6 +6018,13 @@ elf32_arm_adjust_dynamic_symbol (struct bfd_link_info * info,
   if (info->shared || globals->root.is_relocatable_executable)
     return TRUE;
 
+  if (h->size == 0)
+    {
+      (*_bfd_error_handler) (_("dynamic variable `%s' is zero size"),
+                            h->root.root.string);
+      return TRUE;
+    }
+
   /* We must allocate the symbol in our .dynbss section, which will
      become part of the .bss section of the executable.  There will be
      an entry for this symbol in the .dynsym section.  The dynamic
@@ -5367,10 +6412,7 @@ elf32_arm_size_dynamic_sections (bfd * output_bfd ATTRIBUTE_UNUSED,
        {
          struct elf32_arm_relocs_copied *p;
 
-         for (p = *((struct elf32_arm_relocs_copied **)
-                    &elf_section_data (s)->local_dynrel);
-              p != NULL;
-              p = p->next)
+         for (p = elf_section_data (s)->local_dynrel; p != NULL; p = p->next)
            {
              if (!bfd_is_abs_section (p->section)
                  && bfd_is_abs_section (p->section->output_section))
@@ -5445,7 +6487,6 @@ elf32_arm_size_dynamic_sections (bfd * output_bfd ATTRIBUTE_UNUSED,
   for (s = dynobj->sections; s != NULL; s = s->next)
     {
       const char * name;
-      bfd_boolean strip;
 
       if ((s->flags & SEC_LINKER_CREATED) == 0)
        continue;
@@ -5454,38 +6495,14 @@ elf32_arm_size_dynamic_sections (bfd * output_bfd ATTRIBUTE_UNUSED,
         of the dynobj section names depend upon the input files.  */
       name = bfd_get_section_name (dynobj, s);
 
-      strip = FALSE;
-
       if (strcmp (name, ".plt") == 0)
        {
-         if (s->size == 0)
-           {
-             /* Strip this section if we don't need it; see the
-                 comment below.  */
-             strip = TRUE;
-           }
-         else
-           {
-             /* Remember whether there is a PLT.  */
-             plt = TRUE;
-           }
+         /* Remember whether there is a PLT.  */
+         plt = s->size != 0;
        }
       else if (strncmp (name, ".rel", 4) == 0)
        {
-         if (s->size == 0)
-           {
-             /* If we don't need this section, strip it from the
-                output file.  This is mostly to handle .rel.bss and
-                .rel.plt.  We must create both sections in
-                create_dynamic_sections, because they must be created
-                before the linker maps input sections to output
-                sections.  The linker does that before
-                adjust_dynamic_symbol is called, and it is that
-                function which decides whether anything needs to go
-                into these sections.  */
-             strip = TRUE;
-           }
-         else
+         if (s->size != 0)
            {
              /* Remember whether there are any reloc sections other
                  than .rel.plt.  */
@@ -5497,21 +6514,34 @@ elf32_arm_size_dynamic_sections (bfd * output_bfd ATTRIBUTE_UNUSED,
              s->reloc_count = 0;
            }
        }
-      else if (strncmp (name, ".got", 4) != 0)
+      else if (strncmp (name, ".got", 4) != 0
+              && strcmp (name, ".dynbss") != 0)
        {
          /* It's not one of our sections, so don't allocate space.  */
          continue;
        }
 
-      if (strip)
+      if (s->size == 0)
        {
-         _bfd_strip_section_from_output (info, s);
+         /* If we don't need this section, strip it from the
+            output file.  This is mostly to handle .rel.bss and
+            .rel.plt.  We must create both sections in
+            create_dynamic_sections, because they must be created
+            before the linker maps input sections to output
+            sections.  The linker does that before
+            adjust_dynamic_symbol is called, and it is that
+            function which decides whether anything needs to go
+            into these sections.  */
+         s->flags |= SEC_EXCLUDE;
          continue;
        }
 
+      if ((s->flags & SEC_HAS_CONTENTS) == 0)
+       continue;
+
       /* Allocate memory for the section contents.  */
       s->contents = (bfd_byte *) bfd_zalloc (dynobj, s->size);
-      if (s->contents == NULL && s->size != 0)
+      if (s->contents == NULL)
        return FALSE;
     }
 
@@ -5525,7 +6555,7 @@ elf32_arm_size_dynamic_sections (bfd * output_bfd ATTRIBUTE_UNUSED,
 #define add_dynamic_entry(TAG, VAL) \
   _bfd_elf_add_dynamic_entry (info, TAG, VAL)
 
-      if (!info->shared)
+     if (info->executable)
        {
          if (!add_dynamic_entry (DT_DEBUG, 0))
            return FALSE;
@@ -5558,10 +6588,9 @@ elf32_arm_size_dynamic_sections (bfd * output_bfd ATTRIBUTE_UNUSED,
        {
          if (!add_dynamic_entry (DT_TEXTREL, 0))
            return FALSE;
-         info->flags |= DF_TEXTREL;
        }
     }
-#undef add_synamic_entry
+#undef add_dynamic_entry
 
   return TRUE;
 }
@@ -6084,9 +7113,125 @@ elf32_arm_fake_sections (bfd * abfd, Elf_Internal_Shdr * hdr, asection * sec)
       hdr->sh_type = SHT_ARM_EXIDX;
       hdr->sh_flags |= SHF_LINK_ORDER;
     }
+  else if (strcmp(name, ".ARM.attributes") == 0)
+    {
+      hdr->sh_type = SHT_ARM_ATTRIBUTES;
+    }
   return TRUE;
 }
 
+/* Parse an Arm EABI attributes section.  */
+static void
+elf32_arm_parse_attributes (bfd *abfd, Elf_Internal_Shdr * hdr)
+{
+  bfd_byte *contents;
+  bfd_byte *p;
+  bfd_vma len;
+
+  contents = bfd_malloc (hdr->sh_size);
+  if (!contents)
+    return;
+  if (!bfd_get_section_contents (abfd, hdr->bfd_section, contents, 0,
+                                hdr->sh_size))
+    {
+      free (contents);
+      return;
+    }
+  p = contents;
+  if (*(p++) == 'A')
+    {
+      len = hdr->sh_size - 1;
+      while (len > 0)
+       {
+         int namelen;
+         bfd_vma section_len;
+
+         section_len = bfd_get_32 (abfd, p);
+         p += 4;
+         if (section_len > len)
+           section_len = len;
+         len -= section_len;
+         namelen = strlen ((char *)p) + 1;
+         section_len -= namelen + 4;
+         if (strcmp((char *)p, "aeabi") != 0)
+           {
+             /* Vendor section.  Ignore it.  */
+             p += namelen + section_len;
+           }
+         else
+           {
+             p += namelen;
+             while (section_len > 0)
+               {
+                 int tag;
+                 unsigned int n;
+                 unsigned int val;
+                 bfd_vma subsection_len;
+                 bfd_byte *end;
+
+                 tag = read_unsigned_leb128 (abfd, p, &n);
+                 p += n;
+                 subsection_len = bfd_get_32 (abfd, p);
+                 p += 4;
+                 if (subsection_len > section_len)
+                   subsection_len = section_len;
+                 section_len -= subsection_len;
+                 subsection_len -= n + 4;
+                 end = p + subsection_len;
+                 switch (tag)
+                   {
+                   case Tag_File:
+                     while (p < end)
+                       {
+                         bfd_boolean is_string;
+
+                         tag = read_unsigned_leb128 (abfd, p, &n);
+                         p += n;
+                         if (tag == 4 || tag == 5)
+                           is_string = 1;
+                         else if (tag < 32)
+                           is_string = 0;
+                         else
+                           is_string = (tag & 1) != 0;
+                         if (tag == Tag_compatibility)
+                           {
+                             val = read_unsigned_leb128 (abfd, p, &n);
+                             p += n;
+                             elf32_arm_add_eabi_attr_compat (abfd, val,
+                                                             (char *)p);
+                             p += strlen ((char *)p) + 1;
+                           }
+                         else if (is_string)
+                           {
+                             elf32_arm_add_eabi_attr_string (abfd, tag,
+                                                             (char *)p);
+                             p += strlen ((char *)p) + 1;
+                           }
+                         else
+                           {
+                             val = read_unsigned_leb128 (abfd, p, &n);
+                             p += n;
+                             elf32_arm_add_eabi_attr_int (abfd, tag, val);
+                           }
+                       }
+                     break;
+                   case Tag_Section:
+                   case Tag_Symbol:
+                     /* Don't have anywhere convenient to attach these.
+                        Fall through for now.  */
+                   default:
+                     /* Ignore things we don't kow about.  */
+                     p += subsection_len;
+                     subsection_len = 0;
+                     break;
+                   }
+               }
+           }
+       }
+    }
+  free (contents);
+}
+
 /* Handle an ARM specific section when reading an object file.  This is
    called when bfd_section_from_shdr finds a section with an unknown
    type.  */
@@ -6105,6 +7250,8 @@ elf32_arm_section_from_shdr (bfd *abfd,
   switch (hdr->sh_type)
     {
     case SHT_ARM_EXIDX:
+    case SHT_ARM_PREEMPTMAP:
+    case SHT_ARM_ATTRIBUTES:
       break;
 
     default:
@@ -6114,9 +7261,112 @@ elf32_arm_section_from_shdr (bfd *abfd,
   if (! _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex))
     return FALSE;
 
+  if (hdr->sh_type == SHT_ARM_ATTRIBUTES)
+    elf32_arm_parse_attributes(abfd, hdr);
   return TRUE;
 }
 
+/* A structure used to record a list of sections, independently
+   of the next and prev fields in the asection structure.  */
+typedef struct section_list
+{
+  asection * sec;
+  struct section_list * next;
+  struct section_list * prev;
+}
+section_list;
+
+/* Unfortunately we need to keep a list of sections for which
+   an _arm_elf_section_data structure has been allocated.  This
+   is because it is possible for functions like elf32_arm_write_section
+   to be called on a section which has had an elf_data_structure
+   allocated for it (and so the used_by_bfd field is valid) but
+   for which the ARM extended version of this structure - the
+   _arm_elf_section_data structure - has not been allocated.  */
+static section_list * sections_with_arm_elf_section_data = NULL;
+
+static void
+record_section_with_arm_elf_section_data (asection * sec)
+{
+  struct section_list * entry;
+
+  entry = bfd_malloc (sizeof (* entry));
+  if (entry == NULL)
+    return;
+  entry->sec = sec;
+  entry->next = sections_with_arm_elf_section_data;
+  entry->prev = NULL;
+  if (entry->next != NULL)
+    entry->next->prev = entry;
+  sections_with_arm_elf_section_data = entry;
+}
+
+static struct section_list *
+find_arm_elf_section_entry (asection * sec)
+{
+  struct section_list * entry;
+  static struct section_list * last_entry = NULL;
+
+  /* This is a short cut for the typical case where the sections are added
+     to the sections_with_arm_elf_section_data list in forward order and
+     then looked up here in backwards order.  This makes a real difference
+     to the ld-srec/sec64k.exp linker test.  */
+  entry = sections_with_arm_elf_section_data;
+  if (last_entry != NULL)
+    {
+      if (last_entry->sec == sec)
+       entry = last_entry;
+      else if (last_entry->next != NULL
+              && last_entry->next->sec == sec)
+       entry = last_entry->next;
+    }
+
+  for (; entry; entry = entry->next)
+    if (entry->sec == sec)
+      break;
+
+  if (entry)
+    /* Record the entry prior to this one - it is the entry we are most
+       likely to want to locate next time.  Also this way if we have been
+       called from unrecord_section_with_arm_elf_section_data() we will not
+       be caching a pointer that is about to be freed.  */
+    last_entry = entry->prev;
+
+  return entry;
+}
+
+static _arm_elf_section_data *
+get_arm_elf_section_data (asection * sec)
+{
+  struct section_list * entry;
+
+  entry = find_arm_elf_section_entry (sec);
+
+  if (entry)
+    return elf32_arm_section_data (entry->sec);
+  else
+    return NULL;
+}
+
+static void
+unrecord_section_with_arm_elf_section_data (asection * sec)
+{
+  struct section_list * entry;
+
+  entry = find_arm_elf_section_entry (sec);
+
+  if (entry)
+    {
+      if (entry->prev != NULL)
+       entry->prev->next = entry->next;
+      if (entry->next != NULL)
+       entry->next->prev = entry->prev;
+      if (entry == sections_with_arm_elf_section_data)
+       sections_with_arm_elf_section_data = entry->next;
+      free (entry);
+    }
+}
+
 /* Called for each symbol.  Builds a section map based on mapping symbols.
    Does not alter any of the symbols.  */
 
@@ -6129,6 +7379,8 @@ elf32_arm_output_symbol_hook (struct bfd_link_info *info,
 {
   int mapcount;
   elf32_arm_section_map *map;
+  elf32_arm_section_map *newmap;
+  _arm_elf_section_data *arm_data;
   struct elf32_arm_link_hash_table *globals;
 
   /* Only do this on final link.  */
@@ -6144,25 +7396,35 @@ elf32_arm_output_symbol_hook (struct bfd_link_info *info,
   if (! bfd_is_arm_mapping_symbol_name (name))
     return TRUE;
 
-  mapcount = ++(elf32_arm_section_data (input_sec)->mapcount);
-  map = elf32_arm_section_data (input_sec)->map;
+  /* If this section has not been allocated an _arm_elf_section_data
+     structure then we cannot record anything.  */
+  arm_data = get_arm_elf_section_data (input_sec);
+  if (arm_data == NULL)
+    return TRUE;
+
+  mapcount = arm_data->mapcount + 1;
+  map = arm_data->map;
   /* TODO: This may be inefficient, but we probably don't usually have many
      mapping symbols per section.  */
-  map = bfd_realloc (map, mapcount * sizeof (elf32_arm_section_map));
-  elf32_arm_section_data (input_sec)->map = map;
+  newmap = bfd_realloc (map, mapcount * sizeof (* map));
+  if (newmap != NULL)
+    {
+      arm_data->map = newmap;
+      arm_data->mapcount = mapcount;
+
+      map[mapcount - 1].vma = elfsym->st_value;
+      map[mapcount - 1].type = name[1];
+    }
 
-  map[mapcount - 1].vma = elfsym->st_value;
-  map[mapcount - 1].type = name[1];
   return TRUE;
 }
 
-
 /* Allocate target specific section data.  */
 
 static bfd_boolean
 elf32_arm_new_section_hook (bfd *abfd, asection *sec)
 {
-  struct _arm_elf_section_data *sdata;
+  _arm_elf_section_data *sdata;
   bfd_size_type amt = sizeof (*sdata);
 
   sdata = bfd_zalloc (abfd, amt);
@@ -6170,6 +7432,8 @@ elf32_arm_new_section_hook (bfd *abfd, asection *sec)
     return FALSE;
   sec->used_by_bfd = sdata;
 
+  record_section_with_arm_elf_section_data (sec);
+
   return _bfd_elf_new_section_hook (abfd, sec);
 }
 
@@ -6192,6 +7456,7 @@ elf32_arm_write_section (bfd *output_bfd ATTRIBUTE_UNUSED, asection *sec,
                         bfd_byte *contents)
 {
   int mapcount;
+  _arm_elf_section_data *arm_data;
   elf32_arm_section_map *map;
   bfd_vma ptr;
   bfd_vma end;
@@ -6199,14 +7464,19 @@ elf32_arm_write_section (bfd *output_bfd ATTRIBUTE_UNUSED, asection *sec,
   bfd_byte tmp;
   int i;
 
-  mapcount = elf32_arm_section_data (sec)->mapcount;
-  map = elf32_arm_section_data (sec)->map;
+  /* If this section has not been allocated an _arm_elf_section_data
+     structure then we cannot record anything.  */
+  arm_data = get_arm_elf_section_data (sec);
+  if (arm_data == NULL)
+    return FALSE;
+
+  mapcount = arm_data->mapcount;
+  map = arm_data->map;
 
   if (mapcount == 0)
     return FALSE;
 
-  qsort (map, mapcount, sizeof (elf32_arm_section_map),
-        elf32_arm_compare_mapping);
+  qsort (map, mapcount, sizeof (* map), elf32_arm_compare_mapping);
 
   offset = sec->output_section->vma + sec->output_offset;
   ptr = map[0].vma - offset;
@@ -6250,10 +7520,31 @@ elf32_arm_write_section (bfd *output_bfd ATTRIBUTE_UNUSED, asection *sec,
        }
       ptr = end;
     }
+
   free (map);
+  arm_data->mapcount = 0;
+  arm_data->map = NULL;
+  unrecord_section_with_arm_elf_section_data (sec);
+
   return FALSE;
 }
 
+static void
+unrecord_section_via_map_over_sections (bfd * abfd ATTRIBUTE_UNUSED,
+                                       asection * sec,
+                                       void * ignore ATTRIBUTE_UNUSED)
+{
+  unrecord_section_with_arm_elf_section_data (sec);
+}
+
+static bfd_boolean
+elf32_arm_close_and_cleanup (bfd * abfd)
+{
+  bfd_map_over_sections (abfd, unrecord_section_via_map_over_sections, NULL);
+
+  return _bfd_elf_close_and_cleanup (abfd);
+}
+
 /* Display STT_ARM_TFUNC symbols as functions.  */
 
 static void
@@ -6409,8 +7700,11 @@ const struct elf_size_info elf32_arm_size_info = {
 #define bfd_elf32_bfd_link_hash_table_create    elf32_arm_link_hash_table_create
 #define bfd_elf32_bfd_reloc_type_lookup                elf32_arm_reloc_type_lookup
 #define bfd_elf32_find_nearest_line            elf32_arm_find_nearest_line
+#define bfd_elf32_find_inliner_info            elf32_arm_find_inliner_info
 #define bfd_elf32_new_section_hook             elf32_arm_new_section_hook
 #define bfd_elf32_bfd_is_target_special_symbol elf32_arm_is_target_special_symbol
+#define bfd_elf32_close_and_cleanup             elf32_arm_close_and_cleanup
+#define bfd_elf32_bfd_final_link               elf32_arm_bfd_final_link
 
 #define elf_backend_get_symbol_type             elf32_arm_get_symbol_type
 #define elf_backend_gc_mark_hook                elf32_arm_gc_mark_hook
@@ -6534,8 +7828,8 @@ elf32_arm_symbian_link_hash_table_create (bfd *abfd)
   return ret;
 }     
 
-static struct bfd_elf_special_section const 
-  elf32_arm_symbian_special_sections[]=
+static const struct bfd_elf_special_section
+elf32_arm_symbian_special_sections[] =
 {
   /* In a BPABI executable, the dynamic linking sections do not go in
      the loadable read-only segment.  The post-linker may wish to
This page took 0.060848 seconds and 4 git commands to generate.