2002-02-10 Daniel Jacobowitz <drow@mvista.com>
[deliverable/binutils-gdb.git] / bfd / elf32-sh.c
index 0e6be9b0151057fa0047c3384b117d5c3df28bbe..d6033456b2aff14ac86866817c1adb3296d9988e 100644 (file)
@@ -1,5 +1,5 @@
 /* Hitachi SH specific support for 32-bit ELF
-   Copyright 1996, 1997, 1998, 1999, 2000, 2001
+   Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002
    Free Software Foundation, Inc.
    Contributed by Ian Lance Taylor, Cygnus Support.
 
@@ -72,6 +72,19 @@ static boolean sh_elf_finish_dynamic_symbol
           Elf_Internal_Sym *));
 static boolean sh_elf_finish_dynamic_sections
   PARAMS ((bfd *, struct bfd_link_info *));
+static bfd_reloc_status_type sh_elf_reloc_loop
+  PARAMS ((int, bfd *, asection *, bfd_byte *, bfd_vma, asection *,
+          bfd_vma, bfd_vma));
+static boolean sh_elf_create_dynamic_sections
+  PARAMS ((bfd *, struct bfd_link_info *));
+static asection * sh_elf_gc_mark_hook
+  PARAMS ((bfd *, struct bfd_link_info *, Elf_Internal_Rela *,
+          struct elf_link_hash_entry *, Elf_Internal_Sym *));
+static boolean sh_elf_gc_sweep_hook
+  PARAMS ((bfd *, struct bfd_link_info *, asection *,
+          const Elf_Internal_Rela *));
+static enum elf_reloc_type_class sh_elf_reloc_type_class
+  PARAMS ((const Elf_Internal_Rela *));
 
 /* The name of the dynamic interpreter.  This is put in the .interp
    section.  */
@@ -121,8 +134,8 @@ static reloc_howto_type sh_elf_howto_table[] =
         complain_overflow_signed, /* complain_on_overflow */
         sh_elf_ignore_reloc,   /* special_function */
         "R_SH_REL32",          /* name */
-        false,                 /* partial_inplace */
-        0,                     /* src_mask */
+        true,                  /* partial_inplace */
+        0xffffffff,            /* src_mask */
         0xffffffff,            /* dst_mask */
         true),                 /* pcrel_offset */
 
@@ -479,6 +492,114 @@ static reloc_howto_type sh_elf_howto_table[] =
   EMPTY_HOWTO (42),
   EMPTY_HOWTO (43),
   EMPTY_HOWTO (44),
+
+#ifdef INCLUDE_SHMEDIA
+  /* Used in SHLLI.L and SHLRI.L.  */
+  HOWTO (R_SH_DIR5U,           /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        5,                     /* bitsize */
+        false,                 /* pc_relative */
+        10,                    /* bitpos */
+        complain_overflow_unsigned, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_SH_DIR5U",          /* name */
+        false,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0xfc00,                /* dst_mask */
+        false),                /* pcrel_offset */
+
+  /* Used in SHARI, SHLLI et al.  */
+  HOWTO (R_SH_DIR6U,           /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        6,                     /* bitsize */
+        false,                 /* pc_relative */
+        10,                    /* bitpos */
+        complain_overflow_unsigned, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_SH_DIR6U",          /* name */
+        false,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0xfc00,                /* dst_mask */
+        false),                /* pcrel_offset */
+
+  /* Used in BxxI, LDHI.L et al.  */
+  HOWTO (R_SH_DIR6S,           /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        6,                     /* bitsize */
+        false,                 /* pc_relative */
+        10,                    /* bitpos */
+        complain_overflow_signed, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_SH_DIR6S",          /* name */
+        false,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0xfc00,                /* dst_mask */
+        false),                /* pcrel_offset */
+
+  /* Used in ADDI, ANDI et al.  */
+  HOWTO (R_SH_DIR10S,          /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        10,                    /* bitsize */
+        false,                 /* pc_relative */
+        10,                    /* bitpos */
+        complain_overflow_signed, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_SH_DIR10S",         /* name */
+        false,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0xffc00,               /* dst_mask */
+        false),                /* pcrel_offset */
+
+  /* Used in LD.UW, ST.W et al.  */
+  HOWTO (R_SH_DIR10SW, /* type */
+        1,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        11,                    /* bitsize */
+        false,                 /* pc_relative */
+        10,                    /* bitpos */
+        complain_overflow_signed, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_SH_DIR10SW",        /* name */
+        false,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0xffc00,               /* dst_mask */
+        false),                /* pcrel_offset */
+
+  /* Used in LD.L, FLD.S et al.  */
+  HOWTO (R_SH_DIR10SL, /* type */
+        2,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        12,                    /* bitsize */
+        false,                 /* pc_relative */
+        10,                    /* bitpos */
+        complain_overflow_signed, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_SH_DIR10SL",        /* name */
+        false,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0xffc00,               /* dst_mask */
+        false),                /* pcrel_offset */
+
+  /* Used in FLD.D, FST.P et al.  */
+  HOWTO (R_SH_DIR10SQ, /* type */
+        3,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        13,                    /* bitsize */
+        false,                 /* pc_relative */
+        10,                    /* bitpos */
+        complain_overflow_signed, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_SH_DIR10SQ",        /* name */
+        false,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0xffc00,               /* dst_mask */
+        false),                /* pcrel_offset */
+
+#else
   EMPTY_HOWTO (45),
   EMPTY_HOWTO (46),
   EMPTY_HOWTO (47),
@@ -486,6 +607,8 @@ static reloc_howto_type sh_elf_howto_table[] =
   EMPTY_HOWTO (49),
   EMPTY_HOWTO (50),
   EMPTY_HOWTO (51),
+#endif
+
   EMPTY_HOWTO (52),
   EMPTY_HOWTO (53),
   EMPTY_HOWTO (54),
@@ -707,6 +830,704 @@ static reloc_howto_type sh_elf_howto_table[] =
         0xffffffff,            /* dst_mask */
         true),                 /* pcrel_offset */
 
