Add linker relaxation to v850 toolchain
authorNick Clifton <nickc@redhat.com>
Thu, 29 Aug 2002 06:49:35 +0000 (06:49 +0000)
committerNick Clifton <nickc@redhat.com>
Thu, 29 Aug 2002 06:49:35 +0000 (06:49 +0000)
13 files changed:
bfd/ChangeLog
bfd/archures.c
bfd/bfd-in2.h
bfd/cpu-v850.c
bfd/elf32-v850.c
bfd/libbfd.h
bfd/reloc.c
gas/ChangeLog
gas/config/tc-v850.c
gas/config/tc-v850.h
gas/doc/c-v850.texi
include/elf/ChangeLog
include/elf/v850.h

index 43a03634e48dd8f1c032ae7dae25136596dec0c2..b2869495ea23c6dbac845f9d28763f3c6d29fc04 100644 (file)
@@ -1,3 +1,21 @@
+2002-08-28  Catherine Moore  <clm@redhat.com>
+
+       * elf32-v850.c (v850_elf_reloc_map):  Add new relocs.
+       (v850-elf-reloc): Don't resolve pc relative relocs.
+       (v850_elf_ignore_reloc): New routine.
+       (v850_elf_final_link_relocate): Handle new relocs.
+       (v850_elf_relax_delete_bytes ): New routine.
+       (v850_elf_relax_section): New routine.
+       (bfd_elf32_bfd_relax_section): Define.
+       (HOWTO): New entries for new relocs.
+       * reloc.c (BFD_RELOC_V850_LONGCALL): New reloc.
+       (BFD_RELOC_V850_LONGJUMP): New reloc.
+       (BFD_RELOC_V850_ALIGN): New reloc.
+       * archures.c: Remove redundant v850ea architecture.
+       * cpu-v850.c: Remove redundant v850ea support.
+       * libbfd.h: Regenerate.
+       * bfd-in2.h: Regenerated.
+
 2002-08-28  Svein E. Seldal  <Svein.Seldal@solidas.com>
 
        * config.bfd: Add tic4x-*-*coff* and c4x-*-*coff* target.
index f3ca094bcf2ece4bc3c82bd9f7e8b10f16278442..3f0ba7bb65e36f6f6520c275c21d69b99b16b82d 100644 (file)
@@ -236,7 +236,6 @@ DESCRIPTION
 .  bfd_arch_v850,      {* NEC V850 *}
 .#define bfd_mach_v850          0
 .#define bfd_mach_v850e        'E'
-.#define bfd_mach_v850ea       'A'
 .  bfd_arch_arc,       {* ARC Cores *}
 .#define bfd_mach_arc_5         0
 .#define bfd_mach_arc_6         1
index 34fb98ed30887d1850738b7229e11113e5081887..0ab42452029ebc05092fa55de1c0cea87b0d496a 100644 (file)
@@ -274,7 +274,7 @@ bfd_format;
    memory.  If this is set, iostream points to a bfd_in_memory struct.  */
 #define BFD_IN_MEMORY 0x800
  
-/* The sections in this BFD specify a memory page */
+/* The sections in this BFD specify a memory page */
 #define HAS_LOAD_PAGE 0x1000
 \f
 /* Symbols and relocation.  */
@@ -2668,6 +2668,14 @@ bits placed non-contigously in the instruction.  */
 /* This is a 16 bit offset from the call table base pointer.  */
   BFD_RELOC_V850_CALLT_16_16_OFFSET,
 
+/* Used for relaxing indirect function calls.  */
+  BFD_RELOC_V850_LONGCALL,
+
+/* Used for relaxing indirect jumps.  */
+  BFD_RELOC_V850_LONGJUMP,
+
+/* Used to maintain alignment whilst relaxing.  */
+  BFD_RELOC_V850_ALIGN,
 
 /* This is a 32bit pcrel reloc for the mn10300, offset by two bytes in the
 instruction.  */
index 8836362026634aee0717d71e5ac1cba9b9081a00..ce61caa756273f1f9b25b9d75e2452c96f568ebf 100644 (file)
@@ -1,21 +1,21 @@
 /* BFD support for the NEC V850 processor
-   Copyright 1996, 1997, 1998, 2000, 2001 Free Software Foundation, Inc.
+   Copyright 1996, 1997, 1998, 2000, 2001, 2002 Free Software Foundation, Inc.
 
-This file is part of BFD, the Binary File Descriptor library.
+   This file is part of BFD, the Binary File Descriptor library.
 
-This program is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or
-(at your option) any later version.
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
 
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
 
-You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 
 #include "bfd.h"
 #include "sysdep.h"
@@ -67,7 +67,6 @@ scan (info, string)
   switch (number)
     {
     case bfd_mach_v850e:  arch = bfd_arch_v850; break;
-    case bfd_mach_v850ea: arch = bfd_arch_v850; break;
     default:
       return false;
     }
@@ -89,8 +88,7 @@ scan (info, string)
 
 static const bfd_arch_info_type arch_info_struct[] =
 {
-  N (bfd_mach_v850e,  "v850e",  false, & arch_info_struct[1]),
-  N (bfd_mach_v850ea, "v850ea", false, NULL)
+  N (bfd_mach_v850e,  "v850e",  false, NULL)
 };
 
 #undef  NEXT
index 07890c6a7cf5fe3a458a741b56f8d65816b290e0..193a0bf493020cc2eea363f6f82f4113466b9af9 100644 (file)
@@ -2,24 +2,24 @@
    Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002
    Free Software Foundation, Inc.
 
-This file is part of BFD, the Binary File Descriptor library.
+   This file is part of BFD, the Binary File Descriptor library.
 
-This program is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or
-(at your option) any later version.
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
 
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
 
-You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 
 /* XXX FIXME: This code is littered with 32bit int, 16bit short, 8bit char
-   dependencies.  As is the gas & simulator code or the v850.  */
+   dependencies.  As is the gas & simulator code for the v850.  */
 
 #include "bfd.h"
 #include "sysdep.h"
@@ -87,6 +87,12 @@ static asection * v850_elf_gc_mark_hook
   PARAMS ((asection *, struct bfd_link_info *,
           Elf_Internal_Rela *, struct elf_link_hash_entry *,
           Elf_Internal_Sym *));
+static bfd_reloc_status_type v850_elf_ignore_reloc
+  PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
+static boolean v850_elf_relax_delete_bytes
+  PARAMS ((bfd *, asection *, bfd_vma, bfd_vma, int));
+static boolean v850_elf_relax_section
+  PARAMS ((bfd *, asection *, struct bfd_link_info *, boolean *));
 
 /* Note: It is REQUIRED that the 'type' value of each entry
    in this array match the index of the entry in the array.  */
@@ -467,6 +473,51 @@ static reloc_howto_type v850_elf_howto_table[] =
          0,                     /* dst_mask */
          false),                /* pcrel_offset */
 
+  /* Indicates a .longcall pseudo-op.  The compiler will generate a .longcall
+     pseudo-op when it finds a function call which can be relaxed.  */
+  HOWTO (R_V850_LONGCALL,     /* type */
+       0,                     /* rightshift */
+       2,                     /* size (0 = byte, 1 = short, 2 = long) */
+       32,                    /* bitsize */
+       true,                  /* pc_relative */
+       0,                     /* bitpos */
+       complain_overflow_signed, /* complain_on_overflow */
+       v850_elf_ignore_reloc, /* special_function */
+       "R_V850_LONGCALL",     /* name */
+       false,                 /* partial_inplace */
+       0,                     /* src_mask */
+       0,                     /* dst_mask */
+       true),                 /* pcrel_offset */
+
+  /* Indicates a .longjump pseudo-op.  The compiler will generate a
+     .longjump pseudo-op when it finds a branch which can be relaxed.  */
+  HOWTO (R_V850_LONGJUMP,     /* type */
+       0,                     /* rightshift */
+       2,                     /* size (0 = byte, 1 = short, 2 = long) */
+       32,                    /* bitsize */
+       true,                  /* pc_relative */
+       0,                     /* bitpos */
+       complain_overflow_signed, /* complain_on_overflow */
+       v850_elf_ignore_reloc, /* special_function */
+       "R_V850_LONGJUMP",     /* name */
+       false,                 /* partial_inplace */
+       0,                     /* src_mask */
+       0,                     /* dst_mask */
+       true),                 /* pcrel_offset */
+
+  HOWTO (R_V850_ALIGN,        /* type */
+       0,                     /* rightshift */
+       1,                     /* size (0 = byte, 1 = short, 2 = long) */
+       0,                     /* bitsize */
+       false,                 /* pc_relative */
+       0,                     /* bitpos */
+       complain_overflow_unsigned, /* complain_on_overflow */
+       v850_elf_ignore_reloc, /* special_function */
+       "R_V850_ALIGN",        /* name */
+       false,                 /* partial_inplace */
+       0,                     /* src_mask */
+       0,                     /* dst_mask */
+       true),                 /* pcrel_offset */
 };
 
 /* Map BFD reloc types to V850 ELF reloc types.  */
