bfd/
[deliverable/binutils-gdb.git] / bfd / elf32-arm.c
index 9d67e5462af047f9d8b07e74468f5abcde0a44f5..a458d46ce92a7828cdbe6c203edcafc930a3252f 100644 (file)
 
 #include "bfd.h"
 #include "sysdep.h"
+#include "libiberty.h"
 #include "libbfd.h"
 #include "elf-bfd.h"
+#include "elf-vxworks.h"
 #include "elf/arm.h"
 
 #ifndef NUM_ELEM
 #define NUM_ELEM(a)  (sizeof (a) / (sizeof (a)[0]))
 #endif
 
+/* Return the relocation section associated with NAME.  HTAB is the
+   bfd's elf32_arm_link_hash_entry.  */
+#define RELOC_SECTION(HTAB, NAME) \
+  ((HTAB)->use_rel ? ".rel" NAME : ".rela" NAME)
+
+/* Return size of a relocation entry.  HTAB is the bfd's
+   elf32_arm_link_hash_entry.  */
+#define RELOC_SIZE(HTAB) \
+  ((HTAB)->use_rel \
+   ? sizeof (Elf32_External_Rel) \
+   : sizeof (Elf32_External_Rela))
+
+/* Return function to swap relocations in.  HTAB is the bfd's
+   elf32_arm_link_hash_entry.  */
+#define SWAP_RELOC_IN(HTAB) \
+  ((HTAB)->use_rel \
+   ? bfd_elf32_swap_reloc_in \
+   : bfd_elf32_swap_reloca_in)
+
+/* Return function to swap relocations out.  HTAB is the bfd's
+   elf32_arm_link_hash_entry.  */
+#define SWAP_RELOC_OUT(HTAB) \
+  ((HTAB)->use_rel \
+   ? bfd_elf32_swap_reloc_out \
+   : bfd_elf32_swap_reloca_out)
+
 #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 struct elf_backend_data elf32_arm_vxworks_bed;
+
 /* 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.  */
@@ -100,19 +130,19 @@ static reloc_howto_type elf32_arm_howto_table_1[] =
         TRUE),                 /* pcrel_offset */
 
   /* 8 bit absolute - R_ARM_LDR_PC_G0 in AAELF */
-  HOWTO (R_ARM_PC13,           /* type */
+  HOWTO (R_ARM_LDR_PC_G0,      /* type */
         0,                     /* rightshift */
         0,                     /* size (0 = byte, 1 = short, 2 = long) */
-        8,                     /* bitsize */
-        FALSE,                 /* pc_relative */
+        32,                    /* bitsize */
+        TRUE,                  /* pc_relative */
         0,                     /* bitpos */
-        complain_overflow_bitfield,/* complain_on_overflow */
+        complain_overflow_dont,/* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
-        "R_ARM_PC13",          /* name */
+        "R_ARM_LDR_PC_G0",     /* name */
         FALSE,                 /* partial_inplace */
-        0x000000ff,            /* src_mask */
-        0x000000ff,            /* dst_mask */
-        FALSE),                /* pcrel_offset */
+        0xffffffff,            /* src_mask */
+        0xffffffff,            /* dst_mask */
+        TRUE),                 /* pcrel_offset */
 
    /* 16 bit absolute */
   HOWTO (R_ARM_ABS16,          /* type */
@@ -140,8 +170,8 @@ static reloc_howto_type elf32_arm_howto_table_1[] =
         bfd_elf_generic_reloc, /* special_function */
         "R_ARM_ABS12",         /* name */
         FALSE,                 /* partial_inplace */
-        0x000008ff,            /* src_mask */
-        0x000008ff,            /* dst_mask */
+        0x00000fff,            /* src_mask */
+        0x00000fff,            /* dst_mask */
         FALSE),                /* pcrel_offset */
 
   HOWTO (R_ARM_THM_ABS5,       /* type */
@@ -821,27 +851,407 @@ static reloc_howto_type elf32_arm_howto_table_1[] =
         0,                     /* bitpos */
         complain_overflow_signed,/* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
-        "R_ARM_THM_PC12",      /* name */
+        "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 */
+
+  /* Group relocations.  */
+
+  HOWTO (R_ARM_ALU_PC_G0_NC,   /* 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_ALU_PC_G0_NC",  /* name */
+        FALSE,                 /* partial_inplace */
+        0xffffffff,            /* src_mask */
+        0xffffffff,            /* dst_mask */
+        TRUE),                 /* pcrel_offset */
+
+  HOWTO (R_ARM_ALU_PC_G0,      /* 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_ALU_PC_G0",     /* name */
+        FALSE,                 /* partial_inplace */
+        0xffffffff,            /* src_mask */
+        0xffffffff,            /* dst_mask */
+        TRUE),                 /* pcrel_offset */
+
+  HOWTO (R_ARM_ALU_PC_G1_NC,   /* 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_ALU_PC_G1_NC",  /* name */
+        FALSE,                 /* partial_inplace */
+        0xffffffff,            /* src_mask */
+        0xffffffff,            /* dst_mask */
+        TRUE),                 /* pcrel_offset */
+
+  HOWTO (R_ARM_ALU_PC_G1,      /* 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_ALU_PC_G1",     /* name */
+        FALSE,                 /* partial_inplace */
+        0xffffffff,            /* src_mask */
+        0xffffffff,            /* dst_mask */
+        TRUE),                 /* pcrel_offset */
+
+  HOWTO (R_ARM_ALU_PC_G2,      /* 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_ALU_PC_G2",     /* name */
+        FALSE,                 /* partial_inplace */
+        0xffffffff,            /* src_mask */
+        0xffffffff,            /* dst_mask */
+        TRUE),                 /* pcrel_offset */
+
+  HOWTO (R_ARM_LDR_PC_G1,      /* 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_LDR_PC_G1",     /* name */
+        FALSE,                 /* partial_inplace */
+        0xffffffff,            /* src_mask */
+        0xffffffff,            /* dst_mask */
+        TRUE),                 /* pcrel_offset */
+
+  HOWTO (R_ARM_LDR_PC_G2,      /* 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_LDR_PC_G2",     /* name */
+        FALSE,                 /* partial_inplace */
+        0xffffffff,            /* src_mask */
+        0xffffffff,            /* dst_mask */
+        TRUE),                 /* pcrel_offset */
+
+  HOWTO (R_ARM_LDRS_PC_G0,     /* 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_LDRS_PC_G0",    /* name */
+        FALSE,                 /* partial_inplace */
+        0xffffffff,            /* src_mask */
+        0xffffffff,            /* dst_mask */
+        TRUE),                 /* pcrel_offset */
+
+  HOWTO (R_ARM_LDRS_PC_G1,     /* 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_LDRS_PC_G1",    /* name */
+        FALSE,                 /* partial_inplace */
+        0xffffffff,            /* src_mask */
+        0xffffffff,            /* dst_mask */
+        TRUE),                 /* pcrel_offset */
+
+  HOWTO (R_ARM_LDRS_PC_G2,     /* 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_LDRS_PC_G2",    /* name */
+        FALSE,                 /* partial_inplace */
+        0xffffffff,            /* src_mask */
+        0xffffffff,            /* dst_mask */
+        TRUE),                 /* pcrel_offset */
+
+  HOWTO (R_ARM_LDC_PC_G0,      /* 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_LDC_PC_G0",     /* name */
+        FALSE,                 /* partial_inplace */
+        0xffffffff,            /* src_mask */
+        0xffffffff,            /* dst_mask */
+        TRUE),                 /* pcrel_offset */
+
+  HOWTO (R_ARM_LDC_PC_G1,      /* 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_LDC_PC_G1",     /* name */
+        FALSE,                 /* partial_inplace */
+        0xffffffff,            /* src_mask */
+        0xffffffff,            /* dst_mask */
+        TRUE),                 /* pcrel_offset */
+
+  HOWTO (R_ARM_LDC_PC_G2,      /* 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_LDC_PC_G2",     /* name */
+        FALSE,                 /* partial_inplace */
+        0xffffffff,            /* src_mask */
+        0xffffffff,            /* dst_mask */
+        TRUE),                 /* pcrel_offset */
+
+  HOWTO (R_ARM_ALU_SB_G0_NC,           /* 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_ALU_SB_G0_NC",  /* name */
+        FALSE,                 /* partial_inplace */
+        0xffffffff,            /* src_mask */
+        0xffffffff,            /* dst_mask */
+        TRUE),                 /* pcrel_offset */
+
+  HOWTO (R_ARM_ALU_SB_G0,      /* 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_ALU_SB_G0",     /* name */
+        FALSE,                 /* partial_inplace */
+        0xffffffff,            /* src_mask */
+        0xffffffff,            /* dst_mask */
+        TRUE),                 /* pcrel_offset */
+
+  HOWTO (R_ARM_ALU_SB_G1_NC,           /* 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_ALU_SB_G1_NC",  /* name */
+        FALSE,                 /* partial_inplace */
+        0xffffffff,            /* src_mask */
+        0xffffffff,            /* dst_mask */
+        TRUE),                 /* pcrel_offset */
+
+  HOWTO (R_ARM_ALU_SB_G1,      /* 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_ALU_SB_G1",     /* name */
+        FALSE,                 /* partial_inplace */
+        0xffffffff,            /* src_mask */
+        0xffffffff,            /* dst_mask */
+        TRUE),                 /* pcrel_offset */
+
+  HOWTO (R_ARM_ALU_SB_G2,      /* 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_ALU_SB_G2",     /* name */
+        FALSE,                 /* partial_inplace */
+        0xffffffff,            /* src_mask */
+        0xffffffff,            /* dst_mask */
+        TRUE),                 /* pcrel_offset */
+
+  HOWTO (R_ARM_LDR_SB_G0,      /* 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_LDR_SB_G0",     /* name */
+        FALSE,                 /* partial_inplace */
+        0xffffffff,            /* src_mask */
+        0xffffffff,            /* dst_mask */
+        TRUE),                 /* pcrel_offset */
+
+  HOWTO (R_ARM_LDR_SB_G1,      /* 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_LDR_SB_G1",     /* name */
+        FALSE,                 /* partial_inplace */
+        0xffffffff,            /* src_mask */
+        0xffffffff,            /* dst_mask */
+        TRUE),                 /* pcrel_offset */
+
+  HOWTO (R_ARM_LDR_SB_G2,      /* 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_LDR_SB_G2",     /* name */
+        FALSE,                 /* partial_inplace */
+        0xffffffff,            /* src_mask */
+        0xffffffff,            /* dst_mask */
+        TRUE),                 /* pcrel_offset */
+
+  HOWTO (R_ARM_LDRS_SB_G0,     /* 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_LDRS_SB_G0",    /* name */
+        FALSE,                 /* partial_inplace */
+        0xffffffff,            /* src_mask */
+        0xffffffff,            /* dst_mask */
+        TRUE),                 /* pcrel_offset */
+
+  HOWTO (R_ARM_LDRS_SB_G1,     /* 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_LDRS_SB_G1",    /* name */
+        FALSE,                 /* partial_inplace */
+        0xffffffff,            /* src_mask */
+        0xffffffff,            /* dst_mask */
+        TRUE),                 /* pcrel_offset */
+
+  HOWTO (R_ARM_LDRS_SB_G2,     /* 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_LDRS_SB_G2",    /* name */
+        FALSE,                 /* partial_inplace */
+        0xffffffff,            /* src_mask */
+        0xffffffff,            /* dst_mask */
+        TRUE),                 /* pcrel_offset */
+
+  HOWTO (R_ARM_LDC_SB_G0,      /* 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_LDC_SB_G0",     /* name */
         FALSE,                 /* partial_inplace */
-        0x040070ff,            /* src_mask */
-        0x040070ff,            /* dst_mask */
+        0xffffffff,            /* src_mask */
+        0xffffffff,            /* dst_mask */
         TRUE),                 /* pcrel_offset */
 
-  HOWTO (R_ARM_ABS32_NOI,      /* type */
+  HOWTO (R_ARM_LDC_SB_G1,      /* type */
         0,                     /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         32,                    /* bitsize */
-        FALSE,                 /* pc_relative */
+        TRUE,                  /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont,/* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
-        "R_ARM_ABS32_NOI",     /* name */
+        "R_ARM_LDC_SB_G1",     /* name */
         FALSE,                 /* partial_inplace */
         0xffffffff,            /* src_mask */
         0xffffffff,            /* dst_mask */
-        FALSE),                /* pcrel_offset */
+        TRUE),                 /* pcrel_offset */
 
-  HOWTO (R_ARM_REL32_NOI,      /* type */
+  HOWTO (R_ARM_LDC_SB_G2,      /* type */
         0,                     /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         32,                    /* bitsize */
@@ -849,18 +1259,14 @@ static reloc_howto_type elf32_arm_howto_table_1[] =
         0,                     /* bitpos */
         complain_overflow_dont,/* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
-        "R_ARM_REL32_NOI",     /* name */
+        "R_ARM_LDC_SB_G2",     /* name */
         FALSE,                 /* partial_inplace */
         0xffffffff,            /* src_mask */
         0xffffffff,            /* dst_mask */
-        FALSE),                /* pcrel_offset */
-};
+        TRUE),                 /* pcrel_offset */
 
-/* Relocations 57 .. 83 are the "group relocations" which we do not
-   support.  */
+  /* End of group relocations.  */
 
-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) */
@@ -1200,7 +1606,7 @@ static reloc_howto_type elf32_arm_howto_table_2[] =
 
    249-255 extended, currently unused, relocations:  */
 
