+2005-07-14 Bob Rossi <bob@brasko.net>
[deliverable/binutils-gdb.git] / bfd / elf32-arm.c
index 80851092109ac5b1ac10357e6d42547d95e7172b..8adbf104a8c1006e64941d903ac6fb75b6589cef 100644 (file)
@@ -1,5 +1,5 @@
 /* 32-bit ELF support for ARM
-   Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004
+   Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
    Free Software Foundation, Inc.
 
    This file is part of BFD, the Binary File Descriptor library.
@@ -16,7 +16,7 @@
 
    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"
 #define NUM_ELEM(a)  (sizeof (a) / (sizeof (a)[0]))
 #endif
 
-#define USE_REL        1
-
 #define elf_info_to_howto               0
 #define elf_info_to_howto_rel           elf32_arm_info_to_howto
 
 #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 */
@@ -108,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) */
@@ -196,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 */
@@ -204,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 */
@@ -224,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 */
@@ -296,49 +288,49 @@ static reloc_howto_type elf32_arm_howto_table[] =
         0x07ff07ff,            /* dst_mask */
         TRUE),                 /* pcrel_offset */
 
-  /* These next three relocs are not defined, but we need to fill the space.  */
+  /* Dynamic TLS relocations.  */
 
-  HOWTO (R_ARM_NONE,           /* 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_unknown_17",    /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0,                     /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOWTO (R_ARM_TLS_DTPMOD32,   /* 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_DTPMOD32", /* name */
+         TRUE,                 /* partial_inplace */
+         0xffffffff,           /* src_mask */
+         0xffffffff,           /* dst_mask */
+         FALSE),                /* pcrel_offset */
 
-  HOWTO (R_ARM_NONE,           /* 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_unknown_18",    /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0,                     /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOWTO (R_ARM_TLS_DTPOFF32,   /* 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_DTPOFF32", /* name */
+         TRUE,                 /* partial_inplace */
+         0xffffffff,           /* src_mask */
+         0xffffffff,           /* dst_mask */
+         FALSE),                /* pcrel_offset */
 
-  HOWTO (R_ARM_NONE,           /* 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_unknown_19",    /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0,                     /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOWTO (R_ARM_TLS_TPOFF32,    /* 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_TPOFF32",  /* name */
+         TRUE,                 /* partial_inplace */
+         0xffffffff,           /* src_mask */
+         0xffffffff,           /* dst_mask */
+         FALSE),                /* pcrel_offset */
 
   /* Relocs used in ARM Linux */
 
@@ -398,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 */
@@ -406,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 */
@@ -482,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 */
@@ -658,48 +650,409 @@ static reloc_howto_type elf32_arm_howto_table[] =
         0,                     /* bitpos */
         complain_overflow_signed,/* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
-        "R_ARM_PREL31",        /* name */
+        "R_ARM_PREL31",        /* name */
+        FALSE,                 /* partial_inplace */
+        0x7fffffff,            /* src_mask */
+        0x7fffffff,            /* dst_mask */
+        TRUE),                 /* 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 */
+
+  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_bitfield,/* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_ARM_MOVT_ABS",      /* name */
+        FALSE,                 /* partial_inplace */
+        0x0000ffff,            /* src_mask */
+        0x0000ffff,            /* dst_mask */
+        FALSE),                /* pcrel_offset */
+
+  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_dont,/* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_ARM_MOVW_PREL_NC",  /* name */
+        FALSE,                 /* partial_inplace */
+        0x0000ffff,            /* src_mask */
+        0x0000ffff,            /* dst_mask */
+        TRUE),                 /* pcrel_offset */
+
+  HOWTO (R_ARM_MOVT_PREL,      /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        16,                    /* bitsize */
+        TRUE,                  /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_bitfield,/* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_ARM_MOVT_PREL",     /* name */
+        FALSE,                 /* partial_inplace */
+        0x0000ffff,            /* src_mask */
+        0x0000ffff,            /* dst_mask */
+        TRUE),                 /* pcrel_offset */
+
+  HOWTO (R_ARM_THM_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_THM_MOVW_ABS_NC",/* name */
+        FALSE,                 /* partial_inplace */
+        0x040f70ff,            /* src_mask */
+        0x040f70ff,            /* dst_mask */
+        FALSE),                /* pcrel_offset */
+
+  HOWTO (R_ARM_THM_MOVT_ABS,   /* 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_ABS",  /* name */
+        FALSE,                 /* partial_inplace */
+        0x040f70ff,            /* src_mask */
+        0x040f70ff,            /* dst_mask */
+        FALSE),                /* pcrel_offset */
+
+  HOWTO (R_ARM_THM_MOVW_PREL_NC,/* type */
+        0,                     /* rightshift */
+        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_THM_MOVW_PREL_NC",/* name */
+        FALSE,                 /* partial_inplace */
+        0x040f70ff,            /* src_mask */
+        0x040f70ff,            /* dst_mask */
+        TRUE),                 /* pcrel_offset */
+
+  HOWTO (R_ARM_THM_MOVT_PREL,  /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        16,                    /* bitsize */
+        TRUE,                  /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_bitfield,/* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_ARM_THM_MOVT_PREL", /* name */
+        FALSE,                 /* partial_inplace */
+        0x040f70ff,            /* src_mask */
+        0x040f70ff,            /* dst_mask */
+        TRUE),                 /* pcrel_offset */
+
+  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 */
+
+  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 */
+
+  /* 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 */
+
+  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 */
+
+  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 */
+
+  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 */
+};
+
+/* Relocations 57 .. 83 are the "group relocations" which we do not
+   support.  */
+
+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 */
+
+  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 */
-        0x7fffffff,            /* src_mask */
-        0x7fffffff,            /* dst_mask */
-        TRUE),                 /* pcrel_offset */
-};
+        0x00000fff,            /* src_mask */
+        0x00000fff,            /* 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 */
+  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 */
-         NULL,                  /* special_function */
-         "R_ARM_GNU_VTINHERIT", /* name */
+         _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 */
+         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 */
+  /* 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 */
-         _bfd_elf_rel_vtable_reloc_fn,  /* special_function */
-         "R_ARM_GNU_VTENTRY",   /* name */
+         NULL,                  /* special_function */
+         "R_ARM_GNU_VTINHERIT", /* name */
          FALSE,                 /* partial_inplace */
          0,                     /* src_mask */
          0,                     /* dst_mask */
-         FALSE);                /* pcrel_offset */
+         FALSE),                /* pcrel_offset */
 
-  /* 12 bit pc relative */
-static reloc_howto_type elf32_arm_thm_pc11_howto =
-  HOWTO (R_ARM_THM_PC11,       /* type */
+  HOWTO (R_ARM_THM_JUMP11,     /* type */
         1,                     /* rightshift */
         1,                     /* size (0 = byte, 1 = short, 2 = long) */
         11,                    /* bitsize */
@@ -707,15 +1060,13 @@ static reloc_howto_type elf32_arm_thm_pc11_howto =
         0,                     /* bitpos */
         complain_overflow_signed,      /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
-        "R_ARM_THM_PC11",      /* name */
+        "R_ARM_THM_JUMP11",    /* name */
         FALSE,                 /* partial_inplace */
         0x000007ff,            /* src_mask */
         0x000007ff,            /* dst_mask */
-        TRUE);                 /* pcrel_offset */
+        TRUE),                 /* pcrel_offset */
 
-  /* 12 bit pc relative */
-static reloc_howto_type elf32_arm_thm_pc9_howto =
-  HOWTO (R_ARM_THM_PC9,                /* type */
+  HOWTO (R_ARM_THM_JUMP8,      /* type */
         1,                     /* rightshift */
         1,                     /* size (0 = byte, 1 = short, 2 = long) */
         8,                     /* bitsize */
@@ -723,30 +1074,133 @@ static reloc_howto_type elf32_arm_thm_pc9_howto =
         0,                     /* bitpos */
         complain_overflow_signed,      /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
-        "R_ARM_THM_PC9",       /* name */
+        "R_ARM_THM_JUMP8",     /* name */
         FALSE,                 /* partial_inplace */
         0x000000ff,            /* src_mask */
         0x000000ff,            /* dst_mask */
-        TRUE);                 /* pcrel_offset */
+        TRUE),                 /* pcrel_offset */
 
-/* Place relative GOT-indirect.  */
-static reloc_howto_type elf32_arm_got_prel =
-  HOWTO (R_ARM_GOT_PREL,       /* type */
+  /* 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) */
-        32,                    /* bitsize */
-        TRUE,                  /* pc_relative */
+        12,                    /* 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_GOT_PREL",      /* name */
+        "R_ARM_TLS_LDO12",     /* name */
         FALSE,                 /* partial_inplace */
-        0xffffffff,            /* src_mask */
-        0xffffffff,            /* dst_mask */
-        TRUE);                 /* pcrel_offset */
+        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 */
+};
 
-/* Currently unused relocations.  */
-static reloc_howto_type elf32_arm_r_howto[4] =
+/* 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 */
@@ -808,35 +1262,18 @@ static reloc_howto_type elf32_arm_r_howto[4] =
 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;
+  if (r_type < NUM_ELEM (elf32_arm_howto_table_1))
+    return &elf32_arm_howto_table_1[r_type];
 
-    case R_ARM_GNU_VTENTRY:
-      return &elf32_arm_vtentry_howto;
-
-    case R_ARM_THM_PC11:
-      return &elf32_arm_thm_pc11_howto;
+  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];
 
-    case R_ARM_THM_PC9:
-      return &elf32_arm_thm_pc9_howto;
+  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];
 
-    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];
-
-    default:
-      return NULL;
-    }
+  return NULL;
 }
 
 static void
@@ -868,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},
@@ -881,44 +1322,35 @@ static const struct elf32_arm_reloc_map elf32_arm_reloc_map[] =
     {BFD_RELOC_ARM_ROSEGREL32,      R_ARM_ROSEGREL32},
     {BFD_RELOC_ARM_SBREL32,         R_ARM_SBREL32},
     {BFD_RELOC_ARM_PREL31,          R_ARM_PREL31},
-    {BFD_RELOC_ARM_TARGET2,         R_ARM_TARGET2}
+    {BFD_RELOC_ARM_TARGET2,         R_ARM_TARGET2},
+    {BFD_RELOC_ARM_PLT32,            R_ARM_PLT32},
+    {BFD_RELOC_ARM_TLS_GD32,        R_ARM_TLS_GD32},
+    {BFD_RELOC_ARM_TLS_LDO32,       R_ARM_TLS_LDO32},
+    {BFD_RELOC_ARM_TLS_LDM32,       R_ARM_TLS_LDM32},
+    {BFD_RELOC_ARM_TLS_DTPMOD32,     R_ARM_TLS_DTPMOD32},
+    {BFD_RELOC_ARM_TLS_DTPOFF32,     R_ARM_TLS_DTPOFF32},
+    {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;
-
-    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;
@@ -948,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)
     {
@@ -987,10 +1417,6 @@ elf32_arm_nabi_grok_psinfo (abfd, note)
 #define elf_backend_grok_prstatus      elf32_arm_nabi_grok_prstatus
 #define elf_backend_grok_psinfo                elf32_arm_nabi_grok_psinfo
 
-#ifndef USE_REL
-#define USE_REL        0
-#endif
-
 typedef unsigned long int insn32;
 typedef unsigned short int insn16;
 
@@ -1063,11 +1489,19 @@ static const bfd_vma elf32_arm_plt_entry [] =
 
 #endif
 
+/* An initial stub used if the PLT entry is referenced from Thumb code.  */
+#define PLT_THUMB_STUB_SIZE 4
+static const bfd_vma elf32_arm_plt_thumb_stub [] =
+  {
+    0x4778,            /* bx pc */
+    0x46c0             /* nop   */
+  };
+
 /* The entries in a PLT when using a DLL-based target with multiple
    address spaces.  */
 static const bfd_vma elf32_arm_symbian_plt_entry [] = 
   {
-    0xe51ff004,         /* ldr   pr, [pc, #-4] */
+    0xe51ff004,         /* ldr   pc, [pc, #-4] */
     0x00000000,         /* dcd   R_ARM_GLOB_DAT(X) */
   };
 
@@ -1091,14 +1525,41 @@ struct _arm_elf_section_data
 #define elf32_arm_section_data(sec) \
   ((struct _arm_elf_section_data *) elf_section_data (sec))
 
+/* The size of the thread control block.  */
+#define TCB_SIZE       8
+
+struct elf32_arm_obj_tdata
+{
+  struct elf_obj_tdata root;
+
+  /* tls_type for each local got entry.  */
+  char *local_got_tls_type;
+};
+
+#define elf32_arm_tdata(abfd) \
+  ((struct elf32_arm_obj_tdata *) (abfd)->tdata.any)
+
+#define elf32_arm_local_got_tls_type(abfd) \
+  (elf32_arm_tdata (abfd)->local_got_tls_type)
+
+static bfd_boolean
+elf32_arm_mkobject (bfd *abfd)
+{
+  bfd_size_type amt = sizeof (struct elf32_arm_obj_tdata);
+  abfd->tdata.any = bfd_zalloc (abfd, amt);
+  if (abfd->tdata.any == NULL)
+    return FALSE;
+  return TRUE;
+}
+
 /* The ARM linker needs to keep track of the number of relocs that it
    decides to copy in check_relocs for each symbol.  This is so that
    it can discard PC relative relocs if it doesn't need them when
    linking with -Bsymbolic.  We store the information in a field
    extending the regular ELF linker hash table.  */
 
-/* This structure keeps track of the number of PC relative relocs we
-   have copied for a given symbol.  */
+/* This structure keeps track of the number of relocs we have copied
+   for a given symbol.  */
 struct elf32_arm_relocs_copied
   {
     /* Next section.  */
@@ -1107,8 +1568,12 @@ struct elf32_arm_relocs_copied
     asection * section;
     /* Number of relocs copied in this section.  */
     bfd_size_type count;
+    /* Number of PC-relative relocs copied in this section.  */
+    bfd_size_type pc_count;
   };
 
+#define elf32_arm_hash_entry(ent) ((struct elf32_arm_link_hash_entry *)(ent))
+
 /* Arm ELF linker hash entry.  */
 struct elf32_arm_link_hash_entry
   {
@@ -1116,13 +1581,28 @@ struct elf32_arm_link_hash_entry
 
     /* Number of PC relative relocs copied for this symbol.  */
     struct elf32_arm_relocs_copied * relocs_copied;
+
+    /* We reference count Thumb references to a PLT entry separately,
+       so that we can emit the Thumb trampoline only if needed.  */
+    bfd_signed_vma plt_thumb_refcount;
+
+    /* Since PLT entries have variable size if the Thumb prologue is
+       used, we need to record the index into .got.plt instead of
+       recomputing it from the PLT offset.  */
+    bfd_signed_vma plt_got_offset;
+
+#define GOT_UNKNOWN    0
+#define GOT_NORMAL     1
+#define GOT_TLS_GD     2
+#define GOT_TLS_IE     4
+    unsigned char tls_type;
   };
 
 /* Traverse an arm ELF linker hash table.  */
 #define elf32_arm_link_hash_traverse(table, func, info)                        \
   (elf_link_hash_traverse                                              \
    (&(table)->root,                                                    \
-    (bfd_boolean (*) (struct elf_link_hash_entry *, void *))) (func), \
+    (bfd_boolean (*) (struct elf_link_hash_entry *, void *)) (func),   \
     (info)))
 
 /* Get the ARM elf linker hash table from a link_info structure.  */
