* libxcoff.h (struct xcoff_backend_data_rec): Constify src param
[binutils-gdb.git] / bfd / elf32-sh.c
index 2cca369c0acc49d12db25abdd46dc11ff37af712..9869704b49f7ce8ee7ffc5bf30989f1fc020795e 100644 (file)
@@ -1,5 +1,6 @@
 /* Hitachi SH specific support for 32-bit ELF
-   Copyright 1996, 97, 98, 1999, 2000 Free Software Foundation, Inc.
+   Copyright 1996, 1997, 1998, 1999, 2000, 2001
+   Free Software Foundation, Inc.
    Contributed by Ian Lance Taylor, Cygnus Support.
 
 This file is part of BFD, the Binary File Descriptor library.
@@ -236,118 +237,14 @@ static reloc_howto_type sh_elf_howto_table[] =
         0xff,                  /* dst_mask */
         true),                 /* pcrel_offset */
 
-  HOWTO (R_SH_GOT32,           /* 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_GOT32",          /* name */
-        true,                  /* partial_inplace */
-        0xffffffff,            /* src_mask */
-        0xffffffff,            /* dst_mask */
-        false),                /* pcrel_offset */
-
-  HOWTO (R_SH_PLT32,           /* type */
-        0,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        32,                    /* bitsize */
-        true,                  /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_bitfield, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* */
-        "R_SH_PLT32",          /* name */
-        true,                  /* partial_inplace */
-        0xffffffff,            /* src_mask */
-        0xffffffff,            /* dst_mask */
-        true),                 /* pcrel_offset */
-
-  HOWTO (R_SH_COPY,            /* 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_COPY",           /* name */
-        true,                  /* partial_inplace */
-        0xffffffff,            /* src_mask */
-        0xffffffff,            /* dst_mask */
-        false),                /* pcrel_offset */
-
-  HOWTO (R_SH_GLOB_DAT,                /* 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_GLOB_DAT",       /* name */
-        true,                  /* partial_inplace */
-        0xffffffff,            /* src_mask */
-        0xffffffff,            /* dst_mask */
-        false),                /* pcrel_offset */
-
-  HOWTO (R_SH_JMP_SLOT,                /* 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_JMP_SLOT",       /* name */
-        true,                  /* partial_inplace */
-        0xffffffff,            /* src_mask */
-        0xffffffff,            /* dst_mask */
-        false),                /* pcrel_offset */
-
-  HOWTO (R_SH_RELATIVE,                /* 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_RELATIVE",       /* name */
-        true,                  /* partial_inplace */
-        0xffffffff,            /* src_mask */
-        0xffffffff,            /* dst_mask */
-        false),                /* pcrel_offset */
-
-  HOWTO (R_SH_GOTOFF,          /* 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_GOTOFF",         /* name */
-        true,                  /* partial_inplace */
-        0xffffffff,            /* src_mask */
-        0xffffffff,            /* dst_mask */
-        false),                /* pcrel_offset */
-
-  HOWTO (R_SH_GOTPC,           /* type */
-        0,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        32,                    /* bitsize */
-        true,                  /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_bitfield, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* */
-        "R_SH_GOTPC",          /* name */
-        true,                  /* partial_inplace */
-        0xffffffff,            /* src_mask */
-        0xffffffff,            /* dst_mask */
-        true),                 /* pcrel_offset */
-
+  EMPTY_HOWTO (10),
+  EMPTY_HOWTO (11),
+  EMPTY_HOWTO (12),
+  EMPTY_HOWTO (13),
+  EMPTY_HOWTO (14),
+  EMPTY_HOWTO (15),
+  EMPTY_HOWTO (16),
+  EMPTY_HOWTO (17),
   EMPTY_HOWTO (18),
   EMPTY_HOWTO (19),
   EMPTY_HOWTO (20),
@@ -575,11 +472,246 @@ static reloc_howto_type sh_elf_howto_table[] =
         0xff,                  /* dst_mask */
         true),                 /* pcrel_offset */
 