@@ -481,31 +532,34 @@ struct v850_elf_reloc_map
 
 static const struct v850_elf_reloc_map v850_elf_reloc_map[] =
 {
-  { BFD_RELOC_NONE,            R_V850_NONE },
-  { BFD_RELOC_V850_9_PCREL,    R_V850_9_PCREL },
-  { BFD_RELOC_V850_22_PCREL,   R_V850_22_PCREL },
-  { BFD_RELOC_HI16_S,          R_V850_HI16_S },
-  { BFD_RELOC_HI16,            R_V850_HI16 },
-  { BFD_RELOC_LO16,            R_V850_LO16 },
-  { BFD_RELOC_32,              R_V850_32 },
-  { BFD_RELOC_16,              R_V850_16 },
-  { BFD_RELOC_8,               R_V850_8 },
-  { BFD_RELOC_V850_SDA_16_16_OFFSET, R_V850_SDA_16_16_OFFSET },
-  { BFD_RELOC_V850_SDA_15_16_OFFSET, R_V850_SDA_15_16_OFFSET },
-  { BFD_RELOC_V850_ZDA_16_16_OFFSET, R_V850_ZDA_16_16_OFFSET },
-  { BFD_RELOC_V850_ZDA_15_16_OFFSET, R_V850_ZDA_15_16_OFFSET },
-  { BFD_RELOC_V850_TDA_6_8_OFFSET,   R_V850_TDA_6_8_OFFSET   },
-  { BFD_RELOC_V850_TDA_7_8_OFFSET,   R_V850_TDA_7_8_OFFSET   },
-  { BFD_RELOC_V850_TDA_7_7_OFFSET,   R_V850_TDA_7_7_OFFSET   },
-  { BFD_RELOC_V850_TDA_16_16_OFFSET, R_V850_TDA_16_16_OFFSET },
+  { BFD_RELOC_NONE,                       R_V850_NONE                   },
+  { BFD_RELOC_V850_9_PCREL,               R_V850_9_PCREL                },
+  { BFD_RELOC_V850_22_PCREL,              R_V850_22_PCREL               },
+  { BFD_RELOC_HI16_S,                     R_V850_HI16_S                 },
+  { BFD_RELOC_HI16,                       R_V850_HI16                   },
+  { BFD_RELOC_LO16,                       R_V850_LO16                   },
+  { BFD_RELOC_32,                         R_V850_32                     },
+  { BFD_RELOC_16,                         R_V850_16                     },
+  { BFD_RELOC_8,                          R_V850_8                      },
+  { BFD_RELOC_V850_SDA_16_16_OFFSET,       R_V850_SDA_16_16_OFFSET       },
+  { BFD_RELOC_V850_SDA_15_16_OFFSET,       R_V850_SDA_15_16_OFFSET       },
+  { BFD_RELOC_V850_ZDA_16_16_OFFSET,       R_V850_ZDA_16_16_OFFSET       },
+  { BFD_RELOC_V850_ZDA_15_16_OFFSET,       R_V850_ZDA_15_16_OFFSET       },
+  { BFD_RELOC_V850_TDA_6_8_OFFSET,         R_V850_TDA_6_8_OFFSET         },
+  { BFD_RELOC_V850_TDA_7_8_OFFSET,         R_V850_TDA_7_8_OFFSET         },
+  { BFD_RELOC_V850_TDA_7_7_OFFSET,         R_V850_TDA_7_7_OFFSET         },
+  { BFD_RELOC_V850_TDA_16_16_OFFSET,       R_V850_TDA_16_16_OFFSET       },
   { BFD_RELOC_V850_TDA_4_5_OFFSET,         R_V850_TDA_4_5_OFFSET         },
   { BFD_RELOC_V850_TDA_4_4_OFFSET,         R_V850_TDA_4_4_OFFSET         },
   { BFD_RELOC_V850_SDA_16_16_SPLIT_OFFSET, R_V850_SDA_16_16_SPLIT_OFFSET },
   { BFD_RELOC_V850_ZDA_16_16_SPLIT_OFFSET, R_V850_ZDA_16_16_SPLIT_OFFSET },
   { BFD_RELOC_V850_CALLT_6_7_OFFSET,       R_V850_CALLT_6_7_OFFSET       },
   { BFD_RELOC_V850_CALLT_16_16_OFFSET,     R_V850_CALLT_16_16_OFFSET     },
-  { BFD_RELOC_VTABLE_INHERIT,               R_V850_GNU_VTINHERIT },
-  { BFD_RELOC_VTABLE_ENTRY,                 R_V850_GNU_VTENTRY },
+  { BFD_RELOC_VTABLE_INHERIT,              R_V850_GNU_VTINHERIT          },
+  { BFD_RELOC_VTABLE_ENTRY,                R_V850_GNU_VTENTRY            },
+  { BFD_RELOC_V850_LONGCALL,               R_V850_LONGCALL               },
+  { BFD_RELOC_V850_LONGJUMP,               R_V850_LONGJUMP               },
+  { BFD_RELOC_V850_ALIGN,                  R_V850_ALIGN                  },
 
 };
 \f
@@ -1297,6 +1351,9 @@ v850_elf_reloc (abfd, reloc, symbol, data, isection, obfd, err)
   /* Work out which section the relocation is targetted at and the
      initial relocation command value.  */
 
+  if (reloc->howto->pc_relative == true)
+    return bfd_reloc_ok;
+
   /* Get symbol value.  (Common symbols are special.)  */
   if (bfd_is_com_section (symbol->section))
     relocation = 0;
@@ -1335,6 +1392,26 @@ v850_elf_reloc (abfd, reloc, symbol, data, isection, obfd, err)
   reloc->addend = relocation;
   return bfd_reloc_ok;
 }
+
+/* This function is used for relocs which are only used
+   for relaxing, which the linker should otherwise ignore.  */
+
+static bfd_reloc_status_type
+v850_elf_ignore_reloc (abfd, reloc_entry, symbol, data, input_section,
+                       output_bfd, error_message)
+     bfd *      abfd ATTRIBUTE_UNUSED;
+     arelent *  reloc_entry;
+     asymbol *  symbol ATTRIBUTE_UNUSED;
+     PTR        data ATTRIBUTE_UNUSED;
+     asection * input_section;
+     bfd *      output_bfd;
+     char **    error_message ATTRIBUTE_UNUSED;
+{
+  if (output_bfd != NULL)
+    reloc_entry->address += input_section->output_offset;
+
+  return bfd_reloc_ok;
+}
 \f
 static boolean
 v850_elf_is_local_label_name (abfd, name)
@@ -1349,8 +1426,8 @@ v850_elf_is_local_label_name (abfd, name)
 
 static bfd_reloc_status_type
 v850_elf_final_link_relocate (howto, input_bfd, output_bfd,
-                                   input_section, contents, offset, value,
-                                   addend, info, sym_sec, is_local)
+                             input_section, contents, offset, value,
+                             addend, info, sym_sec, is_local)
      reloc_howto_type *      howto;
      bfd *                   input_bfd;
      bfd *                   output_bfd ATTRIBUTE_UNUSED;
@@ -1500,6 +1577,9 @@ v850_elf_final_link_relocate (howto, input_bfd, output_bfd,
     case R_V850_NONE:
     case R_V850_GNU_VTINHERIT:
     case R_V850_GNU_VTENTRY:
+    case R_V850_LONGCALL:
+    case R_V850_LONGJUMP:
+    case R_V850_ALIGN:
       return bfd_reloc_ok;
 
     default:
@@ -1770,7 +1850,6 @@ v850_elf_object_p (abfd)
     default:
     case E_V850_ARCH:   (void) bfd_default_set_arch_mach (abfd, bfd_arch_v850, 0); break;
     case E_V850E_ARCH:  (void) bfd_default_set_arch_mach (abfd, bfd_arch_v850, bfd_mach_v850e); break;
-    case E_V850EA_ARCH: (void) bfd_default_set_arch_mach (abfd, bfd_arch_v850, bfd_mach_v850ea); break;
     }
   return true;
 }
@@ -1789,7 +1868,6 @@ v850_elf_final_write_processing (abfd, linker)
     default:
     case 0: val = E_V850_ARCH; break;
     case bfd_mach_v850e:  val = E_V850E_ARCH; break;
-    case bfd_mach_v850ea: val = E_V850EA_ARCH;  break;
     }
 
   elf_elfheader (abfd)->e_flags &=~ EF_V850_ARCH;
@@ -1882,7 +1960,6 @@ v850_elf_print_private_bfd_data (abfd, ptr)
     default:
     case E_V850_ARCH: fprintf (file, _("v850 architecture")); break;
     case E_V850E_ARCH:  fprintf (file, _("v850e architecture")); break;
-    case E_V850EA_ARCH: fprintf (file, _("v850ea architecture")); break;
     }
 
   fputc ('\n', file);
@@ -2166,6 +2243,939 @@ v850_elf_fake_sections (abfd, hdr, sec)
 
   return true;
 }