+  HOWTO (R_SH_GOTPLT32,                /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        32,                    /* bitsize */
+        false,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_bitfield, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* */
+        "R_SH_GOTPLT32",       /* name */
+        false,                 /* partial_inplace */
+        0xffffffff,            /* src_mask */
+        0xffffffff,            /* dst_mask */
+        false),                /* pcrel_offset */
+
+#ifdef INCLUDE_SHMEDIA
+  /* Used in MOVI and SHORI (x & 65536).  */
+  HOWTO (R_SH_GOT_LOW16,       /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        64,                    /* bitsize */
+        false,                 /* pc_relative */
+        10,                    /* bitpos */
+        complain_overflow_dont, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_SH_GOT_LOW16",      /* name */
+        false,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0x3fffc00,             /* dst_mask */
+        false),                /* pcrel_offset */
+
+  /* Used in MOVI and SHORI ((x >> 16) & 65536).  */
+  HOWTO (R_SH_GOT_MEDLOW16,    /* type */
+        16,                    /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        64,                    /* bitsize */
+        false,                 /* pc_relative */
+        10,                    /* bitpos */
+        complain_overflow_dont, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_SH_GOT_MEDLOW16",   /* name */
+        false,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0x3fffc00,             /* dst_mask */
+        false),                /* pcrel_offset */
+
+  /* Used in MOVI and SHORI ((x >> 32) & 65536).  */
+  HOWTO (R_SH_GOT_MEDHI16,     /* type */
+        32,                    /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        64,                    /* bitsize */
+        false,                 /* pc_relative */
+        10,                    /* bitpos */
+        complain_overflow_dont, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_SH_GOT_MEDHI16",    /* name */
+        false,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0x3fffc00,             /* dst_mask */
+        false),                /* pcrel_offset */
+
+  /* Used in MOVI and SHORI ((x >> 48) & 65536).  */
+  HOWTO (R_SH_GOT_HI16,                /* type */
+        48,                    /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        64,                    /* bitsize */
+        false,                 /* pc_relative */
+        10,                    /* bitpos */
+        complain_overflow_dont, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_SH_GOT_HI16",       /* name */
+        false,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0x3fffc00,             /* dst_mask */
+        false),                /* pcrel_offset */
+
+  /* Used in MOVI and SHORI (x & 65536).  */
+  HOWTO (R_SH_GOTPLT_LOW16,    /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        64,                    /* bitsize */
+        false,                 /* pc_relative */
+        10,                    /* bitpos */
+        complain_overflow_dont, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_SH_GOTPLT_LOW16",   /* name */
+        false,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0x3fffc00,             /* dst_mask */
+        false),                /* pcrel_offset */
+
+  /* Used in MOVI and SHORI ((x >> 16) & 65536).  */
+  HOWTO (R_SH_GOTPLT_MEDLOW16, /* type */
+        16,                    /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        64,                    /* bitsize */
+        false,                 /* pc_relative */
+        10,                    /* bitpos */
+        complain_overflow_dont, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_SH_GOTPLT_MEDLOW16", /* name */
+        false,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0x3fffc00,             /* dst_mask */
+        false),                /* pcrel_offset */
+
+  /* Used in MOVI and SHORI ((x >> 32) & 65536).  */
+  HOWTO (R_SH_GOTPLT_MEDHI16,  /* type */
+        32,                    /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        64,                    /* bitsize */
+        false,                 /* pc_relative */
+        10,                    /* bitpos */
+        complain_overflow_dont, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_SH_GOTPLT_MEDHI16", /* name */
+        false,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0x3fffc00,             /* dst_mask */
+        false),                /* pcrel_offset */
+
+  /* Used in MOVI and SHORI ((x >> 48) & 65536).  */
+  HOWTO (R_SH_GOTPLT_HI16,     /* type */
+        48,                    /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        64,                    /* bitsize */
+        false,                 /* pc_relative */
+        10,                    /* bitpos */
+        complain_overflow_dont, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_SH_GOTPLT_HI16",    /* name */
+        false,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0x3fffc00,             /* dst_mask */
+        false),                /* pcrel_offset */
+
+  /* Used in MOVI and SHORI (x & 65536).  */
+  HOWTO (R_SH_PLT_LOW16,       /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        64,                    /* bitsize */
+        true,                  /* pc_relative */
+        10,                    /* bitpos */
+        complain_overflow_dont, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_SH_PLT_LOW16",      /* name */
+        false,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0x3fffc00,             /* dst_mask */
+        true),                 /* pcrel_offset */
+
+  /* Used in MOVI and SHORI ((x >> 16) & 65536).  */
+  HOWTO (R_SH_PLT_MEDLOW16,    /* type */
+        16,                    /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        64,                    /* bitsize */
+        true,                  /* pc_relative */
+        10,                    /* bitpos */
+        complain_overflow_dont, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_SH_PLT_MEDLOW16",   /* name */
+        false,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0x3fffc00,             /* dst_mask */
+        true),                 /* pcrel_offset */
+
+  /* Used in MOVI and SHORI ((x >> 32) & 65536).  */
+  HOWTO (R_SH_PLT_MEDHI16,     /* type */
+        32,                    /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        64,                    /* bitsize */
+        true,                  /* pc_relative */
+        10,                    /* bitpos */
+        complain_overflow_dont, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_SH_PLT_MEDHI16",    /* name */
+        false,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0x3fffc00,             /* dst_mask */
+        true),                 /* pcrel_offset */
+
+  /* Used in MOVI and SHORI ((x >> 48) & 65536).  */
+  HOWTO (R_SH_PLT_HI16,                /* type */
+        48,                    /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        64,                    /* bitsize */
+        true,                  /* pc_relative */
+        10,                    /* bitpos */
+        complain_overflow_dont, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_SH_PLT_HI16",       /* name */
+        false,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0x3fffc00,             /* dst_mask */
+        true),                 /* pcrel_offset */
+
+  /* Used in MOVI and SHORI (x & 65536).  */
+  HOWTO (R_SH_GOTOFF_LOW16,    /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        64,                    /* bitsize */
+        false,                 /* pc_relative */
+        10,                    /* bitpos */
+        complain_overflow_dont, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_SH_GOTOFF_LOW16",   /* name */
+        false,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0x3fffc00,             /* dst_mask */
+        false),                /* pcrel_offset */
+
+  /* Used in MOVI and SHORI ((x >> 16) & 65536).  */
+  HOWTO (R_SH_GOTOFF_MEDLOW16, /* type */
+        16,                    /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        64,                    /* bitsize */
+        false,                 /* pc_relative */
+        10,                    /* bitpos */
+        complain_overflow_dont, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_SH_GOTOFF_MEDLOW16", /* name */
+        false,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0x3fffc00,             /* dst_mask */
+        false),                /* pcrel_offset */
+
+  /* Used in MOVI and SHORI ((x >> 32) & 65536).  */
+  HOWTO (R_SH_GOTOFF_MEDHI16,  /* type */
+        32,                    /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        64,                    /* bitsize */
+        false,                 /* pc_relative */
+        10,                    /* bitpos */
+        complain_overflow_dont, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_SH_GOTOFF_MEDHI16", /* name */
+        false,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0x3fffc00,             /* dst_mask */
+        false),                /* pcrel_offset */
+
+  /* Used in MOVI and SHORI ((x >> 48) & 65536).  */
+  HOWTO (R_SH_GOTOFF_HI16,     /* type */
+        48,                    /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        64,                    /* bitsize */
+        false,                 /* pc_relative */
+        10,                    /* bitpos */
+        complain_overflow_dont, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_SH_GOTOFF_HI16",    /* name */
+        false,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0x3fffc00,             /* dst_mask */
+        false),                /* pcrel_offset */
+
+  /* Used in MOVI and SHORI (x & 65536).  */
+  HOWTO (R_SH_GOTPC_LOW16,     /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        64,                    /* bitsize */
+        true,                  /* pc_relative */
+        10,                    /* bitpos */
+        complain_overflow_dont, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_SH_GOTPC_LOW16",    /* name */
+        false,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0x3fffc00,             /* dst_mask */
+        true),                 /* pcrel_offset */
+
+  /* Used in MOVI and SHORI ((x >> 16) & 65536).  */
+  HOWTO (R_SH_GOTPC_MEDLOW16,  /* type */
+        16,                    /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        64,                    /* bitsize */
+        true,                  /* pc_relative */
+        10,                    /* bitpos */
+        complain_overflow_dont, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_SH_GOTPC_MEDLOW16", /* name */
+        false,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0x3fffc00,             /* dst_mask */
+        true),                 /* pcrel_offset */
+
+  /* Used in MOVI and SHORI ((x >> 32) & 65536).  */
+  HOWTO (R_SH_GOTPC_MEDHI16,   /* type */
+        32,                    /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        64,                    /* bitsize */
+        true,                  /* pc_relative */
+        10,                    /* bitpos */
+        complain_overflow_dont, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_SH_GOTPC_MEDHI16",  /* name */
+        false,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0x3fffc00,             /* dst_mask */
+        true),                 /* pcrel_offset */
+
+  /* Used in MOVI and SHORI ((x >> 48) & 65536).  */
+  HOWTO (R_SH_GOTPC_HI16,      /* type */
+        48,                    /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        64,                    /* bitsize */
+        true,                  /* pc_relative */
+        10,                    /* bitpos */
+        complain_overflow_dont, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_SH_GOTPC_HI16",     /* name */
+        false,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0x3fffc00,             /* dst_mask */
+        true),                 /* pcrel_offset */
+
+  /* Used in LD.L, FLD.S et al.  */
+  HOWTO (R_SH_GOT10BY4,                /* type */
+        2,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        12,                    /* bitsize */
+        false,                 /* pc_relative */
+        10,                    /* bitpos */
+        complain_overflow_signed, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_SH_GOT10BY4",       /* name */
+        false,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0xffc00,               /* dst_mask */
+        false),                /* pcrel_offset */
+
+  /* Used in LD.L, FLD.S et al.  */
+  HOWTO (R_SH_GOTPLT10BY4,     /* type */
+        2,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        12,                    /* bitsize */
+        false,                 /* pc_relative */
+        10,                    /* bitpos */
+        complain_overflow_signed, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_SH_GOTPLT10BY4",    /* name */
+        false,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0xffc00,               /* dst_mask */
+        false),                /* pcrel_offset */
+
+  /* Used in FLD.D, FST.P et al.  */
+  HOWTO (R_SH_GOT10BY8,                /* type */
+        3,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        13,                    /* bitsize */
+        false,                 /* pc_relative */
+        10,                    /* bitpos */
+        complain_overflow_signed, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_SH_GOT10BY8",       /* name */
+        false,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0xffc00,               /* dst_mask */
+        false),                /* pcrel_offset */
+
+  /* Used in FLD.D, FST.P et al.  */
+  HOWTO (R_SH_GOTPLT10BY8,     /* type */
+        3,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        13,                    /* bitsize */
+        false,                 /* pc_relative */
+        10,                    /* bitpos */
+        complain_overflow_signed, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_SH_GOTPLT10BY8",    /* name */
+        false,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0xffc00,               /* dst_mask */
+        false),                /* pcrel_offset */
+
+  HOWTO (R_SH_COPY64,          /* type */
+        0,                     /* rightshift */
+        4,                     /* size (0 = byte, 1 = short, 2 = long) */
+        64,                    /* bitsize */
+        false,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_SH_COPY64",         /* name */
+        false,                 /* partial_inplace */
+        0,                     /* src_mask */
+        ((bfd_vma) 0) - 1,     /* dst_mask */
+        false),                /* pcrel_offset */
+
+  HOWTO (R_SH_GLOB_DAT64,      /* type */
+        0,                     /* rightshift */
+        4,                     /* size (0 = byte, 1 = short, 2 = long) */
+        64,                    /* bitsize */
+        false,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_SH_GLOB_DAT64",     /* name */
+        false,                 /* partial_inplace */
+        0,                     /* src_mask */
+        ((bfd_vma) 0) - 1,     /* dst_mask */
+        false),                /* pcrel_offset */
+
+  HOWTO (R_SH_JMP_SLOT64,      /* type */
+        0,                     /* rightshift */
+        4,                     /* size (0 = byte, 1 = short, 2 = long) */
+        64,                    /* bitsize */
+        false,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_SH_JMP_SLOT64",     /* name */
+        false,                 /* partial_inplace */
+        0,                     /* src_mask */
+        ((bfd_vma) 0) - 1,     /* dst_mask */
+        false),                /* pcrel_offset */
+
+  HOWTO (R_SH_RELATIVE64,      /* type */
+        0,                     /* rightshift */
+        4,                     /* size (0 = byte, 1 = short, 2 = long) */
+        64,                    /* bitsize */
+        false,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_SH_RELATIVE64",     /* name */
+        false,                 /* partial_inplace */
+        0,                     /* src_mask */
+        ((bfd_vma) 0) - 1,     /* dst_mask */
+        false),                /* pcrel_offset */
+
+  EMPTY_HOWTO (197),
+  EMPTY_HOWTO (198),
+  EMPTY_HOWTO (199),
+  EMPTY_HOWTO (200),
+  EMPTY_HOWTO (201),
+  EMPTY_HOWTO (202),
+  EMPTY_HOWTO (203),
+  EMPTY_HOWTO (204),
+  EMPTY_HOWTO (205),
+  EMPTY_HOWTO (206),
+  EMPTY_HOWTO (207),
+  EMPTY_HOWTO (208),
+  EMPTY_HOWTO (209),
+  EMPTY_HOWTO (210),
+  EMPTY_HOWTO (211),
+  EMPTY_HOWTO (212),
+  EMPTY_HOWTO (213),
+  EMPTY_HOWTO (214),
+  EMPTY_HOWTO (215),
+  EMPTY_HOWTO (216),
+  EMPTY_HOWTO (217),
+  EMPTY_HOWTO (218),
+  EMPTY_HOWTO (219),
+  EMPTY_HOWTO (220),
+  EMPTY_HOWTO (221),
+  EMPTY_HOWTO (222),
+  EMPTY_HOWTO (223),
+  EMPTY_HOWTO (224),
+  EMPTY_HOWTO (225),
+  EMPTY_HOWTO (226),
+  EMPTY_HOWTO (227),
+  EMPTY_HOWTO (228),
+  EMPTY_HOWTO (229),
+  EMPTY_HOWTO (230),
+  EMPTY_HOWTO (231),
+  EMPTY_HOWTO (232),
+  EMPTY_HOWTO (233),
+  EMPTY_HOWTO (234),
+  EMPTY_HOWTO (235),
+  EMPTY_HOWTO (236),
+  EMPTY_HOWTO (237),
+  EMPTY_HOWTO (238),
+  EMPTY_HOWTO (239),
+  EMPTY_HOWTO (240),
+  EMPTY_HOWTO (241),
+
+  /* Relocations for SHmedia code.  None of these are partial_inplace or
+     use the field being relocated (except R_SH_PT_16).  */
+
+  /* The assembler will generate this reloc before a block of SHmedia
+     instructions.  A section should be processed as assuming it contains
+     data, unless this reloc is seen.  Note that a block of SHcompact
+     instructions are instead preceded by R_SH_CODE.
+     This is currently not implemented, but should be used for SHmedia
+     linker relaxation.  */
+  HOWTO (R_SH_SHMEDIA_CODE,    /* type */
+        0,                     /* rightshift */
+        1,                     /* size (0 = byte, 1 = short, 2 = long) */
+        0,                     /* bitsize */
+        false,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_unsigned, /* complain_on_overflow */
+        sh_elf_ignore_reloc,   /* special_function */
+        "R_SH_SHMEDIA_CODE",   /* name */
+        false,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0,                     /* dst_mask */
+        false),                /* pcrel_offset */
+
+  /* The assembler will generate this reloc at a PTA or PTB instruction,
+     and the linker checks the right type of target, or changes a PTA to a
+     PTB, if the original insn was PT.  */
+  HOWTO (R_SH_PT_16,           /* type */
+        2,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        18,                    /* bitsize */
+        true,                  /* pc_relative */
+        10,                    /* bitpos */
+        complain_overflow_signed, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_SH_PT_16",          /* name */
+        false,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0x3fffc00,             /* dst_mask */
+        true),                 /* pcrel_offset */
+
+  /* Used in unexpanded MOVI.  */
+  HOWTO (R_SH_IMMS16,          /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        16,                    /* bitsize */
+        false,                 /* pc_relative */
+        10,                    /* bitpos */
+        complain_overflow_signed, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_SH_IMMS16",         /* name */
+        false,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0x3fffc00,             /* dst_mask */
+        false),                /* pcrel_offset */
+
+  /* Used in SHORI.  */
+  HOWTO (R_SH_IMMU16,          /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        16,                    /* bitsize */
+        false,                 /* pc_relative */
+        10,                    /* bitpos */
+        complain_overflow_unsigned, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_SH_IMMU16",         /* name */
+        false,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0x3fffc00,             /* dst_mask */
+        false),                /* pcrel_offset */
+
+  /* Used in MOVI and SHORI (x & 65536).  */
+  HOWTO (R_SH_IMM_LOW16,       /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        64,                    /* bitsize */
+        false,                 /* pc_relative */
+        10,                    /* bitpos */
+        complain_overflow_dont, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_SH_IMM_LOW16",      /* name */
+        false,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0x3fffc00,             /* dst_mask */
+        false),                /* pcrel_offset */
+
+  /* Used in MOVI and SHORI ((x - $) & 65536).  */
+  HOWTO (R_SH_IMM_LOW16_PCREL, /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        64,                    /* bitsize */
+        true,                  /* pc_relative */
+        10,                    /* bitpos */
+        complain_overflow_dont, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_SH_IMM_LOW16_PCREL", /* name */
+        false,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0x3fffc00,             /* dst_mask */
+        true),                 /* pcrel_offset */
+
+  /* Used in MOVI and SHORI ((x >> 16) & 65536).  */
+  HOWTO (R_SH_IMM_MEDLOW16,    /* type */
+        16,                    /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        64,                    /* bitsize */
+        false,                 /* pc_relative */
+        10,                    /* bitpos */
+        complain_overflow_dont, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_SH_IMM_MEDLOW16",   /* name */
+        false,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0x3fffc00,             /* dst_mask */
+        false),                /* pcrel_offset */
+
+  /* Used in MOVI and SHORI (((x - $) >> 16) & 65536).  */
+  HOWTO (R_SH_IMM_MEDLOW16_PCREL, /* type */
+        16,                    /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        64,                    /* bitsize */
+        true,                  /* pc_relative */
+        10,                    /* bitpos */
+        complain_overflow_dont, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_SH_IMM_MEDLOW16_PCREL", /* name */
+        false,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0x3fffc00,             /* dst_mask */
+        true),                 /* pcrel_offset */
+
+  /* Used in MOVI and SHORI ((x >> 32) & 65536).  */
+  HOWTO (R_SH_IMM_MEDHI16,     /* type */
+        32,                    /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        64,                    /* bitsize */
+        false,                 /* pc_relative */
+        10,                    /* bitpos */
+        complain_overflow_dont, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_SH_IMM_MEDHI16",    /* name */
+        false,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0x3fffc00,             /* dst_mask */
+        false),                /* pcrel_offset */
+
+  /* Used in MOVI and SHORI (((x - $) >> 32) & 65536).  */
+  HOWTO (R_SH_IMM_MEDHI16_PCREL, /* type */
+        32,                    /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        64,                    /* bitsize */
+        true,                  /* pc_relative */
+        10,                    /* bitpos */
+        complain_overflow_dont, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_SH_IMM_MEDHI16_PCREL", /* name */
+        false,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0x3fffc00,             /* dst_mask */
+        true),                 /* pcrel_offset */
+
+  /* Used in MOVI and SHORI ((x >> 48) & 65536).  */
+  HOWTO (R_SH_IMM_HI16,                /* type */
+        48,                    /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        64,                    /* bitsize */
+        false,                 /* pc_relative */
+        10,                    /* bitpos */
+        complain_overflow_dont, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_SH_IMM_HI16",       /* name */
+        false,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0x3fffc00,             /* dst_mask */
+        false),                /* pcrel_offset */
+
+  /* Used in MOVI and SHORI (((x - $) >> 48) & 65536).  */
+  HOWTO (R_SH_IMM_HI16_PCREL,  /* type */
+        48,                    /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        64,                    /* bitsize */
+        true,                  /* pc_relative */
+        10,                    /* bitpos */
+        complain_overflow_dont, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_SH_IMM_HI16_PCREL", /* name */
+        false,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0x3fffc00,             /* dst_mask */
+        true),                 /* pcrel_offset */
+
+  /* For the .uaquad pseudo.  */
+  HOWTO (R_SH_64,              /* type */
+        0,                     /* rightshift */
+        4,                     /* size (0 = byte, 1 = short, 2 = long) */
+        64,                    /* bitsize */
+        false,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_SH_64",             /* name */
+        false,                 /* partial_inplace */
+        0,                     /* src_mask */
+        ((bfd_vma) 0) - 1,     /* dst_mask */
+        false),                /* pcrel_offset */
+
+  /* For the .uaquad pseudo, (x - $).  */
+  HOWTO (R_SH_64_PCREL,                /* type */
+        48,                    /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        64,                    /* bitsize */
+        true,                  /* pc_relative */
+        10,                    /* bitpos */
+        complain_overflow_dont, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_SH_64_PCREL",       /* name */
+        false,                 /* partial_inplace */
+        0,                     /* src_mask */
+        ((bfd_vma) 0) - 1,     /* dst_mask */
+        true),                 /* pcrel_offset */
+
+#endif
 };
 
 static bfd_reloc_status_type