+  EMPTY_HOWTO (38),
+  EMPTY_HOWTO (39),
+  EMPTY_HOWTO (40),
+  EMPTY_HOWTO (41),
+  EMPTY_HOWTO (42),
+  EMPTY_HOWTO (43),
+  EMPTY_HOWTO (44),
+  EMPTY_HOWTO (45),
+  EMPTY_HOWTO (46),
+  EMPTY_HOWTO (47),
+  EMPTY_HOWTO (48),
+  EMPTY_HOWTO (49),
+  EMPTY_HOWTO (50),
+  EMPTY_HOWTO (51),
+  EMPTY_HOWTO (52),
+  EMPTY_HOWTO (53),
+  EMPTY_HOWTO (54),
+  EMPTY_HOWTO (55),
+  EMPTY_HOWTO (56),
+  EMPTY_HOWTO (57),
+  EMPTY_HOWTO (58),
+  EMPTY_HOWTO (59),
+  EMPTY_HOWTO (60),
+  EMPTY_HOWTO (61),
+  EMPTY_HOWTO (62),
+  EMPTY_HOWTO (63),
+  EMPTY_HOWTO (64),
+  EMPTY_HOWTO (65),
+  EMPTY_HOWTO (66),
+  EMPTY_HOWTO (67),
+  EMPTY_HOWTO (68),
+  EMPTY_HOWTO (69),
+  EMPTY_HOWTO (70),
+  EMPTY_HOWTO (71),
+  EMPTY_HOWTO (72),
+  EMPTY_HOWTO (73),
+  EMPTY_HOWTO (74),
+  EMPTY_HOWTO (75),
+  EMPTY_HOWTO (76),
+  EMPTY_HOWTO (77),
+  EMPTY_HOWTO (78),
+  EMPTY_HOWTO (79),
+  EMPTY_HOWTO (80),
+  EMPTY_HOWTO (81),
+  EMPTY_HOWTO (82),
+  EMPTY_HOWTO (83),
+  EMPTY_HOWTO (84),
+  EMPTY_HOWTO (85),
+  EMPTY_HOWTO (86),
+  EMPTY_HOWTO (87),
+  EMPTY_HOWTO (88),
+  EMPTY_HOWTO (89),
+  EMPTY_HOWTO (90),
+  EMPTY_HOWTO (91),
+  EMPTY_HOWTO (92),
+  EMPTY_HOWTO (93),
+  EMPTY_HOWTO (94),
+  EMPTY_HOWTO (95),
+  EMPTY_HOWTO (96),
+  EMPTY_HOWTO (97),
+  EMPTY_HOWTO (98),
+  EMPTY_HOWTO (99),
+  EMPTY_HOWTO (100),
+  EMPTY_HOWTO (101),
+  EMPTY_HOWTO (102),
+  EMPTY_HOWTO (103),
+  EMPTY_HOWTO (104),
+  EMPTY_HOWTO (105),
+  EMPTY_HOWTO (106),
+  EMPTY_HOWTO (107),
+  EMPTY_HOWTO (108),
+  EMPTY_HOWTO (109),
+  EMPTY_HOWTO (110),
+  EMPTY_HOWTO (111),
+  EMPTY_HOWTO (112),
+  EMPTY_HOWTO (113),
+  EMPTY_HOWTO (114),
+  EMPTY_HOWTO (115),
+  EMPTY_HOWTO (116),
+  EMPTY_HOWTO (117),
+  EMPTY_HOWTO (118),
+  EMPTY_HOWTO (119),
+  EMPTY_HOWTO (120),
+  EMPTY_HOWTO (121),
+  EMPTY_HOWTO (122),
+  EMPTY_HOWTO (123),
+  EMPTY_HOWTO (124),
+  EMPTY_HOWTO (125),
+  EMPTY_HOWTO (126),
+  EMPTY_HOWTO (127),
+  EMPTY_HOWTO (128),
+  EMPTY_HOWTO (129),
+  EMPTY_HOWTO (130),
+  EMPTY_HOWTO (131),
+  EMPTY_HOWTO (132),
+  EMPTY_HOWTO (133),
+  EMPTY_HOWTO (134),
+  EMPTY_HOWTO (135),
+  EMPTY_HOWTO (136),
+  EMPTY_HOWTO (137),
+  EMPTY_HOWTO (138),
+  EMPTY_HOWTO (139),
+  EMPTY_HOWTO (140),
+  EMPTY_HOWTO (141),
+  EMPTY_HOWTO (142),
+  EMPTY_HOWTO (143),
+  EMPTY_HOWTO (144),
+  EMPTY_HOWTO (145),
+  EMPTY_HOWTO (146),
+  EMPTY_HOWTO (147),
+  EMPTY_HOWTO (148),
+  EMPTY_HOWTO (149),
+  EMPTY_HOWTO (150),
+  EMPTY_HOWTO (151),
+  EMPTY_HOWTO (152),
+  EMPTY_HOWTO (153),
+  EMPTY_HOWTO (154),
+  EMPTY_HOWTO (155),
+  EMPTY_HOWTO (156),
+  EMPTY_HOWTO (157),
+  EMPTY_HOWTO (158),
+  EMPTY_HOWTO (159),
+
+  HOWTO (R_SH_GOT32,           /* 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_GOT32",          /* name */
+        true,                  /* partial_inplace */
+        0xffffffff,            /* src_mask */
+        0xffffffff,            /* dst_mask */
+        false),                /* pcrel_offset */
+
+  HOWTO (R_SH_PLT32,           /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        32,                    /* bitsize */
+        true,                  /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_bitfield, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* */
+        "R_SH_PLT32",          /* name */
+        true,                  /* partial_inplace */
+        0xffffffff,            /* src_mask */
+        0xffffffff,            /* dst_mask */
+        true),                 /* pcrel_offset */
+
+  HOWTO (R_SH_COPY,            /* 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_COPY",           /* name */
+        true,                  /* partial_inplace */
+        0xffffffff,            /* src_mask */
+        0xffffffff,            /* dst_mask */
+        false),                /* pcrel_offset */
+
+  HOWTO (R_SH_GLOB_DAT,                /* 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_GLOB_DAT",       /* name */
+        true,                  /* partial_inplace */
+        0xffffffff,            /* src_mask */
+        0xffffffff,            /* dst_mask */
+        false),                /* pcrel_offset */
+
+  HOWTO (R_SH_JMP_SLOT,                /* 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_JMP_SLOT",       /* name */
+        true,                  /* partial_inplace */
+        0xffffffff,            /* src_mask */
+        0xffffffff,            /* dst_mask */
+        false),                /* pcrel_offset */
+
+  HOWTO (R_SH_RELATIVE,                /* 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_RELATIVE",       /* name */
+        true,                  /* partial_inplace */
+        0xffffffff,            /* src_mask */
+        0xffffffff,            /* dst_mask */
+        false),                /* pcrel_offset */
+
+  HOWTO (R_SH_GOTOFF,          /* 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_GOTOFF",         /* name */
+        true,                  /* partial_inplace */
+        0xffffffff,            /* src_mask */
+        0xffffffff,            /* dst_mask */
+        false),                /* pcrel_offset */
+
+  HOWTO (R_SH_GOTPC,           /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        32,                    /* bitsize */
+        true,                  /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_bitfield, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* */
+        "R_SH_GOTPC",          /* name */
+        true,                  /* partial_inplace */
+        0xffffffff,            /* src_mask */
+        0xffffffff,            /* dst_mask */
+        true),                 /* pcrel_offset */
+
 };
 
 static bfd_reloc_status_type
 sh_elf_reloc_loop (r_type, input_bfd, input_section, contents, addr,
-                   symbol_section, start, end)
+                  symbol_section, start, end)
      int r_type ATTRIBUTE_UNUSED;
      bfd *input_bfd;
      asection *input_section;