+
+/* Delete some bytes from a section while relaxing.  */
+
+static boolean
+v850_elf_relax_delete_bytes (abfd, sec, addr, toaddr, count)
+     bfd *      abfd;
+     asection * sec;
+     bfd_vma    addr;
+     bfd_vma    toaddr;
+     int        count;
+{
+  Elf_Internal_Shdr *          symtab_hdr;
+  Elf32_External_Sym *         extsyms;
+  Elf32_External_Sym *                 esym;
+  Elf32_External_Sym *                 esymend;
+  int                          index;
+  unsigned int                         sec_shndx;
+  bfd_byte *                           contents;
+  Elf_Internal_Rela *                  irel;
+  Elf_Internal_Rela *                  irelend;
+  struct elf_link_hash_entry *         sym_hash;
+  Elf_Internal_Shdr *           shndx_hdr;
+  Elf_External_Sym_Shndx *      shndx;
+
+  symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
+  extsyms = (Elf32_External_Sym *) symtab_hdr->contents;
+
+  sec_shndx = _bfd_elf_section_from_bfd_section (abfd, sec);
+
+  contents = elf_section_data (sec)->this_hdr.contents;
+
+  /* The deletion must stop at the next ALIGN reloc for an alignment
+     power larger than the number of bytes we are deleting.  */
+
+  /* Actually delete the bytes.  */
+#if (DEBUG_RELAX & 2)
+  fprintf (stderr, "relax_delete: contents: sec: %s  %p .. %p %x\n",
+          sec->name, addr, toaddr, count );
+#endif
+  memmove (contents + addr, contents + addr + count,
+          toaddr - addr - count);
+  memset (contents + toaddr-count, 0, count);
+
+  /* Adjust all the relocs.  */
+  irel = elf_section_data (sec)->relocs;
+  irelend = irel + sec->reloc_count;
+  shndx_hdr = &elf_tdata (abfd)->symtab_shndx_hdr;
+  shndx = (Elf_External_Sym_Shndx *) shndx_hdr->contents;
+
+  for (; irel < irelend; irel++)
+    {
+      bfd_vma raddr, paddr, symval;
+      Elf_Internal_Sym isym;
+
+      /* Get the new reloc address.  */
+      raddr = irel->r_offset;
+      if ((raddr >= (addr + count) && raddr < toaddr))
+       irel->r_offset -= count;        
+
+      if (raddr >= addr && raddr < addr + count)
+       {
+         irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info),
+                                      (int) R_V850_NONE);
+         continue;
+       }
+      
+      if (ELF32_R_TYPE (irel->r_info) == (int) R_V850_ALIGN)
+       continue;
+
+      bfd_elf32_swap_symbol_in (abfd,
+                               extsyms + ELF32_R_SYM (irel->r_info),
+                               shndx ? shndx + ELF32_R_SYM (irel->r_info) : NULL,
+                               & isym);
+      
+      if (isym.st_shndx != sec_shndx)
+       continue;
+
+      /* Get the value of the symbol referred to by the reloc.  */
+      if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info)
+       {
+         symval = isym.st_value;
+#if (DEBUG_RELAX & 2)
+         {
+           char * name = bfd_elf_string_from_elf_section
+                          (abfd, symtab_hdr->sh_link, isym.st_name);
+           fprintf (stderr,
+              "relax_delete: local: sec: %s, sym: %s (%d), value: %x + %x + %x addend %x\n",
+              sec->name, name, isym.st_name,
+              sec->output_section->vma, sec->output_offset,
+              isym.st_value, irel->r_addend);
+         }
+#endif
+       }
+      else
+       {
+         unsigned long indx;
+         struct elf_link_hash_entry * h;
+
+         /* An external symbol.  */
+         indx = ELF32_R_SYM (irel->r_info) - symtab_hdr->sh_info;
+
+         h = elf_sym_hashes (abfd) [indx];
+         BFD_ASSERT (h != NULL);
+
+         symval = h->root.u.def.value;
+#if (DEBUG_RELAX & 2)
+         fprintf (stderr,
+                  "relax_delete: defined: sec: %s, name: %s, value: %x + %x + %x addend %x\n",
+                  sec->name, h->root.root.string, h->root.u.def.value,
+                  sec->output_section->vma, sec->output_offset, irel->r_addend);
+#endif
+       }
+             
+      paddr = symval + irel->r_addend;
+      
+      if ( (symval >= addr + count && symval < toaddr)
+         && (paddr < addr + count || paddr >= toaddr))
+       irel->r_addend += count;
+      else if (    (symval < addr + count || symval >= toaddr)
+               && (paddr >= addr + count && paddr < toaddr))
+       irel->r_addend -= count;
+    }
+
+  /* Adjust the local symbols defined in this section.  */
+  esym = extsyms;
+  esymend = esym + symtab_hdr->sh_info;
+
+  for (; esym < esymend; esym++, shndx = (shndx ? shndx + 1 : NULL))
+    {
+      Elf_Internal_Sym isym;
+
+      bfd_elf32_swap_symbol_in (abfd, esym, shndx, & isym);
+
+      if (isym.st_shndx == sec_shndx
+         && isym.st_value >= addr + count
+         && isym.st_value < toaddr)
+       {
+         isym.st_value -= count;
+
+         if (isym.st_value + isym.st_size >= toaddr)
+           isym.st_size += count;          
+         
+         bfd_elf32_swap_symbol_out (abfd, & isym, shndx, esym);
+       }
+      else if (isym.st_shndx == sec_shndx
+              && isym.st_value < addr + count)
+       {
+         if (isym.st_value+isym.st_size >= addr + count
+             && isym.st_value+isym.st_size < toaddr)
+           isym.st_size -= count;
+
+         if (isym.st_value >= addr
+             && isym.st_value <  addr + count)
+           isym.st_value = addr;
+
+         bfd_elf32_swap_symbol_out (abfd, & isym, shndx, esym);
+       }
+    }
+
+  /* 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 ++)
+    {
+      Elf_Internal_Sym isym;
+
+      bfd_elf32_swap_symbol_in (abfd, esym, shndx, & isym);
+      sym_hash = elf_sym_hashes (abfd) [index];
+
+      if (isym.st_shndx == sec_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 + count
+         && (sym_hash)->root.u.def.value < toaddr)
+       {
+         if ((sym_hash)->root.u.def.value + isym.st_size >= toaddr)
+           {
+             isym.st_size += count;
+             bfd_elf32_swap_symbol_out (abfd, & isym, shndx, esym);
+           }
+
+         (sym_hash)->root.u.def.value -= count;
+       }
+      else if (isym.st_shndx == sec_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 + count)
+       {
+         if ((sym_hash)->root.u.def.value+isym.st_size >= addr + count
+             && (sym_hash)->root.u.def.value+isym.st_size < toaddr)
+           isym.st_size -= count;
+
+         if ((sym_hash)->root.u.def.value >= addr
+             && (sym_hash)->root.u.def.value < addr + count)
+           (sym_hash)->root.u.def.value = addr;
+
+         bfd_elf32_swap_symbol_out (abfd, & isym, shndx, esym);
+       }
+
+      if (shndx)
+       ++ shndx;
+    }
+
+  return true;
+}
+
+#define NOP_OPCODE     (0x0000)
+#define MOVHI          0x0640                          /* 4byte */ 
+#define MOVHI_MASK     0x07e0
+#define MOVHI_R1(insn) ((insn) & 0x1f)                 /* 4byte */ 
+#define MOVHI_R2(insn) ((insn) >> 11)
+#define MOVEA          0x0620                          /* 2byte */
+#define MOVEA_MASK     0x07e0
+#define MOVEA_R1(insn) ((insn) & 0x1f)
+#define MOVEA_R2(insn) ((insn) >> 11)
+#define JARL_4         0x00040780                              /* 4byte */
+#define JARL_4_MASK    0xFFFF07FF
+#define JARL_R2(insn)  (int)(((insn) & (~JARL_4_MASK)) >> 11)
+#define ADD_I          0x0240                                  /* 2byte */
+#define ADD_I_MASK     0x07e0
+#define ADD_I5(insn)   ((((insn) & 0x001f) << 11) >> 11)       /* 2byte */
+#define ADD_R2(insn)   ((insn) >> 11)
+#define JMP_R          0x0060                                  /* 2byte */
+#define JMP_R_MASK     0xFFE0
+#define JMP_R1(insn)   ((insn) & 0x1f)
+
+static boolean 
+v850_elf_relax_section (abfd, sec, link_info, again)
+     bfd *                     abfd;
+     asection *                        sec;
+     struct bfd_link_info *    link_info;
+     boolean *                 again;
+{
+  Elf_Internal_Shdr *      symtab_hdr;
+  Elf_Internal_Rela *      internal_relocs;
+  Elf_Internal_Rela *      free_relocs = NULL;
+  Elf_Internal_Rela *      irel;
+  Elf_Internal_Rela *      irelend;
+  Elf_Internal_Rela *      irelalign = NULL;
+  bfd_byte *               contents = NULL;
+  bfd_byte *               free_contents = NULL;
+  Elf32_External_Sym *     extsyms = NULL;
+  Elf32_External_Sym *     free_extsyms = NULL;
+  bfd_vma                  addr = 0;
+  bfd_vma                  toaddr;
+  int                      align_pad_size = 0;
+  Elf_Internal_Shdr *       shndx_hdr = NULL;
+  Elf_External_Sym_Shndx *  shndx_buf = NULL;
+  
+  * again = false;
+
+  if (link_info->relocateable
+      || (sec->flags & SEC_RELOC) == 0
+      || sec->reloc_count == 0)
+    return true;
+
+  /* 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;
+
+  internal_relocs = (_bfd_elf32_link_read_relocs
+                    (abfd, sec, (PTR) NULL, (Elf_Internal_Rela *) NULL,
+                     link_info->keep_memory));
+  if (internal_relocs == NULL)
+    goto error_return;
+  if (! link_info->keep_memory)
+    free_relocs = internal_relocs;
+
+  irelend = internal_relocs + sec->reloc_count;
+  
+  while (addr < sec->_cooked_size)
+    {
+      toaddr = sec->_cooked_size;
+
+      for (irel = internal_relocs; irel < irelend; irel ++)
+       if (ELF32_R_TYPE (irel->r_info) == (int) R_V850_ALIGN
+           && irel->r_offset > addr
+           && irel->r_offset < toaddr)
+         toaddr = irel->r_offset;
+      
+#ifdef DEBUG_RELAX
+      fprintf (stderr, "relax region 0x%x to 0x%x align pad %d\n",
+              addr, toaddr, align_pad_size);
+#endif
+      if (irelalign)
+       {
+         bfd_vma alignto;
+         bfd_vma alignmoveto;
+
+         alignmoveto = BFD_ALIGN (addr - align_pad_size, 1 << irelalign->r_addend);
+         alignto = BFD_ALIGN (addr, 1 << irelalign->r_addend);
+
+         if (alignmoveto < alignto)
+           {
+             unsigned int i;
+
+             align_pad_size = alignto - alignmoveto;
+#ifdef DEBUG_RELAX
+             fprintf (stderr, "relax move region 0x%x to 0x%x delete size 0x%x\n",
+                      alignmoveto, toaddr, align_pad_size);
+#endif
+             if (!v850_elf_relax_delete_bytes (abfd, sec, alignmoveto,
+                                               toaddr, align_pad_size))
+               goto error_return;              
+
+             for (i  = BFD_ALIGN (toaddr - align_pad_size, 1);
+                  (i + 1) < toaddr; i += 2)
+               bfd_put_16 (abfd, NOP_OPCODE, contents + i);
+
+             addr = alignmoveto;
+           }
+         else
+           align_pad_size = 0;
+       }
+
+      for (irel = internal_relocs; irel < irelend; irel++)
+       {
+         bfd_vma             laddr;
+         bfd_vma             addend;
+         bfd_vma             symval;
+         int                 insn[5];
+         int                 no_match = -1;
+         Elf_Internal_Rela * hi_irelfn;
+         Elf_Internal_Rela * lo_irelfn;
+         Elf_Internal_Rela * irelcall;
+         bfd_signed_vma      foff;
+
+         if (! (irel->r_offset >= addr && irel->r_offset < toaddr
+                && (ELF32_R_TYPE (irel->r_info) == (int) R_V850_LONGCALL
+                    || ELF32_R_TYPE (irel->r_info) == (int) R_V850_LONGJUMP)))
+           continue;
+
+#ifdef DEBUG_RELAX
+         fprintf (stderr, "relax check r_info 0x%x r_offset 0x%x r_addend 0x%x\n",
+                  irel->r_info,
+                  irel->r_offset,
+                  irel->r_addend );
+#endif
+
+         /* Get the section contents.  */
+         if (contents == NULL)
+           {
+             if (elf_section_data (sec)->this_hdr.contents != NULL)
+               contents = elf_section_data (sec)->this_hdr.contents;
+             else
+               {
+                 contents = (bfd_byte *) bfd_malloc (sec->_raw_size);
+                 if (contents == NULL)
+                   goto error_return;
+
+                 free_contents = contents;
+
+                 if (! bfd_get_section_contents (abfd, sec, contents,
+                                                 (file_ptr) 0, sec->_raw_size))
+                   goto error_return;
+               }
+           }
+
+         /* Read this BFD's symbols if we haven't done so already.  */
+         if (extsyms == NULL)
+           {
+             /* Get cached copy if it exists.  */
+             if (symtab_hdr->contents != NULL)
+               extsyms = (Elf32_External_Sym *) symtab_hdr->contents;
+             else
+               {
+                 /* Go get them off disk.  */
+                 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_bread ((PTR) extsyms, amt, abfd) != amt)
+                   goto error_return;
+               }
+
+             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;
+               }
+           }
+
+         laddr = irel->r_offset;
+
+         if (ELF32_R_TYPE (irel->r_info) == (int) R_V850_LONGCALL)
+           {
+             /* Check code for -mlong-calls output. */
+             if (laddr + 16 <= (bfd_vma) sec->_raw_size)
+               {
+                 insn[0] = bfd_get_16 (abfd, contents + laddr);
+                 insn[1] = bfd_get_16 (abfd, contents + laddr + 4);
+                 insn[2] = bfd_get_32 (abfd, contents + laddr + 8);
+                 insn[3] = bfd_get_16 (abfd, contents + laddr + 12);
+                 insn[4] = bfd_get_16 (abfd, contents + laddr + 14);
+         
+                 if ((insn[0] & MOVHI_MASK) != MOVHI
+                      || MOVHI_R1 (insn[0]) != 0)
+                   no_match = 0;
+
+                 if (no_match < 0
+                     && ((insn[1] & MOVEA_MASK) != MOVEA
+                          || MOVHI_R2 (insn[0]) != MOVEA_R1 (insn[1])))
+                   no_match = 1;
+
+                 if (no_match < 0
+                     && (insn[2] & JARL_4_MASK) != JARL_4)
+                   no_match = 2;
+
+                 if (no_match < 0
+                     && ((insn[3] & ADD_I_MASK) != ADD_I
+                          || ADD_I5 (insn[3]) != 4
+                          || JARL_R2 (insn[2]) != ADD_R2 (insn[3])))
+                   no_match = 3;
+
+                 if (no_match < 0
+                     && ((insn[4] & JMP_R_MASK) != JMP_R
+                          || MOVEA_R2 (insn[1]) != JMP_R1 (insn[4])))
+                   no_match = 4;
+               }
+             else
+               {
+                 ((*_bfd_error_handler)
+                  ("%s: 0x%lx: warning: R_V850_LONGCALL points to unrecognized insns",
+                   bfd_get_filename (abfd), (unsigned long) irel->r_offset));
+
+                 continue;
+               }
+
+             if (no_match >= 0)
+               {
+                 ((*_bfd_error_handler)
+                  ("%s: 0x%lx: warning: R_V850_LONGCALL points to unrecognized insn 0x%x",
+                   bfd_get_filename (abfd), (unsigned long) irel->r_offset+no_match, insn[no_match]));
+
+                 continue;
+               }      
+
+             /* Get the reloc for the address from which the register is
+                being loaded.  This reloc will tell us which function is
+                actually being called.  */
+             for (hi_irelfn = internal_relocs; hi_irelfn < irelend; hi_irelfn ++)
+               if (hi_irelfn->r_offset == laddr + 2
+                   && ELF32_R_TYPE (hi_irelfn->r_info) 
+                       == (int) R_V850_HI16_S)
+                 break;
+
+             for (lo_irelfn = internal_relocs; lo_irelfn < irelend; lo_irelfn ++)
+               if (lo_irelfn->r_offset == laddr + 6
+                   && ELF32_R_TYPE (lo_irelfn->r_info)
+                       == (int) R_V850_LO16)
+                 break;
+
+             for (irelcall = internal_relocs; irelcall < irelend; irelcall ++)
+               if (irelcall->r_offset == laddr + 8
+                   && ELF32_R_TYPE (irelcall->r_info)
+                        == (int) R_V850_22_PCREL)
+                 break;
+
+             if (   hi_irelfn == irelend
+                 || lo_irelfn == irelend
+                 || irelcall  == irelend)
+               {
+                 ((*_bfd_error_handler)
+                  ("%s: 0x%lx: warning: R_V850_LONGCALL points to unrecognized reloc",
+                   bfd_get_filename (abfd), (unsigned long) irel->r_offset ));
+
+                 continue;
+               }
+       
+             if (ELF32_R_SYM (irelcall->r_info) < symtab_hdr->sh_info)
+               {
+                 unsigned int             r_index;
+                 Elf_Internal_Sym         isym;
+                 asection *               sym_sec;
+                 Elf32_External_Sym *     esym;
+                 Elf_External_Sym_Shndx * shndx;
+
+                 /* A local symbol.  */
+                 r_index = ELF32_R_SYM (irelcall->r_info);
+                 esym = extsyms + r_index;
+                 shndx = shndx_buf + (shndx_buf ? r_index : 0);
+                 bfd_elf32_swap_symbol_in (abfd, esym, shndx, & isym);
+
+                 if (isym.st_shndx == SHN_UNDEF)
+                   sym_sec = bfd_und_section_ptr;
+                 else if (isym.st_shndx == SHN_ABS)
+                   sym_sec = bfd_abs_section_ptr;
+                 else if (isym.st_shndx == SHN_COMMON)
+                   sym_sec = bfd_com_section_ptr;
+                 else
+                   sym_sec = bfd_section_from_elf_index (abfd, isym.st_shndx);
+                 symval = isym.st_value;
+               }
+             else
+               {
+                 unsigned long indx;
+                 struct elf_link_hash_entry * h;
+
+                 /* An external symbol.  */
+                 indx = ELF32_R_SYM (irelcall->r_info) - symtab_hdr->sh_info;
+                 h = elf_sym_hashes (abfd)[indx];
+                 BFD_ASSERT (h != NULL);
+
+                 if (   h->root.type != bfd_link_hash_defined
+                     && h->root.type != bfd_link_hash_defweak)
+                   /* This appears to be a reference to an undefined
+                      symbol.  Just ignore it--it will be caught by the
+                      regular reloc processing.  */
+                   continue;
+
+                 symval = h->root.u.def.value;
+               }
+
+             if (symval + irelcall->r_addend != irelcall->r_offset + 4)
+               {
+                 ((*_bfd_error_handler)
+                  ("%s: 0x%lx: warning: R_V850_LONGCALL points to unrecognized reloc 0x%lx",
+                   bfd_get_filename (abfd), (unsigned long) irel->r_offset, irelcall->r_offset ));
+
+                 continue;
+               }
+
+             /* Get the value of the symbol referred to by the reloc.  */
+             if (ELF32_R_SYM (hi_irelfn->r_info) < symtab_hdr->sh_info)
+               {
+                 unsigned int             r_index;
+                 Elf_Internal_Sym         isym;
+                 asection *               sym_sec;
+                 Elf32_External_Sym *     esym;
+                 Elf_External_Sym_Shndx * shndx;
+
+                 /* A local symbol.  */
+                 r_index = ELF32_R_SYM (irel->r_info);
+                 esym = extsyms + r_index;
+                 shndx = shndx_buf + (shndx_buf ? r_index : 0);
+                 bfd_elf32_swap_symbol_in (abfd, esym, shndx, & isym);
+          
+                 if (isym.st_shndx == SHN_UNDEF)
+                   sym_sec = bfd_und_section_ptr;
+                 else if (isym.st_shndx == SHN_ABS)
+                   sym_sec = bfd_abs_section_ptr;
+                 else if (isym.st_shndx == SHN_COMMON)
+                   sym_sec = bfd_com_section_ptr;
+                 else
+                   sym_sec = bfd_section_from_elf_index (abfd, isym.st_shndx);
+                 symval = (isym.st_value
+                           + sym_sec->output_section->vma
+                           + sym_sec->output_offset);
+               }
+             else
+               {
+                 unsigned long indx;
+                 struct elf_link_hash_entry * h;
+
+                 /* An external symbol.  */
+                 indx = ELF32_R_SYM (irel->r_info) - symtab_hdr->sh_info;
+                 h = elf_sym_hashes (abfd)[indx];
+                 BFD_ASSERT (h != NULL);
+
+                 if (   h->root.type != bfd_link_hash_defined
+                     && h->root.type != bfd_link_hash_defweak)
+                   /* This appears to be a reference to an undefined
+                      symbol.  Just ignore it--it will be caught by the
+                      regular reloc processing.  */
+                   continue;
+
+                 symval = (h->root.u.def.value
+                           + h->root.u.def.section->output_section->vma
+                           + h->root.u.def.section->output_offset);
+               }
+
+             addend = irel->r_addend;
+
+             foff = (symval + addend
+                     - (irel->r_offset
+                        + sec->output_section->vma
+                        + sec->output_offset
+                        + 4));
+#ifdef DEBUG_RELAX
+             fprintf (stderr, "relax longcall r_offset 0x%x ptr 0x%x symbol 0x%x addend 0x%x distance 0x%x\n",
+                      irel->r_offset,
+                      (irel->r_offset
+                       + sec->output_section->vma
+                       + sec->output_offset),
+                      symval, addend, foff);
+#endif
+
+             if (foff < -0x100000 || foff >= 0x100000)
+               /* After all that work, we can't shorten this function call.  */
+               continue;
+
+             /* For simplicity of coding, we are going to modify the section
+                contents, the section relocs, and the BFD symbol table.  We
+                must tell the rest of the code not to free up this
+                information.  It would be possible to instead create a table
+                of changes which have to be made, as is done in coff-mips.c;
+                that would be more work, but would require less memory when
+                the linker is run.  */
+             elf_section_data (sec)->relocs = internal_relocs;
+             free_relocs = NULL;
+
+             elf_section_data (sec)->this_hdr.contents = contents;
+             free_contents = NULL;
+
+             symtab_hdr->contents = (bfd_byte *) extsyms;
+             free_extsyms = NULL;
+      
+             /* Replace the long call with a jarl.  */
+             irel->r_info = ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info), R_V850_22_PCREL);
+
+             addend = 0;
+
+             if (ELF32_R_SYM (hi_irelfn->r_info) < symtab_hdr->sh_info)
+               /* If this needs to be changed because of future relaxing,
+                  it will be handled here like other internal IND12W
+                  relocs.  */
+               bfd_put_32 (abfd,
+                           0x00000780 | (JARL_R2 (insn[2])<<11) | ((addend << 16) & 0xffff) | ((addend >> 16) & 0xf),
+                           contents + irel->r_offset);
+             else
+               /* 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_32 (abfd, 0x00000780 | (JARL_R2 (insn[2])<<11),
+                           contents + irel->r_offset);
+
+             hi_irelfn->r_info = 
+               ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info), R_V850_NONE);
+             lo_irelfn->r_info =
+               ELF32_R_INFO (ELF32_R_SYM (lo_irelfn->r_info), R_V850_NONE);
+             irelcall->r_info =
+               ELF32_R_INFO (ELF32_R_SYM (irelcall->r_info), R_V850_NONE);
+
+             if (! v850_elf_relax_delete_bytes (abfd, sec,
+                                                irel->r_offset + 4, toaddr, 12))
+               goto error_return;
+
+             align_pad_size += 12;
+           }
+         else if (ELF32_R_TYPE (irel->r_info) == (int) R_V850_LONGJUMP)
+           {
+             /* Check code for -mlong-jumps output.  */
+             if (laddr + 10 <= (bfd_vma) sec->_raw_size)
+               {
+                 insn[0] = bfd_get_16 (abfd, contents + laddr);
+                 insn[1] = bfd_get_16 (abfd, contents + laddr + 4);
+                 insn[2] = bfd_get_16 (abfd, contents + laddr + 8);
+
+                 if ((insn[0] & MOVHI_MASK) != MOVHI
+                      || MOVHI_R1 (insn[0]) != 0)
+                   no_match = 0;
+
+                 if (no_match < 0
+                     && ((insn[1] & MOVEA_MASK) != MOVEA
+                          || MOVHI_R2 (insn[0]) != MOVEA_R1 (insn[1])))
+                   no_match = 1;
+
+                 if (no_match < 0
+                     && ((insn[2] & JMP_R_MASK) != JMP_R
+                          || MOVEA_R2 (insn[1]) != JMP_R1 (insn[2])))
+                   no_match = 4;
+               }
+             else
+               {
+                 ((*_bfd_error_handler)
+                  ("%s: 0x%lx: warning: R_V850_LONGJUMP points to unrecognized insns",
+                   bfd_get_filename (abfd), (unsigned long) irel->r_offset));
+
+                 continue;
+               }
+
+             if (no_match >= 0)
+               {
+                 ((*_bfd_error_handler)
+                  ("%s: 0x%lx: warning: R_V850_LONGJUMP points to unrecognized insn 0x%x",
+                   bfd_get_filename (abfd), (unsigned long) irel->r_offset+no_match, insn[no_match]));
+
+                 continue;
+               }
+
+             /* Get the reloc for the address from which the register is
+                being loaded.  This reloc will tell us which function is
+                actually being called.  */
+             for (hi_irelfn = internal_relocs; hi_irelfn < irelend; hi_irelfn ++)
+               if (hi_irelfn->r_offset == laddr + 2
+                   && ELF32_R_TYPE (hi_irelfn->r_info) == (int) R_V850_HI16_S) 
+                 break;
+
+             for (lo_irelfn = internal_relocs; lo_irelfn < irelend; lo_irelfn ++)
+               if (lo_irelfn->r_offset == laddr + 6
+                   && ELF32_R_TYPE (lo_irelfn->r_info) == (int) R_V850_LO16)
+                 break;
+
+             if (   hi_irelfn == irelend
+                 || lo_irelfn == irelend)
+               {
+                 ((*_bfd_error_handler)
+                  ("%s: 0x%lx: warning: R_V850_LONGJUMP points to unrecognized reloc",
+                   bfd_get_filename (abfd), (unsigned long) irel->r_offset ));
+
+                 continue;
+               }
+       
+             /* Get the value of the symbol referred to by the reloc.  */
+             if (ELF32_R_SYM (hi_irelfn->r_info) < symtab_hdr->sh_info)
+               {
+                 unsigned int             r_index;
+                 Elf_Internal_Sym         isym;
+                 asection *               sym_sec;
+                 Elf32_External_Sym *     esym;
+                 Elf_External_Sym_Shndx * shndx;
+
+                 /* A local symbol.  */
+                 r_index = ELF32_R_SYM (irel->r_info);
+                 esym = extsyms + r_index;
+                 shndx = shndx_buf + (shndx_buf ? r_index : 0);
+                 bfd_elf32_swap_symbol_in (abfd, esym, shndx, & isym);
+         
+                 if (isym.st_shndx == SHN_UNDEF)
+                   sym_sec = bfd_und_section_ptr;
+                 else if (isym.st_shndx == SHN_ABS)
+                   sym_sec = bfd_abs_section_ptr;
+                 else if (isym.st_shndx == SHN_COMMON)
+                   sym_sec = bfd_com_section_ptr;
+                 else
+                   sym_sec = bfd_section_from_elf_index (abfd, isym.st_shndx);
+                 symval = (isym.st_value
+                           + sym_sec->output_section->vma
+                           + sym_sec->output_offset);
+#ifdef DEBUG_RELAX
+                 {
+                   char * name = bfd_elf_string_from_elf_section
+                     (abfd, symtab_hdr->sh_link, isym.st_name);
+
+                   fprintf (stderr, "relax long jump local: sec: %s, sym: %s (%d), value: %x + %x + %x addend %x\n",
+                            sym_sec->name, name, isym.st_name,
+                            sym_sec->output_section->vma, sym_sec->output_offset,
+                            isym.st_value, irel->r_addend);
+                 }
+#endif
+               }
+             else
+               {
+                 unsigned long indx;
+                 struct elf_link_hash_entry * h;
+
+                 /* An external symbol.  */
+                 indx = ELF32_R_SYM (irel->r_info) - symtab_hdr->sh_info;
+                 h = elf_sym_hashes (abfd)[indx];
+                 BFD_ASSERT (h != NULL);
+
+                 if (   h->root.type != bfd_link_hash_defined
+                     && h->root.type != bfd_link_hash_defweak)
+                   /* This appears to be a reference to an undefined
+                      symbol.  Just ignore it--it will be caught by the
+                      regular reloc processing.  */
+                   continue;
+
+                 symval = (h->root.u.def.value
+                           + h->root.u.def.section->output_section->vma
+                           + h->root.u.def.section->output_offset);
+#ifdef DEBUG_RELAX
+                 fprintf (stderr,
+                          "relax longjump defined: sec: %s, name: %s, value: %x + %x + %x addend %x\n",
+                          sec->name, h->root.root.string, h->root.u.def.value,
+                          sec->output_section->vma, sec->output_offset, irel->r_addend);
+#endif
+               }
+
+             addend = irel->r_addend;
+
+             foff = (symval + addend
+                     - (irel->r_offset
+                        + sec->output_section->vma
+                        + sec->output_offset
+                        + 4));
+#ifdef DEBUG_RELAX
+             fprintf (stderr, "relax longjump r_offset 0x%x ptr 0x%x symbol 0x%x addend 0x%x distance 0x%x\n",
+                      irel->r_offset,
+                      (irel->r_offset
+                       + sec->output_section->vma
+                       + sec->output_offset),
+                      symval, addend, foff);
+#endif
+             if (foff < -0x100000 || foff >= 0x100000)
+               /* After all that work, we can't shorten this function call.  */
+               continue;
+
+             /* For simplicity of coding, we are going to modify the section
+                contents, the section relocs, and the BFD symbol table.  We
+                must tell the rest of the code not to free up this
+                information.  It would be possible to instead create a table
+                of changes which have to be made, as is done in coff-mips.c;
+                that would be more work, but would require less memory when
+                the linker is run.  */
+             elf_section_data (sec)->relocs = internal_relocs;
+             free_relocs = NULL;
+
+             elf_section_data (sec)->this_hdr.contents = contents;
+             free_contents = NULL;
+
+             symtab_hdr->contents = (bfd_byte *) extsyms;
+             free_extsyms = NULL;
+
+             if (foff < -0x100 || foff >= 0x100)
+               {
+                 /* Replace the long jump with a jr.  */
+
+                 irel->r_info =
+                       ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_V850_22_PCREL);
+  
+                 irel->r_addend = addend;
+                 addend = 0;
+
+                 if (ELF32_R_SYM (hi_irelfn->r_info) < symtab_hdr->sh_info)
+                   /* If this needs to be changed because of future relaxing,
+                      it will be handled here like other internal IND12W
+                      relocs.  */
+                   bfd_put_32 (abfd,
+                               0x00000780 | ((addend << 15) & 0xffff0000) | ((addend >> 17) & 0xf),
+                               contents + irel->r_offset);
+                 else
+                   /* 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_32 (abfd, 0x00000780, contents + irel->r_offset);
+
+                 hi_irelfn->r_info =
+                       ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info), R_V850_NONE);
+                 lo_irelfn->r_info =
+                       ELF32_R_INFO (ELF32_R_SYM (lo_irelfn->r_info), R_V850_NONE);
+                 if (!v850_elf_relax_delete_bytes (abfd, sec,
+                                                   irel->r_offset + 4, toaddr, 6))
+                   goto error_return;
+
+                 align_pad_size += 6;
+               }
+             else
+               {
+                 /* Replace the long jump with a br.  */
+
+                 irel->r_info =
+                       ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_V850_9_PCREL);
+
+                 irel->r_addend = addend;
+                 addend = 0;
+
+                 if (ELF32_R_SYM (hi_irelfn->r_info) < symtab_hdr->sh_info)
+                   /* If this needs to be changed because of future relaxing,
+                      it will be handled here like other internal IND12W
+                      relocs.  */
+                   bfd_put_16 (abfd,
+                               0x0585 | ((addend << 10) & 0xf800) | ((addend << 3) & 0x0070),
+                               contents + irel->r_offset);
+                 else
+                   /* 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, 0x0585, contents + irel->r_offset);
+
+                 hi_irelfn->r_info =
+                       ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info), R_V850_NONE);
+                 lo_irelfn->r_info =
+                       ELF32_R_INFO (ELF32_R_SYM (lo_irelfn->r_info), R_V850_NONE);
+                 if (!v850_elf_relax_delete_bytes (abfd, sec,
+                                                   irel->r_offset + 2, toaddr, 8))
+                   goto error_return;
+
+                 align_pad_size += 8;
+               }
+           }
+       }
+
+      irelalign = NULL;
+      for (irel = internal_relocs; irel < irelend; irel++)
+       {
+         if (ELF32_R_TYPE (irel->r_info) == (int) R_V850_ALIGN
+             && irel->r_offset == toaddr)
+           {
+             irel->r_offset -= align_pad_size;
+
+             if (irelalign == NULL || irelalign->r_addend > irel->r_addend)
+               irelalign = irel;
+           }
+       }
+
+      addr = toaddr;
+    }
+
+  if (!irelalign)
+    {
+#ifdef DEBUG_RELAX
+      fprintf (stderr, "relax pad %d shorten %d -> %d\n",
+              align_pad_size,
+              sec->_cooked_size,
+              sec->_cooked_size - align_pad_size);
+#endif
+      sec->_cooked_size -= align_pad_size;
+    }
+
+  return true;
+
+ error_return:
+  if (free_relocs != NULL)
+    free (free_relocs);
+
+  if (free_contents != NULL)
+    free (free_contents);
+
+  if (free_extsyms != NULL)
+    free (free_extsyms);
+
+  return false;
+}
 \f
 #define TARGET_LITTLE_SYM                      bfd_elf32_v850_vec
 #define TARGET_LITTLE_NAME                     "elf32-v850"
@@ -2198,6 +3208,7 @@ v850_elf_fake_sections (abfd, hdr, sec)
 #define bfd_elf32_bfd_merge_private_bfd_data   v850_elf_merge_private_bfd_data
 #define bfd_elf32_bfd_set_private_flags                v850_elf_set_private_flags
 #define bfd_elf32_bfd_print_private_bfd_data   v850_elf_print_private_bfd_data
+#define bfd_elf32_bfd_relax_section            v850_elf_relax_section
 
 #define elf_symbol_leading_char                        '_'
 
index 88beae8a9fd50cef9b3e830e1f4a84a1aead73fe..e855db196a1e971ffe71614770c3f45b87ed8749 100644 (file)
@@ -1041,7 +1041,9 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@",
   "BFD_RELOC_V850_ZDA_16_16_SPLIT_OFFSET",
   "BFD_RELOC_V850_CALLT_6_7_OFFSET",
   "BFD_RELOC_V850_CALLT_16_16_OFFSET",
-
+  "BFD_RELOC_V850_LONGCALL",
+  "BFD_RELOC_V850_LONGJUMP",
+  "BFD_RELOC_V850_ALIGN",
   "BFD_RELOC_MN10300_32_PCREL",
   "BFD_RELOC_MN10300_16_PCREL",
   "BFD_RELOC_TIC30_LDP",
index deba952832d5a2add44de6ab43cc02e9e7ab7eb0..e60c26e0512d84117c5fd60736eb93b456691bd7 100644 (file)
@@ -2788,8 +2788,18 @@ ENUM
   BFD_RELOC_V850_CALLT_16_16_OFFSET
 ENUMDOC
   This is a 16 bit offset from the call table base pointer.
-COMMENT
-
+ENUM
+  BFD_RELOC_V850_LONGCALL
+ENUMDOC
+  Used for relaxing indirect function calls.
+ENUM
+  BFD_RELOC_V850_LONGJUMP
+ENUMDOC
+  Used for relaxing indirect jumps.
+ENUM
+  BFD_RELOC_V850_ALIGN
+ENUMDOC
+  Used to maintain alignment whilst relaxing.
 ENUM
   BFD_RELOC_MN10300_32_PCREL
 ENUMDOC
index e8bf9fea53bc49a9c5b561cfbc550d0f00ac0e7e..a083a87cd3048d1bad9ce236815c69d8e7103fdb 100644 (file)
@@ -1,3 +1,24 @@
+2000-08-28  Catherine Moore  <clm@redhat.com>
+
+       * tc-v850.c (v850_relax): Declare.
+       (v850_longcode): New routine.
+       (v850_handle_align): New routine.
+       (md_pseudo_table):  Add longcall and longjump.
+       (md_parse_option): Check for relax option.
+       (tc_gen_reloc):  Handle BFD_RELOC_V850_LONGCALL,
+       BFD_RELOC_V850_LONGJUMP, and BFD_RELOC_V850_ALIGN.
+       (md_apply_fix3): Likewise.
+       (v850_force_relocation): Likewise.
+       (v850_comm): Change the current section.
+       (md_assemble):  Ensure that the correct value is put in the
+       fixup.
+       (v850_sdata, v850_tdata, v850_zdata, v850_sbss, v850_tbss,
+       v850_zbss, v850_rosdata, v850_rozdata): Fix section book keeping.
+        Remove redundant v850ea support.
+       * tc-v850.h (HANDLE_ALIGN): Define.
+       (v850_handle_align): Declare.
+       * doc/c-v850.c: Document -mrelax, .longcall and .longjump.
+
 2002-08-28  Svein E. Seldal  <Svein.Seldal@solidas.com>
 
        * configure.in: Add tic4x-coff* and c4x-coff*-coff-coff targets.
index 2d159cd519778bd5a86cea45896b67824dec71e1..aa789b3dc28081e4aa035be9f95ea32c0385985f 100644 (file)
@@ -78,6 +78,8 @@ const relax_typeS md_relax_table[] = {
   {0x1fffff, -0x200000, 4, 0},
 };
 
+static int  v850_relax = 0;
+
 /* Fixups.  */
 #define MAX_INSN_FIXUPS (5)
 struct v850_fixup {
@@ -394,7 +396,13 @@ v850_comm (area)
        }
       else
        {
+          segT   old_sec;
+          int    old_subsec;
+
        allocate_common:
+          old_sec = now_seg;
+          old_subsec = now_subseg;
+
          S_SET_VALUE (symbolP, (valueT) size);
          S_SET_ALIGN (symbolP, temp);
          S_SET_EXTERNAL (symbolP);
@@ -411,6 +419,9 @@ v850_comm (area)
            default:
              abort ();
            }