@@ -754,10 +1575,10 @@ sh_elf_reloc_loop (r_type, input_bfd, input_section, contents, addr,
        contents = elf_section_data (symbol_section)->this_hdr.contents;
       else
        {
-         free_contents = contents
-           = (bfd_byte *) bfd_malloc (symbol_section->_raw_size);
+         contents = (bfd_byte *) bfd_malloc (symbol_section->_raw_size);
          if (contents == NULL)
            return bfd_reloc_outofrange;
+         free_contents = contents;
          if (! bfd_get_section_contents (input_bfd, symbol_section, contents,
                                          (file_ptr) 0,
                                          symbol_section->_raw_size))
@@ -812,7 +1633,7 @@ sh_elf_reloc_loop (r_type, input_bfd, input_section, contents, addr,
     return bfd_reloc_overflow;
 
   x = (insn & ~0xff) | (x & 0xff);
-  bfd_put_16 (input_bfd, x, contents + addr);
+  bfd_put_16 (input_bfd, (bfd_vma) x, contents + addr);
 
   return bfd_reloc_ok;
 }
@@ -867,7 +1688,7 @@ sh_elf_reloc (abfd, reloc_entry, symbol_in, data, input_section, output_bfd,
     case R_SH_DIR32:
       insn = bfd_get_32 (abfd, hit_data);
       insn += sym_value + reloc_entry->addend;
-      bfd_put_32 (abfd, insn, hit_data);
+      bfd_put_32 (abfd, (bfd_vma) insn, hit_data);
       break;
     case R_SH_IND12W:
       insn = bfd_get_16 (abfd, hit_data);
@@ -880,7 +1701,7 @@ sh_elf_reloc (abfd, reloc_entry, symbol_in, data, input_section, output_bfd,
       if (insn & 0x800)
        sym_value -= 0x1000;
       insn = (insn & 0xf000) | (sym_value & 0xfff);
-      bfd_put_16 (abfd, insn, hit_data);
+      bfd_put_16 (abfd, (bfd_vma) insn, hit_data);
       if (sym_value < (bfd_vma) -0x1000 || sym_value >= 0x1000)
        return bfd_reloc_overflow;
       break;
@@ -952,6 +1773,58 @@ static const struct elf_reloc_map sh_reloc_map[] =
   { BFD_RELOC_SH_RELATIVE, R_SH_RELATIVE },
   { BFD_RELOC_32_GOTOFF, R_SH_GOTOFF },
   { BFD_RELOC_SH_GOTPC, R_SH_GOTPC },
+  { BFD_RELOC_SH_GOTPLT32, R_SH_GOTPLT32 },
+#ifdef INCLUDE_SHMEDIA
+  { BFD_RELOC_SH_GOT_LOW16, R_SH_GOT_LOW16 },
+  { BFD_RELOC_SH_GOT_MEDLOW16, R_SH_GOT_MEDLOW16 },
+  { BFD_RELOC_SH_GOT_MEDHI16, R_SH_GOT_MEDHI16 },
+  { BFD_RELOC_SH_GOT_HI16, R_SH_GOT_HI16 },
+  { BFD_RELOC_SH_GOTPLT_LOW16, R_SH_GOTPLT_LOW16 },
+  { BFD_RELOC_SH_GOTPLT_MEDLOW16, R_SH_GOTPLT_MEDLOW16 },
+  { BFD_RELOC_SH_GOTPLT_MEDHI16, R_SH_GOTPLT_MEDHI16 },
+  { BFD_RELOC_SH_GOTPLT_HI16, R_SH_GOTPLT_HI16 },
+  { BFD_RELOC_SH_PLT_LOW16, R_SH_PLT_LOW16 },
+  { BFD_RELOC_SH_PLT_MEDLOW16, R_SH_PLT_MEDLOW16 },
+  { BFD_RELOC_SH_PLT_MEDHI16, R_SH_PLT_MEDHI16 },
+  { BFD_RELOC_SH_PLT_HI16, R_SH_PLT_HI16 },
+  { BFD_RELOC_SH_GOTOFF_LOW16, R_SH_GOTOFF_LOW16 },
+  { BFD_RELOC_SH_GOTOFF_MEDLOW16, R_SH_GOTOFF_MEDLOW16 },
+  { BFD_RELOC_SH_GOTOFF_MEDHI16, R_SH_GOTOFF_MEDHI16 },
+  { BFD_RELOC_SH_GOTOFF_HI16, R_SH_GOTOFF_HI16 },
+  { BFD_RELOC_SH_GOTPC_LOW16, R_SH_GOTPC_LOW16 },
+  { BFD_RELOC_SH_GOTPC_MEDLOW16, R_SH_GOTPC_MEDLOW16 },
+  { BFD_RELOC_SH_GOTPC_MEDHI16, R_SH_GOTPC_MEDHI16 },
+  { BFD_RELOC_SH_GOTPC_HI16, R_SH_GOTPC_HI16 },
+  { BFD_RELOC_SH_COPY64, R_SH_COPY64 },
+  { BFD_RELOC_SH_GLOB_DAT64, R_SH_GLOB_DAT64 },
+  { BFD_RELOC_SH_JMP_SLOT64, R_SH_JMP_SLOT64 },
+  { BFD_RELOC_SH_RELATIVE64, R_SH_RELATIVE64 },
+  { BFD_RELOC_SH_GOT10BY4, R_SH_GOT10BY4 },
+  { BFD_RELOC_SH_GOT10BY8, R_SH_GOT10BY8 },
+  { BFD_RELOC_SH_GOTPLT10BY4, R_SH_GOTPLT10BY4 },
+  { BFD_RELOC_SH_GOTPLT10BY8, R_SH_GOTPLT10BY8 },
+  { BFD_RELOC_SH_PT_16, R_SH_PT_16 },
+  { BFD_RELOC_SH_SHMEDIA_CODE, R_SH_SHMEDIA_CODE },
+  { BFD_RELOC_SH_IMMU5, R_SH_DIR5U },
+  { BFD_RELOC_SH_IMMS6, R_SH_DIR6S },
+  { BFD_RELOC_SH_IMMU6, R_SH_DIR6U },
+  { BFD_RELOC_SH_IMMS10, R_SH_DIR10S },
+  { BFD_RELOC_SH_IMMS10BY2, R_SH_DIR10SW },
+  { BFD_RELOC_SH_IMMS10BY4, R_SH_DIR10SL },
+  { BFD_RELOC_SH_IMMS10BY8, R_SH_DIR10SQ },
+  { BFD_RELOC_SH_IMMS16, R_SH_IMMS16 },
+  { BFD_RELOC_SH_IMMU16, R_SH_IMMU16 },
+  { BFD_RELOC_SH_IMM_LOW16, R_SH_IMM_LOW16 },
+  { BFD_RELOC_SH_IMM_LOW16_PCREL, R_SH_IMM_LOW16_PCREL },
+  { BFD_RELOC_SH_IMM_MEDLOW16, R_SH_IMM_MEDLOW16 },
+  { BFD_RELOC_SH_IMM_MEDLOW16_PCREL, R_SH_IMM_MEDLOW16_PCREL },
+  { BFD_RELOC_SH_IMM_MEDHI16, R_SH_IMM_MEDHI16 },
+  { BFD_RELOC_SH_IMM_MEDHI16_PCREL, R_SH_IMM_MEDHI16_PCREL },
+  { BFD_RELOC_SH_IMM_HI16, R_SH_IMM_HI16 },
+  { BFD_RELOC_SH_IMM_HI16_PCREL, R_SH_IMM_HI16_PCREL },
+  { BFD_RELOC_64, R_SH_64 },
+  { BFD_RELOC_64_PCREL, R_SH_64_PCREL },
+#endif /* not INCLUDE_SHMEDIA */
 };
 
 /* Given a BFD reloc code, return the howto structure for the
@@ -988,6 +1861,8 @@ sh_elf_info_to_howto (abfd, cache_ptr, dst)
   BFD_ASSERT (r < (unsigned int) R_SH_max);
   BFD_ASSERT (r < R_SH_FIRST_INVALID_RELOC || r > R_SH_LAST_INVALID_RELOC);
   BFD_ASSERT (r < R_SH_FIRST_INVALID_RELOC_2 || r > R_SH_LAST_INVALID_RELOC_2);
+  BFD_ASSERT (r < R_SH_FIRST_INVALID_RELOC_3 || r > R_SH_LAST_INVALID_RELOC_3);
+  BFD_ASSERT (r < R_SH_FIRST_INVALID_RELOC_4 || r > R_SH_LAST_INVALID_RELOC_4);
 
   cache_ptr->howto = &sh_elf_howto_table[r];
 }
@@ -1010,6 +1885,7 @@ sh_elf_relax_section (abfd, sec, link_info, again)
      boolean *again;
 {
   Elf_Internal_Shdr *symtab_hdr;
+  Elf_Internal_Shdr *shndx_hdr;
   Elf_Internal_Rela *internal_relocs;
   Elf_Internal_Rela *free_relocs = NULL;
   boolean have_code;
@@ -1018,6 +1894,7 @@ sh_elf_relax_section (abfd, sec, link_info, again)
   bfd_byte *free_contents = NULL;
   Elf32_External_Sym *extsyms = NULL;
   Elf32_External_Sym *free_extsyms = NULL;
+  Elf_External_Sym_Shndx *shndx_buf = NULL;
 
   *again = false;
 
@@ -1026,12 +1903,21 @@ sh_elf_relax_section (abfd, sec, link_info, again)
       || sec->reloc_count == 0)
     return true;
 
+#ifdef INCLUDE_SHMEDIA
+  if (elf_section_data (sec)->this_hdr.sh_flags
+      & (SHF_SH5_ISA32 | SHF_SH5_ISA32_MIXED))
+    {
+      return true;
+    }
+#endif
+
   /* If this is the first time we have been called for this section,
      initialize the cooked size.  */
   if (sec->_cooked_size == 0)
     sec->_cooked_size = sec->_raw_size;
 
   symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
+  shndx_hdr = &elf_tdata (abfd)->symtab_shndx_hdr;
 
   internal_relocs = (_bfd_elf32_link_read_relocs
                     (abfd, sec, (PTR) NULL, (Elf_Internal_Rela *) NULL,
@@ -1083,7 +1969,7 @@ sh_elf_relax_section (abfd, sec, link_info, again)
       if (laddr >= sec->_raw_size)
        {
          (*_bfd_error_handler) (_("%s: 0x%lx: warning: bad R_SH_USES offset"),
-                                bfd_get_filename (abfd),
+                                bfd_archive_filename (abfd),
                                 (unsigned long) irel->r_offset);
          continue;
        }
@@ -1095,24 +1981,24 @@ sh_elf_relax_section (abfd, sec, link_info, again)
        {
          ((*_bfd_error_handler)
           (_("%s: 0x%lx: warning: R_SH_USES points to unrecognized insn 0x%x"),
-           bfd_get_filename (abfd), (unsigned long) irel->r_offset, insn));
+           bfd_archive_filename (abfd), (unsigned long) irel->r_offset, insn));
          continue;
        }
 
       /* Get the address from which the register is being loaded.  The
-        displacement in the mov.l instruction is quadrupled.  It is a
-        displacement from four bytes after the movl instruction, but,
-        before adding in the PC address, two least significant bits
-        of the PC are cleared.  We assume that the section is aligned
-        on a four byte boundary.  */
+        displacement in the mov.l instruction is quadrupled.  It is a
+        displacement from four bytes after the movl instruction, but,
+        before adding in the PC address, two least significant bits
+        of the PC are cleared.  We assume that the section is aligned
+        on a four byte boundary.  */
       paddr = insn & 0xff;
       paddr *= 4;
-      paddr += (laddr + 4) & ~3;
+      paddr += (laddr + 4) &~ (bfd_vma) 3;
       if (paddr >= sec->_raw_size)
        {
          ((*_bfd_error_handler)
           (_("%s: 0x%lx: warning: bad R_SH_USES load offset"),
-           bfd_get_filename (abfd), (unsigned long) irel->r_offset));
+           bfd_archive_filename (abfd), (unsigned long) irel->r_offset));
          continue;
        }
 
@@ -1127,7 +2013,7 @@ sh_elf_relax_section (abfd, sec, link_info, again)
        {
          ((*_bfd_error_handler)
           (_("%s: 0x%lx: warning: could not find expected reloc"),
-           bfd_get_filename (abfd), (unsigned long) paddr));
+           bfd_archive_filename (abfd), (unsigned long) paddr));
          continue;
        }
 
@@ -1138,33 +2024,54 @@ sh_elf_relax_section (abfd, sec, link_info, again)
            extsyms = (Elf32_External_Sym *) symtab_hdr->contents;
          else
            {
-             extsyms = ((Elf32_External_Sym *)
-                        bfd_malloc (symtab_hdr->sh_size));
+             bfd_size_type amt;
+
+             amt = symtab_hdr->sh_info;
+             amt *= sizeof (Elf32_External_Sym);
+             extsyms = (Elf32_External_Sym *) bfd_malloc (amt);
              if (extsyms == NULL)
                goto error_return;
              free_extsyms = extsyms;
              if (bfd_seek (abfd, symtab_hdr->sh_offset, SEEK_SET) != 0
-                 || (bfd_read (extsyms, 1, symtab_hdr->sh_size, abfd)
-                     != symtab_hdr->sh_size))
+                 || bfd_bread ((PTR) extsyms, amt, abfd) != amt)
                goto error_return;
+             symtab_hdr->contents = (bfd_byte *) extsyms;
+           }
+
+         if (shndx_hdr->sh_size != 0)
+           {
+             bfd_size_type amt;
+
+             amt = symtab_hdr->sh_info;
+             amt *= sizeof (Elf_External_Sym_Shndx);
+             shndx_buf = (Elf_External_Sym_Shndx *) bfd_malloc (amt);
+             if (shndx_buf == NULL)
+               goto error_return;
+             if (bfd_seek (abfd, shndx_hdr->sh_offset, SEEK_SET) != 0
+                 || bfd_bread ((PTR) shndx_buf, amt, abfd) != amt)
+               goto error_return;
+             shndx_hdr->contents = (bfd_byte *) shndx_buf;
            }
        }
 
       /* Get the value of the symbol referred to by the reloc.  */
       if (ELF32_R_SYM (irelfn->r_info) < symtab_hdr->sh_info)
        {
+         /* A local symbol.  */
+         Elf32_External_Sym *esym;
+         Elf_External_Sym_Shndx *shndx;
          Elf_Internal_Sym isym;
 
-         /* A local symbol.  */
-         bfd_elf32_swap_symbol_in (abfd,
-                                   extsyms + ELF32_R_SYM (irelfn->r_info),
-                                   &isym);
+         esym = extsyms + ELF32_R_SYM (irelfn->r_info);
+         shndx = shndx_buf + (shndx_buf ? ELF32_R_SYM (irelfn->r_info) : 0);
+         bfd_elf32_swap_symbol_in (abfd, esym, shndx, &isym);
 
-         if (isym.st_shndx != _bfd_elf_section_from_bfd_section (abfd, sec))
+         if (isym.st_shndx
+             != (unsigned int) _bfd_elf_section_from_bfd_section (abfd, sec))
            {
              ((*_bfd_error_handler)
               (_("%s: 0x%lx: warning: symbol in unexpected section"),
-               bfd_get_filename (abfd), (unsigned long) paddr));
+               bfd_archive_filename (abfd), (unsigned long) paddr));
              continue;
            }
 
@@ -1224,7 +2131,6 @@ sh_elf_relax_section (abfd, sec, link_info, again)
       elf_section_data (sec)->this_hdr.contents = contents;
       free_contents = NULL;
 
-      symtab_hdr->contents = (bfd_byte *) extsyms;
       free_extsyms = NULL;
 
       /* Replace the jsr with a bsr.  */
@@ -1238,7 +2144,7 @@ sh_elf_relax_section (abfd, sec, link_info, again)
              it will be handled here like other internal IND12W
              relocs.  */
          bfd_put_16 (abfd,
-                     0xb000 | ((foff >> 1) & 0xfff),
+                     (bfd_vma) 0xb000 | ((foff >> 1) & 0xfff),
                      contents + irel->r_offset);
        }
       else
@@ -1246,7 +2152,7 @@ sh_elf_relax_section (abfd, sec, link_info, again)
          /* We can't fully resolve this yet, because the external
              symbol value may be changed by future relaxing.  We let
              the final link phase handle it.  */
-         bfd_put_16 (abfd, 0xb000, contents + irel->r_offset);
+         bfd_put_16 (abfd, (bfd_vma) 0xb000, contents + irel->r_offset);
        }
 
       /* See if there is another R_SH_USES reloc referring to the same
@@ -1286,7 +2192,7 @@ sh_elf_relax_section (abfd, sec, link_info, again)
        {
          ((*_bfd_error_handler)
           (_("%s: 0x%lx: warning: could not find expected COUNT reloc"),
-           bfd_get_filename (abfd), (unsigned long) paddr));
+           bfd_archive_filename (abfd), (unsigned long) paddr));
          continue;
        }
 
@@ -1295,7 +2201,7 @@ sh_elf_relax_section (abfd, sec, link_info, again)
       if (irelcount->r_addend == 0)
        {
          ((*_bfd_error_handler) (_("%s: 0x%lx: warning: bad count"),
-                                 bfd_get_filename (abfd),
+                                 bfd_archive_filename (abfd),
                                  (unsigned long) paddr));
          continue;
        }
@@ -1350,16 +2256,12 @@ sh_elf_relax_section (abfd, sec, link_info, again)
          elf_section_data (sec)->this_hdr.contents = contents;
          free_contents = NULL;
 
-         symtab_hdr->contents = (bfd_byte *) extsyms;
          free_extsyms = NULL;
        }
     }
 
   if (free_relocs != NULL)
-    {
-      free (free_relocs);
-      free_relocs = NULL;
-    }
+    free (free_relocs);
 
   if (free_contents != NULL)
     {
@@ -1370,19 +2272,21 @@ sh_elf_relax_section (abfd, sec, link_info, again)
          /* Cache the section contents for elf_link_input_bfd.  */
          elf_section_data (sec)->this_hdr.contents = contents;
        }
-      free_contents = NULL;
+    }
+
+  if (shndx_buf != NULL)
+    {
+      shndx_hdr->contents = NULL;
+      free (shndx_buf);
     }
 
   if (free_extsyms != NULL)
     {
       if (! link_info->keep_memory)
-       free (free_extsyms);
-      else
        {
-         /* Cache the symbols for elf_link_input_bfd.  */
-         symtab_hdr->contents = extsyms;
+         symtab_hdr->contents = NULL;
+         free (free_extsyms);
        }
-      free_extsyms = NULL;
     }
 
   return true;
@@ -1392,8 +2296,17 @@ sh_elf_relax_section (abfd, sec, link_info, again)
     free (free_relocs);
   if (free_contents != NULL)
     free (free_contents);
+  if (shndx_buf != NULL)
+    {
+      shndx_hdr->contents = NULL;
+      free (shndx_buf);
+    }
   if (free_extsyms != NULL)
-    free (free_extsyms);
+    {
+      symtab_hdr->contents = NULL;
+      free (free_extsyms);
+    }
+
   return false;
 }
 
@@ -1409,20 +2322,27 @@ sh_elf_relax_delete_bytes (abfd, sec, addr, count)
      int count;
 {
   Elf_Internal_Shdr *symtab_hdr;
+  Elf_Internal_Shdr *shndx_hdr;
   Elf32_External_Sym *extsyms;
-  int shndx, index;
+  unsigned int sec_shndx;
   bfd_byte *contents;
   Elf_Internal_Rela *irel, *irelend;
   Elf_Internal_Rela *irelalign;
   bfd_vma toaddr;
   Elf32_External_Sym *esym, *esymend;
-  struct elf_link_hash_entry *sym_hash;
+  Elf_External_Sym_Shndx *shndx_buf, *shndx;
+  struct elf_link_hash_entry **sym_hashes;
+  struct elf_link_hash_entry **end_hashes;
+  unsigned int symcount;
   asection *o;
 
   symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
   extsyms = (Elf32_External_Sym *) symtab_hdr->contents;
 
-  shndx = _bfd_elf_section_from_bfd_section (abfd, sec);
+  shndx_hdr = &elf_tdata (abfd)->symtab_shndx_hdr;
+  shndx_buf = (Elf_External_Sym_Shndx *) shndx_hdr->contents;
+
+  sec_shndx = _bfd_elf_section_from_bfd_section (abfd, sec);
 
   contents = elf_section_data (sec)->this_hdr.contents;
 
@@ -1447,7 +2367,8 @@ sh_elf_relax_delete_bytes (abfd, sec, addr, count)
     }
 
   /* Actually delete the bytes.  */
-  memmove (contents + addr, contents + addr + count, toaddr - addr - count);
+  memmove (contents + addr, contents + addr + count,
+          (size_t) (toaddr - addr - count));
   if (irelalign == NULL)
     sec->_cooked_size -= count;
   else
@@ -1458,7 +2379,7 @@ sh_elf_relax_delete_bytes (abfd, sec, addr, count)
 
       BFD_ASSERT ((count & 1) == 0);
       for (i = 0; i < count; i += 2)
-       bfd_put_16 (abfd, NOP_OPCODE, contents + toaddr - count + i);
+       bfd_put_16 (abfd, (bfd_vma) NOP_OPCODE, contents + toaddr - count + i);
     }
 
   /* Adjust all the relocs.  */