@@ -658,7 +790,7 @@ sh_elf_reloc_loop (r_type, input_bfd, input_section, contents, addr,
     {
       bfd_vma start0 = start - 4;
 
-      while (start0 >= 0 && IS_PPI (contents + start0))
+      while (start0 && IS_PPI (contents + start0))
        start0 -= 2;
       start0 = start - 2 - ((start - start0) & 2);
       start = start0 - cum_diff - 2;
@@ -690,7 +822,7 @@ sh_elf_reloc_loop (r_type, input_bfd, input_section, contents, addr,
 
 static bfd_reloc_status_type
 sh_elf_reloc (abfd, reloc_entry, symbol_in, data, input_section, output_bfd,
-         error_message)
+             error_message)
      bfd *abfd;
      arelent *reloc_entry;
      asymbol *symbol_in;
@@ -724,8 +856,8 @@ sh_elf_reloc (abfd, reloc_entry, symbol_in, data, input_section, output_bfd,
     return bfd_reloc_undefined;
 
   if (bfd_is_com_section (symbol_in->section))
-    sym_value = 0;                           
-  else 
+    sym_value = 0;
+  else
     sym_value = (symbol_in->value +
                 symbol_in->section->output_section->vma +
                 symbol_in->section->output_offset);
@@ -855,6 +987,7 @@ 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);
 
   cache_ptr->howto = &sh_elf_howto_table[r];
 }
@@ -869,7 +1002,7 @@ sh_elf_info_to_howto (abfd, cache_ptr, dst)
    values; in coff-sh.c they come from include/coff/sh.h, whereas here
    they come from enum elf_sh_reloc_type in include/elf/sh.h.  */
 
-static boolean 
+static boolean
 sh_elf_relax_section (abfd, sec, link_info, again)
      bfd *abfd;
      asection *sec;
@@ -974,7 +1107,7 @@ sh_elf_relax_section (abfd, sec, link_info, again)
         on a four byte boundary.  */
       paddr = insn & 0xff;
       paddr *= 4;
-      paddr += (laddr + 4) &3;
+      paddr += (laddr + 4) & ~3;
       if (paddr >= sec->_raw_size)
        {
          ((*_bfd_error_handler)
@@ -1432,7 +1565,7 @@ sh_elf_relax_delete_bytes (abfd, sec, addr, count)
 
        case R_SH_DIR8WPL:
          off = insn & 0xff;
-         stop = (start &(bfd_vma) 3) + 4 + off * 4;
+         stop = (start & ~(bfd_vma) 3) + 4 + off * 4;
          break;
 
        case R_SH_SWITCH8:
@@ -1958,6 +2091,115 @@ sh_elf_swap_insns (abfd, sec, relocs, contents, addr)
 
 /* 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 */
@@ -2056,6 +2298,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;
@@ -2256,7 +2499,7 @@ sh_elf_create_dynamic_sections (abfd, info)
        return false;
     }
 
-  s = bfd_make_section (abfd, 
+  s = bfd_make_section (abfd,
                        bed->default_use_rela_p ? ".rela.plt" : ".rel.plt");
   if (s == NULL
       || ! bfd_set_section_flags (abfd, s, flags | SEC_READONLY)
@@ -2316,9 +2559,9 @@ sh_elf_create_dynamic_sections (abfd, info)
         copy relocs.  */
       if (! info->shared)
        {
-         s = bfd_make_section (abfd, 
-                               (bed->default_use_rela_p 
-                                ? ".rela.bss" : ".rel.bss")); 
+         s = bfd_make_section (abfd,
+                               (bed->default_use_rela_p
+                                ? ".rela.bss" : ".rel.bss"));
          if (s == NULL
              || ! bfd_set_section_flags (abfd, s, flags | SEC_READONLY)
              || ! bfd_set_section_alignment (abfd, s, ptralign))
@@ -2329,7 +2572,6 @@ sh_elf_create_dynamic_sections (abfd, info)
   return true;
 }
 \f
-
 /* Adjust a symbol defined by a dynamic object and referenced by a
    regular object.  The current definition is in some section of the
    dynamic object, but we're not including those sections.  We have to
@@ -2698,7 +2940,6 @@ sh_elf_size_dynamic_sections (output_bfd, info)
    check_relocs routine, but we won't fill them in in the
    relocate_section routine.  */
 
-/*ARGSUSED*/
 static boolean
 sh_elf_discard_copies (h, ignore)
      struct elf_sh_link_hash_entry *h;
@@ -2715,7 +2956,6 @@ sh_elf_discard_copies (h, ignore)
 
   return true;
 }
-
 \f
 /* Relocate an SH ELF section.  */
 
@@ -2760,30 +3000,11 @@ sh_elf_relocate_section (output_bfd, info, input_bfd, input_section,
       asection *sec;
       struct elf_link_hash_entry *h;
       bfd_vma relocation;
-      bfd_vma addend = (bfd_vma)0;
+      bfd_vma addend = (bfd_vma) 0;
       bfd_reloc_status_type r;
 
       r_symndx = ELF32_R_SYM (rel->r_info);
 
-      if (info->relocateable)
-       {
-         /* This is a relocateable link.  We don't have to change
-             anything, unless the reloc is against a section symbol,
-             in which case we have to adjust according to where the
-             section symbol winds up in the output section.  */
-         if (r_symndx < symtab_hdr->sh_info)
-           {
-             sym = local_syms + r_symndx;
-             if (ELF_ST_TYPE (sym->st_info) == STT_SECTION)
-               {
-                 sec = local_sections[r_symndx];
-                 rel->r_addend += sec->output_offset + sym->st_value;
-               }
-           }
-
-         continue;
-       }
-
       r_type = ELF32_R_TYPE (rel->r_info);
 
       /* Many of the relocs are only used for relaxing, and are
@@ -2791,11 +3012,15 @@ sh_elf_relocate_section (output_bfd, info, input_bfd, input_section,
       if (r_type > (int) R_SH_LAST_INVALID_RELOC
          && r_type < (int) R_SH_LOOP_START)
        continue;
+      if (r_type == (int) R_SH_NONE)
+       continue;
 
       if (r_type < 0
          || 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_LAST_INVALID_RELOC)
+         || (r_type >= (int) R_SH_FIRST_INVALID_RELOC_2
+             && r_type <= (int) R_SH_LAST_INVALID_RELOC_2))
        {
          bfd_set_error (bfd_error_bad_value);
          return false;
@@ -2814,9 +3039,28 @@ sh_elf_relocate_section (output_bfd, info, input_bfd, input_section,
          relocation = (sec->output_section->vma
                        + sec->output_offset
                        + sym->st_value);
+
+         if (info->relocateable)
+           {
+             /* This is a relocateable link.  We don't have to change
+                anything, unless the reloc is against a section symbol,
+                in which case we have to adjust according to where the
+                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;
+
+             continue;
+           }
        }
       else
        {
+         /* Section symbol are never (?) placed in the hash table, so
+            we can just ignore hash relocations when creating a
+            relocateable object file.  */
+         if (info->relocateable)
+           continue;
+
          h = sym_hashes[r_symndx - symtab_hdr->sh_info];
          while (h->root.type == bfd_link_hash_indirect
                 || h->root.type == bfd_link_hash_warning)
@@ -2827,7 +3071,7 @@ sh_elf_relocate_section (output_bfd, info, input_bfd, input_section,
              sec = h->root.u.def.section;
              /* In these cases, we don't need the relocation value.
                 We check specially because in some obscure cases
-                sec->output_section will be NULL. */
+                sec->output_section will be NULL.  */
              if (r_type == R_SH_GOTPC
                  || (r_type == R_SH_PLT32
                      && h->plt.offset != (bfd_vma) -1)
@@ -2884,25 +3128,57 @@ sh_elf_relocate_section (output_bfd, info, input_bfd, input_section,
            }
        }
 
-      switch ((int)r_type)
+      switch ((int) r_type)
        {
        final_link_relocate:
          /* COFF relocs don't use the addend. The addend is used for
-            R_SH_DIR32 to be compatible with other compilers. */
+            R_SH_DIR32 to be compatible with other compilers.  */
          r = _bfd_final_link_relocate (howto, input_bfd, input_section,
                                        contents, rel->r_offset,
                                        relocation, addend);
          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_get_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:
          bfd_set_error (bfd_error_bad_value);
@@ -3002,9 +3278,9 @@ sh_elf_relocate_section (output_bfd, info, input_bfd, input_section,
                }
 
              bfd_elf32_swap_reloca_out (output_bfd, &outrel,
-                                       (((Elf32_External_Rela *)
-                                         sreloc->contents)
-                                        + sreloc->reloc_count));
+                                        (((Elf32_External_Rela *)
+                                          sreloc->contents)
+                                         + sreloc->reloc_count));
              ++sreloc->reloc_count;
 
              /* If this reloc is against an external symbol, we do
@@ -3235,7 +3511,7 @@ sh_elf_relocate_section (output_bfd, info, input_bfd, input_section,
 
 static bfd_byte *
 sh_elf_get_relocated_section_contents (output_bfd, link_info, link_order,
-                                       data, relocateable, symbols)
+                                      data, relocateable, symbols)
      bfd *output_bfd;
      struct bfd_link_info *link_info;
      struct bfd_link_order *link_order;
@@ -3367,45 +3643,43 @@ sh_elf_get_relocated_section_contents (output_bfd, link_info, link_order,
 }
 static asection *
 sh_elf_gc_mark_hook (abfd, info, rel, h, sym)
-       bfd *abfd;
-       struct bfd_link_info *info ATTRIBUTE_UNUSED;
-       Elf_Internal_Rela *rel;
-       struct elf_link_hash_entry *h;
-       Elf_Internal_Sym *sym;
+     bfd *abfd;
+     struct bfd_link_info *info ATTRIBUTE_UNUSED;
+     Elf_Internal_Rela *rel;
+     struct elf_link_hash_entry *h;
+     Elf_Internal_Sym *sym;
 {
   if (h != NULL)
     {
       switch (ELF32_R_TYPE (rel->r_info))
-      {
-      case R_SH_GNU_VTINHERIT:
-      case R_SH_GNU_VTENTRY:
-        break;
+       {
+       case R_SH_GNU_VTINHERIT:
+       case R_SH_GNU_VTENTRY:
+         break;
 
-      default:
-        switch (h->root.type)
-          {
-          case bfd_link_hash_defined:
-          case bfd_link_hash_defweak:
-            return h->root.u.def.section;
+       default:
+         switch (h->root.type)
+           {
+           case bfd_link_hash_defined:
+           case bfd_link_hash_defweak:
+             return h->root.u.def.section;
 
-          case bfd_link_hash_common:
-            return h->root.u.c.p->section;
+           case bfd_link_hash_common:
+             return h->root.u.c.p->section;
 
-         default:
-           break;
-          }
-       }
-     }
-   else
-     {
-       if (!(elf_bad_symtab (abfd)
-           && ELF_ST_BIND (sym->st_info) != STB_LOCAL)
-         && ! ((sym->st_shndx <= 0 || sym->st_shndx >= SHN_LORESERVE)
+           default:
+             break;
+           }
+       }
+    }
+  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;
 }
 
@@ -3421,14 +3695,14 @@ sh_elf_gc_sweep_hook (abfd, info, sec, relocs)
   /* We use got and plt entries for sh, but it would seem that the
      existing SH code does no sort of reference counting or whatnot on
      its GOT and PLT entries, so it is not possible to garbage collect
-     them at this time. */
+     them at this time.  */
   return true;
 }
 
 /* Look through the relocs for a section during the first phase.
    Since we don't do .gots or .plts, we just need to consider the
    virtual table relocs for gc.  */
+
 static boolean
 sh_elf_check_relocs (abfd, info, sec, relocs)
      bfd *abfd;
@@ -3445,21 +3719,20 @@ sh_elf_check_relocs (abfd, info, sec, relocs)
   asection *sgot;
   asection *srelgot;
   asection *sreloc;
+
   sgot = NULL;
   srelgot = NULL;
   sreloc = NULL;
 
   if (info->relocateable)
     return true;
+
   symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
   sym_hashes = elf_sym_hashes (abfd);
-  sym_hashes_end = sym_hashes + symtab_hdr->sh_size/sizeof(Elf32_External_Sym);
+  sym_hashes_end = sym_hashes + symtab_hdr->sh_size/sizeof (Elf32_External_Sym);
   if (!elf_bad_symtab (abfd))
     sym_hashes_end -= symtab_hdr->sh_info;
+
   dynobj = elf_hash_table (info)->dynobj;
   local_got_offsets = elf_local_got_offsets (abfd);
 
@@ -3468,13 +3741,13 @@ sh_elf_check_relocs (abfd, info, sec, relocs)
     {
       struct elf_link_hash_entry *h;
       unsigned long r_symndx;
+
       r_symndx = ELF32_R_SYM (rel->r_info);
       if (r_symndx < symtab_hdr->sh_info)
-        h = NULL;
+       h = NULL;
       else
-        h = sym_hashes[r_symndx - symtab_hdr->sh_info];
+       h = sym_hashes[r_symndx - symtab_hdr->sh_info];
+
       /* Some relocs require a global offset table.  */
       if (dynobj == NULL)
        {
@@ -3497,17 +3770,17 @@ sh_elf_check_relocs (abfd, info, sec, relocs)
         {
         /* This relocation describes the C++ object vtable hierarchy.
            Reconstruct it for later use during GC.  */
-        case R_SH_GNU_VTINHERIT:
-          if (!_bfd_elf32_gc_record_vtinherit (abfd, sec, h, rel->r_offset))
-            return false;
-          break;
+       case R_SH_GNU_VTINHERIT:
+         if (!_bfd_elf32_gc_record_vtinherit (abfd, sec, h, rel->r_offset))
+           return false;
+         break;
+
         /* This relocation describes which C++ vtable entries are actually
            used.  Record for later use during GC.  */
-        case R_SH_GNU_VTENTRY:
-          if (!_bfd_elf32_gc_record_vtentry (abfd, sec, h, rel->r_addend))
-            return false;
-          break;
+       case R_SH_GNU_VTENTRY:
+         if (!_bfd_elf32_gc_record_vtentry (abfd, sec, h, rel->r_addend))
+           return false;
+         break;
 
        case R_SH_GOT32:
          /* This symbol requires a global offset table entry.  */
@@ -3558,8 +3831,8 @@ sh_elf_check_relocs (abfd, info, sec, relocs)
            }
          else
            {
-             /* This is a global offset table entry for a local
-                symbol.  */
+             /* This is a global offset table entry for a local
+                symbol.  */
              if (local_got_offsets == NULL)
                {
                  size_t size;
@@ -3713,15 +3986,15 @@ sh_elf_check_relocs (abfd, info, sec, relocs)
            }
 
          break;
-        }
+       }
     }
+
   return true;
 }
 
 static boolean
 sh_elf_set_mach_from_flags (abfd)
-     bfd *    abfd;
+     bfd *abfd;
 {
   flagword flags = elf_elfheader (abfd)->e_flags;
 
@@ -3755,10 +4028,11 @@ sh_elf_set_mach_from_flags (abfd)
   return true;
 }
 
-/* Function to keep SH specific file flags. */
+/* Function to keep SH specific file flags.  */
+
 static boolean
 sh_elf_set_private_flags (abfd, flags)
-     bfd *    abfd;
+     bfd *abfd;
      flagword flags;
 {
   BFD_ASSERT (! elf_flags_init (abfd)
@@ -3770,6 +4044,7 @@ sh_elf_set_private_flags (abfd, flags)
 }
 
 /* Copy backend specific data from one object module to another */
+
 static boolean
 sh_elf_copy_private_data (ibfd, obfd)
      bfd * ibfd;
@@ -3873,7 +4148,7 @@ sh_elf_finish_dynamic_symbol (output_bfd, info, h, sym)
        {
          if (elf_sh_plt_entry == NULL)
            {
-             elf_sh_plt_entry = (bfd_big_endian (output_bfd)?
+             elf_sh_plt_entry = (bfd_big_endian (output_bfd) ?
                                  elf_sh_plt_entry_be : elf_sh_plt_entry_le);
            }
          memcpy (splt->contents + h->plt.offset, elf_sh_plt_entry,
@@ -3894,7 +4169,7 @@ sh_elf_finish_dynamic_symbol (output_bfd, info, h, sym)
        {
          if (elf_sh_pic_plt_entry == NULL)
            {
-             elf_sh_pic_plt_entry = (bfd_big_endian (output_bfd)?
+             elf_sh_pic_plt_entry = (bfd_big_endian (output_bfd) ?
                                      elf_sh_pic_plt_entry_be :
                                      elf_sh_pic_plt_entry_le);
            }
@@ -3974,8 +4249,8 @@ sh_elf_finish_dynamic_symbol (output_bfd, info, h, sym)
        }
 
       bfd_elf32_swap_reloca_out (output_bfd, &rel,
-                               ((Elf32_External_Rela *) srel->contents
-                                + srel->reloc_count));
+                                ((Elf32_External_Rela *) srel->contents
+                                 + srel->reloc_count));
       ++srel->reloc_count;
     }
 
@@ -4000,8 +4275,8 @@ sh_elf_finish_dynamic_symbol (output_bfd, info, h, sym)
       rel.r_info = ELF32_R_INFO (h->dynindx, R_SH_COPY);
       rel.r_addend = 0;
       bfd_elf32_swap_reloca_out (output_bfd, &rel,
-                               ((Elf32_External_Rela *) s->contents
-                                + s->reloc_count));
+                                ((Elf32_External_Rela *) s->contents
+                                 + s->reloc_count));
       ++s->reloc_count;
     }
 
@@ -4106,7 +4381,7 @@ sh_elf_finish_dynamic_sections (output_bfd, info)
            {
              if (elf_sh_pic_plt_entry == NULL)
                {
-                 elf_sh_pic_plt_entry = (bfd_big_endian (output_bfd)?
+                 elf_sh_pic_plt_entry = (bfd_big_endian (output_bfd) ?
                                          elf_sh_pic_plt_entry_be :
                                          elf_sh_pic_plt_entry_le);
                }
@@ -4117,7 +4392,7 @@ sh_elf_finish_dynamic_sections (output_bfd, info)
            {
              if (elf_sh_plt0_entry == NULL)
                {
-                 elf_sh_plt0_entry = (bfd_big_endian (output_bfd)?
+                 elf_sh_plt0_entry = (bfd_big_endian (output_bfd) ?
                                       elf_sh_plt0_entry_be :
                                       elf_sh_plt0_entry_le);
                }
@@ -4161,7 +4436,7 @@ sh_elf_finish_dynamic_sections (output_bfd, info)
 #define TARGET_LITTLE_NAME     "elf32-shl"
 #define ELF_ARCH               bfd_arch_sh
 #define ELF_MACHINE_CODE       EM_SH
-#define ELF_MAXPAGESIZE                0x1
+#define ELF_MAXPAGESIZE                128
 
 #define elf_symbol_leading_char '_'
 #endif /* ELF_ARCH */