@@ -1144,10 +1624,6 @@ struct elf32_arm_link_hash_table
     /* An arbitrary input BFD chosen to hold the glue sections.  */
     bfd * bfd_of_glue_owner;
 
-    /* A boolean indicating whether knowledge of the ARM's pipeline
-       length should be applied by the linker.  */
-    int no_pipeline_knowledge;
-
     /* Nonzero to output a BE8 image.  */
     int byteswap_code;
 
@@ -1158,6 +1634,12 @@ struct elf32_arm_link_hash_table
     /* The relocation to use for R_ARM_TARGET2 relocations.  */
     int target2_reloc;
 
+    /* Nonzero to fix BX instructions for ARMv4 targets.  */
+    int fix_v4bx;
+
+    /* Nonzero if the ARM/Thumb BLX instructions are available for use.  */
+    int use_blx;
+
     /* The number of bytes in the initial entry in the PLT.  */
     bfd_size_type plt_header_size;
 
@@ -1167,6 +1649,9 @@ struct elf32_arm_link_hash_table
     /* True if the target system is Symbian OS.  */
     int symbian_p;
 
+    /* True if the target uses REL relocations.  */
+    int use_rel;
+
     /* Short-cuts to get to dynamic linker sections.  */
     asection *sgot;
     asection *sgotplt;
@@ -1176,8 +1661,17 @@ struct elf32_arm_link_hash_table
     asection *sdynbss;
     asection *srelbss;
 
+    /* Data for R_ARM_TLS_LDM32 relocations.  */
+    union {
+      bfd_signed_vma refcount;
+      bfd_vma offset;
+    } tls_ldm_got;
+    
     /* Small local sym to section mapping cache.  */
     struct sym_sec_cache sym_sec;
+
+    /* For convenience in allocate_dynrelocs.  */
+    bfd * obfd;
   };
 
 /* Create an entry in an ARM ELF linker hash table.  */
@@ -1202,7 +1696,12 @@ elf32_arm_link_hash_newfunc (struct bfd_hash_entry * entry,
         _bfd_elf_link_hash_newfunc ((struct bfd_hash_entry *) ret,
                                     table, string));
   if (ret != NULL)
-    ret->relocs_copied = NULL;
+    {
+      ret->relocs_copied = NULL;
+      ret->tls_type = GOT_UNKNOWN;
+      ret->plt_thumb_refcount = 0;
+      ret->plt_got_offset = -1;
+    }
 
   return (struct bfd_hash_entry *) ret;
 }
@@ -1228,12 +1727,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;
@@ -1301,6 +1801,7 @@ elf32_arm_copy_indirect_symbol (const struct elf_backend_data *bed,
              for (q = edir->relocs_copied; q != NULL; q = q->next)
                if (q->section == p->section)
                  {
+                   q->pc_count += p->pc_count;
                    q->count += p->count;
                    *pp = p->next;
                    break;
@@ -1315,6 +1816,24 @@ 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);
+
+  if (ind->root.type == bfd_link_hash_indirect
+      && dir->got.refcount <= 0)
+    {
+      edir->tls_type = eind->tls_type;
+      eind->tls_type = GOT_UNKNOWN;
+    }
+
   _bfd_elf_link_hash_copy_indirect (bed, dir, ind);
 }
 
@@ -1347,7 +1866,6 @@ elf32_arm_link_hash_table_create (bfd *abfd)
   ret->thumb_glue_size = 0;
   ret->arm_glue_size = 0;
   ret->bfd_of_glue_owner = NULL;
-  ret->no_pipeline_knowledge = 0;
   ret->byteswap_code = 0;
   ret->target1_is_rel = 0;
   ret->target2_reloc = R_ARM_NONE;
@@ -1358,8 +1876,13 @@ elf32_arm_link_hash_table_create (bfd *abfd)
   ret->plt_header_size = 20;
   ret->plt_entry_size = 12;
 #endif
+  ret->fix_v4bx = 0;
+  ret->use_blx = 0;
   ret->symbian_p = 0;
+  ret->use_rel = 1;
   ret->sym_sec.abfd = NULL;
+  ret->obfd = abfd;
+  ret->tls_ldm_got.refcount = 0;
 
   return &ret->root.root;
 }
@@ -1432,20 +1955,35 @@ find_arm_glue (struct bfd_link_info *link_info,
   return myh;
 }
 
-/* ARM->Thumb glue:
+/* ARM->Thumb glue (static images):
 
    .arm
    __func_from_arm:
    ldr r12, __func_addr
    bx  r12
    __func_addr:
-   .word func    @ behave as if you saw a ARM_32 reloc.  */
+   .word func    @ behave as if you saw a ARM_32 reloc.  
+
+   (relocatable images)
+   .arm
+   __func_from_arm:
+   ldr r12, __func_offset
+   add r12, r12, pc
+   bx  r12
+   __func_offset:
+   .word func - .
+   */
 
-#define ARM2THUMB_GLUE_SIZE 12
+#define ARM2THUMB_STATIC_GLUE_SIZE 12
 static const insn32 a2t1_ldr_insn = 0xe59fc000;
 static const insn32 a2t2_bx_r12_insn = 0xe12fff1c;
 static const insn32 a2t3_func_addr_insn = 0x00000001;
 
+#define ARM2THUMB_PIC_GLUE_SIZE 16
+static const insn32 a2t1p_ldr_insn = 0xe59fc004;
+static const insn32 a2t2p_add_pc_insn = 0xe08cc00f;
+static const insn32 a2t3p_bx_r12_insn = 0xe12fff1c;
+
 /* Thumb->ARM:                          Thumb->(non-interworking aware) ARM
 
    .thumb                               .thumb
@@ -1559,9 +2097,16 @@ record_arm_to_thumb_glue (struct bfd_link_info * link_info,
                                    tmp_name, BSF_GLOBAL, s, val,
                                    NULL, TRUE, FALSE, &bh);
 
+  myh = (struct elf_link_hash_entry *) bh;
+  myh->type = ELF_ST_INFO (STB_LOCAL, STT_FUNC);
+  myh->forced_local = 1;
+
   free (tmp_name);
 
-  globals->arm_glue_size += ARM2THUMB_GLUE_SIZE;
+  if ((link_info->shared || globals->root.is_relocatable_executable))
+    globals->arm_glue_size += ARM2THUMB_PIC_GLUE_SIZE;
+  else
+    globals->arm_glue_size += ARM2THUMB_STATIC_GLUE_SIZE;
 
   return;
 }
@@ -1576,7 +2121,6 @@ record_thumb_to_arm_glue (struct bfd_link_info *link_info,
   struct elf_link_hash_entry *myh;
   struct bfd_link_hash_entry *bh;
   struct elf32_arm_link_hash_table *hash_table;
-  char bind;
   bfd_vma val;
 
   hash_table = elf32_arm_hash_table (link_info);
@@ -1614,8 +2158,8 @@ record_thumb_to_arm_glue (struct bfd_link_info *link_info,
 
   /* If we mark it 'Thumb', the disassembler will do a better job.  */
   myh = (struct elf_link_hash_entry *) bh;
-  bind = ELF_ST_BIND (myh->type);
-  myh->type = ELF_ST_INFO (bind, STT_ARM_TFUNC);
+  myh->type = ELF_ST_INFO (STB_LOCAL, STT_ARM_TFUNC);
+  myh->forced_local = 1;
 
   free (tmp_name);
 
@@ -1667,10 +2211,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;
 
@@ -1686,10 +2231,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;
 
@@ -1713,6 +2259,9 @@ bfd_elf32_arm_get_bfd_for_interworking (bfd *abfd, struct bfd_link_info *info)
   if (info->relocatable)
     return TRUE;
 
+  /* Make sure we don't attach the glue sections to a dynamic object.  */
+  BFD_ASSERT (!(abfd->flags & DYNAMIC));
+
   globals = elf32_arm_hash_table (info);
 
   BFD_ASSERT (globals != NULL);