@@ -1521,10 +2442,11 @@ sh_elf_relax_delete_bytes (abfd, sec, addr, count)
              range to be adjusted, and hence must be changed.  */
          if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info)
            {
-             bfd_elf32_swap_symbol_in (abfd,
-                                       extsyms + ELF32_R_SYM (irel->r_info),
-                                       &sym);
-             if (sym.st_shndx == shndx
+             esym = extsyms + ELF32_R_SYM (irel->r_info);
+             shndx = shndx_buf + (shndx_buf ? ELF32_R_SYM (irel->r_info) : 0);
+             bfd_elf32_swap_symbol_in (abfd, esym, shndx, &sym);
+
+             if (sym.st_shndx == sec_shndx
                  && (sym.st_value <= addr
                      || sym.st_value >= toaddr))
                {
@@ -1636,14 +2558,14 @@ sh_elf_relax_delete_bytes (abfd, sec, addr, count)
              insn += adjust / 2;
              if ((oinsn & 0xff00) != (insn & 0xff00))
                overflow = true;
-             bfd_put_16 (abfd, insn, contents + nraddr);
+             bfd_put_16 (abfd, (bfd_vma) insn, contents + nraddr);
              break;
 
            case R_SH_IND12W:
              insn += adjust / 2;
              if ((oinsn & 0xf000) != (insn & 0xf000))
                overflow = true;
-             bfd_put_16 (abfd, insn, contents + nraddr);
+             bfd_put_16 (abfd, (bfd_vma) insn, contents + nraddr);
              break;
 
            case R_SH_DIR8WPL:
@@ -1657,7 +2579,7 @@ sh_elf_relax_delete_bytes (abfd, sec, addr, count)
                }
              if ((oinsn & 0xff00) != (insn & 0xff00))
                overflow = true;
-             bfd_put_16 (abfd, insn, contents + nraddr);
+             bfd_put_16 (abfd, (bfd_vma) insn, contents + nraddr);
              break;
 
            case R_SH_SWITCH8:
@@ -1671,12 +2593,12 @@ sh_elf_relax_delete_bytes (abfd, sec, addr, count)
              voff += adjust;
              if (voff < - 0x8000 || voff >= 0x8000)
                overflow = true;
-             bfd_put_signed_16 (abfd, voff, contents + nraddr);
+             bfd_put_signed_16 (abfd, (bfd_vma) voff, contents + nraddr);
              break;
 
            case R_SH_SWITCH32:
              voff += adjust;
-             bfd_put_signed_32 (abfd, voff, contents + nraddr);
+             bfd_put_signed_32 (abfd, (bfd_vma) voff, contents + nraddr);
              break;
 
            case R_SH_USES:
@@ -1688,7 +2610,7 @@ sh_elf_relax_delete_bytes (abfd, sec, addr, count)
            {
              ((*_bfd_error_handler)
               (_("%s: 0x%lx: fatal: reloc overflow while relaxing"),
-               bfd_get_filename (abfd), (unsigned long) irel->r_offset));
+               bfd_archive_filename (abfd), (unsigned long) irel->r_offset));
              bfd_set_error (bfd_error_bad_value);
              return false;
            }
@@ -1767,12 +2689,12 @@ sh_elf_relax_delete_bytes (abfd, sec, addr, count)
              if (start > addr
                  && start < toaddr
                  && (stop <= addr || stop >= toaddr))
-               bfd_put_signed_32 (abfd, voff + count,
+               bfd_put_signed_32 (abfd, (bfd_vma) voff + count,
                                   ocontents + irelscan->r_offset);
              else if (stop > addr
                       && stop < toaddr
                       && (start <= addr || start >= toaddr))
-               bfd_put_signed_32 (abfd, voff - count,
+               bfd_put_signed_32 (abfd, (bfd_vma) voff - count,
                                   ocontents + irelscan->r_offset);
            }
 
@@ -1782,11 +2704,12 @@ sh_elf_relax_delete_bytes (abfd, sec, addr, count)
          if (ELF32_R_SYM (irelscan->r_info) >= symtab_hdr->sh_info)
            continue;
 
-         bfd_elf32_swap_symbol_in (abfd,
-                                   extsyms + ELF32_R_SYM (irelscan->r_info),
-                                   &sym);
 
-         if (sym.st_shndx == shndx
+         esym = extsyms + ELF32_R_SYM (irelscan->r_info);
+         shndx = shndx_buf + (shndx_buf ? ELF32_R_SYM (irelscan->r_info) : 0);
+         bfd_elf32_swap_symbol_in (abfd, esym, shndx, &sym);
+
+         if (sym.st_shndx == sec_shndx
              && (sym.st_value <= addr
                  || sym.st_value >= toaddr))
            {
@@ -1823,40 +2746,40 @@ sh_elf_relax_delete_bytes (abfd, sec, addr, count)
     }
 
   /* Adjust the local symbols defined in this section.  */
+  shndx = shndx_buf;
   esym = extsyms;
   esymend = esym + symtab_hdr->sh_info;
-  for (; esym < esymend; esym++)
+  for (; esym < esymend; esym++, shndx = (shndx ? shndx + 1 : NULL))
     {
       Elf_Internal_Sym isym;
+      Elf_External_Sym_Shndx dummy;
 
-      bfd_elf32_swap_symbol_in (abfd, esym, &isym);
+      bfd_elf32_swap_symbol_in (abfd, esym, shndx, &isym);
 
-      if (isym.st_shndx == shndx
+      if (isym.st_shndx == sec_shndx
          && isym.st_value > addr
          && isym.st_value < toaddr)
        {
          isym.st_value -= count;
-         bfd_elf32_swap_symbol_out (abfd, &isym, esym);
+         bfd_elf32_swap_symbol_out (abfd, &isym, (PTR) esym, (PTR) &dummy);
        }
     }
 
   /* Now adjust the global symbols defined in this section.  */
-  esym = extsyms + symtab_hdr->sh_info;
-  esymend = extsyms + (symtab_hdr->sh_size / sizeof (Elf32_External_Sym));
-  for (index = 0; esym < esymend; esym++, index++)
+  symcount = (symtab_hdr->sh_size / sizeof (Elf32_External_Sym)
+             - symtab_hdr->sh_info);
+  sym_hashes = elf_sym_hashes (abfd);
+  end_hashes = sym_hashes + symcount;
+  for (; sym_hashes < end_hashes; sym_hashes++)
     {
-      Elf_Internal_Sym isym;
-
-      bfd_elf32_swap_symbol_in (abfd, esym, &isym);
-      sym_hash = elf_sym_hashes (abfd)[index];
-      if (isym.st_shndx == shndx
-         && ((sym_hash)->root.type == bfd_link_hash_defined
-             || (sym_hash)->root.type == bfd_link_hash_defweak)
-         && (sym_hash)->root.u.def.section == sec
-         && (sym_hash)->root.u.def.value > addr
-         && (sym_hash)->root.u.def.value < toaddr)
+      struct elf_link_hash_entry *sym_hash = *sym_hashes;
+      if ((sym_hash->root.type == bfd_link_hash_defined
+          || sym_hash->root.type == bfd_link_hash_defweak)
+         && sym_hash->root.u.def.section == sec
+         && sym_hash->root.u.def.value > addr
+         && sym_hash->root.u.def.value < toaddr)
        {
-         (sym_hash)->root.u.def.value -= count;
+         sym_hash->root.u.def.value -= count;
        }
     }
 
@@ -1873,7 +2796,7 @@ sh_elf_relax_delete_bytes (abfd, sec, addr, count)
        {
          /* Tail recursion.  */
          return sh_elf_relax_delete_bytes (abfd, sec, alignaddr,
-                                           alignto - alignaddr);
+                                           (int) (alignto - alignaddr));
        }
     }
 
@@ -1894,13 +2817,16 @@ sh_elf_align_loads (abfd, sec, internal_relocs, contents, pswapped)
   Elf_Internal_Rela *irel, *irelend;
   bfd_vma *labels = NULL;
   bfd_vma *label, *label_end;
+  bfd_size_type amt;
 
   *pswapped = false;
 
   irelend = internal_relocs + sec->reloc_count;
 
   /* Get all the addresses with labels on them.  */
-  labels = (bfd_vma *) bfd_malloc (sec->reloc_count * sizeof (bfd_vma));
+  amt = sec->reloc_count;
+  amt *= sizeof (bfd_vma);
+  labels = (bfd_vma *) bfd_malloc (amt);
   if (labels == NULL)
     goto error_return;
   label_end = labels;
@@ -1969,8 +2895,8 @@ sh_elf_swap_insns (abfd, sec, relocs, contents, addr)
   /* Swap the instructions themselves.  */
   i1 = bfd_get_16 (abfd, contents + addr);
   i2 = bfd_get_16 (abfd, contents + addr + 2);
-  bfd_put_16 (abfd, i2, contents + addr);
-  bfd_put_16 (abfd, i1, contents + addr + 2);
+  bfd_put_16 (abfd, (bfd_vma) i2, contents + addr);
+  bfd_put_16 (abfd, (bfd_vma) i1, contents + addr + 2);
 
   /* Adjust all reloc addresses.  */
   irelend = internal_relocs + sec->reloc_count;
@@ -2039,58 +2965,339 @@ sh_elf_swap_insns (abfd, sec, relocs, contents, addr)
              insn += add / 2;
              if ((oinsn & 0xff00) != (insn & 0xff00))
                overflow = true;
-             bfd_put_16 (abfd, insn, loc);
+             bfd_put_16 (abfd, (bfd_vma) insn, loc);
+             break;
+
+           case R_SH_IND12W:
+             insn = bfd_get_16 (abfd, loc);
+             oinsn = insn;
+             insn += add / 2;
+             if ((oinsn & 0xf000) != (insn & 0xf000))
+               overflow = true;
+             bfd_put_16 (abfd, (bfd_vma) insn, loc);
+             break;
+
+           case R_SH_DIR8WPL:
+             /* This reloc ignores the least significant 3 bits of
+                 the program counter before adding in the offset.
+                 This means that if ADDR is at an even address, the
+                 swap will not affect the offset.  If ADDR is an at an
+                 odd address, then the instruction will be crossing a
+                 four byte boundary, and must be adjusted.  */
+             if ((addr & 3) != 0)
+               {
+                 insn = bfd_get_16 (abfd, loc);
+                 oinsn = insn;
+                 insn += add / 2;
+                 if ((oinsn & 0xff00) != (insn & 0xff00))
+                   overflow = true;
+                 bfd_put_16 (abfd, (bfd_vma) insn, loc);
+               }
+
              break;
+           }
+
+         if (overflow)
+           {
+             ((*_bfd_error_handler)
+              (_("%s: 0x%lx: fatal: reloc overflow while relaxing"),
+               bfd_archive_filename (abfd), (unsigned long) irel->r_offset));
+             bfd_set_error (bfd_error_bad_value);
+             return false;
+           }
+       }
+    }
+
+  return true;
+}
+\f
+#ifdef INCLUDE_SHMEDIA
+
+/* The size in bytes of an entry in the procedure linkage table.  */
+
+#define PLT_ENTRY_SIZE 64
+
+/* First entry in an absolute procedure linkage table look like this.  */
+
+static const bfd_byte elf_sh_plt0_entry_be[PLT_ENTRY_SIZE] =
+{
+  0xcc, 0x00, 0x01, 0x10, /* movi  .got.plt >> 16, r17 */
+  0xc8, 0x00, 0x01, 0x10, /* shori .got.plt & 65535, r17 */
+  0x89, 0x10, 0x09, 0x90, /* ld.l  r17, 8, r25 */
+  0x6b, 0xf1, 0x46, 0x00, /* ptabs r17, tr0 */
+  0x89, 0x10, 0x05, 0x10, /* ld.l  r17, 4, r17 */
+  0x44, 0x01, 0xff, 0xf0, /* blink tr0, r63 */
+  0x6f, 0xf0, 0xff, 0xf0, /* nop */
+  0x6f, 0xf0, 0xff, 0xf0, /* nop */
+  0x6f, 0xf0, 0xff, 0xf0, /* nop */
+  0x6f, 0xf0, 0xff, 0xf0, /* nop */
+  0x6f, 0xf0, 0xff, 0xf0, /* nop */
+  0x6f, 0xf0, 0xff, 0xf0, /* nop */
+  0x6f, 0xf0, 0xff, 0xf0, /* nop */
+  0x6f, 0xf0, 0xff, 0xf0, /* nop */
+  0x6f, 0xf0, 0xff, 0xf0, /* nop */
+  0x6f, 0xf0, 0xff, 0xf0, /* nop */
+};
+
+static const bfd_byte elf_sh_plt0_entry_le[PLT_ENTRY_SIZE] =
+{
+  0x10, 0x01, 0x00, 0xcc, /* movi  .got.plt >> 16, r17 */
+  0x10, 0x01, 0x00, 0xc8, /* shori .got.plt & 65535, r17 */
+  0x90, 0x09, 0x10, 0x89, /* ld.l  r17, 8, r25 */
+  0x00, 0x46, 0xf1, 0x6b, /* ptabs r17, tr0 */
+  0x10, 0x05, 0x10, 0x89, /* ld.l  r17, 4, r17 */
+  0xf0, 0xff, 0x01, 0x44, /* blink tr0, r63 */
+  0xf0, 0xff, 0xf0, 0x6f, /* nop */
+  0xf0, 0xff, 0xf0, 0x6f, /* nop */
+  0xf0, 0xff, 0xf0, 0x6f, /* nop */
+  0xf0, 0xff, 0xf0, 0x6f, /* nop */
+  0xf0, 0xff, 0xf0, 0x6f, /* nop */
+  0xf0, 0xff, 0xf0, 0x6f, /* nop */
+  0xf0, 0xff, 0xf0, 0x6f, /* nop */
+  0xf0, 0xff, 0xf0, 0x6f, /* nop */
+  0xf0, 0xff, 0xf0, 0x6f, /* nop */
+  0xf0, 0xff, 0xf0, 0x6f, /* nop */
+};
+
+/* Sebsequent entries in an absolute procedure linkage table look like
+   this.  */
+
+static const bfd_byte elf_sh_plt_entry_be[PLT_ENTRY_SIZE] =
+{
+  0xcc, 0x00, 0x01, 0x90, /* movi  nameN-in-GOT >> 16, r25 */
+  0xc8, 0x00, 0x01, 0x90, /* shori nameN-in-GOT & 65535, r25 */
+  0x89, 0x90, 0x01, 0x90, /* ld.l  r25, 0, r25 */
+  0x6b, 0xf1, 0x66, 0x00, /* ptabs r25, tr0 */
+  0x44, 0x01, 0xff, 0xf0, /* blink tr0, r63 */
+  0x6f, 0xf0, 0xff, 0xf0, /* nop */
+  0x6f, 0xf0, 0xff, 0xf0, /* nop */
+  0x6f, 0xf0, 0xff, 0xf0, /* nop */
+  0xcc, 0x00, 0x01, 0x90, /* movi  .PLT0 >> 16, r25 */
+  0xc8, 0x00, 0x01, 0x90, /* shori .PLT0 & 65535, r25 */
+  0x6b, 0xf1, 0x66, 0x00, /* ptabs r25, tr0 */
+  0xcc, 0x00, 0x01, 0x50, /* movi  reloc-offset >> 16, r21 */
+  0xc8, 0x00, 0x01, 0x50, /* shori reloc-offset & 65535, r21 */
+  0x44, 0x01, 0xff, 0xf0, /* blink tr0, r63 */
+  0x6f, 0xf0, 0xff, 0xf0, /* nop */
+  0x6f, 0xf0, 0xff, 0xf0, /* nop */
+};
+
+static const bfd_byte elf_sh_plt_entry_le[PLT_ENTRY_SIZE] =
+{
+  0x90, 0x01, 0x00, 0xcc, /* movi  nameN-in-GOT >> 16, r25 */
+  0x90, 0x01, 0x00, 0xc8, /* shori nameN-in-GOT & 65535, r25 */
+  0x90, 0x01, 0x90, 0x89, /* ld.l  r25, 0, r25 */
+  0x00, 0x66, 0xf1, 0x6b, /* ptabs r25, tr0 */
+  0xf0, 0xff, 0x01, 0x44, /* blink tr0, r63 */
+  0xf0, 0xff, 0xf0, 0x6f, /* nop */
+  0xf0, 0xff, 0xf0, 0x6f, /* nop */
+  0xf0, 0xff, 0xf0, 0x6f, /* nop */
+  0x90, 0x01, 0x00, 0xcc, /* movi  .PLT0 >> 16, r25 */
+  0x90, 0x01, 0x00, 0xc8, /* shori .PLT0 & 65535, r25 */
+  0x00, 0x66, 0xf1, 0x6b, /* ptabs r25, tr0 */
+  0x50, 0x01, 0x00, 0xcc, /* movi  reloc-offset >> 16, r21 */
+  0x50, 0x01, 0x00, 0xc8, /* shori reloc-offset & 65535, r21 */
+  0xf0, 0xff, 0x01, 0x44, /* blink tr0, r63 */
+  0xf0, 0xff, 0xf0, 0x6f, /* nop */
+  0xf0, 0xff, 0xf0, 0x6f, /* nop */
+};
+
+/* Entries in a PIC procedure linkage table look like this.  */
+
+static const bfd_byte elf_sh_pic_plt_entry_be[PLT_ENTRY_SIZE] =
+{
+  0xcc, 0x00, 0x01, 0x90, /* movi  nameN@GOT >> 16, r25 */
+  0xc8, 0x00, 0x01, 0x90, /* shori nameN@GOT & 65535, r25 */
+  0x40, 0xc2, 0x65, 0x90, /* ldx.l r12, r25, r25 */
+  0x6b, 0xf1, 0x66, 0x00, /* ptabs r25, tr0 */
+  0x44, 0x01, 0xff, 0xf0, /* blink tr0, r63 */
+  0x6f, 0xf0, 0xff, 0xf0, /* nop */
+  0x6f, 0xf0, 0xff, 0xf0, /* nop */
+  0x6f, 0xf0, 0xff, 0xf0, /* nop */
+  0xce, 0x00, 0x01, 0x10, /* movi  -GOT_BIAS, r17 */
+  0x00, 0xca, 0x45, 0x10, /* sub.l r12, r17, r17 */
+  0x89, 0x10, 0x09, 0x90, /* ld.l  r17, 8, r25 */
+  0x6b, 0xf1, 0x66, 0x00, /* ptabs r25, tr0 */
+  0x89, 0x10, 0x05, 0x10, /* ld.l  r17, 4, r17 */
+  0xcc, 0x00, 0x01, 0x50, /* movi  reloc-offset >> 16, r21 */
+  0xc8, 0x00, 0x01, 0x50, /* shori reloc-offset & 65535, r21 */
+  0x44, 0x01, 0xff, 0xf0, /* blink tr0, r63 */
+};
+
+static const bfd_byte elf_sh_pic_plt_entry_le[PLT_ENTRY_SIZE] =
+{
+  0x90, 0x01, 0x00, 0xcc, /* movi  nameN@GOT >> 16, r25 */
+  0x90, 0x01, 0x00, 0xc8, /* shori nameN@GOT & 65535, r25 */
+  0x90, 0x65, 0xc2, 0x40, /* ldx.l r12, r25, r25 */
+  0x00, 0x66, 0xf1, 0x6b, /* ptabs r25, tr0 */
+  0xf0, 0xff, 0x01, 0x44, /* blink tr0, r63 */
+  0xf0, 0xff, 0xf0, 0x6f, /* nop */
+  0xf0, 0xff, 0xf0, 0x6f, /* nop */
+  0xf0, 0xff, 0xf0, 0x6f, /* nop */
+  0x10, 0x01, 0x00, 0xce, /* movi  -GOT_BIAS, r17 */
+  0x10, 0x45, 0xca, 0x00, /* sub.l r12, r17, r17 */
+  0x90, 0x09, 0x10, 0x89, /* ld.l  r17, 8, r25 */
+  0x00, 0x66, 0xf1, 0x6b, /* ptabs r25, tr0 */
+  0x10, 0x05, 0x10, 0x89, /* ld.l  r17, 4, r17 */
+  0x50, 0x01, 0x00, 0xcc, /* movi  reloc-offset >> 16, r21 */
+  0x50, 0x01, 0x00, 0xc8, /* shori reloc-offset & 65535, r21 */
+  0xf0, 0xff, 0x01, 0x44, /* blink tr0, r63 */
+};
+
+static const bfd_byte *elf_sh_plt0_entry;
+static const bfd_byte *elf_sh_plt_entry;
+static const bfd_byte *elf_sh_pic_plt_entry;
 