+
+         obj_elf_section_change_hook ();
+         subseg_set (old_sec, old_subsec);
        }
     }
   else
@@ -468,10 +479,45 @@ set_machine (number)
     {
     case 0:               processor_mask = PROCESSOR_V850;   break;
     case bfd_mach_v850e:  processor_mask = PROCESSOR_V850E;  break;
-    case bfd_mach_v850ea: processor_mask = PROCESSOR_V850EA; break;
     }
 }
 
+static void v850_longcode PARAMS ((int));
+
+static void
+v850_longcode (type)
+     int type;
+{
+  expressionS ex;
+
+  if (! v850_relax)
+    {
+      if (type == 1)
+       as_warn (".longcall pseudo-op seen when not relaxing");
+      else
+       as_warn (".longjump pseudo-op seen when not relaxing"); 
+    }
+
+  expression (&ex);
+
+  if (ex.X_op != O_symbol || ex.X_add_number != 0)
+    {
+      as_bad ("bad .longcall format");
+      ignore_rest_of_line ();
+
+      return;
+    }
+
+  if (type == 1) 
+    fix_new_exp (frag_now, frag_now_fix (), 4, & ex, 1,
+                BFD_RELOC_V850_LONGCALL);
+  else
+    fix_new_exp (frag_now, frag_now_fix (), 4, & ex, 1,
+                BFD_RELOC_V850_LONGJUMP);
+
+  demand_empty_rest_of_line ();
+}
+
 /* The target specific pseudo-ops which we support.  */
 const pseudo_typeS md_pseudo_table[] = {
   { "sdata",           v850_seg,               SDATA_SECTION           },
@@ -492,9 +538,10 @@ const pseudo_typeS md_pseudo_table[] = {
   { "call_table_data", v850_seg,               CALL_TABLE_DATA_SECTION },
   { "call_table_text", v850_seg,               CALL_TABLE_TEXT_SECTION },
   { "v850e",           set_machine,            bfd_mach_v850e          },
-  { "v850ea",          set_machine,            bfd_mach_v850ea         },
   { "file", (void (*) PARAMS ((int))) dwarf2_directive_file, 0 },
   { "loc",             dwarf2_directive_loc,   0                       },
+  { "longcall",         v850_longcode,          1                       },
+  { "longjump",         v850_longcode,          2                       },
   { NULL,              NULL,                   0                       }
 };
 
@@ -1103,8 +1150,9 @@ md_show_usage (stream)
   fprintf (stream, _("  -mwarn-unsigned-overflow  Warn if unsigned immediate values overflow\n"));
   fprintf (stream, _("  -mv850                    The code is targeted at the v850\n"));
   fprintf (stream, _("  -mv850e                   The code is targeted at the v850e\n"));
-  fprintf (stream, _("  -mv850ea                  The code is targeted at the v850ea\n"));
   fprintf (stream, _("  -mv850any                 The code is generic, despite any processor specific instructions\n"));
+  fprintf (stream, _("  -mrelax                   Enable relaxation\n"));
+  
 }
 
 int