@@ -1729,7 +2278,6 @@ bfd_elf32_arm_get_bfd_for_interworking (bfd *abfd, struct bfd_link_info *info)
 bfd_boolean
 bfd_elf32_arm_process_before_allocation (bfd *abfd,
                                         struct bfd_link_info *link_info,
-                                        int no_pipeline_knowledge,
                                         int byteswap_code)
 {
   Elf_Internal_Shdr *symtab_hdr;
@@ -1752,8 +2300,6 @@ bfd_elf32_arm_process_before_allocation (bfd *abfd,
   BFD_ASSERT (globals != NULL);
   BFD_ASSERT (globals->bfd_of_glue_owner != NULL);
 
-  globals->no_pipeline_knowledge = no_pipeline_knowledge;
-
   if (byteswap_code && !bfd_big_endian (abfd))
     {
       _bfd_error_handler (_("%B: BE8 images only valid in big-endian mode."),
@@ -1796,11 +2342,10 @@ bfd_elf32_arm_process_before_allocation (bfd *abfd,
 
          /* These are the only relocation types we care about.  */
          if (   r_type != R_ARM_PC24
-#ifndef OLD_ARM_ABI
+             && r_type != R_ARM_PLT32
              && 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.  */
@@ -1834,13 +2379,17 @@ bfd_elf32_arm_process_before_allocation (bfd *abfd,
          if (h == NULL)
            continue;
 
+         /* If the call will go through a PLT entry then we do not need
+            glue.  */
+         if (globals->splt != NULL && h->plt.offset != (bfd_vma) -1)
+           continue;
+
          switch (r_type)
            {
            case R_ARM_PC24:
-#ifndef OLD_ARM_ABI
+           case R_ARM_PLT32:
            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.  */
@@ -1848,7 +2397,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.  */
@@ -1857,7 +2406,7 @@ bfd_elf32_arm_process_before_allocation (bfd *abfd,
              break;
 
            default:
-             break;
+             abort ();
            }
        }
 
@@ -1887,13 +2436,14 @@ error_return:
 #endif
 
 
-#ifndef OLD_ARM_ABI
 /* Set target relocation values needed during linking.  */
 
 void
 bfd_elf32_arm_set_target_relocs (struct bfd_link_info *link_info,
                                 int target1_is_rel,
-                                char * target2_type)
+                                char * target2_type,
+                                 int fix_v4bx,
+                                int use_blx)
 {
   struct elf32_arm_link_hash_table *globals;
 
@@ -1911,8 +2461,9 @@ bfd_elf32_arm_set_target_relocs (struct bfd_link_info *link_info,
       _bfd_error_handler (_("Invalid TARGET2 relocation type '%s'."),
                          target2_type);
     }
+  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
@@ -2127,15 +2678,39 @@ elf32_arm_to_thumb_stub (struct bfd_link_info * info,
       --my_offset;
       myh->root.u.def.value = my_offset;
 
-      bfd_put_32 (output_bfd, (bfd_vma) a2t1_ldr_insn,
-                 s->contents + my_offset);
+      if ((info->shared || globals->root.is_relocatable_executable))
+       {
+         /* For relocatable objects we can't use absolute addresses,
+            so construct the address from a relative offset.  */
+         /* TODO: If the offset is small it's probably worth
+            constructing the address with adds.  */
+         bfd_put_32 (output_bfd, (bfd_vma) a2t1p_ldr_insn,
+                     s->contents + my_offset);
+         bfd_put_32 (output_bfd, (bfd_vma) a2t2p_add_pc_insn,
+                     s->contents + my_offset + 4);
+         bfd_put_32 (output_bfd, (bfd_vma) a2t3p_bx_r12_insn,
+                     s->contents + my_offset + 8);
+         /* Adjust the offset by 4 for the position of the add,
+            and 8 for the pipeline offset.  */
+         ret_offset = (val - (s->output_offset
+                              + s->output_section->vma
+                              + my_offset + 12))
+                      | 1;
+         bfd_put_32 (output_bfd, ret_offset,
+                     s->contents + my_offset + 12);
+       }
+      else
+       {
+         bfd_put_32 (output_bfd, (bfd_vma) a2t1_ldr_insn,
+                     s->contents + my_offset);
 
-      bfd_put_32 (output_bfd, (bfd_vma) a2t2_bx_r12_insn,
-                 s->contents + my_offset + 4);
+         bfd_put_32 (output_bfd, (bfd_vma) a2t2_bx_r12_insn,
+                     s->contents + my_offset + 4);
 
-      /* It's a thumb address.  Add the low order bit.  */
-      bfd_put_32 (output_bfd, val | a2t3_func_addr_insn,
-                 s->contents + my_offset + 8);
+         /* It's a thumb address.  Add the low order bit.  */
+         bfd_put_32 (output_bfd, val | a2t3_func_addr_insn,
+                     s->contents + my_offset + 8);
+       }
     }
 
   BFD_ASSERT (my_offset <= globals->arm_glue_size);
@@ -2159,8 +2734,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
@@ -2182,8 +2755,35 @@ 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.
+   This is PT_TLS segment p_vaddr.  */
+
+static bfd_vma
+dtpoff_base (struct bfd_link_info *info)
+{
+  /* If tls_sec is NULL, we should have signalled an error already.  */
+  if (elf_hash_table (info)->tls_sec == NULL)
+    return 0;
+  return elf_hash_table (info)->tls_sec->vma;
+}
+
+/* Return the relocation value for @tpoff relocation
+   if STT_TLS virtual address is ADDRESS.  */
+
+static bfd_vma
+tpoff (struct bfd_link_info *info, bfd_vma address)
+{
+  struct elf_link_hash_table *htab = elf_hash_table (info);
+  bfd_vma base;
+
+  /* If tls_sec is NULL, we should have signalled an error already.  */
+  if (htab->tls_sec == NULL)
+    return 0;
+  base = align_power ((bfd_vma) TCB_SIZE, htab->tls_sec->alignment_power);
+  return address - htab->tls_sec->vma + base;
+}
 
 /* Perform a relocation as part of a final link.  */
 
@@ -2199,7 +2799,8 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
                               asection *                   sym_sec,
                               const char *                 sym_name,
                               int                          sym_flags,
-                              struct elf_link_hash_entry * h)
+                              struct elf_link_hash_entry * h,
+                              bfd_boolean *                unresolved_reloc_p)
 {
   unsigned long                 r_type = howto->type;
   unsigned long                 r_symndx;
@@ -2217,13 +2818,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
@@ -2248,35 +2847,37 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
   local_got_offsets = elf_local_got_offsets (input_bfd);
   r_symndx = ELF32_R_SYM (rel->r_info);
 
-#if USE_REL
-  addend = bfd_get_32 (input_bfd, hit_data) & howto->src_mask;
-
-  if (addend & ((howto->src_mask + 1) >> 1))
+  if (globals->use_rel)
     {
-      signed_addend = -1;
-      signed_addend &= ~ howto->src_mask;
-      signed_addend |= addend;
+      addend = bfd_get_32 (input_bfd, hit_data) & howto->src_mask;
+
+      if (addend & ((howto->src_mask + 1) >> 1))
+       {
+         signed_addend = -1;
+         signed_addend &= ~ howto->src_mask;
+         signed_addend |= addend;
+       }
+      else
+       signed_addend = addend;
     }
   else
-    signed_addend = addend;
-#else
-  addend = signed_addend = rel->r_addend;
-#endif
+    addend = signed_addend = rel->r_addend;
 
   switch (r_type)
     {
     case R_ARM_NONE:
+      /* We don't need to find a value for this symbol.  It's just a
+        marker.  */
+      *unresolved_reloc_p = FALSE;
       return bfd_reloc_ok;
 
     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
@@ -2288,11 +2889,7 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
         will use the symbol's value, which may point to a PLT entry, but we
         don't need to handle that here.  If we created a PLT entry, all
         branches in this object should go to it.  */
-      if ((r_type != R_ARM_ABS32 && r_type != R_ARM_REL32
-#ifndef OLD_ARM_ABI
-          && r_type != R_ARM_PREL31
-#endif
-          )
+      if ((r_type != R_ARM_ABS32 && r_type != R_ARM_REL32)
          && h != NULL
          && splt != NULL
          && h->plt.offset != (bfd_vma) -1)
@@ -2305,34 +2902,34 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
          value = (splt->output_section->vma
                   + splt->output_offset
                   + h->plt.offset);
+         *unresolved_reloc_p = FALSE;
          return _bfd_final_link_relocate (howto, input_bfd, input_section,
                                           contents, rel->r_offset, value,
                                           (bfd_vma) 0);
        }
 
-      /* When generating a shared object, these relocations are copied
-        into the output file to be resolved at run time.  */
-      if (info->shared
+      /* When generating a shared object or relocatable executable, these
+        relocations are copied into the output file to be resolved at
+        run time.  */
+      if ((info->shared || globals->root.is_relocatable_executable)
          && (input_section->flags & SEC_ALLOC)
-         && ((r_type != R_ARM_REL32
-#ifndef OLD_ARM_ABI
-             && r_type != R_ARM_PREL31
-#endif
-             ) || !SYMBOL_CALLS_LOCAL (info, h))
+         && (r_type != R_ARM_REL32
+             || !SYMBOL_CALLS_LOCAL (info, h))
          && (h == NULL
              || 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
-#endif
+         && r_type != R_ARM_PREL31
          && r_type != R_ARM_PLT32)
        {
          Elf_Internal_Rela outrel;
          bfd_byte *loc;
          bfd_boolean skip, relocate;
 
+         *unresolved_reloc_p = FALSE;
+
          if (sreloc == NULL)
            {
              const char * name;
@@ -2380,16 +2977,24 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
 
              /* This symbol is local, or marked to become local.  */
              relocate = TRUE;
+             if (sym_flags == STT_ARM_TFUNC)
+               value |= 1;
              if (globals->symbian_p)
-               /* On Symbian OS, the data segment and text segement
-                  can be relocated independently.  Therefore, we must
-                  indicate the segment to which this relocation is
-                  relative.  The BPABI allows us to use any symbol in
-                  the right segment; we just use 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 = input_section->output_section->target_index;
+               {
+                 /* On Symbian OS, the data segment and text segement
+                    can be relocated independently.  Therefore, we
+                    must indicate the segment to which this
+                    relocation is relative.  The BPABI allows us to
+                    use any symbol in the right segment; we just use
+                    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.)  */
+                 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
                /* On SVR4-ish systems, the dynamic loader cannot
                   relocate the text and data segments independently,
@@ -2414,14 +3019,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.  */
@@ -2434,7 +3036,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)
@@ -2447,61 +3048,33 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
                }
            }
 
-         if (   strcmp (bfd_get_target (input_bfd), "elf32-littlearm-oabi") == 0
-             || strcmp (bfd_get_target (input_bfd), "elf32-bigarm-oabi") == 0)
-           {
-             /* The old way of doing things.  Trearing the addend as a
-                byte sized field and adding in the pipeline offset.  */
-             value -= (input_section->output_section->vma
-                       + input_section->output_offset);
-             value -= rel->r_offset;
-             value += addend;
-
-             if (! globals->no_pipeline_knowledge)
-               value -= 8;
-           }
+         /* The ARM ELF ABI says that this reloc is computed as: S - P + A
+            where:
+             S is the address of the symbol in the relocation.
+             P is address of the instruction being relocated.
+             A is the addend (extracted from the instruction) in bytes.
+
+            S is held in 'value'.
+            P is the base address of the section containing the
+              instruction plus the offset of the reloc into that
+              section, ie:
+                (input_section->output_section->vma +
+                 input_section->output_offset +
+                 rel->r_offset).
+            A is the addend, converted into bytes, ie:
+                (signed_addend * 4)
+
+            Note: None of these operations have knowledge of the pipeline
+            size of the processor, thus it is up to the assembler to
+            encode this information into the addend.  */
+         value -= (input_section->output_section->vma
+                   + input_section->output_offset);
+         value -= rel->r_offset;
+         if (globals->use_rel)
+           value += (signed_addend << howto->size);
          else
-           {
-             /* The ARM ELF ABI says that this reloc is computed as: S - P + A
-                where:
-                 S is the address of the symbol in the relocation.
-                 P is address of the instruction being relocated.
-                 A is the addend (extracted from the instruction) in bytes.
-
-                S is held in 'value'.
-                P is the base address of the section containing the
-                  instruction plus the offset of the reloc into that
-                  section, ie:
-                    (input_section->output_section->vma +
-                     input_section->output_offset +
-                     rel->r_offset).
-                A is the addend, converted into bytes, ie:
-                    (signed_addend * 4)
-
-                Note: None of these operations have knowledge of the pipeline
-                size of the processor, thus it is up to the assembler to
-                encode this information into the addend.  */
-             value -= (input_section->output_section->vma
-                       + input_section->output_offset);
-             value -= rel->r_offset;
-             value += (signed_addend << howto->size);
-
-             /* Previous versions of this code also used to add in the
-                pipeline offset here.  This is wrong because the linker is
-                not supposed to know about such things, and one day it might
-                change.  In order to support old binaries that need the old
-                behaviour however, so we attempt to detect which ABI was
-                used to create the reloc.  */
-             if (! globals->no_pipeline_knowledge)
-               {
-                 Elf_Internal_Ehdr * i_ehdrp; /* Elf file header, internal form */
-
-                 i_ehdrp = elf_elfheader (input_bfd);
-
-                 if (i_ehdrp->e_ident[EI_OSABI] == 0)
-                   value -= 8;
-               }
-           }
+           /* RELA addends do not have to be adjusted by howto->size.  */
+           value += signed_addend;
 
          signed_addend = value;
          signed_addend >>= howto->rightshift;
@@ -2518,14 +3091,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;
@@ -2542,7 +3113,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);
@@ -2558,7 +3128,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);
@@ -2595,12 +3164,13 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
 
     case R_ARM_THM_ABS5:
       /* Support ldr and str instructions for the thumb.  */
-#if USE_REL
-      /* Need to refetch addend.  */
-      addend = bfd_get_16 (input_bfd, hit_data) & howto->src_mask;
-      /* ??? Need to determine shift amount from operand size.  */
-      addend >>= howto->rightshift;
-#endif
+      if (globals->use_rel)
+       {
+         /* Need to refetch addend.  */
+         addend = bfd_get_16 (input_bfd, hit_data) & howto->src_mask;
+         /* ??? Need to determine shift amount from operand size.  */
+         addend >>= howto->rightshift;
+       }
       value += addend;
 
       /* ??? Isn't value unsigned?  */
@@ -2612,10 +3182,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;
@@ -2626,19 +3194,19 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
        bfd_signed_vma reloc_signed_min = ~ reloc_signed_max;
        bfd_vma check;
        bfd_signed_vma signed_check;
+       bfd_boolean thumb_plt_call = FALSE;
 
-#if USE_REL
        /* Need to refetch the addend and squish the two 11 bit pieces
           together.  */
-       {
-         bfd_vma upper = upper_insn & 0x7ff;
-         bfd_vma lower = lower_insn & 0x7ff;
-         upper = (upper ^ 0x400) - 0x400; /* Sign extend.  */
-         addend = (upper << 12) | (lower << 1);
-         signed_addend = addend;
-       }
-#endif
-#ifndef OLD_ARM_ABI
+       if (globals->use_rel)
+         {
+           bfd_vma upper = upper_insn & 0x7ff;
+           bfd_vma lower = lower_insn & 0x7ff;
+           upper = (upper ^ 0x400) - 0x400; /* Sign extend.  */
+           addend = (upper << 12) | (lower << 1);
+           signed_addend = addend;
+         }
+
        if (r_type == R_ARM_THM_XPC22)
          {
            /* Check for Thumb to Thumb call.  */
@@ -2651,12 +3219,14 @@ 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
-              function call at all, but rather a long jump.  */
-           if (sym_flags != STT_ARM_TFUNC && sym_flags != STT_SECTION)
+              function call at all, but rather a long jump.  Calls through
+              the PLT do not require stubs.  */
+           if (sym_flags != STT_ARM_TFUNC && sym_flags != STT_SECTION
+               && (h == NULL || splt == NULL
+                   || h->plt.offset == (bfd_vma) -1))
              {
                if (elf32_thumb_to_arm_stub
                    (info, sym_name, input_bfd, output_bfd, input_section,
@@ -2667,29 +3237,34 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
              }
          }
 
+       /* Handle calls via the PLT.  */
+       if (h != NULL && splt != NULL && h->plt.offset != (bfd_vma) -1)
+         {
+           value = (splt->output_section->vma
+                    + splt->output_offset
+                    + h->plt.offset);
+           if (globals->use_blx)
+             {
+               /* If the Thumb BLX instruction is available, convert the
+                  BL to a BLX instruction to call the ARM-mode PLT entry.  */
+               if ((lower_insn & (0x3 << 11)) == 0x3 << 11)
+                 {
+                   lower_insn = (lower_insn & ~(0x3 << 11)) | 0x1 << 11;
+                   thumb_plt_call = TRUE;
+                 }
+             }
+           else
+             /* Target the Thumb stub before the ARM PLT entry.  */
+             value -= PLT_THUMB_STUB_SIZE;
+           *unresolved_reloc_p = FALSE;
+         }
+
        relocation = value + signed_addend;
 
        relocation -= (input_section->output_section->vma
                       + input_section->output_offset
                       + rel->r_offset);
 
-       if (! globals->no_pipeline_knowledge)
-         {
-           Elf_Internal_Ehdr * i_ehdrp; /* Elf file header, internal form.  */
-
-           i_ehdrp = elf_elfheader (input_bfd);
-
-           /* Previous versions of this code also used to add in the pipline
-              offset here.  This is wrong because the linker is not supposed
-              to know about such things, and one day it might change.  In order
-              to support old binaries that need the old behaviour however, so
-              we attempt to detect which ABI was used to create the reloc.  */
-           if (   strcmp (bfd_get_target (input_bfd), "elf32-littlearm-oabi") == 0
-               || strcmp (bfd_get_target (input_bfd), "elf32-bigarm-oabi") == 0
-               || i_ehdrp->e_ident[EI_OSABI] == 0)
-             relocation += 4;
-         }
-
        check = relocation >> howto->rightshift;
 
        /* If this is a signed value, the rightshift just dropped
@@ -2703,15 +3278,15 @@ 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))
+       if ((r_type == R_ARM_THM_XPC22
+            && ((lower_insn & 0x1800) == 0x0800))
+           || thumb_plt_call)
          /* For a BLX instruction, make sure that the relocation is rounded up
             to a word boundary.  This follows the semantics of the instruction
             which specifies that bit 1 of the target address will come from bit
             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);
@@ -2724,7 +3299,153 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
       }
       break;
 
-    case R_ARM_THM_PC11:
+    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;
@@ -2732,22 +3453,27 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
        bfd_signed_vma reloc_signed_min = ~ reloc_signed_max;
        bfd_signed_vma signed_check;
 
-#if USE_REL
-       /* Need to refetch addend.  */
-       addend = bfd_get_16 (input_bfd, hit_data) & howto->src_mask;
-       if (addend & ((howto->src_mask + 1) >> 1))
+       /* CZB cannot jump backward.  */
+       if (r_type == R_ARM_THM_JUMP6)
+         reloc_signed_min = 0;
+
+       if (globals->use_rel)
          {
-           signed_addend = -1;
-           signed_addend &= ~ howto->src_mask;
-           signed_addend |= addend;
+           /* Need to refetch addend.  */
+           addend = bfd_get_16 (input_bfd, hit_data) & howto->src_mask;
+           if (addend & ((howto->src_mask + 1) >> 1))
+             {
+               signed_addend = -1;
+               signed_addend &= ~ howto->src_mask;
+               signed_addend |= addend;
+             }
+           else
+             signed_addend = addend;
+           /* The value in the insn has been right shifted.  We need to
+              undo this, so that we can perform the address calculation
+              in terms of bytes.  */
+           signed_addend <<= howto->rightshift;
          }
-       else
-         signed_addend = addend;
-       /* The value in the insn has been right shifted.  We need to
-          undo this, so that we can perform the address calculation
-          in terms of bytes.  */
-       signed_addend <<= howto->rightshift;
-#endif
        relocation = value + signed_addend;
 
        relocation -= (input_section->output_section->vma
@@ -2756,7 +3482,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);
@@ -2768,7 +3498,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:
@@ -2777,11 +3506,12 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
        bfd_vma relocation;
 
        insn = bfd_get_32 (input_bfd, hit_data);
-#if USE_REL
-       /* Extract the addend.  */
-       addend = (insn & 0xff) << ((insn & 0xf00) >> 7);
-       signed_addend = addend;
-#endif
+       if (globals->use_rel)
+         {
+           /* Extract the addend.  */
+           addend = (insn & 0xff) << ((insn & 0xf00) >> 7);
+           signed_addend = addend;
+         }
        relocation = value + signed_addend;
 
        relocation -= (input_section->output_section->vma
@@ -2793,25 +3523,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.  */
 
@@ -2842,15 +3559,14 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
       if (sgot == NULL)
         return bfd_reloc_notsupported;
 
+      *unresolved_reloc_p = FALSE;
       value = sgot->output_section->vma;
       return _bfd_final_link_relocate (howto, input_bfd, input_section,
                                       contents, rel->r_offset, value,
                                       (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)
@@ -2895,6 +3611,8 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
                  h->got.offset |= 1;
                }
            }
+         else
+           *unresolved_reloc_p = FALSE;
 
          value = sgot->output_offset + off;
        }
@@ -2914,6 +3632,13 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
            off &= ~1;
          else
            {
+             /* If we are addressing a Thumb function, we need to
+                adjust the address by one, so that attempts to
+                call the function pointer will correctly
+                interpret it as Thumb code.  */
+             if (sym_flags == STT_ARM_TFUNC)
+               value |= 1;
+
              bfd_put_32 (output_bfd, value, sgot->contents + off);
 
              if (info->shared)
@@ -2946,36 +3671,243 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
                                       contents, rel->r_offset, value,
                                       (bfd_vma) 0);
 
-    case R_ARM_SBREL32:
-      return bfd_reloc_notsupported;
+    case R_ARM_TLS_LDO32:
+      value = value - dtpoff_base (info);
 
-    case R_ARM_AMP_VCALL9:
-      return bfd_reloc_notsupported;
+      return _bfd_final_link_relocate (howto, input_bfd, input_section,
+                                      contents, rel->r_offset, value, (bfd_vma) 0);
 
-    case R_ARM_RSBREL32:
-      return bfd_reloc_notsupported;
+    case R_ARM_TLS_LDM32:
+      {
+       bfd_vma off;
 
-    case R_ARM_THM_RPC22:
-      return bfd_reloc_notsupported;
+       if (globals->sgot == NULL)
+         abort ();
 
-    case R_ARM_RREL32:
-      return bfd_reloc_notsupported;
+       off = globals->tls_ldm_got.offset;
 
-    case R_ARM_RABS32:
-      return bfd_reloc_notsupported;
+       if ((off & 1) != 0)
+         off &= ~1;
+       else
+         {
+           /* If we don't know the module number, create a relocation
+              for it.  */
+           if (info->shared)
+             {
+               Elf_Internal_Rela outrel;
+               bfd_byte *loc;
 
-    case R_ARM_RPC24:
-      return bfd_reloc_notsupported;
+               if (globals->srelgot == NULL)
+                 abort ();
 
-    case R_ARM_RBASE:
-      return bfd_reloc_notsupported;
+               outrel.r_offset = (globals->sgot->output_section->vma
+                                  + globals->sgot->output_offset + off);
+               outrel.r_info = ELF32_R_INFO (0, R_ARM_TLS_DTPMOD32);
+
+               bfd_put_32 (output_bfd, 0, globals->sgot->contents + off);
+
+               loc = globals->srelgot->contents;
+               loc += globals->srelgot->reloc_count++ * sizeof (Elf32_External_Rel);
+               bfd_elf32_swap_reloc_out (output_bfd, &outrel, loc);
+             }
+           else
+             bfd_put_32 (output_bfd, 1, globals->sgot->contents + off);
+
+           globals->tls_ldm_got.offset |= 1;
+         }
+
+       value = globals->sgot->output_section->vma + globals->sgot->output_offset + off 
+         - (input_section->output_section->vma + input_section->output_offset + rel->r_offset);
+
+       return _bfd_final_link_relocate (howto, input_bfd, input_section,
+                                        contents, rel->r_offset, value,
+                                        (bfd_vma) 0);
+      }
+
+    case R_ARM_TLS_GD32:
+    case R_ARM_TLS_IE32:
+      {
+       bfd_vma off;
+       int indx;
+       char tls_type;
+
+       if (globals->sgot == NULL)
+         abort ();
+
+       indx = 0;
+       if (h != NULL)
+         {
+           bfd_boolean dyn;
+           dyn = globals->root.dynamic_sections_created;
+           if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info->shared, h)
+               && (!info->shared
+                   || !SYMBOL_REFERENCES_LOCAL (info, h)))
+             {
+               *unresolved_reloc_p = FALSE;
+               indx = h->dynindx;
+             }
+           off = h->got.offset;
+           tls_type = ((struct elf32_arm_link_hash_entry *) h)->tls_type;
+         }
+       else
+         {
+           if (local_got_offsets == NULL)
+             abort ();
+           off = local_got_offsets[r_symndx];
+           tls_type = elf32_arm_local_got_tls_type (input_bfd)[r_symndx];
+         }
+
+       if (tls_type == GOT_UNKNOWN)
+         abort ();
+
+       if ((off & 1) != 0)
+         off &= ~1;
+       else
+         {
+           bfd_boolean need_relocs = FALSE;
+           Elf_Internal_Rela outrel;
+           bfd_byte *loc = NULL;
+           int cur_off = off;
+
+           /* The GOT entries have not been initialized yet.  Do it
+              now, and emit any relocations.  If both an IE GOT and a
+              GD GOT are necessary, we emit the GD first.  */
+
+           if ((info->shared || indx != 0)
+               && (h == NULL
+                   || ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
+                   || h->root.type != bfd_link_hash_undefweak))
+             {
+               need_relocs = TRUE;
+               if (globals->srelgot == NULL)
+                 abort ();
+               loc = globals->srelgot->contents;
+               loc += globals->srelgot->reloc_count * sizeof (Elf32_External_Rel);
+             }
+
+           if (tls_type & GOT_TLS_GD)
+             {
+               if (need_relocs)
+                 {
+                   outrel.r_offset = (globals->sgot->output_section->vma
+                                      + globals->sgot->output_offset + cur_off);
+                   outrel.r_info = ELF32_R_INFO (indx, R_ARM_TLS_DTPMOD32);
+                   bfd_put_32 (output_bfd, 0, globals->sgot->contents + cur_off);
+
+                   bfd_elf32_swap_reloc_out (output_bfd, &outrel, loc);
+                   globals->srelgot->reloc_count++;
+                   loc += sizeof (Elf32_External_Rel);
+
+                   if (indx == 0)
+                     bfd_put_32 (output_bfd, value - dtpoff_base (info),
+                                 globals->sgot->contents + cur_off + 4);
+                   else
+                     {
+                       bfd_put_32 (output_bfd, 0,
+                                   globals->sgot->contents + cur_off + 4);
+
+                       outrel.r_info = ELF32_R_INFO (indx,
+                                                     R_ARM_TLS_DTPOFF32);
+                       outrel.r_offset += 4;
+                       bfd_elf32_swap_reloc_out (output_bfd, &outrel, loc);
+                       globals->srelgot->reloc_count++;
+                       loc += sizeof (Elf32_External_Rel);
+                     }
+                 }
+               else
+                 {
+                   /* If we are not emitting relocations for a
+                      general dynamic reference, then we must be in a
+                      static link or an executable link with the
+                      symbol binding locally.  Mark it as belonging
+                      to module 1, the executable.  */
+                   bfd_put_32 (output_bfd, 1,
+                               globals->sgot->contents + cur_off);
+                   bfd_put_32 (output_bfd, value - dtpoff_base (info),
+                               globals->sgot->contents + cur_off + 4);
+                 }
+
+               cur_off += 8;
+             }
+
+           if (tls_type & GOT_TLS_IE)
+             {
+               if (need_relocs)
+                 {
+                   outrel.r_offset = (globals->sgot->output_section->vma
+                                      + globals->sgot->output_offset
+                                      + cur_off);
+                   outrel.r_info = ELF32_R_INFO (indx, R_ARM_TLS_TPOFF32);
+
+                   if (indx == 0)
+                     bfd_put_32 (output_bfd, value - dtpoff_base (info),
+                                 globals->sgot->contents + cur_off);
+                   else
+                     bfd_put_32 (output_bfd, 0,
+                                 globals->sgot->contents + cur_off);
+
+                   bfd_elf32_swap_reloc_out (output_bfd, &outrel, loc);
+                   globals->srelgot->reloc_count++;
+                   loc += sizeof (Elf32_External_Rel);
+                 }
+               else
+                 bfd_put_32 (output_bfd, tpoff (info, value),
+                             globals->sgot->contents + cur_off);
+               cur_off += 4;
+             }
+
+           if (h != NULL)
+             h->got.offset |= 1;
+           else
+             local_got_offsets[r_symndx] |= 1;
+         }
+
+       if ((tls_type & GOT_TLS_GD) && r_type != R_ARM_TLS_GD32)
+         off += 8;
+       value = globals->sgot->output_section->vma + globals->sgot->output_offset + off 
+         - (input_section->output_section->vma + input_section->output_offset + rel->r_offset);
+
+       return _bfd_final_link_relocate (howto, input_bfd, input_section,
+                                        contents, rel->r_offset, value,
+                                        (bfd_vma) 0);
+      }
+
+    case R_ARM_TLS_LE32:
+      if (info->shared)
+       {
+         (*_bfd_error_handler)
+           (_("%B(%A+0x%lx): R_ARM_TLS_LE32 relocation not permitted in shared object"),
+            input_bfd, input_section,
+            (long) rel->r_offset, howto->name);
+         return FALSE;   
+       }
+      else
+       value = tpoff (info, value);
+      
+      return _bfd_final_link_relocate (howto, input_bfd, input_section,
+                                      contents, rel->r_offset, value, (bfd_vma) 0);
+
+    case R_ARM_V4BX:
+      if (globals->fix_v4bx)
+        {
+          bfd_vma insn = bfd_get_32 (input_bfd, hit_data);
+
+          /* Ensure that we have a BX instruction.  */
+          BFD_ASSERT ((insn & 0x0ffffff0) == 0x012fff10);
+
+          /* Preserve Rm (lowest four bits) and the condition code
+             (highest four bits). Other bits encode MOV PC,Rm.  */
+          insn = (insn & 0xf000000f) | 0x01a0f000;
+
+          bfd_put_32 (input_bfd, insn, hit_data);
+        }
+      return bfd_reloc_ok;
 
     default:
       return bfd_reloc_notsupported;
     }
 }
 
-#if USE_REL
 /* Add INCREMENT to the reloc (of type HOWTO) at ADDRESS.  */
 static void
 arm_add_to_rel (bfd *              abfd,
@@ -2985,7 +3917,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;
@@ -3030,10 +3962,9 @@ arm_add_to_rel (bfd *              abfd,
          break;
 
        case R_ARM_PC24:
-#ifndef OLD_ARM_ABI
+       case R_ARM_PLT32:
        case R_ARM_CALL:
        case R_ARM_JUMP24:
-#endif
          addend <<= howto->size;
          addend += increment;
 
@@ -3049,7 +3980,16 @@ arm_add_to_rel (bfd *              abfd,
       bfd_put_32 (abfd, contents, address);
     }
 }
-#endif /* USE_REL */
+
+#define IS_ARM_TLS_RELOC(R_TYPE)       \
+  ((R_TYPE) == R_ARM_TLS_GD32          \
+   || (R_TYPE) == R_ARM_TLS_LDO32      \
+   || (R_TYPE) == R_ARM_TLS_LDM32      \
+   || (R_TYPE) == R_ARM_TLS_DTPOFF32   \
+   || (R_TYPE) == R_ARM_TLS_DTPMOD32   \
+   || (R_TYPE) == R_ARM_TLS_TPOFF32    \
+   || (R_TYPE) == R_ARM_TLS_LE32       \
+   || (R_TYPE) == R_ARM_TLS_IE32)
 
 /* Relocate an ARM ELF section.  */
 static bfd_boolean
@@ -3067,11 +4007,11 @@ elf32_arm_relocate_section (bfd *                  output_bfd,
   Elf_Internal_Rela *rel;
   Elf_Internal_Rela *relend;
   const char *name;
+  struct elf32_arm_link_hash_table * globals;
 
-#if !USE_REL
-  if (info->relocatable)
+  globals = elf32_arm_hash_table (info);
+  if (info->relocatable && !globals->use_rel)
     return TRUE;
-#endif
 
   symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr;
   sym_hashes = elf_sym_hashes (input_bfd);
@@ -3089,19 +4029,21 @@ elf32_arm_relocate_section (bfd *                  output_bfd,
       bfd_vma                      relocation;
       bfd_reloc_status_type        r;
       arelent                      bfd_reloc;
+      char                         sym_type;
+      bfd_boolean                  unresolved_reloc = FALSE;
 
       r_symndx = ELF32_R_SYM (rel->r_info);
       r_type   = ELF32_R_TYPE (rel->r_info);
+      r_type   = arm_real_reloc_type (globals, r_type);
 
       if (   r_type == R_ARM_GNU_VTENTRY
           || r_type == R_ARM_GNU_VTINHERIT)
         continue;
 
-      elf32_arm_info_to_howto (input_bfd, & bfd_reloc, rel);
+      bfd_reloc.howto = elf32_arm_howto_from_type (r_type);
       howto = bfd_reloc.howto;
 
-#if USE_REL
-      if (info->relocatable)
+      if (info->relocatable && globals->use_rel)
        {
          /* This is a relocatable link.  We don't have to change
             anything, unless the reloc is against a section symbol,
@@ -3122,7 +4064,6 @@ elf32_arm_relocate_section (bfd *                  output_bfd,
 
          continue;
        }
-#endif
 
       /* This is a final link.  */
       h = NULL;
@@ -3132,118 +4073,62 @@ elf32_arm_relocate_section (bfd *                  output_bfd,
       if (r_symndx < symtab_hdr->sh_info)
        {
          sym = local_syms + r_symndx;
+         sym_type = ELF32_ST_TYPE (sym->st_info);
          sec = local_sections[r_symndx];
-#if USE_REL
-         relocation = (sec->output_section->vma
-                       + sec->output_offset
-                       + sym->st_value);
-         if ((sec->flags & SEC_MERGE)
-                  && ELF_ST_TYPE (sym->st_info) == STT_SECTION)
+         if (globals->use_rel)
            {
-             asection *msec;
-             bfd_vma addend, value;
-
-             if (howto->rightshift)
+             relocation = (sec->output_section->vma
+                           + sec->output_offset
+                           + sym->st_value);
+             if ((sec->flags & SEC_MERGE)
+                      && ELF_ST_TYPE (sym->st_info) == STT_SECTION)
                {
-                 (*_bfd_error_handler)
-                   (_("%B(%A+0x%lx): %s relocation against SEC_MERGE section"),
-                    input_bfd, input_section,
-                    (long) rel->r_offset, howto->name);
-                 return FALSE;
-               }
+                 asection *msec;
+                 bfd_vma addend, value;
 
-             value = bfd_get_32 (input_bfd, contents + rel->r_offset);
+                 if (howto->rightshift)
+                   {
+                     (*_bfd_error_handler)
+                       (_("%B(%A+0x%lx): %s relocation against SEC_MERGE section"),
+                        input_bfd, input_section,
+                        (long) rel->r_offset, howto->name);
+                     return FALSE;
+                   }
 
-             /* Get the (signed) value from the instruction.  */
-             addend = value & howto->src_mask;
-             if (addend & ((howto->src_mask + 1) >> 1))
-               {
-                 bfd_signed_vma mask;
+                 value = bfd_get_32 (input_bfd, contents + rel->r_offset);
 
-                 mask = -1;
-                 mask &= ~ howto->src_mask;
-                 addend |= mask;
+                 /* Get the (signed) value from the instruction.  */
+                 addend = value & howto->src_mask;
+                 if (addend & ((howto->src_mask + 1) >> 1))
+                   {
+                     bfd_signed_vma mask;
+
+                     mask = -1;
+                     mask &= ~ howto->src_mask;
+                     addend |= mask;
+                   }
+                 msec = sec;
+                 addend =
+                   _bfd_elf_rel_local_sym (output_bfd, sym, &msec, addend)
+                   - relocation;
+                 addend += msec->output_section->vma + msec->output_offset;
+                 value = (value & ~ howto->dst_mask) | (addend & howto->dst_mask);
+                 bfd_put_32 (input_bfd, value, contents + rel->r_offset);
                }
-             msec = sec;
-             addend =
-               _bfd_elf_rel_local_sym (output_bfd, sym, &msec, addend)
-               - relocation;
-             addend += msec->output_section->vma + msec->output_offset;
-             value = (value & ~ howto->dst_mask) | (addend & howto->dst_mask);
-             bfd_put_32 (input_bfd, value, contents + rel->r_offset);
            }
-#else
-         relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel);
-#endif
+         else
+           relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel);
        }
       else
        {
          bfd_boolean warned;
-         bfd_boolean unresolved_reloc;
 
          RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel,
                                   r_symndx, symtab_hdr, sym_hashes,
                                   h, sec, relocation,
                                   unresolved_reloc, warned);
 
-         if (unresolved_reloc || relocation != 0)
-           {
-             /* In these cases, we don't need the relocation value.
-                We check specially because in some obscure cases
-                sec->output_section will be NULL.  */
-             switch (r_type)
-               {
-               case R_ARM_PC24:
-#ifndef OLD_ARM_ABI
-               case R_ARM_CALL:
-               case R_ARM_JUMP24:
-#endif
-               case R_ARM_ABS32:
-               case R_ARM_THM_PC22:
-               case R_ARM_PLT32:
-
-                 if (info->shared
-                     && ((!info->symbolic && h->dynindx != -1)
-                         || !h->def_regular)
-                     && ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
-                     && ((input_section->flags & SEC_ALLOC) != 0
-                         /* DWARF will emit R_ARM_ABS32 relocations in its
-                            sections against symbols defined externally
-                            in shared libraries.  We can't do anything
-                            with them here.  */
-                         || ((input_section->flags & SEC_DEBUGGING) != 0
-                             && h->def_dynamic))
-                     )
-                   relocation = 0;
-                 break;
-
-               case R_ARM_GOTPC:
-                 relocation = 0;
-                 break;
-
-               case R_ARM_GOT32:
-#ifndef OLD_ARM_ABI
-               case R_ARM_GOT_PREL:
-#endif
-                 if ((WILL_CALL_FINISH_DYNAMIC_SYMBOL
-                      (elf_hash_table (info)->dynamic_sections_created,
-                       info->shared, h))
-                     && (!info->shared
-                         || (!info->symbolic && h->dynindx != -1)
-                         || !h->def_regular))
-                   relocation = 0;
-                 break;
-
-               default:
-                 if (unresolved_reloc)
-                   _bfd_error_handler
-                     (_("%B(%A): warning: unresolvable relocation %d against symbol `%s'"),
-                      input_bfd, input_section,
-                      r_type,
-                      h->root.root.string);
-                 break;
-               }
-           }
+         sym_type = h->type;
        }
 
       if (h != NULL)
@@ -3256,11 +4141,44 @@ elf32_arm_relocate_section (bfd *                  output_bfd,
            name = bfd_section_name (input_bfd, sec);
        }
 
+      if (r_symndx != 0
+         && r_type != R_ARM_NONE
+         && (h == NULL
+             || h->root.type == bfd_link_hash_defined
+             || h->root.type == bfd_link_hash_defweak)
+         && IS_ARM_TLS_RELOC (r_type) != (sym_type == STT_TLS))
+       {
+         (*_bfd_error_handler)
+           ((sym_type == STT_TLS
+             ? _("%B(%A+0x%lx): %s used with TLS symbol %s")
+             : _("%B(%A+0x%lx): %s used with non-TLS symbol %s")),
+            input_bfd,
+            input_section,
+            (long) rel->r_offset,
+            howto->name,
+            name);
+       }
+
       r = elf32_arm_final_link_relocate (howto, input_bfd, output_bfd,
                                         input_section, contents, rel,
                                         relocation, info, sec, name,
                                         (h ? ELF_ST_TYPE (h->type) :
-                                         ELF_ST_TYPE (sym->st_info)), h);
+                                         ELF_ST_TYPE (sym->st_info)), h,
+                                        &unresolved_reloc);
+
+      /* Dynamic relocs are not propagated for SEC_DEBUGGING sections
+        because such sections are not SEC_ALLOC and thus ld.so will
+        not process them.  */
+      if (unresolved_reloc
+          && !((input_section->flags & SEC_DEBUGGING) != 0
+               && 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);
+         return FALSE;
+       }
 
       if (r != bfd_reloc_ok)
        {
@@ -3414,6 +4332,10 @@ elf32_arm_copy_private_bfd_data (bfd *ibfd, bfd *obfd)
   elf_elfheader (obfd)->e_flags = in_flags;
   elf_flags_init (obfd) = TRUE;
 
+  /* Also copy the EI_OSABI field.  */
+  elf_elfheader (obfd)->e_ident[EI_OSABI] =
+    elf_elfheader (ibfd)->e_ident[EI_OSABI];
+
   return TRUE;
 }
 
@@ -3816,17 +4738,15 @@ elf32_arm_gc_mark_hook (asection *                   sec,
 /* Update the got entry reference counts for the section being removed.  */
 
 static bfd_boolean
-elf32_arm_gc_sweep_hook (bfd *                     abfd ATTRIBUTE_UNUSED,
-                        struct bfd_link_info *    info ATTRIBUTE_UNUSED,
-                        asection *                sec ATTRIBUTE_UNUSED,
-                        const Elf_Internal_Rela * relocs ATTRIBUTE_UNUSED)
+elf32_arm_gc_sweep_hook (bfd *                     abfd,
+                        struct bfd_link_info *    info,
+                        asection *                sec,
+                        const Elf_Internal_Rela * relocs)
 {
   Elf_Internal_Shdr *symtab_hdr;
   struct elf_link_hash_entry **sym_hashes;
   bfd_signed_vma *local_got_refcounts;
   const Elf_Internal_Rela *rel, *relend;
-  unsigned long r_symndx;
-  struct elf_link_hash_entry *h;
   struct elf32_arm_link_hash_table * globals;
 
   globals = elf32_arm_hash_table (info);
@@ -3840,22 +4760,29 @@ elf32_arm_gc_sweep_hook (bfd *                     abfd ATTRIBUTE_UNUSED,
   relend = relocs + sec->reloc_count;
   for (rel = relocs; rel < relend; rel++)
     {
+      unsigned long r_symndx;
+      struct elf_link_hash_entry *h = NULL;
       int r_type;
 
+      r_symndx = ELF32_R_SYM (rel->r_info);
+      if (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;
+       }
+
       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
-         r_symndx = ELF32_R_SYM (rel->r_info);
-         if (r_symndx >= symtab_hdr->sh_info)
+       case R_ARM_TLS_GD32:
+       case R_ARM_TLS_IE32:
+         if (h != NULL)
            {
-             h = sym_hashes[r_symndx - symtab_hdr->sh_info];
              if (h->got.refcount > 0)
                h->got.refcount -= 1;
            }
@@ -3866,40 +4793,45 @@ elf32_arm_gc_sweep_hook (bfd *                     abfd ATTRIBUTE_UNUSED,
            }
          break;
 
+       case R_ARM_TLS_LDM32:
+         elf32_arm_hash_table (info)->tls_ldm_got.refcount -= 1;
+         break;
+
        case R_ARM_ABS32:
        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
-         r_symndx = ELF32_R_SYM (rel->r_info);
-         if (r_symndx >= symtab_hdr->sh_info)
+       case R_ARM_THM_CALL:
+         /* Should the interworking branches be here also?  */
+
+         if (h != NULL)
            {
              struct elf32_arm_link_hash_entry *eh;
              struct elf32_arm_relocs_copied **pp;
              struct elf32_arm_relocs_copied *p;
 
-             h = sym_hashes[r_symndx - symtab_hdr->sh_info];
+             eh = (struct elf32_arm_link_hash_entry *) h;
 
              if (h->plt.refcount > 0)
-               h->plt.refcount -= 1;
+               {
+                 h->plt.refcount -= 1;
+                 if (ELF32_R_TYPE (rel->r_info) == R_ARM_THM_CALL)
+                   eh->plt_thumb_refcount--;
+               }
 
              if (r_type == R_ARM_ABS32
-#ifndef OLD_ARM_ABI
-                 || r_type == R_ARM_PREL31
-#endif
                  || r_type == R_ARM_REL32)
                {
-                 eh = (struct elf32_arm_link_hash_entry *) h;
-
                  for (pp = &eh->relocs_copied; (p = *pp) != NULL;
                       pp = &p->next)
                  if (p->section == sec)
                    {
                      p->count -= 1;
+                     if (ELF32_R_TYPE (rel->r_info) == R_ARM_REL32)
+                       p->pc_count -= 1;
                      if (p->count == 0)
                        *pp = p->next;
                      break;
@@ -3938,6 +4870,15 @@ elf32_arm_check_relocs (bfd *abfd, struct bfd_link_info *info,
   htab = elf32_arm_hash_table (info);
   sreloc = NULL;
 
+  /* Create dynamic sections for relocatable executables so that we can
+     copy relocations.  */
+  if (htab->root.is_relocatable_executable
+      && ! htab->root.dynamic_sections_created)
+    {
+      if (! _bfd_elf_link_create_dynamic_sections (abfd, info))
+       return FALSE;
+    }
+
   dynobj = elf_hash_table (info)->dynobj;
   local_got_offsets = elf_local_got_offsets (abfd);
 
@@ -3953,54 +4894,102 @@ elf32_arm_check_relocs (bfd *abfd, struct bfd_link_info *info,
   for (rel = relocs; rel < rel_end; rel++)
     {
       struct elf_link_hash_entry *h;
+      struct elf32_arm_link_hash_entry *eh;
       unsigned long r_symndx;
       int r_type;
 
       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))
+       {
+         (*_bfd_error_handler) (_("%B: bad symbol index: %d"), abfd,
+                                r_symndx);
+         return FALSE;
+       }
+
       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.  */
-           if (h != NULL)
-             {
-               h->got.refcount++;
-             }
-           else
-             {
-               bfd_signed_vma *local_got_refcounts;
+           {
+             int tls_type, old_tls_type;
 
-               /* This is a global offset table entry for a local symbol.  */
-               local_got_refcounts = elf_local_got_refcounts (abfd);
-               if (local_got_refcounts == NULL)
-                 {
-                   bfd_size_type size;
+             switch (r_type)
+               {
+               case R_ARM_TLS_GD32: tls_type = GOT_TLS_GD; break;
+               case R_ARM_TLS_IE32: tls_type = GOT_TLS_IE; break;
+               default: tls_type = GOT_NORMAL; break;
+               }
 
-                   size = symtab_hdr->sh_info;
-                   size *= (sizeof (bfd_signed_vma) + sizeof (char));
-                   local_got_refcounts = bfd_zalloc (abfd, size);
-                   if (local_got_refcounts == NULL)
-                     return FALSE;
-                   elf_local_got_refcounts (abfd) = local_got_refcounts;
-                 }
-               local_got_refcounts[r_symndx] += 1;
-             }
-           if (r_type == R_ARM_GOT32)
-             break;
-           /* Fall through.  */
+             if (h != NULL)
+               {
+                 h->got.refcount++;
+                 old_tls_type = elf32_arm_hash_entry (h)->tls_type;
+               }
+             else
+               {
+                 bfd_signed_vma *local_got_refcounts;
+
+                 /* This is a global offset table entry for a local symbol.  */
+                 local_got_refcounts = elf_local_got_refcounts (abfd);
+                 if (local_got_refcounts == NULL)
+                   {
+                     bfd_size_type size;
+                     
+                     size = symtab_hdr->sh_info;
+                     size *= (sizeof (bfd_signed_vma) + sizeof(char));
+                     local_got_refcounts = bfd_zalloc (abfd, size);
+                     if (local_got_refcounts == NULL)
+                       return FALSE;
+                     elf_local_got_refcounts (abfd) = local_got_refcounts;
+                     elf32_arm_local_got_tls_type (abfd)
+                       = (char *) (local_got_refcounts + symtab_hdr->sh_info);
+                   }
+                 local_got_refcounts[r_symndx] += 1;
+                 old_tls_type = elf32_arm_local_got_tls_type (abfd) [r_symndx];
+               }
+
+             /* We will already have issued an error message if there is a
+                TLS / non-TLS mismatch, based on the symbol type.  We don't
+                support any linker relaxations.  So just combine any TLS
+                types needed.  */
+             if (old_tls_type != GOT_UNKNOWN && old_tls_type != GOT_NORMAL
+                 && tls_type != GOT_NORMAL)
+               tls_type |= old_tls_type;
+
+             if (old_tls_type != tls_type)
+               {
+                 if (h != NULL)
+                   elf32_arm_hash_entry (h)->tls_type = tls_type;
+                 else
+                   elf32_arm_local_got_tls_type (abfd) [r_symndx] = tls_type;
+               }
+           }
+           /* Fall through */
 
-         case R_ARM_GOTOFF:
+         case R_ARM_TLS_LDM32:
+           if (r_type == R_ARM_TLS_LDM32)
+               htab->tls_ldm_got.refcount++;
+           /* Fall through */
+
+         case R_ARM_GOTOFF32:
          case R_ARM_GOTPC:
            if (htab->sgot == NULL)
              {
@@ -4015,11 +5004,11 @@ 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_CALL:
+           /* Should the interworking branches be listed here?  */
            if (h != NULL)
              {
                /* If this reloc is in a read-only section, we might
@@ -4036,23 +5025,26 @@ 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
-#endif
-                   || r_type == R_ARM_PLT32)
+                   || r_type == R_ARM_PREL31
+                   || r_type == R_ARM_PLT32
+                   || 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_CALL)
+                 eh->plt_thumb_refcount += 1;
              }
 
-           /* If we are creating a shared library, and this is a reloc
-               against a global symbol, or a non PC relative reloc
-               against a local symbol, then we need to copy the reloc
-               into the shared library.  However, if we are linking with
-               -Bsymbolic, we do not need to copy a reloc against a
+           /* If we are creating a shared library or relocatable executable,
+              and this is a reloc against a global symbol, or a non PC
+              relative reloc against a local symbol, then we need to copy
+              the reloc into the shared library.  However, if we are linking
+              with -Bsymbolic, we do not need to copy a reloc against a
                global symbol which is defined in an object we are
                including in the link (i.e., DEF_REGULAR is set).  At
                this point we have not seen all the input files, so it is
@@ -4060,19 +5052,11 @@ elf32_arm_check_relocs (bfd *abfd, struct bfd_link_info *info,
                later (it is never cleared).  We account for that
                possibility below by storing information in the
                relocs_copied field of the hash table entry.  */
-           if (info->shared
+           if ((info->shared || htab->root.is_relocatable_executable)
                && (sec->flags & SEC_ALLOC) != 0
-               && ((r_type != R_ARM_PC24
-                    && r_type != R_ARM_PLT32
-#ifndef OLD_ARM_ABI
-                    && r_type != R_ARM_CALL
-                    && r_type != R_ARM_JUMP24
-                    && r_type != R_ARM_PREL31
-#endif
-                    && r_type != R_ARM_REL32)
-                   || (h != NULL
-                       && (! info->symbolic
-                           || !h->def_regular))))
+               && (r_type == R_ARM_ABS32
+                   || (h != NULL && ! h->needs_plt
+                       && (! info->symbolic || ! h->def_regular))))
              {
                struct elf32_arm_relocs_copied *p, **head;
 
@@ -4099,7 +5083,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
@@ -4107,8 +5090,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;
                      }
@@ -4150,14 +5135,12 @@ elf32_arm_check_relocs (bfd *abfd, struct bfd_link_info *info,
                    *head = p;
                    p->section = sec;
                    p->count = 0;
+                   p->pc_count = 0;
                  }
 
-               if (r_type == R_ARM_ABS32
-#ifndef OLD_ARM_ABI
-                   || r_type == R_ARM_PREL31
-#endif
-                   || r_type == R_ARM_REL32)
-                 p->count += 1;
+               if (r_type == R_ARM_REL32)
+                 p->pc_count += 1;
+               p->count += 1;
              }
            break;
 
@@ -4180,21 +5163,12 @@ elf32_arm_check_relocs (bfd *abfd, struct bfd_link_info *info,
   return TRUE;
 }
 
-static bfd_boolean
-is_arm_mapping_symbol_name (const char * name)
-{
-  return (name != NULL)
-    && (name[0] == '$')
-    && ((name[1] == 'a') || (name[1] == 't') || (name[1] == 'd'))
-    && (name[2] == 0);
-}
-
 /* Treat mapping symbols as special target symbols.  */
 
 static bfd_boolean
 elf32_arm_is_target_special_symbol (bfd * abfd ATTRIBUTE_UNUSED, asymbol * sym)
 {
-  return is_arm_mapping_symbol_name (sym->name);
+  return bfd_is_arm_mapping_symbol_name (sym->name);
 }
 
 /* This is a copy of elf_find_function() from elf.c except that
@@ -4229,12 +5203,12 @@ arm_elf_find_function (bfd *         abfd ATTRIBUTE_UNUSED,
          break;
        case STT_FUNC:
        case STT_ARM_TFUNC:
+       case STT_NOTYPE:
          /* Skip $a and $t symbols.  */
          if ((q->symbol.flags & BSF_LOCAL)
-             && is_arm_mapping_symbol_name (q->symbol.name))
+             && bfd_is_arm_mapping_symbol_name (q->symbol.name))
            continue;
          /* Fall through.  */
-       case STT_NOTYPE:
          if (bfd_get_section (&q->symbol) == section
              && q->symbol.value >= low_func
              && q->symbol.value <= offset)
@@ -4308,6 +5282,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
@@ -4321,7 +5308,10 @@ elf32_arm_adjust_dynamic_symbol (struct bfd_link_info * info,
   bfd * dynobj;
   asection * s;
   unsigned int power_of_two;
+  struct elf32_arm_link_hash_entry * eh;
+  struct elf32_arm_link_hash_table *globals;
 
+  globals = elf32_arm_hash_table (info);
   dynobj = elf_hash_table (info)->dynobj;
 
   /* Make sure we know what is going on here.  */
@@ -4332,10 +5322,12 @@ elf32_arm_adjust_dynamic_symbol (struct bfd_link_info * info,
                      && h->ref_regular
                      && !h->def_regular)));
 
+  eh = (struct elf32_arm_link_hash_entry *) h;
+
   /* If this is a function, put it in the procedure linkage table.  We
      will fill in the contents of the procedure linkage table later,
      when we know the address of the .got section.  */
-  if (h->type == STT_FUNC
+  if (h->type == STT_FUNC || h->type == STT_ARM_TFUNC
       || h->needs_plt)
     {
       if (h->plt.refcount <= 0
@@ -4349,18 +5341,22 @@ elf32_arm_adjust_dynamic_symbol (struct bfd_link_info * info,
             such a case, we don't actually need to build a procedure
             linkage table, and we can just do a PC24 reloc instead.  */
          h->plt.offset = (bfd_vma) -1;
+         eh->plt_thumb_refcount = 0;
          h->needs_plt = 0;
        }
 
       return TRUE;
     }
   else
-    /* It's possible that we incorrectly decided a .plt reloc was
-       needed for an R_ARM_PC24 or similar reloc to a non-function sym
-       in check_relocs.  We can't decide accurately between function
-       and non-function syms in check-relocs; Objects loaded later in
-       the link may change h->type.  So fix it now.  */
-    h->plt.offset = (bfd_vma) -1;
+    {
+      /* It's possible that we incorrectly decided a .plt reloc was
+        needed for an R_ARM_PC24 or similar reloc to a non-function sym
+        in check_relocs.  We can't decide accurately between function
+        and non-function syms in check-relocs; Objects loaded later in
+        the link may change h->type.  So fix it now.  */
+      h->plt.offset = (bfd_vma) -1;
+      eh->plt_thumb_refcount = 0;
+    }
 
   /* If this is a weak symbol, and there is a real definition, the
      processor independent code will have arranged for us to see the
@@ -4374,14 +5370,21 @@ elf32_arm_adjust_dynamic_symbol (struct bfd_link_info * info,
       return TRUE;
     }
 
+  /* If there are no non-GOT references, we do not need a copy
+     relocation.  */
+  if (!h->non_got_ref)
+    return TRUE;
+
   /* This is a reference to a symbol defined by a dynamic object which
      is not a function.  */
 
   /* If we are creating a shared library, we must presume that the
      only references to the symbol are via the global offset table.
      For such cases we need not do anything here; the relocations will
-     be handled correctly by relocate_section.  */
-  if (info->shared)
+     be handled correctly by relocate_section.  Relocatable executables
+     can reference data in shared objects directly, so we don't need to
+     do anything here.  */
+  if (info->shared || globals->root.is_relocatable_executable)
     return TRUE;
 
   /* We must allocate the symbol in our .dynbss section, which will
@@ -4445,6 +5448,8 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
   struct elf32_arm_link_hash_entry *eh;
   struct elf32_arm_relocs_copied *p;
 
+  eh = (struct elf32_arm_link_hash_entry *) h;
+
   if (h->root.type == bfd_link_hash_indirect)
     return TRUE;
 
@@ -4481,6 +5486,14 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
 
          h->plt.offset = s->size;
 
+         /* If we will insert a Thumb trampoline before this PLT, leave room
+            for it.  */
+         if (!htab->use_blx && eh->plt_thumb_refcount > 0)
+           {
+             h->plt.offset += PLT_THUMB_STUB_SIZE;
+             s->size += PLT_THUMB_STUB_SIZE;
+           }
+
          /* If this symbol is not defined in a regular file, and we are
             not generating a shared library, then set the symbol to this
             location in the .plt.  This is required to make function
@@ -4491,15 +5504,24 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
            {
              h->root.u.def.section = s;
              h->root.u.def.value = h->plt.offset;
+
+             /* Make sure the function is not marked as Thumb, in case
+                it is the target of an ABS32 relocation, which will
+                point to the PLT entry.  */
+             if (ELF_ST_TYPE (h->type) == STT_ARM_TFUNC)
+               h->type = ELF_ST_INFO (ELF_ST_BIND (h->type), STT_FUNC);
            }
 
          /* Make room for this entry.  */
          s->size += htab->plt_entry_size;
 
          if (!htab->symbian_p)
-           /* We also need to make an entry in the .got.plt section, which
-              will be placed in the .got section by the linker script.  */
-           htab->sgotplt->size += 4;
+           {
+             /* We also need to make an entry in the .got.plt section, which
+                will be placed in the .got section by the linker script.  */
+             eh->plt_got_offset = htab->sgotplt->size;
+             htab->sgotplt->size += 4;
+           }
 
          /* We also need to make an entry in the .rel.plt section.  */
          htab->srelplt->size += sizeof (Elf32_External_Rel);
@@ -4520,6 +5542,8 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
     {
       asection *s;
       bfd_boolean dyn;
+      int tls_type = elf32_arm_hash_entry (h)->tls_type;
+      int indx;
 
       /* Make sure this symbol is output as a dynamic symbol.
         Undefined weak syms won't yet be marked as dynamic.  */
@@ -4534,19 +5558,55 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
        {
          s = htab->sgot;
          h->got.offset = s->size;
-         s->size += 4;
+
+         if (tls_type == GOT_UNKNOWN)
+           abort ();
+
+         if (tls_type == GOT_NORMAL)
+           /* Non-TLS symbols need one GOT slot.  */
+           s->size += 4;
+         else
+           {
+             if (tls_type & GOT_TLS_GD)
+               /* R_ARM_TLS_GD32 needs 2 consecutive GOT slots.  */
+               s->size += 8;
+             if (tls_type & GOT_TLS_IE)
+               /* R_ARM_TLS_IE32 needs one GOT slot.  */
+               s->size += 4;
+           }
+
          dyn = htab->root.dynamic_sections_created;
-         if ((ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
-              || h->root.type != bfd_link_hash_undefweak)
-             && (info->shared
-                 || WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, 0, h)))
+
+         indx = 0;
+         if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info->shared, h)
+             && (!info->shared
+                 || !SYMBOL_REFERENCES_LOCAL (info, h)))
+           indx = h->dynindx;
+
+         if (tls_type != GOT_NORMAL
+             && (info->shared || indx != 0)
+             && (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
+                 || h->root.type != bfd_link_hash_undefweak))
+           {
+             if (tls_type & GOT_TLS_IE)
+               htab->srelgot->size += sizeof (Elf32_External_Rel);
+
+             if (tls_type & GOT_TLS_GD)
+               htab->srelgot->size += sizeof (Elf32_External_Rel);
+
+             if ((tls_type & GOT_TLS_GD) && indx != 0)
+               htab->srelgot->size += sizeof (Elf32_External_Rel);
+           }
+         else if ((ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
+                   || h->root.type != bfd_link_hash_undefweak)
+                  && (info->shared
+                  || WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, 0, h)))
            htab->srelgot->size += sizeof (Elf32_External_Rel);
        }
     }
   else
     h->got.offset = (bfd_vma) -1;
 
-  eh = (struct elf32_arm_link_hash_entry *) h;
   if (eh->relocs_copied == NULL)
     return TRUE;
 
@@ -4556,13 +5616,44 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
      space for pc-relative relocs that have become local due to symbol
      visibility changes.  */
 
-  if (info->shared)
+  if (info->shared || htab->root.is_relocatable_executable)
     {
-      /* Discard relocs on undefined weak syms with non-default
+      /* The only reloc that uses pc_count is R_ARM_REL32, which will
+        appear on something like ".long foo - .".  We want calls to
+        protected symbols to resolve directly to the function rather
+        than going via the plt.  If people want function pointer
+        comparisons to work as expected then they should avoid
+        writing assembly like ".long foo - .".  */
+      if (SYMBOL_CALLS_LOCAL (info, h))
+       {
+         struct elf32_arm_relocs_copied **pp;
+
+         for (pp = &eh->relocs_copied; (p = *pp) != NULL; )
+           {
+             p->count -= p->pc_count;
+             p->pc_count = 0;
+             if (p->count == 0)
+               *pp = p->next;
+             else
+               pp = &p->next;
+           }
+       }
+
+      /* Also discard relocs on undefined weak syms with non-default
          visibility.  */
       if (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT
          && h->root.type == bfd_link_hash_undefweak)
        eh->relocs_copied = NULL;
+      else if (htab->root.is_relocatable_executable && h->dynindx == -1
+              && h->root.type == bfd_link_hash_new)
+       {
+         /* Output absolute symbols so that we can create relocations
+            against them.  For normal symbols we output a relocation
+            against the section that contains them.  */
+         if (! bfd_elf_link_record_dynamic_symbol (info, h))
+           return FALSE;
+       }
+
     }
   else
     {
@@ -4607,6 +5698,35 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
   return TRUE;
 }
 
+/* Find any dynamic relocs that apply to read-only sections.  */
+
+static bfd_boolean
+elf32_arm_readonly_dynrelocs (struct elf_link_hash_entry *h, PTR inf)
+{
+  struct elf32_arm_link_hash_entry *eh;
+  struct elf32_arm_relocs_copied *p;
+
+  if (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;
+  for (p = eh->relocs_copied; p != NULL; p = p->next)
+    {
+      asection *s = p->section;
+
+      if (s != NULL && (s->flags & SEC_READONLY) != 0)
+       {
+         struct bfd_link_info *info = (struct bfd_link_info *) inf;
+
+         info->flags |= DF_TEXTREL;
+
+         /* Not an error, just cut short the traversal.  */
+         return FALSE;
+       }
+    }
+  return TRUE;
+}
+
 /* Set the sizes of the dynamic sections.  */
 
 static bfd_boolean
@@ -4684,6 +5804,7 @@ elf32_arm_size_dynamic_sections (bfd * output_bfd ATTRIBUTE_UNUSED,
       symtab_hdr = &elf_tdata (ibfd)->symtab_hdr;
       locsymcount = symtab_hdr->sh_info;
       end_local_got = local_got + locsymcount;
+      local_tls_type = elf32_arm_local_got_tls_type (ibfd);
       s = htab->sgot;
       srel = htab->srelgot;
       for (; local_got < end_local_got; ++local_got, ++local_tls_type)
@@ -4691,8 +5812,15 @@ elf32_arm_size_dynamic_sections (bfd * output_bfd ATTRIBUTE_UNUSED,
          if (*local_got > 0)
            {
              *local_got = s->size;
-             s->size += 4;
-             if (info->shared)
+             if (*local_tls_type & GOT_TLS_GD)
+               /* TLS_GD relocs need an 8-byte structure in the GOT.  */
+               s->size += 8;
+             if (*local_tls_type & GOT_TLS_IE)
+               s->size += 4;
+             if (*local_tls_type == GOT_NORMAL)
+               s->size += 4;
+
+             if (info->shared || *local_tls_type == GOT_TLS_GD)
                srel->size += sizeof (Elf32_External_Rel);
            }
          else
@@ -4700,6 +5828,18 @@ elf32_arm_size_dynamic_sections (bfd * output_bfd ATTRIBUTE_UNUSED,
        }
     }
 
+  if (htab->tls_ldm_got.refcount > 0)
+    {
+      /* Allocate two GOT entries and one dynamic relocation (if necessary)
+        for R_ARM_TLS_LDM32 relocations.  */
+      htab->tls_ldm_got.offset = htab->sgot->size;
+      htab->sgot->size += 8;
+      if (info->shared)
+       htab->srelgot->size += sizeof (Elf32_External_Rel);
+    }
+  else
+    htab->tls_ldm_got.offset = -1;
+
   /* Allocate global sym .plt and .got entries, and space for global
      sym dynamic relocs.  */
   elf_link_hash_traverse (& htab->root, allocate_dynrelocs, info);
@@ -4712,7 +5852,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;
@@ -4721,38 +5860,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.  */
@@ -4764,21 +5879,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;
     }
 
@@ -4792,7 +5920,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;
@@ -4815,14 +5943,19 @@ elf32_arm_size_dynamic_sections (bfd * output_bfd ATTRIBUTE_UNUSED,
            return FALSE;
        }
 
+      /* If any dynamic relocs apply to a read-only section,
+        then we need a DT_TEXTREL entry.  */
+      if ((info->flags & DF_TEXTREL) == 0)
+       elf_link_hash_traverse (&htab->root, elf32_arm_readonly_dynrelocs,
+                               (PTR) info);
+
       if ((info->flags & DF_TEXTREL) != 0)
        {
          if (!add_dynamic_entry (DT_TEXTREL, 0))
            return FALSE;
-         info->flags |= DF_TEXTREL;
        }
     }
-#undef add_synamic_entry
+#undef add_dynamic_entry
 
   return TRUE;
 }
@@ -4836,9 +5969,11 @@ elf32_arm_finish_dynamic_symbol (bfd * output_bfd, struct bfd_link_info * info,
 {
   bfd * dynobj;
   struct elf32_arm_link_hash_table *htab;
+  struct elf32_arm_link_hash_entry *eh;
 
   dynobj = elf_hash_table (info)->dynobj;
   htab = elf32_arm_hash_table (info);
+  eh = (struct elf32_arm_link_hash_entry *) h;
 
   if (h->plt.offset != (bfd_vma) -1)
     {
@@ -4857,13 +5992,6 @@ elf32_arm_finish_dynamic_symbol (bfd * output_bfd, struct bfd_link_info * info,
       srel = bfd_get_section_by_name (dynobj, ".rel.plt");
       BFD_ASSERT (splt != NULL && srel != NULL);
 
-      /* Get the index in the procedure linkage table which
-        corresponds to this symbol.  This is the index of this symbol
-        in all the symbols for which we are making plt entries.  The
-        first entry in the procedure linkage table is reserved.  */
-      plt_index = ((h->plt.offset - htab->plt_header_size) 
-                  / htab->plt_entry_size);
-
       /* Fill in the entry in the procedure linkage table.  */
       if (htab->symbian_p)
        {
@@ -4878,6 +6006,13 @@ elf32_arm_finish_dynamic_symbol (bfd * output_bfd, struct bfd_link_info * info,
                          + splt->output_offset
                          + h->plt.offset + 4 * (i - 1));
          rel.r_info = ELF32_R_INFO (h->dynindx, R_ARM_GLOB_DAT);
+
+         /* Get the index in the procedure linkage table which
+            corresponds to this symbol.  This is the index of this symbol
+            in all the symbols for which we are making plt entries.  The
+            first entry in the procedure linkage table is reserved.  */
+         plt_index = ((h->plt.offset - htab->plt_header_size) 
+                      / htab->plt_entry_size);
        }
       else
        {
@@ -4888,13 +6023,21 @@ elf32_arm_finish_dynamic_symbol (bfd * output_bfd, struct bfd_link_info * info,
          sgot = bfd_get_section_by_name (dynobj, ".got.plt");
          BFD_ASSERT (sgot != NULL);
 
-         /* Get the offset into the .got table of the entry that
-            corresponds to this function.  Each .got entry is 4 bytes.
-            The first three are reserved.  */
-         got_offset = (plt_index + 3) * 4;
+         /* Get the offset into the .got.plt table of the entry that
+            corresponds to this function.  */
+         got_offset = eh->plt_got_offset;
+
+         /* Get the index in the procedure linkage table which
+            corresponds to this symbol.  This is the index of this symbol
+            in all the symbols for which we are making plt entries.  The
+            first three entries in .got.plt are reserved; after that
+            symbols appear in the same order as in .plt.  */
+         plt_index = (got_offset - 12) / 4;
 
          /* Calculate the displacement between the PLT slot and the
-            entry in the GOT.  */
+            entry in the GOT.  The eight-byte offset accounts for the
+            value produced by adding to pc in the first instruction
+            of the PLT stub.  */
          got_displacement = (sgot->output_section->vma
                              + sgot->output_offset
                              + got_offset
@@ -4905,6 +6048,14 @@ elf32_arm_finish_dynamic_symbol (bfd * output_bfd, struct bfd_link_info * info,
 
          BFD_ASSERT ((got_displacement & 0xf0000000) == 0);
 
+         if (!htab->use_blx && eh->plt_thumb_refcount > 0)
+           {
+             bfd_put_16 (output_bfd, elf32_arm_plt_thumb_stub[0],
+                         splt->contents + h->plt.offset - 4);
+             bfd_put_16 (output_bfd, elf32_arm_plt_thumb_stub[1],
+                         splt->contents + h->plt.offset - 2);
+           }
+
          bfd_put_32 (output_bfd, elf32_arm_plt_entry[0] | ((got_displacement & 0x0ff00000) >> 20),
                      splt->contents + h->plt.offset + 0);
          bfd_put_32 (output_bfd, elf32_arm_plt_entry[1] | ((got_displacement & 0x000ff000) >> 12),
@@ -4946,7 +6097,9 @@ elf32_arm_finish_dynamic_symbol (bfd * output_bfd, struct bfd_link_info * info,
        }
     }
 
-  if (h->got.offset != (bfd_vma) -1)
+  if (h->got.offset != (bfd_vma) -1
+      && (elf32_arm_hash_entry (h)->tls_type & GOT_TLS_GD) == 0
+      && (elf32_arm_hash_entry (h)->tls_type & GOT_TLS_IE) == 0)
     {
       asection * sgot;
       asection * srel;
@@ -5154,8 +6307,8 @@ elf32_arm_finish_dynamic_sections (bfd * output_bfd, struct bfd_link_info * info
                          if (dyn.d_tag == DT_RELSZ 
                              || dyn.d_tag == DT_RELASZ)
                            dyn.d_un.d_val += hdr->sh_size;
-                         else if (dyn.d_un.d_val == 0
-                                  || hdr->sh_offset < dyn.d_un.d_val)
+                         else if ((ufile_ptr) hdr->sh_offset
+                                  <= dyn.d_un.d_val - 1)
                            dyn.d_un.d_val = hdr->sh_offset;
                        }
                    }
@@ -5249,7 +6402,10 @@ elf32_arm_post_process_headers (bfd * abfd, struct bfd_link_info * link_info ATT
 
   i_ehdrp = elf_elfheader (abfd);
 
-  i_ehdrp->e_ident[EI_OSABI]      = ARM_ELF_OS_ABI_VERSION;
+  if (EF_ARM_EABI_VERSION (i_ehdrp->e_flags) == EF_ARM_EABI_UNKNOWN)
+    i_ehdrp->e_ident[EI_OSABI] = ELFOSABI_ARM;
+  else
+    i_ehdrp->e_ident[EI_OSABI] = 0;
   i_ehdrp->e_ident[EI_ABIVERSION] = ARM_ELF_ABI_VERSION;
 
   if (link_info)
@@ -5325,13 +6481,15 @@ elf32_arm_fake_sections (bfd * abfd, Elf_Internal_Shdr * hdr, asection * sec)
   return TRUE;
 }
 
-/* Handle an ARM specific section when reading an object file.
-   This is called when elf.c finds a section with an unknown type.  */
+/* Handle an ARM specific section when reading an object file.  This is
+   called when bfd_section_from_shdr finds a section with an unknown
+   type.  */
 
 static bfd_boolean
 elf32_arm_section_from_shdr (bfd *abfd,
                             Elf_Internal_Shdr * hdr,
-                            const char *name)
+                            const char *name,
+                            int shindex)
 {
   /* There ought to be a place to keep ELF backend specific flags, but
      at the moment there isn't one.  We just keep track of the
@@ -5347,7 +6505,7 @@ elf32_arm_section_from_shdr (bfd *abfd,
       return FALSE;
     }
 
-  if (! _bfd_elf_make_section_from_shdr (abfd, hdr, name))
+  if (! _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex))
     return FALSE;
 
   return TRUE;
@@ -5377,7 +6535,7 @@ elf32_arm_output_symbol_hook (struct bfd_link_info *info,
     return TRUE;
 
   /* We only want mapping symbols.  */
-  if (! is_arm_mapping_symbol_name (name))
+  if (! bfd_is_arm_mapping_symbol_name (name))
     return TRUE;
 
   mapcount = ++(elf32_arm_section_data (input_sec)->mapcount);
@@ -5490,6 +6648,143 @@ elf32_arm_write_section (bfd *output_bfd ATTRIBUTE_UNUSED, asection *sec,
   return FALSE;
 }
 
+/* Display STT_ARM_TFUNC symbols as functions.  */
+
+static void
+elf32_arm_symbol_processing (bfd *abfd ATTRIBUTE_UNUSED,
+                            asymbol *asym)
+{
+  elf_symbol_type *elfsym = (elf_symbol_type *) asym;
+
+  if (ELF_ST_TYPE (elfsym->internal_elf_sym.st_info) == STT_ARM_TFUNC)
+    elfsym->symbol.flags |= BSF_FUNCTION;
+}
+
+
+/* Mangle thumb function symbols as we read them in.  */
+
+static void
+elf32_arm_swap_symbol_in (bfd * abfd,
+                         const void *psrc,
+                         const void *pshn,
+                         Elf_Internal_Sym *dst)
+{
+  bfd_elf32_swap_symbol_in (abfd, psrc, pshn, dst);
+
+  /* New EABI objects mark thumb function symbols by setting the low bit of
+     the address.  Turn these into STT_ARM_TFUNC.  */
+  if (ELF_ST_TYPE (dst->st_info) == STT_FUNC
+      && (dst->st_value & 1))
+    {
+      dst->st_info = ELF_ST_INFO (ELF_ST_BIND (dst->st_info), STT_ARM_TFUNC);
+      dst->st_value &= ~(bfd_vma) 1;
+    }
+}
+
+
+/* Mangle thumb function symbols as we write them out.  */
+
+static void
+elf32_arm_swap_symbol_out (bfd *abfd,
+                          const Elf_Internal_Sym *src,
+                          void *cdst,
+                          void *shndx)
+{
+  Elf_Internal_Sym newsym;
+
+  /* We convert STT_ARM_TFUNC symbols into STT_FUNC with the low bit
+     of the address set, as per the new EABI.  We do this unconditionally
+     because objcopy does not set the elf header flags until after
+     it writes out the symbol table.  */
+  if (ELF_ST_TYPE (src->st_info) == STT_ARM_TFUNC)
+    {
+      newsym = *src;
+      newsym.st_info = ELF_ST_INFO (ELF_ST_BIND (src->st_info), STT_FUNC);
+      newsym.st_value |= 1;
+      
+      src = &newsym;
+    }
+  bfd_elf32_swap_symbol_out (abfd, src, cdst, shndx);
+}
+
+/* Add the PT_ARM_EXIDX program header.  */
+
+static bfd_boolean
+elf32_arm_modify_segment_map (bfd *abfd, 
+                             struct bfd_link_info *info ATTRIBUTE_UNUSED)
+{
+  struct elf_segment_map *m;
+  asection *sec;
+
+  sec = bfd_get_section_by_name (abfd, ".ARM.exidx");
+  if (sec != NULL && (sec->flags & SEC_LOAD) != 0)
+    {
+      /* If there is already a PT_ARM_EXIDX header, then we do not
+        want to add another one.  This situation arises when running
+        "strip"; the input binary already has the header.  */
+      m = elf_tdata (abfd)->segment_map;
+      while (m && m->p_type != PT_ARM_EXIDX)
+       m = m->next;
+      if (!m)
+       {
+         m = bfd_zalloc (abfd, sizeof (struct elf_segment_map));
+         if (m == NULL)
+           return FALSE;
+         m->p_type = PT_ARM_EXIDX;
+         m->count = 1;
+         m->sections[0] = sec;
+
+         m->next = elf_tdata (abfd)->segment_map;
+         elf_tdata (abfd)->segment_map = m;
+       }
+    }
+
+  return TRUE;
+}
+
+/* We may add a PT_ARM_EXIDX program header.  */
+
+static int
+elf32_arm_additional_program_headers (bfd *abfd)
+{
+  asection *sec;
+
+  sec = bfd_get_section_by_name (abfd, ".ARM.exidx");
+  if (sec != NULL && (sec->flags & SEC_LOAD) != 0)
+    return 1;
+  else
+    return 0;
+}
+
+/* We use this to override swap_symbol_in and swap_symbol_out.  */
+const struct elf_size_info elf32_arm_size_info = {
+  sizeof (Elf32_External_Ehdr),
+  sizeof (Elf32_External_Phdr),
+  sizeof (Elf32_External_Shdr),
+  sizeof (Elf32_External_Rel),
+  sizeof (Elf32_External_Rela),
+  sizeof (Elf32_External_Sym),
+  sizeof (Elf32_External_Dyn),
+  sizeof (Elf_External_Note),
+  4,
+  1,
+  32, 2,
+  ELFCLASS32, EV_CURRENT,
+  bfd_elf32_write_out_phdrs,
+  bfd_elf32_write_shdrs_and_ehdr,
+  bfd_elf32_write_relocs,
+  elf32_arm_swap_symbol_in,
+  elf32_arm_swap_symbol_out,
+  bfd_elf32_slurp_reloc_table,
+  bfd_elf32_slurp_symbol_table,
+  bfd_elf32_swap_dyn_in,
+  bfd_elf32_swap_dyn_out,
+  bfd_elf32_swap_reloc_in,
+  bfd_elf32_swap_reloc_out,
+  bfd_elf32_swap_reloca_in,
+  bfd_elf32_swap_reloca_out
+};
+
 #define ELF_ARCH                       bfd_arch_arm
 #define ELF_MACHINE_CODE               EM_ARM
 #ifdef __QNXTARGET__
@@ -5497,6 +6792,9 @@ elf32_arm_write_section (bfd *output_bfd ATTRIBUTE_UNUSED, asection *sec,
 #else
 #define ELF_MAXPAGESIZE                        0x8000
 #endif
+#define ELF_MINPAGESIZE                        0x1000
+
+#define bfd_elf32_mkobject                     elf32_arm_mkobject
 
 #define bfd_elf32_bfd_copy_private_bfd_data    elf32_arm_copy_private_bfd_data
 #define bfd_elf32_bfd_merge_private_bfd_data   elf32_arm_merge_private_bfd_data
@@ -5505,6 +6803,7 @@ elf32_arm_write_section (bfd *output_bfd ATTRIBUTE_UNUSED, asection *sec,
 #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
 
@@ -5528,20 +6827,73 @@ elf32_arm_write_section (bfd *output_bfd ATTRIBUTE_UNUSED, asection *sec,
 #define elf_backend_section_from_shdr                  elf32_arm_section_from_shdr
 #define elf_backend_final_write_processing      elf32_arm_final_write_processing
 #define elf_backend_copy_indirect_symbol        elf32_arm_copy_indirect_symbol
+#define elf_backend_symbol_processing          elf32_arm_symbol_processing
+#define elf_backend_size_info                  elf32_arm_size_info
+#define elf_backend_modify_segment_map         elf32_arm_modify_segment_map
+#define elf_backend_additional_program_headers \
+  elf32_arm_additional_program_headers
 
 #define elf_backend_can_refcount    1
 #define elf_backend_can_gc_sections 1
 #define elf_backend_plt_readonly    1
 #define elf_backend_want_got_plt    1
 #define elf_backend_want_plt_sym    0
-#if !USE_REL
-#define elf_backend_rela_normal     1
-#endif
+#define elf_backend_may_use_rel_p   1
+#define elf_backend_may_use_rela_p  0
+#define elf_backend_default_use_rela_p 0
+#define elf_backend_rela_normal     0
 
 #define elf_backend_got_header_size    12
 
 #include "elf32-target.h"
 
+/* VxWorks Targets */
+
+#undef TARGET_LITTLE_SYM
+#define TARGET_LITTLE_SYM               bfd_elf32_littlearm_vxworks_vec
+#undef TARGET_LITTLE_NAME
+#define TARGET_LITTLE_NAME              "elf32-littlearm-vxworks"
+#undef TARGET_BIG_SYM
+#define TARGET_BIG_SYM                  bfd_elf32_bigarm_vxworks_vec
+#undef TARGET_BIG_NAME
+#define TARGET_BIG_NAME                 "elf32-bigarm-vxworks"
+
+/* Like elf32_arm_link_hash_table_create -- but overrides
+   appropriately for VxWorks.  */
+static struct bfd_link_hash_table *
+elf32_arm_vxworks_link_hash_table_create (bfd *abfd)
+{
+  struct bfd_link_hash_table *ret;
+
+  ret = elf32_arm_link_hash_table_create (abfd);
+  if (ret)
+    {
+      struct elf32_arm_link_hash_table *htab
+       = (struct elf32_arm_link_hash_table *)ret;
+      htab->use_rel = 0;
+    }
+  return ret;
+}     
+
+#undef elf32_bed
+#define elf32_bed elf32_arm_vxworks_bed
+
+#undef bfd_elf32_bfd_link_hash_table_create
+#define bfd_elf32_bfd_link_hash_table_create \
+  elf32_arm_vxworks_link_hash_table_create
+
+#undef elf_backend_may_use_rel_p
+#define elf_backend_may_use_rel_p   0
+#undef elf_backend_may_use_rela_p
+#define elf_backend_may_use_rela_p  1
+#undef elf_backend_default_use_rela_p
+#define elf_backend_default_use_rela_p 1
+#undef elf_backend_rela_normal
+#define elf_backend_rela_normal     1
+
+#include "elf32-target.h"
+
+
 /* Symbian OS Targets */
 
 #undef TARGET_LITTLE_SYM
@@ -5570,36 +6922,38 @@ elf32_arm_symbian_link_hash_table_create (bfd *abfd)
       /* The PLT entries are each three instructions.  */
       htab->plt_entry_size = 4 * NUM_ELEM (elf32_arm_symbian_plt_entry);
       htab->symbian_p = 1;
+      /* Symbian uses armv5t or above, so use_blx is always true.  */
+      htab->use_blx = 1;
+      htab->root.is_relocatable_executable = 1;
     }
   return ret;
 }     
 
-/* In a BPABI executable, the dynamic linking sections do not go in
-   the loadable read-only segment.  The post-linker may wish to refer
-   to these sections, but they are not part of the final program
-   image.  */
-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
+     refer to these sections, but they are not part of the final
+     program image.  */
   { ".dynamic",        8,  0, SHT_DYNAMIC,  0 },
   { ".dynstr",         7,  0, SHT_STRTAB,   0 },
   { ".dynsym",         7,  0, SHT_DYNSYM,   0 },
   { ".got",            4,  0, SHT_PROGBITS, 0 },
   { ".hash",           5,  0, SHT_HASH,     0 },
+  /* These sections do not need to be writable as the SymbianOS
+     postlinker will arrange things so that no dynamic relocation is
+     required.  */
+  { ".init_array",    11,  0, SHT_INIT_ARRAY, SHF_ALLOC },
+  { ".fini_array",    11,  0, SHT_FINI_ARRAY, SHF_ALLOC },
+  { ".preinit_array", 14,  0, SHT_PREINIT_ARRAY, SHF_ALLOC },
   { NULL,              0,  0, 0,            0 }
 };
 
-static bfd_boolean
-elf32_arm_symbian_modify_segment_map
-  PARAMS ((bfd *, struct bfd_link_info *));
-static void
-elf32_arm_symbian_begin_write_processing
-  PARAMS ((bfd *, bfd_boolean));
-
 static void
-elf32_arm_symbian_begin_write_processing (abfd, linker)
-     bfd *abfd;
-     bfd_boolean linker;
+elf32_arm_symbian_begin_write_processing (bfd *abfd, 
+                                         struct bfd_link_info *link_info
+                                           ATTRIBUTE_UNUSED)
 {
   /* BPABI objects are never loaded directly by an OS kernel; they are
      processed by a postlinker first, into an OS-specific format.  If
@@ -5613,9 +6967,8 @@ elf32_arm_symbian_begin_write_processing (abfd, linker)
 }
 
 static bfd_boolean
-elf32_arm_symbian_modify_segment_map (abfd, info)
-     bfd *abfd;
-     struct bfd_link_info *info ATTRIBUTE_UNUSED;
+elf32_arm_symbian_modify_segment_map (bfd *abfd, 
+                                     struct bfd_link_info *info)
 {
   struct elf_segment_map *m;
   asection *dynsec;
@@ -5632,7 +6985,8 @@ elf32_arm_symbian_modify_segment_map (abfd, info)
       elf_tdata (abfd)->segment_map = m;
     }
 
-  return TRUE;
+  /* Also call the generic arm routine.  */
+  return elf32_arm_modify_segment_map (abfd, info);
 }
 
 #undef elf32_bed
@@ -5666,5 +7020,13 @@ elf32_arm_symbian_modify_segment_map (abfd, info)
 #undef elf_backend_want_got_plt
 #define elf_backend_want_got_plt 0
 
-#include "elf32-target.h"
+#undef elf_backend_may_use_rel_p
+#define elf_backend_may_use_rel_p   1
+#undef elf_backend_may_use_rela_p
+#define elf_backend_may_use_rela_p  0
+#undef elf_backend_default_use_rela_p
+#define elf_backend_default_use_rela_p 0
+#undef elf_backend_rela_normal
+#define elf_backend_rela_normal     0
 
+#include "elf32-target.h"
This page took 0.074787 seconds and 4 git commands to generate.