-           case R_SH_IND12W:
-             insn = bfd_get_16 (abfd, loc);
-             oinsn = insn;
-             insn += add / 2;
-             if ((oinsn & 0xf000) != (insn & 0xf000))
-               overflow = true;
-             bfd_put_16 (abfd, insn, loc);
-             break;
+/* Return size of a PLT entry.  */
+#define elf_sh_sizeof_plt(info) PLT_ENTRY_SIZE
 
-           case R_SH_DIR8WPL:
-             /* This reloc ignores the least significant 3 bits of
-                 the program counter before adding in the offset.
-                 This means that if ADDR is at an even address, the
-                 swap will not affect the offset.  If ADDR is an at an
-                 odd address, then the instruction will be crossing a
-                 four byte boundary, and must be adjusted.  */
-             if ((addr & 3) != 0)
-               {
-                 insn = bfd_get_16 (abfd, loc);
-                 oinsn = insn;
-                 insn += add / 2;
-                 if ((oinsn & 0xff00) != (insn & 0xff00))
-                   overflow = true;
-                 bfd_put_16 (abfd, insn, loc);
-               }
+/* Return offset of the PLT0 address in an absolute PLT entry.  */
+#define elf_sh_plt_plt0_offset(info) 32
 
-             break;
-           }
+/* Return offset of the linker in PLT0 entry.  */
+#define elf_sh_plt0_gotplt_offset(info) 0
 
-         if (overflow)
-           {
-             ((*_bfd_error_handler)
-              (_("%s: 0x%lx: fatal: reloc overflow while relaxing"),
-               bfd_get_filename (abfd), (unsigned long) irel->r_offset));
-             bfd_set_error (bfd_error_bad_value);
-             return false;
-           }
-       }
-    }
+/* Return offset of the trampoline in PLT entry */
+#define elf_sh_plt_temp_offset(info) 33 /* Add one because it's SHmedia.  */
 
-  return true;
+/* Return offset of the symbol in PLT entry.  */
+#define elf_sh_plt_symbol_offset(info) 0
+
+/* Return offset of the relocation in PLT entry.  */
+#define elf_sh_plt_reloc_offset(info) (info->shared ? 52 : 44)
+
+inline static void
+movi_shori_putval (output_bfd, value, addr)
+     bfd *output_bfd;
+     unsigned long value;
+     char *addr;
+{
+  bfd_put_32 (output_bfd,
+             bfd_get_32 (output_bfd, addr)
+             | ((value >> 6) & 0x3fffc00),
+             addr);
+  bfd_put_32 (output_bfd,
+             bfd_get_32 (output_bfd, addr + 4)
+             | ((value << 10) & 0x3fffc00),
+             addr + 4);
 }
-\f
+
+#else
 /* The size in bytes of an entry in the procedure linkage table.  */
 
 #define PLT_ENTRY_SIZE 28
 
 /* First entry in an absolute procedure linkage table look like this.  */
 
+#if 1
+/* Note - this code has been "optimised" not to use r2.  r2 is used by
+   GCC to return the address of large strutcures, so it should not be
+   corrupted here.  This does mean however, that this PLT does not conform
+   to the SH PIC ABI.  That spec says that r0 contains the type of the PLT
+   and r2 contains the GOT id.  This version stores the GOT id in r0 and
+   ignores the type.  Loaders can easily detect this difference however,
+   since the type will always be 0 or 8, and the GOT ids will always be
+   greater than or equal to 12.  */
+static const bfd_byte elf_sh_plt0_entry_be[PLT_ENTRY_SIZE] =
+{
+  0xd0, 0x05,  /* mov.l 2f,r0 */
+  0x60, 0x02,  /* mov.l @r0,r0 */
+  0x2f, 0x06,  /* mov.l r0,@-r15 */
+  0xd0, 0x03,  /* mov.l 1f,r0 */
+  0x60, 0x02,  /* mov.l @r0,r0 */
+  0x40, 0x2b,  /* jmp @r0 */
+  0x60, 0xf6,  /*  mov.l @r15+,r0 */
+  0x00, 0x09,  /* nop */
+  0x00, 0x09,  /* nop */
+  0x00, 0x09,  /* nop */
+  0, 0, 0, 0,  /* 1: replaced with address of .got.plt + 8.  */
+  0, 0, 0, 0,  /* 2: replaced with address of .got.plt + 4.  */
+};
+
+static const bfd_byte elf_sh_plt0_entry_le[PLT_ENTRY_SIZE] =
+{
+  0x05, 0xd0,  /* mov.l 2f,r0 */
+  0x02, 0x60,  /* mov.l @r0,r0 */
+  0x06, 0x2f,  /* mov.l r0,@-r15 */
+  0x03, 0xd0,  /* mov.l 1f,r0 */
+  0x02, 0x60,  /* mov.l @r0,r0 */
+  0x2b, 0x40,  /* jmp @r0 */
+  0xf6, 0x60,  /*  mov.l @r15+,r0 */
+  0x09, 0x00,  /* nop */
+  0x09, 0x00,  /* nop */
+  0x09, 0x00,  /* nop */
+  0, 0, 0, 0,  /* 1: replaced with address of .got.plt + 8.  */
+  0, 0, 0, 0,  /* 2: replaced with address of .got.plt + 4.  */
+};
+
+/* Sebsequent entries in an absolute procedure linkage table look like
+   this.  */
+
+static const bfd_byte elf_sh_plt_entry_be[PLT_ENTRY_SIZE] =
+{
+  0xd0, 0x04,  /* mov.l 1f,r0 */
+  0x60, 0x02,  /* mov.l @r0,r0 */
+  0xd1, 0x02,  /* mov.l 0f,r1 */
+  0x40, 0x2b,   /* jmp @r0 */
+  0x60, 0x13,  /*  mov r1,r0 */
+  0xd1, 0x03,  /* mov.l 2f,r1 */
+  0x40, 0x2b,  /* jmp @r0 */
+  0x00, 0x09,  /* nop */
+  0, 0, 0, 0,  /* 0: replaced with address of .PLT0.  */
+  0, 0, 0, 0,  /* 1: replaced with address of this symbol in .got.  */
+  0, 0, 0, 0,  /* 2: replaced with offset into relocation table.  */
+};
+
+static const bfd_byte elf_sh_plt_entry_le[PLT_ENTRY_SIZE] =
+{
+  0x04, 0xd0,  /* mov.l 1f,r0 */
+  0x02, 0x60,  /* mov.l @r0,r0 */
+  0x02, 0xd1,  /* mov.l 0f,r1 */
+  0x2b, 0x40,   /* jmp @r0 */
+  0x13, 0x60,  /*  mov r1,r0 */
+  0x03, 0xd1,  /* mov.l 2f,r1 */
+  0x2b, 0x40,  /* jmp @r0 */
+  0x09, 0x00,  /*  nop */
+  0, 0, 0, 0,  /* 0: replaced with address of .PLT0.  */
+  0, 0, 0, 0,  /* 1: replaced with address of this symbol in .got.  */
+  0, 0, 0, 0,  /* 2: replaced with offset into relocation table.  */
+};
+
+/* Entries in a PIC procedure linkage table look like this.  */
+
+static const bfd_byte elf_sh_pic_plt_entry_be[PLT_ENTRY_SIZE] =
+{
+  0xd0, 0x04,  /* mov.l 1f,r0 */
+  0x00, 0xce,  /* mov.l @(r0,r12),r0 */
+  0x40, 0x2b,  /* jmp @r0 */
+  0x00, 0x09,  /*  nop */
+  0x50, 0xc2,  /* mov.l @(8,r12),r0 */
+  0xd1, 0x03,  /* mov.l 2f,r1 */
+  0x40, 0x2b,  /* jmp @r0 */
+  0x50, 0xc1,  /*  mov.l @(4,r12),r0 */
+  0x00, 0x09,  /* nop */
+  0x00, 0x09,  /* nop */
+  0, 0, 0, 0,  /* 1: replaced with address of this symbol in .got.  */
+  0, 0, 0, 0    /* 2: replaced with offset into relocation table.  */
+};
+
+static const bfd_byte elf_sh_pic_plt_entry_le[PLT_ENTRY_SIZE] =
+{
+  0x04, 0xd0,  /* mov.l 1f,r0 */
+  0xce, 0x00,  /* mov.l @(r0,r12),r0 */
+  0x2b, 0x40,  /* jmp @r0 */
+  0x09, 0x00,  /*  nop */
+  0xc2, 0x50,  /* mov.l @(8,r12),r0 */
+  0x03, 0xd1,  /* mov.l 2f,r1 */
+  0x2b, 0x40,  /* jmp @r0 */
+  0xc1, 0x50,  /*  mov.l @(4,r12),r0 */
+  0x09, 0x00,  /*  nop */
+  0x09, 0x00,  /* nop */
+  0, 0, 0, 0,  /* 1: replaced with address of this symbol in .got.  */
+  0, 0, 0, 0    /* 2: replaced with offset into relocation table.  */
+};
+
+#else /* These are the old style PLT entries.  */
 static const bfd_byte elf_sh_plt0_entry_be[PLT_ENTRY_SIZE] =
 {
   0xd0, 0x04,  /* mov.l 1f,r0 */
@@ -2189,6 +3396,7 @@ static const bfd_byte elf_sh_pic_plt_entry_le[PLT_ENTRY_SIZE] =
   0, 0, 0, 0,  /* 1: replaced with address of this symbol in .got.  */
   0, 0, 0, 0    /* 2: replaced with offset into relocation table.  */
 };
+#endif /* old style PLT entries.  */
 
 static const bfd_byte *elf_sh_plt0_entry;
 static const bfd_byte *elf_sh_plt_entry;
@@ -2214,6 +3422,7 @@ static const bfd_byte *elf_sh_pic_plt_entry;
 
 /* Return offset of the relocation in PLT entry.  */
 #define elf_sh_plt_reloc_offset(info) 24
+#endif
 
 /* The sh linker needs to keep track of the number of relocs that it
    decides to copy in check_relocs for each symbol.  This is so that
@@ -2240,6 +3449,10 @@ struct elf_sh_link_hash_entry
 {
   struct elf_link_hash_entry root;
 
+#ifdef INCLUDE_SHMEDIA
+  bfd_vma datalabel_got_offset;
+#endif
+
   /* Number of PC relative relocs copied for this symbol.  */
   struct elf_sh_pcrel_relocs_copied *pcrel_relocs_copied;
 };
@@ -2296,6 +3509,9 @@ sh_elf_link_hash_newfunc (entry, table, string)
   if (ret != (struct elf_sh_link_hash_entry *) NULL)
     {
       ret->pcrel_relocs_copied = NULL;
+#ifdef INCLUDE_SHMEDIA
+      ret->datalabel_got_offset = (bfd_vma) -1;
+#endif
     }
 
   return (struct bfd_hash_entry *) ret;
@@ -2308,9 +3524,9 @@ sh_elf_link_hash_table_create (abfd)
      bfd *abfd;
 {
   struct elf_sh_link_hash_table *ret;
+  bfd_size_type amt = sizeof (struct elf_sh_link_hash_table);
 
-  ret = ((struct elf_sh_link_hash_table *)
-        bfd_alloc (abfd, sizeof (struct elf_sh_link_hash_table)));
+  ret = (struct elf_sh_link_hash_table *) bfd_alloc (abfd, amt);
   if (ret == (struct elf_sh_link_hash_table *) NULL)
     return NULL;
 
@@ -2412,7 +3628,7 @@ sh_elf_create_dynamic_sections (abfd, info)
            || ((secflags & SEC_HAS_CONTENTS) != SEC_HAS_CONTENTS))
          continue;
        secname = bfd_get_section_name (abfd, sec);
-       relname = (char *) bfd_malloc (strlen (secname) + 6);
+       relname = (char *) bfd_malloc ((bfd_size_type) strlen (secname) + 6);
        strcpy (relname, ".rela");
        strcat (relname, secname);
        s = bfd_make_section (abfd, relname);