@@ -1138,19 +1186,16 @@ md_parse_option (c, arg)
       machine = bfd_mach_v850e;
       processor_mask = PROCESSOR_V850E;
     }
-  else if (strcmp (arg, "v850ea") == 0)
-    {
-      machine = bfd_mach_v850ea;
-      processor_mask = PROCESSOR_V850EA;
-    }
   else if (strcmp (arg, "v850any") == 0)
     {
       /* Tell the world that this is for any v850 chip.  */
       machine = 0;
 
       /* But support instructions for the extended versions.  */
-      processor_mask = PROCESSOR_V850EA;
+      processor_mask = PROCESSOR_V850E;
     }
+  else if (strcmp (arg, "relax") == 0)
+    v850_relax = 1;
   else
     {
       /* xgettext:c-format  */
@@ -1275,17 +1320,9 @@ void
 md_begin ()
 {
   char *prev_name = "";
-  register const struct v850_opcode *op;
-
-  if (strncmp (TARGET_CPU, "v850ea", 6) == 0)
-    {
-      if (machine == -1)
-       machine = bfd_mach_v850ea;
+  const struct v850_opcode *op;
 
-      if (processor_mask == -1)
-       processor_mask = PROCESSOR_V850EA;
-    }
-  else if (strncmp (TARGET_CPU, "v850e", 5) == 0)
+  if (strncmp (TARGET_CPU, "v850e", 5) == 0)
     {
       if (machine == -1)
        machine = bfd_mach_v850e;
@@ -1750,8 +1787,7 @@ md_assemble (str)
 
                      extra_data_after_insn = true;
                      extra_data_len        = 4;
-                     extra_data            = ex.X_add_number;
-                     ex.X_add_number       = 0;
+                     extra_data            = 0;
                      break;
 
                    default:
@@ -2215,12 +2251,32 @@ tc_gen_reloc (seg, fixp)
   if (fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY
       || fixp->fx_r_type == BFD_RELOC_VTABLE_INHERIT)
     reloc->addend = fixp->fx_offset;
+  else if (   fixp->fx_r_type == BFD_RELOC_V850_LONGCALL
+          || fixp->fx_r_type == BFD_RELOC_V850_LONGJUMP
+           || fixp->fx_r_type == BFD_RELOC_V850_ALIGN)
+    reloc->addend = fixp->fx_offset;
   else
     reloc->addend = fixp->fx_addnumber;
 
   return reloc;
 }
 
+void
+v850_handle_align (frag)
+     fragS * frag;
+{
+  if (v850_relax
+      && frag->fr_type == rs_align
+      && frag->fr_address + frag->fr_fix > 0
+      && frag->fr_offset > 1
+      && now_seg != bss_section
+      && now_seg != v850_seg_table[SBSS_SECTION].s
+      && now_seg != v850_seg_table[TBSS_SECTION].s
+      && now_seg != v850_seg_table[ZBSS_SECTION].s)
+    fix_new (frag, frag->fr_fix, 2, & abs_symbol, frag->fr_offset, 0,
+           BFD_RELOC_V850_ALIGN);
+}
+
 /* Return current size of variable part of frag.  */
 
 int
@@ -2261,6 +2317,8 @@ md_apply_fix3 (fixP, valueP, seg)
   char *where;
 
   if (fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT
+      || fixP->fx_r_type == BFD_RELOC_V850_LONGCALL
+      || fixP->fx_r_type == BFD_RELOC_V850_LONGJUMP
       || fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
     {
       fixP->fx_done = 0;
@@ -2268,10 +2326,11 @@ md_apply_fix3 (fixP, valueP, seg)
     }
 
   if (fixP->fx_addsy == (symbolS *) NULL)
+    fixP->fx_addnumber = value,
     fixP->fx_done = 1;
 
   else if (fixP->fx_pcrel)
-    ;
+    fixP->fx_addnumber = fixP->fx_offset;
 
   else
     {
@@ -2287,6 +2346,7 @@ md_apply_fix3 (fixP, valueP, seg)
                            _("expression too complex"));
            }
        }
+      fixP->fx_addnumber = value;
     }
 
   if ((int) fixP->fx_r_type >= (int) BFD_RELOC_UNUSED)