-static reloc_howto_type elf32_arm_howto_table_3[4] =
+static reloc_howto_type elf32_arm_howto_table_2[4] =
 {
   HOWTO (R_ARM_RREL32,         /* type */
         0,                     /* rightshift */
@@ -1265,13 +1671,9 @@ elf32_arm_howto_from_type (unsigned int r_type)
   if (r_type < NUM_ELEM (elf32_arm_howto_table_1))
     return &elf32_arm_howto_table_1[r_type];
 
-  if (r_type >= R_ARM_MOVW_BREL_NC
-      && r_type < R_ARM_MOVW_BREL_NC + NUM_ELEM (elf32_arm_howto_table_2))
-    return &elf32_arm_howto_table_2[r_type - R_ARM_MOVW_BREL_NC];
-
   if (r_type >= R_ARM_RREL32
       && r_type < R_ARM_RREL32 + NUM_ELEM (elf32_arm_howto_table_2))
-    return &elf32_arm_howto_table_3[r_type - R_ARM_RREL32];
+    return &elf32_arm_howto_table_2[r_type - R_ARM_RREL32];
 
   return NULL;
 }
@@ -1336,6 +1738,42 @@ static const struct elf32_arm_reloc_map elf32_arm_reloc_map[] =
     {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},
+    {BFD_RELOC_ARM_MOVW,            R_ARM_MOVW_ABS_NC},
+    {BFD_RELOC_ARM_MOVT,            R_ARM_MOVT_ABS},
+    {BFD_RELOC_ARM_MOVW_PCREL,      R_ARM_MOVW_PREL_NC},
+    {BFD_RELOC_ARM_MOVT_PCREL,      R_ARM_MOVT_PREL},
+    {BFD_RELOC_ARM_THUMB_MOVW,      R_ARM_THM_MOVW_ABS_NC},
+    {BFD_RELOC_ARM_THUMB_MOVT,      R_ARM_THM_MOVT_ABS},
+    {BFD_RELOC_ARM_THUMB_MOVW_PCREL, R_ARM_THM_MOVW_PREL_NC},
+    {BFD_RELOC_ARM_THUMB_MOVT_PCREL, R_ARM_THM_MOVT_PREL},
+    {BFD_RELOC_ARM_ALU_PC_G0_NC, R_ARM_ALU_PC_G0_NC},
+    {BFD_RELOC_ARM_ALU_PC_G0, R_ARM_ALU_PC_G0},
+    {BFD_RELOC_ARM_ALU_PC_G1_NC, R_ARM_ALU_PC_G1_NC},
+    {BFD_RELOC_ARM_ALU_PC_G1, R_ARM_ALU_PC_G1},
+    {BFD_RELOC_ARM_ALU_PC_G2, R_ARM_ALU_PC_G2},
+    {BFD_RELOC_ARM_LDR_PC_G0, R_ARM_LDR_PC_G0},
+    {BFD_RELOC_ARM_LDR_PC_G1, R_ARM_LDR_PC_G1},
+    {BFD_RELOC_ARM_LDR_PC_G2, R_ARM_LDR_PC_G2},
+    {BFD_RELOC_ARM_LDRS_PC_G0, R_ARM_LDRS_PC_G0},
+    {BFD_RELOC_ARM_LDRS_PC_G1, R_ARM_LDRS_PC_G1},
+    {BFD_RELOC_ARM_LDRS_PC_G2, R_ARM_LDRS_PC_G2},
+    {BFD_RELOC_ARM_LDC_PC_G0, R_ARM_LDC_PC_G0},
+    {BFD_RELOC_ARM_LDC_PC_G1, R_ARM_LDC_PC_G1},
+    {BFD_RELOC_ARM_LDC_PC_G2, R_ARM_LDC_PC_G2},
+    {BFD_RELOC_ARM_ALU_SB_G0_NC, R_ARM_ALU_SB_G0_NC},
+    {BFD_RELOC_ARM_ALU_SB_G0, R_ARM_ALU_SB_G0},
+    {BFD_RELOC_ARM_ALU_SB_G1_NC, R_ARM_ALU_SB_G1_NC},
+    {BFD_RELOC_ARM_ALU_SB_G1, R_ARM_ALU_SB_G1},
+    {BFD_RELOC_ARM_ALU_SB_G2, R_ARM_ALU_SB_G2},
+    {BFD_RELOC_ARM_LDR_SB_G0, R_ARM_LDR_SB_G0},
+    {BFD_RELOC_ARM_LDR_SB_G1, R_ARM_LDR_SB_G1},
+    {BFD_RELOC_ARM_LDR_SB_G2, R_ARM_LDR_SB_G2},
+    {BFD_RELOC_ARM_LDRS_SB_G0, R_ARM_LDRS_SB_G0},
+    {BFD_RELOC_ARM_LDRS_SB_G1, R_ARM_LDRS_SB_G1},
+    {BFD_RELOC_ARM_LDRS_SB_G2, R_ARM_LDRS_SB_G2},
+    {BFD_RELOC_ARM_LDC_SB_G0, R_ARM_LDC_SB_G0},
+    {BFD_RELOC_ARM_LDC_SB_G1, R_ARM_LDC_SB_G1},
+    {BFD_RELOC_ARM_LDC_SB_G2, R_ARM_LDC_SB_G2}
   };
 
 static reloc_howto_type *
@@ -1422,9 +1860,10 @@ elf32_arm_nabi_grok_psinfo (bfd *abfd, Elf_Internal_Note *note)
 typedef unsigned long int insn32;
 typedef unsigned short int insn16;
 
-/* In lieu of proper flags, assume all EABIv4 objects are interworkable.  */
+/* In lieu of proper flags, assume all EABIv4 or later objects are
+   interworkable.  */
 #define INTERWORK_FLAG(abfd)  \