@@ -2640,14 +3856,13 @@ sh_elf_adjust_dynamic_symbol (info, h)
 
 static boolean
 sh_elf_size_dynamic_sections (output_bfd, info)
-     bfd *output_bfd;
+     bfd *output_bfd ATTRIBUTE_UNUSED;
      struct bfd_link_info *info;
 {
   bfd *dynobj;
   asection *s;
   boolean plt;
   boolean relocs;
-  boolean reltext;
 
   dynobj = elf_hash_table (info)->dynobj;
   BFD_ASSERT (dynobj != NULL);
@@ -2689,7 +3904,6 @@ sh_elf_size_dynamic_sections (output_bfd, info)
      memory for them.  */
   plt = false;
   relocs = false;
-  reltext = false;
   for (s = dynobj->sections; s != NULL; s = s->next)
     {
       const char *name;
@@ -2735,29 +3949,10 @@ sh_elf_size_dynamic_sections (output_bfd, info)
            }
          else
            {
-             asection *target;
-
              /* Remember whether there are any reloc sections other
                 than .rela.plt.  */
              if (strcmp (name, ".rela.plt") != 0)
-               {
-                 const char *outname;
-
-                 relocs = true;
-
-                 /* If this relocation section applies to a read only
-                    section, then we probably need a DT_TEXTREL
-                    entry.  The entries in the .rela.plt section
-                    really apply to the .got section, which we
-                    created ourselves and so know is not readonly.  */
-                 outname = bfd_get_section_name (output_bfd,
-                                                 s->output_section);
-                 target = bfd_get_section_by_name (output_bfd, outname + 5);
-                 if (target != NULL
-                     && (target->flags & SEC_READONLY) != 0
-                     && (target->flags & SEC_ALLOC) != 0)
-                   reltext = true;
-               }
+               relocs = true;
 
              /* We use the reloc_count field as a counter if we need
                 to copy relocs into the output file.  */
@@ -2789,36 +3984,39 @@ sh_elf_size_dynamic_sections (output_bfd, info)
         must add the entries now so that we get the correct size for
         the .dynamic section.  The DT_DEBUG entry is filled in by the
         dynamic linker and used by the debugger.  */
+#define add_dynamic_entry(TAG, VAL) \
+  bfd_elf32_add_dynamic_entry (info, (bfd_vma) (TAG), (bfd_vma) (VAL))
+
       if (! info->shared)
        {
-         if (! bfd_elf32_add_dynamic_entry (info, DT_DEBUG, 0))
+         if (!add_dynamic_entry (DT_DEBUG, 0))
            return false;
        }
 
       if (plt)
        {
-         if (! bfd_elf32_add_dynamic_entry (info, DT_PLTGOT, 0)
-             || ! bfd_elf32_add_dynamic_entry (info, DT_PLTRELSZ, 0)
-             || ! bfd_elf32_add_dynamic_entry (info, DT_PLTREL, DT_RELA)
-             || ! bfd_elf32_add_dynamic_entry (info, DT_JMPREL, 0))
+         if (!add_dynamic_entry (DT_PLTGOT, 0)
+             || !add_dynamic_entry (DT_PLTRELSZ, 0)
+             || !add_dynamic_entry (DT_PLTREL, DT_RELA)
+             || !add_dynamic_entry (DT_JMPREL, 0))
            return false;
        }
 
       if (relocs)
        {
-         if (! bfd_elf32_add_dynamic_entry (info, DT_RELA, 0)
-             || ! bfd_elf32_add_dynamic_entry (info, DT_RELASZ, 0)
-             || ! bfd_elf32_add_dynamic_entry (info, DT_RELAENT,
-                                               sizeof (Elf32_External_Rela)))
+         if (!add_dynamic_entry (DT_RELA, 0)
+             || !add_dynamic_entry (DT_RELASZ, 0)
+             || !add_dynamic_entry (DT_RELAENT, sizeof (Elf32_External_Rela)))
            return false;
        }
 
-      if (reltext)
+      if ((info->flags & DF_TEXTREL) != 0)
        {
-         if (! bfd_elf32_add_dynamic_entry (info, DT_TEXTREL, 0))
+         if (!add_dynamic_entry (DT_TEXTREL, 0))
            return false;
        }
     }
+#undef add_dynamic_entry
 
   return true;
 }
@@ -2852,7 +4050,7 @@ sh_elf_discard_copies (h, ignore)
 static boolean
 sh_elf_relocate_section (output_bfd, info, input_bfd, input_section,
                         contents, relocs, local_syms, local_sections)
-     bfd *output_bfd ATTRIBUTE_UNUSED;
+     bfd *output_bfd;
      struct bfd_link_info *info;
      bfd *input_bfd;
      asection *input_section;