@@ -2345,8 +2405,6 @@ md_apply_fix3 (fixP, valueP, seg)
       else if (fixP->fx_size == 4)
        bfd_putl32 (value, (unsigned char *) where);
     }
-
-  fixP->fx_addnumber = value;
 }
 \f
 /* Parse a cons expression.  We have to handle hi(), lo(), etc
@@ -2430,5 +2488,17 @@ v850_force_relocation (fixP)
       || fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
     return 1;
 
+  if (   fixP->fx_r_type == BFD_RELOC_V850_LONGCALL
+      || fixP->fx_r_type == BFD_RELOC_V850_LONGJUMP)
+    return 1;
+
+  if (v850_relax
+      && (fixP->fx_pcrel
+        || fixP->fx_r_type == BFD_RELOC_V850_ALIGN
+        || fixP->fx_r_type == BFD_RELOC_V850_22_PCREL
+        || fixP->fx_r_type == BFD_RELOC_V850_9_PCREL
+        || fixP->fx_r_type >= BFD_RELOC_UNUSED))
+    return 1;
+
   return 0;
 }
index 8257428eabecaa7524a1f9b5d1085c0333da0c0b..f3827e7c9c1726f4ac8ba2c0169cb595d4ed5465 100644 (file)
@@ -70,6 +70,11 @@ extern void cons_fix_new_v850 PARAMS ((fragS *, int, int, expressionS *));
 #define TC_GENERIC_RELAX_TABLE md_relax_table
 extern const struct relax_type md_relax_table[];
 
+/* When relaxing, we need to generate
+   relocations for alignment directives.  */
+#define HANDLE_ALIGN(frag) v850_handle_align (frag)
+extern void v850_handle_align PARAMS ((fragS *));
+
 /* This section must be in the small data area (pointed to by GP).  */
 #define SHF_V850_GPREL         0x10000000
 /* This section must be in the tiny data area (pointed to by EP).  */