-  (EF_ARM_EABI_VERSION (elf_elfheader (abfd)->e_flags) == EF_ARM_EABI_VER4 \
+  (EF_ARM_EABI_VERSION (elf_elfheader (abfd)->e_flags) >= EF_ARM_EABI_VER4 \
   || (elf_elfheader (abfd)->e_flags & EF_ARM_INTERWORK))
 
 /* The linker script knows the section names for placement.
@@ -1491,6 +1930,38 @@ static const bfd_vma elf32_arm_plt_entry [] =
 
 #endif
 
+/* The format of the first entry in the procedure linkage table
+   for a VxWorks executable.  */
+static const bfd_vma elf32_arm_vxworks_exec_plt0_entry[] =
+  {
+    0xe52dc008,                /* str    ip,[sp,#-8]!                  */
+    0xe59fc000,         /* ldr    ip,[pc]                      */
+    0xe59cf008,         /* ldr    pc,[ip,#8]                   */
+    0x00000000,         /* .long  _GLOBAL_OFFSET_TABLE_                */
+  };
+
+/* The format of subsequent entries in a VxWorks executable.  */
+static const bfd_vma elf32_arm_vxworks_exec_plt_entry[] =
+  {
+    0xe59fc000,         /* ldr    ip,[pc]                      */
+    0xe59cf000,         /* ldr    pc,[ip]                      */
+    0x00000000,         /* .long  @got                         */
+    0xe59fc000,         /* ldr    ip,[pc]                      */
+    0xea000000,         /* b      _PLT                         */
+    0x00000000,         /* .long  @pltindex*sizeof(Elf32_Rela) */
+  };
+
+/* The format of entries in a VxWorks shared library.  */
+static const bfd_vma elf32_arm_vxworks_shared_plt_entry[] =
+  {
+    0xe59fc000,         /* ldr    ip,[pc]                      */
+    0xe79cf009,         /* ldr    pc,[ip,r9]                   */
+    0x00000000,         /* .long  @got                         */
+    0xe59fc000,         /* ldr    ip,[pc]                      */
+    0xe599f008,         /* ldr    pc,[r9,#8]                   */
+    0x00000000,         /* .long  @pltindex*sizeof(Elf32_Rela) */
+  };
+
 /* 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 [] =
@@ -1567,11 +2038,14 @@ struct elf32_arm_obj_tdata
 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;
+    {
+      bfd_size_type amt = sizeof (struct elf32_arm_obj_tdata);
+      abfd->tdata.any = bfd_zalloc (abfd, amt);
+      if (abfd->tdata.any == NULL)
+       return FALSE;
+    }
+  return bfd_elf_mkobject (abfd);
 }
 
 /* The ARM linker needs to keep track of the number of relocs that it
@@ -1668,6 +2142,9 @@ struct elf32_arm_link_hash_table
     /* The number of bytes in the subsequent PLT etries.  */
     bfd_size_type plt_entry_size;
 
+    /* True if the target system is VxWorks.  */
+    int vxworks_p;
+
     /* True if the target system is Symbian OS.  */
     int symbian_p;
 
@@ -1683,6 +2160,9 @@ struct elf32_arm_link_hash_table
     asection *sdynbss;
     asection *srelbss;
 
+    /* The (unloaded but important) VxWorks .rela.plt.unloaded section.  */
+    asection *srelplt2;
+
     /* Data for R_ARM_TLS_LDM32 relocations.  */
     union {
       bfd_signed_vma refcount;
@@ -1728,7 +2208,20 @@ elf32_arm_link_hash_newfunc (struct bfd_hash_entry * entry,
   return (struct bfd_hash_entry *) ret;
 }
 
-/* Create .got, .gotplt, and .rel.got sections in DYNOBJ, and set up
+/* Return true if NAME is the name of the relocation section associated
+   with S.  */
+
+static bfd_boolean
+reloc_section_p (struct elf32_arm_link_hash_table *htab,
+                const char *name, asection *s)
+{
+  if (htab->use_rel)
+    return strncmp (name, ".rel", 4) == 0 && strcmp (s->name, name + 4) == 0;
+  else
+    return strncmp (name, ".rela", 5) == 0 && strcmp (s->name, name + 5) == 0;
+}
+
+/* Create .got, .gotplt, and .rel(a).got sections in DYNOBJ, and set up
    shortcuts to them in our hash table.  */
 
 static bfd_boolean
@@ -1749,7 +2242,8 @@ create_got_section (bfd *dynobj, struct bfd_link_info *info)
   if (!htab->sgot || !htab->sgotplt)
     abort ();
 
-  htab->srelgot = bfd_make_section_with_flags (dynobj, ".rel.got",
+  htab->srelgot = bfd_make_section_with_flags (dynobj,
+                                              RELOC_SECTION (htab, ".got"),
                                               (SEC_ALLOC | SEC_LOAD
                                                | SEC_HAS_CONTENTS
                                                | SEC_IN_MEMORY
@@ -1761,8 +2255,8 @@ create_got_section (bfd *dynobj, struct bfd_link_info *info)
   return TRUE;
 }
 
-/* Create .plt, .rel.plt, .got, .got.plt, .rel.got, .dynbss, and
-   .rel.bss sections in DYNOBJ, and set up shortcuts to them in our
+/* Create .plt, .rel(a).plt, .got, .got.plt, .rel(a).got, .dynbss, and
+   .rel(a).bss sections in DYNOBJ, and set up shortcuts to them in our
    hash table.  */
 
 static bfd_boolean
@@ -1778,10 +2272,32 @@ elf32_arm_create_dynamic_sections (bfd *dynobj, struct bfd_link_info *info)
     return FALSE;
 
   htab->splt = bfd_get_section_by_name (dynobj, ".plt");
-  htab->srelplt = bfd_get_section_by_name (dynobj, ".rel.plt");
+  htab->srelplt = bfd_get_section_by_name (dynobj,
+                                          RELOC_SECTION (htab, ".plt"));
   htab->sdynbss = bfd_get_section_by_name (dynobj, ".dynbss");
   if (!info->shared)
-    htab->srelbss = bfd_get_section_by_name (dynobj, ".rel.bss");
+    htab->srelbss = bfd_get_section_by_name (dynobj,
+                                            RELOC_SECTION (htab, ".bss"));
+
+  if (htab->vxworks_p)
+    {
+      if (!elf_vxworks_create_dynamic_sections (dynobj, info, &htab->srelplt2))
+       return FALSE;
+
+      if (info->shared)
+       {
+         htab->plt_header_size = 0;
+         htab->plt_entry_size
+           = 4 * ARRAY_SIZE (elf32_arm_vxworks_shared_plt_entry);
+       }
+      else
+       {
+         htab->plt_header_size
+           = 4 * ARRAY_SIZE (elf32_arm_vxworks_exec_plt0_entry);
+         htab->plt_entry_size
+           = 4 * ARRAY_SIZE (elf32_arm_vxworks_exec_plt_entry);
+       }
+    }
 
   if (!htab->splt 
       || !htab->srelplt
@@ -1862,7 +2378,8 @@ elf32_arm_link_hash_table_create (bfd *abfd)
     return NULL;
 
   if (!_bfd_elf_link_hash_table_init (& ret->root, abfd,
-                                     elf32_arm_link_hash_newfunc))
+                                     elf32_arm_link_hash_newfunc,
+                                     sizeof (struct elf32_arm_link_hash_entry)))
     {
       free (ret);
       return NULL;
@@ -1875,6 +2392,7 @@ elf32_arm_link_hash_table_create (bfd *abfd)
   ret->srelplt = NULL;
   ret->sdynbss = NULL;
   ret->srelbss = NULL;
+  ret->srelplt2 = NULL;
   ret->thumb_glue_size = 0;
   ret->arm_glue_size = 0;
   ret->bfd_of_glue_owner = NULL;
@@ -1890,6 +2408,7 @@ elf32_arm_link_hash_table_create (bfd *abfd)
 #endif
   ret->fix_v4bx = 0;
   ret->use_blx = 0;
+  ret->vxworks_p = 0;
   ret->symbian_p = 0;
   ret->use_rel = 1;
   ret->sym_sec.abfd = NULL;
@@ -2539,6 +3058,35 @@ insert_thumb_branch (insn32 br_insn, int rel_off)
   return br_insn;
 }
 
+
+/* Store an Arm insn into an output section not processed by
+   elf32_arm_write_section.  */
+
+static void
+put_arm_insn (struct elf32_arm_link_hash_table *htab,
+            bfd * output_bfd, bfd_vma val, void * ptr)
+{
+    if (htab->byteswap_code != bfd_little_endian (output_bfd))
+      bfd_putl32 (val, ptr);
+    else
+      bfd_putb32 (val, ptr);
+}
+
+
+/* Store a 16-bit Thumb insn into an output section not processed by
+   elf32_arm_write_section.  */
+
+static void
+put_thumb_insn (struct elf32_arm_link_hash_table *htab,
+              bfd * output_bfd, bfd_vma val, void * ptr)
+{
+    if (htab->byteswap_code != bfd_little_endian (output_bfd))
+      bfd_putl16 (val, ptr);
+    else
+      bfd_putb16 (val, ptr);
+}
+
+
 /* Thumb code calling an ARM function.  */
 
 static int
@@ -2595,11 +3143,11 @@ elf32_thumb_to_arm_stub (struct bfd_link_info * info,
       --my_offset;
       myh->root.u.def.value = my_offset;
 
-      bfd_put_16 (output_bfd, (bfd_vma) t2a1_bx_pc_insn,
-                 s->contents + my_offset);
+      put_thumb_insn (globals, output_bfd, (bfd_vma) t2a1_bx_pc_insn,
+                     s->contents + my_offset);
 
-      bfd_put_16 (output_bfd, (bfd_vma) t2a2_noop_insn,
-                 s->contents + my_offset + 2);
+      put_thumb_insn (globals, output_bfd, (bfd_vma) t2a2_noop_insn,
+                     s->contents + my_offset + 2);
 
       ret_offset =
        /* Address of destination of the stub.  */
@@ -2617,9 +3165,9 @@ elf32_thumb_to_arm_stub (struct bfd_link_info * info,
           /* ARM branches work from the pc of the instruction + 8.  */
           + 8);
 
-      bfd_put_32 (output_bfd,
-                 (bfd_vma) t2a3_b_insn | ((ret_offset >> 2) & 0x00FFFFFF),
-                 s->contents + my_offset + 4);
+      put_arm_insn (globals, output_bfd,
+                   (bfd_vma) t2a3_b_insn | ((ret_offset >> 2) & 0x00FFFFFF),
+                   s->contents + my_offset + 4);
     }
 
   BFD_ASSERT (my_offset <= globals->thumb_glue_size);
@@ -2704,12 +3252,12 @@ elf32_arm_to_thumb_stub (struct bfd_link_info * info,
             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);
+         put_arm_insn (globals, output_bfd, (bfd_vma) a2t1p_ldr_insn,
+                       s->contents + my_offset);
+         put_arm_insn (globals, output_bfd, (bfd_vma) a2t2p_add_pc_insn,
+                       s->contents + my_offset + 4);
+         put_arm_insn (globals, 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
@@ -2721,11 +3269,11 @@ elf32_arm_to_thumb_stub (struct bfd_link_info * info,
        }
       else
        {
-         bfd_put_32 (output_bfd, (bfd_vma) a2t1_ldr_insn,
-                     s->contents + my_offset);
+         put_arm_insn (globals, 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);
+         put_arm_insn (globals, 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,
@@ -2805,6 +3353,88 @@ tpoff (struct bfd_link_info *info, bfd_vma address)
   return address - htab->tls_sec->vma + base;
 }
 
+/* Perform an R_ARM_ABS12 relocation on the field pointed to by DATA.
+   VALUE is the relocation value.  */
+
+static bfd_reloc_status_type
+elf32_arm_abs12_reloc (bfd *abfd, void *data, bfd_vma value)
+{
+  if (value > 0xfff)
+    return bfd_reloc_overflow;
+
+  value |= bfd_get_32 (abfd, data) & 0xfffff000;
+  bfd_put_32 (abfd, value, data);
+  return bfd_reloc_ok;
+}
+
+/* For a given value of n, calculate the value of G_n as required to
+   deal with group relocations.  We return it in the form of an
+   encoded constant-and-rotation, together with the final residual.  If n is
+   specified as less than zero, then final_residual is filled with the
+   input value and no further action is performed.  */
+
+static bfd_vma
+calculate_group_reloc_mask (bfd_vma value, int n, bfd_vma *final_residual)
+{
+  int current_n;
+  bfd_vma g_n;
+  bfd_vma encoded_g_n = 0;
+  bfd_vma residual = value; /* Also known as Y_n.  */
+
+  for (current_n = 0; current_n <= n; current_n++)
+    {
+      int shift;
+
+      /* Calculate which part of the value to mask.  */
+      if (residual == 0)
+        shift = 0;
+      else
+        {
+          int msb;
+
+          /* Determine the most significant bit in the residual and
+             align the resulting value to a 2-bit boundary.  */
+          for (msb = 30; msb >= 0; msb -= 2)
+            if (residual & (3 << msb))
+              break;
+
+          /* The desired shift is now (msb - 6), or zero, whichever
+             is the greater.  */
+          shift = msb - 6;
+          if (shift < 0)
+            shift = 0;
+        }
+
+      /* Calculate g_n in 32-bit as well as encoded constant+rotation form.  */
+      g_n = residual & (0xff << shift);
+      encoded_g_n = (g_n >> shift)
+                    | ((g_n <= 0xff ? 0 : (32 - shift) / 2) << 8);
+
+      /* Calculate the residual for the next time around.  */
+      residual &= ~g_n;
+    }
+
+  *final_residual = residual;
+
+  return encoded_g_n;
+}
+
+/* Given an ARM instruction, determine whether it is an ADD or a SUB.
+   Returns 1 if it is an ADD, -1 if it is a SUB, and 0 otherwise.  */
+static int
+identify_add_or_sub(bfd_vma insn)
+{
+  int opcode = insn & 0x1e00000;
+
+  if (opcode == 1 << 23) /* ADD */
+    return 1;
+
+  if (opcode == 1 << 22) /* SUB */
+    return -1;
+
+  return 0;
+}
+
 /* Perform a relocation as part of a final link.  */
 
 static bfd_reloc_status_type
@@ -2891,6 +3521,10 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
       *unresolved_reloc_p = FALSE;
       return bfd_reloc_ok;
 
+    case R_ARM_ABS12:
+      if (!globals->vxworks_p)
+       return elf32_arm_abs12_reloc (input_bfd, hit_data, value + addend);
+
     case R_ARM_PC24:
     case R_ARM_ABS32:
     case R_ARM_REL32:
@@ -2925,7 +3559,7 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
          *unresolved_reloc_p = FALSE;
          return _bfd_final_link_relocate (howto, input_bfd, input_section,
                                           contents, rel->r_offset, value,
-                                          (bfd_vma) 0);
+                                          rel->r_addend);
        }
 
       /* When generating a shared object or relocatable executable, these
@@ -2961,10 +3595,7 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
              if (name == NULL)
                return bfd_reloc_notsupported;
 
-             BFD_ASSERT (strncmp (name, ".rel", 4) == 0
-                         && strcmp (bfd_get_section_name (input_bfd,
-                                                          input_section),
-                                    name + 4) == 0);
+             BFD_ASSERT (reloc_section_p (globals, name, input_section));
 
              sreloc = bfd_get_section_by_name (dynobj, name);
              BFD_ASSERT (sreloc != NULL);
@@ -2973,6 +3604,7 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
          skip = FALSE;
          relocate = FALSE;
 
+         outrel.r_addend = addend;
          outrel.r_offset =
            _bfd_elf_section_offset (output_bfd, info, input_section,
                                     rel->r_offset);
@@ -2996,7 +3628,6 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
              int symbol;
 
              /* This symbol is local, or marked to become local.  */
-             relocate = TRUE;
              if (sym_flags == STT_ARM_TFUNC)
                value |= 1;
              if (globals->symbian_p)
@@ -3021,11 +3652,15 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
                   so the symbol does not matter.  */
                symbol = 0;
              outrel.r_info = ELF32_R_INFO (symbol, R_ARM_RELATIVE);
+             if (globals->use_rel)
+               relocate = TRUE;
+             else
+               outrel.r_addend += value;
            }
 
          loc = sreloc->contents;
-         loc += sreloc->reloc_count++ * sizeof (Elf32_External_Rel);
-         bfd_elf32_swap_reloc_out (output_bfd, &outrel, loc);
+         loc += sreloc->reloc_count++ * RELOC_SIZE (globals);
+         SWAP_RELOC_OUT (globals) (output_bfd, &outrel, loc);
 
          /* If this reloc is against an external symbol, we do not want to
             fiddle with the addend.  Otherwise, we need to include the symbol
@@ -3039,6 +3674,9 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
        }
       else switch (r_type)
        {
+       case R_ARM_ABS12:
+         return elf32_arm_abs12_reloc (input_bfd, hit_data, value + addend);
+
        case R_ARM_XPC25:         /* Arm BLX instruction.  */
        case R_ARM_CALL:
        case R_ARM_JUMP24:
@@ -3144,9 +3782,11 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
          break;
 
        case R_ARM_REL32:
+         value += addend;
+         if (sym_flags == STT_ARM_TFUNC)
+           value |= 1;
          value -= (input_section->output_section->vma
                    + input_section->output_offset + rel->r_offset);
-         value += addend;
          break;
 
        case R_ARM_PREL31:
@@ -3186,18 +3826,6 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
       bfd_put_16 (input_bfd, value, hit_data);
       return bfd_reloc_ok;
 
-    case R_ARM_ABS12:
-      /* Support ldr and str instruction for the arm */
-      /* Also thumb b (unconditional branch).  ??? Really?  */
-      value += addend;
-
-      if ((long) value > 0x7ff || (long) value < -0x800)
-       return bfd_reloc_overflow;
-
-      value |= (bfd_get_32 (input_bfd, hit_data) & 0xfffff000);
-      bfd_put_32 (input_bfd, value, hit_data);
-      return bfd_reloc_ok;
-
     case R_ARM_THM_ABS5:
       /* Support ldr and str instructions for the thumb.  */
       if (globals->use_rel)
@@ -3589,7 +4217,7 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
       value -= sgot->output_section->vma;
       return _bfd_final_link_relocate (howto, input_bfd, input_section,
                                       contents, rel->r_offset, value,
-                                      (bfd_vma) 0);
+                                      rel->r_addend);
 
     case R_ARM_GOTPC:
       /* Use global offset table as symbol value.  */
@@ -3602,7 +4230,7 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
       value = sgot->output_section->vma;
       return _bfd_final_link_relocate (howto, input_bfd, input_section,
                                       contents, rel->r_offset, value,
-                                      (bfd_vma) 0);
+                                      rel->r_addend);
 
     case R_ARM_GOT32:
     case R_ARM_GOT_PREL:
@@ -3632,7 +4260,7 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
                 always be a multiple of 4, we use the least significant bit
                 to record whether we have initialized it already.
 
-                When doing a dynamic link, we create a .rel.got relocation
+                When doing a dynamic link, we create a .rel(a).got relocation
                 entry to initialize the value.  This is done in the
                 finish_dynamic_symbol routine.  */
              if ((off & 1) != 0)
@@ -3678,7 +4306,8 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
              if (sym_flags == STT_ARM_TFUNC)
                value |= 1;
 
-             bfd_put_32 (output_bfd, value, sgot->contents + off);
+             if (globals->use_rel)
+               bfd_put_32 (output_bfd, value, sgot->contents + off);
 
              if (info->shared)
                {
@@ -3686,16 +4315,18 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
                  Elf_Internal_Rela outrel;
                  bfd_byte *loc;
 
-                 srelgot = bfd_get_section_by_name (dynobj, ".rel.got");
+                 srelgot = (bfd_get_section_by_name
+                            (dynobj, RELOC_SECTION (globals, ".got")));
                  BFD_ASSERT (srelgot != NULL);
 
+                 outrel.r_addend = addend + value;
                  outrel.r_offset = (sgot->output_section->vma
                                     + sgot->output_offset
                                     + off);
                  outrel.r_info = ELF32_R_INFO (0, R_ARM_RELATIVE);
                  loc = srelgot->contents;
-                 loc += srelgot->reloc_count++ * sizeof (Elf32_External_Rel);
-                 bfd_elf32_swap_reloc_out (output_bfd, &outrel, loc);
+                 loc += srelgot->reloc_count++ * RELOC_SIZE (globals);
+                 SWAP_RELOC_OUT (globals) (output_bfd, &outrel, loc);
                }
 
              local_got_offsets[r_symndx] |= 1;
@@ -3708,13 +4339,14 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
 
       return _bfd_final_link_relocate (howto, input_bfd, input_section,
                                       contents, rel->r_offset, value,
-                                      (bfd_vma) 0);
+                                      rel->r_addend);
 
     case R_ARM_TLS_LDO32:
       value = value - dtpoff_base (info);
 
       return _bfd_final_link_relocate (howto, input_bfd, input_section,
-                                      contents, rel->r_offset, value, (bfd_vma) 0);
+                                      contents, rel->r_offset, value,
+                                      rel->r_addend);
 
     case R_ARM_TLS_LDM32:
       {
@@ -3739,15 +4371,18 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
                if (globals->srelgot == NULL)
                  abort ();
 
+               outrel.r_addend = 0;
                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);
+               if (globals->use_rel)
+                 bfd_put_32 (output_bfd, outrel.r_addend,
+                             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);
+               loc += globals->srelgot->reloc_count++ * RELOC_SIZE (globals);
+               SWAP_RELOC_OUT (globals) (output_bfd, &outrel, loc);
              }
            else
              bfd_put_32 (output_bfd, 1, globals->sgot->contents + off);
@@ -3760,7 +4395,7 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
 
        return _bfd_final_link_relocate (howto, input_bfd, input_section,
                                         contents, rel->r_offset, value,
-                                        (bfd_vma) 0);
+                                        rel->r_addend);
       }
 
     case R_ARM_TLS_GD32:
@@ -3821,36 +4456,45 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
                if (globals->srelgot == NULL)
                  abort ();
                loc = globals->srelgot->contents;
-               loc += globals->srelgot->reloc_count * sizeof (Elf32_External_Rel);
+               loc += globals->srelgot->reloc_count * RELOC_SIZE (globals);
              }
 
            if (tls_type & GOT_TLS_GD)
              {
                if (need_relocs)
                  {
+                   outrel.r_addend = 0;
                    outrel.r_offset = (globals->sgot->output_section->vma
-                                      + globals->sgot->output_offset + cur_off);
+                                      + 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);
+                   if (globals->use_rel)
+                     bfd_put_32 (output_bfd, outrel.r_addend,
+                                 globals->sgot->contents + cur_off);
+
+                   SWAP_RELOC_OUT (globals) (output_bfd, &outrel, loc);
                    globals->srelgot->reloc_count++;
-                   loc += sizeof (Elf32_External_Rel);
+                   loc += RELOC_SIZE (globals);
 
                    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_addend = 0;
                        outrel.r_info = ELF32_R_INFO (indx,
                                                      R_ARM_TLS_DTPOFF32);
                        outrel.r_offset += 4;
-                       bfd_elf32_swap_reloc_out (output_bfd, &outrel, loc);
+
+                       if (globals->use_rel)
+                         bfd_put_32 (output_bfd, outrel.r_addend,
+                                     globals->sgot->contents + cur_off + 4);
+
+
+                       SWAP_RELOC_OUT (globals) (output_bfd, &outrel, loc);
                        globals->srelgot->reloc_count++;
-                       loc += sizeof (Elf32_External_Rel);
+                       loc += RELOC_SIZE (globals);
                      }
                  }
                else