@@ -2867,6 +4065,7 @@ sh_elf_relocate_section (output_bfd, info, input_bfd, input_section,
   bfd *dynobj;
   bfd_vma *local_got_offsets;
   asection *sgot;
+  asection *sgotplt;
   asection *splt;
   asection *sreloc;
 
@@ -2876,6 +4075,7 @@ sh_elf_relocate_section (output_bfd, info, input_bfd, input_section,
   local_got_offsets = elf_local_got_offsets (input_bfd);
 
   sgot = NULL;
+  sgotplt = NULL;
   splt = NULL;
   sreloc = NULL;
 
@@ -2892,6 +4092,7 @@ sh_elf_relocate_section (output_bfd, info, input_bfd, input_section,
       bfd_vma relocation;
       bfd_vma addend = (bfd_vma) 0;
       bfd_reloc_status_type r;
+      int seen_stt_datalabel = 0;
 
       r_symndx = ELF32_R_SYM (rel->r_info);
 
@@ -2909,6 +4110,10 @@ sh_elf_relocate_section (output_bfd, info, input_bfd, input_section,
          || r_type >= R_SH_max
          || (r_type >= (int) R_SH_FIRST_INVALID_RELOC
              && r_type <= (int) R_SH_LAST_INVALID_RELOC)
+         || (   r_type >= (int) R_SH_FIRST_INVALID_RELOC_3
+             && r_type <= (int) R_SH_LAST_INVALID_RELOC_3)
+         || (   r_type >= (int) R_SH_FIRST_INVALID_RELOC_4
+             && r_type <= (int) R_SH_LAST_INVALID_RELOC_4)
          || (r_type >= (int) R_SH_FIRST_INVALID_RELOC_2
              && r_type <= (int) R_SH_LAST_INVALID_RELOC_2))
        {
@@ -2918,7 +4123,11 @@ sh_elf_relocate_section (output_bfd, info, input_bfd, input_section,
 
       howto = sh_elf_howto_table + r_type;
 
-      /* This is a final link.  */
+      /* For relocs that aren't partial_inplace, we get the addend from
+         the relocation.  */
+      if (! howto->partial_inplace)
+       addend = rel->r_addend;
+
       h = NULL;
       sym = NULL;
       sec = NULL;
@@ -2929,7 +4138,14 @@ sh_elf_relocate_section (output_bfd, info, input_bfd, input_section,
          relocation = (sec->output_section->vma
                        + sec->output_offset
                        + sym->st_value);
-
+         /* A local symbol never has STO_SH5_ISA32, so we don't need
+            datalabel processing here.  Make sure this does not change
+            without notice.  */
+         if ((sym->st_other & STO_SH5_ISA32) != 0)
+           ((*info->callbacks->reloc_dangerous)
+            (info,
+             _("Unexpected STO_SH5_ISA32 on local symbol is not handled"),
+             input_bfd, input_section, rel->r_offset));
          if (info->relocateable)
            {
              /* This is a relocateable link.  We don't have to change
@@ -2938,10 +4154,64 @@ sh_elf_relocate_section (output_bfd, info, input_bfd, input_section,
                 section symbol winds up in the output section.  */
              sym = local_syms + r_symndx;
              if (ELF_ST_TYPE (sym->st_info) == STT_SECTION)
-               goto final_link_relocate;
+               {
+                 if (! howto->partial_inplace)
+                   {
+                     /* For relocations with the addend in the
+                        relocation, we need just to update the addend.
+                        All real relocs are of type partial_inplace; this
+                        code is mostly for completeness.  */
+                     rel->r_addend += sec->output_offset + sym->st_value;
+
+                     continue;
+                   }
+
+                 /* Relocs of type partial_inplace need to pick up the
+                    contents in the contents and add the offset resulting
+                    from the changed location of the section symbol.
+                    Using _bfd_final_link_relocate (e.g. goto
+                    final_link_relocate) here would be wrong, because
+                    relocations marked pc_relative would get the current
+                    location subtracted, and we must only do that at the
+                    final link.  */
+                 r = _bfd_relocate_contents (howto, input_bfd,
+                                             sec->output_offset
+                                             + sym->st_value,
+                                             contents + rel->r_offset);
+                 goto relocation_done;
+               }
 
              continue;
            }
+         else if (! howto->partial_inplace)
+           {
+             relocation = _bfd_elf_rela_local_sym (output_bfd, sym, sec, rel);
+             addend = rel->r_addend;
+           }
+         else if ((sec->flags & SEC_MERGE)
+                  && ELF_ST_TYPE (sym->st_info) == STT_SECTION)
+           {
+             asection *msec;
+
+             if (howto->rightshift || howto->src_mask != 0xffffffff)
+               {
+                 (*_bfd_error_handler)
+                   (_("%s(%s+0x%lx): %s relocation against SEC_MERGE section"),
+                    bfd_archive_filename (input_bfd),
+                    bfd_get_section_name (input_bfd, input_section),
+                    (long) rel->r_offset, howto->name);
+                 return false;
+               }
+
+              addend = bfd_get_32 (input_bfd, contents + rel->r_offset);
+              msec = sec;
+              addend =
+               _bfd_elf_rel_local_sym (output_bfd, sym, &msec, addend)
+               - relocation;
+             addend += msec->output_section->vma + msec->output_offset;
+             bfd_put_32 (input_bfd, addend, contents + rel->r_offset);
+             addend = 0;
+           }
        }
       else
        {
@@ -2954,7 +4224,15 @@ sh_elf_relocate_section (output_bfd, info, input_bfd, input_section,
          h = sym_hashes[r_symndx - symtab_hdr->sh_info];
          while (h->root.type == bfd_link_hash_indirect
                 || h->root.type == bfd_link_hash_warning)
-           h = (struct elf_link_hash_entry *) h->root.u.i.link;
+           {
+#ifdef INCLUDE_SHMEDIA
+             /* If the reference passes a symbol marked with
+                STT_DATALABEL, then any STO_SH5_ISA32 on the final value
+                doesn't count.  */
+             seen_stt_datalabel |= h->type == STT_DATALABEL;
+#endif
+             h = (struct elf_link_hash_entry *) h->root.u.i.link;
+           }
          if (h->root.type == bfd_link_hash_defined
              || h->root.type == bfd_link_hash_defweak)
            {
@@ -2963,9 +4241,21 @@ sh_elf_relocate_section (output_bfd, info, input_bfd, input_section,
                 We check specially because in some obscure cases
                 sec->output_section will be NULL.  */
              if (r_type == R_SH_GOTPC
-                 || (r_type == R_SH_PLT32
+                 || r_type == R_SH_GOTPC_LOW16
+                 || r_type == R_SH_GOTPC_MEDLOW16
+                 || r_type == R_SH_GOTPC_MEDHI16
+                 || r_type == R_SH_GOTPC_HI16
+                 || ((r_type == R_SH_PLT32
+                      || r_type == R_SH_PLT_LOW16
+                      || r_type == R_SH_PLT_MEDLOW16
+                      || r_type == R_SH_PLT_MEDHI16
+                      || r_type == R_SH_PLT_HI16)
                      && h->plt.offset != (bfd_vma) -1)
-                 || (r_type == R_SH_GOT32
+                 || ((r_type == R_SH_GOT32
+                      || r_type == R_SH_GOT_LOW16
+                      || r_type == R_SH_GOT_MEDLOW16
+                      || r_type == R_SH_GOT_MEDHI16
+                      || r_type == R_SH_GOT_HI16)
                      && elf_hash_table (info)->dynamic_sections_created
                      && (! info->shared
                          || (! info->symbolic && h->dynindx != -1)
@@ -2995,18 +4285,25 @@ sh_elf_relocate_section (output_bfd, info, input_bfd, input_section,
                {
                  (*_bfd_error_handler)
                    (_("%s: warning: unresolvable relocation against symbol `%s' from %s section"),
-                    bfd_get_filename (input_bfd), h->root.root.string,
+                    bfd_archive_filename (input_bfd), h->root.root.string,
                     bfd_get_section_name (input_bfd, input_section));
                  relocation = 0;
                }
              else
-               relocation = (h->root.u.def.value
+               relocation = ((h->root.u.def.value
                              + sec->output_section->vma
-                             + sec->output_offset);
+                             + sec->output_offset)
+                             /* A STO_SH5_ISA32 causes a "bitor 1" to the
+                                symbol value, unless we've seen
+                                STT_DATALABEL on the way to it.  */
+                             | ((h->other & STO_SH5_ISA32) != 0
+                                && ! seen_stt_datalabel));
            }
          else if (h->root.type == bfd_link_hash_undefweak)
            relocation = 0;
-         else if (info->shared && !info->symbolic && !info->no_undefined)
+         else if (info->shared
+              && (!info->symbolic || info->allow_shlib_undefined)
+              && !info->no_undefined)
            relocation = 0;
          else
            {
@@ -3029,22 +4326,60 @@ sh_elf_relocate_section (output_bfd, info, input_bfd, input_section,
          break;
 
        case R_SH_IND12W:
+         relocation -= 4;
+         goto final_link_relocate;
+
        case R_SH_DIR8WPN:
        case R_SH_DIR8WPZ:
        case R_SH_DIR8WPL:
-         /* These should normally be handled by the assembler, but at
-            least IND12W is generated by ourselves, so we must deal
-            with it.  */
-         relocation -= 4;
-         goto final_link_relocate;
+         /* If the reloc is against the start of this section, then
+            the assembler has already taken care of it and the reloc
+            is here only to assist in relaxing.  If the reloc is not
+            against the start of this section, then it's against an
+            external symbol and we must deal with it ourselves.  */
+         if (input_section->output_section->vma + input_section->output_offset
+             != relocation)
+           {
+             int disp = (relocation
+                         - input_section->output_section->vma
+                         - input_section->output_offset
+                         - rel->r_offset);
+             int mask = 0;
+             switch (r_type)
+               {
+               case R_SH_DIR8WPN:
+               case R_SH_DIR8WPZ: mask = 1; break;
+               case R_SH_DIR8WPL: mask = 3; break;
+               default: mask = 0; break;
+               }
+             if (disp & mask)
+               {
+                 ((*_bfd_error_handler)
+                  (_("%s: 0x%lx: fatal: unaligned branch target for relax-support relocation"),
+                   bfd_archive_filename (input_section->owner),
+                   (unsigned long) rel->r_offset));
+                 bfd_set_error (bfd_error_bad_value);
+                 return false;
+               }
+             relocation -= 4;
+             goto final_link_relocate;
+           }
+         r = bfd_reloc_ok;
+         break;
 
        default:
+#ifdef INCLUDE_SHMEDIA
+         if (shmedia_prepare_reloc (info, input_bfd, input_section,
+                                    contents, rel, &relocation))
+           goto final_link_relocate;
+#endif
          bfd_set_error (bfd_error_bad_value);
          return false;
 
        case R_SH_DIR32:
        case R_SH_REL32:
          if (info->shared
+             && r_symndx != 0
              && (input_section->flags & SEC_ALLOC) != 0
              && (r_type != R_SH_REL32
                  || (h != NULL
@@ -3082,22 +4417,11 @@ sh_elf_relocate_section (output_bfd, info, input_bfd, input_section,
 
              skip = false;
 
-             if (elf_section_data (input_section)->stab_info == NULL)
-               outrel.r_offset = rel->r_offset;
-             else
-               {
-                 bfd_vma off;
-
-                 off = (_bfd_stab_section_offset
-                        (output_bfd, &elf_hash_table (info)->stab_info,
-                         input_section,
-                         &elf_section_data (input_section)->stab_info,
-                         rel->r_offset));
-                 if (off == (bfd_vma) -1)
-                   skip = true;
-                 outrel.r_offset = off;
-               }
-
+             outrel.r_offset =
+               _bfd_elf_section_offset (output_bfd, info, input_section,
+                                        rel->r_offset);
+             if (outrel.r_offset == (bfd_vma) -1)
+               skip = true;
              outrel.r_offset += (input_section->output_section->vma
                                  + input_section->output_offset);
 
@@ -3111,7 +4435,8 @@ sh_elf_relocate_section (output_bfd, info, input_bfd, input_section,
                  BFD_ASSERT (h != NULL && h->dynindx != -1);
                  relocate = false;
                  outrel.r_info = ELF32_R_INFO (h->dynindx, R_SH_REL32);
-                 outrel.r_addend = rel->r_addend;
+                 outrel.r_addend
+                   = bfd_get_32 (input_bfd, contents + rel->r_offset);
                }
              else
                {
@@ -3124,14 +4449,18 @@ sh_elf_relocate_section (output_bfd, info, input_bfd, input_section,
                    {
                      relocate = true;
                      outrel.r_info = ELF32_R_INFO (0, R_SH_RELATIVE);
-                     outrel.r_addend = relocation + rel->r_addend;
+                     outrel.r_addend
+                       = relocation + bfd_get_32 (input_bfd,
+                                                  contents + rel->r_offset);
                    }
                  else
                    {
                      BFD_ASSERT (h->dynindx != -1);
                      relocate = false;
                      outrel.r_info = ELF32_R_INFO (h->dynindx, R_SH_DIR32);
-                     outrel.r_addend = relocation + rel->r_addend;
+                     outrel.r_addend
+                       = relocation + bfd_get_32 (input_bfd,
+                                                  contents + rel->r_offset);
                    }
                }
 
@@ -3148,11 +4477,58 @@ sh_elf_relocate_section (output_bfd, info, input_bfd, input_section,
              if (! relocate)
                continue;
            }
-         else if (r_type == R_SH_DIR32)
-           addend = rel->r_addend;
          goto final_link_relocate;
 
+       case R_SH_GOTPLT32:
+#ifdef INCLUDE_SHMEDIA
+       case R_SH_GOTPLT_LOW16:
+       case R_SH_GOTPLT_MEDLOW16:
+       case R_SH_GOTPLT_MEDHI16:
+       case R_SH_GOTPLT_HI16:
+       case R_SH_GOTPLT10BY4:
+       case R_SH_GOTPLT10BY8:
+#endif
+         /* Relocation is to the entry for this symbol in the
+            procedure linkage table.  */
+
+         if (h == NULL
+             || ELF_ST_VISIBILITY (h->other) == STV_INTERNAL
+             || ELF_ST_VISIBILITY (h->other) == STV_HIDDEN
+             || ! info->shared
+             || info->symbolic
+             || h->dynindx == -1
+             || h->plt.offset == (bfd_vma) -1
+             || h->got.offset != (bfd_vma) -1)
+           goto force_got;
+
+         /* Relocation is to the entry for this symbol in the global
+            offset table extension for the procedure linkage table.  */
+         if (sgotplt == NULL)
+           {
+             sgotplt = bfd_get_section_by_name (dynobj, ".got.plt");
+             BFD_ASSERT (sgotplt != NULL);
+           }
+
+         relocation = (sgotplt->output_offset
+                       + ((h->plt.offset / elf_sh_sizeof_plt (info)
+                           - 1 + 3) * 4));
+
+#ifdef GOT_BIAS
+         relocation -= GOT_BIAS;
+#endif
+
+         goto final_link_relocate;
+
+       force_got:
        case R_SH_GOT32:
+#ifdef INCLUDE_SHMEDIA
+       case R_SH_GOT_LOW16:
+       case R_SH_GOT_MEDLOW16:
+       case R_SH_GOT_MEDHI16:
+       case R_SH_GOT_HI16:
+       case R_SH_GOT10BY4:
+       case R_SH_GOT10BY8:
+#endif
          /* Relocation is to the entry for this symbol in the global
             offset table.  */
          if (sgot == NULL)
@@ -3166,6 +4542,15 @@ sh_elf_relocate_section (output_bfd, info, input_bfd, input_section,
              bfd_vma off;
 
              off = h->got.offset;
+#ifdef INCLUDE_SHMEDIA
+             if (seen_stt_datalabel)
+               {
+                 struct elf_sh_link_hash_entry *hsh;
+
+                 hsh = (struct elf_sh_link_hash_entry *)h;
+                 off = hsh->datalabel_got_offset;
+               }
+#endif
              BFD_ASSERT (off != (bfd_vma) -1);
 
              if (! elf_hash_table (info)->dynamic_sections_created
@@ -3193,7 +4578,17 @@ sh_elf_relocate_section (output_bfd, info, input_bfd, input_section,
                    {
                      bfd_put_32 (output_bfd, relocation,
                                  sgot->contents + off);
-                     h->got.offset |= 1;
+#ifdef INCLUDE_SHMEDIA
+                     if (seen_stt_datalabel)
+                       {
+                         struct elf_sh_link_hash_entry *hsh;
+
+                         hsh = (struct elf_sh_link_hash_entry *)h;
+                         hsh->datalabel_got_offset |= 1;
+                       }
+                     else
+#endif
+                       h->got.offset |= 1;
                    }
                }
 
@@ -3203,10 +4598,27 @@ sh_elf_relocate_section (output_bfd, info, input_bfd, input_section,
            {
              bfd_vma off;
 
+#ifdef INCLUDE_SHMEDIA
+             if (rel->r_addend)
+               {
+                 BFD_ASSERT (local_got_offsets != NULL
+                             && (local_got_offsets[symtab_hdr->sh_info
+                                                   + r_symndx]
+                                 != (bfd_vma) -1));
+
+                 off = local_got_offsets[symtab_hdr->sh_info
+                                         + r_symndx];
+               }
+             else
+               {
+#endif
              BFD_ASSERT (local_got_offsets != NULL
                          && local_got_offsets[r_symndx] != (bfd_vma) -1);
 
              off = local_got_offsets[r_symndx];
+#ifdef INCLUDE_SHMEDIA
+               }
+#endif
 
              /* The offset must always be a multiple of 4.  We use
                 the least significant bit to record whether we have
@@ -3237,15 +4649,30 @@ sh_elf_relocate_section (output_bfd, info, input_bfd, input_section,
                      ++srelgot->reloc_count;
                    }
 
-                 local_got_offsets[r_symndx] |= 1;
+#ifdef INCLUDE_SHMEDIA
+                 if (rel->r_addend)
+                   local_got_offsets[symtab_hdr->sh_info + r_symndx] |= 1;
+                 else
+#endif
+                   local_got_offsets[r_symndx] |= 1;
                }
 
              relocation = sgot->output_offset + off;
            }
 
+#ifdef GOT_BIAS
+         relocation -= GOT_BIAS;
+#endif
+
          goto final_link_relocate;
 
        case R_SH_GOTOFF:
+#ifdef INCLUDE_SHMEDIA
+       case R_SH_GOTOFF_LOW16:
+       case R_SH_GOTOFF_MEDLOW16:
+       case R_SH_GOTOFF_MEDHI16:
+       case R_SH_GOTOFF_HI16:
+#endif
          /* Relocation is relative to the start of the global offset
             table.  */
 
@@ -3262,9 +4689,21 @@ sh_elf_relocate_section (output_bfd, info, input_bfd, input_section,
             calculation.  */
          relocation -= sgot->output_section->vma;
 
+#ifdef GOT_BIAS
+         relocation -= GOT_BIAS;
+#endif
+
+         addend = rel->r_addend;
+
          goto final_link_relocate;
 
        case R_SH_GOTPC:
+#ifdef INCLUDE_SHMEDIA
+       case R_SH_GOTPC_LOW16:
+       case R_SH_GOTPC_MEDLOW16:
+       case R_SH_GOTPC_MEDHI16:
+       case R_SH_GOTPC_HI16:
+#endif
          /* Use global offset table as symbol value.  */
 
          if (sgot == NULL)
@@ -3275,9 +4714,21 @@ sh_elf_relocate_section (output_bfd, info, input_bfd, input_section,
 
          relocation = sgot->output_section->vma;
 
+#ifdef GOT_BIAS
+         relocation += GOT_BIAS;
+#endif
+
+         addend = rel->r_addend;
+
          goto final_link_relocate;
 
        case R_SH_PLT32:
+#ifdef INCLUDE_SHMEDIA
+       case R_SH_PLT_LOW16:
+       case R_SH_PLT_MEDLOW16:
+       case R_SH_PLT_MEDHI16:
+       case R_SH_PLT_HI16:
+#endif
          /* Relocation is to the entry for this symbol in the
             procedure linkage table.  */
 
@@ -3308,6 +4759,12 @@ sh_elf_relocate_section (output_bfd, info, input_bfd, input_section,
                        + splt->output_offset
                        + h->plt.offset);
 
+#ifdef INCLUDE_SHMEDIA
+         relocation++;
+#endif
+
+         addend = rel->r_addend;
+
          goto final_link_relocate;
 
        case R_SH_LOOP_START:
@@ -3329,6 +4786,7 @@ sh_elf_relocate_section (output_bfd, info, input_bfd, input_section,
          }
        }
 
+    relocation_done:
       if (r != bfd_reloc_ok)
        {
          switch (r)
@@ -3378,11 +4836,14 @@ sh_elf_get_relocated_section_contents (output_bfd, link_info, link_order,
      asymbol **symbols;
 {
   Elf_Internal_Shdr *symtab_hdr;
+  Elf_Internal_Shdr *shndx_hdr;
   asection *input_section = link_order->u.indirect.section;
   bfd *input_bfd = input_section->owner;
   asection **sections = NULL;
   Elf_Internal_Rela *internal_relocs = NULL;
   Elf32_External_Sym *external_syms = NULL;
+  Elf_External_Sym_Shndx *shndx_buf = NULL;
+  Elf_External_Sym_Shndx *shndx;
   Elf_Internal_Sym *internal_syms = NULL;
 
   /* We only need to handle the case of relaxing, or of having a
@@ -3395,9 +4856,10 @@ sh_elf_get_relocated_section_contents (output_bfd, link_info, link_order,
                                                       symbols);
 
   symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
+  shndx_hdr = &elf_tdata (input_bfd)->symtab_shndx_hdr;
 
   memcpy (data, elf_section_data (input_section)->this_hdr.contents,
-         input_section->_raw_size);
+         (size_t) input_section->_raw_size);
 
   if ((input_section->flags & SEC_RELOC) != 0
       && input_section->reloc_count > 0)
@@ -3405,20 +4867,31 @@ sh_elf_get_relocated_section_contents (output_bfd, link_info, link_order,
       Elf_Internal_Sym *isymp;
       asection **secpp;
       Elf32_External_Sym *esym, *esymend;
+      bfd_size_type amt;
 
       if (symtab_hdr->contents != NULL)
        external_syms = (Elf32_External_Sym *) symtab_hdr->contents;
-      else
+      else if (symtab_hdr->sh_info != 0)
        {
-         external_syms = ((Elf32_External_Sym *)
-                          bfd_malloc (symtab_hdr->sh_info
-                                      * sizeof (Elf32_External_Sym)));
-         if (external_syms == NULL && symtab_hdr->sh_info > 0)
+         amt = symtab_hdr->sh_info;
+         amt *= sizeof (Elf32_External_Sym);
+         external_syms = (Elf32_External_Sym *) bfd_malloc (amt);
+         if (external_syms == NULL)
            goto error_return;
          if (bfd_seek (input_bfd, symtab_hdr->sh_offset, SEEK_SET) != 0
-             || (bfd_read (external_syms, sizeof (Elf32_External_Sym),
-                           symtab_hdr->sh_info, input_bfd)
-                 != (symtab_hdr->sh_info * sizeof (Elf32_External_Sym))))
+             || bfd_bread ((PTR) external_syms, amt, input_bfd) != amt)
+           goto error_return;
+       }
+
+      if (symtab_hdr->sh_info != 0 && shndx_hdr->sh_size != 0)
+       {
+         amt = symtab_hdr->sh_info;
+         amt *= sizeof (Elf_External_Sym_Shndx);
+         shndx_buf = (Elf_External_Sym_Shndx *) bfd_malloc (amt);
+         if (shndx_buf == NULL)
+           goto error_return;
+         if (bfd_seek (input_bfd, shndx_hdr->sh_offset, SEEK_SET) != 0
+             || bfd_bread ((PTR) shndx_buf, amt, input_bfd) != amt)
            goto error_return;
        }
 
@@ -3428,40 +4901,35 @@ sh_elf_get_relocated_section_contents (output_bfd, link_info, link_order,
       if (internal_relocs == NULL)
        goto error_return;
 
-      internal_syms = ((Elf_Internal_Sym *)
-                      bfd_malloc (symtab_hdr->sh_info
-                                  * sizeof (Elf_Internal_Sym)));
-      if (internal_syms == NULL && symtab_hdr->sh_info > 0)
+      amt = symtab_hdr->sh_info;
+      amt *= sizeof (Elf_Internal_Sym);
+      internal_syms = (Elf_Internal_Sym *) bfd_malloc (amt);
+      if (internal_syms == NULL && amt != 0)
        goto error_return;
 
-      sections = (asection **) bfd_malloc (symtab_hdr->sh_info
-                                          * sizeof (asection *));
-      if (sections == NULL && symtab_hdr->sh_info > 0)
+      amt = symtab_hdr->sh_info;
+      amt *= sizeof (asection *);
+      sections = (asection **) bfd_malloc (amt);
+      if (sections == NULL && amt != 0)
        goto error_return;
 
-      isymp = internal_syms;
-      secpp = sections;
-      esym = external_syms;
-      esymend = esym + symtab_hdr->sh_info;
-      for (; esym < esymend; ++esym, ++isymp, ++secpp)
+      for (isymp = internal_syms, secpp = sections, shndx = shndx_buf,
+            esym = external_syms, esymend = esym + symtab_hdr->sh_info;
+          esym < esymend;
+          ++esym, ++isymp, ++secpp, shndx = (shndx ? shndx + 1 : NULL))
        {
          asection *isec;
 
-         bfd_elf32_swap_symbol_in (input_bfd, esym, isymp);
+         bfd_elf32_swap_symbol_in (input_bfd, esym, shndx, isymp);
 
          if (isymp->st_shndx == SHN_UNDEF)
            isec = bfd_und_section_ptr;
-         else if (isymp->st_shndx > 0 && isymp->st_shndx < SHN_LORESERVE)
-           isec = bfd_section_from_elf_index (input_bfd, isymp->st_shndx);
          else if (isymp->st_shndx == SHN_ABS)
            isec = bfd_abs_section_ptr;
          else if (isymp->st_shndx == SHN_COMMON)
            isec = bfd_com_section_ptr;
          else
-           {
-             /* Who knows?  */
-             isec = NULL;
-           }
+           isec = bfd_section_from_elf_index (input_bfd, isymp->st_shndx);
 
          *secpp = isec;
        }
@@ -3473,16 +4941,14 @@ sh_elf_get_relocated_section_contents (output_bfd, link_info, link_order,
 
       if (sections != NULL)
        free (sections);
-      sections = NULL;
       if (internal_syms != NULL)
        free (internal_syms);
-      internal_syms = NULL;
+      if (shndx_buf != NULL)
+       free (shndx_buf);
       if (external_syms != NULL && symtab_hdr->contents == NULL)
        free (external_syms);
-      external_syms = NULL;
       if (internal_relocs != elf_section_data (input_section)->relocs)
        free (internal_relocs);
-      internal_relocs = NULL;
     }
 
   return data;
@@ -3491,6 +4957,8 @@ sh_elf_get_relocated_section_contents (output_bfd, link_info, link_order,
   if (internal_relocs != NULL
       && internal_relocs != elf_section_data (input_section)->relocs)
     free (internal_relocs);
+  if (shndx_buf != NULL)
+    free (shndx_buf);
   if (external_syms != NULL && symtab_hdr->contents == NULL)
     free (external_syms);
   if (internal_syms != NULL)
@@ -3499,6 +4967,7 @@ sh_elf_get_relocated_section_contents (output_bfd, link_info, link_order,
     free (sections);
   return NULL;
 }
+
 static asection *
 sh_elf_gc_mark_hook (abfd, info, rel, h, sym)
      bfd *abfd;
@@ -3532,12 +5001,9 @@ sh_elf_gc_mark_hook (abfd, info, rel, h, sym)
     }
   else
     {
-      if (!(elf_bad_symtab (abfd)
-           && ELF_ST_BIND (sym->st_info) != STB_LOCAL)
-         && ! ((sym->st_shndx <= 0 || sym->st_shndx >= SHN_LORESERVE)
-                && sym->st_shndx != SHN_COMMON))
-       return bfd_section_from_elf_index (abfd, sym->st_shndx);
+      return bfd_section_from_elf_index (abfd, sym->st_shndx);
     }
+
   return NULL;
 }
 
@@ -3611,9 +5077,32 @@ sh_elf_check_relocs (abfd, info, sec, relocs)
        {
          switch (ELF32_R_TYPE (rel->r_info))
            {
+           case R_SH_GOTPLT32:
            case R_SH_GOT32:
            case R_SH_GOTOFF:
            case R_SH_GOTPC:
+#ifdef INCLUDE_SHMEDIA
+           case R_SH_GOTPLT_LOW16:
+           case R_SH_GOTPLT_MEDLOW16:
+           case R_SH_GOTPLT_MEDHI16:
+           case R_SH_GOTPLT_HI16:
+           case R_SH_GOTPLT10BY4:
+           case R_SH_GOTPLT10BY8:
+           case R_SH_GOT_LOW16:
+           case R_SH_GOT_MEDLOW16:
+           case R_SH_GOT_MEDHI16:
+           case R_SH_GOT_HI16:
+           case R_SH_GOT10BY4:
+           case R_SH_GOT10BY8:
+           case R_SH_GOTOFF_LOW16:
+           case R_SH_GOTOFF_MEDLOW16:
+           case R_SH_GOTOFF_MEDHI16:
+           case R_SH_GOTOFF_HI16:
+           case R_SH_GOTPC_LOW16:
+           case R_SH_GOTPC_MEDLOW16:
+           case R_SH_GOTPC_MEDHI16:
+           case R_SH_GOTPC_HI16:
+#endif
              elf_hash_table (info)->dynobj = dynobj = abfd;
              if (! _bfd_elf_create_got_section (dynobj, info))
                return false;
@@ -3640,7 +5129,16 @@ sh_elf_check_relocs (abfd, info, sec, relocs)
            return false;
          break;
 
+       force_got:
        case R_SH_GOT32:
+#ifdef INCLUDE_SHMEDIA
+       case R_SH_GOT_LOW16:
+       case R_SH_GOT_MEDLOW16:
+       case R_SH_GOT_MEDHI16:
+       case R_SH_GOT_HI16:
+       case R_SH_GOT10BY4:
+       case R_SH_GOT10BY8:
+#endif
          /* This symbol requires a global offset table entry.  */
 
          if (sgot == NULL)
@@ -3671,12 +5169,30 @@ sh_elf_check_relocs (abfd, info, sec, relocs)
 
          if (h != NULL)
            {
+#ifdef INCLUDE_SHMEDIA
+             if (h->type == STT_DATALABEL)
+               {
+                 struct elf_sh_link_hash_entry *hsh;
+
+                 h = (struct elf_link_hash_entry *) h->root.u.i.link;
+                 hsh = (struct elf_sh_link_hash_entry *)h;
+                 if (hsh->datalabel_got_offset != (bfd_vma) -1)
+                   break;
+
+                 hsh->datalabel_got_offset = sgot->_raw_size;
+               }
+             else
+               {
+#endif
              if (h->got.offset != (bfd_vma) -1)
                {
                  /* We have already allocated space in the .got.  */
                  break;
                }
              h->got.offset = sgot->_raw_size;
+#ifdef INCLUDE_SHMEDIA
+               }
+#endif
 
              /* Make sure this symbol is output as a dynamic symbol.  */
              if (h->dynindx == -1)
@@ -3693,23 +5209,51 @@ sh_elf_check_relocs (abfd, info, sec, relocs)
                 symbol.  */
              if (local_got_offsets == NULL)
                {
-                 size_t size;
+                 bfd_size_type size;
                  register unsigned int i;
 
-                 size = symtab_hdr->sh_info * sizeof (bfd_vma);
+                 size = symtab_hdr->sh_info;
+                 size *= sizeof (bfd_vma);
+#ifdef INCLUDE_SHMEDIA
+                 /* Reserve space for both the datalabel and
+                    codelabel local GOT offsets.  */
+                 size *= 2;
+#endif
                  local_got_offsets = (bfd_vma *) bfd_alloc (abfd, size);
                  if (local_got_offsets == NULL)
                    return false;
                  elf_local_got_offsets (abfd) = local_got_offsets;
                  for (i = 0; i < symtab_hdr->sh_info; i++)
                    local_got_offsets[i] = (bfd_vma) -1;
+#ifdef INCLUDE_SHMEDIA
+                 for (; i < 2 * symtab_hdr->sh_info; i++)
+                   local_got_offsets[i] = (bfd_vma) -1;
+#endif
+               }
+#ifdef INCLUDE_SHMEDIA
+             if ((rel->r_addend & 1) != 0)
+               {
+                 if (local_got_offsets[symtab_hdr->sh_info
+                                       + r_symndx] != (bfd_vma) -1)
+                   {
+                     /* We have already allocated space in the .got.  */
+                     break;
+                   }
+                 local_got_offsets[symtab_hdr->sh_info
+                                   + r_symndx] = sgot->_raw_size;
                }
+             else
+               {
+#endif
              if (local_got_offsets[r_symndx] != (bfd_vma) -1)
                {
                  /* We have already allocated space in the .got.  */
                  break;
                }
              local_got_offsets[r_symndx] = sgot->_raw_size;
+#ifdef INCLUDE_SHMEDIA
+               }
+#endif
 
              if (info->shared)
                {
@@ -3724,7 +5268,45 @@ sh_elf_check_relocs (abfd, info, sec, relocs)
 
          break;
 
+       case R_SH_GOTPLT32:
+#ifdef INCLUDE_SHMEDIA
+       case R_SH_GOTPLT_LOW16:
+       case R_SH_GOTPLT_MEDLOW16:
+       case R_SH_GOTPLT_MEDHI16:
+       case R_SH_GOTPLT_HI16:
+       case R_SH_GOTPLT10BY4:
+       case R_SH_GOTPLT10BY8:
+#endif
+         /* If this is a local symbol, we resolve it directly without
+            creating a procedure linkage table entry.  */
+
+         if (h == NULL
+             || ELF_ST_VISIBILITY (h->other) == STV_INTERNAL
+             || ELF_ST_VISIBILITY (h->other) == STV_HIDDEN
+             || ! info->shared
+             || info->symbolic
+             || h->dynindx == -1
+             || h->got.offset != (bfd_vma) -1)
+           goto force_got;
+
+         /* Make sure this symbol is output as a dynamic symbol.  */
+         if (h->dynindx == -1)
+           {
+             if (! bfd_elf32_link_record_dynamic_symbol (info, h))
+               return false;
+           }
+
+         h->elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_PLT;
+
+         break;
+
        case R_SH_PLT32:
+#ifdef INCLUDE_SHMEDIA
+       case R_SH_PLT_LOW16:
+       case R_SH_PLT_MEDLOW16:
+       case R_SH_PLT_MEDHI16:
+       case R_SH_PLT_HI16:
+#endif
          /* This symbol requires a procedure linkage table entry.  We
             actually build the entry in adjust_dynamic_symbol,
             because this might be a case of linking PIC code which is
@@ -3803,6 +5385,8 @@ sh_elf_check_relocs (abfd, info, sec, relocs)
                          || ! bfd_set_section_alignment (dynobj, sreloc, 2))
                        return false;
                    }
+                 if (sec->flags & SEC_READONLY)
+                   info->flags |= DF_TEXTREL;
                }
 
              sreloc->_raw_size += sizeof (Elf32_External_Rela);
@@ -3830,7 +5414,7 @@ sh_elf_check_relocs (abfd, info, sec, relocs)
                  if (p == NULL)
                    {
                      p = ((struct elf_sh_pcrel_relocs_copied *)
-                          bfd_alloc (dynobj, sizeof *p));
+                          bfd_alloc (dynobj, (bfd_size_type) sizeof *p));
                      if (p == NULL)
                        return false;
                      p->next = eh->pcrel_relocs_copied;
@@ -3850,6 +5434,7 @@ sh_elf_check_relocs (abfd, info, sec, relocs)
   return true;
 }
 
+#ifndef sh_elf_set_mach_from_flags
 static boolean
 sh_elf_set_mach_from_flags (abfd)
      bfd *abfd;
@@ -3885,7 +5470,9 @@ sh_elf_set_mach_from_flags (abfd)
     }
   return true;
 }
+#endif /* not sh_elf_set_mach_from_flags */
 
+#ifndef sh_elf_set_private_flags
 /* Function to keep SH specific file flags.  */
 
 static boolean
@@ -3900,7 +5487,9 @@ sh_elf_set_private_flags (abfd, flags)
   elf_flags_init (abfd) = true;
   return sh_elf_set_mach_from_flags (abfd);
 }
+#endif /* not sh_elf_set_private_flags */
 
+#ifndef sh_elf_copy_private_data
 /* Copy backend specific data from one object module to another */
 
 static boolean
@@ -3914,7 +5503,9 @@ sh_elf_copy_private_data (ibfd, obfd)
 
   return sh_elf_set_private_flags (obfd, elf_elfheader (ibfd)->e_flags);
 }
+#endif /* not sh_elf_copy_private_data */
 
+#ifndef sh_elf_merge_private_data
 /* This routine checks for linking big and little endian objects
    together, and for linking sh-dsp with sh3e / sh4 objects.  */
 
@@ -3945,7 +5536,7 @@ sh_elf_merge_private_data (ibfd, obfd)
     {
       (*_bfd_error_handler)
        ("%s: uses %s instructions while previous modules use %s instructions",
-        bfd_get_filename (ibfd),
+        bfd_archive_filename (ibfd),
         EF_SH_HAS_DSP (new_flags) ? "dsp" : "floating point",
         EF_SH_HAS_DSP (new_flags) ? "floating point" : "dsp");
       bfd_set_error (bfd_error_bad_value);
@@ -3955,6 +5546,7 @@ sh_elf_merge_private_data (ibfd, obfd)
 
   return sh_elf_set_mach_from_flags (obfd);
 }
+#endif /* not sh_elf_merge_private_data */
 
 /* Finish up dynamic symbol handling.  We set the contents of various
    dynamic sections here.  */
@@ -4001,6 +5593,10 @@ sh_elf_finish_dynamic_symbol (output_bfd, info, h, sym)
         The first three are reserved.  */
       got_offset = (plt_index + 3) * 4;
 
+#ifdef GOT_BIAS
+      got_offset -= GOT_BIAS;
+#endif
+
       /* Fill in the entry in the procedure linkage table.  */
       if (! info->shared)
        {
@@ -4011,6 +5607,19 @@ sh_elf_finish_dynamic_symbol (output_bfd, info, h, sym)
            }
          memcpy (splt->contents + h->plt.offset, elf_sh_plt_entry,
                  elf_sh_sizeof_plt (info));
+#ifdef INCLUDE_SHMEDIA
+         movi_shori_putval (output_bfd,
+                            (sgot->output_section->vma
+                             + sgot->output_offset
+                             + got_offset),
+                            (splt->contents + h->plt.offset
+                             + elf_sh_plt_symbol_offset (info)));
+
+         movi_shori_putval (output_bfd,
+                            (splt->output_section->vma + splt->output_offset),
+                            (splt->contents + h->plt.offset
+                             + elf_sh_plt_plt0_offset (info)));
+#else
          bfd_put_32 (output_bfd,
                      (sgot->output_section->vma
                       + sgot->output_offset
@@ -4022,6 +5631,7 @@ sh_elf_finish_dynamic_symbol (output_bfd, info, h, sym)
                      (splt->output_section->vma + splt->output_offset),
                      (splt->contents + h->plt.offset
                       + elf_sh_plt_plt0_offset (info)));
+#endif
        }
       else
        {
@@ -4033,14 +5643,31 @@ sh_elf_finish_dynamic_symbol (output_bfd, info, h, sym)
            }
          memcpy (splt->contents + h->plt.offset, elf_sh_pic_plt_entry,
                  elf_sh_sizeof_plt (info));
+#ifdef INCLUDE_SHMEDIA
+         movi_shori_putval (output_bfd, got_offset,
+                            (splt->contents + h->plt.offset
+                             + elf_sh_plt_symbol_offset (info)));
+#else
          bfd_put_32 (output_bfd, got_offset,
                      (splt->contents + h->plt.offset
                       + elf_sh_plt_symbol_offset (info)));
+#endif
        }
 
+#ifdef GOT_BIAS
+      got_offset += GOT_BIAS;
+#endif
+
+#ifdef INCLUDE_SHMEDIA
+      movi_shori_putval (output_bfd,
+                        plt_index * sizeof (Elf32_External_Rela),
+                        (splt->contents + h->plt.offset
+                         + elf_sh_plt_reloc_offset (info)));
+#else
       bfd_put_32 (output_bfd, plt_index * sizeof (Elf32_External_Rela),
                  (splt->contents + h->plt.offset
                   + elf_sh_plt_reloc_offset (info)));
+#endif
 
       /* Fill in the entry in the global offset table.  */
       bfd_put_32 (output_bfd,
@@ -4056,6 +5683,9 @@ sh_elf_finish_dynamic_symbol (output_bfd, info, h, sym)
                      + got_offset);
       rel.r_info = ELF32_R_INFO (h->dynindx, R_SH_JMP_SLOT);
       rel.r_addend = 0;
+#ifdef GOT_BIAS
+      rel.r_addend = GOT_BIAS;
+#endif
       bfd_elf32_swap_reloca_out (output_bfd, &rel,
                                ((Elf32_External_Rela *) srel->contents
                                 + plt_index));
@@ -4083,7 +5713,7 @@ sh_elf_finish_dynamic_symbol (output_bfd, info, h, sym)
 
       rel.r_offset = (sgot->output_section->vma
                      + sgot->output_offset
-                     + (h->got.offset &~ 1));
+                     + (h->got.offset &~ (bfd_vma) 1));
 
       /* If this is a -Bsymbolic link, and the symbol is defined
         locally, we just want to emit a RELATIVE reloc.  Likewise if
@@ -4255,12 +5885,20 @@ sh_elf_finish_dynamic_sections (output_bfd, info)
                                       elf_sh_plt0_entry_le);
                }
              memcpy (splt->contents, elf_sh_plt0_entry, PLT_ENTRY_SIZE);
+#ifdef INCLUDE_SHMEDIA
+             movi_shori_putval (output_bfd,
+                                sgot->output_section->vma
+                                + sgot->output_offset,
+                                splt->contents
+                                + elf_sh_plt0_gotplt_offset (info));
+#else
              bfd_put_32 (output_bfd,
                          sgot->output_section->vma + sgot->output_offset + 4,
                          splt->contents + elf_sh_plt0_gotid_offset (info));
              bfd_put_32 (output_bfd,
                          sgot->output_section->vma + sgot->output_offset + 8,
                          splt->contents + elf_sh_plt0_linker_offset (info));
+#endif
            }
 
          /* UnixWare sets the entsize of .plt to 4, although that doesn't
@@ -4287,6 +5925,23 @@ sh_elf_finish_dynamic_sections (output_bfd, info)
   return true;
 }
 
+static enum elf_reloc_type_class
+sh_elf_reloc_type_class (rela)
+     const Elf_Internal_Rela *rela;
+{
+  switch ((int) ELF32_R_TYPE (rela->r_info))
+    {
+    case R_SH_RELATIVE:
+      return reloc_class_relative;
+    case R_SH_JMP_SLOT:
+      return reloc_class_plt;
+    case R_SH_COPY:
+      return reloc_class_copy;
+    default:
+      return reloc_class_normal;
+    }
+}
+
 #ifndef ELF_ARCH
 #define TARGET_BIG_SYM         bfd_elf32_sh_vec
 #define TARGET_BIG_NAME                "elf32-sh"
@@ -4330,6 +5985,7 @@ sh_elf_finish_dynamic_sections (output_bfd, info)
                                        sh_elf_finish_dynamic_symbol
 #define elf_backend_finish_dynamic_sections \
                                        sh_elf_finish_dynamic_sections
+#define elf_backend_reloc_type_class   sh_elf_reloc_type_class
 
 #define elf_backend_want_got_plt       1
 #define elf_backend_plt_readonly       1
This page took 0.05945 seconds and 4 git commands to generate.