index 4b36461ee52b69fe5aed03cd1c09ce6ed5dad984..f67ad5c74348670411ec3fcfe8b1266ac55cab68 100644 (file)
@@ -62,6 +62,14 @@ routines used by the code produced by GCC for all versions of the v850
 architecture, together with support routines only used by the V850E
 architecture.
 
+@cindex @code{-mrelax} command line option, V850
+@item -mrelax
+Enables relaxation.  This allows the .longcall and .longjump pseudo
+ops to be used in the assembler source code.  These ops label sections
+of code which are either a long function call or a long branch.  The
+assembler will then flag these sections of code and the linker will
+attempt to relax them.
+
 @end table
 
 
@@ -354,10 +362,23 @@ example:
 will put the call the function whoes address is held in the call table
 at the location labeled 'table_func1'.
 
+@cindex @code{longcall} pseudo-op, V850
+@item .longcall @code{name}
+Indicates that the following sequence of instructions is a long call
+to function @code{name}.  The linker will attempt to shorten this call
+sequence if @code{name} is within a 22bit offset of the call.  Only
+valid if the @code{-mrelax} command line switch has been enabled.
+
+@cindex @code{longjump} pseudo-op, V850
+@item .longjump @code{name}
+Indicates that the following sequence of instructions is a long jump
+to label @code{name}.  The linker will attempt to shorten this code
+sequence if @code{name} is within a 22bit offset of the jump.  Only
+valid if the @code{-mrelax} command line switch has been enabled.
+
 @end table
 
 
 For information on the V850 instruction set, see @cite{V850
 Family 32-/16-Bit single-Chip Microcontroller Architecture Manual} from NEC.
 Ltd.