@@ -3873,73 +4517,536 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
              {
                if (need_relocs)
                  {
+                   if (indx == 0)
+                     outrel.r_addend = value - dtpoff_base (info);
+                   else
+                     outrel.r_addend = 0;
                    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,
+                   if (globals->use_rel)
+                     bfd_put_32 (output_bfd, outrel.r_addend,
                                  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;
-             }
+                   SWAP_RELOC_OUT (globals) (output_bfd, &outrel, loc);
+                   globals->srelgot->reloc_count++;
+                   loc += RELOC_SIZE (globals);
+                 }
+               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,
+                                        rel->r_addend);
+      }
+
+    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,
+                                      rel->r_addend);
+
+    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;
+
+    case R_ARM_MOVW_ABS_NC:
+    case R_ARM_MOVT_ABS:
+    case R_ARM_MOVW_PREL_NC:
+    case R_ARM_MOVT_PREL:
+      {
+       bfd_vma insn = bfd_get_32 (input_bfd, hit_data);
+
+       if (globals->use_rel)
+         {
+           addend = ((insn >> 4) & 0xf000) | (insn & 0xfff);
+           signed_addend = (addend ^ 0x10000) - 0x10000;
+         }
+       value += signed_addend;
+       if (sym_flags == STT_ARM_TFUNC)
+         value |= 1;
+
+       if (r_type == R_ARM_MOVW_PREL_NC || r_type == R_ARM_MOVT_PREL)
+         value -= (input_section->output_section->vma
+                   + input_section->output_offset + rel->r_offset);
+
+       if (r_type == R_ARM_MOVT_ABS || r_type == R_ARM_MOVT_PREL)
+         value >>= 16;
+
+       insn &= 0xfff0f000;
+       insn |= value & 0xfff;
+       insn |= (value & 0xf000) << 4;
+       bfd_put_32 (input_bfd, insn, hit_data);
+      }
+      return bfd_reloc_ok;
+
+    case R_ARM_THM_MOVW_ABS_NC:
+    case R_ARM_THM_MOVT_ABS:
+    case R_ARM_THM_MOVW_PREL_NC:
+    case R_ARM_THM_MOVT_PREL:
+      {
+       bfd_vma insn;
+       
+       insn = bfd_get_16 (input_bfd, hit_data) << 16;
+       insn |= bfd_get_16 (input_bfd, hit_data + 2);
+
+       if (globals->use_rel)
+         {
+           addend = ((insn >> 4)  & 0xf000)
+                  | ((insn >> 15) & 0x0800)
+                  | ((insn >> 4)  & 0x0700)
+                  | (insn         & 0x00ff);
+           signed_addend = (addend ^ 0x10000) - 0x10000;
+         }
+       value += signed_addend;
+       if (sym_flags == STT_ARM_TFUNC)
+         value |= 1;
+
+       if (r_type == R_ARM_THM_MOVW_PREL_NC || r_type == R_ARM_THM_MOVT_PREL)
+         value -= (input_section->output_section->vma
+                   + input_section->output_offset + rel->r_offset);
+
+       if (r_type == R_ARM_THM_MOVT_ABS || r_type == R_ARM_THM_MOVT_PREL)
+         value >>= 16;
+
+       insn &= 0xfbf08f00;
+       insn |= (value & 0xf000) << 4;
+       insn |= (value & 0x0800) << 15;
+       insn |= (value & 0x0700) << 4;
+       insn |= (value & 0x00ff);
+
+       bfd_put_16 (input_bfd, insn >> 16, hit_data);
+       bfd_put_16 (input_bfd, insn & 0xffff, hit_data + 2);
+      }
+      return bfd_reloc_ok;
+
+    case R_ARM_ALU_PC_G0_NC:
+    case R_ARM_ALU_PC_G1_NC:
+    case R_ARM_ALU_PC_G0:
+    case R_ARM_ALU_PC_G1:
+    case R_ARM_ALU_PC_G2:
+    case R_ARM_ALU_SB_G0_NC:
+    case R_ARM_ALU_SB_G1_NC:
+    case R_ARM_ALU_SB_G0:
+    case R_ARM_ALU_SB_G1:
+    case R_ARM_ALU_SB_G2:
+      {
+       bfd_vma insn = bfd_get_32 (input_bfd, hit_data);
+        bfd_vma pc = input_section->output_section->vma
+                    + input_section->output_offset + rel->r_offset;
+        /* sb should be the origin of the *segment* containing the symbol.
+           It is not clear how to obtain this OS-dependent value, so we
+           make an arbitrary choice of zero.  */
+        bfd_vma sb = 0;
+        bfd_vma residual;
+        bfd_vma g_n;
+       bfd_signed_vma signed_value;
+        int group = 0;
+
+        /* Determine which group of bits to select.  */
+        switch (r_type)
+          {
+          case R_ARM_ALU_PC_G0_NC:
+          case R_ARM_ALU_PC_G0:
+          case R_ARM_ALU_SB_G0_NC:
+          case R_ARM_ALU_SB_G0:
+            group = 0;
+            break;
+
+          case R_ARM_ALU_PC_G1_NC:
+          case R_ARM_ALU_PC_G1:
+          case R_ARM_ALU_SB_G1_NC:
+          case R_ARM_ALU_SB_G1:
+            group = 1;
+            break;
+
+          case R_ARM_ALU_PC_G2:
+          case R_ARM_ALU_SB_G2:
+            group = 2;
+            break;
+
+          default:
+            abort();
+          }
+
+        /* If REL, extract the addend from the insn.  If RELA, it will
+           have already been fetched for us.  */
+       if (globals->use_rel)
+          {
+            int negative;
+            bfd_vma constant = insn & 0xff;
+            bfd_vma rotation = (insn & 0xf00) >> 8;
+
+            if (rotation == 0)
+              signed_addend = constant;
+            else
+              {
+                /* Compensate for the fact that in the instruction, the
+                   rotation is stored in multiples of 2 bits.  */
+                rotation *= 2;
+
+                /* Rotate "constant" right by "rotation" bits.  */
+                signed_addend = (constant >> rotation) |
+                                (constant << (8 * sizeof (bfd_vma) - rotation));
+              }
+
+            /* Determine if the instruction is an ADD or a SUB.
+               (For REL, this determines the sign of the addend.)  */
+            negative = identify_add_or_sub (insn);
+            if (negative == 0)
+              {
+                (*_bfd_error_handler)
+                  (_("%B(%A+0x%lx): Only ADD or SUB instructions are allowed for ALU group relocations"),
+                  input_bfd, input_section,
+                  (long) rel->r_offset, howto->name);
+                return bfd_reloc_overflow;       
+             }
+
+            signed_addend *= negative;
+          }
+
+       /* Compute the value (X) to go in the place.  */
+        if (r_type == R_ARM_ALU_PC_G0_NC
+            || r_type == R_ARM_ALU_PC_G1_NC
+            || r_type == R_ARM_ALU_PC_G0
+            || r_type == R_ARM_ALU_PC_G1
+            || r_type == R_ARM_ALU_PC_G2)
+          /* PC relative.  */
+          signed_value = value - pc + signed_addend;
+        else
+          /* Section base relative.  */
+          signed_value = value - sb + signed_addend;
+
+        /* If the target symbol is a Thumb function, then set the
+           Thumb bit in the address.  */
+       if (sym_flags == STT_ARM_TFUNC)
+         signed_value |= 1;
+
+        /* Calculate the value of the relevant G_n, in encoded
+           constant-with-rotation format.  */
+        g_n = calculate_group_reloc_mask (abs (signed_value), group,
+                                          &residual);
+
+        /* Check for overflow if required.  */
+        if ((r_type == R_ARM_ALU_PC_G0
+             || r_type == R_ARM_ALU_PC_G1
+             || r_type == R_ARM_ALU_PC_G2
+             || r_type == R_ARM_ALU_SB_G0
+             || r_type == R_ARM_ALU_SB_G1
+             || r_type == R_ARM_ALU_SB_G2) && residual != 0)
+          {
+            (*_bfd_error_handler)
+              (_("%B(%A+0x%lx): Overflow whilst splitting 0x%lx for group relocation %s"),
+              input_bfd, input_section,
+              (long) rel->r_offset, abs (signed_value), howto->name);
+            return bfd_reloc_overflow;
+          }
+
+        /* Mask out the value and the ADD/SUB part of the opcode; take care
+           not to destroy the S bit.  */
+        insn &= 0xff1ff000;
+
+        /* Set the opcode according to whether the value to go in the
+           place is negative.  */
+        if (signed_value < 0)
+          insn |= 1 << 22;
+        else
+          insn |= 1 << 23;
+
+        /* Encode the offset.  */
+        insn |= g_n;
+
+       bfd_put_32 (input_bfd, insn, hit_data);
+      }
+      return bfd_reloc_ok;
+
+    case R_ARM_LDR_PC_G0:
+    case R_ARM_LDR_PC_G1:
+    case R_ARM_LDR_PC_G2:
+    case R_ARM_LDR_SB_G0:
+    case R_ARM_LDR_SB_G1:
+    case R_ARM_LDR_SB_G2:
+      {
+       bfd_vma insn = bfd_get_32 (input_bfd, hit_data);
+        bfd_vma pc = input_section->output_section->vma
+                    + input_section->output_offset + rel->r_offset;
+        bfd_vma sb = 0; /* See note above.  */
+        bfd_vma residual;
+       bfd_signed_vma signed_value;
+        int group = 0;
+
+        /* Determine which groups of bits to calculate.  */
+        switch (r_type)
+          {
+          case R_ARM_LDR_PC_G0:
+          case R_ARM_LDR_SB_G0:
+            group = 0;
+            break;
+
+          case R_ARM_LDR_PC_G1:
+          case R_ARM_LDR_SB_G1:
+            group = 1;
+            break;
+
+          case R_ARM_LDR_PC_G2:
+          case R_ARM_LDR_SB_G2:
+            group = 2;
+            break;
+
+          default:
+            abort();
+          }
+
+        /* If REL, extract the addend from the insn.  If RELA, it will
+           have already been fetched for us.  */
+       if (globals->use_rel)
+          {
+            int negative = (insn & (1 << 23)) ? 1 : -1;
+            signed_addend = negative * (insn & 0xfff);
+          }
+
+       /* Compute the value (X) to go in the place.  */
+        if (r_type == R_ARM_LDR_PC_G0
+            || r_type == R_ARM_LDR_PC_G1
+            || r_type == R_ARM_LDR_PC_G2)
+          /* PC relative.  */
+          signed_value = value - pc + signed_addend;
+        else
+          /* Section base relative.  */
+          signed_value = value - sb + signed_addend;
+
+        /* Calculate the value of the relevant G_{n-1} to obtain
+           the residual at that stage.  */
+        calculate_group_reloc_mask (abs (signed_value), group - 1, &residual);
+
+        /* Check for overflow.  */
+        if (residual >= 0x1000)
+          {
+            (*_bfd_error_handler)
+              (_("%B(%A+0x%lx): Overflow whilst splitting 0x%lx for group relocation %s"),
+              input_bfd, input_section,
+              (long) rel->r_offset, abs (signed_value), howto->name);
+            return bfd_reloc_overflow;
+          }
+
+        /* Mask out the value and U bit.  */
+        insn &= 0xff7ff000;
+
+        /* Set the U bit if the value to go in the place is non-negative.  */
+        if (signed_value >= 0)
+          insn |= 1 << 23;
+
+        /* Encode the offset.  */
+        insn |= residual;
+
+       bfd_put_32 (input_bfd, insn, hit_data);
+      }
+      return bfd_reloc_ok;
+
+    case R_ARM_LDRS_PC_G0:
+    case R_ARM_LDRS_PC_G1:
+    case R_ARM_LDRS_PC_G2:
+    case R_ARM_LDRS_SB_G0:
+    case R_ARM_LDRS_SB_G1:
+    case R_ARM_LDRS_SB_G2:
+      {
+       bfd_vma insn = bfd_get_32 (input_bfd, hit_data);
+        bfd_vma pc = input_section->output_section->vma
+                    + input_section->output_offset + rel->r_offset;
+        bfd_vma sb = 0; /* See note above.  */
+        bfd_vma residual;
+       bfd_signed_vma signed_value;
+        int group = 0;
+
+        /* Determine which groups of bits to calculate.  */
+        switch (r_type)
+          {
+          case R_ARM_LDRS_PC_G0:
+          case R_ARM_LDRS_SB_G0:
+            group = 0;
+            break;
+
+          case R_ARM_LDRS_PC_G1:
+          case R_ARM_LDRS_SB_G1:
+            group = 1;
+            break;
+
+          case R_ARM_LDRS_PC_G2:
+          case R_ARM_LDRS_SB_G2:
+            group = 2;
+            break;
+
+          default:
+            abort();
+          }
+
+        /* If REL, extract the addend from the insn.  If RELA, it will
+           have already been fetched for us.  */
+       if (globals->use_rel)
+          {
+            int negative = (insn & (1 << 23)) ? 1 : -1;
+            signed_addend = negative * (((insn & 0xf00) >> 4) + (insn & 0xf));
+          }
+
+       /* Compute the value (X) to go in the place.  */
+        if (r_type == R_ARM_LDRS_PC_G0
+            || r_type == R_ARM_LDRS_PC_G1
+            || r_type == R_ARM_LDRS_PC_G2)
+          /* PC relative.  */
+          signed_value = value - pc + signed_addend;
+        else
+          /* Section base relative.  */
+          signed_value = value - sb + signed_addend;
+
+        /* Calculate the value of the relevant G_{n-1} to obtain
+           the residual at that stage.  */
+        calculate_group_reloc_mask (abs (signed_value), group - 1, &residual);
+
+        /* Check for overflow.  */
+        if (residual >= 0x100)
+          {
+            (*_bfd_error_handler)
+              (_("%B(%A+0x%lx): Overflow whilst splitting 0x%lx for group relocation %s"),
+              input_bfd, input_section,
+              (long) rel->r_offset, abs (signed_value), howto->name);
+            return bfd_reloc_overflow;
+          }
+
+        /* Mask out the value and U bit.  */
+        insn &= 0xff7ff0f0;
 
-           if (h != NULL)
-             h->got.offset |= 1;
-           else
-             local_got_offsets[r_symndx] |= 1;
-         }
+        /* Set the U bit if the value to go in the place is non-negative.  */
+        if (signed_value >= 0)
+          insn |= 1 << 23;
 