-
index a7dfa25965b661f25b13d12ddb2fffc4daffbb34..0ffa6ab9d31625e3c820972612725f03d5b526ea 100644 (file)
@@ -1,3 +1,8 @@
+2002-08-28  Catherine Moore  <clm@redhat.com>
+
+       * elf/v850.h (R_V850_LONGCALL, R_V850_ALIGN,
+       R_V850_LONGJUMP): New relocations.
+
 2002-08-15  Alan Modra  <amodra@bigpond.net.au>
 
        * i370.h: Define relocs using reloc-macros.h.
index 62b9541e8e98296218d4ffdd3ea00e270918b6af..a15c9ee0864a1b1b1b93b28265cca7a0089a2833 100644 (file)
@@ -1,22 +1,22 @@
 /* V850 ELF support for BFD.
-   Copyright 1997, 1998, 2000 Free Software Foundation, Inc.
+   Copyright 1997, 1998, 2000, 2002 Free Software Foundation, Inc.
    Created by Michael Meissner, Cygnus Support <meissner@cygnus.com>
 
-This file is part of BFD, the Binary File Descriptor library.
+   This file is part of BFD, the Binary File Descriptor library.
 
-This program is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or
-(at your option) any later version.
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
 
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
 
-You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 
 /* This file holds definitions specific to the MIPS ELF ABI.  Note
    that most of this is not actually implemented by BFD.  */
@@ -35,18 +35,15 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 /* v850e code.  */
 #define E_V850E_ARCH           0x10000000
 
-/* v850ea code.  */
-#define E_V850EA_ARCH          0x20000000
 
+/* Flags for the st_other field.  */
+#define V850_OTHER_SDA         0x01    /* Symbol had SDA relocations.  */
+#define V850_OTHER_ZDA         0x02    /* Symbol had ZDA relocations.  */
+#define V850_OTHER_TDA         0x04    /* Symbol had TDA relocations.  */
+#define V850_OTHER_TDA_BYTE    0x08    /* Symbol had TDA byte relocations.  */
+#define V850_OTHER_ERROR       0x80    /* Symbol had an error reported.  */
 
-/* Flags for the st_other field */
-#define V850_OTHER_SDA         0x01    /* symbol had SDA relocations */
-#define V850_OTHER_ZDA         0x02    /* symbol had ZDA relocations */
-#define V850_OTHER_TDA         0x04    /* symbol had TDA relocations */
-#define V850_OTHER_TDA_BYTE    0x08    /* symbol had TDA byte relocations */
-#define V850_OTHER_ERROR       0x80    /* symbol had an error reported */
-
-/* V850 relocations */
+/* V850 relocations.  */
 #include "elf/reloc-macros.h"
 
 START_RELOC_NUMBERS (v850_reloc_type)
@@ -75,6 +72,9 @@ START_RELOC_NUMBERS (v850_reloc_type)
      RELOC_NUMBER( R_V850_CALLT_16_16_OFFSET, 22)      /* For callt */
      RELOC_NUMBER (R_V850_GNU_VTINHERIT, 23)
      RELOC_NUMBER (R_V850_GNU_VTENTRY, 24)
+     RELOC_NUMBER (R_V850_LONGCALL, 25)
+     RELOC_NUMBER (R_V850_LONGJUMP, 26)
+     RELOC_NUMBER (R_V850_ALIGN, 27)
 END_RELOC_NUMBERS (R_V850_max)
 
 \f
@@ -103,5 +103,4 @@ END_RELOC_NUMBERS (R_V850_max)
 /* Section contains the .scommon data.  */
 #define SHT_V850_ZCOMMON       0x70000002
 
-
 #endif /* _ELF_V850_H */