-       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);
+        /* Encode the offset.  */
+        insn |= ((residual & 0xf0) << 4) | (residual & 0xf);
 
-       return _bfd_final_link_relocate (howto, input_bfd, input_section,
-                                        contents, rel->r_offset, value,
-                                        (bfd_vma) 0);
+       bfd_put_32 (input_bfd, insn, hit_data);
       }
+      return bfd_reloc_ok;
 
-    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_LDC_PC_G0:
+    case R_ARM_LDC_PC_G1:
+    case R_ARM_LDC_PC_G2:
+    case R_ARM_LDC_SB_G0:
+    case R_ARM_LDC_SB_G1:
+    case R_ARM_LDC_SB_G2:
+      {
+       bfd_vma insn = bfd_get_32 (input_bfd, hit_data);
+        bfd_vma pc = input_section->output_section->vma
+                    + input_section->output_offset + rel->r_offset;
+        bfd_vma sb = 0; /* See note above.  */
+        bfd_vma residual;
+       bfd_signed_vma signed_value;
+        int group = 0;
+
+        /* Determine which groups of bits to calculate.  */
+        switch (r_type)
+          {
+          case R_ARM_LDC_PC_G0:
+          case R_ARM_LDC_SB_G0:
+            group = 0;
+            break;
+
+          case R_ARM_LDC_PC_G1:
+          case R_ARM_LDC_SB_G1:
+            group = 1;
+            break;
+
+          case R_ARM_LDC_PC_G2:
+          case R_ARM_LDC_SB_G2:
+            group = 2;
+            break;
+
+          default:
+            abort();
+          }
 
-    case R_ARM_V4BX:
-      if (globals->fix_v4bx)
-        {
-          bfd_vma insn = bfd_get_32 (input_bfd, hit_data);
+        /* If REL, extract the addend from the insn.  If RELA, it will
+           have already been fetched for us.  */
+       if (globals->use_rel)
+          {
+            int negative = (insn & (1 << 23)) ? 1 : -1;
+            signed_addend = negative * ((insn & 0xff) << 2);
+          }
 
-          /* Ensure that we have a BX instruction.  */
-          BFD_ASSERT ((insn & 0x0ffffff0) == 0x012fff10);
+       /* Compute the value (X) to go in the place.  */
+        if (r_type == R_ARM_LDC_PC_G0
+            || r_type == R_ARM_LDC_PC_G1
+            || r_type == R_ARM_LDC_PC_G2)
+          /* PC relative.  */
+          signed_value = value - pc + signed_addend;
+        else
+          /* Section base relative.  */
+          signed_value = value - sb + signed_addend;
+
+        /* Calculate the value of the relevant G_{n-1} to obtain
+           the residual at that stage.  */
+        calculate_group_reloc_mask (abs (signed_value), group - 1, &residual);
+
+        /* Check for overflow.  (The absolute value to go in the place must be
+           divisible by four and, after having been divided by four, must
+           fit in eight bits.)  */
+        if ((residual & 0x3) != 0 || residual >= 0x400)
+          {
+            (*_bfd_error_handler)
+              (_("%B(%A+0x%lx): Overflow whilst splitting 0x%lx for group relocation %s"),
+              input_bfd, input_section,
+              (long) rel->r_offset, abs (signed_value), howto->name);
+            return bfd_reloc_overflow;
+          }
 
-          /* Preserve Rm (lowest four bits) and the condition code
-             (highest four bits). Other bits encode MOV PC,Rm.  */
-          insn = (insn & 0xf000000f) | 0x01a0f000;
+        /* Mask out the value and U bit.  */
+        insn &= 0xff7fff00;
 
-          bfd_put_32 (input_bfd, insn, hit_data);
-        }
+        /* Set the U bit if the value to go in the place is non-negative.  */
+        if (signed_value >= 0)
+          insn |= 1 << 23;
+
+        /* Encode the offset.  */
+        insn |= residual >> 2;
+
+       bfd_put_32 (input_bfd, insn, hit_data);
+      }
       return bfd_reloc_ok;
 
     default:
@@ -5011,14 +6118,31 @@ elf32_arm_merge_eabi_attributes (bfd *ibfd, bfd *obfd)
   for (; in_list; in_list = in_list->next)
     {
       if ((in_list->tag & 128) < 64)
-       _bfd_error_handler
-         (_("Warning: %B: Unknown EABI object attribute %d"),
-          ibfd, in_list->tag);
-      break;
+       {
+         _bfd_error_handler
+           (_("Warning: %B: Unknown EABI object attribute %d"),
+            ibfd, in_list->tag);
+         break;
+       }
     }
   return TRUE;
 }
 
+
+/* Return TRUE if the two EABI versions are incompatible.  */
+
+static bfd_boolean
+elf32_arm_versions_compatible (unsigned iver, unsigned over)
+{
+  /* v4 and v5 are the same spec before and after it was released,
+     so allow mixing them.  */
+  if ((iver == EF_ARM_EABI_VER4 && over == EF_ARM_EABI_VER5)
+      || (iver == EF_ARM_EABI_VER5 && over == EF_ARM_EABI_VER4))
+    return TRUE;
+
+  return (iver == over);
+}
+
 /* Merge backend specific data from an object file to the output
    object file when linking.  */
 
@@ -5117,7 +6241,8 @@ elf32_arm_merge_private_bfd_data (bfd * ibfd, bfd * obfd)
     }
 
   /* Complain about various flag mismatches.  */
-  if (EF_ARM_EABI_VERSION (in_flags) != EF_ARM_EABI_VERSION (out_flags))
+  if (!elf32_arm_versions_compatible (EF_ARM_EABI_VERSION (in_flags),
+                                     EF_ARM_EABI_VERSION (out_flags)))
     {
       _bfd_error_handler
        (_("ERROR: Source object %B has EABI version %d, but target %B has EABI version %d"),
@@ -5128,7 +6253,10 @@ elf32_arm_merge_private_bfd_data (bfd * ibfd, bfd * obfd)
     }
 
   /* Not sure what needs to be checked for EABI versions >= 1.  */
-  if (EF_ARM_EABI_VERSION (in_flags) == EF_ARM_EABI_UNKNOWN)
+  /* VxWorks libraries do not use these flags.  */
+  if (get_elf_backend_data (obfd) != &elf32_arm_vxworks_bed
+      && get_elf_backend_data (ibfd) != &elf32_arm_vxworks_bed
+      && EF_ARM_EABI_VERSION (in_flags) == EF_ARM_EABI_UNKNOWN)
     {
       if ((in_flags & EF_ARM_APCS_26) != (out_flags & EF_ARM_APCS_26))
        {
@@ -5325,7 +6453,11 @@ elf32_arm_print_private_bfd_data (bfd *abfd, void * ptr)
 
     case EF_ARM_EABI_VER4:
       fprintf (file, _(" [Version4 EABI]"));
+      goto eabi;
 
+    case EF_ARM_EABI_VER5:
+      fprintf (file, _(" [Version5 EABI]"));
+    eabi:
       if (flags & EF_ARM_BE8)
        fprintf (file, _(" [BE8]"));
 
@@ -5371,7 +6503,7 @@ elf32_arm_get_symbol_type (Elf_Internal_Sym * elf_sym, int type)
         This allows us to distinguish between data used by Thumb instructions
         and non-data (which is probably code) inside Thumb regions of an
         executable.  */
-      if (type != STT_OBJECT)
+      if (type != STT_OBJECT && type != STT_TLS)
        return ELF_ST_TYPE (elf_sym->st_info);
       break;
 
@@ -5488,6 +6620,14 @@ elf32_arm_gc_sweep_hook (bfd *                     abfd,
        case R_ARM_JUMP24:
        case R_ARM_PREL31:
        case R_ARM_THM_CALL:
+       case R_ARM_MOVW_ABS_NC:
+       case R_ARM_MOVT_ABS:
+       case R_ARM_MOVW_PREL_NC:
+       case R_ARM_MOVT_PREL:
+       case R_ARM_THM_MOVW_ABS_NC:
+       case R_ARM_THM_MOVT_ABS:
+       case R_ARM_THM_MOVW_PREL_NC:
+       case R_ARM_THM_MOVT_PREL:
          /* Should the interworking branches be here also?  */
 
          if (h != NULL)
@@ -5683,6 +6823,13 @@ elf32_arm_check_relocs (bfd *abfd, struct bfd_link_info *info,
              }
            break;
 
+         case R_ARM_ABS12:
+           /* VxWorks uses dynamic R_ARM_ABS12 relocations for
+              ldr __GOTT_INDEX__ offsets.  */
+           if (!htab->vxworks_p)
+             break;
+           /* Fall through */
+
          case R_ARM_ABS32:
          case R_ARM_REL32:
          case R_ARM_PC24:
@@ -5691,6 +6838,14 @@ elf32_arm_check_relocs (bfd *abfd, struct bfd_link_info *info,
          case R_ARM_JUMP24:
          case R_ARM_PREL31:
          case R_ARM_THM_CALL:
+         case R_ARM_MOVW_ABS_NC:
+         case R_ARM_MOVT_ABS:
+         case R_ARM_MOVW_PREL_NC:
+         case R_ARM_MOVT_PREL:
+         case R_ARM_THM_MOVW_ABS_NC:
+         case R_ARM_THM_MOVT_ABS:
+         case R_ARM_THM_MOVW_PREL_NC:
+         case R_ARM_THM_MOVT_PREL:
            /* Should the interworking branches be listed here?  */
            if (h != NULL)
              {
@@ -5707,12 +6862,7 @@ elf32_arm_check_relocs (bfd *abfd, struct bfd_link_info *info,
                   refers to is in a different object.  We can't tell for
                   sure yet, because something later might force the
                   symbol local.  */
-               if (r_type == R_ARM_PC24
-                   || r_type == R_ARM_CALL
-                   || r_type == R_ARM_JUMP24
-                   || r_type == R_ARM_PREL31
-                   || r_type == R_ARM_PLT32
-                   || r_type == R_ARM_THM_CALL)
+               if (r_type != R_ARM_ABS32 && r_type != R_ARM_REL32)
                  h->needs_plt = 1;
 
                /* If we create a PLT entry, this relocation will reference
@@ -5757,9 +6907,7 @@ elf32_arm_check_relocs (bfd *abfd, struct bfd_link_info *info,
                    if (name == NULL)
                      return FALSE;
 
-                   BFD_ASSERT (strncmp (name, ".rel", 4) == 0
-                               && strcmp (bfd_get_section_name (abfd, sec),
-                                          name + 4) == 0);
+                   BFD_ASSERT (reloc_section_p (htab, name, sec));
 
                    sreloc = bfd_get_section_by_name (dynobj, name);
                    if (sreloc == NULL)
@@ -5853,7 +7001,8 @@ elf32_arm_check_relocs (bfd *abfd, struct bfd_link_info *info,
 static bfd_boolean
 elf32_arm_is_target_special_symbol (bfd * abfd ATTRIBUTE_UNUSED, asymbol * sym)
 {
-  return bfd_is_arm_mapping_symbol_name (sym->name);
+  return bfd_is_arm_special_symbol_name (sym->name,
+                                        BFD_ARM_SPECIAL_SYM_TYPE_ANY);
 }
 
 /* This is a copy of elf_find_function() from elf.c except that
@@ -5889,9 +7038,10 @@ arm_elf_find_function (bfd *         abfd ATTRIBUTE_UNUSED,
        case STT_FUNC:
        case STT_ARM_TFUNC:
        case STT_NOTYPE:
-         /* Skip $a and $t symbols.  */
+         /* Skip mapping symbols.  */
          if ((q->symbol.flags & BSF_LOCAL)
-             && bfd_is_arm_mapping_symbol_name (q->symbol.name))
+             && bfd_is_arm_special_symbol_name (q->symbol.name,
+                   BFD_ARM_SPECIAL_SYM_TYPE_ANY))
            continue;
          /* Fall through.  */
          if (bfd_get_section (&q->symbol) == section
@@ -6094,14 +7244,14 @@ elf32_arm_adjust_dynamic_symbol (struct bfd_link_info * info,
   /* We must generate a R_ARM_COPY reloc to tell the dynamic linker to
      copy the initial value out of the dynamic object and into the
      runtime process image.  We need to remember the offset into the
-     .rel.bss section we are going to use.  */
+     .rel(a).bss section we are going to use.  */
   if ((h->root.u.def.section->flags & SEC_ALLOC) != 0)
     {
       asection *srel;
 
-      srel = bfd_get_section_by_name (dynobj, ".rel.bss");
+      srel = bfd_get_section_by_name (dynobj, RELOC_SECTION (globals, ".bss"));
       BFD_ASSERT (srel != NULL);
-      srel->size += sizeof (Elf32_External_Rel);
+      srel->size += RELOC_SIZE (globals);
       h->needs_copy = 1;
     }
 
@@ -6215,8 +7365,24 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
              htab->sgotplt->size += 4;
            }
 
-         /* We also need to make an entry in the .rel.plt section.  */
-         htab->srelplt->size += sizeof (Elf32_External_Rel);
+         /* We also need to make an entry in the .rel(a).plt section.  */
+         htab->srelplt->size += RELOC_SIZE (htab);
+
+         /* VxWorks executables have a second set of relocations for
+            each PLT entry.  They go in a separate relocation section,
+            which is processed by the kernel loader.  */
+         if (htab->vxworks_p && !info->shared)
+           {
+             /* There is a relocation for the initial PLT entry:
+                an R_ARM_32 relocation for _GLOBAL_OFFSET_TABLE_.  */
+             if (h->plt.offset == htab->plt_header_size)
+               htab->srelplt2->size += RELOC_SIZE (htab);
+
+             /* There are two extra relocations for each subsequent
+                PLT entry: an R_ARM_32 relocation for the GOT entry,
+                and an R_ARM_32 relocation for the PLT entry.  */
+             htab->srelplt2->size += RELOC_SIZE (htab) * 2;
+           }
        }
       else
        {
@@ -6281,19 +7447,19 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
                  || h->root.type != bfd_link_hash_undefweak))
            {
              if (tls_type & GOT_TLS_IE)
-               htab->srelgot->size += sizeof (Elf32_External_Rel);
+               htab->srelgot->size += RELOC_SIZE (htab);
 
              if (tls_type & GOT_TLS_GD)
-               htab->srelgot->size += sizeof (Elf32_External_Rel);
+               htab->srelgot->size += RELOC_SIZE (htab);
 
              if ((tls_type & GOT_TLS_GD) && indx != 0)
-               htab->srelgot->size += sizeof (Elf32_External_Rel);
+               htab->srelgot->size += RELOC_SIZE (htab);
            }
          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);
+           htab->srelgot->size += RELOC_SIZE (htab);
        }
     }
   else
@@ -6333,9 +7499,22 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
 
       /* Also discard relocs on undefined weak syms with non-default
          visibility.  */
-      if (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT
+      if (eh->relocs_copied != NULL
          && h->root.type == bfd_link_hash_undefweak)
-       eh->relocs_copied = NULL;
+       {
+         if (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT)
+           eh->relocs_copied = NULL;
+
+         /* Make sure undefined weak symbols are output as a dynamic
+            symbol in PIEs.  */
+         else if (h->dynindx == -1
+                  && !h->forced_local)
+           {
+             if (! bfd_elf_link_record_dynamic_symbol (info, h))
+               return FALSE;
+           }
+       }
+
       else if (htab->root.is_relocatable_executable && h->dynindx == -1
               && h->root.type == bfd_link_hash_new)
        {
@@ -6384,7 +7563,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
   for (p = eh->relocs_copied; p != NULL; p = p->next)
     {
       asection *sreloc = elf_section_data (p->section)->sreloc;
-      sreloc->size += p->count * sizeof (Elf32_External_Rel);
+      sreloc->size += p->count * RELOC_SIZE (htab);
     }
 
   return TRUE;
@@ -6480,7 +7659,7 @@ elf32_arm_size_dynamic_sections (bfd * output_bfd ATTRIBUTE_UNUSED,
              else if (p->count != 0)
                {
                  srel = elf_section_data (p->section)->sreloc;
-                 srel->size += p->count * sizeof (Elf32_External_Rel);
+                 srel->size += p->count * RELOC_SIZE (htab);
                  if ((p->section->output_section->flags & SEC_READONLY) != 0)
                    info->flags |= DF_TEXTREL;
                }
@@ -6511,7 +7690,7 @@ elf32_arm_size_dynamic_sections (bfd * output_bfd ATTRIBUTE_UNUSED,
                s->size += 4;
 
              if (info->shared || *local_tls_type == GOT_TLS_GD)
-               srel->size += sizeof (Elf32_External_Rel);
+               srel->size += RELOC_SIZE (htab);
            }
          else
            *local_got = (bfd_vma) -1;
@@ -6525,7 +7704,7 @@ elf32_arm_size_dynamic_sections (bfd * output_bfd ATTRIBUTE_UNUSED,
       htab->tls_ldm_got.offset = htab->sgot->size;
       htab->sgot->size += 8;
       if (info->shared)
-       htab->srelgot->size += sizeof (Elf32_External_Rel);
+       htab->srelgot->size += RELOC_SIZE (htab);
     }
   else
     htab->tls_ldm_got.offset = -1;
@@ -6560,8 +7739,8 @@ elf32_arm_size_dynamic_sections (bfd * output_bfd ATTRIBUTE_UNUSED,
          if (s->size != 0)
            {
              /* Remember whether there are any reloc sections other
-                 than .rel.plt.  */
-             if (strcmp (name, ".rel.plt") != 0)
+                than .rel(a).plt and .rela.plt.unloaded.  */
+             if (s != htab->srelplt && s != htab->srelplt2)
                relocs = TRUE;
 
              /* We use the reloc_count field as a counter if we need
@@ -6579,8 +7758,8 @@ elf32_arm_size_dynamic_sections (bfd * output_bfd ATTRIBUTE_UNUSED,
       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
+            output file.  This is mostly to handle .rel(a).bss and
+            .rel(a).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
@@ -6620,17 +7799,28 @@ elf32_arm_size_dynamic_sections (bfd * output_bfd ATTRIBUTE_UNUSED,
        {
          if (   !add_dynamic_entry (DT_PLTGOT, 0)
              || !add_dynamic_entry (DT_PLTRELSZ, 0)
-             || !add_dynamic_entry (DT_PLTREL, DT_REL)
+             || !add_dynamic_entry (DT_PLTREL,
+                                    htab->use_rel ? DT_REL : DT_RELA)
              || !add_dynamic_entry (DT_JMPREL, 0))
            return FALSE;
        }
 
       if (relocs)
        {
-         if (   !add_dynamic_entry (DT_REL, 0)
-             || !add_dynamic_entry (DT_RELSZ, 0)
-             || !add_dynamic_entry (DT_RELENT, sizeof (Elf32_External_Rel)))
-           return FALSE;
+         if (htab->use_rel)
+           {
+             if (!add_dynamic_entry (DT_REL, 0)
+                 || !add_dynamic_entry (DT_RELSZ, 0)
+                 || !add_dynamic_entry (DT_RELENT, RELOC_SIZE (htab)))
+               return FALSE;
+           }
+         else
+           {
+             if (!add_dynamic_entry (DT_RELA, 0)
+                 || !add_dynamic_entry (DT_RELASZ, 0)
+                 || !add_dynamic_entry (DT_RELAENT, RELOC_SIZE (htab)))
+               return FALSE;
+           }
        }
 
       /* If any dynamic relocs apply to a read-only section,
@@ -6679,22 +7869,23 @@ elf32_arm_finish_dynamic_symbol (bfd * output_bfd, struct bfd_link_info * info,
       BFD_ASSERT (h->dynindx != -1);
 
       splt = bfd_get_section_by_name (dynobj, ".plt");
-      srel = bfd_get_section_by_name (dynobj, ".rel.plt");
+      srel = bfd_get_section_by_name (dynobj, RELOC_SECTION (htab, ".plt"));
       BFD_ASSERT (splt != NULL && srel != NULL);
 
       /* Fill in the entry in the procedure linkage table.  */
       if (htab->symbian_p)
        {
-         unsigned i;
-         for (i = 0; i < htab->plt_entry_size / 4; ++i)
-           bfd_put_32 (output_bfd, 
-                       elf32_arm_symbian_plt_entry[i],
-                       splt->contents + h->plt.offset + 4 * i);
+         put_arm_insn (htab, output_bfd, 
+                     elf32_arm_symbian_plt_entry[0],
+                     splt->contents + h->plt.offset);
+         bfd_put_32 (output_bfd, 
+                     elf32_arm_symbian_plt_entry[1],
+                     splt->contents + h->plt.offset + 4);
          
          /* Fill in the entry in the .rel.plt section.  */
          rel.r_offset = (splt->output_section->vma
                          + splt->output_offset
-                         + h->plt.offset + 4 * (i - 1));
+                         + h->plt.offset + 4);
          rel.r_info = ELF32_R_INFO (h->dynindx, R_ARM_GLOB_DAT);
 
          /* Get the index in the procedure linkage table which
@@ -6706,9 +7897,10 @@ elf32_arm_finish_dynamic_symbol (bfd * output_bfd, struct bfd_link_info * info,
        }
       else
        {
-         bfd_vma got_offset;
+         bfd_vma got_offset, got_address, plt_address;
          bfd_vma got_displacement;
          asection * sgot;
+         bfd_byte * ptr;
          
          sgot = bfd_get_section_by_name (dynobj, ".got.plt");
          BFD_ASSERT (sgot != NULL);
@@ -6724,38 +7916,107 @@ elf32_arm_finish_dynamic_symbol (bfd * output_bfd, struct bfd_link_info * info,
             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.  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
-                             - splt->output_section->vma
-                             - splt->output_offset
-                             - h->plt.offset
-                             - 8);
+         /* Calculate the address of the GOT entry.  */
+         got_address = (sgot->output_section->vma
+                        + sgot->output_offset
+                        + got_offset);
 
-         BFD_ASSERT ((got_displacement & 0xf0000000) == 0);
+         /* ...and the address of the PLT entry.  */
+         plt_address = (splt->output_section->vma
+                        + splt->output_offset
+                        + h->plt.offset);
 
-         if (!htab->use_blx && eh->plt_thumb_refcount > 0)
+         ptr = htab->splt->contents + h->plt.offset;
+         if (htab->vxworks_p && info->shared)
+           {
+             unsigned int i;
+             bfd_vma val;
+
+             for (i = 0; i != htab->plt_entry_size / 4; i++, ptr += 4)
+               {
+                 val = elf32_arm_vxworks_shared_plt_entry[i];
+                 if (i == 2)
+                   val |= got_address - sgot->output_section->vma;
+                 if (i == 5)
+                   val |= plt_index * RELOC_SIZE (htab);
+                 if (i == 2 || i == 5)
+                   bfd_put_32 (output_bfd, val, ptr);
+                 else
+                   put_arm_insn (htab, output_bfd, val, ptr);
+               }
+           }
+         else if (htab->vxworks_p)
            {
-             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);
+             unsigned int i;
+             bfd_vma val;
+
+             for (i = 0; i != htab->plt_entry_size / 4; i++)
+               {
+                 val = elf32_arm_vxworks_exec_plt_entry[i];
+                 if (i == 2)
+                   val |= got_address;
+                 if (i == 4)
+                   val |= 0xffffff & -((h->plt.offset + i * 4 + 8) >> 2);
+                 if (i == 5)
+                   val |= plt_index * RELOC_SIZE (htab);
+                 if (i == 2 || i == 5)
+                   bfd_put_32 (output_bfd, val, ptr);
+                 else
+                   put_arm_insn (htab, output_bfd, val, ptr);
+               }
+
+             loc = (htab->srelplt2->contents
+                    + (plt_index * 2 + 1) * RELOC_SIZE (htab));
+
+             /* Create the .rela.plt.unloaded R_ARM_ABS32 relocation
+                referencing the GOT for this PLT entry.  */
+             rel.r_offset = plt_address + 8;
+             rel.r_info = ELF32_R_INFO (htab->root.hgot->indx, R_ARM_ABS32);
+             rel.r_addend = got_offset;
+             SWAP_RELOC_OUT (htab) (output_bfd, &rel, loc);
+             loc += RELOC_SIZE (htab);
+
+             /* Create the R_ARM_ABS32 relocation referencing the
+                beginning of the PLT for this GOT entry.  */
+             rel.r_offset = got_address;
+             rel.r_info = ELF32_R_INFO (htab->root.hplt->indx, R_ARM_ABS32);
+             rel.r_addend = 0;
+             SWAP_RELOC_OUT (htab) (output_bfd, &rel, loc);
            }
+         else
+           {
+             /* Calculate the displacement between the PLT slot and the
+                entry in the GOT.  The eight-byte offset accounts for the
+                value produced by adding to pc in the first instruction
+                of the PLT stub.  */
+             got_displacement = got_address - (plt_address + 8);
 
-         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),
-                     splt->contents + h->plt.offset + 4);
-         bfd_put_32 (output_bfd, elf32_arm_plt_entry[2] | (got_displacement & 0x00000fff),
-                     splt->contents + h->plt.offset + 8);
+             BFD_ASSERT ((got_displacement & 0xf0000000) == 0);
+
+             if (!htab->use_blx && eh->plt_thumb_refcount > 0)
+               {
+                 put_thumb_insn (htab, output_bfd,
+                                 elf32_arm_plt_thumb_stub[0], ptr - 4);
+                 put_thumb_insn (htab, output_bfd,
+                                 elf32_arm_plt_thumb_stub[1], ptr - 2);
+               }
+
+             put_arm_insn (htab, output_bfd,
+                           elf32_arm_plt_entry[0]
+                           | ((got_displacement & 0x0ff00000) >> 20),
+                           ptr + 0);
+             put_arm_insn (htab, output_bfd,
+                           elf32_arm_plt_entry[1]
+                           | ((got_displacement & 0x000ff000) >> 12),
+                           ptr+ 4);
+             put_arm_insn (htab, output_bfd,
+                           elf32_arm_plt_entry[2]
+                           | (got_displacement & 0x00000fff),
+                           ptr + 8);
 #ifdef FOUR_WORD_PLT
-         bfd_put_32 (output_bfd, elf32_arm_plt_entry[3],
-                     splt->contents + h->plt.offset + 12);
+             bfd_put_32 (output_bfd, elf32_arm_plt_entry[3], ptr + 12);
 #endif
+           }
 
          /* Fill in the entry in the global offset table.  */
          bfd_put_32 (output_bfd,
@@ -6763,15 +8024,14 @@ elf32_arm_finish_dynamic_symbol (bfd * output_bfd, struct bfd_link_info * info,
                       + splt->output_offset),
                      sgot->contents + got_offset);
          
-         /* Fill in the entry in the .rel.plt section.  */
-         rel.r_offset = (sgot->output_section->vma
-                         + sgot->output_offset
-                         + got_offset);
+         /* Fill in the entry in the .rel(a).plt section.  */
+         rel.r_addend = 0;
+         rel.r_offset = got_address;
          rel.r_info = ELF32_R_INFO (h->dynindx, R_ARM_JUMP_SLOT);
        }
 
-      loc = srel->contents + plt_index * sizeof (Elf32_External_Rel);
-      bfd_elf32_swap_reloc_out (output_bfd, &rel, loc);
+      loc = srel->contents + plt_index * RELOC_SIZE (htab);
+      SWAP_RELOC_OUT (htab) (output_bfd, &rel, loc);
 
       if (!h->def_regular)
        {
@@ -6795,16 +8055,19 @@ elf32_arm_finish_dynamic_symbol (bfd * output_bfd, struct bfd_link_info * info,
       asection * srel;
       Elf_Internal_Rela rel;
       bfd_byte *loc;
+      bfd_vma offset;
 
       /* This symbol has an entry in the global offset table.  Set it
         up.  */
       sgot = bfd_get_section_by_name (dynobj, ".got");
-      srel = bfd_get_section_by_name (dynobj, ".rel.got");
+      srel = bfd_get_section_by_name (dynobj, RELOC_SECTION (htab, ".got"));
       BFD_ASSERT (sgot != NULL && srel != NULL);
 
+      offset = (h->got.offset & ~(bfd_vma) 1);
+      rel.r_addend = 0;
       rel.r_offset = (sgot->output_section->vma
                      + sgot->output_offset
-                     + (h->got.offset &~ (bfd_vma) 1));
+                     + offset);
 
       /* If this is a static link, or it is a -Bsymbolic link and the
         symbol is defined locally or was forced to be local because
@@ -6816,16 +8079,21 @@ elf32_arm_finish_dynamic_symbol (bfd * output_bfd, struct bfd_link_info * info,
        {
          BFD_ASSERT((h->got.offset & 1) != 0);
          rel.r_info = ELF32_R_INFO (0, R_ARM_RELATIVE);
+         if (!htab->use_rel)
+           {
+             rel.r_addend = bfd_get_32 (output_bfd, sgot->contents + offset);
+             bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents + offset);
+           }
        }
       else
        {
          BFD_ASSERT((h->got.offset & 1) == 0);
-         bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents + h->got.offset);
+         bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents + offset);
          rel.r_info = ELF32_R_INFO (h->dynindx, R_ARM_GLOB_DAT);
        }
 
-      loc = srel->contents + srel->reloc_count++ * sizeof (Elf32_External_Rel);
-      bfd_elf32_swap_reloc_out (output_bfd, &rel, loc);
+      loc = srel->contents + srel->reloc_count++ * RELOC_SIZE (htab);
+      SWAP_RELOC_OUT (htab) (output_bfd, &rel, loc);
     }
 
   if (h->needs_copy)
@@ -6840,20 +8108,23 @@ elf32_arm_finish_dynamic_symbol (bfd * output_bfd, struct bfd_link_info * info,
                      || h->root.type == bfd_link_hash_defweak));
 
       s = bfd_get_section_by_name (h->root.u.def.section->owner,
-                                  ".rel.bss");
+                                  RELOC_SECTION (htab, ".bss"));
       BFD_ASSERT (s != NULL);
 
+      rel.r_addend = 0;
       rel.r_offset = (h->root.u.def.value
                      + h->root.u.def.section->output_section->vma
                      + h->root.u.def.section->output_offset);
       rel.r_info = ELF32_R_INFO (h->dynindx, R_ARM_COPY);
-      loc = s->contents + s->reloc_count++ * sizeof (Elf32_External_Rel);
-      bfd_elf32_swap_reloc_out (output_bfd, &rel, loc);
+      loc = s->contents + s->reloc_count++ * RELOC_SIZE (htab);
+      SWAP_RELOC_OUT (htab) (output_bfd, &rel, loc);
     }
 
-  /* Mark _DYNAMIC and _GLOBAL_OFFSET_TABLE_ as absolute.  */
+  /* Mark _DYNAMIC and _GLOBAL_OFFSET_TABLE_ as absolute.  On VxWorks,
+     the _GLOBAL_OFFSET_TABLE_ symbol is not absolute: it is relative
+     to the ".got" section.  */
   if (strcmp (h->root.root.string, "_DYNAMIC") == 0
-      || strcmp (h->root.root.string, "_GLOBAL_OFFSET_TABLE_") == 0)
+      || (!htab->vxworks_p && h == htab->root.hgot))
     sym->st_shndx = SHN_ABS;
 
   return TRUE;
@@ -6925,7 +8196,7 @@ elf32_arm_finish_dynamic_sections (bfd * output_bfd, struct bfd_link_info * info
              name = ".got";
              goto get_vma;
            case DT_JMPREL:
-             name = ".rel.plt";
+             name = RELOC_SECTION (htab, ".plt");
            get_vma:
              s = bfd_get_section_by_name (output_bfd, name);
              BFD_ASSERT (s != NULL);
@@ -6945,13 +8216,15 @@ elf32_arm_finish_dynamic_sections (bfd * output_bfd, struct bfd_link_info * info
              break;
 
            case DT_PLTRELSZ:
-             s = bfd_get_section_by_name (output_bfd, ".rel.plt");
+             s = bfd_get_section_by_name (output_bfd,
+                                          RELOC_SECTION (htab, ".plt"));
              BFD_ASSERT (s != NULL);
              dyn.d_un.d_val = s->size;
              bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon);
              break;
              
            case DT_RELSZ:
+           case DT_RELASZ:
              if (!htab->symbian_p)
                {
                  /* My reading of the SVR4 ABI indicates that the
@@ -6960,10 +8233,11 @@ elf32_arm_finish_dynamic_sections (bfd * output_bfd, struct bfd_link_info * info
                     what Solaris does.  However, UnixWare can not handle
                     that case.  Therefore, we override the DT_RELSZ entry
                     here to make it not include the JMPREL relocs.  Since
-                    the linker script arranges for .rel.plt to follow all
+                    the linker script arranges for .rel(a).plt to follow all
                     other relocation sections, we don't have to worry
                     about changing the DT_REL entry.  */
-                 s = bfd_get_section_by_name (output_bfd, ".rel.plt");
+                 s = bfd_get_section_by_name (output_bfd,
+                                              RELOC_SECTION (htab, ".plt"));
                  if (s != NULL)
                    dyn.d_un.d_val -= s->size;
                  bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon);
@@ -6973,7 +8247,6 @@ elf32_arm_finish_dynamic_sections (bfd * output_bfd, struct bfd_link_info * info
 
            case DT_REL:
            case DT_RELA:
-           case DT_RELASZ:
              /* In the BPABI, the DT_REL tag must point at the file
                 offset, not the VMA, of the first relocation
                 section.  So, we use code similar to that in
@@ -7036,31 +8309,90 @@ elf32_arm_finish_dynamic_sections (bfd * output_bfd, struct bfd_link_info * info
       /* Fill in the first entry in the procedure linkage table.  */
       if (splt->size > 0 && elf32_arm_hash_table (info)->plt_header_size)
        {
-         bfd_vma got_displacement;
+         const bfd_vma *plt0_entry;
+         bfd_vma got_address, plt_address, got_displacement;
+
+         /* Calculate the addresses of the GOT and PLT.  */
+         got_address = sgot->output_section->vma + sgot->output_offset;
+         plt_address = splt->output_section->vma + splt->output_offset;
+
+         if (htab->vxworks_p)
+           {
+             /* The VxWorks GOT is relocated by the dynamic linker.
+                Therefore, we must emit relocations rather than simply
+                computing the values now.  */
+             Elf_Internal_Rela rel;
+
+             plt0_entry = elf32_arm_vxworks_exec_plt0_entry;
+             put_arm_insn (htab, output_bfd, plt0_entry[0],
+                           splt->contents + 0);
+             put_arm_insn (htab, output_bfd, plt0_entry[1],
+                           splt->contents + 4);
+             put_arm_insn (htab, output_bfd, plt0_entry[2],
+                           splt->contents + 8);
+             bfd_put_32 (output_bfd, got_address, splt->contents + 12);
+
+             /* Generate a relocation for _GLOBAL_OFFSET_TABLE_. */
+             rel.r_offset = plt_address + 12;
+             rel.r_info = ELF32_R_INFO (htab->root.hgot->indx, R_ARM_ABS32);
+             rel.r_addend = 0;
+             SWAP_RELOC_OUT (htab) (output_bfd, &rel,
+                                    htab->srelplt2->contents);
+           }
+         else
+           {
+             got_displacement = got_address - (plt_address + 16);
+
+             plt0_entry = elf32_arm_plt0_entry;
+             put_arm_insn (htab, output_bfd, plt0_entry[0],
+                           splt->contents + 0);
+             put_arm_insn (htab, output_bfd, plt0_entry[1],
+                           splt->contents + 4);
+             put_arm_insn (htab, output_bfd, plt0_entry[2],
+                           splt->contents + 8);
+             put_arm_insn (htab, output_bfd, plt0_entry[3],
+                           splt->contents + 12);
 
-         /* Calculate the displacement between the PLT slot and &GOT[0].  */
-         got_displacement = (sgot->output_section->vma
-                             + sgot->output_offset
-                             - splt->output_section->vma
-                             - splt->output_offset
-                             - 16);
-
-         bfd_put_32 (output_bfd, elf32_arm_plt0_entry[0], splt->contents +  0);
-         bfd_put_32 (output_bfd, elf32_arm_plt0_entry[1], splt->contents +  4);
-         bfd_put_32 (output_bfd, elf32_arm_plt0_entry[2], splt->contents +  8);
-         bfd_put_32 (output_bfd, elf32_arm_plt0_entry[3], splt->contents + 12);
 #ifdef FOUR_WORD_PLT
-         /* The displacement value goes in the otherwise-unused last word of
-            the second entry.  */
-         bfd_put_32 (output_bfd, got_displacement,        splt->contents + 28);
+             /* The displacement value goes in the otherwise-unused
+                last word of the second entry.  */
+             bfd_put_32 (output_bfd, got_displacement, splt->contents + 28);
 #else
-         bfd_put_32 (output_bfd, got_displacement,        splt->contents + 16);
+             bfd_put_32 (output_bfd, got_displacement, splt->contents + 16);
 #endif
+           }
        }
 
       /* UnixWare sets the entsize of .plt to 4, although that doesn't
         really seem like the right value.  */
       elf_section_data (splt->output_section)->this_hdr.sh_entsize = 4;
+
+      if (htab->vxworks_p && !info->shared && htab->splt->size > 0)
+       {
+         /* Correct the .rel(a).plt.unloaded relocations.  They will have
+            incorrect symbol indexes.  */
+         int num_plts;
+         unsigned char *p;
+
+         num_plts = ((htab->splt->size - htab->plt_header_size)
+                     / htab->plt_entry_size);
+         p = htab->srelplt2->contents + RELOC_SIZE (htab);
+
+         for (; num_plts; num_plts--)
+           {
+             Elf_Internal_Rela rel;
+
+             SWAP_RELOC_IN (htab) (output_bfd, p, &rel);
+             rel.r_info = ELF32_R_INFO (htab->root.hgot->indx, R_ARM_ABS32);
+             SWAP_RELOC_OUT (htab) (output_bfd, &rel, p);
+             p += RELOC_SIZE (htab);
+
+             SWAP_RELOC_IN (htab) (output_bfd, p, &rel);
+             rel.r_info = ELF32_R_INFO (htab->root.hplt->indx, R_ARM_ABS32);
+             SWAP_RELOC_OUT (htab) (output_bfd, &rel, p);
+             p += RELOC_SIZE (htab);
+           }
+       }
     }
 
   /* Fill in the first three entries in the global offset table.  */
@@ -7430,7 +8762,7 @@ elf32_arm_output_symbol_hook (struct bfd_link_info *info,
                              const char *name,
                              Elf_Internal_Sym *elfsym,
                              asection *input_sec,
-                             struct elf_link_hash_entry *h ATTRIBUTE_UNUSED)
+                             struct elf_link_hash_entry *h)
 {
   int mapcount;
   elf32_arm_section_map *map;
@@ -7438,17 +8770,22 @@ elf32_arm_output_symbol_hook (struct bfd_link_info *info,
   _arm_elf_section_data *arm_data;
   struct elf32_arm_link_hash_table *globals;
 
+  globals = elf32_arm_hash_table (info);
+  if (globals->vxworks_p
+      && !elf_vxworks_link_output_symbol_hook (info, name, elfsym,
+                                              input_sec, h))
+    return FALSE;
+
   /* Only do this on final link.  */
   if (info->relocatable)
     return TRUE;
 
   /* Only build a map if we need to byteswap code.  */
-  globals = elf32_arm_hash_table (info);
   if (!globals->byteswap_code)
     return TRUE;
 
   /* We only want mapping symbols.  */
-  if (! bfd_is_arm_mapping_symbol_name (name))
+  if (!bfd_is_arm_special_symbol_name (name, BFD_ARM_SPECIAL_SYM_TYPE_MAP))
     return TRUE;
 
   /* If this section has not been allocated an _arm_elf_section_data
@@ -7475,18 +8812,189 @@ elf32_arm_output_symbol_hook (struct bfd_link_info *info,
   return TRUE;
 }
 
+typedef struct
+{
+  void *finfo;
+  struct bfd_link_info *info;
+  int plt_shndx;
+  bfd_vma plt_offset;
+  bfd_boolean (*func) (void *, const char *, Elf_Internal_Sym *,
+                      asection *, struct elf_link_hash_entry *);
+} output_arch_syminfo;
+
+enum map_symbol_type
+{
+  ARM_MAP_ARM,
+  ARM_MAP_THUMB,
+  ARM_MAP_DATA
+};
+
+
+/* Output a single PLT mapping symbol.  */
+
+static bfd_boolean
+elf32_arm_ouput_plt_map_sym (output_arch_syminfo *osi,
+                            enum map_symbol_type type,
+                            bfd_vma offset)
+{
+  static const char *names[3] = {"$a", "$t", "$d"};
+  struct elf32_arm_link_hash_table *htab;
+  Elf_Internal_Sym sym;
+
+  htab = elf32_arm_hash_table (osi->info);
+  sym.st_value = osi->plt_offset + offset;
+  sym.st_size = 0;
+  sym.st_other = 0;
+  sym.st_info = ELF_ST_INFO (STB_LOCAL, STT_NOTYPE);
+  sym.st_shndx = osi->plt_shndx;
+  if (!osi->func (osi->finfo, names[type], &sym, htab->splt, NULL))
+    return FALSE;
+  return TRUE;
+}
+
+
+/* Output mapping symbols for PLT entries associated with H.  */
+
+static bfd_boolean
+elf32_arm_output_plt_map (struct elf_link_hash_entry *h, void *inf)
+{
+  output_arch_syminfo *osi = (output_arch_syminfo *) inf;
+  struct elf32_arm_link_hash_table *htab;
+  struct elf32_arm_link_hash_entry *eh;
+  bfd_vma addr;
+
+  htab = elf32_arm_hash_table (osi->info);
+
+  if (h->root.type == bfd_link_hash_indirect)
+    return TRUE;
+
+  if (h->root.type == bfd_link_hash_warning)
+    /* When warning symbols are created, they **replace** the "real"
+       entry in the hash table, thus we never get to see the real
+       symbol in a hash traversal.  So look at it now.  */
+    h = (struct elf_link_hash_entry *) h->root.u.i.link;
+
+  if (h->plt.offset == (bfd_vma) -1)
+    return TRUE;
+
+  eh = (struct elf32_arm_link_hash_entry *) h;
+  addr = h->plt.offset;
+  if (htab->symbian_p)
+    {
+      if (!elf32_arm_ouput_plt_map_sym (osi, ARM_MAP_ARM, addr))
+       return FALSE;
+      if (!elf32_arm_ouput_plt_map_sym (osi, ARM_MAP_DATA, addr + 4))
+       return FALSE;
+    }
+  else if (htab->vxworks_p)
+    {
+      if (!elf32_arm_ouput_plt_map_sym (osi, ARM_MAP_ARM, addr))
+       return FALSE;
+      if (!elf32_arm_ouput_plt_map_sym (osi, ARM_MAP_DATA, addr + 8))
+       return FALSE;
+      if (!elf32_arm_ouput_plt_map_sym (osi, ARM_MAP_ARM, addr + 12))
+       return FALSE;
+      if (!elf32_arm_ouput_plt_map_sym (osi, ARM_MAP_DATA, addr + 20))
+       return FALSE;
+    }
+  else
+    {
+      bfd_boolean thumb_stub;
+
+      thumb_stub = eh->plt_thumb_refcount > 0 && !htab->use_blx;
+      if (thumb_stub)
+       {
+         if (!elf32_arm_ouput_plt_map_sym (osi, ARM_MAP_THUMB, addr - 4))
+           return FALSE;
+       }
+#ifdef FOUR_WORD_PLT
+      if (!elf32_arm_ouput_plt_map_sym (osi, ARM_MAP_ARM, addr))
+       return FALSE;
+      if (!elf32_arm_ouput_plt_map_sym (osi, ARM_MAP_DATA, addr + 12))
+       return FALSE;
+#else
+      /* A three-word PLT with no Thumb thunk contains only Arm code, 
+        so only need to output a mapping symbol for the first PLT entry and
+        entries with thumb thunks.  */
+      if (thumb_stub || addr == 20)
+       {
+         if (!elf32_arm_ouput_plt_map_sym (osi, ARM_MAP_ARM, addr))
+           return FALSE;
+       }
+#endif
+    }
+
+  return TRUE;
+}
+
+
+/* Output mapping symbols for the PLT.  */
+
+static bfd_boolean
+elf32_arm_output_arch_local_syms (bfd *output_bfd,
+    struct bfd_link_info *info,
+    void *finfo, bfd_boolean (*func) (void *, const char *,
+                                   Elf_Internal_Sym *,
+                                   asection *,
+                                   struct elf_link_hash_entry *))
+{
+  output_arch_syminfo osi;
+  struct elf32_arm_link_hash_table *htab;
+
+  htab = elf32_arm_hash_table (info);
+  if (!htab->splt || htab->splt->size == 0)
+    return TRUE;
+
+  check_use_blx(htab);
+  osi.finfo = finfo;
+  osi.info = info;
+  osi.func = func;
+  osi.plt_shndx = _bfd_elf_section_from_bfd_section (output_bfd,
+      htab->splt->output_section);
+  osi.plt_offset = htab->splt->output_section->vma;
+
+  /* Output mapping symbols for the plt header.  SymbianOS does not have a
+     plt header.  */
+  if (htab->vxworks_p)
+    {
+      /* VxWorks shared libraries have no PLT header.  */
+      if (!info->shared)
+       {
+         if (!elf32_arm_ouput_plt_map_sym (&osi, ARM_MAP_ARM, 0))
+           return FALSE;
+         if (!elf32_arm_ouput_plt_map_sym (&osi, ARM_MAP_DATA, 12))
+           return FALSE;
+       }
+    }
+  else if (!htab->symbian_p)
+    {
+      if (!elf32_arm_ouput_plt_map_sym (&osi, ARM_MAP_ARM, 0))
+       return FALSE;
+#ifndef FOUR_WORD_PLT
+      if (!elf32_arm_ouput_plt_map_sym (&osi, ARM_MAP_DATA, 16))
+       return FALSE;
+#endif
+    }
+
+  elf_link_hash_traverse (&htab->root, elf32_arm_output_plt_map, (void *) &osi);
+  return TRUE;
+}
+
 /* Allocate target specific section data.  */
 
 static bfd_boolean
 elf32_arm_new_section_hook (bfd *abfd, asection *sec)
 {
-  _arm_elf_section_data *sdata;
-  bfd_size_type amt = sizeof (*sdata);
+  if (!sec->used_by_bfd)
+    {
+      _arm_elf_section_data *sdata;
+      bfd_size_type amt = sizeof (*sdata);
 
-  sdata = bfd_zalloc (abfd, amt);
-  if (sdata == NULL)
-    return FALSE;
-  sec->used_by_bfd = sdata;
+      sdata = bfd_zalloc (abfd, amt);
+      if (sdata == NULL)
+       return FALSE;
+      sec->used_by_bfd = sdata;
+    }
 
   record_section_with_arm_elf_section_data (sec);
 
@@ -7596,11 +9104,25 @@ unrecord_section_via_map_over_sections (bfd * abfd ATTRIBUTE_UNUSED,
 static bfd_boolean
 elf32_arm_close_and_cleanup (bfd * abfd)
 {
-  bfd_map_over_sections (abfd, unrecord_section_via_map_over_sections, NULL);
+  if (abfd->sections)
+    bfd_map_over_sections (abfd,
+                          unrecord_section_via_map_over_sections,
+                          NULL);
 
   return _bfd_elf_close_and_cleanup (abfd);
 }
 
+static bfd_boolean
+elf32_arm_bfd_free_cached_info (bfd * abfd)
+{
+  if (abfd->sections)
+    bfd_map_over_sections (abfd,
+                          unrecord_section_via_map_over_sections,
+                          NULL);
+
+  return _bfd_free_cached_info (abfd);
+}
+
 /* Display STT_ARM_TFUNC symbols as functions.  */
 
 static void
@@ -7653,6 +9175,19 @@ elf32_arm_swap_symbol_out (bfd *abfd,
     {
       newsym = *src;
       newsym.st_info = ELF_ST_INFO (ELF_ST_BIND (src->st_info), STT_FUNC);
+      if (newsym.st_shndx != SHN_UNDEF)
+        {
+          /* Do this only for defined symbols. At link type, the static
+             linker will simulate the work of dynamic linker of resolving
+             symbols and will carry over the thumbness of found symbols to
+             the output symbol table. It's not clear how it happens, but
+             the thumbness of underfined symbols can well be different at
+             runtime, and writing '1' for them will be confusing for users
+             and possibly for dynamic linker itself.
+          */
+          newsym.st_value |= 1;
+        }
+
       newsym.st_value |= 1;
       
       src = &newsym;
@@ -7698,7 +9233,8 @@ elf32_arm_modify_segment_map (bfd *abfd,
 /* We may add a PT_ARM_EXIDX program header.  */
 
 static int
-elf32_arm_additional_program_headers (bfd *abfd)
+elf32_arm_additional_program_headers (bfd *abfd,
+                                     struct bfd_link_info *info ATTRIBUTE_UNUSED)
 {
   asection *sec;
 
@@ -7746,6 +9282,7 @@ const struct elf_size_info elf32_arm_size_info = {
 #define ELF_MAXPAGESIZE                        0x8000
 #endif
 #define ELF_MINPAGESIZE                        0x1000
+#define ELF_COMMONPAGESIZE             0x1000
 
 #define bfd_elf32_mkobject                     elf32_arm_mkobject
 
@@ -7760,6 +9297,7 @@ const struct elf_size_info elf32_arm_size_info = {
 #define bfd_elf32_new_section_hook             elf32_arm_new_section_hook
 #define bfd_elf32_bfd_is_target_special_symbol elf32_arm_is_target_special_symbol
 #define bfd_elf32_close_and_cleanup             elf32_arm_close_and_cleanup
+#define bfd_elf32_bfd_free_cached_info          elf32_arm_bfd_free_cached_info
 #define bfd_elf32_bfd_final_link               elf32_arm_bfd_final_link
 
 #define elf_backend_get_symbol_type             elf32_arm_get_symbol_type
@@ -7787,6 +9325,8 @@ const struct elf_size_info elf32_arm_size_info = {
 #define elf_backend_modify_segment_map         elf32_arm_modify_segment_map
 #define elf_backend_additional_program_headers \
   elf32_arm_additional_program_headers
+#define elf_backend_output_arch_local_syms \
+  elf32_arm_output_arch_local_syms
 
 #define elf_backend_can_refcount    1
 #define elf_backend_can_gc_sections 1
@@ -7824,27 +9364,48 @@ elf32_arm_vxworks_link_hash_table_create (bfd *abfd)
   if (ret)
     {
       struct elf32_arm_link_hash_table *htab
-       = (struct elf32_arm_link_hash_table *)ret;
+       = (struct elf32_arm_link_hash_table *) ret;
       htab->use_rel = 0;
+      htab->vxworks_p = 1;
     }
   return ret;
 }     
 
+static void
+elf32_arm_vxworks_final_write_processing (bfd *abfd, bfd_boolean linker)
+{
+  elf32_arm_final_write_processing (abfd, linker);
+  elf_vxworks_final_write_processing (abfd, linker);
+}
+
 #undef elf32_bed
 #define elf32_bed elf32_arm_vxworks_bed
 
 #undef bfd_elf32_bfd_link_hash_table_create
 #define bfd_elf32_bfd_link_hash_table_create \
   elf32_arm_vxworks_link_hash_table_create
+#undef elf_backend_add_symbol_hook
+#define elf_backend_add_symbol_hook \
+  elf_vxworks_add_symbol_hook
+#undef elf_backend_final_write_processing
+#define elf_backend_final_write_processing \
+  elf32_arm_vxworks_final_write_processing
+#undef elf_backend_emit_relocs
+#define elf_backend_emit_relocs \
+  elf_vxworks_emit_relocs
 
 #undef elf_backend_may_use_rel_p
-#define elf_backend_may_use_rel_p   0
+#define elf_backend_may_use_rel_p      0
 #undef elf_backend_may_use_rela_p
-#define elf_backend_may_use_rela_p  1
+#define elf_backend_may_use_rela_p     1
 #undef elf_backend_default_use_rela_p
-#define elf_backend_default_use_rela_p 1
+#define elf_backend_default_use_rela_p 1
 #undef elf_backend_rela_normal
-#define elf_backend_rela_normal     1
+#define elf_backend_rela_normal                1
+#undef elf_backend_want_plt_sym
+#define elf_backend_want_plt_sym       1
+#undef ELF_MAXPAGESIZE
+#define ELF_MAXPAGESIZE                        0x1000
 
 #include "elf32-target.h"
 
@@ -7935,9 +9496,16 @@ elf32_arm_symbian_modify_segment_map (bfd *abfd,
   dynsec = bfd_get_section_by_name (abfd, ".dynamic");
   if (dynsec)
     {
-      m = _bfd_elf_make_dynamic_segment (abfd, dynsec);
-      m->next = elf_tdata (abfd)->segment_map;
-      elf_tdata (abfd)->segment_map = m;
+      for (m = elf_tdata (abfd)->segment_map; m != NULL; m = m->next)
+       if (m->p_type == PT_DYNAMIC)
+         break;
+
+      if (m == NULL)
+       {
+         m = _bfd_elf_make_dynamic_segment (abfd, dynsec);
+         m->next = elf_tdata (abfd)->segment_map;
+         elf_tdata (abfd)->segment_map = m;
+       }
     }
 
   /* Also call the generic arm routine.  */
@@ -7956,6 +9524,7 @@ elf32_arm_symbian_modify_segment_map (bfd *abfd,
 #undef bfd_elf32_bfd_link_hash_table_create
 #define bfd_elf32_bfd_link_hash_table_create \
   elf32_arm_symbian_link_hash_table_create
+#undef elf_backend_add_symbol_hook
 
 #undef elf_backend_special_sections
 #define elf_backend_special_sections elf32_arm_symbian_special_sections
@@ -7963,6 +9532,10 @@ elf32_arm_symbian_modify_segment_map (bfd *abfd,
 #undef elf_backend_begin_write_processing
 #define elf_backend_begin_write_processing \
     elf32_arm_symbian_begin_write_processing
+#undef elf_backend_final_write_processing
+#define elf_backend_final_write_processing \
+  elf32_arm_final_write_processing
+#undef elf_backend_emit_relocs
 
 #undef elf_backend_modify_segment_map
 #define elf_backend_modify_segment_map elf32_arm_symbian_modify_segment_map
@@ -7976,12 +9549,16 @@ elf32_arm_symbian_modify_segment_map (bfd *abfd,
 #define elf_backend_want_got_plt 0
 
 #undef elf_backend_may_use_rel_p
-#define elf_backend_may_use_rel_p   1
+#define elf_backend_may_use_rel_p      1
 #undef elf_backend_may_use_rela_p
-#define elf_backend_may_use_rela_p  0
+#define elf_backend_may_use_rela_p     0
 #undef elf_backend_default_use_rela_p
-#define elf_backend_default_use_rela_p 0
+#define elf_backend_default_use_rela_p 0
 #undef elf_backend_rela_normal
-#define elf_backend_rela_normal     0
+#define elf_backend_rela_normal                0
+#undef elf_backend_want_plt_sym
+#define elf_backend_want_plt_sym       0
+#undef ELF_MAXPAGESIZE
+#define ELF_MAXPAGESIZE                        0x8000
 
 #include "elf32-target.h"
This page took 0.066523 seconds and 4 git commands to generate.