add a heavily cleaned up version of ubicom32 toolchain support
authorFelix Fietkau <nbd@openwrt.org>
Fri, 21 Aug 2009 22:31:47 +0000 (22:31 +0000)
committerFelix Fietkau <nbd@openwrt.org>
Fri, 21 Aug 2009 22:31:47 +0000 (22:31 +0000)
SVN-Revision: 17346

scripts/config.sub
target/Config.in
toolchain/binutils/patches/2.19.1/600-ubicom32_binutils_20090818.patch [new file with mode: 0644]
toolchain/gcc/Config.in
toolchain/gcc/Config.version
toolchain/gcc/patches/4.4.0/600-ubicom_support.patch [new file with mode: 0644]
toolchain/kernel-headers/Makefile
toolchain/kernel-headers/patches-2.6.28/100-ubicom_headers.patch [new file with mode: 0644]
toolchain/uClibc/config-0.9.30.1/common
toolchain/uClibc/config-0.9.30.1/ubicom32 [new file with mode: 0644]
toolchain/uClibc/patches-0.9.30.1/600-ubicom32-uClibc.patch [new file with mode: 0644]

index c060f44..139347a 100755 (executable)
@@ -284,6 +284,7 @@ case $basic_machine in
        | spu | strongarm \
        | tahoe | thumb | tic4x | tic80 | tron \
        | v850 | v850e \
+       | ubicom32 \
        | we32k \
        | x86 | xc16x | xscale | xscalee[bl] | xstormy16 | xtensa \
        | z8k)
@@ -367,6 +368,7 @@ case $basic_machine in
        | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \
        | tron-* \
        | v850-* | v850e-* | vax-* \
+       | ubicom32-* \
        | we32k-* \
        | x86-* | x86_64-* | xc16x-* | xps100-* | xscale-* | xscalee[bl]-* \
        | xstormy16-* | xtensa-* \
index ffd81d3..0d597e6 100644 (file)
@@ -124,6 +124,10 @@ config sparc
 config x86_64
        bool
 
+config ubicom32
+       select BIG_ENDIAN
+       bool
+
 config ARCH
        string
        default "arm"     if arm
@@ -144,4 +148,5 @@ config ARCH
        default "sh4eb"   if sh4eb
        default "sparc"   if sparc
        default "x86_64"  if x86_64
+       default "ubicom32"  if ubicom32
 
diff --git a/toolchain/binutils/patches/2.19.1/600-ubicom32_binutils_20090818.patch b/toolchain/binutils/patches/2.19.1/600-ubicom32_binutils_20090818.patch
new file mode 100644 (file)
index 0000000..f95c05d
--- /dev/null
@@ -0,0 +1,48967 @@
+--- a/bfd/archures.c
++++ b/bfd/archures.c
+@@ -375,6 +375,11 @@ DESCRIPTION
+ .  bfd_arch_score,     {* Sunplus score *} 
+ .  bfd_arch_openrisc,  {* OpenRISC *}
+ .  bfd_arch_mmix,      {* Donald Knuth's educational processor.  *}
++.  bfd_arch_ubicom32,
++.#define bfd_mach_ubicom32        0
++.#define bfd_mach_ubicom32dsp     1
++.#define bfd_mach_ubicom32ver4      2
++.#define bfd_mach_ubicom32posix     3
+ .  bfd_arch_xstormy16,
+ .#define bfd_mach_xstormy16   1
+ .  bfd_arch_msp430,    {* Texas Instruments MSP430 architecture.  *}
+@@ -501,6 +506,7 @@ extern const bfd_arch_info_type bfd_tic3
+ extern const bfd_arch_info_type bfd_tic4x_arch;
+ extern const bfd_arch_info_type bfd_tic54x_arch;
+ extern const bfd_arch_info_type bfd_tic80_arch;
++extern const bfd_arch_info_type bfd_ubicom32_arch;
+ extern const bfd_arch_info_type bfd_v850_arch;
+ extern const bfd_arch_info_type bfd_vax_arch;
+ extern const bfd_arch_info_type bfd_we32k_arch;
+@@ -570,6 +576,7 @@ static const bfd_arch_info_type * const 
+     &bfd_tic4x_arch,
+     &bfd_tic54x_arch,
+     &bfd_tic80_arch,
++    &bfd_ubicom32_arch,
+     &bfd_v850_arch,
+     &bfd_vax_arch,
+     &bfd_w65_arch,
+--- a/bfd/bfd-in2.h
++++ b/bfd/bfd-in2.h
+@@ -1997,6 +1997,11 @@ enum bfd_architecture
+   bfd_arch_score,     /* Sunplus score */ 
+   bfd_arch_openrisc,  /* OpenRISC */
+   bfd_arch_mmix,      /* Donald Knuth's educational processor.  */
++  bfd_arch_ubicom32,
++#define bfd_mach_ubicom32          0
++#define bfd_mach_ubicom32dsp       1
++#define bfd_mach_ubicom32ver4      2
++#define bfd_mach_ubicom32posix     3
+   bfd_arch_xstormy16,
+ #define bfd_mach_xstormy16     1
+   bfd_arch_msp430,    /* Texas Instruments MSP430 architecture.  */
+@@ -3908,6 +3913,41 @@ instructions  */
+   BFD_RELOC_VPE4KMATH_DATA,
+   BFD_RELOC_VPE4KMATH_INSN,
++/* Ubicom UBICOM32 Relocations.  */
++  BFD_RELOC_UBICOM32_21_PCREL,
++  BFD_RELOC_UBICOM32_24_PCREL,
++  BFD_RELOC_UBICOM32_HI24,
++  BFD_RELOC_UBICOM32_LO7_S,
++  BFD_RELOC_UBICOM32_LO7_2_S,
++  BFD_RELOC_UBICOM32_LO7_4_S,
++  BFD_RELOC_UBICOM32_LO7_D,
++  BFD_RELOC_UBICOM32_LO7_2_D,
++  BFD_RELOC_UBICOM32_LO7_4_D,
++  BFD_RELOC_UBICOM32_LO7_CALLI,
++  BFD_RELOC_UBICOM32_LO16_CALLI,
++  BFD_RELOC_UBICOM32_GOT_HI24,
++  BFD_RELOC_UBICOM32_GOT_LO7_S,
++  BFD_RELOC_UBICOM32_GOT_LO7_2_S,
++  BFD_RELOC_UBICOM32_GOT_LO7_4_S,
++  BFD_RELOC_UBICOM32_GOT_LO7_D,
++  BFD_RELOC_UBICOM32_GOT_LO7_2_D,
++  BFD_RELOC_UBICOM32_GOT_LO7_4_D,
++  BFD_RELOC_UBICOM32_FUNCDESC_GOT_HI24,
++  BFD_RELOC_UBICOM32_FUNCDESC_GOT_LO7_S,
++  BFD_RELOC_UBICOM32_FUNCDESC_GOT_LO7_2_S,
++  BFD_RELOC_UBICOM32_FUNCDESC_GOT_LO7_4_S,
++  BFD_RELOC_UBICOM32_FUNCDESC_GOT_LO7_D,
++  BFD_RELOC_UBICOM32_FUNCDESC_GOT_LO7_2_D,
++  BFD_RELOC_UBICOM32_FUNCDESC_GOT_LO7_4_D,
++  BFD_RELOC_UBICOM32_GOT_LO7_CALLI,
++  BFD_RELOC_UBICOM32_FUNCDESC_GOT_LO7_CALLI,
++  BFD_RELOC_UBICOM32_FUNCDESC_VALUE,
++  BFD_RELOC_UBICOM32_FUNCDESC,
++  BFD_RELOC_UBICOM32_GOTOFFSET_LO,
++  BFD_RELOC_UBICOM32_GOTOFFSET_HI,
++  BFD_RELOC_UBICOM32_FUNCDESC_GOTOFFSET_LO,
++  BFD_RELOC_UBICOM32_FUNCDESC_GOTOFFSET_HI,
++
+ /* These two relocations are used by the linker to determine which of
+ the entries in a C++ virtual function table are actually used.  When
+ the --gc-sections option is given, the linker will zero out the entries
+--- a/bfd/config.bfd
++++ b/bfd/config.bfd
+@@ -1432,6 +1432,11 @@ case "${targ}" in
+     targ_underscore=yes
+     ;;
++  ubicom32-*-*)
++    targ_defvec=bfd_elf32_ubicom32_vec
++    targ_selvecs=bfd_elf32_ubicom32fdpic_vec
++    ;;
++
+   v850-*-*)
+     targ_defvec=bfd_elf32_v850_vec
+     ;;
+--- a/bfd/configure
++++ b/bfd/configure
+@@ -19743,6 +19743,8 @@ do
+     bfd_elf32_tradbigmips_vec)  tb="$tb elf32-mips.lo elfxx-mips.lo elf-vxworks.lo elf32.lo $elf ecofflink.lo" ;;
+     bfd_elf32_tradlittlemips_vec) tb="$tb elf32-mips.lo elfxx-mips.lo elf-vxworks.lo elf32.lo $elf ecofflink.lo" ;;
+     bfd_elf32_us_cris_vec)    tb="$tb elf32-cris.lo elf32.lo $elf" ;;
++    bfd_elf32_ubicom32_vec)   tb="$tb elf32-ubicom32.lo elf32.lo $elf" ;;
++    bfd_elf32_ubicom32fdpic_vec)      tb="$tb elf32-ubicom32.lo elf32.lo $elf" ;;
+     bfd_elf32_v850_vec)               tb="$tb elf32-v850.lo elf32.lo $elf" ;;
+     bfd_elf32_vax_vec)                tb="$tb elf32-vax.lo elf32.lo $elf" ;;
+     bfd_elf32_xstormy16_vec)  tb="$tb elf32-xstormy16.lo elf32.lo $elf" ;;
+--- a/bfd/configure.in
++++ b/bfd/configure.in
+@@ -736,6 +736,8 @@ do
+     bfd_elf32_tradbigmips_vec)  tb="$tb elf32-mips.lo elfxx-mips.lo elf-vxworks.lo elf32.lo $elf ecofflink.lo" ;;
+     bfd_elf32_tradlittlemips_vec) tb="$tb elf32-mips.lo elfxx-mips.lo elf-vxworks.lo elf32.lo $elf ecofflink.lo" ;;
+     bfd_elf32_us_cris_vec)    tb="$tb elf32-cris.lo elf32.lo $elf" ;;
++    bfd_elf32_ubicom32_vec)   tb="$tb elf32-ubicom32.lo elf32.lo $elf" ;;
++    bfd_elf32_ubicom32fdpic_vec) tb="$tb elf32-ubicom32.lo elf32.lo $elf" ;;
+     bfd_elf32_v850_vec)               tb="$tb elf32-v850.lo elf32.lo $elf" ;;
+     bfd_elf32_vax_vec)                tb="$tb elf32-vax.lo elf32.lo $elf" ;;
+     bfd_elf32_xstormy16_vec)  tb="$tb elf32-xstormy16.lo elf32.lo $elf" ;;
+--- /dev/null
++++ b/bfd/cpu-ubicom32.c
+@@ -0,0 +1,126 @@
++/* BFD support for the Ubicom32 processor.
++   Copyright (C) 2000 Free Software Foundation, Inc.
++
++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 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.  */
++
++#include "bfd.h"
++#include "sysdep.h"
++#include "libbfd.h"
++
++static const bfd_arch_info_type *
++ubicom32_arch_compatible (const bfd_arch_info_type *a,
++                      const bfd_arch_info_type *b)
++{
++  if (a->arch != b->arch)
++    return NULL;
++
++  if (a->bits_per_word != b->bits_per_word)
++    return NULL;
++
++  if (a->mach > b->mach)
++    return a;
++
++  if (b->mach > a->mach)
++    return b;
++
++  if (b->mach == bfd_mach_ubicom32ver4  && 
++      strcmp("ubicom32uclinux", b->printable_name) == 0) {
++        return b;
++  }
++  
++  return a;
++}
++
++const bfd_arch_info_type bfd_ubicom32_uclinux_arch =
++{
++  32,                         /* bits per word */
++  32,                         /* bits per address */
++  8,                          /* bits per byte */
++  bfd_arch_ubicom32,          /* architecture */
++  bfd_mach_ubicom32ver4,      /* machine */
++  "ubicom32",                 /* architecture name */
++  "ubicom32uclinux",          /* printable name */
++  3,                          /* section align power */
++  FALSE,                      /* the default ? */
++  ubicom32_arch_compatible,   /* architecture comparison fn */
++  bfd_default_scan,           /* string to architecture convert fn */
++  NULL                                /* next in list */
++};
++
++const bfd_arch_info_type bfd_ubicom32_posix_arch =
++{
++  32,                         /* bits per word */
++  32,                         /* bits per address */
++  8,                          /* bits per byte */
++  bfd_arch_ubicom32,          /* architecture */
++  bfd_mach_ubicom32ver4,      /* machine */
++  "ubicom32",                 /* architecture name */
++  "ubicom32posix",            /* printable name */
++  3,                          /* section align power */
++  FALSE,                      /* the default ? */
++  bfd_default_compatible,     /* architecture comparison fn */
++  bfd_default_scan,           /* string to architecture convert fn */
++  &bfd_ubicom32_uclinux_arch, /* next in list */
++};
++
++const bfd_arch_info_type bfd_ubicom32_ver4_arch =
++{
++  32,                         /* bits per word */
++  32,                         /* bits per address */
++  8,                          /* bits per byte */
++  bfd_arch_ubicom32,          /* architecture */
++  bfd_mach_ubicom32ver4,      /* machine */
++  "ubicom32",                 /* architecture name */
++  "ubicom32ver4",             /* printable name */
++  3,                          /* section align power */
++  FALSE,                      /* the default ? */
++  ubicom32_arch_compatible,   /* architecture comparison fn */
++  bfd_default_scan,           /* string to architecture convert fn */
++  &bfd_ubicom32_posix_arch    /* next in list */
++};
++
++const bfd_arch_info_type bfd_ubicom32_nonext_arch =
++{
++  32,                         /* bits per word */
++  32,                         /* bits per address */
++  8,                          /* bits per byte */
++  bfd_arch_ubicom32,          /* architecture */
++  bfd_mach_ubicom32dsp,               /* machine */
++  "ubicom32",                 /* architecture name */
++  "ubicom32dsp",              /* printable name */
++  3,                          /* section align power */
++  FALSE,                      /* the default ? */
++  bfd_default_compatible,     /* architecture comparison fn */
++  bfd_default_scan,           /* string to architecture convert fn */
++  & bfd_ubicom32_ver4_arch    /* next in list */
++};
++
++const bfd_arch_info_type bfd_ubicom32_arch =
++{
++  32,                         /* bits per word */
++  32,                         /* bits per address */
++  8,                          /* bits per byte */
++  bfd_arch_ubicom32,          /* architecture */
++  bfd_mach_ubicom32,          /* machine */
++  "ubicom32",                 /* architecture name */
++  "ubicom32",                 /* printable name */
++  3,                          /* section align power */
++  TRUE,                               /* the default ? */
++  bfd_default_compatible,     /* architecture comparison fn */
++  bfd_default_scan,           /* string to architecture convert fn */
++  & bfd_ubicom32_nonext_arch  /* next in list */
++};
+--- a/bfd/doc/archures.texi
++++ b/bfd/doc/archures.texi
+@@ -303,6 +303,11 @@ enum bfd_architecture
+   bfd_arch_ip2k,      /* Ubicom IP2K microcontrollers. */
+ #define bfd_mach_ip2022        1
+ #define bfd_mach_ip2022ext     2
++  bfd_arch_ubicom32,
++#define bfd_mach_ubicom32          0
++#define bfd_mach_ubicom32dsp       1
++#define bfd_mach_ubicom32ver4      2
++#define bfd_mach_ubicom32posix     3
+  bfd_arch_iq2000,     /* Vitesse IQ2000.  */
+ #define bfd_mach_iq2000        1
+ #define bfd_mach_iq10          2
+--- /dev/null
++++ b/bfd/elf32-ubicom32.c
+@@ -0,0 +1,5008 @@
++/* Ubicom32 specific support for 32-bit ELF
++   Copyright 2000 Free Software Foundation, Inc.
++
++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 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.  */
++
++#include <string.h>
++#include "bfd.h"
++#include "sysdep.h"
++#include "libbfd.h"
++#include "elf-bfd.h"
++#include "elf/ubicom32.h"
++#include "elf/dwarf2.h"
++
++/* Call offset = signed 24bit word offset
++   => 26bit signed byte offset.  */
++#define UBICOM32_CALL_MAX_POS_OFFS ((1 << 25) - 1)
++#define UBICOM32_CALL_MAX_NEG_OFFS (-(1 << 25))
++
++#define UNDEFINED_SYMBOL (~(bfd_vma)0)
++#define BASEADDR(SEC) ((SEC)->output_section->vma + (SEC)->output_offset)
++
++#if 0
++#define DPRINTF(fmt, ...) { printf("DBG %4d:"  fmt, __LINE__, __VA_ARGS__); fflush(stdout); }
++#else
++#define DPRINTF(fmt, ...) {}
++#endif
++struct debugLineInfo {
++  unsigned int startOffset;
++  unsigned int length;
++  char *sectionName;
++  unsigned int startRelocIndex;
++  unsigned int endRelocIndex;
++  unsigned int discard;
++};
++
++struct debugLineInfoHeader {
++  unsigned int numEntries;
++  struct debugLineInfo linfo[1];
++};
++
++/* we want RELA relocations, not REL */
++#undef USE_REL
++#define USE_RELA
++
++static bfd_reloc_status_type ubicom32_elf_generic_reloc
++  PARAMS ((bfd *abfd, arelent *reloc_entry, asymbol *symbol, PTR data,
++         asection *input_section, bfd *output_bfd, char **error_message));
++static bfd_reloc_status_type ubicom32_elf_relocate_hi16
++  PARAMS ((bfd *,  Elf_Internal_Rela *, bfd_byte *, bfd_vma));
++static bfd_reloc_status_type ubicom32_elf_relocate_lo16
++  PARAMS ((bfd *,  Elf_Internal_Rela *, bfd_byte *, bfd_vma));
++static bfd_reloc_status_type ubicom32_elf_relocate_hi24
++  PARAMS ((bfd *,  Elf_Internal_Rela *,   bfd_byte *, bfd_vma));
++static bfd_reloc_status_type ubicom32_elf_relocate_lo7_s
++  PARAMS ((bfd *,  Elf_Internal_Rela *,   bfd_byte *, bfd_vma));
++static bfd_reloc_status_type ubicom32_elf_relocate_lo7_2_s
++  PARAMS ((bfd *,  Elf_Internal_Rela *,   bfd_byte *, bfd_vma));
++static bfd_reloc_status_type ubicom32_elf_relocate_lo7_4_s
++  PARAMS ((bfd *,  Elf_Internal_Rela *,   bfd_byte *, bfd_vma));
++static bfd_reloc_status_type ubicom32_elf_relocate_lo7_d
++  PARAMS ((bfd *,  Elf_Internal_Rela *,   bfd_byte *, bfd_vma));
++static bfd_reloc_status_type ubicom32_elf_relocate_lo7_2_d
++  PARAMS ((bfd *,  Elf_Internal_Rela *,   bfd_byte *, bfd_vma));
++static bfd_reloc_status_type ubicom32_elf_relocate_lo7_4_d
++  PARAMS ((bfd *,  Elf_Internal_Rela *,   bfd_byte *, bfd_vma));
++static bfd_reloc_status_type ubicom32_elf_relocate_pcrel24
++  PARAMS ((bfd *, asection *, Elf_Internal_Rela *, bfd_byte *, bfd_vma));
++static bfd_reloc_status_type ubicom32_elf_relocate_lo_calli
++  PARAMS ((bfd *,  Elf_Internal_Rela *,   bfd_byte *, bfd_vma, int));
++
++static void ubicom32_info_to_howto_rela
++  PARAMS ((bfd *, arelent *, Elf_Internal_Rela *));
++
++static reloc_howto_type * ubicom32_reloc_type_lookup
++  PARAMS ((bfd *abfd, bfd_reloc_code_real_type code));
++
++static bfd_vma symbol_value
++  PARAMS ((bfd *, Elf_Internal_Rela *));
++static Elf_Internal_Shdr *file_symtab_hdr
++  PARAMS ((bfd *));
++static Elf_Internal_Sym *file_isymbuf
++  PARAMS ((bfd *));
++static Elf_Internal_Rela *section_relocs
++  PARAMS ((bfd *, asection *));
++static bfd_byte *section_contents
++  PARAMS ((bfd *, asection *));
++static bfd_boolean ubicom32_elf_relax_section
++  PARAMS ((bfd *, asection *, struct bfd_link_info *, bfd_boolean *));
++static bfd_boolean ubicom32_elf_relax_calli
++  PARAMS ((bfd *, asection *, bfd_boolean *));
++static bfd_boolean ubicom32_elf_relax_delete_bytes
++  PARAMS ((bfd *, asection *, bfd_vma, int));
++static void adjust_sec_relocations
++  PARAMS ((bfd *, asection *, asection *, bfd_vma, int));
++static void adjust_all_relocations
++  PARAMS ((bfd *, asection *, bfd_vma, int));
++
++static bfd_reloc_status_type ubicom32_final_link_relocate
++  PARAMS ((reloc_howto_type *, bfd *, asection *, bfd_byte *,
++         Elf_Internal_Rela *, bfd_vma));
++static bfd_boolean ubicom32_elf_relocate_section
++  PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *,
++         bfd_byte *, Elf_Internal_Rela *, Elf_Internal_Sym *,
++         asection **));
++
++static bfd_boolean ubicom32_elf_gc_sweep_hook
++  PARAMS ((bfd *, struct bfd_link_info *, asection *, const
++         Elf_Internal_Rela *));
++static asection * ubicom32_elf_gc_mark_hook
++  PARAMS ((asection *, struct bfd_link_info *, Elf_Internal_Rela *, struct
++         elf_link_hash_entry *, Elf_Internal_Sym *));
++static bfd_boolean ubicom32_elf_check_relocs
++  PARAMS ((bfd *, struct bfd_link_info *, asection *,
++         const Elf_Internal_Rela *));
++extern bfd_boolean ubicom32_elf_discard_info
++  PARAMS ((bfd *, struct elf_reloc_cookie *, struct bfd_link_info *));
++
++static bfd_boolean ubicom32_elf_object_p PARAMS ((bfd *));
++static bfd_boolean ubicom32_elf_set_private_flags PARAMS ((bfd *, flagword));
++static bfd_boolean ubicom32_elf_copy_private_bfd_data PARAMS ((bfd *, bfd *));
++static bfd_boolean ubicom32_elf_merge_private_bfd_data PARAMS ((bfd *, bfd *));
++static bfd_boolean ubicom32_elf_print_private_bfd_data PARAMS ((bfd *, PTR));
++
++//static unsigned long read_unsigned_leb128 (bfd *, char *, unsigned int *);
++
++//static long read_signed_leb128 (bfd *, char *, unsigned int *);
++
++/* read dwarf information from a buffer */
++
++#define UBICOM32_HOWTO(t,rs,s,bs,pr,bp,name,sm,dm) \
++    HOWTO(t,                  /* type */ \
++        rs,                   /* rightshift */ \
++        s,                    /* size (0 = byte, 1 = short, 2 = long) */ \
++        bs,                   /* bitsize */ \
++        pr,                   /* pc_relative */ \
++        bp,                   /* bitpos */ \
++        complain_overflow_bitfield,   /* complain_on_overflow */ \
++        ubicom32_elf_generic_reloc,   /* special_function */ \
++        name,                 /* name */ \
++        FALSE,                /* partial_inplace */ \
++        sm,                   /* src_mask */ \
++        dm,                   /* dst_mask */ \
++        pr)                   /* pcrel_offset */
++
++/* Special Note:  For addresses, we must always zero out the top byte of a
++                address because the harvard address space is represented as
++                a single virtual address space that uses the top byte to denote
++                whether the address belongs in the data or program space.  This is
++                done to accomodate GDB which cannot handle program and data addresses
++                overlapping.                                                       */
++
++static reloc_howto_type ubicom32_elf_howto_table [] =
++{
++  /* This reloc does nothing.  */
++  UBICOM32_HOWTO (R_UBICOM32_NONE, 0, 2, 32, FALSE, 0, "R_UBICOM32_NONE", 0, 0),
++
++  /* A 16 bit absolute relocation.  */
++  UBICOM32_HOWTO (R_UBICOM32_16, 0, 1, 16, FALSE, 0,  "R_UBICOM32_16", 0, 0xffff),
++
++  /* A 32 bit absolute relocation.  Must zero top byte of virtual address. */
++  UBICOM32_HOWTO (R_UBICOM32_32, 0, 2, 32, FALSE, 0, "R_UBICOM32_32", 0, 0xffffffff),
++
++  /* A 16 bit indirect relocation, low 16 bits of 32 */
++  UBICOM32_HOWTO (R_UBICOM32_LO16, 0, 2, 16, FALSE, 0, "R_UBICOM32_LO16", 0x0, 0x0000ffff),
++
++  /* A 16 bit indirect relocation, high 16 bits of 32 - must zero top byte of virtual address */
++  UBICOM32_HOWTO (R_UBICOM32_HI16, 0, 2, 16, FALSE, 0, "R_UBICOM32_HI16", 0x0, 0x0000ffff),
++
++  /* A 21 bit relative relocation.  */
++  UBICOM32_HOWTO (R_UBICOM32_21_PCREL, 2, 2, 21, TRUE, 0, "R_UBICOM32_21_PCREL", 0x0, 0x001fffff),
++
++  /* A 24 bit relative relocation.  */
++  UBICOM32_HOWTO (R_UBICOM32_24_PCREL, 2, 2, 24, TRUE, 0, "R_UBICOM32_24_PCREL", 0x0, 0x071fffff),
++
++  /* A 24 bit indirect relocation, bits 31:7 - assume top byte zero. */
++  UBICOM32_HOWTO (R_UBICOM32_HI24, 7, 2, 24, FALSE, 0, "R_UBICOM32_HI24", 0x0, 0x0001ffff),
++
++  /* A source operand low 7 bit indirect relocation. */
++  UBICOM32_HOWTO (R_UBICOM32_LO7_S, 0, 2, 7, FALSE, 0, "R_UBICOM32_LO7_S", 0x0, 0x0000031f),
++
++  /* A source operand low 7 bit .2 insn indirect relocation. */
++  UBICOM32_HOWTO (R_UBICOM32_LO7_2_S, 1, 2, 7, FALSE, 0, "R_UBICOM32_LO7_2_S", 0x0, 0x0000031f),
++
++  /* A source operand low 7 bit .4 insn indirect relocation. */
++  UBICOM32_HOWTO (R_UBICOM32_LO7_4_S, 2, 2, 7, FALSE, 0, "R_UBICOM32_LO7_4_S", 0x0, 0x0000031f),
++
++  /* A destination operand low 7 bit indirect relocation. */
++  UBICOM32_HOWTO (R_UBICOM32_LO7_D, 0, 2, 7, FALSE, 0, "R_UBICOM32_LO7_D", 0x0, 0x031f0000),
++
++  /* A destination operand low 7 bit .2 insn indirect relocation. */
++  UBICOM32_HOWTO (R_UBICOM32_LO7_2_D, 1, 2, 7, FALSE, 0, "R_UBICOM32_LO7_2_D", 0x0, 0x031f0000),
++
++  /* A destination operand low 7 bit .2 insn indirect relocation. */
++  UBICOM32_HOWTO (R_UBICOM32_LO7_4_D, 2, 2, 7, FALSE, 0, "R_UBICOM32_LO7_4_D", 0x0, 0x031f0000),
++
++  /* A 32 bit absolute relocation in debug section.  Must retain top byte of virtual address. */
++  UBICOM32_HOWTO (R_UBICOM32_32_HARVARD, 0, 2, 32, FALSE, 0, "R_UBICOM32_32_HARVARD", 0, 0xffffffff),
++
++  /* A calli offset operand low 7 bit .4 insn indirect relocation. */
++  UBICOM32_HOWTO (R_UBICOM32_LO7_CALLI, 2, 2, 7, FALSE, 0, "R_UBICOM32_LO7_CALLI", 0x0, 0x071f071f),
++
++  /* A calli offset operand low 18 bit .4 insn indirect relocation. */
++  UBICOM32_HOWTO (R_UBICOM32_LO16_CALLI, 2, 2, 16, FALSE, 0, "R_UBICOM32_LO16_CALLI", 0x0, 0x071f071f),
++
++  /* A 24 bit indirect relocation, bits 31:7 - assume top byte zero. */
++  UBICOM32_HOWTO (R_UBICOM32_GOT_HI24, 7, 2, 24, FALSE, 0, "R_UBICOM32_GOT_HI24", 0x0, 0x0001ffff),
++
++  /* A source operand low 7 bit indirect relocation. */
++  UBICOM32_HOWTO (R_UBICOM32_GOT_LO7_S, 0, 2, 7, FALSE, 0, "R_UBICOM32_GOT_LO7_S", 0x0, 0x0000031f),
++
++  /* A source operand low 7 bit .2 insn indirect relocation. */
++  UBICOM32_HOWTO (R_UBICOM32_GOT_LO7_2_S, 1, 2, 7, FALSE, 0, "R_UBICOM32_GOT_LO7_2_S", 0x0, 0x0000031f),
++
++  /* A source operand low 7 bit .4 insn indirect relocation. */
++  UBICOM32_HOWTO (R_UBICOM32_GOT_LO7_4_S, 2, 2, 7, FALSE, 0, "R_UBICOM32_GOT_LO7_4_S", 0x0, 0x0000031f),
++
++  /* A destination operand low 7 bit indirect relocation. */
++  UBICOM32_HOWTO (R_UBICOM32_GOT_LO7_D, 0, 2, 7, FALSE, 0, "R_UBICOM32_GOT_LO7_D", 0x0, 0x031f0000),
++
++  /* A destination operand low 7 bit .2 insn indirect relocation. */
++  UBICOM32_HOWTO (R_UBICOM32_GOT_LO7_2_D, 1, 2, 7, FALSE, 0, "R_UBICOM32_GOT_LO7_2_D", 0x0, 0x031f0000),
++
++  /* A destination operand low 7 bit .2 insn indirect relocation. */
++  UBICOM32_HOWTO (R_UBICOM32_GOT_LO7_4_D, 2, 2, 7, FALSE, 0, "R_UBICOM32_GOT_LO7_4_D", 0x0, 0x031f0000),
++
++  /* A 24 bit indirect relocation, bits 31:7 - assume top byte zero. */
++  UBICOM32_HOWTO (R_UBICOM32_FUNCDESC_GOT_HI24, 7, 2, 24, FALSE, 0, "R_UBICOM32_FUNCDESC_GOT_HI24", 0x0, 0x0001ffff),
++
++  /* A source operand low 7 bit indirect relocation. */
++  UBICOM32_HOWTO (R_UBICOM32_FUNCDESC_GOT_LO7_S, 0, 2, 7, FALSE, 0, "R_UBICOM32_FUNCDESC_GOT_LO7_S", 0x0, 0x0000031f),
++
++  /* A source operand low 7 bit .2 insn indirect relocation. */
++  UBICOM32_HOWTO (R_UBICOM32_FUNCDESC_GOT_LO7_2_S, 1, 2, 7, FALSE, 0, "R_UBICOM32_FUNCDESC_GOT_LO7_2_S", 0x0, 0x0000031f),
++
++  /* A source operand low 7 bit .4 insn indirect relocation. */
++  UBICOM32_HOWTO (R_UBICOM32_FUNCDESC_GOT_LO7_4_S, 2, 2, 7, FALSE, 0, "R_UBICOM32_FUNCDESC_GOT_LO7_4_S", 0x0, 0x0000031f),
++
++  /* A destination operand low 7 bit indirect relocation. */
++  UBICOM32_HOWTO (R_UBICOM32_FUNCDESC_GOT_LO7_D, 0, 2, 7, FALSE, 0, "R_UBICOM32_FUNCDESC_GOT_LO7_D", 0x0, 0x031f0000),
++
++  /* A destination operand low 7 bit .2 insn indirect relocation. */
++  UBICOM32_HOWTO (R_UBICOM32_FUNCDESC_GOT_LO7_2_D, 1, 2, 7, FALSE, 0, "R_UBICOM32_FUNCDESC_GOT_LO7_2_D", 0x0, 0x031f0000),
++
++  /* A destination operand low 7 bit .2 insn indirect relocation. */
++  UBICOM32_HOWTO (R_UBICOM32_FUNCDESC_GOT_LO7_4_D, 2, 2, 7, FALSE, 0, "R_UBICOM32_FUNCDESC_GOT_LO7_4_D", 0x0, 0x031f0000),
++
++  /* A calli offset operand low 7 bit .4 insn indirect relocation. */
++  UBICOM32_HOWTO (R_UBICOM32_GOT_LO7_CALLI, 2, 2, 7, FALSE, 0, "R_UBICOM32_GOT_LO7_CALLI", 0x0, 0x071f071f),
++
++  /* A calli offset operand low 7 bit .4 insn indirect relocation. */
++  UBICOM32_HOWTO (R_UBICOM32_FUNCDESC_GOT_LO7_CALLI, 2, 2, 7, FALSE, 0, "R_UBICOM32_FUNCDESC_GOT_LO7_CALLI", 0x0, 0x071f071f),
++
++  /* A 32 bit absolute relocation.  Must zero top byte of virtual address. */
++  UBICOM32_HOWTO (R_UBICOM32_FUNCDESC_VALUE, 0, 2, 32, FALSE, 0, "R_UBICOM32_FUNCDESC_VALUE", 0, 0xffffffff),
++
++  /* A 32 bit absolute relocation.  Must zero top byte of virtual address. */
++  UBICOM32_HOWTO (R_UBICOM32_FUNCDESC, 0, 2, 32, FALSE, 0, "R_UBICOM32_FUNCDESC", 0, 0xffffffff),
++
++  /* A 16 bit absolute relocation.  */
++  UBICOM32_HOWTO (R_UBICOM32_GOTOFFSET_LO, 0, 1, 16, FALSE, 0,        "R_UBICOM32_GOTOFFSET_LO", 0, 0xffff),
++
++  /* A 16 bit absolute relocation.  */
++  UBICOM32_HOWTO (R_UBICOM32_GOTOFFSET_HI, 0, 1, 16, FALSE, 0,        "R_UBICOM32_GOTOFFSET_HI", 0, 0xffff),
++
++  /* A 16 bit absolute relocation.  */
++  UBICOM32_HOWTO (R_UBICOM32_FUNCDESC_GOTOFFSET_LO, 0, 1, 16, FALSE, 0,       "R_UBICOM32_FUNCDESC_GOTOFFSET_LO", 0, 0xffff),
++
++  /* A 16 bit absolute relocation.  */
++  UBICOM32_HOWTO (R_UBICOM32_FUNCDESC_GOTOFFSET_HI, 0, 1, 16, FALSE, 0,       "R_UBICOM32_FUNCDESC_GOTOFFSET_HI", 0, 0xffff),
++};
++
++/* GNU extension to record C++ vtable hierarchy */
++static reloc_howto_type ubicom32_elf_vtinherit_howto =
++  HOWTO (R_UBICOM32_GNU_VTINHERIT,   /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       0,                     /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       NULL,                  /* special_function */
++       "R_UBICOM32_GNU_VTINHERIT", /* name */
++       FALSE,                 /* partial_inplace */
++       0,                     /* src_mask */
++       0,                     /* dst_mask */
++       FALSE);                /* pcrel_offset */
++
++  /* GNU extension to record C++ vtable member usage */
++static reloc_howto_type ubicom32_elf_vtentry_howto =
++  HOWTO (R_UBICOM32_GNU_VTENTRY,     /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       0,                     /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       _bfd_elf_rel_vtable_reloc_fn,  /* special_function */
++       "R_UBICOM32_GNU_VTENTRY",   /* name */
++       FALSE,                 /* partial_inplace */
++       0,                     /* src_mask */
++       0,                     /* dst_mask */
++       FALSE);                /* pcrel_offset */
++
++extern const bfd_target bfd_elf32_ubicom32fdpic_vec;
++#define IS_FDPIC(bfd) ((bfd)->xvec == &bfd_elf32_ubicom32fdpic_vec)
++\f
++/* Relocation helpers */
++bfd_reloc_status_type
++ubicom32_elf_generic_reloc (abfd,
++                          reloc_entry,
++                          symbol,
++                          data,
++                          input_section,
++                          output_bfd,
++                          error_message)
++     bfd *abfd ATTRIBUTE_UNUSED;
++     arelent *reloc_entry;
++     asymbol *symbol;
++     PTR data ATTRIBUTE_UNUSED;
++     asection *input_section;
++     bfd *output_bfd;
++     char **error_message ATTRIBUTE_UNUSED;
++{
++  if (output_bfd != (bfd *) NULL
++      && (symbol->flags & BSF_SECTION_SYM) == 0
++      && (! reloc_entry->howto->partial_inplace
++        || reloc_entry->addend == 0))
++    {
++      reloc_entry->address += input_section->output_offset;
++      symbol = *reloc_entry->sym_ptr_ptr;
++
++      if((symbol->flags & BSF_OBJECT) == 0)
++      {
++        reloc_entry->addend -= symbol->value;
++      }
++      return bfd_reloc_ok;
++    }
++
++  return bfd_reloc_continue;
++}
++
++bfd_reloc_status_type
++ubicom32_elf_relocate_hi16 (input_bfd, relhi, contents, value)
++     bfd *input_bfd;
++     Elf_Internal_Rela *relhi;
++     bfd_byte *contents;
++     bfd_vma value;
++{
++  bfd_vma insn;
++
++  insn = bfd_get_32 (input_bfd, contents + relhi->r_offset);
++
++  value += relhi->r_addend;
++  value >>= 16;
++  value &= 0xffff;  /* take off top byte of virtual address */
++  insn = ((insn & ~0xFFFF) | value);
++
++  bfd_put_32 (input_bfd, insn, contents + relhi->r_offset);
++  return bfd_reloc_ok;
++}
++
++bfd_reloc_status_type
++ubicom32_elf_relocate_lo16 (input_bfd, relhi, contents, value)
++     bfd *input_bfd;
++     Elf_Internal_Rela *relhi;
++     bfd_byte *contents;
++     bfd_vma value;
++{
++  bfd_vma insn;
++
++  insn = bfd_get_32 (input_bfd, contents + relhi->r_offset);
++
++  value += relhi->r_addend;
++  value &= 0xFFFF;
++  insn = ((insn & ~0xFFFF) | value);
++
++  bfd_put_32 (input_bfd, insn, contents + relhi->r_offset);
++  return bfd_reloc_ok;
++}
++
++bfd_reloc_status_type
++ubicom32_elf_relocate_hi24 (input_bfd, relhi, contents, value)
++     bfd *input_bfd;
++     Elf_Internal_Rela *relhi;
++     bfd_byte *contents;
++     bfd_vma value;
++{
++  bfd_vma insn;
++
++  insn = bfd_get_32 (input_bfd, contents + relhi->r_offset);
++
++  value += relhi->r_addend;
++  if (value & 0x80000000) {
++    fprintf (stderr,"@@@: You are trying load the address of something at %08lx\n  This is >= 0x80000000 and the moveai instruction does not support it!\n",value);
++  }
++  value &= 0x7fffffff; /* zero off top bit of virtual address */
++  value >>= 7;
++  insn = (insn & ~0x071FFFFF);
++
++  insn |= (value & 0x1FFFFF);
++  insn |= (value & 0xe00000) << 3;
++
++  bfd_put_32 (input_bfd, insn, contents + relhi->r_offset);
++  return bfd_reloc_ok;
++}
++
++bfd_reloc_status_type
++ubicom32_elf_relocate_lo7_s (input_bfd, relhi, contents, value)
++     bfd *input_bfd;
++     Elf_Internal_Rela *relhi;
++     bfd_byte *contents;
++     bfd_vma value;
++{
++  bfd_vma insn;
++  bfd_vma top;
++  bfd_vma bottom;
++
++  insn = bfd_get_32 (input_bfd, contents + relhi->r_offset);
++
++  value += relhi->r_addend;
++  value &= 0x7f;
++
++  /* must split up value into top 2 bits and bottom 5 bits */
++  top = value >> 5;
++  bottom = value & 0x1f;
++  insn = ((insn & ~0x31f) | (top << 8) | bottom);
++
++  bfd_put_32 (input_bfd, insn, contents + relhi->r_offset);
++  return bfd_reloc_ok;
++}
++
++bfd_reloc_status_type
++ubicom32_elf_relocate_lo7_2_s (input_bfd, relhi, contents, value)
++     bfd *input_bfd;
++     Elf_Internal_Rela *relhi;
++     bfd_byte *contents;
++     bfd_vma value;
++{
++  bfd_vma insn;
++  bfd_vma top;
++  bfd_vma bottom;
++
++  insn = bfd_get_32 (input_bfd, contents + relhi->r_offset);
++
++  value += relhi->r_addend;
++  value &= 0x7f;
++  value >>= 1;  /* must shift by 1 because this is .2 insn */
++
++  /* must split up value into top 2 bits and bottom 5 bits */
++  top = value >> 5;
++  bottom = value & 0x1f;
++  insn = ((insn & ~0x31f) | (top << 8) | bottom);
++
++  bfd_put_32 (input_bfd, insn, contents + relhi->r_offset);
++  return bfd_reloc_ok;
++}
++
++bfd_reloc_status_type
++ubicom32_elf_relocate_lo7_4_s (input_bfd, relhi, contents, value)
++     bfd *input_bfd;
++     Elf_Internal_Rela *relhi;
++     bfd_byte *contents;
++     bfd_vma value;
++{
++  bfd_vma insn;
++  bfd_vma top;
++  bfd_vma bottom;
++
++  insn = bfd_get_32 (input_bfd, contents + relhi->r_offset);
++
++  value += relhi->r_addend;
++  value &= 0x7f;
++  value >>= 2;  /* must shift by 1 because this is .4 insn */
++
++  /* must split up value into top 2 bits and bottom 5 bits */
++  top = value >> 5;
++  bottom = value & 0x1f;
++  insn = ((insn & ~0x31f) | (top << 8) | bottom);
++
++  bfd_put_32 (input_bfd, insn, contents + relhi->r_offset);
++  return bfd_reloc_ok;
++}
++
++bfd_reloc_status_type
++ubicom32_elf_relocate_lo7_d (input_bfd, relhi, contents, value)
++     bfd *input_bfd;
++     Elf_Internal_Rela *relhi;
++     bfd_byte *contents;
++     bfd_vma value;
++{
++  bfd_vma insn;
++  bfd_vma top;
++  bfd_vma bottom;
++
++  insn = bfd_get_32 (input_bfd, contents + relhi->r_offset);
++
++  value += relhi->r_addend;
++  value &= 0x7f;
++
++  /* must split up value into top 2 bits and bottom 5 bits */
++  top = value >> 5;
++  bottom = value & 0x1f;
++  insn = ((insn & ~0x031f0000) | (top << 24) | (bottom << 16));
++
++  bfd_put_32 (input_bfd, insn, contents + relhi->r_offset);
++  return bfd_reloc_ok;
++}
++
++bfd_reloc_status_type
++ubicom32_elf_relocate_lo7_2_d (input_bfd, relhi, contents, value)
++     bfd *input_bfd;
++     Elf_Internal_Rela *relhi;
++     bfd_byte *contents;
++     bfd_vma value;
++{
++  bfd_vma insn;
++  bfd_vma top;
++  bfd_vma bottom;
++
++  insn = bfd_get_32 (input_bfd, contents + relhi->r_offset);
++
++  value += relhi->r_addend;
++  value &= 0x7f;
++  value >>= 1; /* must shift by 1 because this is for a .2 insn */
++
++  /* must split up value into top 2 bits and bottom 5 bits */
++  top = value >> 5;
++  bottom = value & 0x1f;
++  insn = ((insn & ~0x031f0000) | (top << 24) | (bottom << 16));
++
++  bfd_put_32 (input_bfd, insn, contents + relhi->r_offset);
++  return bfd_reloc_ok;
++}
++
++bfd_reloc_status_type
++ubicom32_elf_relocate_lo7_4_d (input_bfd, relhi, contents, value)
++     bfd *input_bfd;
++     Elf_Internal_Rela *relhi;
++     bfd_byte *contents;
++     bfd_vma value;
++{
++  bfd_vma insn;
++  bfd_vma top;
++  bfd_vma bottom;
++
++  insn = bfd_get_32 (input_bfd, contents + relhi->r_offset);
++
++  value += relhi->r_addend;
++  value &= 0x7f;
++  value >>= 2; /* must shift by 2 because this is for a .4 insn */
++
++  /* must split up value into top 2 bits and bottom 5 bits */
++  top = value >> 5;
++  bottom = value & 0x1f;
++  insn = ((insn & ~0x031f0000) | (top << 24) | (bottom << 16));
++
++  bfd_put_32 (input_bfd, insn, contents + relhi->r_offset);
++  return bfd_reloc_ok;
++}
++
++/* Perform the relocation for call instructions */
++static bfd_reloc_status_type
++ubicom32_elf_relocate_pcrel24 (input_bfd, input_section, rello, contents, value)
++     bfd *input_bfd;
++     asection *input_section;
++     Elf_Internal_Rela *rello;
++     bfd_byte *contents;
++     bfd_vma value;
++{
++  bfd_vma insn;
++  bfd_vma value_top;
++  bfd_vma value_bottom;
++
++  /* Grab the instruction */
++  insn = bfd_get_32 (input_bfd, contents + rello->r_offset);
++
++  value -= input_section->output_section->vma + input_section->output_offset;
++  value -= rello->r_offset;
++  value += rello->r_addend;
++
++  /* insn uses bottom 24 bits of relocation value times 4 */
++  if (value & 0x03)
++    return bfd_reloc_dangerous;
++
++  value = (value & 0x3ffffff) >> 2;
++
++  if ((long) value > 0xffffff)
++    return bfd_reloc_overflow;
++
++  value_top = (value >> 21) << 24;
++  value_bottom = value & 0x1fffff;
++
++  insn = insn & 0xf8e00000;
++  insn = insn | value_top | value_bottom;
++
++  bfd_put_32 (input_bfd, insn, contents + rello->r_offset);
++
++  return bfd_reloc_ok;
++}
++
++static bfd_reloc_status_type
++ubicom32_elf_relocate_gotoffset_lo (input_bfd, input_section, rello, contents, value)
++     bfd *input_bfd;
++     asection *input_section;
++     Elf_Internal_Rela *rello;
++     bfd_byte *contents;
++     bfd_vma value;
++{
++  bfd_vma insn;
++
++  /* Grab the instruction */
++  insn = bfd_get_32 (input_bfd, contents + rello->r_offset);
++
++  /* Truncte to 16 and store. */
++  value &= 0xffff;
++
++  insn = (insn & 0xffff0000) | value;
++
++  /* output it. */
++  bfd_put_32 (input_bfd, insn, contents + rello->r_offset);
++}
++
++static bfd_reloc_status_type
++ubicom32_elf_relocate_funcdesc_gotoffset_lo (input_bfd, input_section, rello, contents, value)
++     bfd *input_bfd;
++     asection *input_section;
++     Elf_Internal_Rela *rello;
++     bfd_byte *contents;
++     bfd_vma value;
++{
++  bfd_vma insn;
++
++  /* Grab the instruction */
++  insn = bfd_get_32 (input_bfd, contents + rello->r_offset);
++
++  /* Truncte to 16 and store. */
++  value &= 0xffff;
++
++  insn = (insn & 0xffff0000) | value;
++
++  /* output it. */
++  bfd_put_32 (input_bfd, insn, contents + rello->r_offset);
++}
++
++static bfd_reloc_status_type
++ubicom32_elf_relocate_funcdesc (input_bfd, input_section, rello, contents, value)
++     bfd *input_bfd;
++     asection *input_section;
++     Elf_Internal_Rela *rello;
++     bfd_byte *contents;
++     bfd_vma value;
++{
++  bfd_vma insn;
++
++  /* Grab the instruction */
++  insn = bfd_get_32 (input_bfd, contents + rello->r_offset);
++
++  /* Truncte to 16 and store. */
++  value &= 0xffff;
++
++  insn = (insn & 0xffff0000) | value;
++
++  /* output it. */
++  bfd_put_32 (input_bfd, insn, contents + rello->r_offset);
++}
++
++bfd_reloc_status_type
++ubicom32_elf_relocate_lo_calli (input_bfd, relhi, contents, value, bits)
++     bfd *input_bfd;
++     Elf_Internal_Rela *relhi;
++     bfd_byte *contents;
++     bfd_vma value;
++     int bits;
++{
++  bfd_vma insn;
++
++  insn = bfd_get_32 (input_bfd, contents + relhi->r_offset);
++
++  value += relhi->r_addend;
++  value &= (1 << bits) - 1;
++  value >>= 2;  /* must shift by 2 because this is .4 insn */
++
++  /* must split up value into top 2 bits and bottom 5 bits */
++  insn &= ~0x071f071f;
++  insn |= (value & 0x1f) << 0;
++  value >>= 5;
++  insn |= (value & 0x07) << 8;
++  value >>= 3;
++  insn |= (value & 0x1f) << 16;
++  value >>= 5;
++  insn |= (value & 0x07) << 24;
++
++  bfd_put_32 (input_bfd, insn, contents + relhi->r_offset);
++  return bfd_reloc_ok;
++}
++
++\f
++/* Set the howto pointer for a UBICOM32 ELF reloc.  */
++
++static void
++ubicom32_info_to_howto_rela (abfd, cache_ptr, dst)
++     bfd * abfd ATTRIBUTE_UNUSED;
++     arelent * cache_ptr;
++     Elf_Internal_Rela * dst;
++{
++  unsigned int r_type;
++
++  r_type = ELF32_R_TYPE (dst->r_info);
++  switch (r_type)
++    {
++    case R_UBICOM32_GNU_VTINHERIT:
++      cache_ptr->howto = &ubicom32_elf_vtinherit_howto;
++      break;
++
++    case R_UBICOM32_GNU_VTENTRY:
++      cache_ptr->howto = &ubicom32_elf_vtentry_howto;
++      break;
++
++    default:
++      cache_ptr->howto = &ubicom32_elf_howto_table[r_type];
++      break;
++    }
++}
++
++\f
++static reloc_howto_type *
++ubicom32_reloc_type_lookup (abfd, code)
++     bfd * abfd ATTRIBUTE_UNUSED;
++     bfd_reloc_code_real_type code;
++{
++  switch (code)
++    {
++    case BFD_RELOC_NONE:
++      return &ubicom32_elf_howto_table[(int)R_UBICOM32_NONE];
++
++    case BFD_RELOC_16:
++      return &ubicom32_elf_howto_table[(int)R_UBICOM32_16];
++
++    case BFD_RELOC_32:
++      return &ubicom32_elf_howto_table[(int)R_UBICOM32_32];
++
++    case BFD_RELOC_LO16:
++      return &ubicom32_elf_howto_table[(int)R_UBICOM32_LO16];
++
++    case BFD_RELOC_HI16:
++      return &ubicom32_elf_howto_table[(int)R_UBICOM32_HI16];
++
++    case BFD_RELOC_UBICOM32_HI24:
++      return &ubicom32_elf_howto_table[(int)R_UBICOM32_HI24];
++
++    case BFD_RELOC_UBICOM32_LO7_S:
++      return &ubicom32_elf_howto_table[(int)R_UBICOM32_LO7_S];
++
++    case BFD_RELOC_UBICOM32_LO7_2_S:
++      return &ubicom32_elf_howto_table[(int)R_UBICOM32_LO7_2_S];
++
++    case BFD_RELOC_UBICOM32_LO7_4_S:
++      return &ubicom32_elf_howto_table[(int)R_UBICOM32_LO7_4_S];
++
++    case BFD_RELOC_UBICOM32_LO7_D:
++      return &ubicom32_elf_howto_table[(int)R_UBICOM32_LO7_D];
++
++    case BFD_RELOC_UBICOM32_LO7_2_D:
++      return &ubicom32_elf_howto_table[(int)R_UBICOM32_LO7_2_D];
++
++    case BFD_RELOC_UBICOM32_LO7_4_D:
++      return &ubicom32_elf_howto_table[(int)R_UBICOM32_LO7_4_D];
++
++    case BFD_RELOC_UBICOM32_21_PCREL:
++      return &ubicom32_elf_howto_table[(int)R_UBICOM32_21_PCREL];
++
++    case BFD_RELOC_UBICOM32_24_PCREL:
++      return &ubicom32_elf_howto_table[(int)R_UBICOM32_24_PCREL];
++
++    case BFD_RELOC_UBICOM32_GOT_HI24:
++      return &ubicom32_elf_howto_table[(int)R_UBICOM32_GOT_HI24];
++
++    case BFD_RELOC_UBICOM32_GOT_LO7_S:
++      return &ubicom32_elf_howto_table[(int)R_UBICOM32_GOT_LO7_S];
++
++    case BFD_RELOC_UBICOM32_GOT_LO7_2_S:
++      return &ubicom32_elf_howto_table[(int)R_UBICOM32_GOT_LO7_2_S];
++
++    case BFD_RELOC_UBICOM32_GOT_LO7_4_S:
++      return &ubicom32_elf_howto_table[(int)R_UBICOM32_GOT_LO7_4_S];
++
++    case BFD_RELOC_UBICOM32_GOT_LO7_D:
++      return &ubicom32_elf_howto_table[(int)R_UBICOM32_GOT_LO7_D];
++
++    case BFD_RELOC_UBICOM32_GOT_LO7_2_D:
++      return &ubicom32_elf_howto_table[(int)R_UBICOM32_GOT_LO7_2_D];
++
++    case BFD_RELOC_UBICOM32_GOT_LO7_4_D:
++      return &ubicom32_elf_howto_table[(int)R_UBICOM32_GOT_LO7_4_D];
++
++    case BFD_RELOC_UBICOM32_FUNCDESC_GOT_HI24:
++      return &ubicom32_elf_howto_table[(int)R_UBICOM32_FUNCDESC_GOT_HI24];
++
++    case BFD_RELOC_UBICOM32_FUNCDESC_GOT_LO7_S:
++      return &ubicom32_elf_howto_table[(int)R_UBICOM32_FUNCDESC_GOT_LO7_S];
++
++    case BFD_RELOC_UBICOM32_FUNCDESC_GOT_LO7_2_S:
++      return &ubicom32_elf_howto_table[(int)R_UBICOM32_FUNCDESC_GOT_LO7_2_S];
++
++    case BFD_RELOC_UBICOM32_FUNCDESC_GOT_LO7_4_S:
++      return &ubicom32_elf_howto_table[(int)R_UBICOM32_FUNCDESC_GOT_LO7_4_S];
++
++    case BFD_RELOC_UBICOM32_FUNCDESC_GOT_LO7_D:
++      return &ubicom32_elf_howto_table[(int)R_UBICOM32_FUNCDESC_GOT_LO7_D];
++
++    case BFD_RELOC_UBICOM32_FUNCDESC_GOT_LO7_2_D:
++      return &ubicom32_elf_howto_table[(int)R_UBICOM32_FUNCDESC_GOT_LO7_2_D];
++
++    case BFD_RELOC_UBICOM32_FUNCDESC_GOT_LO7_4_D:
++      return &ubicom32_elf_howto_table[(int)R_UBICOM32_FUNCDESC_GOT_LO7_4_D];
++
++    case BFD_RELOC_UBICOM32_LO7_CALLI:
++      return &ubicom32_elf_howto_table[(int)R_UBICOM32_LO7_CALLI];
++
++    case BFD_RELOC_UBICOM32_GOT_LO7_CALLI:
++      return &ubicom32_elf_howto_table[(int)R_UBICOM32_GOT_LO7_CALLI];
++
++    case BFD_RELOC_UBICOM32_FUNCDESC_GOT_LO7_CALLI:
++      return &ubicom32_elf_howto_table[(int)R_UBICOM32_FUNCDESC_GOT_LO7_CALLI];
++
++    case BFD_RELOC_UBICOM32_LO16_CALLI:
++      return &ubicom32_elf_howto_table[(int)R_UBICOM32_LO16_CALLI];
++
++    case BFD_RELOC_UBICOM32_FUNCDESC_VALUE:
++      return &ubicom32_elf_howto_table[(int)R_UBICOM32_FUNCDESC_VALUE];
++
++    case BFD_RELOC_UBICOM32_FUNCDESC:
++      return &ubicom32_elf_howto_table[(int)R_UBICOM32_FUNCDESC];
++
++    case BFD_RELOC_UBICOM32_GOTOFFSET_LO:
++      return &ubicom32_elf_howto_table[(int)R_UBICOM32_GOTOFFSET_LO];
++
++    case BFD_RELOC_UBICOM32_GOTOFFSET_HI:
++      return &ubicom32_elf_howto_table[(int)R_UBICOM32_GOTOFFSET_HI];
++
++    case BFD_RELOC_UBICOM32_FUNCDESC_GOTOFFSET_LO:
++      return &ubicom32_elf_howto_table[(int)R_UBICOM32_FUNCDESC_GOTOFFSET_LO];
++
++    case BFD_RELOC_UBICOM32_FUNCDESC_GOTOFFSET_HI:
++      return &ubicom32_elf_howto_table[(int)R_UBICOM32_FUNCDESC_GOTOFFSET_HI];
++
++    case BFD_RELOC_VTABLE_INHERIT:
++      return &ubicom32_elf_vtinherit_howto;
++
++    case BFD_RELOC_VTABLE_ENTRY:
++      return &ubicom32_elf_vtentry_howto;
++
++    default:
++      /* Pacify gcc -Wall. */
++      return NULL;
++    }
++
++  return NULL;
++}
++
++static reloc_howto_type *
++ubicom32_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
++                          const char *r_name)
++{
++  unsigned int i;
++
++  for (i = 0;
++       i < (sizeof (ubicom32_elf_howto_table)
++          / sizeof (ubicom32_elf_howto_table[0]));
++       i++)
++    if (ubicom32_elf_howto_table[i].name != NULL
++      && strcasecmp (ubicom32_elf_howto_table[i].name, r_name) == 0)
++      return &ubicom32_elf_howto_table[i];
++
++  return NULL;
++}
++
++/* Return the value of the symbol associated with the relocation IREL.  */
++
++static bfd_vma
++symbol_value (abfd, irel)
++     bfd *abfd;
++     Elf_Internal_Rela *irel;
++{
++  Elf_Internal_Shdr *symtab_hdr = file_symtab_hdr (abfd);
++  Elf_Internal_Sym *isymbuf = file_isymbuf (abfd);
++
++  if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info)
++    {
++      Elf_Internal_Sym *isym;
++      asection *sym_sec;
++
++      isym = isymbuf + ELF32_R_SYM (irel->r_info);
++      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);
++
++      return isym->st_value + BASEADDR (sym_sec);
++    }
++  else
++    {
++      unsigned long indx;
++      struct elf_link_hash_entry *h;
++
++      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)
++      return UNDEFINED_SYMBOL;
++
++      return (h->root.u.def.value + BASEADDR (h->root.u.def.section));
++    }
++}
++
++
++static Elf_Internal_Shdr *
++file_symtab_hdr (abfd)
++     bfd *abfd;
++{
++  return &elf_tdata (abfd)->symtab_hdr;
++}
++
++static Elf_Internal_Sym *
++file_isymbuf (abfd)
++     bfd *abfd;
++{
++  Elf_Internal_Shdr *symtab_hdr;
++
++  symtab_hdr = file_symtab_hdr (abfd);
++  if (symtab_hdr->sh_info == 0)
++    return NULL;
++
++  if (symtab_hdr->contents == NULL)
++    {
++      Elf_Internal_Sym * contents = bfd_elf_get_elf_syms (abfd, symtab_hdr, symtab_hdr->sh_info, 0,
++                                                        NULL, NULL, NULL);
++      symtab_hdr->contents = (unsigned char *) contents;
++    }
++
++  return (Elf_Internal_Sym *) symtab_hdr->contents;
++}
++
++static Elf_Internal_Rela *
++section_relocs (abfd, sec)
++     bfd *abfd;
++     asection *sec;
++{
++  if ((sec->flags & SEC_RELOC) == 0)
++    return NULL;
++
++  if (sec->reloc_count == 0)
++    return NULL;
++
++  if (elf_section_data (sec)->relocs == NULL)
++    elf_section_data (sec)->relocs =
++      _bfd_elf_link_read_relocs (abfd, sec, NULL, NULL, 1);
++
++  return elf_section_data (sec)->relocs;
++}
++
++static bfd_byte *
++section_contents (abfd, sec)
++     bfd *abfd;
++     asection *sec;
++{
++  bfd_byte *contents;
++
++  sec->rawsize = sec->rawsize ? sec->rawsize: sec->size;
++
++  if (elf_section_data (sec)->this_hdr.contents)
++    return elf_section_data (sec)->this_hdr.contents;
++
++  contents = (bfd_byte *) bfd_malloc (sec->rawsize);
++  if (contents == NULL)
++    return NULL;
++
++  if (! bfd_get_section_contents (abfd, sec, contents,
++                                (file_ptr) 0, sec->rawsize))
++    {
++      free (contents);
++      return NULL;
++    }
++
++  elf_section_data (sec)->this_hdr.contents = contents;
++  return contents;
++}
++
++/* This function handles relaxing for the ubicom32.
++
++   Principle: Start with the first page and remove page instructions that
++   are not require on this first page. By removing page instructions more
++   code will fit into this page - repeat until nothing more can be achieved
++   for this page. Move on to the next page.
++
++   Processing the pages one at a time from the lowest page allows a removal
++   only policy to be used - pages can be removed but are never reinserted.  */
++
++static bfd_boolean
++ubicom32_elf_relax_section (abfd, sec, link_info, again)
++     bfd *abfd;
++     asection *sec;
++     struct bfd_link_info *link_info;
++     bfd_boolean *again;
++{
++  /* Assume nothing changes.  */
++  *again = FALSE;
++
++  /* We don't have to do anything for a relocatable link,
++     if this section does not have relocs, or if this is
++     not a code section.  */
++  if (link_info->relocatable
++      || (sec->flags & SEC_RELOC) == 0
++      || sec->reloc_count == 0
++      || (sec->flags & SEC_CODE) == 0)
++    return TRUE;
++
++  /* If this is the first time we have been called
++      for this section, initialise the cooked size.
++  if (sec->_cooked_size == 0)
++    sec->_cooked_size = sec->rawsize;
++  */
++
++  /* This is where all the relaxation actually get done.  */
++  if (!ubicom32_elf_relax_calli (abfd, sec, again))
++    return FALSE;
++
++  if (sec->rawsize != sec->size)
++    sec->size = sec->rawsize;
++
++  /* Success!  */
++  return TRUE;
++}
++
++static bfd_boolean
++ubicom32_elf_relax_calli (abfd, sec, again)
++     bfd *abfd;
++     asection *sec;
++     bfd_boolean *again;
++{
++  bfd_byte *contents = section_contents (abfd, sec);
++  Elf_Internal_Rela *irelbase = section_relocs (abfd, sec);
++  Elf_Internal_Rela *irelend = irelbase + sec->reloc_count;
++  Elf_Internal_Rela *irel_moveai = NULL;
++  Elf_Internal_Rela *irel;
++  unsigned long insn;
++  bfd_vma symval;
++  bfd_vma pc;
++  bfd_vma dest;
++  signed long offs;
++
++  /* Walk thru the section looking for relaxation opertunities.  */
++  for (irel = irelbase; irel < irelend; irel++)
++    {
++      /* Remember last moveai instruction */
++      if (ELF32_R_TYPE (irel->r_info) == (int) R_UBICOM32_HI24)
++      {
++        irel_moveai = irel;
++        continue;
++      }
++
++      /* Ignore non calli instructions */
++      if (ELF32_R_TYPE (irel->r_info) != (int) R_UBICOM32_LO7_CALLI)
++      continue;
++
++      /* calli instruction => verify it is a calli instruction
++       using a5 with a 5 bit positive offset */
++      insn = bfd_get_32 (abfd, (bfd_byte *)(contents + irel->r_offset));
++      if ((insn & 0xffffffe0) != 0xf0a000a0)
++      continue;
++      symval = symbol_value (abfd, irel);
++      if (symval == UNDEFINED_SYMBOL)
++      continue;
++      dest = symval + irel->r_addend;
++
++      /* Check proceeding instruction for a valid moveai */
++      if (!irel_moveai)
++      continue;
++      if (irel_moveai->r_offset != (irel->r_offset - 4))
++      continue;
++      insn = bfd_get_32 (abfd, (bfd_byte *)(contents + irel_moveai->r_offset));
++      if ((insn & 0xf8e00000) !=  0xe0a00000)
++      continue;
++      symval = symbol_value (abfd, irel_moveai);
++      if (symval == UNDEFINED_SYMBOL)
++      continue;
++      symval += irel_moveai->r_addend;
++      if (symval != dest)
++      continue;
++
++      /* Check offset required */
++      pc = BASEADDR (sec) + irel_moveai->r_offset;
++      offs = dest - pc;
++      if (offs > (UBICOM32_CALL_MAX_POS_OFFS + 4))
++      continue;
++      if (offs < UBICOM32_CALL_MAX_NEG_OFFS)
++      continue;
++
++      /* Replace calli with a call instruction */
++      irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_UBICOM32_24_PCREL);
++      bfd_put_32 (abfd, 0xd8a00000, contents + irel->r_offset);
++
++      /* Delete moveai instruction */
++      irel_moveai->r_info = ELF32_R_INFO (ELF32_R_SYM (irel_moveai->r_info), R_UBICOM32_NONE);
++      if (!ubicom32_elf_relax_delete_bytes (abfd, sec, irel_moveai->r_offset, 4))
++      return FALSE;
++
++      /* Modified => will need to iterate relaxation again.  */
++      *again = TRUE;
++    }
++
++  return TRUE;
++}
++
++/* Delete some bytes from a section while relaxing.  */
++
++static bfd_boolean
++ubicom32_elf_relax_delete_bytes (abfd, sec, addr, count)
++     bfd *abfd;
++     asection *sec;
++     bfd_vma addr;
++     int count;
++{
++  bfd_byte *contents = elf_section_data (sec)->this_hdr.contents;
++  bfd_vma endaddr = sec->rawsize;
++
++  /* Actually delete the bytes.  */
++  memmove (contents + addr, contents + addr + count,
++         endaddr - addr - count);
++
++  sec->rawsize -= count;
++
++  adjust_all_relocations (abfd, sec, addr + count, -count);
++  return TRUE;
++}
++
++/* Adjust all the relocations entries after adding or inserting instructions.  */
++
++static void
++adjust_sec_relocations (abfd, sec_to_process, addr_sec, addr, count)
++     bfd *abfd;
++     asection *sec_to_process;
++     asection *addr_sec;
++     bfd_vma addr;
++     int count;
++{
++  Elf_Internal_Shdr *symtab_hdr;
++  Elf_Internal_Sym *isymbuf, *isym;
++  Elf_Internal_Rela *irel, *irelend, *irelbase;
++  unsigned int addr_shndx;
++
++  irelbase = section_relocs (abfd, sec_to_process);
++  if (irelbase == NULL)
++    return;
++  irelend = irelbase + sec_to_process->reloc_count;
++
++  symtab_hdr = file_symtab_hdr (abfd);
++  isymbuf = file_isymbuf (abfd);
++
++  addr_shndx = _bfd_elf_section_from_bfd_section (abfd, addr_sec);
++
++  for (irel = irelbase; irel < irelend; irel++)
++    {
++      if (ELF32_R_TYPE (irel->r_info) != R_UBICOM32_NONE)
++      {
++        /* Get the value of the symbol referred to by the reloc.  */
++        if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info)
++          {
++            asection *sym_sec;
++            bfd_vma xaddr, symval, relval;
++
++            /* A local symbol.  */
++            isym = isymbuf + ELF32_R_SYM (irel->r_info);
++            sym_sec = bfd_section_from_elf_index (abfd, isym->st_shndx);
++            xaddr = BASEADDR (addr_sec) + addr;
++            symval = BASEADDR (sym_sec) + isym->st_value;
++            relval = symval + irel->r_addend;
++
++            if ((isym->st_shndx == addr_shndx)
++                && (xaddr > symval)
++                && (xaddr <= relval))
++              irel->r_addend += count;
++          }
++      }
++
++      /* Adjust irel base address for PC space relocations after a deleted instruction.  */
++      if (sec_to_process == addr_sec)
++      {
++        if (addr <= irel->r_offset)
++          irel->r_offset += count;
++      }
++    }
++}
++
++static void
++adjust_all_relocations (abfd, sec, addr, count)
++     bfd *abfd;
++     asection *sec;
++     bfd_vma addr;
++     int count;
++{
++  Elf_Internal_Shdr *symtab_hdr;
++  Elf_Internal_Sym *isymbuf, *isym, *isymend;
++  struct elf_link_hash_entry **sym_hashes;
++  struct elf_link_hash_entry **end_hashes;
++  unsigned int symcount;
++  asection *section;
++  unsigned int shndx;
++
++  symtab_hdr = file_symtab_hdr (abfd);
++  isymbuf = file_isymbuf (abfd);
++
++  shndx = _bfd_elf_section_from_bfd_section (abfd, sec);
++
++  /* Adjust all relocations that are affected.  */
++  for (section = abfd->sections; section != NULL; section = section->next)
++    adjust_sec_relocations (abfd, section, sec, addr, count);
++
++  /* Adjust the local symbols defined in this section.  */
++  isymend = isymbuf + symtab_hdr->sh_info;
++  for (isym = isymbuf; isym < isymend; isym++)
++    {
++      if (isym->st_shndx == shndx
++        && addr <= isym->st_value)
++      isym->st_value += count;
++    }
++
++  /* Now adjust the global symbols defined in this section.  */
++  symcount = (symtab_hdr->sh_size / sizeof (Elf32_External_Sym)
++            - symtab_hdr->sh_info);
++  sym_hashes = elf_sym_hashes (abfd);
++  end_hashes = sym_hashes + symcount;
++  for (; sym_hashes < end_hashes; sym_hashes++)
++    {
++      struct elf_link_hash_entry *sym_hash = *sym_hashes;
++
++      if ((sym_hash->root.type == bfd_link_hash_defined
++         || sym_hash->root.type == bfd_link_hash_defweak)
++        && sym_hash->root.u.def.section == sec)
++      {
++        if (addr <= sym_hash->root.u.def.value)
++          sym_hash->root.u.def.value += count;
++      }
++    }
++}
++
++/* Perform a single relocation.  By default we use the standard BFD
++   routines. */
++
++static bfd_reloc_status_type
++ubicom32_final_link_relocate (howto, input_bfd, input_section, contents, rel, relocation)
++     reloc_howto_type *  howto;
++     bfd *               input_bfd;
++     asection *          input_section;
++     bfd_byte *          contents;
++     Elf_Internal_Rela * rel;
++     bfd_vma             relocation;
++{
++  bfd_reloc_status_type r = bfd_reloc_ok;
++
++  switch (howto->type)
++    {
++    default:
++      r = _bfd_final_link_relocate (howto, input_bfd, input_section,
++                                  contents, rel->r_offset,
++                                  relocation, rel->r_addend);
++    }
++
++  return r;
++}
++
++/* Relocate a UBICOM32 ELF section.
++   There is some attempt to make this function usable for many architectures,
++   both USE_REL and USE_RELA ['twould be nice if such a critter existed],
++   if only to serve as a learning tool.
++
++   The RELOCATE_SECTION function is called by the new ELF backend linker
++   to handle the relocations for a section.
++
++   The relocs are always passed as Rela structures; if the section
++   actually uses Rel structures, the r_addend field will always be
++   zero.
++
++   This function is responsible for adjusting the section contents as
++   necessary, and (if using Rela relocs and generating a relocatable
++   output file) adjusting the reloc addend as necessary.
++
++   This function does not have to worry about setting the reloc
++   address or the reloc symbol index.
++
++   LOCAL_SYMS is a pointer to the swapped in local symbols.
++
++   LOCAL_SECTIONS is an array giving the section in the input file
++   corresponding to the st_shndx field of each local symbol.
++
++   The global hash table entry for the global symbols can be found
++   via elf_sym_hashes (input_bfd).
++
++   When generating relocatable output, this function must handle
++   STB_LOCAL/STT_SECTION symbols specially.  The output symbol is
++   going to be the section symbol corresponding to the output
++   section, which means that the addend must be adjusted
++   accordingly.  */
++
++static bfd_boolean
++ubicom32_elf_relocate_section (output_bfd, info, input_bfd, input_section,
++                             contents, relocs, local_syms, local_sections)
++     bfd *                   output_bfd ATTRIBUTE_UNUSED;
++     struct bfd_link_info *  info;
++     bfd *                   input_bfd;
++     asection *              input_section;
++     bfd_byte *              contents;
++     Elf_Internal_Rela *     relocs;
++     Elf_Internal_Sym *      local_syms;
++     asection **             local_sections;
++{
++  Elf_Internal_Shdr *           symtab_hdr;
++  struct elf_link_hash_entry ** sym_hashes;
++  Elf_Internal_Rela *           rel;
++  Elf_Internal_Rela *           relend;
++  struct debugLineInfoHeader *lh = NULL;
++  int cooked_size, discard_size;
++  bfd_byte *src, *dest, *content_end;
++  unsigned int i;
++
++  symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr;
++  sym_hashes = elf_sym_hashes (input_bfd);
++  relend     = relocs + input_section->reloc_count;
++
++  for (rel = relocs; rel < relend; rel ++)
++    {
++      reloc_howto_type *           howto;
++      unsigned long                r_symndx;
++      Elf_Internal_Sym *           sym;
++      asection *                   sec;
++      struct elf_link_hash_entry * h;
++      bfd_vma                      relocation;
++      bfd_reloc_status_type        r;
++      const char *                 name = NULL;
++      int                          r_type;
++
++      r_type = ELF32_R_TYPE (rel->r_info);
++
++      if ( r_type == R_UBICOM32_GNU_VTINHERIT
++         || r_type == R_UBICOM32_GNU_VTENTRY)
++      continue;
++
++      r_symndx = ELF32_R_SYM (rel->r_info);
++
++      if (info->relocatable)
++      {
++        /* This is a relocatable 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;
++      }
++
++      /* This is a final link.  */
++      howto  = ubicom32_elf_howto_table + ELF32_R_TYPE (rel->r_info);
++      h      = NULL;
++      sym    = NULL;
++      sec    = NULL;
++
++      if (r_symndx < symtab_hdr->sh_info)
++      {
++        sym = local_syms + r_symndx;
++        sec = local_sections [r_symndx];
++        relocation = (sec->output_section->vma
++                      + sec->output_offset
++                      + sym->st_value);
++
++        name = bfd_elf_string_from_elf_section
++          (input_bfd, symtab_hdr->sh_link, sym->st_name);
++        name = (name == NULL) ? bfd_section_name (input_bfd, sec) : name;
++      }
++      else
++      {
++        h = sym_hashes [r_symndx - symtab_hdr->sh_info];
++
++        while (h->root.type == bfd_link_hash_indirect
++               || h->root.type == bfd_link_hash_warning)
++          h = (struct elf_link_hash_entry *) h->root.u.i.link;
++
++        name = h->root.root.string;
++
++        if (h->root.type == bfd_link_hash_defined
++            || h->root.type == bfd_link_hash_defweak)
++          {
++            sec = h->root.u.def.section;
++            relocation = (h->root.u.def.value
++                          + sec->output_section->vma
++                          + sec->output_offset);
++          }
++        else if (h->root.type == bfd_link_hash_undefweak)
++          {
++            relocation = 0;
++          }
++        else
++          {
++            if (! ((*info->callbacks->undefined_symbol)
++                   (info, h->root.root.string, input_bfd,
++                    input_section, rel->r_offset,
++                    (!info->shared ))))
++              return FALSE;
++            relocation = 0;
++          }
++      }
++
++      switch (r_type)
++      {
++      case R_UBICOM32_LO16:
++        r = ubicom32_elf_relocate_lo16 (input_bfd, rel, contents, relocation);
++        break;
++
++      case R_UBICOM32_HI16:
++        r = ubicom32_elf_relocate_hi16 (input_bfd, rel, contents, relocation);
++        break;
++
++      case R_UBICOM32_HI24:
++        r = ubicom32_elf_relocate_hi24 (input_bfd, rel, contents, relocation);
++        break;
++
++      case R_UBICOM32_LO7_S:
++        r = ubicom32_elf_relocate_lo7_s (input_bfd, rel, contents, relocation);
++        break;
++
++      case R_UBICOM32_LO7_2_S:
++        r = ubicom32_elf_relocate_lo7_2_s (input_bfd, rel, contents, relocation);
++        break;
++
++      case R_UBICOM32_LO7_4_S:
++        r = ubicom32_elf_relocate_lo7_4_s (input_bfd, rel, contents, relocation);
++        break;
++
++      case R_UBICOM32_LO7_D:
++        r = ubicom32_elf_relocate_lo7_d (input_bfd, rel, contents, relocation);
++        break;
++
++      case R_UBICOM32_LO7_2_D:
++        r = ubicom32_elf_relocate_lo7_2_d (input_bfd, rel, contents, relocation);
++        break;
++
++      case R_UBICOM32_LO7_4_D:
++        r = ubicom32_elf_relocate_lo7_4_d (input_bfd, rel, contents, relocation);
++        break;
++
++      case R_UBICOM32_24_PCREL:
++        r = ubicom32_elf_relocate_pcrel24 (input_bfd, input_section, rel, contents, relocation);
++        break;
++
++      case R_UBICOM32_LO7_CALLI:
++        r = ubicom32_elf_relocate_lo_calli (input_bfd, rel, contents, relocation, 7);
++        break;
++
++      case R_UBICOM32_LO16_CALLI:
++        r = ubicom32_elf_relocate_lo_calli (input_bfd, rel, contents, relocation, 18);
++        break;
++
++      case R_UBICOM32_32:
++        /* relocation &= ~(0xff << 24); */
++        /* FALLTHROUGH */
++
++      default:
++        r = ubicom32_final_link_relocate (howto, input_bfd, input_section,
++                                          contents, rel, relocation);
++        break;
++      }
++
++      if (r != bfd_reloc_ok)
++      {
++        const char * msg = (const char *) NULL;
++
++        switch (r)
++          {
++          case bfd_reloc_overflow:
++            r = info->callbacks->reloc_overflow
++              (info, NULL, name, howto->name, (bfd_vma) 0,
++               input_bfd, input_section, rel->r_offset);
++            break;
++
++          case bfd_reloc_undefined:
++            r = info->callbacks->undefined_symbol
++              (info, name, input_bfd, input_section, rel->r_offset, TRUE);
++            break;
++
++          case bfd_reloc_outofrange:
++            msg = _("internal error: out of range error");
++            break;
++
++          case bfd_reloc_notsupported:
++            msg = _("internal error: unsupported relocation error");
++            break;
++
++          case bfd_reloc_dangerous:
++            msg = _("internal error: dangerous relocation");
++            break;
++
++          default:
++            msg = _("internal error: unknown error");
++            break;
++          }
++
++        if (msg)
++          r = info->callbacks->warning
++            (info, msg, name, input_bfd, input_section, rel->r_offset);
++
++        if (! r)
++          return FALSE;
++      }
++    }
++
++  /*
++   * now we have to collapse the .debug_line section if it has a
++   * sec_info section
++   */
++
++  if(strcmp(input_section->name, ".debug_line"))
++    return TRUE;
++
++  /* this is a .debug_line section. See it has a sec_info entry */
++  if(elf_section_data(input_section)->sec_info == NULL)
++    return TRUE;
++
++  lh = (struct debugLineInfoHeader *) elf_section_data(input_section)->sec_info;
++
++  if(lh->numEntries == 0)
++    return TRUE;
++
++  dest = contents + lh->linfo[0].startOffset;
++
++  cooked_size = input_section->rawsize;
++  content_end = contents + cooked_size;
++  discard_size = 0;
++
++  for(i=0; i< lh->numEntries; i++)
++    {
++      if(lh->linfo[i].discard)
++      discard_size += lh->linfo[i].length;
++      else
++      {
++        src = contents + lh->linfo[i].startOffset;
++        (void) memcpy(dest, src, lh->linfo[i].length);
++        dest += lh->linfo[i].length;
++      }
++    }
++
++  src = contents + lh->linfo[lh->numEntries-1].startOffset + lh->linfo[lh->numEntries-1].length;
++  if(src < content_end)
++    (void) memcpy(dest, src, content_end - src);
++
++  i = bfd_get_32(input_bfd, contents);
++  i -= discard_size;
++  bfd_put_32(input_bfd, i, contents);
++  //input_section->rawsize -= discard_size;
++  return TRUE;
++}
++
++\f
++/* Update the got entry reference counts for the section being
++   removed.  */
++
++static bfd_boolean
++ubicom32_elf_gc_sweep_hook (abfd, info, sec, relocs)
++     bfd *                     abfd ATTRIBUTE_UNUSED;
++     struct bfd_link_info *    info ATTRIBUTE_UNUSED;
++     asection *                sec ATTRIBUTE_UNUSED;
++     const Elf_Internal_Rela * relocs ATTRIBUTE_UNUSED;
++{
++  return TRUE;
++}
++
++/* Return the section that should be marked against GC for a given
++   relocation.  */
++
++static asection *
++ubicom32_elf_gc_mark_hook (sec, info, rel, h, sym)
++     asection *                   sec;
++     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_UBICOM32_GNU_VTINHERIT:
++      case R_UBICOM32_GNU_VTENTRY:
++        break;
++
++      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;
++
++          default:
++            break;
++          }
++      }
++    }
++  else
++    {
++      if (!(elf_bad_symtab (sec->owner)
++          && 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 (sec->owner, sym->st_shndx);
++      }
++    }
++
++  return NULL;
++}
++
++/* 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 bfd_boolean
++ubicom32_elf_check_relocs (abfd, info, sec, relocs)
++     bfd *abfd;
++     struct bfd_link_info *info;
++     asection *sec;
++     const Elf_Internal_Rela *relocs;
++{
++  Elf_Internal_Shdr *symtab_hdr;
++  struct elf_link_hash_entry **sym_hashes, **sym_hashes_end;
++  Elf_Internal_Rela *rel;
++  Elf_Internal_Rela *rel_end;
++  Elf_Internal_Rela *my_rel = ( Elf_Internal_Rela*)relocs;
++  if (info->relocatable)
++    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);
++  if (!elf_bad_symtab (abfd))
++    sym_hashes_end -= symtab_hdr->sh_info;
++
++  rel_end = my_rel + sec->reloc_count;
++  for (rel = my_rel; rel < rel_end; rel++)
++    {
++      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;
++      else
++      h = sym_hashes [r_symndx - symtab_hdr->sh_info];
++
++      switch (ELF32_R_TYPE (rel->r_info))
++      {
++        /* This relocation describes the C++ object vtable hierarchy.
++           Reconstruct it for later use during GC.  */
++      case R_UBICOM32_GNU_VTINHERIT:
++        if (!bfd_elf_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_UBICOM32_GNU_VTENTRY:
++        if (!bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend))
++          return FALSE;
++        break;
++
++      case R_UBICOM32_32:
++        /* For debug section, change to harvard relocations */
++        if (memcmp (sec->name, ".debug", 6) == 0
++            || memcmp (sec->name, ".stab", 5) == 0)
++          rel->r_info = ELF32_R_INFO (ELF32_R_SYM (rel->r_info), R_UBICOM32_32_HARVARD);
++        break;
++      }
++    }
++  return TRUE;
++}
++
++static bfd_boolean
++ubicom32_elf_object_p (abfd)
++     bfd *abfd;
++{
++  flagword  mach = elf_elfheader (abfd)->e_flags & 0xffff;
++  bfd_default_set_arch_mach (abfd, bfd_arch_ubicom32, mach);
++  return (((elf_elfheader (abfd)->e_flags & EF_UBICOM32_FDPIC) != 0)
++        == (IS_FDPIC (abfd)));
++}
++
++\f
++/* Function to set the ELF flag bits */
++
++static bfd_boolean
++ubicom32_elf_set_private_flags (abfd, flags)
++     bfd *abfd;
++     flagword flags;
++{
++  elf_elfheader (abfd)->e_flags = flags;
++  elf_flags_init (abfd) = TRUE;
++  return TRUE;
++}
++
++static bfd_boolean
++ubicom32_elf_copy_private_bfd_data (ibfd, obfd)
++     bfd *ibfd;
++     bfd *obfd;
++{
++  if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour
++      || bfd_get_flavour (obfd) != bfd_target_elf_flavour)
++    return TRUE;
++
++  BFD_ASSERT (!elf_flags_init (obfd)
++            || elf_elfheader (obfd)->e_flags == elf_elfheader (ibfd)->e_flags);
++
++  elf_elfheader (obfd)->e_flags = elf_elfheader (ibfd)->e_flags;
++  elf_flags_init (obfd) = TRUE;
++  return TRUE;
++}
++
++/* Merge backend specific data from an object file to the output
++   object file when linking. */
++static bfd_boolean
++ubicom32_elf_merge_private_bfd_data (ibfd, obfd)
++     bfd *ibfd;
++     bfd *obfd;
++{
++  flagword old_flags, new_flags;
++  bfd_boolean error = FALSE;
++
++  new_flags = elf_elfheader (ibfd)->e_flags;
++  old_flags = elf_elfheader (obfd)->e_flags;
++
++#ifdef DEBUG
++  (*_bfd_error_handler) ("old_flags = 0x%.8lx, new_flags = 0x%.8lx, init = %s, filename = %s",
++                       old_flags, new_flags, elf_flags_init (obfd) ? "yes" : "no",
++                       bfd_get_filename (ibfd));
++#endif
++
++  if (!elf_flags_init (obfd))                 /* First call, no flags set */
++    {
++      elf_flags_init (obfd) = TRUE;
++      elf_elfheader (obfd)->e_flags = new_flags;
++    }
++  else
++    {
++      if (new_flags != old_flags)
++      {
++        /* Mismatched flags. */
++        char *output_cpu_version = ((old_flags &0xffff) == 1) ? "V3" : (((old_flags &0xffff) == 2) ? "V4" : "unknown");
++        char *input_cpu_version = ((new_flags &0xffff) == 1) ? "V3" : (((new_flags &0xffff) == 2) ? "V4" : "unknown");
++        char *output_filename = bfd_get_filename (obfd);
++        char *input_filename = bfd_get_filename (ibfd);
++        char *output_pic = (old_flags & EF_UBICOM32_PIC_FLAGS) ? ((old_flags & EF_UBICOM32_PIC) ? "FPIC" : "FDPIC") : NULL;
++        char *input_pic = (new_flags & EF_UBICOM32_PIC_FLAGS) ? ((new_flags & EF_UBICOM32_PIC) ? "FPIC" : "FDPIC") : NULL;
++
++        (*_bfd_error_handler) ("Linking mismatched file types. Output file = %s file type 0x%.8lx, input file = %s file type 0x%.8lx",
++                               output_filename, old_flags, input_filename, new_flags);
++
++        if (output_pic)
++          {
++            (*_bfd_error_handler)("Output file %s %s for cpu version %s", output_filename, output_pic, output_cpu_version);
++          }
++        else
++          {
++            (*_bfd_error_handler)("Output file %s for cpu version %s", output_filename, output_cpu_version);
++          }
++
++        if (input_pic)
++          {
++            (*_bfd_error_handler)("Input file %s %s for cpu version %s", input_filename, input_pic, input_cpu_version);
++          }
++        else
++          {
++            (*_bfd_error_handler)("Input file %s for cpu version %s", input_filename, input_cpu_version);
++          }
++        
++        (*_bfd_error_handler) ("Link ABORTED.");
++        _exit(EXIT_FAILURE);
++      }
++    }
++  if (error)
++    bfd_set_error (bfd_error_bad_value);
++
++  return !error;
++}
++
++static bfd_boolean
++ubicom32_elf_print_private_bfd_data (abfd, ptr)
++     bfd *abfd;
++     PTR ptr;
++{
++  FILE *file = (FILE *) ptr;
++  flagword flags;
++
++  BFD_ASSERT (abfd != NULL && ptr != NULL);
++
++  /* Print normal ELF private data.  */
++  _bfd_elf_print_private_bfd_data (abfd, ptr);
++
++  flags = elf_elfheader (abfd)->e_flags;
++  fprintf (file, _("private flags = 0x%lx:"), (long)flags);
++
++  fputc ('\n', file);
++
++  return TRUE;
++}
++
++bfd_boolean
++ubicom32_elf_discard_info(abfd, cookie, info)
++     bfd *abfd;
++     struct elf_reloc_cookie *cookie ATTRIBUTE_UNUSED;
++     struct bfd_link_info *info;
++
++{
++  unsigned int hasDebugLine=0;
++  unsigned needExclude = 0;
++  asection *o;
++  asection *sec= NULL;
++  bfd_byte *contents = NULL;
++  bfd_byte *contentsEnd;
++  Elf_Internal_Rela *irel, *irelend, *irelbase;
++  Elf_Internal_Shdr *symtab_hdr;
++  Elf_Internal_Sym *isym;
++  Elf_Internal_Sym *isymbuf = NULL;
++  struct debugLineInfoHeader *lh = NULL;
++  unsigned int maxLineInfoEntries = 10;
++  unsigned int offset, contentLength;
++  unsigned char *ptr, *sequence_start;
++  unsigned int setupEntry=1;
++  unsigned int opcode_base, op_code;
++  unsigned int bytes_read;
++
++  for (o = abfd->sections; o != NULL; o = o->next)
++    {
++      if(!hasDebugLine)
++      if(!strcmp(o->name, ".debug_line"))
++        {
++          hasDebugLine =1;
++          sec = o;
++        }
++
++      /* Keep special sections.  Keep .debug sections.  */
++      if (o->flags & SEC_EXCLUDE)
++      {
++        needExclude = 1;
++      }
++    }
++
++  if(needExclude == 0 || hasDebugLine ==0)
++    return FALSE;
++
++  /*
++   * you can be here only if we have .debug_line section and some
++   * section is being excudled
++   */
++
++  /*
++   * We need to extract .debug_line section contents and its
++   * relocation contents.
++   */
++
++  /* We don't have to do anything for a relocatable link,
++     if this section does not have relocs */
++  if (info->relocatable
++      || (sec->flags & SEC_RELOC) == 0
++      || sec->reloc_count == 0)
++    return FALSE;
++
++  /* If this is the first time we have been called
++     for this section, initialise the cooked size.
++     if (sec->_cooked_size == 0)
++     sec->_cooked_size = sec->rawsize;
++  */
++
++  symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
++
++  irelbase = _bfd_elf_link_read_relocs (abfd, sec, NULL,
++                                      (Elf_Internal_Rela *)NULL,
++                                      info->keep_memory);
++
++  if(irelbase == NULL)
++    return FALSE;
++
++  irelend = irelbase +sec->reloc_count;
++
++  /* Get section contents cached copy if it exists.  */
++  if (contents == NULL)
++    {
++      contents = section_contents(abfd, sec);
++    }
++
++  if (isymbuf == NULL && symtab_hdr->sh_info != 0)
++    {
++      isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents;
++      if (isymbuf == NULL)
++      isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr,
++                                      symtab_hdr->sh_info, 0,
++                                      NULL, NULL, NULL);
++      if (isymbuf == NULL)
++      return FALSE;
++    }
++
++  /* allocate the line header and initialize it */
++  lh = (struct debugLineInfoHeader *)
++    realloc( (void *)lh, sizeof (struct debugLineInfo)*maxLineInfoEntries +
++           sizeof(unsigned int));
++
++  lh->numEntries = 0;
++
++  /* the first 4 bytes contains the length */
++  contentLength = bfd_get_32 (abfd, (bfd_byte *)contents);
++  contentsEnd = contents + contentLength + 4;
++
++  ptr = (unsigned char *)contents;
++  ptr +=6;
++  /* read the header length */
++  offset = bfd_get_32(abfd, (bfd_byte *)ptr);
++  ptr += 4;
++  ptr += offset;
++
++  /* extract the base opcode */
++  opcode_base = (unsigned char)contents[14];
++  sequence_start = NULL;
++  while(ptr < (unsigned char *) contentsEnd)
++    {
++      if(setupEntry)
++      {
++        if(lh->numEntries == maxLineInfoEntries)
++          {
++            /* need to do some reallocing. Bump up the entries by 10 */
++            maxLineInfoEntries += 10;
++            lh = (struct debugLineInfoHeader *)
++              realloc( (void *)lh,
++                       sizeof (struct debugLineInfo)*maxLineInfoEntries +
++                       sizeof(unsigned int));
++          }
++
++        /* zero out the entry */
++        memset((void *) &lh->linfo[lh->numEntries],
++               0,
++               sizeof(struct debugLineInfo));
++        lh->linfo[lh->numEntries].startOffset = (bfd_byte *)ptr - contents;
++        setupEntry = 0;
++        sequence_start = ptr;
++      }
++
++      /* We need to run the state machine */
++      op_code = bfd_get_8 (abfd, (bfd_byte *)ptr);
++      ptr += 1;
++
++      if(op_code >= opcode_base)
++      continue;
++
++      switch(op_code)
++      {
++      case DW_LNS_extended_op:
++        ptr += 1;     /* ignore length */
++        op_code = bfd_get_8 (abfd, (bfd_byte *)ptr);
++        ptr += 1;
++        switch (op_code)
++          {
++          case DW_LNE_end_sequence:
++            /* end of sequence. Time to record stuff */
++            lh->linfo[lh->numEntries++].length =
++              (bfd_byte *)ptr - sequence_start;
++            setupEntry = 1;
++            break;
++          case DW_LNE_set_address:
++            ptr += 4;
++            break;
++          case DW_LNE_define_file:
++            {
++              ptr += (strlen((char *)ptr) + 1);
++              (void) read_unsigned_leb128(abfd, ptr, &bytes_read);
++              ptr += bytes_read;
++              (void) read_unsigned_leb128(abfd, ptr, &bytes_read);
++              ptr += bytes_read;
++              (void) read_unsigned_leb128(abfd, ptr, &bytes_read);
++              ptr += bytes_read;
++              break;
++            }
++          }
++      case DW_LNS_negate_stmt:
++      case DW_LNS_set_basic_block:
++      case DW_LNS_const_add_pc:
++      case DW_LNS_copy:
++        break;
++      case DW_LNS_advance_pc:
++      case DW_LNS_set_file:
++      case DW_LNS_set_column:
++        (void) read_unsigned_leb128 (abfd, ptr, &bytes_read);
++        ptr += bytes_read;
++        break;
++      case DW_LNS_advance_line:
++        (void) read_signed_leb128 (abfd, ptr, &bytes_read);
++        ptr += bytes_read;
++        break;
++      case DW_LNS_fixed_advance_pc:
++        ptr += 2;
++        break;
++      }
++    }
++
++  /*
++   * now scan through the relocations and match the
++   * lineinfo to a section name
++   */
++  for(irel = irelbase; irel< irelend; irel++)
++    {
++      bfd_vma offset;
++      asection *sym_sec;
++      int i;
++
++      offset = irel->r_offset;
++      isym = isymbuf + ELF32_R_SYM (irel->r_info);
++
++      sym_sec = bfd_section_from_elf_index (abfd, isym->st_shndx);
++
++      /* find which line section this rel entry belongs to */
++      for(i=0; i< (int) lh->numEntries; i++)
++      {
++        if(lh->linfo[i].startOffset <= offset &&
++           offset < lh->linfo[i].startOffset + lh->linfo[i].length)
++          break;
++      }
++
++      if(lh->linfo[i].sectionName == NULL)
++      lh->linfo[i].sectionName = strdup(sym_sec->name);
++    }
++
++  /* now scan through and find the exclude sections */
++  for (o = abfd->sections; o != NULL; o = o->next)
++    {
++      if (o->flags & SEC_EXCLUDE)
++      {
++        /* go through the lh entries and mark as discard */
++        int i;
++        for(i=0; i< (int) lh->numEntries; i++)
++          {
++            if(!strcmp(o->name, lh->linfo[i].sectionName))
++              lh->linfo[i].discard = 1;
++          }
++      }
++    }
++
++  elf_section_data(sec)->sec_info = (PTR)(lh);
++
++  return TRUE;
++}
++
++\f
++/* An extension of the elf hash table data structure, containing some
++   additional Blackfin-specific data.  */
++struct ubicom32fdpic_elf_link_hash_table
++{
++  struct elf_link_hash_table elf;
++
++  /* A pointer to the .got section.  */
++  asection *sgot;
++  /* A pointer to the .rel.got section.  */
++  asection *sgotrel;
++  /* A pointer to the .rofixup section.  */
++  asection *sgotfixup;
++  /* A pointer to the .plt section.  */
++  asection *splt;
++  /* A pointer to the .rel.plt section.  */
++  asection *spltrel;
++  /* GOT base offset.  */
++  bfd_vma got0;
++  /* Location of the first non-lazy PLT entry, i.e., the number of
++     bytes taken by lazy PLT entries.  */
++  bfd_vma plt0;
++  /* A hash table holding information about which symbols were
++     referenced with which PIC-related relocations.  */
++  struct htab *relocs_info;
++};
++
++/* Get the Ubicom32 ELF linker hash table from a link_info structure.  */
++
++#define ubicom32fdpic_hash_table(info) \
++  ((struct ubicom32fdpic_elf_link_hash_table *) ((info)->hash))
++
++#define ubicom32fdpic_got_section(info) \
++  (ubicom32fdpic_hash_table (info)->sgot)
++#define ubicom32fdpic_gotrel_section(info) \
++  (ubicom32fdpic_hash_table (info)->sgotrel)
++#define ubicom32fdpic_gotfixup_section(info) \
++  (ubicom32fdpic_hash_table (info)->sgotfixup)
++#define ubicom32fdpic_plt_section(info) \
++  (ubicom32fdpic_hash_table (info)->splt)
++#define ubicom32fdpic_pltrel_section(info) \
++  (ubicom32fdpic_hash_table (info)->spltrel)
++#define ubicom32fdpic_relocs_info(info) \
++  (ubicom32fdpic_hash_table (info)->relocs_info)
++#define ubicom32fdpic_got_initial_offset(info) \
++  (ubicom32fdpic_hash_table (info)->got0)
++#define ubicom32fdpic_plt_initial_offset(info) \
++  (ubicom32fdpic_hash_table (info)->plt0)
++
++/* The name of the dynamic interpreter.  This is put in the .interp
++   section.  */
++
++#define ELF_DYNAMIC_INTERPRETER "/lib/ld.so.1"
++
++#define DEFAULT_STACK_SIZE 0x20000
++
++/* This structure is used to collect the number of entries present in
++   each addressable range of the got.  */
++struct _ubicom32fdpic_dynamic_got_info
++{
++  /* Several bits of information about the current link.  */
++  struct bfd_link_info *info;
++  /* Total size needed for GOT entries. */
++  bfd_vma gotoffset_lo, gotoffset_hi;
++  /* Total size needed for function descriptor entries. */
++  bfd_vma fd_gotoffset_lo, fd_gotoffset_hi;
++  /* Total size needed function descriptor entries referenced in PLT
++     entries, that would be profitable to place in offsets close to
++     the PIC register.  */
++  bfd_vma fdplt, privfdplt;
++  /* Total size needed by lazy PLT entries.  */
++  bfd_vma lzplt;
++  bfd_vma num_plts;
++
++  /* Number of relocations carried over from input object files.  */
++  unsigned long relocs;
++  /* Number of fixups introduced by relocations in input object files.  */
++  unsigned long fixups;
++};
++
++/* This structure is used to assign offsets to got entries, function
++   descriptors, plt entries and lazy plt entries.  */
++struct ubicom32fdpic_dynamic_got_plt_info
++{
++  /* Summary information collected with _bfinfdpic_count_got_plt_entries.  */
++  struct _ubicom32fdpic_dynamic_got_info g;
++
++  bfd_signed_vma current_got; /* This will be used during got entry allocation */
++  bfd_signed_vma current_fd;  /* This will be used for function descriptro allocation. The numbers will go negative */
++  bfd_signed_vma current_privfd;      /* This will be used for function descriptro allocation. The numbers will go negative */
++  bfd_vma current_plt;                /* This is the offset to the PLT entry. We will need this to resolve the call entries. */
++  bfd_vma current_plt_trampoline; /* This is the offset to the PLT trampoline entry. */
++  bfd_vma total_fdplt;                /* Total size of function descriptors. This is the memory above GOT pointer. */
++  bfd_vma total_got;          /* This is the total of got entries for got_lo and got_funcdesc_lo references. */
++  bfd_vma total_lzplt;                /* This is the total area for the PLT entries. This does not have the trampoline entry. */
++  bfd_vma total_trampoline;   /* This is the total area for the PLT trampoline entries. */
++};
++
++/* Decide whether a reference to a symbol can be resolved locally or
++   not.  If the symbol is protected, we want the local address, but
++   its function descriptor must be assigned by the dynamic linker.  */
++#define UBICOM32FDPIC_SYM_LOCAL(INFO, H) \
++  (_bfd_elf_symbol_refs_local_p ((H), (INFO), 1) \
++   || ! elf_hash_table (INFO)->dynamic_sections_created)
++#define UBICOM32FDPIC_FUNCDESC_LOCAL(INFO, H) \
++  ((H)->dynindx == -1 || ! elf_hash_table (INFO)->dynamic_sections_created)
++
++/* This structure collects information on what kind of GOT, PLT or
++   function descriptors are required by relocations that reference a
++   certain symbol.  */
++struct ubicom32fdpic_relocs_info
++{
++  /* The index of the symbol, as stored in the relocation r_info, if
++     we have a local symbol; -1 otherwise.  */
++  long symndx;
++  union
++  {
++    /* The input bfd in which the symbol is defined, if it's a local
++       symbol.  */
++    bfd *abfd;
++    /* If symndx == -1, the hash table entry corresponding to a global
++       symbol (even if it turns out to bind locally, in which case it
++       should ideally be replaced with section's symndx + addend).  */
++    struct elf_link_hash_entry *h;
++  } d;
++  /* The addend of the relocation that references the symbol.  */
++  bfd_vma addend;
++
++  /* The fields above are used to identify an entry.  The fields below
++     contain information on how an entry is used and, later on, which
++     locations it was assigned.  */
++  /* The following 2 fields record whether the symbol+addend above was
++     ever referenced with a GOT relocation.  The 17M4 suffix indicates a
++     GOT17M4 relocation; hilo is used for GOTLO/GOTHI pairs.  */
++  unsigned gotoffset_lo;
++  unsigned gotoffset_hi;
++  /* Whether a FUNCDESC relocation references symbol+addend.  */
++  unsigned fd;
++  /* Whether a FUNCDESC_GOT relocation references symbol+addend.  */
++  unsigned fd_gotoffset_lo;
++  unsigned fd_gotoffset_hi;
++  /* Whether symbol+addend is referenced with GOTOFF17M4, GOTOFFLO or
++     GOTOFFHI relocations.  The addend doesn't really matter, since we
++     envision that this will only be used to check whether the symbol
++     is mapped to the same segment as the got.  */
++  unsigned gotoff;
++  /* Whether symbol+addend is referenced by a LABEL24 relocation.  */
++  unsigned call;
++  /* Whether symbol+addend is referenced by a 32 or FUNCDESC_VALUE
++     relocation.  */
++  unsigned sym;
++  /* Whether we need a PLT entry for a symbol.  Should be implied by
++     something like:
++     (call && symndx == -1 && ! BFINFDPIC_SYM_LOCAL (info, d.h))  */
++  unsigned plt:1;
++  /* Whether a function descriptor should be created in this link unit
++     for symbol+addend.  Should be implied by something like:
++     (plt || fd_gotoffset_lo || fd_gotoffset_hi
++     || ((fd || fdgot17m4 || fdgothilo)
++     && (symndx != -1 || BFINFDPIC_FUNCDESC_LOCAL (info, d.h))))  */
++  unsigned privfd:1;
++  /* Whether a lazy PLT entry is needed for this symbol+addend.
++     Should be implied by something like:
++     (privfd && symndx == -1 && ! BFINFDPIC_SYM_LOCAL (info, d.h)
++     && ! (info->flags & DF_BIND_NOW))  */
++  unsigned lazyplt:1;
++  /* Whether we've already emitted GOT relocations and PLT entries as
++     needed for this symbol.  */
++  unsigned done:1;
++
++  /* The number of R_byte4_data, R_BFIN_FUNCDESC and R_BFIN_FUNCDESC_VALUE
++     relocations referencing the symbol.  */
++  unsigned relocs32, relocsfd, relocsfdv;
++
++  /* The number of .rofixups entries and dynamic relocations allocated
++     for this symbol, minus any that might have already been used.  */
++  unsigned fixups, dynrelocs;
++
++  /* The offsets of the GOT entries assigned to symbol+addend, to the
++     function descriptor's address, and to a function descriptor,
++     respectively.  Should be zero if unassigned.  The offsets are
++     counted from the value that will be assigned to the PIC register,
++     not from the beginning of the .got section.  */
++  bfd_signed_vma got_entry, fdgot_entry, fd_entry;
++  /* The offsets of the PLT entries assigned to symbol+addend,
++     non-lazy and lazy, respectively.  If unassigned, should be
++     (bfd_vma)-1.  */
++  bfd_vma plt_entry;
++  bfd_vma plt_trampoline_entry;
++
++  /* plt_type is 1 for Sequence type 2 (0 - 255) it is 2 for > 255 */
++  bfd_vma plt_type;
++
++  /* rel_offset. Plt relocation offset need to be encoded into the plt entry. */
++  bfd_vma rel_offset;
++
++  /* bfd_vma lzplt_entry; not used in ubicom32 */
++};
++
++/* Compute the total GOT size required by each symbol in each range.
++   Symbols may require up to 4 words in the GOT: an entry pointing to
++   the symbol, an entry pointing to its function descriptor, and a
++   private function descriptors taking two words.  */
++
++#if 0
++static bfd_vma plt_code[] = {
++  0xc90f0000, //movei d15,#0
++  0x0123e30f, //lea.4 a3,(a0,d15)
++  0x0124630f, //move.4 a4,(a0,d15)
++  0x01206461, //move.4 a0,4(a3)
++  0xf0800080, //calli a4,0(a4)
++};
++#endif
++
++static bfd_vma plt_trampoline[] = {
++  0xc9280000,   //    movei mac_hi,#0
++  0x00002400,   //    ret (a0)
++};
++
++static bfd_vma plt_code_seq1[] = {
++  0xc90fffe8,         //movei d15,#-24
++  0x0123e30f,         //lea.4 a3,(a0,d15)
++  0x01206461,         //move.4 a0,4(a3)
++  0x00002460,         //ret (a3)
++};
++
++static bfd_vma plt_code_seq2[] = {
++  0x0123f71f,   //    pdec a3,4(a0)
++  0x01206461,   //    move.4 a0,4(a3)
++  0x00002460,   //    ret (a3)
++};
++
++#define NUM_PLT_CODE_WORDS (sizeof (plt_code) / sizeof (bfd_vma))
++#define LZPLT_NORMAL_SIZE (sizeof(plt_code))
++
++#define NUM_PLT_CODE_WORDS_SEQ1 (sizeof (plt_code_seq1) / sizeof (bfd_vma))
++#define LZPLT_SIZE_SEQ1 (sizeof(plt_code_seq1))
++
++#define NUM_PLT_CODE_WORDS_SEQ2 (sizeof (plt_code_seq2) / sizeof (bfd_vma))
++#define LZPLT_SIZE_SEQ2 (sizeof(plt_code_seq2))
++
++#define NUM_PLT_TRAMPOLINE_WORDS (sizeof (plt_trampoline) / sizeof (bfd_vma))
++#define PLT_TRAMPOLINE_SIZE (sizeof(plt_trampoline))
++
++//#define FUNCTION_DESCRIPTOR_SIZE 12
++#define FUNCTION_DESCRIPTOR_SIZE 8
++/* Decide whether a reference to a symbol can be resolved locally or
++   not.  If the symbol is protected, we want the local address, but
++   its function descriptor must be assigned by the dynamic linker.  */
++#define UBICOM32FPIC_SYM_LOCAL(INFO, H) \
++  (_bfd_elf_symbol_refs_local_p ((H), (INFO), 1) \
++   || ! elf_hash_table (INFO)->dynamic_sections_created)
++#define UBICOM32FPIC_FUNCDESC_LOCAL(INFO, H) \
++  ((H)->dynindx == -1 || ! elf_hash_table (INFO)->dynamic_sections_created)
++
++
++static int
++ubicom32fdpic_count_got_plt_entries (void **entryp, void *dinfo_)
++{
++  struct ubicom32fdpic_relocs_info *entry = *entryp;
++  struct _ubicom32fdpic_dynamic_got_info *dinfo = dinfo_;
++  unsigned relocs = 0, fixups = 0;
++
++  /* Allocate space for a GOT entry pointing to the symbol.  */
++  if (entry->gotoffset_lo)
++    {
++      dinfo->gotoffset_lo += 4;
++      entry->relocs32++;
++    }
++
++  /* Allocate space for a GOT entry pointing to the function
++     descriptor.  */
++  if (entry->fd_gotoffset_lo)
++    {
++      dinfo->gotoffset_lo += 4;
++      entry->relocsfd++;
++    }
++  else if (entry->fd_gotoffset_hi)
++    {
++      dinfo->gotoffset_lo += 4;
++      entry->relocsfd++;
++    }
++
++  /* Decide whether we need a PLT entry, a function descriptor in the
++     GOT, and a lazy PLT entry for this symbol.  */
++  entry->plt = entry->call
++    && entry->symndx == -1 && ! UBICOM32FPIC_SYM_LOCAL (dinfo->info, entry->d.h)
++    && elf_hash_table (dinfo->info)->dynamic_sections_created;
++  entry->privfd = entry->plt
++    || ((entry->fd_gotoffset_lo || entry->fd_gotoffset_hi || entry->fd)
++      && (entry->symndx != -1
++          || UBICOM32FPIC_FUNCDESC_LOCAL (dinfo->info, entry->d.h)));
++  entry->lazyplt = entry->privfd
++    && entry->symndx == -1 && ! UBICOM32FPIC_SYM_LOCAL (dinfo->info, entry->d.h)
++    && ! (dinfo->info->flags & DF_BIND_NOW)
++    && elf_hash_table (dinfo->info)->dynamic_sections_created;
++
++  /* Allocate space for a function descriptor.  */
++  if (entry->privfd && entry->plt)
++    {
++      dinfo->fdplt += FUNCTION_DESCRIPTOR_SIZE;
++      entry->relocsfdv++;
++    }
++  else if (entry->privfd)
++    {
++      /* privfd with plt = 0 */
++      //printf("Privfd set with plt 0 gotoff_lo = %d fd_gotoffset_lo = %d entry = 0x%x\n", entry->gotoffset_lo, entry->fd_gotoffset_lo, entry);
++      //printf("symnxd = 0x%x sym_local = %d funcdesc_local = %d\n", entry->symndx,
++      //     UBICOM32FPIC_SYM_LOCAL (dinfo->info, entry->d.h),
++      //     UBICOM32FPIC_FUNCDESC_LOCAL (dinfo->info, entry->d.h));
++      //printf("Name = %s\n\n", entry->d.h->root.root.string);
++      dinfo->privfdplt += FUNCTION_DESCRIPTOR_SIZE;
++      entry->relocsfdv++;
++    }
++
++
++  if (entry->lazyplt)
++    {
++      //dinfo->lzplt += LZPLT_NORMAL_SIZE;
++      dinfo->num_plts++;
++
++#if 0
++      if (dinfo->num_plts > 256)
++      dinfo->lzplt += LZPLT_SIZE_SEQ1;
++      else
++      dinfo->lzplt += LZPLT_SIZE_SEQ2;
++
++      DPRINTF("lzplt %d num_plt %d\n",  dinfo->lzplt, dinfo->num_plts);
++#endif
++    }
++
++  if (!dinfo->info->executable || dinfo->info->pie)
++    relocs = entry->relocs32 + entry->relocsfd + entry->relocsfdv;
++  else
++    {
++      if (entry->symndx != -1 || UBICOM32FPIC_SYM_LOCAL (dinfo->info, entry->d.h))
++      {
++        if (entry->symndx != -1
++            || entry->d.h->root.type != bfd_link_hash_undefweak)
++          fixups += entry->relocs32 + 2 * entry->relocsfdv;
++      }
++      else
++      relocs += entry->relocs32 + entry->relocsfdv;
++
++      if (entry->symndx != -1
++        || UBICOM32FPIC_FUNCDESC_LOCAL (dinfo->info, entry->d.h))
++      {
++        if (entry->symndx != -1
++            || entry->d.h->root.type != bfd_link_hash_undefweak)
++          fixups += entry->relocsfd;
++      }
++      else
++      relocs += entry->relocsfd;
++    }
++
++  entry->dynrelocs += relocs;
++  entry->fixups += fixups;
++  dinfo->relocs += relocs;
++  dinfo->fixups += fixups;
++
++  return 1;
++}
++
++/* Create a Ubicom32 ELF linker hash table.  */
++static struct bfd_link_hash_table *
++ubicom32fdpic_elf_link_hash_table_create (bfd *abfd)
++{
++  struct ubicom32fdpic_elf_link_hash_table *ret;
++  bfd_size_type amt = sizeof (struct ubicom32fdpic_elf_link_hash_table);
++
++  ret = bfd_zalloc (abfd, amt);
++  if (ret == NULL)
++    return NULL;
++
++  if (!_bfd_elf_link_hash_table_init (&ret->elf, abfd,
++                                    _bfd_elf_link_hash_newfunc,
++                                    sizeof (struct elf_link_hash_entry)))
++    {
++      free (ret);
++      return NULL;
++    }
++
++  return &ret->elf.root;
++}
++
++/* Compute a hash with the key fields of an ubicom32fdpic_relocs_info entry.  */
++static hashval_t
++ubicom32fdpic_relocs_info_hash (const void *entry_)
++{
++  const struct ubicom32fdpic_relocs_info *entry = entry_;
++
++  return (entry->symndx == -1
++        ? (long) entry->d.h->root.root.hash
++        : entry->symndx + (long) entry->d.abfd->id * 257) + entry->addend;
++}
++
++/* Test whether the key fields of two ubicom32fdpic_relocs_info entries are
++   identical.  */
++static int
++ubicom32fdpic_relocs_info_eq (const void *entry1, const void *entry2)
++{
++  const struct ubicom32fdpic_relocs_info *e1 = entry1;
++  const struct ubicom32fdpic_relocs_info *e2 = entry2;
++
++  return e1->symndx == e2->symndx && e1->addend == e2->addend
++    && (e1->symndx == -1 ? e1->d.h == e2->d.h : e1->d.abfd == e2->d.abfd);
++}
++
++/* Find or create an entry in a hash table HT that matches the key
++   fields of the given ENTRY.  If it's not found, memory for a new
++   entry is allocated in ABFD's obstack.  */
++static struct ubicom32fdpic_relocs_info *
++ubicom32fdpic_relocs_info_find (struct htab *ht,
++                              bfd *abfd,
++                              const struct ubicom32fdpic_relocs_info *entry,
++                              enum insert_option insert)
++{
++  struct ubicom32fdpic_relocs_info **loc =
++    (struct ubicom32fdpic_relocs_info **) htab_find_slot (ht, entry, insert);
++
++  if (! loc)
++    return NULL;
++
++  if (*loc)
++    return *loc;
++
++  *loc = bfd_zalloc (abfd, sizeof (**loc));
++
++  if (! *loc)
++    return *loc;
++
++  (*loc)->symndx = entry->symndx;
++  (*loc)->d = entry->d;
++  (*loc)->addend = entry->addend;
++  (*loc)->plt_entry = (bfd_vma)-1;
++  /* (*loc)->lzplt_entry = (bfd_vma)-1; */
++
++  return *loc;
++}
++
++/* Obtain the address of the entry in HT associated with H's symbol +
++   addend, creating a new entry if none existed.  ABFD is only used
++   for memory allocation purposes.  */
++inline static struct ubicom32fdpic_relocs_info *
++ubicom32fdpic_relocs_info_for_global (struct htab *ht,
++                                    bfd *abfd,
++                                    struct elf_link_hash_entry *h,
++                                    bfd_vma addend,
++                                    enum insert_option insert)
++{
++  struct ubicom32fdpic_relocs_info entry;
++
++  entry.symndx = -1;
++  entry.d.h = h;
++  entry.addend = addend;
++
++  return ubicom32fdpic_relocs_info_find (ht, abfd, &entry, insert);
++}
++
++/* Obtain the address of the entry in HT associated with the SYMNDXth
++   local symbol of the input bfd ABFD, plus the addend, creating a new
++   entry if none existed.  */
++inline static struct ubicom32fdpic_relocs_info *
++ubicom32fdpic_relocs_info_for_local (struct htab *ht,
++                                   bfd *abfd,
++                                   long symndx,
++                                   bfd_vma addend,
++                                   enum insert_option insert)
++{
++  struct ubicom32fdpic_relocs_info entry;
++
++  entry.symndx = symndx;
++  entry.d.abfd = abfd;
++  entry.addend = addend;
++
++  return ubicom32fdpic_relocs_info_find (ht, abfd, &entry, insert);
++}
++
++/* Merge fields set by check_relocs() of two entries that end up being
++   mapped to the same (presumably global) symbol.  */
++
++inline static void
++ubicom32fdpic_pic_merge_early_relocs_info (struct ubicom32fdpic_relocs_info *e2,
++                                         struct ubicom32fdpic_relocs_info const *e1)
++{
++  e2->gotoffset_lo |= e1->gotoffset_lo;
++  e2->gotoffset_hi |= e1->gotoffset_hi;
++  e2->fd_gotoffset_lo |= e1->fd_gotoffset_lo;
++  e2->fd_gotoffset_hi |= e1->fd_gotoffset_hi;
++  e2->fd |= e1->fd;
++  e2->gotoff |= e1->gotoff;
++  e2->call |= e1->call;
++  e2->sym |= e1->sym;
++}
++
++/* Add a dynamic relocation to the SRELOC section.  */
++
++inline static bfd_vma
++ubicom32fdpic_add_dyn_reloc (bfd *output_bfd, asection *sreloc, bfd_vma offset,
++                           int reloc_type, long dynindx, bfd_vma addend,
++                           struct ubicom32fdpic_relocs_info *entry)
++{
++  Elf_Internal_Rela outrel;
++  bfd_vma reloc_offset;
++
++  outrel.r_offset = offset;
++  outrel.r_info = ELF32_R_INFO (dynindx, reloc_type);
++  outrel.r_addend = addend;
++
++  reloc_offset = sreloc->reloc_count * sizeof (Elf32_External_Rel);
++  BFD_ASSERT (reloc_offset < sreloc->size);
++  bfd_elf32_swap_reloc_out (output_bfd, &outrel,
++                          sreloc->contents + reloc_offset);
++  sreloc->reloc_count++;
++
++  /* If the entry's index is zero, this relocation was probably to a
++     linkonce section that got discarded.  We reserved a dynamic
++     relocation, but it was for another entry than the one we got at
++     the time of emitting the relocation.  Unfortunately there's no
++     simple way for us to catch this situation, since the relocation
++     is cleared right before calling relocate_section, at which point
++     we no longer know what the relocation used to point to.  */
++  if (entry->symndx)
++    {
++      BFD_ASSERT (entry->dynrelocs > 0);
++      entry->dynrelocs--;
++    }
++
++  return reloc_offset;
++}
++
++/* Add a fixup to the ROFIXUP section.  */
++
++static bfd_vma
++ubicom32fdpic_add_rofixup (bfd *output_bfd, asection *rofixup, bfd_vma offset,
++                         struct ubicom32fdpic_relocs_info *entry)
++{
++  bfd_vma fixup_offset;
++
++  if (rofixup->flags & SEC_EXCLUDE)
++    return -1;
++
++  fixup_offset = rofixup->reloc_count * 4;
++  if (rofixup->contents)
++    {
++      BFD_ASSERT (fixup_offset < rofixup->size);
++      bfd_put_32 (output_bfd, offset, rofixup->contents + fixup_offset);
++    }
++  rofixup->reloc_count++;
++
++  if (entry && entry->symndx)
++    {
++      /* See discussion about symndx == 0 in _ubicom32fdpic_add_dyn_reloc
++       above.  */
++      BFD_ASSERT (entry->fixups > 0);
++      entry->fixups--;
++    }
++
++  return fixup_offset;
++}
++
++/* Find the segment number in which OSEC, and output section, is
++   located.  */
++
++static unsigned
++ubicom32fdpic_osec_to_segment (bfd *output_bfd, asection *osec)
++{
++  Elf_Internal_Phdr *p = _bfd_elf_find_segment_containing_section (output_bfd, osec);
++
++  return (p != NULL) ? p - elf_tdata (output_bfd)->phdr : -1;
++}
++
++inline static bfd_boolean
++ubicom32fdpic_osec_readonly_p (bfd *output_bfd, asection *osec)
++{
++  unsigned seg = ubicom32fdpic_osec_to_segment (output_bfd, osec);
++
++  return ! (elf_tdata (output_bfd)->phdr[seg].p_flags & PF_W);
++}
++
++#if 0
++static bfd_vma plt_trampoline[] = {
++  0x00002400, //ret (a0)
++};
++#endif
++
++/* Generate relocations for GOT entries, function descriptors, and
++   code for PLT and lazy PLT entries.  */
++
++static bfd_boolean
++ubicom32fdpic_emit_got_relocs_plt_entries (struct ubicom32fdpic_relocs_info *entry,
++                                         bfd *output_bfd,
++                                         struct bfd_link_info *info,
++                                         asection *sec,
++                                         Elf_Internal_Sym *sym,
++                                         bfd_vma addend)
++
++{
++  bfd_vma fd_lazy_rel_offset = (bfd_vma)-1;
++  int dynindx = -1;
++
++  if (entry->done)
++    return TRUE;
++  entry->done = 1;
++
++  if (entry->got_entry || entry->fdgot_entry || entry->fd_entry)
++    {
++      DPRINTF(" emit %p got %d fdgot %d fd %d addend %d\n", entry, entry->got_entry, entry->fdgot_entry, entry->fd_entry, addend);
++      /* If the symbol is dynamic, consider it for dynamic
++       relocations, otherwise decay to section + offset.  */
++      if (entry->symndx == -1 && entry->d.h->dynindx != -1)
++      dynindx = entry->d.h->dynindx;
++      else
++      {
++        if (sec->output_section
++            && ! bfd_is_abs_section (sec->output_section)
++            && ! bfd_is_und_section (sec->output_section))
++          dynindx = elf_section_data (sec->output_section)->dynindx;
++        else
++          dynindx = 0;
++      }
++    }
++
++  /* Generate relocation for GOT entry pointing to the symbol.  */
++  if (entry->got_entry)
++    {
++      DPRINTF(" emit got entry %d:%p\n", entry->got_entry, entry);
++
++      int idx = dynindx;
++      bfd_vma ad = addend;
++
++      /* If the symbol is dynamic but binds locally, use
++       section+offset.  */
++      if (sec && (entry->symndx != -1
++                || UBICOM32FDPIC_SYM_LOCAL (info, entry->d.h)))
++      {
++        if (entry->symndx == -1)
++          ad += entry->d.h->root.u.def.value;
++        else
++          ad += sym->st_value;
++        ad += sec->output_offset;
++        if (sec->output_section && elf_section_data (sec->output_section))
++          idx = elf_section_data (sec->output_section)->dynindx;
++        else
++          idx = 0;
++      }
++
++      /* If we're linking an executable at a fixed address, we can
++       omit the dynamic relocation as long as the symbol is local to
++       this module.  */
++      if (info->executable && !info->pie
++        && (entry->symndx != -1
++            || UBICOM32FDPIC_SYM_LOCAL (info, entry->d.h)))
++      {
++        if (sec)
++          ad += sec->output_section->vma;
++        if (entry->symndx != -1
++            || entry->d.h->root.type != bfd_link_hash_undefweak)
++          ubicom32fdpic_add_rofixup (output_bfd,
++                                     ubicom32fdpic_gotfixup_section (info),
++                                     ubicom32fdpic_got_section (info)->output_section->vma
++                                     + ubicom32fdpic_got_section (info)->output_offset
++                                     + ubicom32fdpic_got_initial_offset (info)
++                                     + entry->got_entry, entry);
++      }
++      else
++      ubicom32fdpic_add_dyn_reloc (output_bfd, ubicom32fdpic_gotrel_section (info),
++                                   _bfd_elf_section_offset
++                                   (output_bfd, info,
++                                    ubicom32fdpic_got_section (info),
++                                    ubicom32fdpic_got_initial_offset (info)
++                                    + entry->got_entry)
++                                   + ubicom32fdpic_got_section (info)
++                                   ->output_section->vma
++                                   + ubicom32fdpic_got_section (info)->output_offset,
++                                   R_UBICOM32_32, idx, ad, entry);
++
++      bfd_put_32 (output_bfd, ad,
++                ubicom32fdpic_got_section (info)->contents
++                + ubicom32fdpic_got_initial_offset (info)
++                + entry->got_entry);
++    }
++
++  /* Generate relocation for GOT entry pointing to a canonical
++     function descriptor.  */
++  if (entry->fdgot_entry)
++    {
++      DPRINTF(" emit got fdgot entry %d:%p\n", entry->fdgot_entry, entry);
++
++      int reloc, idx;
++      bfd_vma ad = 0;
++
++      if (! (entry->symndx == -1
++           && entry->d.h->root.type == bfd_link_hash_undefweak
++           && UBICOM32FDPIC_SYM_LOCAL (info, entry->d.h)))
++      {
++        /* If the symbol is dynamic and there may be dynamic symbol
++           resolution because we are, or are linked with, a shared
++           library, emit a FUNCDESC relocation such that the dynamic
++           linker will allocate the function descriptor.  If the
++           symbol needs a non-local function descriptor but binds
++           locally (e.g., its visibility is protected, emit a
++           dynamic relocation decayed to section+offset.  */
++        if (entry->symndx == -1
++            && ! UBICOM32FDPIC_FUNCDESC_LOCAL (info, entry->d.h)
++            && UBICOM32FDPIC_SYM_LOCAL (info, entry->d.h)
++            && !(info->executable && !info->pie))
++          {
++            reloc = R_UBICOM32_FUNCDESC;
++            idx = elf_section_data (entry->d.h->root.u.def.section
++                                    ->output_section)->dynindx;
++            ad = entry->d.h->root.u.def.section->output_offset
++              + entry->d.h->root.u.def.value;
++          }
++        else if (entry->symndx == -1
++                 && ! UBICOM32FDPIC_FUNCDESC_LOCAL (info, entry->d.h))
++          {
++            reloc = R_UBICOM32_FUNCDESC;
++            idx = dynindx;
++            ad = addend;
++            if (ad)
++              return FALSE;
++          }
++        else
++          {
++            /* Otherwise, we know we have a private function descriptor,
++               so reference it directly.  */
++            if (elf_hash_table (info)->dynamic_sections_created)
++              BFD_ASSERT (entry->privfd);
++            reloc = R_UBICOM32_32;
++            idx = elf_section_data (ubicom32fdpic_got_section (info)
++                                    ->output_section)->dynindx;
++            ad = ubicom32fdpic_got_section (info)->output_offset
++              + ubicom32fdpic_got_initial_offset (info) + entry->fd_entry;
++          }
++
++        /* If there is room for dynamic symbol resolution, emit the
++           dynamic relocation.  However, if we're linking an
++           executable at a fixed location, we won't have emitted a
++           dynamic symbol entry for the got section, so idx will be
++           zero, which means we can and should compute the address
++           of the private descriptor ourselves.  */
++        if (info->executable && !info->pie
++            && (entry->symndx != -1
++                || UBICOM32FDPIC_FUNCDESC_LOCAL (info, entry->d.h)))
++          {
++            ad += ubicom32fdpic_got_section (info)->output_section->vma;
++            ubicom32fdpic_add_rofixup (output_bfd,
++                                       ubicom32fdpic_gotfixup_section (info),
++                                       ubicom32fdpic_got_section (info)
++                                       ->output_section->vma
++                                       + ubicom32fdpic_got_section (info)
++                                       ->output_offset
++                                       + ubicom32fdpic_got_initial_offset (info)
++                                       + entry->fdgot_entry, entry);
++          }
++        else
++          ubicom32fdpic_add_dyn_reloc (output_bfd,
++                                       ubicom32fdpic_gotrel_section (info),
++                                       _bfd_elf_section_offset
++                                       (output_bfd, info,
++                                        ubicom32fdpic_got_section (info),
++                                        ubicom32fdpic_got_initial_offset (info)
++                                        + entry->fdgot_entry)
++                                       + ubicom32fdpic_got_section (info)
++                                       ->output_section->vma
++                                       + ubicom32fdpic_got_section (info)
++                                       ->output_offset,
++                                       reloc, idx, ad, entry);
++      }
++
++      bfd_put_32 (output_bfd, ad,
++                ubicom32fdpic_got_section (info)->contents
++                + ubicom32fdpic_got_initial_offset (info)
++                + entry->fdgot_entry);
++    }
++
++  /* Generate relocation to fill in a private function descriptor in
++     the GOT.  */
++  if (entry->fd_entry)
++    {
++
++      int idx = dynindx;
++      bfd_vma ad = addend;
++      bfd_vma ofst;
++      long lowword, highword;
++
++      /* If the symbol is dynamic but binds locally, use
++       section+offset.  */
++      if (sec && (entry->symndx != -1
++                || UBICOM32FDPIC_SYM_LOCAL (info, entry->d.h)))
++      {
++        if (entry->symndx == -1)
++          ad += entry->d.h->root.u.def.value;
++        else
++          ad += sym->st_value;
++        ad += sec->output_offset;
++        if (sec->output_section && elf_section_data (sec->output_section))
++          idx = elf_section_data (sec->output_section)->dynindx;
++        else
++          idx = 0;
++      }
++
++      /* If we're linking an executable at a fixed address, we can
++       omit the dynamic relocation as long as the symbol is local to
++       this module.  */
++      if (info->executable && !info->pie
++        && (entry->symndx != -1 || UBICOM32FDPIC_SYM_LOCAL (info, entry->d.h)))
++      {
++        if (sec)
++          ad += sec->output_section->vma;
++        ofst = 0;
++        if (entry->symndx != -1
++            || entry->d.h->root.type != bfd_link_hash_undefweak)
++          {
++            ubicom32fdpic_add_rofixup (output_bfd,
++                                       ubicom32fdpic_gotfixup_section (info),
++                                       ubicom32fdpic_got_section (info)
++                                       ->output_section->vma
++                                       + ubicom32fdpic_got_section (info)
++                                       ->output_offset
++                                       + ubicom32fdpic_got_initial_offset (info)
++                                       + entry->fd_entry, entry);
++            ubicom32fdpic_add_rofixup (output_bfd,
++                                       ubicom32fdpic_gotfixup_section (info),
++                                       ubicom32fdpic_got_section (info)
++                                       ->output_section->vma
++                                       + ubicom32fdpic_got_section (info)
++                                       ->output_offset
++                                       + ubicom32fdpic_got_initial_offset (info)
++                                       + entry->fd_entry + 4, entry);
++          }
++      }
++      else
++      {
++        ofst
++          = ubicom32fdpic_add_dyn_reloc (output_bfd,
++                                         entry->lazyplt
++                                         ? ubicom32fdpic_pltrel_section (info)
++                                         : ubicom32fdpic_gotrel_section (info),
++                                         _bfd_elf_section_offset
++                                         (output_bfd, info,
++                                          ubicom32fdpic_got_section (info),
++                                          ubicom32fdpic_got_initial_offset (info)
++                                          + entry->fd_entry)
++                                         + ubicom32fdpic_got_section (info)
++                                         ->output_section->vma
++                                         + ubicom32fdpic_got_section (info)
++                                         ->output_offset,
++                                         R_UBICOM32_FUNCDESC_VALUE, idx, ad, entry);
++      }
++
++      /* If we've omitted the dynamic relocation, just emit the fixed
++       addresses of the symbol and of the local GOT base offset.  */
++      if (info->executable && !info->pie && sec && sec->output_section)
++      {
++        lowword = ad;
++        highword = ubicom32fdpic_got_section (info)->output_section->vma
++          + ubicom32fdpic_got_section (info)->output_offset
++          + ubicom32fdpic_got_initial_offset (info);
++      }
++      else if (entry->lazyplt)
++      {
++        if (ad)
++          return FALSE;
++
++        fd_lazy_rel_offset = ofst;
++
++        /* A function descriptor used for lazy or local resolving is
++           initialized such that its high word contains the output
++           section index in which the PLT entries are located, and
++           the low word contains the address to the base of the PLT.
++           That location contains the PLT trampoline instruction ret 0(a0).
++           assigned to that section.  */
++        lowword =  ubicom32fdpic_plt_section (info)->output_offset
++          + ubicom32fdpic_plt_section (info)->output_section->vma + entry->plt_trampoline_entry;
++        highword = ubicom32fdpic_osec_to_segment
++          (output_bfd, ubicom32fdpic_plt_section (info)->output_section);
++      }
++      else
++      {
++        /* A function descriptor for a local function gets the index
++           of the section.  For a non-local function, it's
++           disregarded.  */
++        lowword = ad;
++        if (entry->symndx == -1 && entry->d.h->dynindx != -1
++            && entry->d.h->dynindx == idx)
++          highword = 0;
++        else
++          highword = ubicom32fdpic_osec_to_segment
++            (output_bfd, sec->output_section);
++      }
++
++      DPRINTF(" emit got fd_entry %d:%p lw 0x%x hw 0x%x fd_l_r_off 0x%x\n", entry->fd_entry, entry, lowword, highword, fd_lazy_rel_offset);
++
++
++      bfd_put_32 (output_bfd, lowword,
++                ubicom32fdpic_got_section (info)->contents
++                + ubicom32fdpic_got_initial_offset (info)
++                + entry->fd_entry);
++      bfd_put_32 (output_bfd, highword,
++                ubicom32fdpic_got_section (info)->contents
++                + ubicom32fdpic_got_initial_offset (info)
++                + entry->fd_entry + 4);
++
++#if 0
++      /* Load the fixup offset here. */
++      bfd_put_32 (output_bfd, fd_lazy_rel_offset,
++                ubicom32fdpic_got_section (info)->contents
++                + ubicom32fdpic_got_initial_offset (info)
++                + entry->fd_entry + 8);
++#endif
++
++      entry->rel_offset = fd_lazy_rel_offset;
++    }
++
++  /* Generate code for the PLT entry.  */
++  if (entry->plt_entry != (bfd_vma) -1)
++    {
++      static output_trampoline_code = 1;
++      bfd_byte *plt_output_code = ubicom32fdpic_plt_section (info)->contents;
++      int i;
++      bfd_vma *plt_code;
++
++      DPRINTF(" emit fd entry %x:%p plt=%2x code=%p\n", entry->fd_entry, entry, entry->plt_entry, plt_output_code);
++
++#if 0
++      if (output_trampoline_code)
++      {
++        /* output the trampoline code.*/
++        bfd_put_32 (output_bfd, plt_trampoline[0], plt_output_code);
++      }
++#endif
++
++      /* output the trampoline entry. */
++
++      plt_output_code += entry->plt_trampoline_entry;
++      plt_code = plt_trampoline;
++      plt_code[0] = (plt_code[0] & 0xFFFF0000) | (entry->rel_offset &0xffff);
++      bfd_put_32 (output_bfd, plt_code[0], plt_output_code);
++      bfd_put_32 (output_bfd, plt_code[1], plt_output_code + 4);
++
++
++      /* output the plt itself. */
++      plt_output_code = ubicom32fdpic_plt_section (info)->contents;
++      plt_output_code += entry->plt_entry;
++      BFD_ASSERT (entry->fd_entry);
++
++      if (entry->plt_type == 2)
++      {
++        bfd_vma data_lo = (entry->fd_entry >> 2) & 0xff;
++
++        /* Output seqence 2. */
++        plt_code = plt_code_seq2;
++
++        /* Code the entry into the PDEC instruction. */
++        plt_code[0] &= 0xFFFFF8E0;
++        plt_code[0] |= (data_lo & 0x1F);
++        plt_code[0] |= (data_lo & 0xE0) << 3;
++
++        /* Write out the sequence. */
++        for (i = 0; i < NUM_PLT_CODE_WORDS_SEQ2; i++)
++          {
++            bfd_put_32 (output_bfd, plt_code[i], plt_output_code);
++            plt_output_code += 4;
++          }
++      }
++      else if (entry->plt_type == 1)
++      {
++        /* Outupt sequence 1 */
++        plt_code = plt_code_seq1;
++
++        /* Code the entry into the movei instruction. */
++        plt_code[0] = (plt_code[0] & 0xFFFF0000) | ((entry->fd_entry >> 2) & 0xFFFF);
++
++        /* Write out the sequence. */
++        for (i = 0; i < NUM_PLT_CODE_WORDS_SEQ1; i++)
++          {
++            bfd_put_32 (output_bfd, plt_code[i], plt_output_code);
++            plt_output_code += 4;
++          }
++      }
++      else
++      BFD_ASSERT(0);
++
++#if 0
++      /* We have to output 5 words. The very first movei has to be modified with whatever is in fd_entry. */
++      plt_code[0] = (plt_code[0] & 0xFFFF0000) | ((entry->fd_entry >> 2) & 0xFFFF);
++
++      for (i = 0; i < NUM_PLT_CODE_WORDS; i++)
++      {
++        bfd_put_32 (output_bfd, plt_code[i], plt_output_code);
++        plt_output_code += 4;
++      }
++#endif
++    }
++
++  return TRUE;
++}
++
++\f
++/* Create  a .got section, as well as its additional info field.  This
++   is almost entirely copied from
++   elflink.c:_bfd_elf_create_got_section().  */
++
++static bfd_boolean
++ubicom32fdpic_elf_create_got_section (bfd *abfd, struct bfd_link_info *info)
++{
++  flagword flags, pltflags;
++  asection *s;
++  struct elf_link_hash_entry *h;
++  const struct elf_backend_data *bed = get_elf_backend_data (abfd);
++  int ptralign;
++  int offset;
++
++  /* This function may be called more than once.  */
++  s = bfd_get_section_by_name (abfd, ".got");
++  if (s != NULL && (s->flags & SEC_LINKER_CREATED) != 0)
++    return TRUE;
++
++  /* Machine specific: although pointers are 32-bits wide, we want the
++     GOT to be aligned to a 64-bit boundary, such that function
++     descriptors in it can be accessed with 64-bit loads and
++     stores.  */
++  ptralign = 3;
++
++  flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY
++         | SEC_LINKER_CREATED);
++  pltflags = flags;
++
++  s = bfd_make_section_with_flags (abfd, ".got", flags);
++  if (s == NULL
++      || !bfd_set_section_alignment (abfd, s, ptralign))
++    return FALSE;
++
++  if (bed->want_got_plt)
++    {
++      s = bfd_make_section_with_flags (abfd, ".got.plt", flags);
++      if (s == NULL
++        || !bfd_set_section_alignment (abfd, s, ptralign))
++      return FALSE;
++    }
++
++  if (bed->want_got_sym)
++    {
++      /* Define the symbol _GLOBAL_OFFSET_TABLE_ at the start of the .got
++       (or .got.plt) section.  We don't do this in the linker script
++       because we don't want to define the symbol if we are not creating
++       a global offset table.  */
++      h = _bfd_elf_define_linkage_sym (abfd, info, s, "_GLOBAL_OFFSET_TABLE_");
++      elf_hash_table (info)->hgot = h;
++      if (h == NULL)
++      return FALSE;
++
++      /* Machine-specific: we want the symbol for executables as
++       well.  */
++      if (! bfd_elf_link_record_dynamic_symbol (info, h))
++      return FALSE;
++    }
++
++  /* The first bit of the global offset table is the header.  */
++  s->size += bed->got_header_size;
++
++  /* This is the machine-specific part.  Create and initialize section
++     data for the got.  */
++  if (IS_FDPIC (abfd))
++    {
++      ubicom32fdpic_got_section (info) = s;
++      ubicom32fdpic_relocs_info (info) = htab_try_create (1,
++                                                        ubicom32fdpic_relocs_info_hash,
++                                                        ubicom32fdpic_relocs_info_eq,
++                                                        (htab_del) NULL);
++      if (! ubicom32fdpic_relocs_info (info))
++      return FALSE;
++
++      s = bfd_make_section_with_flags (abfd, ".rel.got",
++                                     (flags | SEC_READONLY));
++      if (s == NULL
++        || ! bfd_set_section_alignment (abfd, s, 2))
++      return FALSE;
++
++      ubicom32fdpic_gotrel_section (info) = s;
++
++      /* Machine-specific.  */
++      s = bfd_make_section_with_flags (abfd, ".rofixup",
++                                     (flags | SEC_READONLY));
++      if (s == NULL
++        || ! bfd_set_section_alignment (abfd, s, 2))
++      return FALSE;
++
++      ubicom32fdpic_gotfixup_section (info) = s;
++      offset = -2048;
++      flags = BSF_GLOBAL;
++    }
++  else
++    {
++      offset = 2048;
++      flags = BSF_GLOBAL | BSF_WEAK;
++    }
++
++  return TRUE;
++}
++
++/* Make sure the got and plt sections exist, and that our pointers in
++   the link hash table point to them.  */
++
++static bfd_boolean
++ubicom32fdpic_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
++{  flagword flags, pltflags;
++  asection *s;
++  const struct elf_backend_data *bed = get_elf_backend_data (abfd);
++
++  /* We need to create .plt, .rel[a].plt, .got, .got.plt, .dynbss, and
++     .rel[a].bss sections.  */
++  DPRINTF(" ubicom32fdpic_elf_create_dynamic_sections %p %p\n", abfd, info);
++
++  flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY
++         | SEC_LINKER_CREATED);
++
++  pltflags = flags;
++  pltflags |= SEC_CODE;
++  if (bed->plt_not_loaded)
++    pltflags &= ~ (SEC_CODE | SEC_LOAD | SEC_HAS_CONTENTS);
++  if (bed->plt_readonly)
++    pltflags |= SEC_READONLY;
++
++  s = bfd_make_section_with_flags (abfd, ".plt", pltflags);
++  if (s == NULL
++      || ! bfd_set_section_alignment (abfd, s, bed->plt_alignment))
++    return FALSE;
++  /* Blackfin-specific: remember it.  */
++  ubicom32fdpic_plt_section (info) = s;
++
++  if (bed->want_plt_sym)
++    {
++      /* Define the symbol _PROCEDURE_LINKAGE_TABLE_ at the start of the
++       .plt section.  */
++      struct elf_link_hash_entry *h;
++      struct bfd_link_hash_entry *bh = NULL;
++
++      if (! (_bfd_generic_link_add_one_symbol
++           (info, abfd, "_PROCEDURE_LINKAGE_TABLE_", BSF_GLOBAL, s, 0, NULL,
++            FALSE, get_elf_backend_data (abfd)->collect, &bh)))
++      return FALSE;
++      h = (struct elf_link_hash_entry *) bh;
++      h->def_regular = 1;
++      h->type = STT_OBJECT;
++
++      if (! info->executable
++        && ! bfd_elf_link_record_dynamic_symbol (info, h))
++      return FALSE;
++    }
++
++  /* Blackfin-specific: we want rel relocations for the plt.  */
++  s = bfd_make_section_with_flags (abfd, ".rel.plt", flags | SEC_READONLY);
++  if (s == NULL
++      || ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align))
++    return FALSE;
++  /* Blackfin-specific: remember it.  */
++  ubicom32fdpic_pltrel_section (info) = s;
++
++  /* Blackfin-specific: we want to create the GOT in the Blackfin way.  */
++  if (! ubicom32fdpic_elf_create_got_section (abfd, info))
++    return FALSE;
++
++  /* Blackfin-specific: make sure we created everything we wanted.  */
++  BFD_ASSERT (ubicom32fdpic_got_section (info) && ubicom32fdpic_gotrel_section (info)
++            /* && ubicom32fdpic_gotfixup_section (info) */
++            && ubicom32fdpic_plt_section (info)
++            && ubicom32fdpic_pltrel_section (info));
++
++  if (bed->want_dynbss)
++    {
++      /* The .dynbss section is a place to put symbols which are defined
++       by dynamic objects, are referenced by regular objects, and are
++       not functions.  We must allocate space for them in the process
++       image and use a R_*_COPY reloc to tell the dynamic linker to
++       initialize them at run time.  The linker script puts the .dynbss
++       section into the .bss section of the final image.  */
++      s = bfd_make_section_with_flags (abfd, ".dynbss",
++                                     SEC_ALLOC | SEC_LINKER_CREATED);
++      if (s == NULL)
++      return FALSE;
++
++      /* The .rel[a].bss section holds copy relocs.  This section is not
++     normally needed.  We need to create it here, though, so that the
++     linker will map it to an output section.  We can't just create it
++     only if we need it, because we will not know whether we need it
++     until we have seen all the input files, and the first time the
++     main linker code calls BFD after examining all the input files
++     (size_dynamic_sections) the input sections have already been
++     mapped to the output sections.  If the section turns out not to
++     be needed, we can discard it later.  We will never need this
++     section when generating a shared object, since they do not use
++     copy relocs.  */
++      if (! info->shared)
++      {
++        s = bfd_make_section_with_flags (abfd,
++                                         (bed->default_use_rela_p
++                                          ? ".rela.bss" : ".rel.bss"),
++                                         flags | SEC_READONLY);
++        if (s == NULL
++            || ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align))
++          return FALSE;
++      }
++    }
++
++  return TRUE;
++}
++
++/* We need dynamic symbols for every section, since segments can
++   relocate independently.  */
++static bfd_boolean
++ubicom32fdpic_elf_link_omit_section_dynsym (bfd *output_bfd ATTRIBUTE_UNUSED,
++                                          struct bfd_link_info *info
++                                          ATTRIBUTE_UNUSED,
++                                          asection *p ATTRIBUTE_UNUSED)
++{
++  switch (elf_section_data (p)->this_hdr.sh_type)
++    {
++    case SHT_PROGBITS:
++    case SHT_NOBITS:
++      /* If sh_type is yet undecided, assume it could be
++       SHT_PROGBITS/SHT_NOBITS.  */
++    case SHT_NULL:
++      return FALSE;
++
++      /* There shouldn't be section relative relocations
++       against any other section.  */
++    default:
++      return TRUE;
++    }
++}
++
++/* Look through the relocs for a section during the first phase.
++
++   Besides handling virtual table relocs for gc, we have to deal with
++   all sorts of PIC-related relocations.  We describe below the
++   general plan on how to handle such relocations, even though we only
++   collect information at this point, storing them in hash tables for
++   perusal of later passes.
++
++*/
++static bfd_boolean
++ubicom32fdpic_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
++                              asection *sec, const Elf_Internal_Rela *relocs)
++{
++  Elf_Internal_Shdr *symtab_hdr;
++  struct elf_link_hash_entry **sym_hashes, **sym_hashes_end;
++  const Elf_Internal_Rela *rel;
++  const Elf_Internal_Rela *rel_end;
++  bfd *dynobj;
++  struct ubicom32fdpic_relocs_info *picrel;
++
++  if (info->relocatable)
++    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);
++  if (!elf_bad_symtab (abfd))
++    sym_hashes_end -= symtab_hdr->sh_info;
++
++  dynobj = elf_hash_table (info)->dynobj;
++  rel_end = relocs + sec->reloc_count;
++  for (rel = relocs; rel < rel_end; rel++)
++    {
++      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;
++      else
++      h = sym_hashes[r_symndx - symtab_hdr->sh_info];
++
++      switch (ELF32_R_TYPE (rel->r_info))
++      {
++      case R_UBICOM32_GOTOFFSET_HI:
++      case R_UBICOM32_GOTOFFSET_LO:
++      case R_UBICOM32_FUNCDESC_GOTOFFSET_HI:
++      case R_UBICOM32_FUNCDESC_GOTOFFSET_LO:
++      case R_UBICOM32_FUNCDESC:
++      case R_UBICOM32_FUNCDESC_VALUE:
++        if (! IS_FDPIC (abfd))
++          goto bad_reloc;
++        /* Fall through.  */
++      case R_UBICOM32_24_PCREL:
++      case R_UBICOM32_32:
++        if (IS_FDPIC (abfd) && ! dynobj)
++          {
++            elf_hash_table (info)->dynobj = dynobj = abfd;
++            if (! ubicom32fdpic_elf_create_got_section (abfd, info))
++              return FALSE;
++          }
++        if (! IS_FDPIC (abfd))
++          {
++            picrel = NULL;
++            break;
++          }
++        if (h != NULL)
++          {
++            if (h->dynindx == -1)
++              switch (ELF_ST_VISIBILITY (h->other))
++                {
++                case STV_INTERNAL:
++                case STV_HIDDEN:
++                  break;
++                default:
++                  bfd_elf_link_record_dynamic_symbol (info, h);
++                  break;
++                }
++            picrel
++              = ubicom32fdpic_relocs_info_for_global (ubicom32fdpic_relocs_info (info),
++                                                      abfd, h,
++                                                      rel->r_addend, INSERT);
++          }
++        else
++          picrel = ubicom32fdpic_relocs_info_for_local (ubicom32fdpic_relocs_info (info),
++                                                        abfd, r_symndx,
++                                                        rel->r_addend, INSERT);
++        if (! picrel)
++          return FALSE;
++        break;
++
++      default:
++        picrel = NULL;
++        break;
++      }
++
++      switch (ELF32_R_TYPE (rel->r_info))
++      {
++      case R_UBICOM32_24_PCREL:
++        if (IS_FDPIC (abfd))
++          picrel->call++;
++        break;
++
++      case R_UBICOM32_FUNCDESC_VALUE:
++        picrel->relocsfdv++;
++        picrel->sym++;
++        break;
++
++      case R_UBICOM32_32:
++        if (! IS_FDPIC (abfd))
++          break;
++
++        picrel->sym++;
++        if (bfd_get_section_flags (abfd, sec) & SEC_ALLOC)
++          picrel->relocs32++;
++        break;
++
++      case R_UBICOM32_GOTOFFSET_HI:
++        picrel->gotoffset_hi++;
++        break;
++
++      case R_UBICOM32_GOTOFFSET_LO:
++        picrel->gotoffset_lo++;
++        break;
++
++      case R_UBICOM32_FUNCDESC_GOTOFFSET_HI:
++        picrel->fd_gotoffset_hi++;
++        break;
++
++      case R_UBICOM32_FUNCDESC_GOTOFFSET_LO:
++        picrel->fd_gotoffset_lo++;
++        break;
++
++      case R_UBICOM32_FUNCDESC:
++        picrel->fd++;
++        picrel->relocsfd++;
++        break;
++
++        /* This relocation describes the C++ object vtable hierarchy.
++           Reconstruct it for later use during GC.  */
++      case R_UBICOM32_GNU_VTINHERIT:
++        if (!bfd_elf_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_UBICOM32_GNU_VTENTRY:
++        if (!bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend))
++          return FALSE;
++        break;
++
++      case R_UBICOM32_21_PCREL:
++      case R_UBICOM32_HI24:
++      case R_UBICOM32_LO7_S:
++        break;
++
++      default:
++      bad_reloc:
++        (*_bfd_error_handler)
++          (_("%B: unsupported (ubicom32) relocation type %i"),
++           abfd, ELF32_R_TYPE (rel->r_info));
++        return FALSE;
++      }
++    }
++
++  return TRUE;
++}
++
++/* Follow indirect and warning hash entries so that each got entry
++   points to the final symbol definition.  P must point to a pointer
++   to the hash table we're traversing.  Since this traversal may
++   modify the hash table, we set this pointer to NULL to indicate
++   we've made a potentially-destructive change to the hash table, so
++   the traversal must be restarted.  */
++static int
++ubicom32fdpic_resolve_final_relocs_info (void **entryp, void *p)
++{
++  struct ubicom32fdpic_relocs_info *entry = *entryp;
++  htab_t *htab = p;
++
++  if (entry->symndx == -1)
++    {
++      struct elf_link_hash_entry *h = entry->d.h;
++      struct ubicom32fdpic_relocs_info *oentry;
++
++      while (h->root.type == bfd_link_hash_indirect
++           || h->root.type == bfd_link_hash_warning)
++      h = (struct elf_link_hash_entry *)h->root.u.i.link;
++
++      if (entry->d.h == h)
++      return 1;
++
++      oentry = ubicom32fdpic_relocs_info_for_global (*htab, 0, h, entry->addend,
++                                                   NO_INSERT);
++
++      if (oentry)
++      {
++        /* Merge the two entries.  */
++        ubicom32fdpic_pic_merge_early_relocs_info (oentry, entry);
++        htab_clear_slot (*htab, entryp);
++        return 1;
++      }
++
++      entry->d.h = h;
++
++      /* If we can't find this entry with the new bfd hash, re-insert
++       it, and get the traversal restarted.  */
++      if (! htab_find (*htab, entry))
++      {
++        htab_clear_slot (*htab, entryp);
++        entryp = htab_find_slot (*htab, entry, INSERT);
++        if (! *entryp)
++          *entryp = entry;
++        /* Abort the traversal, since the whole table may have
++           moved, and leave it up to the parent to restart the
++           process.  */
++        *(htab_t *)p = NULL;
++        return 0;
++      }
++    }
++
++  return 1;
++}
++
++/* Assign GOT offsets to private function descriptors used by PLT
++   entries (or referenced by 32-bit offsets), as well as PLT entries
++   and lazy PLT entries.  */
++static int
++ubicom32fdpic_assign_plt_entries (void **entryp, void *info_)
++{
++  struct ubicom32fdpic_relocs_info *entry = *entryp;
++  struct ubicom32fdpic_dynamic_got_plt_info *dinfo = info_;
++
++  if (entry->privfd && entry->fd_entry == 0)
++    {
++      //      dinfo->current_fd -= FUNCTION_DESCRIPTOR_SIZE;
++      //      entry->fd_entry = dinfo->current_fd;
++      DPRINTF(" late assign fd  % 5d:%p \n", entry->fd_entry, entry);
++    }
++
++  if (entry->plt)
++    {
++      /* We use the section's raw size to mark the location of the
++       next PLT entry.  */
++      entry->plt_entry = dinfo->current_plt;
++      entry->plt_trampoline_entry = dinfo->current_plt_trampoline;
++      dinfo->current_plt_trampoline += PLT_TRAMPOLINE_SIZE;
++
++      if (entry->fd_entry >= (-512))
++      {
++        /* This entry is going to be of type seq2 */
++        dinfo->current_plt += LZPLT_SIZE_SEQ2;
++        entry->plt_type = 2;
++      }
++      else
++      {
++        /* This entry is going to be of type seq1 */
++        dinfo->current_plt += LZPLT_SIZE_SEQ1;
++        entry->plt_type = 1;
++      }
++      DPRINTF(" assign plt % 4d for fd=% 4d:%p next %d plttype %d\n", entry->plt_entry, entry->fd_entry, entry,  dinfo->current_plt, entry->plt_type);
++
++    }
++
++  return 1;
++}
++
++/* Assign GOT offsets for every GOT entry and function descriptor.
++   Doing everything in a single pass is tricky.  */
++static int
++ubicom32fdpic_assign_got_entries (void **entryp, void *info_)
++{
++  struct ubicom32fdpic_relocs_info *entry = *entryp;
++  struct ubicom32fdpic_dynamic_got_plt_info *dinfo = info_;
++
++  if (entry->gotoffset_lo || entry->gotoffset_hi)
++    {
++      entry->got_entry = dinfo->current_got;
++      DPRINTF(" assign got % 5d:%p \n", entry->got_entry, entry);
++      dinfo->current_got += 4;
++    }
++
++  if (entry->fd_gotoffset_lo || entry->fd_gotoffset_hi)
++    {
++      entry->fdgot_entry = dinfo->current_got;
++      DPRINTF(" assign fdgot % 5d:%p \n", entry->fdgot_entry, entry);
++      dinfo->current_got += 4;
++    }
++
++  if (entry->plt)
++    {
++      dinfo->current_fd -= FUNCTION_DESCRIPTOR_SIZE;
++      entry->fd_entry = dinfo->current_fd;
++
++      dinfo->total_trampoline += PLT_TRAMPOLINE_SIZE;
++
++      if (entry->fd_entry >= (-512))
++      {
++        /* This entry is going to be of type seq2 */
++        dinfo->total_lzplt += LZPLT_SIZE_SEQ2;
++        entry->plt_type = 2;
++      }
++      else
++      {
++        /* This entry is going to be of type seq1 */
++        dinfo->total_lzplt += LZPLT_SIZE_SEQ1;
++        entry->plt_type = 1;
++      }
++
++      DPRINTF(" assign fd  % 5d:%p \n", entry->fd_entry, entry);
++    }
++  else if (entry->privfd)
++    {
++      dinfo->current_privfd -= FUNCTION_DESCRIPTOR_SIZE;
++      entry->fd_entry = dinfo->current_privfd;
++      DPRINTF(" assign private fd  % 5d:%p %p \n", entry->fd_entry, entry, entry->plt);
++    }
++
++  return 1;
++}
++
++/* Set the sizes of the dynamic sections.  */
++
++static bfd_boolean
++ubicom32fdpic_elf_size_dynamic_sections (bfd *output_bfd,
++                                       struct bfd_link_info *info)
++{
++  bfd *dynobj;
++  asection *s;
++  struct ubicom32fdpic_dynamic_got_plt_info gpinfo;
++  bfd_vma total_plt_size;
++
++  dynobj = elf_hash_table (info)->dynobj;
++  BFD_ASSERT (dynobj != NULL);
++
++  if (elf_hash_table (info)->dynamic_sections_created)
++    {
++      /* Set the contents of the .interp section to the interpreter.  */
++      if (info->executable)
++      {
++        s = bfd_get_section_by_name (dynobj, ".interp");
++        BFD_ASSERT (s != NULL);
++        s->size = sizeof ELF_DYNAMIC_INTERPRETER;
++        s->contents = (bfd_byte *) ELF_DYNAMIC_INTERPRETER;
++      }
++    }
++
++  memset (&gpinfo, 0, sizeof (gpinfo));
++  gpinfo.g.info = info;
++
++  for (;;)
++    {
++      htab_t relocs = ubicom32fdpic_relocs_info (info);
++
++      htab_traverse (relocs, ubicom32fdpic_resolve_final_relocs_info, &relocs);
++
++      if (relocs == ubicom32fdpic_relocs_info (info))
++      break;
++    }
++
++  htab_traverse (ubicom32fdpic_relocs_info (info), ubicom32fdpic_count_got_plt_entries,
++               &gpinfo.g);
++
++  /* At this point we know how many PLT entries we need. We know how many got entries we need and the total number of function descriptors in this link. */
++  gpinfo.total_fdplt = gpinfo.g.fdplt + gpinfo.g.privfdplt;
++  gpinfo.total_got = gpinfo.g.gotoffset_lo;
++  gpinfo.total_lzplt = 0;
++
++  gpinfo.current_got = 12;    /* The first 12 bytes are reserved to get to resolver. */
++  gpinfo.current_fd = 0;      /* We will decrement this by FUNCTION_DESCRIPTOR_SIZE for each allocation. */
++  gpinfo.current_privfd = -gpinfo.g.fdplt;    /* We will decrement this by FUNCTION_DESCRIPTOR_SIZE for each allocation. */
++  gpinfo.current_plt = 0;     /* Initialize this to 0. The trampoline code is at the start of the plt section.
++                                 We will decrement this by LZPLT_NORMAL_SIZE each time we allocate. */
++  gpinfo.current_plt_trampoline = 0;
++
++  DPRINTF("Total plts = %d \n", gpinfo.g.num_plts);
++
++  /* Now assign (most) GOT offsets.  */
++  htab_traverse (ubicom32fdpic_relocs_info (info), ubicom32fdpic_assign_got_entries,
++               &gpinfo);
++
++
++  ubicom32fdpic_got_section (info)->size = gpinfo.total_fdplt + gpinfo.total_got + 12;
++
++  DPRINTF("GOT size = fd=%d, got=%d\n", gpinfo.total_fdplt, gpinfo.total_got);
++
++  if (ubicom32fdpic_got_section (info)->size == 0)
++    ubicom32fdpic_got_section (info)->flags |= SEC_EXCLUDE;
++  else if (ubicom32fdpic_got_section (info)->size == 12
++         && ! elf_hash_table (info)->dynamic_sections_created)
++    {
++      ubicom32fdpic_got_section (info)->flags |= SEC_EXCLUDE;
++      ubicom32fdpic_got_section (info)->size = 0;
++    }
++  else
++    {
++      DPRINTF(" Alloc GOT size = %d\n", ubicom32fdpic_got_section (info)->size);
++      ubicom32fdpic_got_section (info)->contents =
++      (bfd_byte *) bfd_zalloc (dynobj,
++                               ubicom32fdpic_got_section (info)->size);
++      if (ubicom32fdpic_got_section (info)->contents == NULL)
++      return FALSE;
++    }
++
++  if (elf_hash_table (info)->dynamic_sections_created)
++    /* Subtract the number of lzplt entries, since those will generate
++       relocations in the pltrel section.  */
++    ubicom32fdpic_gotrel_section (info)->size =
++      (gpinfo.g.relocs - gpinfo.g.num_plts)
++      * get_elf_backend_data (output_bfd)->s->sizeof_rel;
++  else
++    BFD_ASSERT (gpinfo.g.relocs == 0);
++  if (ubicom32fdpic_gotrel_section (info)->size == 0)
++    ubicom32fdpic_gotrel_section (info)->flags |= SEC_EXCLUDE;
++  else
++    {
++      ubicom32fdpic_gotrel_section (info)->contents =
++      (bfd_byte *) bfd_zalloc (dynobj,
++                               ubicom32fdpic_gotrel_section (info)->size);
++      if (ubicom32fdpic_gotrel_section (info)->contents == NULL)
++      return FALSE;
++    }
++
++  ubicom32fdpic_gotfixup_section (info)->size = (gpinfo.g.fixups + 1) * 4;
++  if (ubicom32fdpic_gotfixup_section (info)->size == 0)
++    ubicom32fdpic_gotfixup_section (info)->flags |= SEC_EXCLUDE;
++  else
++    {
++      ubicom32fdpic_gotfixup_section (info)->contents =
++      (bfd_byte *) bfd_zalloc (dynobj,
++                               ubicom32fdpic_gotfixup_section (info)->size);
++      if (ubicom32fdpic_gotfixup_section (info)->contents == NULL)
++      return FALSE;
++    }
++
++  if (elf_hash_table (info)->dynamic_sections_created)
++    {
++      ubicom32fdpic_pltrel_section (info)->size =
++      gpinfo.g.num_plts * get_elf_backend_data (output_bfd)->s->sizeof_rel;
++      if (ubicom32fdpic_pltrel_section (info)->size == 0)
++      ubicom32fdpic_pltrel_section (info)->flags |= SEC_EXCLUDE;
++      else
++      {
++        ubicom32fdpic_pltrel_section (info)->contents =
++          (bfd_byte *) bfd_zalloc (dynobj,
++                                   ubicom32fdpic_pltrel_section (info)->size);
++        if (ubicom32fdpic_pltrel_section (info)->contents == NULL)
++          return FALSE;
++      }
++    }
++
++  /* The Pltsection is g.lzplt . The 4 is for the trampoline code. */
++  total_plt_size = gpinfo.total_lzplt + gpinfo.total_trampoline;
++  gpinfo.current_plt_trampoline = gpinfo.total_lzplt;
++
++  if (elf_hash_table (info)->dynamic_sections_created)
++    {
++      DPRINTF(" PLT size = %d\n", (total_plt_size ));
++      ubicom32fdpic_plt_section (info)->size = (total_plt_size);
++    }
++
++  /* Save information that we're going to need to generate GOT and PLT
++     entries.  */
++  ubicom32fdpic_got_initial_offset (info) = gpinfo.total_fdplt;
++
++  if (get_elf_backend_data (output_bfd)->want_got_sym)
++    elf_hash_table (info)->hgot->root.u.def.value
++      += ubicom32fdpic_got_initial_offset (info);
++
++  /* Allocate the PLT section contents.  */
++  if (elf_hash_table (info)->dynamic_sections_created)
++    {
++      if (ubicom32fdpic_plt_section (info)->size == 4)
++      {
++        ubicom32fdpic_plt_section (info)->flags |= SEC_EXCLUDE;
++        ubicom32fdpic_plt_section (info)->size = 0;
++      }
++      else
++      {
++        DPRINTF(" Alloc PLT size = %d\n", (total_plt_size));
++        ubicom32fdpic_plt_section (info)->contents =
++          (bfd_byte *) bfd_zalloc (dynobj,
++                                   ubicom32fdpic_plt_section (info)->size);
++        if (ubicom32fdpic_plt_section (info)->contents == NULL)
++          return FALSE;
++      }
++    }
++
++  
++  htab_traverse (ubicom32fdpic_relocs_info (info), ubicom32fdpic_assign_plt_entries,
++               &gpinfo);
++
++
++  if (elf_hash_table (info)->dynamic_sections_created)
++    {
++      if (ubicom32fdpic_got_section (info)->size)
++      if (!_bfd_elf_add_dynamic_entry (info, DT_PLTGOT, 0))
++        return FALSE;
++
++      if (ubicom32fdpic_pltrel_section (info)->size)
++      if (!_bfd_elf_add_dynamic_entry (info, DT_PLTRELSZ, 0)
++          || !_bfd_elf_add_dynamic_entry (info, DT_PLTREL, DT_REL)
++          || !_bfd_elf_add_dynamic_entry (info, DT_JMPREL, 0))
++        return FALSE;
++
++      if (ubicom32fdpic_gotrel_section (info)->size)
++      if (!_bfd_elf_add_dynamic_entry (info, DT_REL, 0)
++          || !_bfd_elf_add_dynamic_entry (info, DT_RELSZ, 0)
++          || !_bfd_elf_add_dynamic_entry (info, DT_RELENT,
++                                          sizeof (Elf32_External_Rel)))
++        return FALSE;
++    }
++
++  s = bfd_get_section_by_name (dynobj, ".rela.bss");
++  if (s && s->size == 0)
++    s->flags |= SEC_EXCLUDE;
++
++  s = bfd_get_section_by_name (dynobj, ".rel.plt");
++  if (s && s->size == 0)
++    s->flags |= SEC_EXCLUDE;
++
++  return TRUE;
++}
++
++
++/* Adjust a symbol defined by a dynamic object and referenced by a
++   regular object.  */
++
++static bfd_boolean
++ubicom32fdpic_elf_adjust_dynamic_symbol
++(struct bfd_link_info *info ATTRIBUTE_UNUSED,
++ struct elf_link_hash_entry *h ATTRIBUTE_UNUSED)
++{
++  bfd * dynobj;
++
++  dynobj = elf_hash_table (info)->dynobj;
++
++  /* Make sure we know what is going on here.  */
++  BFD_ASSERT (dynobj != NULL
++            && (h->u.weakdef != NULL
++                || (h->def_dynamic
++                    && h->ref_regular
++                    && !h->def_regular)));
++
++  /* If this is a weak symbol, and there is a real definition, the
++     processor independent code will have arranged for us to see the
++     real definition first, and we can just use the same value.  */
++  if (h->u.weakdef != NULL)
++    {
++      BFD_ASSERT (h->u.weakdef->root.type == bfd_link_hash_defined
++                || h->u.weakdef->root.type == bfd_link_hash_defweak);
++      h->root.u.def.section = h->u.weakdef->root.u.def.section;
++      h->root.u.def.value = h->u.weakdef->root.u.def.value;
++    }
++
++  return TRUE;
++}
++
++static bfd_boolean
++ubicom32fdpic_elf_always_size_sections (bfd *output_bfd,
++                                      struct bfd_link_info *info)
++{
++  if (!info->relocatable)
++    {
++      struct elf_link_hash_entry *h;
++
++      /* Force a PT_GNU_STACK segment to be created.  */
++      if (! elf_tdata (output_bfd)->stack_flags)
++      elf_tdata (output_bfd)->stack_flags = PF_R | PF_W | PF_X;
++
++      /* Define __stacksize if it's not defined yet.  */
++      h = elf_link_hash_lookup (elf_hash_table (info), "__stacksize",
++                              FALSE, FALSE, FALSE);
++      if (! h || h->root.type != bfd_link_hash_defined
++        || h->type != STT_OBJECT
++        || !h->def_regular)
++      {
++        struct bfd_link_hash_entry *bh = NULL;
++
++        if (!(_bfd_generic_link_add_one_symbol
++              (info, output_bfd, "__stacksize",
++               BSF_GLOBAL, bfd_abs_section_ptr, DEFAULT_STACK_SIZE,
++               (const char *) NULL, FALSE,
++               get_elf_backend_data (output_bfd)->collect, &bh)))
++          return FALSE;
++
++        h = (struct elf_link_hash_entry *) bh;
++        h->def_regular = 1;
++        h->type = STT_OBJECT;
++      }
++    }
++
++  return TRUE;
++}
++
++static bfd_boolean
++ubicom32fdpic_elf_finish_dynamic_sections (bfd *output_bfd,
++                                         struct bfd_link_info *info)
++{
++  bfd *dynobj;
++  asection *sdyn;
++
++  dynobj = elf_hash_table (info)->dynobj;
++
++  if (ubicom32fdpic_got_section (info))
++    {
++      BFD_ASSERT (ubicom32fdpic_gotrel_section (info)->size
++                == (ubicom32fdpic_gotrel_section (info)->reloc_count
++                    * sizeof (Elf32_External_Rel)));
++
++      if (ubicom32fdpic_gotfixup_section (info))
++      {
++        struct elf_link_hash_entry *hgot = elf_hash_table (info)->hgot;
++        bfd_vma got_value = hgot->root.u.def.value
++          + hgot->root.u.def.section->output_section->vma
++          + hgot->root.u.def.section->output_offset;
++
++        ubicom32fdpic_add_rofixup (output_bfd, ubicom32fdpic_gotfixup_section (info),
++                                   got_value, 0);
++
++        if (ubicom32fdpic_gotfixup_section (info)->size
++            != (ubicom32fdpic_gotfixup_section (info)->reloc_count * 4))
++          {
++            (*_bfd_error_handler)
++              ("LINKER BUG: .rofixup section size mismatch Size %d, should be %d ",
++               ubicom32fdpic_gotfixup_section (info)->size, ubicom32fdpic_gotfixup_section (info)->reloc_count * 4);
++            return FALSE;
++          }
++      }
++    }
++  if (elf_hash_table (info)->dynamic_sections_created)
++    {
++      BFD_ASSERT (ubicom32fdpic_pltrel_section (info)->size
++                == (ubicom32fdpic_pltrel_section (info)->reloc_count
++                    * sizeof (Elf32_External_Rel)));
++    }
++
++  sdyn = bfd_get_section_by_name (dynobj, ".dynamic");
++
++  if (elf_hash_table (info)->dynamic_sections_created)
++    {
++      Elf32_External_Dyn * dyncon;
++      Elf32_External_Dyn * dynconend;
++
++      BFD_ASSERT (sdyn != NULL);
++
++      dyncon = (Elf32_External_Dyn *) sdyn->contents;
++      dynconend = (Elf32_External_Dyn *) (sdyn->contents + sdyn->size);
++
++      for (; dyncon < dynconend; dyncon++)
++      {
++        Elf_Internal_Dyn dyn;
++
++        bfd_elf32_swap_dyn_in (dynobj, dyncon, &dyn);
++
++        switch (dyn.d_tag)
++          {
++          default:
++            break;
++
++          case DT_PLTGOT:
++            dyn.d_un.d_ptr = ubicom32fdpic_got_section (info)->output_section->vma
++              + ubicom32fdpic_got_section (info)->output_offset
++              + ubicom32fdpic_got_initial_offset (info);
++            bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon);
++            break;
++
++          case DT_JMPREL:
++            dyn.d_un.d_ptr = ubicom32fdpic_pltrel_section (info)
++              ->output_section->vma
++              + ubicom32fdpic_pltrel_section (info)->output_offset;
++            bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon);
++            break;
++
++          case DT_PLTRELSZ:
++            dyn.d_un.d_val = ubicom32fdpic_pltrel_section (info)->size;
++            bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon);
++            break;
++          }
++      }
++    }
++
++  return TRUE;
++}
++
++/* Perform any actions needed for dynamic symbols.  */
++static bfd_boolean
++ubicom32fdpic_elf_finish_dynamic_symbol
++(bfd *output_bfd ATTRIBUTE_UNUSED,
++ struct bfd_link_info *info ATTRIBUTE_UNUSED,
++ struct elf_link_hash_entry *h ATTRIBUTE_UNUSED,
++ Elf_Internal_Sym *sym ATTRIBUTE_UNUSED)
++{
++  return TRUE;
++}
++
++static bfd_boolean
++ubicom32fdpic_elf_modify_program_headers (bfd *output_bfd,
++                                        struct bfd_link_info *info)
++{
++  struct elf_obj_tdata *tdata = elf_tdata (output_bfd);
++  struct elf_segment_map *m;
++  Elf_Internal_Phdr *p;
++
++  if (! info)
++    return TRUE;
++
++  for (p = tdata->phdr, m = tdata->segment_map; m != NULL; m = m->next, p++)
++    if (m->p_type == PT_GNU_STACK)
++      break;
++
++  if (m)
++    {
++      struct elf_link_hash_entry *h;
++
++      /* Obtain the pointer to the __stacksize symbol.  */
++      h = elf_link_hash_lookup (elf_hash_table (info), "__stacksize",
++                              FALSE, FALSE, FALSE);
++      if (h)
++      {
++        while (h->root.type == bfd_link_hash_indirect
++               || h->root.type == bfd_link_hash_warning)
++          h = (struct elf_link_hash_entry *) h->root.u.i.link;
++        BFD_ASSERT (h->root.type == bfd_link_hash_defined);
++      }
++
++      /* Set the header p_memsz from the symbol value.  We
++       intentionally ignore the symbol section.  */
++      if (h && h->root.type == bfd_link_hash_defined)
++      p->p_memsz = h->root.u.def.value;
++      else
++      p->p_memsz = DEFAULT_STACK_SIZE;
++
++      p->p_align = 8;
++    }
++
++  return TRUE;
++}
++
++static bfd_boolean
++ubicom32fdpic_elf_gc_sweep_hook (bfd *abfd,
++                               struct bfd_link_info *info,
++                               asection *sec,
++                               const Elf_Internal_Rela *relocs)
++{
++  Elf_Internal_Shdr *symtab_hdr;
++  struct elf_link_hash_entry **sym_hashes, **sym_hashes_end;
++  const Elf_Internal_Rela *rel;
++  const Elf_Internal_Rela *rel_end;
++  struct ubicom32fdpic_relocs_info *picrel;
++
++  BFD_ASSERT (IS_FDPIC (abfd));
++
++  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);
++  if (!elf_bad_symtab (abfd))
++    sym_hashes_end -= symtab_hdr->sh_info;
++
++  rel_end = relocs + sec->reloc_count;
++  for (rel = relocs; rel < rel_end; rel++)
++    {
++      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;
++      else
++      h = sym_hashes[r_symndx - symtab_hdr->sh_info];
++
++      if (h != NULL)
++      picrel = ubicom32fdpic_relocs_info_for_global (ubicom32fdpic_relocs_info (info),
++                                                     abfd, h,
++                                                     rel->r_addend, NO_INSERT);
++      else
++      picrel = ubicom32fdpic_relocs_info_for_local (ubicom32fdpic_relocs_info
++                                                    (info), abfd, r_symndx,
++                                                    rel->r_addend, NO_INSERT);
++
++      if (!picrel)
++      continue;
++
++      switch (ELF32_R_TYPE (rel->r_info))
++      {
++      case R_UBICOM32_24_PCREL:
++        picrel->call--;
++        break;
++
++      case R_UBICOM32_FUNCDESC_VALUE:
++        picrel->relocsfdv--;
++        picrel->sym--;
++        break;
++
++      case R_UBICOM32_GOTOFFSET_LO:
++        picrel->gotoffset_lo--;
++        break;
++
++      case R_UBICOM32_FUNCDESC_GOTOFFSET_LO:
++        picrel->fd_gotoffset_lo--;
++        break;
++
++      case R_UBICOM32_FUNCDESC_GOTOFFSET_HI:
++        picrel->fd_gotoffset_hi--;
++        break;
++
++      case R_UBICOM32_FUNCDESC:
++        picrel->fd--;
++        picrel->relocsfd--;
++        break;
++
++      case R_UBICOM32_32:
++        if (! IS_FDPIC (abfd))
++          break;
++
++        if (picrel->sym)
++          picrel->relocs32--;;
++
++        picrel->sym--;
++        break;
++
++      default:
++        break;
++      }
++    }
++
++  return TRUE;
++}
++/* Decide whether to attempt to turn absptr or lsda encodings in
++   shared libraries into pcrel within the given input section.  */
++
++static bfd_boolean
++ubicom32fdpic_elf_use_relative_eh_frame
++(bfd *input_bfd ATTRIBUTE_UNUSED,
++ struct bfd_link_info *info ATTRIBUTE_UNUSED,
++ asection *eh_frame_section ATTRIBUTE_UNUSED)
++{
++  /* We can't use PC-relative encodings in FDPIC binaries, in general.  */
++  return FALSE;
++}
++
++/* Adjust the contents of an eh_frame_hdr section before they're output.  */
++
++static bfd_byte
++ubicom32fdpic_elf_encode_eh_address (bfd *abfd,
++                                   struct bfd_link_info *info,
++                                   asection *osec, bfd_vma offset,
++                                   asection *loc_sec, bfd_vma loc_offset,
++                                   bfd_vma *encoded)
++{
++  struct elf_link_hash_entry *h;
++
++  h = elf_hash_table (info)->hgot;
++  BFD_ASSERT (h && h->root.type == bfd_link_hash_defined);
++
++  if (! h || (ubicom32fdpic_osec_to_segment (abfd, osec)
++            == ubicom32fdpic_osec_to_segment (abfd, loc_sec->output_section)))
++    return _bfd_elf_encode_eh_address (abfd, info, osec, offset,
++                                     loc_sec, loc_offset, encoded);
++
++  BFD_ASSERT (ubicom32fdpic_osec_to_segment (abfd, osec)
++            == (ubicom32fdpic_osec_to_segment
++                (abfd, h->root.u.def.section->output_section)));
++
++  *encoded = osec->vma + offset
++    - (h->root.u.def.value
++       + h->root.u.def.section->output_section->vma
++       + h->root.u.def.section->output_offset);
++
++  return DW_EH_PE_datarel | DW_EH_PE_sdata4;
++}
++static bfd_boolean
++ubicom32fdpic_elf_copy_private_bfd_data (bfd *ibfd, bfd *obfd)
++{
++  unsigned i;
++
++  if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour
++      || bfd_get_flavour (obfd) != bfd_target_elf_flavour)
++    return TRUE;
++
++  if (! ubicom32_elf_copy_private_bfd_data (ibfd, obfd))
++    return FALSE;
++
++  if (! elf_tdata (ibfd) || ! elf_tdata (ibfd)->phdr
++      || ! elf_tdata (obfd) || ! elf_tdata (obfd)->phdr)
++    return TRUE;
++
++  /* Copy the stack size.  */
++  for (i = 0; i < elf_elfheader (ibfd)->e_phnum; i++)
++    if (elf_tdata (ibfd)->phdr[i].p_type == PT_GNU_STACK)
++      {
++      Elf_Internal_Phdr *iphdr = &elf_tdata (ibfd)->phdr[i];
++
++      for (i = 0; i < elf_elfheader (obfd)->e_phnum; i++)
++        if (elf_tdata (obfd)->phdr[i].p_type == PT_GNU_STACK)
++          {
++            memcpy (&elf_tdata (obfd)->phdr[i], iphdr, sizeof (*iphdr));
++
++            /* Rewrite the phdrs, since we're only called after they
++               were first written.  */
++            if (bfd_seek (obfd, (bfd_signed_vma) get_elf_backend_data (obfd)
++                          ->s->sizeof_ehdr, SEEK_SET) != 0
++                || get_elf_backend_data (obfd)->s
++                ->write_out_phdrs (obfd, elf_tdata (obfd)->phdr,
++                                   elf_elfheader (obfd)->e_phnum) != 0)
++              return FALSE;
++            break;
++          }
++
++      break;
++      }
++
++  return TRUE;
++}
++
++static bfd_boolean
++ubicom32fdpic_elf_relocate_section (bfd * output_bfd,
++                                  struct bfd_link_info *info,
++                                  bfd * input_bfd,
++                                  asection * input_section,
++                                  bfd_byte * contents,
++                                  Elf_Internal_Rela * relocs,
++                                  Elf_Internal_Sym * local_syms,
++                                  asection ** local_sections)
++{
++  Elf_Internal_Shdr *symtab_hdr;
++  struct elf_link_hash_entry **sym_hashes;
++  Elf_Internal_Rela *rel;
++  Elf_Internal_Rela *relend;
++  unsigned isec_segment, got_segment, plt_segment,
++    check_segment[2];
++  int silence_segment_error = !(info->shared || info->pie);
++
++  if (info->relocatable)
++    return TRUE;
++
++  symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr;
++  sym_hashes = elf_sym_hashes (input_bfd);
++  relend     = relocs + input_section->reloc_count;
++
++  isec_segment = ubicom32fdpic_osec_to_segment (output_bfd,
++                                              input_section->output_section);
++  if (IS_FDPIC (output_bfd) && ubicom32fdpic_got_section (info))
++    got_segment = ubicom32fdpic_osec_to_segment (output_bfd,
++                                               ubicom32fdpic_got_section (info)
++                                               ->output_section);
++  else
++    got_segment = -1;
++  if (IS_FDPIC (output_bfd) && elf_hash_table (info)->dynamic_sections_created)
++    plt_segment = ubicom32fdpic_osec_to_segment (output_bfd,
++                                               ubicom32fdpic_plt_section (info)
++                                               ->output_section);
++  else
++    plt_segment = -1;
++
++  for (rel = relocs; rel < relend; rel ++)
++    {
++      reloc_howto_type *howto;
++      unsigned long r_symndx;
++      Elf_Internal_Sym *sym;
++      asection *sec;
++      struct elf_link_hash_entry *h;
++      bfd_vma relocation;
++      bfd_reloc_status_type r;
++      const char * name = NULL;
++      int r_type;
++      asection *osec;
++      struct ubicom32fdpic_relocs_info *picrel;
++      bfd_vma orig_addend = rel->r_addend;
++
++      r_type = ELF32_R_TYPE (rel->r_info);
++
++      if (r_type == R_UBICOM32_GNU_VTINHERIT
++        || r_type == R_UBICOM32_GNU_VTENTRY)
++      continue;
++
++      /* This is a final link.  */
++      r_symndx = ELF32_R_SYM (rel->r_info);
++
++      //howto = ubicom32_reloc_type_lookup (input_bfd, r_type);
++      howto  = ubicom32_elf_howto_table + ELF32_R_TYPE (rel->r_info);
++      if (howto == NULL)
++      {
++        bfd_set_error (bfd_error_bad_value);
++        return FALSE;
++      }
++
++      h      = NULL;
++      sym    = NULL;
++      sec    = NULL;
++
++      if (r_symndx < symtab_hdr->sh_info)
++      {
++        sym = local_syms + r_symndx;
++        osec = sec = local_sections [r_symndx];
++        relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel);
++
++        name = bfd_elf_string_from_elf_section
++          (input_bfd, symtab_hdr->sh_link, sym->st_name);
++        name = (name == NULL) ? bfd_section_name (input_bfd, sec) : name;
++      }
++      else
++      {
++        h = sym_hashes [r_symndx - symtab_hdr->sh_info];
++
++        while (h->root.type == bfd_link_hash_indirect
++               || h->root.type == bfd_link_hash_warning)
++          h = (struct elf_link_hash_entry *) h->root.u.i.link;
++
++        name = h->root.root.string;
++
++        if ((h->root.type == bfd_link_hash_defined
++             || h->root.type == bfd_link_hash_defweak)
++            && ! UBICOM32FDPIC_SYM_LOCAL (info, h))
++          {
++            sec = NULL;
++            relocation = 0;
++          }
++        else
++          if (h->root.type == bfd_link_hash_defined
++              || h->root.type == bfd_link_hash_defweak)
++            {
++              sec = h->root.u.def.section;
++              relocation = (h->root.u.def.value
++                            + sec->output_section->vma
++                            + sec->output_offset);
++            }
++          else if (h->root.type == bfd_link_hash_undefweak)
++            {
++              relocation = 0;
++            }
++          else if (info->unresolved_syms_in_objects == RM_IGNORE
++                   && ELF_ST_VISIBILITY (h->other) == STV_DEFAULT)
++            relocation = 0;
++          else
++            {
++              if (! ((*info->callbacks->undefined_symbol)
++                     (info, h->root.root.string, input_bfd,
++                      input_section, rel->r_offset,
++                      (info->unresolved_syms_in_objects == RM_GENERATE_ERROR
++                       || ELF_ST_VISIBILITY (h->other)))))
++                return FALSE;
++              relocation = 0;
++            }
++        osec = sec;
++      }
++
++      switch (r_type)
++      {
++      case R_UBICOM32_24_PCREL:
++      case R_UBICOM32_32:
++        if (! IS_FDPIC (output_bfd))
++          goto non_fdpic;
++
++      case R_UBICOM32_FUNCDESC_VALUE:
++      case R_UBICOM32_FUNCDESC:
++      case R_UBICOM32_GOTOFFSET_LO:
++      case R_UBICOM32_GOTOFFSET_HI:
++      case R_UBICOM32_FUNCDESC_GOTOFFSET_LO:
++      case R_UBICOM32_FUNCDESC_GOTOFFSET_HI:
++        if (h != NULL)
++          picrel = ubicom32fdpic_relocs_info_for_global (ubicom32fdpic_relocs_info
++                                                         (info), input_bfd, h,
++                                                         orig_addend, INSERT);
++        else
++          /* In order to find the entry we created before, we must
++             use the original addend, not the one that may have been
++             modified by _bfd_elf_rela_local_sym().  */
++          picrel = ubicom32fdpic_relocs_info_for_local (ubicom32fdpic_relocs_info
++                                                        (info), input_bfd, r_symndx,
++                                                        orig_addend, INSERT);
++        if (! picrel)
++          return FALSE;
++
++        if (!ubicom32fdpic_emit_got_relocs_plt_entries (picrel, output_bfd, info,
++                                                        osec, sym,
++                                                        rel->r_addend))
++          {
++            (*_bfd_error_handler)
++              (_("%B: relocation at `%A+0x%x' references symbol `%s' with nonzero addend"),
++               input_bfd, input_section, rel->r_offset, name);
++            return FALSE;
++
++          }
++
++        break;
++      case R_UBICOM32_21_PCREL:
++      case R_UBICOM32_HI24:
++      case R_UBICOM32_LO7_S:
++        //printf("Seeing this stuff Don;t know what to do. r_type %d r_symndx %d %s %s\n", r_type, r_symndx, input_bfd->filename, input_section->name);
++        break;
++
++      default:
++      non_fdpic:
++        picrel = NULL;
++        //printf("h = 0x%x %d\n", h, UBICOM32FDPIC_SYM_LOCAL (info, h));
++        if (h && ! UBICOM32FDPIC_SYM_LOCAL (info, h))
++          {
++            printf("h = 0x%x %d\n", h, UBICOM32FDPIC_SYM_LOCAL (info, h));
++            printf("Seeing this stuff. r_type %d r_symndx %d %s %s\n", r_type, r_symndx, input_bfd->filename, input_section->name);
++            info->callbacks->warning
++              (info, _("relocation references symbol not defined in the module"),
++               name, input_bfd, input_section, rel->r_offset);
++            return FALSE;
++          }
++        break;
++      }
++
++      switch (r_type)
++      {
++      case R_UBICOM32_21_PCREL:
++      case R_UBICOM32_HI24:
++      case R_UBICOM32_LO7_S:
++        //printf("Seeing this stuff. r_type %d r_symndx %d %s %s\n", r_type, r_symndx, input_bfd->filename, input_section->name);
++        check_segment[0] = check_segment[1] = got_segment;
++        break;
++
++      case R_UBICOM32_24_PCREL:
++        check_segment[0] = isec_segment;
++        if (! IS_FDPIC (output_bfd))
++          check_segment[1] = isec_segment;
++        else if (picrel->plt)
++          {
++            relocation = ubicom32fdpic_plt_section (info)->output_section->vma
++              + ubicom32fdpic_plt_section (info)->output_offset
++              + picrel->plt_entry;
++
++            /* subtract rel->addend. This will get added back in the 23pcrel howto routine. */
++            relocation -= rel->r_addend;
++
++            check_segment[1] = plt_segment;
++          }
++        /* We don't want to warn on calls to undefined weak symbols,
++           as calls to them must be protected by non-NULL tests
++           anyway, and unprotected calls would invoke undefined
++           behavior.  */
++        else if (picrel->symndx == -1
++                 && picrel->d.h->root.type == bfd_link_hash_undefweak)
++          check_segment[1] = check_segment[0];
++        else
++          check_segment[1] = sec
++            ? ubicom32fdpic_osec_to_segment (output_bfd, sec->output_section)
++            : (unsigned)-1;
++        break;
++
++      case R_UBICOM32_GOTOFFSET_LO:
++        relocation = picrel->got_entry >> 2;
++        check_segment[0] = check_segment[1] = got_segment;
++        break;
++
++      case R_UBICOM32_FUNCDESC_GOTOFFSET_LO:
++        relocation = picrel->fdgot_entry >> 2;
++        check_segment[0] = check_segment[1] = got_segment;
++        break;
++
++      case R_UBICOM32_FUNCDESC:
++        {
++          int dynindx;
++          bfd_vma addend = rel->r_addend;
++
++          if (! (h && h->root.type == bfd_link_hash_undefweak
++                 && UBICOM32FDPIC_SYM_LOCAL (info, h)))
++            {
++              /* If the symbol is dynamic and there may be dynamic
++                 symbol resolution because we are or are linked with a
++                 shared library, emit a FUNCDESC relocation such that
++                 the dynamic linker will allocate the function
++                 descriptor.  If the symbol needs a non-local function
++                 descriptor but binds locally (e.g., its visibility is
++                 protected, emit a dynamic relocation decayed to
++                 section+offset.  */
++              if (h && ! UBICOM32FDPIC_FUNCDESC_LOCAL (info, h)
++                  && UBICOM32FDPIC_SYM_LOCAL (info, h)
++                  && !(info->executable && !info->pie))
++                {
++                  dynindx = elf_section_data (h->root.u.def.section
++                                              ->output_section)->dynindx;
++                  addend += h->root.u.def.section->output_offset
++                    + h->root.u.def.value;
++                }
++              else if (h && ! UBICOM32FDPIC_FUNCDESC_LOCAL (info, h))
++                {
++                  if (addend)
++                    {
++                      info->callbacks->warning
++                        (info, _("R_UBICOM32_FUNCDESC references dynamic symbol with nonzero addend"),
++                         name, input_bfd, input_section, rel->r_offset);
++                      return FALSE;
++                    }
++                  dynindx = h->dynindx;
++                }
++              else
++                {
++                  /* Otherwise, we know we have a private function
++                     descriptor, so reference it directly.  */
++                  BFD_ASSERT (picrel->privfd);
++                  r_type = R_UBICOM32_32; // was FUNCDESC but bfin uses 32 bit
++                  dynindx = elf_section_data (ubicom32fdpic_got_section (info)
++                                              ->output_section)->dynindx;
++                  addend = ubicom32fdpic_got_section (info)->output_offset
++                    + ubicom32fdpic_got_initial_offset (info)
++                    + picrel->fd_entry;
++                }
++
++              /* If there is room for dynamic symbol resolution, emit
++                 the dynamic relocation.  However, if we're linking an
++                 executable at a fixed location, we won't have emitted a
++                 dynamic symbol entry for the got section, so idx will
++                 be zero, which means we can and should compute the
++                 address of the private descriptor ourselves.  */
++              if (info->executable && !info->pie
++                  && (!h || UBICOM32FDPIC_FUNCDESC_LOCAL (info, h)))
++                {
++                  addend += ubicom32fdpic_got_section (info)->output_section->vma;
++                  if ((bfd_get_section_flags (output_bfd,
++                                              input_section->output_section)
++                       & (SEC_ALLOC | SEC_LOAD)) == (SEC_ALLOC | SEC_LOAD))
++                    {
++                      if (ubicom32fdpic_osec_readonly_p (output_bfd,
++                                                         input_section
++                                                         ->output_section))
++                        {
++                          info->callbacks->warning
++                            (info,
++                             _("cannot emit fixups in read-only section"),
++                             name, input_bfd, input_section, rel->r_offset);
++                          return FALSE;
++                        }
++                      ubicom32fdpic_add_rofixup (output_bfd,
++                                                 ubicom32fdpic_gotfixup_section
++                                                 (info),
++                                                 _bfd_elf_section_offset
++                                                 (output_bfd, info,
++                                                  input_section, rel->r_offset)
++                                                 + input_section
++                                                 ->output_section->vma
++                                                 + input_section->output_offset,
++                                                 picrel);
++                    }
++                }
++              else if ((bfd_get_section_flags (output_bfd,
++                                               input_section->output_section)
++                        & (SEC_ALLOC | SEC_LOAD)) == (SEC_ALLOC | SEC_LOAD))
++                {
++                  bfd_vma offset;
++
++                  if (ubicom32fdpic_osec_readonly_p (output_bfd,
++                                                     input_section
++                                                     ->output_section))
++                    {
++                      info->callbacks->warning
++                        (info,
++                         _("cannot emit dynamic relocations in read-only section"),
++                         name, input_bfd, input_section, rel->r_offset);
++                      return FALSE;
++                    }
++                  offset = _bfd_elf_section_offset (output_bfd, info,
++                                                    input_section, rel->r_offset);
++                  /* Only output a reloc for a not deleted entry.  */
++                  if (offset >= (bfd_vma) -2)
++                    ubicom32fdpic_add_dyn_reloc (output_bfd,
++                                                 ubicom32fdpic_gotrel_section (info),
++                                                 0,
++                                                 R_UBICOM32_NONE,
++                                                 dynindx, addend, picrel);
++                  else
++                    ubicom32fdpic_add_dyn_reloc (output_bfd,
++                                                 ubicom32fdpic_gotrel_section (info),
++                                                 offset + input_section
++                                                 ->output_section->vma
++                                                 + input_section->output_offset,
++                                                 r_type,
++                                                 dynindx, addend, picrel);
++                }
++              else
++                addend += ubicom32fdpic_got_section (info)->output_section->vma;
++            }
++
++          /* We want the addend in-place because dynamic
++             relocations are REL.  Setting relocation to it should
++             arrange for it to be installed.  */
++          relocation = addend - rel->r_addend;
++        }
++        check_segment[0] = check_segment[1] = got_segment;
++        break;
++
++      case R_UBICOM32_32:
++        if (! IS_FDPIC (output_bfd))
++          {
++            check_segment[0] = check_segment[1] = -1;
++            break;
++          }
++        /* Fall through.  */
++      case R_UBICOM32_FUNCDESC_VALUE:
++        {
++          int dynindx;
++          bfd_vma addend = rel->r_addend;
++          bfd_vma offset;
++          offset = _bfd_elf_section_offset (output_bfd, info,
++                                            input_section, rel->r_offset);
++
++          /* If the symbol is dynamic but binds locally, use
++             section+offset.  */
++          if (h && ! UBICOM32FDPIC_SYM_LOCAL (info, h))
++            {
++              if (addend && r_type == R_UBICOM32_FUNCDESC_VALUE)
++                {
++                  info->callbacks->warning
++                    (info, _("R_UBICOM32_FUNCDESC_VALUE references dynamic symbol with nonzero addend"),
++                     name, input_bfd, input_section, rel->r_offset);
++                  return FALSE;
++                }
++              dynindx = h->dynindx;
++            }
++          else
++            {
++              if (h)
++                addend += h->root.u.def.value;
++              else
++                addend += sym->st_value;
++              if (osec)
++                addend += osec->output_offset;
++              if (osec && osec->output_section
++                  && ! bfd_is_abs_section (osec->output_section)
++                  && ! bfd_is_und_section (osec->output_section))
++                dynindx = elf_section_data (osec->output_section)->dynindx;
++              else
++                dynindx = 0;
++            }
++
++          /* If we're linking an executable at a fixed address, we
++             can omit the dynamic relocation as long as the symbol
++             is defined in the current link unit (which is implied
++             by its output section not being NULL).  */
++          if (info->executable && !info->pie
++              && (!h || UBICOM32FDPIC_SYM_LOCAL (info, h)))
++            {
++              if (osec)
++                addend += osec->output_section->vma;
++              if (IS_FDPIC (input_bfd)
++                  && (bfd_get_section_flags (output_bfd,
++                                             input_section->output_section)
++                      & (SEC_ALLOC | SEC_LOAD)) == (SEC_ALLOC | SEC_LOAD))
++                {
++                  if (ubicom32fdpic_osec_readonly_p (output_bfd,
++                                                     input_section
++                                                     ->output_section))
++                    {
++                      info->callbacks->warning
++                        (info,
++                         _("cannot emit fixups in read-only section"),
++                         name, input_bfd, input_section, rel->r_offset);
++                      return FALSE;
++                    }
++                  if (!h || h->root.type != bfd_link_hash_undefweak)
++                    {
++                      /* Only output a reloc for a not deleted entry.  */
++                      if (offset >= (bfd_vma)-2)
++                        ubicom32fdpic_add_rofixup (output_bfd,
++                                                   ubicom32fdpic_gotfixup_section
++                                                   (info), -1, picrel);
++                      else
++                        ubicom32fdpic_add_rofixup (output_bfd,
++                                                   ubicom32fdpic_gotfixup_section
++                                                   (info),
++                                                   offset + input_section
++                                                   ->output_section->vma
++                                                   + input_section->output_offset,
++                                                   picrel);
++
++                      if (r_type == R_UBICOM32_FUNCDESC_VALUE)
++                        {
++                          if (offset >= (bfd_vma)-2)
++                            ubicom32fdpic_add_rofixup
++                              (output_bfd,
++                               ubicom32fdpic_gotfixup_section (info),
++                               -1, picrel);
++                          else
++                            ubicom32fdpic_add_rofixup
++                              (output_bfd,
++                               ubicom32fdpic_gotfixup_section (info),
++                               offset + input_section->output_section->vma
++                               + input_section->output_offset + 4, picrel);
++                        }
++                    }
++                }
++            }
++          else
++            {
++              if ((bfd_get_section_flags (output_bfd,
++                                          input_section->output_section)
++                   & (SEC_ALLOC | SEC_LOAD)) == (SEC_ALLOC | SEC_LOAD))
++                {
++                  if (ubicom32fdpic_osec_readonly_p (output_bfd,
++                                                     input_section
++                                                     ->output_section))
++                    {
++                      info->callbacks->warning
++                        (info,
++                         _("cannot emit dynamic relocations in read-only section"),
++                         name, input_bfd, input_section, rel->r_offset);
++                      return FALSE;
++                    }
++                  /* Only output a reloc for a not deleted entry.  */
++                  if (offset >= (bfd_vma)-2)
++                    ubicom32fdpic_add_dyn_reloc (output_bfd,
++                                                 ubicom32fdpic_gotrel_section (info),
++                                                 0, R_UBICOM32_NONE, dynindx, addend, picrel);
++                  else
++                    ubicom32fdpic_add_dyn_reloc (output_bfd,
++                                                 ubicom32fdpic_gotrel_section (info),
++                                                 offset
++                                                 + input_section
++                                                 ->output_section->vma
++                                                 + input_section->output_offset,
++                                                 r_type, dynindx, addend, picrel);
++                }
++              else if (osec)
++                addend += osec->output_section->vma;
++              /* We want the addend in-place because dynamic
++                 relocations are REL.  Setting relocation to it
++                 should arrange for it to be installed.  */
++              relocation = addend - rel->r_addend;
++            }
++
++          if (r_type == R_UBICOM32_FUNCDESC_VALUE && offset < (bfd_vma)-2)
++            {
++              /* If we've omitted the dynamic relocation, just emit
++                 the fixed addresses of the symbol and of the local
++                 GOT base offset.  */
++              if (info->executable && !info->pie
++                  && (!h || UBICOM32FDPIC_SYM_LOCAL (info, h)))
++                bfd_put_32 (output_bfd,
++                            ubicom32fdpic_got_section (info)->output_section->vma
++                            + ubicom32fdpic_got_section (info)->output_offset
++                            + ubicom32fdpic_got_initial_offset (info),
++                            contents + rel->r_offset + 4);
++              else
++                /* A function descriptor used for lazy or local
++                   resolving is initialized such that its high word
++                   contains the output section index in which the
++                   PLT entries are located, and the low word
++                   contains the offset of the lazy PLT entry entry
++                   point into that section.  */
++                bfd_put_32 (output_bfd,
++                            h && ! UBICOM32FDPIC_SYM_LOCAL (info, h)
++                            ? 0
++                            : ubicom32fdpic_osec_to_segment (output_bfd,
++                                                             sec
++                                                             ->output_section),
++                            contents + rel->r_offset + 4);
++            }
++        }
++        check_segment[0] = check_segment[1] = got_segment;
++        break;
++
++      default:
++        check_segment[0] = isec_segment;
++        check_segment[1] = sec
++          ? ubicom32fdpic_osec_to_segment (output_bfd, sec->output_section)
++          : (unsigned)-1;
++        break;
++      }
++
++      if (check_segment[0] != check_segment[1] && IS_FDPIC (output_bfd))
++      {
++#if 1 /* If you take this out, remove the #error from fdpic-static-6.d
++       in the ld testsuite.  */
++        /* This helps catch problems in GCC while we can't do more
++           than static linking.  The idea is to test whether the
++           input file basename is crt0.o only once.  */
++        if (silence_segment_error == 1)
++          silence_segment_error =
++            (strlen (input_bfd->filename) == 6
++             && strcmp (input_bfd->filename, "crt0.o") == 0)
++            || (strlen (input_bfd->filename) > 6
++                && strcmp (input_bfd->filename
++                           + strlen (input_bfd->filename) - 7,
++                           "/crt0.o") == 0)
++            ? -1 : 0;
++#endif
++        if (!silence_segment_error
++            /* We don't want duplicate errors for undefined
++               symbols.  */
++            && !(picrel && picrel->symndx == -1
++                 && picrel->d.h->root.type == bfd_link_hash_undefined))
++          info->callbacks->warning
++            (info,
++             (info->shared || info->pie)
++             ? _("relocations between different segments are not supported")
++             : _("warning: relocation references a different segment"),
++             name, input_bfd, input_section, rel->r_offset);
++        if (!silence_segment_error && (info->shared || info->pie))
++          return FALSE;
++        elf_elfheader (output_bfd)->e_flags |= 0x80000000;
++      }
++
++      switch (r_type)
++      {
++      case R_UBICOM32_LO16:
++        r = ubicom32_elf_relocate_lo16 (input_bfd, rel, contents, relocation);
++        break;
++
++      case R_UBICOM32_HI16:
++        r = ubicom32_elf_relocate_hi16 (input_bfd, rel, contents, relocation);
++        break;
++
++      case R_UBICOM32_HI24:
++        r = ubicom32_elf_relocate_hi24 (input_bfd, rel, contents, relocation);
++        break;
++
++      case R_UBICOM32_LO7_S:
++        r = ubicom32_elf_relocate_lo7_s (input_bfd, rel, contents, relocation);
++        break;
++
++      case R_UBICOM32_LO7_2_S:
++        r = ubicom32_elf_relocate_lo7_2_s (input_bfd, rel, contents, relocation);
++        break;
++
++      case R_UBICOM32_LO7_4_S:
++        r = ubicom32_elf_relocate_lo7_4_s (input_bfd, rel, contents, relocation);
++        break;
++
++      case R_UBICOM32_LO7_D:
++        r = ubicom32_elf_relocate_lo7_d (input_bfd, rel, contents, relocation);
++        break;
++
++      case R_UBICOM32_LO7_2_D:
++        r = ubicom32_elf_relocate_lo7_2_d (input_bfd, rel, contents, relocation);
++        break;
++
++      case R_UBICOM32_LO7_4_D:
++        r = ubicom32_elf_relocate_lo7_4_d (input_bfd, rel, contents, relocation);
++        break;
++
++      case R_UBICOM32_24_PCREL:
++        r = ubicom32_elf_relocate_pcrel24 (input_bfd, input_section, rel, contents, relocation);
++        break;
++
++      case R_UBICOM32_LO7_CALLI:
++        r = ubicom32_elf_relocate_lo_calli (input_bfd, rel, contents, relocation, 7);
++        break;
++
++      case R_UBICOM32_LO16_CALLI:
++        r = ubicom32_elf_relocate_lo_calli (input_bfd, rel, contents, relocation, 18);
++        break;
++
++      case R_UBICOM32_GOTOFFSET_LO:
++        r = ubicom32_elf_relocate_gotoffset_lo(input_bfd, input_section, rel, contents, relocation);
++        break;
++
++      case R_UBICOM32_FUNCDESC_GOTOFFSET_LO:
++        r = ubicom32_elf_relocate_funcdesc_gotoffset_lo(input_bfd, input_section, rel, contents, relocation);
++        break;
++
++      case R_UBICOM32_32:
++      case R_UBICOM32_FUNCDESC:
++        /* relocation &= ~(0xff << 24); */
++        /* FALLTHROUGH */
++
++      default:
++        r = ubicom32_final_link_relocate (howto, input_bfd, input_section,
++                                          contents, rel, relocation);
++        break;
++      }
++    }
++
++  return TRUE;
++}
++\f
++#define elf_info_to_howto                     ubicom32_info_to_howto_rela
++#define elf_info_to_howto_rel                 NULL
++
++#define bfd_elf32_bfd_reloc_type_lookup               ubicom32_reloc_type_lookup
++#define bfd_elf32_bfd_reloc_name_lookup               ubicom32_reloc_name_lookup
++#define bfd_elf32_bfd_relax_section           ubicom32_elf_relax_section
++
++#define elf_backend_relocate_section          ubicom32_elf_relocate_section
++#define elf_backend_gc_mark_hook              ubicom32_elf_gc_mark_hook
++#define elf_backend_gc_sweep_hook             ubicom32_elf_gc_sweep_hook
++#define elf_backend_check_relocs                ubicom32_elf_check_relocs
++#define elf_backend_object_p                  ubicom32_elf_object_p
++
++#define elf_backend_discard_info              ubicom32_elf_discard_info
++
++#define elf_backend_can_gc_sections           1
++
++#define bfd_elf32_bfd_set_private_flags               ubicom32_elf_set_private_flags
++#define bfd_elf32_bfd_copy_private_bfd_data   ubicom32_elf_copy_private_bfd_data
++#define bfd_elf32_bfd_merge_private_bfd_data  ubicom32_elf_merge_private_bfd_data
++#define bfd_elf32_bfd_print_private_bfd_data  ubicom32_elf_print_private_bfd_data
++
++#define bfd_elf32_bfd_extcode_relax           NULL
++
++#define TARGET_BIG_SYM         bfd_elf32_ubicom32_vec
++#define TARGET_BIG_NAME  "elf32-ubicom32"
++
++#define ELF_ARCH       bfd_arch_ubicom32
++#define ELF_MACHINE_CODE EM_UBICOM32
++#define ELF_MAXPAGESIZE  0x1000
++
++#include "elf32-target.h"
++
++#undef TARGET_BIG_SYM
++#define TARGET_BIG_SYM         bfd_elf32_ubicom32fdpic_vec
++#undef TARGET_BIG_NAME
++#define TARGET_BIG_NAME  "elf32-ubicom32fdpic"
++#undef        elf32_bed
++#define       elf32_bed               elf32_ubicom32fdpic_bed
++
++#undef elf_backend_relocate_section
++#define elf_backend_relocate_section          ubicom32fdpic_elf_relocate_section
++
++#undef elf_backend_check_relocs
++#define elf_backend_check_relocs                ubicom32fdpic_elf_check_relocs
++
++#undef elf_backend_gc_sweep_hook
++#define elf_backend_gc_sweep_hook             ubicom32fdpic_elf_gc_sweep_hook
++#undef bfd_elf32_bfd_link_hash_table_create
++#define bfd_elf32_bfd_link_hash_table_create \
++              ubicom32fdpic_elf_link_hash_table_create
++#undef elf_backend_always_size_sections
++#define elf_backend_always_size_sections \
++              ubicom32fdpic_elf_always_size_sections
++#undef elf_backend_modify_program_headers
++#define elf_backend_modify_program_headers \
++              ubicom32fdpic_elf_modify_program_headers
++#undef bfd_elf32_bfd_copy_private_bfd_data
++#define bfd_elf32_bfd_copy_private_bfd_data \
++              ubicom32fdpic_elf_copy_private_bfd_data
++
++#undef elf_backend_create_dynamic_sections
++#define elf_backend_create_dynamic_sections \
++              ubicom32fdpic_elf_create_dynamic_sections
++#undef elf_backend_adjust_dynamic_symbol
++#define elf_backend_adjust_dynamic_symbol \
++              ubicom32fdpic_elf_adjust_dynamic_symbol
++#undef elf_backend_size_dynamic_sections
++#define elf_backend_size_dynamic_sections \
++              ubicom32fdpic_elf_size_dynamic_sections
++#undef elf_backend_finish_dynamic_symbol
++#define elf_backend_finish_dynamic_symbol \
++              ubicom32fdpic_elf_finish_dynamic_symbol
++#undef elf_backend_finish_dynamic_sections
++#define elf_backend_finish_dynamic_sections \
++              ubicom32fdpic_elf_finish_dynamic_sections
++
++#undef elf_backend_can_make_relative_eh_frame
++#define elf_backend_can_make_relative_eh_frame \
++              ubicom32fdpic_elf_use_relative_eh_frame
++#undef elf_backend_can_make_lsda_relative_eh_frame
++#define elf_backend_can_make_lsda_relative_eh_frame \
++              ubicom32fdpic_elf_use_relative_eh_frame
++#undef elf_backend_encode_eh_address
++#define elf_backend_encode_eh_address \
++              ubicom32fdpic_elf_encode_eh_address
++
++#undef elf_backend_may_use_rel_p
++#define elf_backend_may_use_rel_p       1
++#undef elf_backend_may_use_rela_p
++#define elf_backend_may_use_rela_p      1
++/* We use REL for dynamic relocations only.  */
++#undef elf_backend_default_use_rela_p
++#define elf_backend_default_use_rela_p  1
++
++#undef elf_backend_omit_section_dynsym
++#define elf_backend_omit_section_dynsym ubicom32fdpic_elf_link_omit_section_dynsym
++
++#undef elf_backend_can_refcount
++#define elf_backend_can_refcount 1
++
++#undef elf_backend_want_got_plt
++#define elf_backend_want_got_plt 0
++
++#undef elf_backend_plt_readonly
++#define elf_backend_plt_readonly 1
++
++#undef elf_backend_want_plt_sym
++#define elf_backend_want_plt_sym 1
++
++#undef elf_backend_got_header_size
++#define elf_backend_got_header_size     12
++
++#undef elf_backend_rela_normal
++#define elf_backend_rela_normal         1
++
++#include "elf32-target.h"
+--- a/bfd/libbfd.h
++++ b/bfd/libbfd.h
+@@ -1689,6 +1689,39 @@ static const char *const bfd_reloc_code_
+   "BFD_RELOC_IP2K_FR_OFFSET",
+   "BFD_RELOC_VPE4KMATH_DATA",
+   "BFD_RELOC_VPE4KMATH_INSN",
++  "BFD_RELOC_UBICOM32_21_PCREL",
++  "BFD_RELOC_UBICOM32_24_PCREL",
++  "BFD_RELOC_UBICOM32_HI24",
++  "BFD_RELOC_UBICOM32_LO7_S",
++  "BFD_RELOC_UBICOM32_LO7_2_S",
++  "BFD_RELOC_UBICOM32_LO7_4_S",
++  "BFD_RELOC_UBICOM32_LO7_D",
++  "BFD_RELOC_UBICOM32_LO7_2_D",
++  "BFD_RELOC_UBICOM32_LO7_4_D",
++  "BFD_RELOC_UBICOM32_LO7_CALLI",
++  "BFD_RELOC_UBICOM32_LO16_CALLI",
++  "BFD_RELOC_UBICOM32_GOT_HI24",
++  "BFD_RELOC_UBICOM32_GOT_LO7_S",
++  "BFD_RELOC_UBICOM32_GOT_LO7_2_S",
++  "BFD_RELOC_UBICOM32_GOT_LO7_4_S",
++  "BFD_RELOC_UBICOM32_GOT_LO7_D",
++  "BFD_RELOC_UBICOM32_GOT_LO7_2_D",
++  "BFD_RELOC_UBICOM32_GOT_LO7_4_D",
++  "BFD_RELOC_UBICOM32_FUNCDESC_GOT_HI24",
++  "BFD_RELOC_UBICOM32_FUNCDESC_GOT_LO7_S",
++  "BFD_RELOC_UBICOM32_FUNCDESC_GOT_LO7_2_S",
++  "BFD_RELOC_UBICOM32_FUNCDESC_GOT_LO7_4_S",
++  "BFD_RELOC_UBICOM32_FUNCDESC_GOT_LO7_D",
++  "BFD_RELOC_UBICOM32_FUNCDESC_GOT_LO7_2_D",
++  "BFD_RELOC_UBICOM32_FUNCDESC_GOT_LO7_4_D",
++  "BFD_RELOC_UBICOM32_GOT_LO7_CALLI",
++  "BFD_RELOC_UBICOM32_FUNCDESC_GOT_LO7_CALLI",
++  "BFD_RELOC_UBICOM32_FUNCDESC_VALUE",
++  "BFD_RELOC_UBICOM32_FUNCDESC",
++  "BFD_RELOC_UBICOM32_GOTOFFSET_LO",
++  "BFD_RELOC_UBICOM32_GOTOFFSET_HI",
++  "BFD_RELOC_UBICOM32_FUNCDESC_GOTOFFSET_LO",
++  "BFD_RELOC_UBICOM32_FUNCDESC_GOTOFFSET_HI",
+   "BFD_RELOC_VTABLE_INHERIT",
+   "BFD_RELOC_VTABLE_ENTRY",
+   "BFD_RELOC_IA64_IMM14",
+--- a/bfd/Makefile.am
++++ b/bfd/Makefile.am
+@@ -114,6 +114,7 @@ ALL_MACHINES = \
+       cpu-tic4x.lo \
+       cpu-tic54x.lo \
+       cpu-tic80.lo \
++      cpu-ubicom32.lo \
+       cpu-v850.lo \
+       cpu-vax.lo \
+       cpu-we32k.lo \
+@@ -180,6 +181,7 @@ ALL_MACHINES_CFILES = \
+       cpu-tic4x.c \
+       cpu-tic54x.c \
+       cpu-tic80.c \
++      cpu-ubicom32.c \
+       cpu-v850.c \
+       cpu-vax.c \
+       cpu-we32k.c \
+@@ -292,6 +294,7 @@ BFD32_BACKENDS = \
+       elfxx-sparc.lo \
+       elf32-sparc.lo \
+       elf32-spu.lo \
++      elf32-ubicom32.lo \
+       elf32-v850.lo \
+       elf32-vax.lo \
+       elf32-xstormy16.lo \
+@@ -473,6 +476,7 @@ BFD32_BACKENDS_CFILES = \
+       elfxx-sparc.c \
+       elf32-sparc.c \
+       elf32-spu.c \
++      elf32-ubicom32.c \
+       elf32-v850.c \
+       elf32-vax.c \
+       elf32-xstormy16.c \
+@@ -1131,6 +1135,7 @@ cpu-tic30.lo: cpu-tic30.c $(INCDIR)/file
+ cpu-tic4x.lo: cpu-tic4x.c $(INCDIR)/filenames.h $(INCDIR)/hashtab.h
+ cpu-tic54x.lo: cpu-tic54x.c $(INCDIR)/filenames.h $(INCDIR)/hashtab.h
+ cpu-tic80.lo: cpu-tic80.c $(INCDIR)/filenames.h $(INCDIR)/hashtab.h
++cpu-ubicom32.lo: cpu-ubicom32.c $(INCDIR)/filenames.h
+ cpu-v850.lo: cpu-v850.c $(INCDIR)/filenames.h $(INCDIR)/hashtab.h \
+   $(INCDIR)/safe-ctype.h
+ cpu-vax.lo: cpu-vax.c $(INCDIR)/filenames.h $(INCDIR)/hashtab.h
+@@ -1556,6 +1561,10 @@ elf32-spu.lo: elf32-spu.c $(INCDIR)/file
+   $(INCDIR)/bfdlink.h $(INCDIR)/hashtab.h elf-bfd.h $(INCDIR)/elf/common.h \
+   $(INCDIR)/elf/external.h $(INCDIR)/elf/internal.h $(INCDIR)/elf/spu.h \
+   $(INCDIR)/elf/reloc-macros.h elf32-spu.h elf32-target.h
++elf32-ubicom32.lo: elf32-ubicom32.c $(INCDIR)/filenames.h elf-bfd.h \
++  $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h $(INCDIR)/elf/external.h \
++  $(INCDIR)/bfdlink.h $(INCDIR)/elf/ubicom32.h $(INCDIR)/elf/reloc-macros.h \
++  elf32-target.h
+ elf32-v850.lo: elf32-v850.c $(INCDIR)/filenames.h $(INCDIR)/bfdlink.h \
+   $(INCDIR)/hashtab.h elf-bfd.h $(INCDIR)/elf/common.h \
+   $(INCDIR)/elf/external.h $(INCDIR)/elf/internal.h $(INCDIR)/elf/v850.h \
+--- a/bfd/Makefile.in
++++ b/bfd/Makefile.in
+@@ -367,6 +367,7 @@ ALL_MACHINES = \
+       cpu-tic4x.lo \
+       cpu-tic54x.lo \
+       cpu-tic80.lo \
++      cpu-ubicom32.lo \
+       cpu-v850.lo \
+       cpu-vax.lo \
+       cpu-we32k.lo \
+@@ -433,6 +434,7 @@ ALL_MACHINES_CFILES = \
+       cpu-tic4x.c \
+       cpu-tic54x.c \
+       cpu-tic80.c \
++      cpu-ubicom32.c \
+       cpu-v850.c \
+       cpu-vax.c \
+       cpu-we32k.c \
+@@ -546,6 +548,7 @@ BFD32_BACKENDS = \
+       elfxx-sparc.lo \
+       elf32-sparc.lo \
+       elf32-spu.lo \
++      elf32-ubicom32.lo \
+       elf32-v850.lo \
+       elf32-vax.lo \
+       elf32-xstormy16.lo \
+@@ -727,6 +730,7 @@ BFD32_BACKENDS_CFILES = \
+       elfxx-sparc.c \
+       elf32-sparc.c \
+       elf32-spu.c \
++      elf32-ubicom32.c \
+       elf32-v850.c \
+       elf32-vax.c \
+       elf32-xstormy16.c \
+@@ -1715,6 +1719,7 @@ cpu-tic30.lo: cpu-tic30.c $(INCDIR)/file
+ cpu-tic4x.lo: cpu-tic4x.c $(INCDIR)/filenames.h $(INCDIR)/hashtab.h
+ cpu-tic54x.lo: cpu-tic54x.c $(INCDIR)/filenames.h $(INCDIR)/hashtab.h
+ cpu-tic80.lo: cpu-tic80.c $(INCDIR)/filenames.h $(INCDIR)/hashtab.h
++cpu-ubicom32.lo: cpu-ubicom32.c $(INCDIR)/filenames.h
+ cpu-v850.lo: cpu-v850.c $(INCDIR)/filenames.h $(INCDIR)/hashtab.h \
+   $(INCDIR)/safe-ctype.h
+ cpu-vax.lo: cpu-vax.c $(INCDIR)/filenames.h $(INCDIR)/hashtab.h
+@@ -2140,6 +2145,10 @@ elf32-spu.lo: elf32-spu.c $(INCDIR)/file
+   $(INCDIR)/bfdlink.h $(INCDIR)/hashtab.h elf-bfd.h $(INCDIR)/elf/common.h \
+   $(INCDIR)/elf/external.h $(INCDIR)/elf/internal.h $(INCDIR)/elf/spu.h \
+   $(INCDIR)/elf/reloc-macros.h elf32-spu.h elf32-target.h
++elf32-ubicom32.lo: elf32-ubicom32.c $(INCDIR)/filenames.h elf-bfd.h \
++  $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h $(INCDIR)/elf/external.h \
++  $(INCDIR)/bfdlink.h $(INCDIR)/elf/ubicom32.h $(INCDIR)/elf/reloc-macros.h \
++  elf32-target.h
+ elf32-v850.lo: elf32-v850.c $(INCDIR)/filenames.h $(INCDIR)/bfdlink.h \
+   $(INCDIR)/hashtab.h elf-bfd.h $(INCDIR)/elf/common.h \
+   $(INCDIR)/elf/external.h $(INCDIR)/elf/internal.h $(INCDIR)/elf/v850.h \
+--- a/bfd/reloc.c
++++ b/bfd/reloc.c
+@@ -4227,6 +4227,75 @@ ENUMDOC
+   Scenix VPE4K coprocessor - data/insn-space addressing
+ ENUM
++  BFD_RELOC_UBICOM32_21_PCREL
++ENUMX
++  BFD_RELOC_UBICOM32_24_PCREL
++ENUMX
++  BFD_RELOC_UBICOM32_HI24
++ENUMX
++  BFD_RELOC_UBICOM32_LO7_S
++ENUMX
++  BFD_RELOC_UBICOM32_LO7_2_S
++ENUMX
++  BFD_RELOC_UBICOM32_LO7_4_S
++ENUMX
++  BFD_RELOC_UBICOM32_LO7_D
++ENUMX
++  BFD_RELOC_UBICOM32_LO7_2_D
++ENUMX
++  BFD_RELOC_UBICOM32_LO7_4_D
++ENUMX
++  BFD_RELOC_UBICOM32_LO7_CALLI
++ENUMX
++  BFD_RELOC_UBICOM32_LO16_CALLI
++ENUMX
++  BFD_RELOC_UBICOM32_GOT_HI24
++ENUMX
++  BFD_RELOC_UBICOM32_GOT_LO7_S
++ENUMX
++  BFD_RELOC_UBICOM32_GOT_LO7_2_S
++ENUMX
++  BFD_RELOC_UBICOM32_GOT_LO7_4_S
++ENUMX
++  BFD_RELOC_UBICOM32_GOT_LO7_D
++ENUMX
++  BFD_RELOC_UBICOM32_GOT_LO7_2_D
++ENUMX
++  BFD_RELOC_UBICOM32_GOT_LO7_4_D
++ENUMX
++  BFD_RELOC_UBICOM32_FUNCDESC_GOT_HI24
++ENUMX
++  BFD_RELOC_UBICOM32_FUNCDESC_GOT_LO7_S
++ENUMX
++  BFD_RELOC_UBICOM32_FUNCDESC_GOT_LO7_2_S
++ENUMX
++  BFD_RELOC_UBICOM32_FUNCDESC_GOT_LO7_4_S
++ENUMX
++  BFD_RELOC_UBICOM32_FUNCDESC_GOT_LO7_D
++ENUMX
++  BFD_RELOC_UBICOM32_FUNCDESC_GOT_LO7_2_D
++ENUMX
++  BFD_RELOC_UBICOM32_FUNCDESC_GOT_LO7_4_D
++ENUMX
++  BFD_RELOC_UBICOM32_GOT_LO7_CALLI
++ENUMX
++  BFD_RELOC_UBICOM32_FUNCDESC_GOT_LO7_CALLI
++ENUMX
++  BFD_RELOC_UBICOM32_FUNCDESC_VALUE
++ENUMX
++  BFD_RELOC_UBICOM32_FUNCDESC
++ENUMX
++  BFD_RELOC_UBICOM32_GOTOFFSET_LO
++ENUMX
++  BFD_RELOC_UBICOM32_GOTOFFSET_HI
++ENUMX
++  BFD_RELOC_UBICOM32_FUNCDESC_GOTOFFSET_LO
++ENUMX
++  BFD_RELOC_UBICOM32_FUNCDESC_GOTOFFSET_HI
++ENUMDOC
++  Ubicom UBICOM32 Relocations.
++
++ENUM
+   BFD_RELOC_VTABLE_INHERIT
+ ENUMX
+   BFD_RELOC_VTABLE_ENTRY
+--- a/bfd/targets.c
++++ b/bfd/targets.c
+@@ -663,6 +663,8 @@ extern const bfd_target bfd_elf32_spu_ve
+ extern const bfd_target bfd_elf32_tradbigmips_vec;
+ extern const bfd_target bfd_elf32_tradlittlemips_vec;
+ extern const bfd_target bfd_elf32_us_cris_vec;
++extern const bfd_target bfd_elf32_ubicom32_vec;
++extern const bfd_target bfd_elf32_ubicom32fdpic_vec;
+ extern const bfd_target bfd_elf32_v850_vec;
+ extern const bfd_target bfd_elf32_vax_vec;
+ extern const bfd_target bfd_elf32_xc16x_vec;
+@@ -1001,6 +1003,7 @@ static const bfd_target * const _bfd_tar
+       &bfd_elf32_tradbigmips_vec,
+       &bfd_elf32_tradlittlemips_vec,
+       &bfd_elf32_us_cris_vec,
++      &bfd_elf32_ubicom32_vec,
+       &bfd_elf32_v850_vec,
+       &bfd_elf32_vax_vec,
+       &bfd_elf32_xc16x_vec,
+--- a/binutils/Makefile.am
++++ b/binutils/Makefile.am
+@@ -584,7 +584,7 @@ readelf.o: readelf.c config.h sysdep.h $
+   $(INCDIR)/elf/dlx.h $(INCDIR)/elf/fr30.h $(INCDIR)/elf/frv.h \
+   $(INCDIR)/elf/hppa.h $(INCDIR)/elf/i386.h $(INCDIR)/elf/i370.h \
+   $(INCDIR)/elf/i860.h $(INCDIR)/elf/i960.h $(INCDIR)/elf/ia64.h \
+-  $(INCDIR)/elf/ip2k.h $(INCDIR)/elf/iq2000.h $(INCDIR)/elf/m32c.h \
++  $(INCDIR)/elf/ip2k.h $(INCDIR)/elf/ubicom32.h $(INCDIR)/elf/iq2000.h $(INCDIR)/elf/m32c.h \
+   $(INCDIR)/elf/m32r.h $(INCDIR)/elf/m68k.h $(INCDIR)/elf/m68hc11.h \
+   $(INCDIR)/elf/mcore.h $(INCDIR)/elf/mep.h $(INCDIR)/elf/mips.h \
+   $(INCDIR)/elf/mmix.h $(INCDIR)/elf/mn10200.h $(INCDIR)/elf/mn10300.h \
+--- a/binutils/Makefile.in
++++ b/binutils/Makefile.in
+@@ -1338,7 +1338,7 @@ readelf.o: readelf.c config.h sysdep.h $
+   $(INCDIR)/elf/dlx.h $(INCDIR)/elf/fr30.h $(INCDIR)/elf/frv.h \
+   $(INCDIR)/elf/hppa.h $(INCDIR)/elf/i386.h $(INCDIR)/elf/i370.h \
+   $(INCDIR)/elf/i860.h $(INCDIR)/elf/i960.h $(INCDIR)/elf/ia64.h \
+-  $(INCDIR)/elf/ip2k.h $(INCDIR)/elf/iq2000.h $(INCDIR)/elf/m32c.h \
++  $(INCDIR)/elf/ip2k.h $(INCDIR)/elf/ubicom32.h $(INCDIR)/elf/iq2000.h $(INCDIR)/elf/m32c.h \
+   $(INCDIR)/elf/m32r.h $(INCDIR)/elf/m68k.h $(INCDIR)/elf/m68hc11.h \
+   $(INCDIR)/elf/mcore.h $(INCDIR)/elf/mep.h $(INCDIR)/elf/mips.h \
+   $(INCDIR)/elf/mmix.h $(INCDIR)/elf/mn10200.h $(INCDIR)/elf/mn10300.h \
+--- a/binutils/readelf.c
++++ b/binutils/readelf.c
+@@ -152,6 +152,7 @@
+ #include "elf/sh.h"
+ #include "elf/sparc.h"
+ #include "elf/spu.h"
++#include "elf/ubicom32.h"
+ #include "elf/v850.h"
+ #include "elf/vax.h"
+ #include "elf/x86-64.h"
+@@ -612,6 +613,7 @@ guess_is_rela (unsigned int e_machine)
+     case EM_SPARC32PLUS:
+     case EM_SPARCV9:
+     case EM_SPU:
++    case EM_UBICOM32:
+     case EM_V850:
+     case EM_CYGNUS_V850:
+     case EM_VAX:
+@@ -1159,6 +1161,10 @@ dump_relocations (FILE *file,
+         rtype = elf_crx_reloc_type (type);
+         break;
++      case EM_UBICOM32:
++        rtype = elf_ubicom32_reloc_type (type);
++        break;
++
+       case EM_VAX:
+         rtype = elf_vax_reloc_type (type);
+         break;
+@@ -1812,6 +1818,7 @@ get_machine_name (unsigned e_machine)
+     case EM_DLX:              return "OpenDLX";
+     case EM_IP2K_OLD:
+     case EM_IP2K:             return "Ubicom IP2xxx 8-bit microcontrollers";
++    case EM_UBICOM32:         return "Ubicom32 32-bit microcontrollers";
+     case EM_IQ2000:           return "Vitesse IQ2000";
+     case EM_XTENSA_OLD:
+     case EM_XTENSA:           return "Tensilica Xtensa Processor";
+--- a/config.sub
++++ b/config.sub
+@@ -283,6 +283,7 @@ case $basic_machine in
+       | sparcv8 | sparcv9 | sparcv9b | sparcv9v \
+       | spu | strongarm \
+       | tahoe | thumb | tic4x | tic80 | tron \
++      | ubicom32 \
+       | v850 | v850e \
+       | ubicom32 \
+       | we32k \
+@@ -367,6 +368,7 @@ case $basic_machine in
+       | tahoe-* | thumb-* \
+       | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \
+       | tron-* \
++      | ubicom32-* \
+       | v850-* | v850e-* | vax-* \
+       | ubicom32-* \
+       | we32k-* \
+--- a/configure
++++ b/configure
+@@ -2666,6 +2666,12 @@ case "${target}" in
+   xtensa*-*-*)
+     noconfigdirs="$noconfigdirs ${libgcj}"
+     ;;
++  ubicom32-*-*linux*)
++    noconfigdirs="$noconfigdirs target-libffi target-newlib"
++    ;;
++  ubicom32-*-*)
++    noconfigdirs="$noconfigdirs target-libffi target-newlib"
++    ;;
+   ip2k-*-*)
+     noconfigdirs="$noconfigdirs target-libiberty target-libstdc++-v3 ${libgcj}"
+     ;;
+--- a/configure.ac
++++ b/configure.ac
+@@ -915,6 +915,12 @@ case "${target}" in
+   xtensa*-*-*)
+     noconfigdirs="$noconfigdirs ${libgcj}"
+     ;;
++  ubicom32-*-*linux*)
++    noconfigdirs="$noconfigdirs target-libffi target-newlib"
++    ;;
++  ubicom32-*-*)
++    noconfigdirs="$noconfigdirs target-libffi"
++    ;;
+   ip2k-*-*)
+     noconfigdirs="$noconfigdirs target-libiberty target-libstdc++-v3 ${libgcj}"
+     ;;
+--- /dev/null
++++ b/gas/config/tc-ubicom32.c
+@@ -0,0 +1,609 @@
++/* tc-ubicom32.c -- Assembler for the Ubicom32
++   Copyright (C) 2000, 2002 Free Software Foundation.
++
++   This file is part of GAS, the GNU Assembler.
++
++   GAS 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, or (at your option)
++   any later version.
++
++   GAS 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 GAS; see the file COPYING.  If not, write to
++   the Free Software Foundation, 59 Temple Place - Suite 330,
++   Boston, MA 02111-1307, USA.  */
++
++#include <stdio.h>
++#include <ctype.h>
++
++#include "as.h"
++#include "dwarf2dbg.h"
++#include "subsegs.h"
++#include "symcat.h"
++#include "opcodes/ubicom32-desc.h"
++#include "opcodes/ubicom32-opc.h"
++#include "cgen.h"
++#include "elf/common.h"
++#include "elf/ubicom32.h"
++#include "libbfd.h"
++
++extern void gas_cgen_md_operand (expressionS *);
++
++/* Structure to hold all of the different components describing
++   an individual instruction.  */
++typedef struct
++{
++  const CGEN_INSN *   insn;
++  const CGEN_INSN *   orig_insn;
++  CGEN_FIELDS         fields;
++#if CGEN_INT_INSN_P
++  CGEN_INSN_INT         buffer [1];
++#define INSN_VALUE(buf) (*(buf))
++#else
++  unsigned char         buffer [CGEN_MAX_INSN_SIZE];
++#define INSN_VALUE(buf) (buf)
++#endif
++  char *              addr;
++  fragS *             frag;
++  int                   num_fixups;
++  fixS *                fixups [GAS_CGEN_MAX_FIXUPS];
++  int                   indices [MAX_OPERAND_INSTANCES];
++}
++ubicom32_insn;
++
++const char comment_chars[]        = ";";
++const char line_comment_chars[]   = "#";
++const char line_separator_chars[] = "";
++const char EXP_CHARS[]            = "eE";
++const char FLT_CHARS[]            = "dD";
++
++/* Ubicom32 specific function to handle FD-PIC pointer initializations.  */
++
++static void
++ubicom32_pic_ptr (int nbytes)
++{
++  expressionS exp;
++  char *p;
++
++  if (nbytes != 4)
++    abort ();
++
++#ifdef md_flush_pending_output
++  md_flush_pending_output ();
++#endif
++
++  if (is_it_end_of_statement ())
++    {
++      demand_empty_rest_of_line ();
++      return;
++    }
++
++#ifdef md_cons_align
++  md_cons_align (nbytes);
++#endif
++
++  do
++    {
++      bfd_reloc_code_real_type reloc_type = BFD_RELOC_UBICOM32_FUNCDESC;
++
++      if (strncasecmp (input_line_pointer, "%funcdesc(", strlen("%funcdesc(")) == 0)
++      {
++        input_line_pointer += strlen("%funcdesc(");
++        expression (&exp);
++        if (*input_line_pointer == ')')
++          input_line_pointer++;
++        else
++          as_bad (_("missing ')'"));
++      }
++      else
++      as_bad ("missing funcdesc in picptr");
++
++      p = frag_more (4);
++      memset (p, 0, 4);
++      fix_new_exp (frag_now, p - frag_now->fr_literal, 4, &exp, 0,
++                 reloc_type);
++    }
++  while (*input_line_pointer++ == ',');
++
++  input_line_pointer--;                       /* Put terminator back into stream. */
++  demand_empty_rest_of_line ();
++}
++
++/* The target specific pseudo-ops which we support.  */
++const pseudo_typeS md_pseudo_table[] =
++{
++    { "file", (void (*)(int))dwarf2_directive_file,   0 },
++    { "loc",  dwarf2_directive_loc,   0 },
++    { "picptr", ubicom32_pic_ptr,     4 },
++    { "word", cons,                   4 },
++    { NULL,   NULL,                   0 }
++};
++
++/* A table of the register symbols */
++#if 0
++static symbolS *ubicom32_register_table[40];  /* 32 data & 8 address */
++#endif
++
++\f
++#define OPTION_CPU_IP3035    (OPTION_MD_BASE)
++#define OPTION_CPU_UBICOM32DSP   (OPTION_MD_BASE+1)
++#define OPTION_CPU_UBICOM32VER4  (OPTION_MD_BASE+2)
++#define OPTION_CPU_UBICOM32VER3FDPIC  (OPTION_MD_BASE+3)
++#define OPTION_CPU_UBICOM32VER4FDPIC  (OPTION_MD_BASE+4)
++#define OPTION_CPU_UBICOM32_FDPIC  (OPTION_MD_BASE+5)
++
++struct option md_longopts[] =
++{
++  { "mubicom32v1",    no_argument, NULL, OPTION_CPU_IP3035 },
++  { "mubicom32v2",    no_argument, NULL, OPTION_CPU_UBICOM32DSP },
++  { "mubicom32v3",    no_argument, NULL, OPTION_CPU_UBICOM32DSP },
++  { "mubicom32v4",    no_argument, NULL, OPTION_CPU_UBICOM32VER4 },
++  { "mubicom32v3fdpic", no_argument, NULL, OPTION_CPU_UBICOM32VER3FDPIC },
++  { "mubicom32v4fdpic",       no_argument, NULL, OPTION_CPU_UBICOM32VER4FDPIC },
++  { "mfdpic", no_argument, NULL, OPTION_CPU_UBICOM32_FDPIC },
++  { NULL,     no_argument, NULL, 0 },
++};
++size_t md_longopts_size = sizeof (md_longopts);
++
++const char * md_shortopts = "";
++
++/* Mach selected from command line.  */
++int ubicom32_mach = 0;
++unsigned ubicom32_mach_bitmask = 0;
++
++int
++md_parse_option (c, arg)
++    int c ATTRIBUTE_UNUSED;
++    char * arg ATTRIBUTE_UNUSED;
++{
++  int pic_state = ubicom32_mach & 0xffff0000;
++  switch (c)
++    {
++    case OPTION_CPU_IP3035:
++      ubicom32_mach = bfd_mach_ubicom32;
++      ubicom32_mach_bitmask = 1 << MACH_IP3035;
++      break;
++
++    case OPTION_CPU_UBICOM32DSP:
++      ubicom32_mach = bfd_mach_ubicom32dsp;
++      ubicom32_mach_bitmask = (1 << MACH_UBICOM32DSP)| (1 << MACH_IP3023COMPATIBILITY);
++      break;
++
++    case OPTION_CPU_UBICOM32VER4:
++      ubicom32_mach = bfd_mach_ubicom32ver4;
++      ubicom32_mach_bitmask = (1 << MACH_UBICOM32DSP)| (1 << MACH_IP3023COMPATIBILITY) | (1 << MACH_UBICOM32_VER4);
++      break;
++
++    case OPTION_CPU_UBICOM32VER3FDPIC:
++      ubicom32_mach = bfd_mach_ubicom32dsp | EF_UBICOM32_FDPIC;
++      ubicom32_mach_bitmask = (1 << MACH_UBICOM32DSP)| (1 << MACH_IP3023COMPATIBILITY);
++      break;
++
++    case OPTION_CPU_UBICOM32VER4FDPIC:
++      ubicom32_mach = bfd_mach_ubicom32ver4 | EF_UBICOM32_FDPIC;
++      ubicom32_mach_bitmask = (1 << MACH_UBICOM32DSP)| (1 << MACH_IP3023COMPATIBILITY) | (1 << MACH_UBICOM32_VER4);
++      break;
++
++    case OPTION_CPU_UBICOM32_FDPIC:
++      ubicom32_mach |= EF_UBICOM32_FDPIC;
++      break;
++
++    default:
++      return 0;
++    }
++  ubicom32_mach |= pic_state;
++
++  return 1;
++}
++
++
++void
++md_show_usage (stream)
++    FILE * stream;
++{
++  fprintf (stream, _("UBICOM32 specific command line options:\n"));
++  fprintf (stream, _("  -mubicom32v1               restrict to IP3023 insns \n"));
++  fprintf (stream, _("  -mubicom32v3               permit DSP extended insn\n"));
++  fprintf (stream, _("  -mubicom32v4               permit DSP extended insn and additional .1 instructions.\n"));
++  fprintf (stream, _("  -mfdpic                    This in addition to the v3 or v4 flags will produce a FDPIC .o.\n"));
++
++}
++
++\f
++void
++md_begin ()
++{
++  /* Initialize the `cgen' interface.  */
++  if(ubicom32_mach_bitmask == 0) {
++        /* md_parse_option has not been called */
++        ubicom32_mach_bitmask = 1<<MACH_IP3035;
++        ubicom32_mach = bfd_mach_ubicom32;
++  }
++
++  /* Record the specific machine in the elf header flags area */
++  bfd_set_private_flags (stdoutput, ubicom32_mach);
++
++
++  /* Set the machine number and endian.  */
++  gas_cgen_cpu_desc = ubicom32_cgen_cpu_open (CGEN_CPU_OPEN_MACHS,
++                                        ubicom32_mach_bitmask,
++                                        CGEN_CPU_OPEN_ENDIAN,
++                                        CGEN_ENDIAN_BIG,
++                                        CGEN_CPU_OPEN_END);
++  ubicom32_cgen_init_asm (gas_cgen_cpu_desc);
++
++#if 0
++  /* Construct symbols for each of the registers */
++
++  for (i = 0; i < 32; ++i)
++    {
++      char name[4];
++      sprintf(name, "d%d", i);
++      ubicom32_register_table[i] = symbol_create(name, reg_section, i,
++                                            &zero_address_frag);
++    }
++  for (; i < 40; ++i)
++    {
++      char name[4];
++      sprintf(name, "a%d", i-32);
++      ubicom32_register_table[i] = symbol_create(name, reg_section, i,
++                                            &zero_address_frag);
++    }
++#endif
++
++  /* This is a callback from cgen to gas to parse operands.  */
++  cgen_set_parse_operand_fn (gas_cgen_cpu_desc, gas_cgen_parse_operand);
++
++  /* Set the machine type */
++  bfd_default_set_arch_mach (stdoutput, bfd_arch_ubicom32, ubicom32_mach & 0xffff);
++
++  /* Cuz our bit fields are shifted from their values */
++  flag_signed_overflow_ok = 1;
++}
++
++void
++md_assemble (str)
++     char * str;
++{
++  ubicom32_insn insn;
++  char * errmsg;
++
++  /* Initialize GAS's cgen interface for a new instruction.  */
++  gas_cgen_init_parse ();
++  gas_cgen_cpu_desc->signed_overflow_ok_p=1;
++
++  /* need a way to detect when we have multiple increments to same An register */
++  insn.fields.f_s1_i4_1 = 0;
++  insn.fields.f_s1_i4_2 = 0;
++  insn.fields.f_s1_i4_4 = 0;
++  insn.fields.f_d_i4_1 = 0;
++  insn.fields.f_d_i4_2 = 0;
++  insn.fields.f_d_i4_4 = 0;
++  insn.fields.f_s1_direct = 0;
++  insn.fields.f_d_direct = 0;
++
++  memset(&insn.fields, 0, sizeof(insn.fields));
++  insn.insn = ubicom32_cgen_assemble_insn
++      (gas_cgen_cpu_desc, str, & insn.fields, insn.buffer, & errmsg);
++
++  if (!insn.insn)
++    {
++      as_bad ("%s", errmsg);
++      return;
++    }
++
++  if (insn.fields.f_s1_An == insn.fields.f_d_An)
++    {
++      if ((insn.fields.f_s1_i4_1 != 0 && insn.fields.f_d_i4_1 != 0) ||
++        (insn.fields.f_s1_i4_2 != 0 && insn.fields.f_d_i4_2 != 0) ||
++        (insn.fields.f_s1_i4_4 != 0 && insn.fields.f_d_i4_4 != 0))
++      {
++        /* user has tried to increment the same An register in both the s1
++           and d operands which is illegal */
++        static char errbuf[255];
++        char *first_part;
++        first_part = _("s1 and d operands update same An register");
++        if (strlen (str) > 50)
++          sprintf (errbuf, "%s `%.50s...'", first_part, str);
++        else
++          sprintf (errbuf, "%s `%.50s'", first_part, str);
++
++        as_bad ("%s", errbuf);
++        return;
++      }
++    }
++
++  if(insn.fields.f_d_direct &&
++     insn.fields.f_d_An == 0 &&
++     insn.fields.f_d_imm7_4 == 0 &&
++     insn.fields.f_d_imm7_2 == 0 &&
++     insn.fields.f_d_imm7_1 == 0 &&
++     insn.fields.f_d_i4_1 == 0 &&
++     insn.fields.f_d_i4_2 == 0 &&
++     insn.fields.f_d_i4_4 == 0)
++    {
++      if (insn.fields.f_d_direct >= A0_ADDRESS &&
++        insn.fields.f_d_direct <= A7_ADDRESS)
++      {
++        long d_direct = (insn.fields.f_d_direct - A0_ADDRESS) >> 2;
++        if (d_direct == insn.fields.f_s1_An &&
++            (insn.fields.f_s1_i4_1 != 0 ||
++             insn.fields.f_s1_i4_2 != 0 ||
++             insn.fields.f_s1_i4_4 != 0))
++          {
++            /* user has tried to increment an An register that is also the destination register */
++            static char errbuf[255];
++            char *first_part;
++            first_part = _("s1 and d operands update same An register");
++            if (strlen (str) > 50)
++              sprintf (errbuf, "%s `%.50s...'", first_part, str);
++            else
++              sprintf (errbuf, "%s `%.50s'", first_part, str);
++
++            as_bad ("%s", errbuf);
++            return;
++          }
++      }
++    }
++
++  /* Doesn't really matter what we pass for RELAX_P here.  */
++  gas_cgen_finish_insn (insn.insn, insn.buffer,
++                      CGEN_FIELDS_BITSIZE (& insn.fields), 1, NULL);
++
++}
++
++/* The syntax in the manual says constants begin with '#'.
++   We just ignore it.  */
++
++void
++md_operand (expressionP)
++     expressionS * expressionP;
++{
++  /* In case of a syntax error, escape back to try next syntax combo. */
++  if (expressionP->X_op == O_absent)
++    gas_cgen_md_operand (expressionP);
++}
++
++valueT
++md_section_align (segment, size)
++     segT   segment;
++     valueT size;
++{
++  int align = bfd_get_section_alignment (stdoutput, segment);
++  return ((size + (1 << align) - 1) & (-1 << align));
++}
++
++
++/* Be sure to use our register symbols. */
++symbolS *
++md_undefined_symbol (char * name ATTRIBUTE_UNUSED)
++{
++#if 0
++  char c;
++  unsigned int u;
++
++  if (sscanf(name, "%c%u", &c, &u) == 2)
++    {
++      if (c == 'd' && u < 32)
++      return ubicom32_register_table[u];
++      if (c == 'a' && u < 8)
++      return ubicom32_register_table[u + 32];
++    }
++#endif
++  return (0);
++}
++\f
++/* Interface to relax_segment.  */
++
++/* Return an initial guess of the length by which a fragment must grow to
++   hold a branch to reach its destination.
++   Also updates fr_type/fr_subtype as necessary.
++
++   Called just before doing relaxation.
++   Any symbol that is now undefined will not become defined.
++   The guess for fr_var is ACTUALLY the growth beyond fr_fix.
++   Whatever we do to grow fr_fix or fr_var contributes to our returned value.
++   Although it may not be explicit in the frag, pretend fr_var starts with a
++   0 value.  */
++
++int
++md_estimate_size_before_relax (fragP, segment)
++     fragS * fragP;
++     segT    segment ATTRIBUTE_UNUSED;
++{
++  int    old_fr_fix = fragP->fr_fix;
++
++  /* The only thing we have to handle here are symbols outside of the
++     current segment.  They may be undefined or in a different segment in
++     which case linker scripts may place them anywhere.
++     However, we can't finish the fragment here and emit the reloc as insn
++     alignment requirements may move the insn about.  */
++
++  return (fragP->fr_var + fragP->fr_fix - old_fr_fix);
++}
++
++/* *fragP has been relaxed to its final size, and now needs to have
++   the bytes inside it modified to conform to the new size.
++
++   Called after relaxation is finished.
++   fragP->fr_type == rs_machine_dependent.
++   fragP->fr_subtype is the subtype of what the address relaxed to.  */
++
++void
++md_convert_frag (abfd, sec, fragP)
++    bfd   * abfd  ATTRIBUTE_UNUSED;
++    segT    sec   ATTRIBUTE_UNUSED;
++    fragS * fragP ATTRIBUTE_UNUSED;
++{
++}
++
++\f
++/* Functions concerning relocs.  */
++
++long
++md_pcrel_from_section (fixS *fixP ATTRIBUTE_UNUSED, segT   sec ATTRIBUTE_UNUSED)
++{
++  /* Leave it for the linker to figure out so relaxation can work*/
++  return 0;
++}
++
++/* Return the bfd reloc type for OPERAND of INSN at fixup FIXP.
++   Returns BFD_RELOC_NONE if no reloc type can be found.
++   *FIXP may be modified if desired.  */
++
++bfd_reloc_code_real_type
++md_cgen_lookup_reloc (insn, operand, fixP)
++     const CGEN_INSN *    insn     ATTRIBUTE_UNUSED;
++     const CGEN_OPERAND * operand;
++     fixS *               fixP;
++{
++  switch (operand->type)
++    {
++    case UBICOM32_OPERAND_IMM16_2:
++    case UBICOM32_OPERAND_IMM24:
++    case UBICOM32_OPERAND_S1_IMM7_1:
++    case UBICOM32_OPERAND_S1_IMM7_2:
++    case UBICOM32_OPERAND_S1_IMM7_4:
++    case UBICOM32_OPERAND_D_IMM7_1:
++    case UBICOM32_OPERAND_D_IMM7_2:
++    case UBICOM32_OPERAND_D_IMM7_4:
++    case UBICOM32_OPERAND_OFFSET16:
++     /* The relocation type should be recorded in opinfo */
++      if (fixP->fx_cgen.opinfo != 0)
++      return fixP->fx_cgen.opinfo;
++
++    case UBICOM32_OPERAND_OFFSET21:
++      fixP->fx_pcrel = TRUE;
++      return BFD_RELOC_UBICOM32_21_PCREL;
++
++    case UBICOM32_OPERAND_OFFSET24:
++      fixP->fx_pcrel = TRUE;
++      return BFD_RELOC_UBICOM32_24_PCREL;
++
++    default:
++      /* Pacify gcc -Wall. */
++      return BFD_RELOC_NONE;
++    }
++}
++
++/* See whether we need to force a relocation into the output file. */
++
++int
++ubicom32_force_relocation (fix)
++     fixS * fix;
++{
++  if (fix->fx_r_type == BFD_RELOC_UNUSED)
++    return 0;
++
++  /* Force all relocations so linker relaxation can work.  */
++  return 1;
++}
++
++/* Write a value out to the object file, using the appropriate endianness.  */
++
++void
++md_number_to_chars (buf, val, n)
++     char * buf;
++     valueT val;
++     int    n;
++{
++  number_to_chars_bigendian (buf, val, n);
++}
++
++/* Turn a string in input_line_pointer into a floating point constant of type
++   type, and store the appropriate bytes in *litP.  The number of LITTLENUMS
++   emitted is stored in *sizeP .  An error message is returned, or NULL on OK.
++*/
++
++/* Equal to MAX_PRECISION in atof-ieee.c */
++#define MAX_LITTLENUMS 6
++
++char *
++md_atof (int  type,
++       char * litP,
++       int *  sizeP)
++{
++  int              prec;
++  LITTLENUM_TYPE   words [MAX_LITTLENUMS];
++  LITTLENUM_TYPE  *wordP;
++  char *           t;
++  //char *           atof_ieee (void);
++
++  switch (type)
++    {
++    case 'f':
++    case 'F':
++    case 's':
++    case 'S':
++      prec = 2;
++      break;
++
++    case 'd':
++    case 'D':
++    case 'r':
++    case 'R':
++      prec = 4;
++      break;
++
++   /* FIXME: Some targets allow other format chars for bigger sizes here.  */
++
++    default:
++      * sizeP = 0;
++      return _("Bad call to md_atof()");
++    }
++
++  t = atof_ieee (input_line_pointer, type, words);
++  if (t)
++    input_line_pointer = t;
++  * sizeP = prec * sizeof (LITTLENUM_TYPE);
++
++  /* This loops outputs the LITTLENUMs in REVERSE order; in accord with
++     the ubicom32 endianness.  */
++  for (wordP = words; prec--;)
++    {
++      md_number_to_chars (litP, (valueT) (*wordP++), sizeof (LITTLENUM_TYPE));
++      litP += sizeof (LITTLENUM_TYPE);
++    }
++
++  return 0;
++}
++
++bfd_boolean
++ubicom32_fix_adjustable (fixP)
++   fixS * fixP;
++{
++  bfd_reloc_code_real_type reloc_type;
++
++  if ((int) fixP->fx_r_type >= (int) BFD_RELOC_UNUSED)
++    {
++      const CGEN_INSN *insn = NULL;
++      int opindex = (int) fixP->fx_r_type - (int) BFD_RELOC_UNUSED;
++      const CGEN_OPERAND *operand = cgen_operand_lookup_by_num(gas_cgen_cpu_desc, opindex);
++      reloc_type = md_cgen_lookup_reloc (insn, operand, fixP);
++    }
++  else
++    reloc_type = fixP->fx_r_type;
++
++  if (fixP->fx_addsy == NULL)
++    return 1;
++
++  if (!S_IS_LOCAL (fixP->fx_addsy))
++    /* Let the linker resolve all symbols not within the local function
++       so the linker can relax correctly.  */
++    return 0;
++
++  if (S_IS_WEAK (fixP->fx_addsy))
++    return 0;
++
++  /* We need the symbol name for the VTABLE entries */
++  if (   reloc_type == BFD_RELOC_VTABLE_INHERIT
++      || reloc_type == BFD_RELOC_VTABLE_ENTRY)
++    return 0;
++
++  return 1;
++}
+--- /dev/null
++++ b/gas/config/tc-ubicom32.h
+@@ -0,0 +1,74 @@
++/* tc-ubicom32.h -- Header file for tc-ubicom32.c.
++   Copyright (C) 2000 Free Software Foundation, Inc.
++
++   This file is part of GAS, the GNU Assembler.
++
++   GAS 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, or (at your option)
++   any later version.
++
++   GAS 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 GAS; see the file COPYING.  If not, write to
++   the Free Software Foundation, 59 Temple Place - Suite 330,
++   Boston, MA 02111-1307, USA. */
++
++#define TC_UBICOM32
++
++#if 0
++#ifndef BFD_ASSEMBLER
++/* leading space so will compile with cc */
++ #error UBICOM32 support requires BFD_ASSEMBLER
++#endif
++#endif
++
++#define LISTING_HEADER "IP3xxx GAS "
++
++/* The target BFD architecture.  */
++#define TARGET_ARCH bfd_arch_ubicom32
++
++#define TARGET_FORMAT "elf32-ubicom32"
++
++#define TARGET_BYTES_BIG_ENDIAN 1
++
++/* Permit temporary numeric labels. */
++#define LOCAL_LABELS_FB 1
++
++/* .-foo gets turned into PC relative relocs. */
++#define DIFF_EXPR_OK
++
++/* UBICOM32 uses '(' and ')' as punctuation in addressing mode syntax. */
++#define RELAX_PAREN_GROUPING
++
++/* We don't need to handle .word strangely. */
++#define WORKING_DOT_WORD
++
++#define MD_APPLY_FIX3
++#define md_apply_fix gas_cgen_md_apply_fix
++
++/* special characters for hex and bin literals */
++#define LITERAL_PREFIXDOLLAR_HEX
++#define LITERAL_PREFIXPERCENT_BIN
++#define DOUBLESLASH_LINE_COMMENTS
++
++/* call md_pcrel_from_section, not md_pcrel_from */
++long md_pcrel_from_section PARAMS ((struct fix *, segT));
++#define MD_PCREL_FROM_SECTION(FIXP, SEC) md_pcrel_from_section (FIXP, SEC)
++
++#define obj_fix_adjustable(fixP) ubicom32_fix_adjustable (fixP)
++extern bfd_boolean ubicom32_fix_adjustable PARAMS ((struct fix *));
++
++/* Permit temporary numeric labels.  */
++#define LOCAL_LABELS_FB 1
++
++#define TC_HANDLES_FX_DONE
++
++#define tc_gen_reloc gas_cgen_tc_gen_reloc
++
++#define TC_FORCE_RELOCATION(fixp) ubicom32_force_relocation(fixp)
++extern int ubicom32_force_relocation PARAMS ((struct fix *));
+--- a/gas/configure
++++ b/gas/configure
+@@ -11188,7 +11188,7 @@ _ACEOF
+         fi
+         ;;
+-      fr30 | ip2k | iq2000 | m32r | openrisc)
++      fr30 | ubicom32 | ip2k | iq2000 | m32r | openrisc)
+       using_cgen=yes
+       ;;
+--- a/gas/configure.in
++++ b/gas/configure.in
+@@ -307,7 +307,7 @@ changequote([,])dnl
+         fi
+         ;;
+-      fr30 | ip2k | iq2000 | m32r | openrisc)
++      fr30 | ubicom32 | ip2k | iq2000 | m32r | openrisc)
+       using_cgen=yes
+       ;;
+--- a/gas/configure.tgt
++++ b/gas/configure.tgt
+@@ -81,6 +81,7 @@ case ${cpu} in
+   strongarm*be)               cpu_type=arm endian=big ;;
+   strongarm*b)                cpu_type=arm endian=big ;;
+   strongarm*)         cpu_type=arm endian=little ;;
++  ubicom32)                   cpu_type=ubicom32 endian=big ;; 
+   v850*)              cpu_type=v850 ;;
+   x86_64*)            cpu_type=i386 arch=x86_64;;
+   xscale*be|xscale*b) cpu_type=arm endian=big ;;
+@@ -384,6 +385,8 @@ case ${generic_target} in
+   tic4x-*-* | c4x-*-*)                        fmt=coff bfd_gas=yes ;;
+   tic54x-*-* | c54x*-*-*)             fmt=coff bfd_gas=yes need_libm=yes;;
++  ubicom32-*-*)                               fmt=elf ;;
++
+   v850-*-*)                           fmt=elf ;;
+   v850e-*-*)                          fmt=elf ;;
+   v850ea-*-*)                         fmt=elf ;;
+--- a/gas/Makefile.am
++++ b/gas/Makefile.am
+@@ -92,6 +92,7 @@ CPU_TYPES = \
+       tic30 \
+       tic4x \
+       tic54x \
++      ubicom32 \
+       v850 \
+       vax \
+       xc16x \
+@@ -287,6 +288,7 @@ TARGET_CPU_CFILES = \
+       config/tc-tic30.c \
+       config/tc-tic4x.c \
+       config/tc-tic54x.c \
++      config/tc-ubicom32.c \
+       config/tc-vax.c \
+       config/tc-v850.c \
+       config/tc-xstormy16.c \
+@@ -1415,6 +1417,14 @@ DEPTC_tic54x_coff = $(srcdir)/config/obj
+   $(BFDDIR)/libcoff.h $(INCDIR)/bfdlink.h $(INCDIR)/safe-ctype.h \
+   sb.h macro.h subsegs.h $(INCDIR)/obstack.h struc-symbol.h \
+   $(INCDIR)/opcode/tic54x.h
++DEPTC_ubicom32_elf = $(srcdir)/config/obj-elf.h $(BFDDIR)/elf-bfd.h \
++  $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h $(INCDIR)/elf/external.h \
++  $(INCDIR)/bfdlink.h $(srcdir)/config/tc-ubicom32.h dwarf2dbg.h \
++  subsegs.h $(INCDIR)/obstack.h $(srcdir)/../opcodes/ubicom32-desc.h \
++  $(INCDIR)/opcode/cgen-bitset.h $(INCDIR)/opcode/cgen.h \
++  $(INCDIR)/opcode/cgen-bitset.h $(srcdir)/../opcodes/ubicom32-opc.h \
++  cgen.h $(INCDIR)/elf/common.h $(INCDIR)/elf/ubicom32.h \
++  $(INCDIR)/elf/reloc-macros.h $(BFDDIR)/libbfd.h $(INCDIR)/hashtab.h
+ DEPTC_v850_elf = $(srcdir)/config/obj-elf.h $(BFDDIR)/elf-bfd.h \
+   $(INCDIR)/elf/common.h $(INCDIR)/elf/external.h $(INCDIR)/elf/internal.h \
+   $(INCDIR)/bfdlink.h $(srcdir)/config/tc-v850.h $(INCDIR)/elf/v850.h \
+@@ -1791,6 +1801,11 @@ DEPOBJ_tic54x_coff = $(srcdir)/config/ob
+   $(INCDIR)/coff/internal.h $(INCDIR)/coff/tic54x.h $(INCDIR)/coff/ti.h \
+   $(BFDDIR)/libcoff.h $(INCDIR)/bfdlink.h $(INCDIR)/obstack.h \
+   subsegs.h
++DEPOBJ_ubicomm32_elf = $(srcdir)/config/obj-elf.h $(BFDDIR)/elf-bfd.h \
++  $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h $(INCDIR)/elf/external.h \
++  $(INCDIR)/bfdlink.h $(srcdir)/config/tc-ubicom32.h dwarf2dbg.h \
++  $(INCDIR)/safe-ctype.h subsegs.h $(INCDIR)/obstack.h \
++  $(INCDIR)/obstack.h struc-symbol.h dwarf2dbg.h $(INCDIR)/aout/aout64.h
+ DEPOBJ_v850_elf = $(srcdir)/config/obj-elf.h $(BFDDIR)/elf-bfd.h \
+   $(INCDIR)/elf/common.h $(INCDIR)/elf/external.h $(INCDIR)/elf/internal.h \
+   $(INCDIR)/bfdlink.h $(srcdir)/config/tc-v850.h $(INCDIR)/elf/v850.h \
+@@ -2106,6 +2121,11 @@ DEP_tic4x_coff = $(srcdir)/config/obj-co
+ DEP_tic54x_coff = $(srcdir)/config/obj-coff.h $(srcdir)/config/tc-tic54x.h \
+   $(INCDIR)/coff/internal.h $(INCDIR)/coff/tic54x.h $(INCDIR)/coff/ti.h \
+   $(BFDDIR)/libcoff.h $(INCDIR)/bfdlink.h
++DEP_ubicom32_elf = $(srcdir)/config/obj-elf.h $(BFDDIR)/elf-bfd.h \
++  $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h $(INCDIR)/elf/external.h \
++  $(INCDIR)/bfdlink.h $(srcdir)/config/tc-ubicom32.h dwarf2dbg.h \
++  $(srcdir)/config/obj-coff.h $(INCDIR)/coff/internal.h \
++  $(BFDDIR)/libcoff.h
+ DEP_v850_elf = $(srcdir)/config/obj-elf.h $(BFDDIR)/elf-bfd.h \
+   $(INCDIR)/elf/common.h $(INCDIR)/elf/external.h $(INCDIR)/elf/internal.h \
+   $(INCDIR)/bfdlink.h $(srcdir)/config/tc-v850.h $(INCDIR)/elf/v850.h \
+--- a/gas/Makefile.in
++++ b/gas/Makefile.in
+@@ -341,6 +341,7 @@ CPU_TYPES = \
+       tic30 \
+       tic4x \
+       tic54x \
++      ubicom32 \
+       v850 \
+       vax \
+       xc16x \
+@@ -534,6 +535,7 @@ TARGET_CPU_CFILES = \
+       config/tc-tic30.c \
+       config/tc-tic4x.c \
+       config/tc-tic54x.c \
++      config/tc-ubicom32.c \
+       config/tc-vax.c \
+       config/tc-v850.c \
+       config/tc-xstormy16.c \
+@@ -594,6 +596,7 @@ TARGET_CPU_HFILES = \
+       config/tc-tic30.h \
+       config/tc-tic4x.h \
+       config/tc-tic54x.h \
++      config/tc-ubicom32.h \
+       config/tc-vax.h \
+       config/tc-v850.h \
+       config/tc-xstormy16.h \
+@@ -1244,6 +1247,13 @@ DEPTC_tic54x_coff = $(srcdir)/config/obj
+   $(BFDDIR)/libcoff.h $(INCDIR)/bfdlink.h $(INCDIR)/safe-ctype.h \
+   sb.h macro.h subsegs.h $(INCDIR)/obstack.h struc-symbol.h \
+   $(INCDIR)/opcode/tic54x.h
++DEPTC_ubicom32_elf = $(srcdir)/config/obj-elf.h $(BFDDIR)/elf-bfd.h \
++  $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h $(INCDIR)/elf/external.h \
++  $(INCDIR)/bfdlink.h $(srcdir)/config/tc-ubicom32.h dwarf2dbg.h \
++  subsegs.h $(INCDIR)/obstack.h $(srcdir)/../opcodes/ubicom32-desc.h \
++  $(INCDIR)/opcode/cgen-bitset.h $(INCDIR)/opcode/cgen.h \
++  $(srcdir)/../opcodes/ubicom32-opc.h cgen.h $(INCDIR)/elf/ubicom32.h \
++  $(INCDIR)/elf/reloc-macros.h $(BFDDIR)/libbfd.h $(INCDIR)/hashtab.h
+ DEPTC_v850_elf = $(srcdir)/config/obj-elf.h $(BFDDIR)/elf-bfd.h \
+   $(INCDIR)/elf/common.h $(INCDIR)/elf/external.h $(INCDIR)/elf/internal.h \
+@@ -1700,6 +1710,11 @@ DEPOBJ_tic54x_coff = $(srcdir)/config/ob
+   $(INCDIR)/coff/internal.h $(INCDIR)/coff/tic54x.h $(INCDIR)/coff/ti.h \
+   $(BFDDIR)/libcoff.h $(INCDIR)/bfdlink.h $(INCDIR)/obstack.h \
+   subsegs.h
++DEPOBJ_ubicom32_elf = $(srcdir)/config/obj-elf.h $(BFDDIR)/elf-bfd.h \
++  $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h $(INCDIR)/elf/external.h \
++  $(INCDIR)/bfdlink.h $(srcdir)/config/tc-ubicom32.h dwarf2dbg.h \
++  $(INCDIR)/safe-ctype.h subsegs.h $(INCDIR)/obstack.h \
++  struc-symbol.h $(INCDIR)/aout/aout64.h
+ DEPOBJ_v850_elf = $(srcdir)/config/obj-elf.h $(BFDDIR)/elf-bfd.h \
+   $(INCDIR)/elf/common.h $(INCDIR)/elf/external.h $(INCDIR)/elf/internal.h \
+@@ -2096,6 +2111,11 @@ DEP_tic54x_coff = $(srcdir)/config/obj-c
+   $(INCDIR)/coff/internal.h $(INCDIR)/coff/tic54x.h $(INCDIR)/coff/ti.h \
+   $(BFDDIR)/libcoff.h $(INCDIR)/bfdlink.h
++DEP_ubicom32_elf = $(srcdir)/config/obj-elf.h $(BFDDIR)/elf-bfd.h \
++  $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h $(INCDIR)/elf/external.h \
++  $(INCDIR)/bfdlink.h $(srcdir)/config/tc-ubicom32.h dwarf2dbg.h \
++  $(srcdir)/config/obj-coff.h $(INCDIR)/coff/internal.h \
++  $(BFDDIR)/libcoff.h
+ DEP_v850_elf = $(srcdir)/config/obj-elf.h $(BFDDIR)/elf-bfd.h \
+   $(INCDIR)/elf/common.h $(INCDIR)/elf/external.h $(INCDIR)/elf/internal.h \
+   $(INCDIR)/bfdlink.h $(srcdir)/config/tc-v850.h $(INCDIR)/elf/v850.h \
+--- a/include/dis-asm.h
++++ b/include/dis-asm.h
+@@ -275,6 +275,7 @@ extern int print_insn_tic30                (bfd_vma, d
+ extern int print_insn_tic4x           (bfd_vma, disassemble_info *);
+ extern int print_insn_tic54x          (bfd_vma, disassemble_info *);
+ extern int print_insn_tic80           (bfd_vma, disassemble_info *);
++extern int print_insn_ubicom32                (bfd_vma, disassemble_info *);
+ extern int print_insn_v850            (bfd_vma, disassemble_info *);
+ extern int print_insn_vax             (bfd_vma, disassemble_info *);
+ extern int print_insn_w65             (bfd_vma, disassemble_info *);
+--- /dev/null
++++ b/include/dis-asm_ubicom32.h
+@@ -0,0 +1,339 @@
++/* Interface between the opcode library and its callers.
++
++   Copyright 1999, 2000, 2001, 2002, 2003, 2004, 2005
++   Free Software Foundation, Inc.
++
++   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, 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.
++
++   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., 51 Franklin Street - Fifth Floor,
++   Boston, MA 02110-1301, USA.
++
++   Written by Cygnus Support, 1993.
++
++   The opcode library (libopcodes.a) provides instruction decoders for
++   a large variety of instruction sets, callable with an identical
++   interface, for making instruction-processing programs more independent
++   of the instruction set being processed.  */
++
++#ifndef DIS_ASM_H
++#define DIS_ASM_H
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++#include <stdio.h>
++#include "bfd.h"
++
++typedef int (*fprintf_ftype) (void *, const char*, ...) ATTRIBUTE_FPTR_PRINTF_2;
++
++enum dis_insn_type {
++  dis_noninsn,                        /* Not a valid instruction */
++  dis_nonbranch,              /* Not a branch instruction */
++  dis_branch,                 /* Unconditional branch */
++  dis_condbranch,             /* Conditional branch */
++  dis_jsr,                    /* Jump to subroutine */
++  dis_condjsr,                        /* Conditional jump to subroutine */
++  dis_dref,                   /* Data reference instruction */
++  dis_dref2                   /* Two data references in instruction */
++};
++
++/* This struct is passed into the instruction decoding routine,
++   and is passed back out into each callback.  The various fields are used
++   for conveying information from your main routine into your callbacks,
++   for passing information into the instruction decoders (such as the
++   addresses of the callback functions), or for passing information
++   back from the instruction decoders to their callers.
++
++   It must be initialized before it is first passed; this can be done
++   by hand, or using one of the initialization macros below.  */
++
++typedef struct disassemble_info {
++  fprintf_ftype fprintf_func;
++  void *stream;
++  void *application_data;
++
++  /* Target description.  We could replace this with a pointer to the bfd,
++     but that would require one.  There currently isn't any such requirement
++     so to avoid introducing one we record these explicitly.  */
++  /* The bfd_flavour.  This can be bfd_target_unknown_flavour.  */
++  enum bfd_flavour flavour;
++  /* The bfd_arch value.  */
++  enum bfd_architecture arch;
++  /* The bfd_mach value.  */
++  unsigned long mach;
++  /* Endianness (for bi-endian cpus).  Mono-endian cpus can ignore this.  */
++  enum bfd_endian endian;
++  /* An arch/mach-specific bitmask of selected instruction subsets, mainly
++     for processors with run-time-switchable instruction sets.  The default,
++     zero, means that there is no constraint.  CGEN-based opcodes ports
++     may use ISA_foo masks.  */
++  void *insn_sets;
++
++  /* Some targets need information about the current section to accurately
++     display insns.  If this is NULL, the target disassembler function
++     will have to make its best guess.  */
++  asection *section;
++
++  /* An array of pointers to symbols either at the location being disassembled
++     or at the start of the function being disassembled.  The array is sorted
++     so that the first symbol is intended to be the one used.  The others are
++     present for any misc. purposes.  This is not set reliably, but if it is
++     not NULL, it is correct.  */
++  asymbol **symbols;
++  /* Number of symbols in array.  */
++  int num_symbols;
++
++  /* For use by the disassembler.
++     The top 16 bits are reserved for public use (and are documented here).
++     The bottom 16 bits are for the internal use of the disassembler.  */
++  unsigned long flags;
++#define INSN_HAS_RELOC        0x80000000
++  void *private_data;
++
++  /* Function used to get bytes to disassemble.  MEMADDR is the
++     address of the stuff to be disassembled, MYADDR is the address to
++     put the bytes in, and LENGTH is the number of bytes to read.
++     INFO is a pointer to this struct.
++     Returns an errno value or 0 for success.  */
++  int (*read_memory_func)
++    (bfd_vma memaddr, bfd_byte *myaddr, unsigned int length,
++     struct disassemble_info *info);
++
++  /* Function which should be called if we get an error that we can't
++     recover from.  STATUS is the errno value from read_memory_func and
++     MEMADDR is the address that we were trying to read.  INFO is a
++     pointer to this struct.  */
++  void (*memory_error_func)
++    (int status, bfd_vma memaddr, struct disassemble_info *info);
++
++  /* Function called to print ADDR.  */
++  void (*print_address_func)
++    (bfd_vma addr, struct disassemble_info *info);
++
++  /* Function called to determine if there is a symbol at the given ADDR.
++     If there is, the function returns 1, otherwise it returns 0.
++     This is used by ports which support an overlay manager where
++     the overlay number is held in the top part of an address.  In
++     some circumstances we want to include the overlay number in the
++     address, (normally because there is a symbol associated with
++     that address), but sometimes we want to mask out the overlay bits.  */
++  int (* symbol_at_address_func)
++    (bfd_vma addr, struct disassemble_info * info);
++
++  /* Function called to check if a SYMBOL is can be displayed to the user.
++     This is used by some ports that want to hide special symbols when
++     displaying debugging outout.  */
++  bfd_boolean (* symbol_is_valid)
++    (asymbol *, struct disassemble_info * info);
++
++  /* These are for buffer_read_memory.  */
++  bfd_byte *buffer;
++  bfd_vma buffer_vma;
++  unsigned int buffer_length;
++
++  /* This variable may be set by the instruction decoder.  It suggests
++      the number of bytes objdump should display on a single line.  If
++      the instruction decoder sets this, it should always set it to
++      the same value in order to get reasonable looking output.  */
++  int bytes_per_line;
++
++  /* The next two variables control the way objdump displays the raw data.  */
++  /* For example, if bytes_per_line is 8 and bytes_per_chunk is 4, the */
++  /* output will look like this:
++     00:   00000000 00000000
++     with the chunks displayed according to "display_endian". */
++  int bytes_per_chunk;
++  enum bfd_endian display_endian;
++
++  /* Number of octets per incremented target address
++     Normally one, but some DSPs have byte sizes of 16 or 32 bits.  */
++  unsigned int octets_per_byte;
++
++  /* The number of zeroes we want to see at the end of a section before we
++     start skipping them.  */
++  unsigned int skip_zeroes;
++
++  /* The number of zeroes to skip at the end of a section.  If the number
++     of zeroes at the end is between SKIP_ZEROES_AT_END and SKIP_ZEROES,
++     they will be disassembled.  If there are fewer than
++     SKIP_ZEROES_AT_END, they will be skipped.  This is a heuristic
++     attempt to avoid disassembling zeroes inserted by section
++     alignment.  */
++  unsigned int skip_zeroes_at_end;
++
++  /* Whether the disassembler always needs the relocations.  */
++  bfd_boolean disassembler_needs_relocs;
++
++  /* Results from instruction decoders.  Not all decoders yet support
++     this information.  This info is set each time an instruction is
++     decoded, and is only valid for the last such instruction.
++
++     To determine whether this decoder supports this information, set
++     insn_info_valid to 0, decode an instruction, then check it.  */
++
++  char insn_info_valid;               /* Branch info has been set. */
++  char branch_delay_insns;    /* How many sequential insn's will run before
++                                 a branch takes effect.  (0 = normal) */
++  char data_size;             /* Size of data reference in insn, in bytes */
++  enum dis_insn_type insn_type;       /* Type of instruction */
++  bfd_vma target;             /* Target address of branch or dref, if known;
++                                 zero if unknown.  */
++  bfd_vma target2;            /* Second target address for dref2 */
++
++  /* Command line options specific to the target disassembler.  */
++  char * disassembler_options;
++
++} disassemble_info;
++
++\f
++/* Standard disassemblers.  Disassemble one instruction at the given
++   target address.  Return number of octets processed.  */
++typedef int (*disassembler_ftype) (bfd_vma, disassemble_info *);
++
++extern int print_insn_big_mips                (bfd_vma, disassemble_info *);
++extern int print_insn_little_mips     (bfd_vma, disassemble_info *);
++extern int print_insn_i386            (bfd_vma, disassemble_info *);
++extern int print_insn_i386_att                (bfd_vma, disassemble_info *);
++extern int print_insn_i386_intel      (bfd_vma, disassemble_info *);
++extern int print_insn_ia64            (bfd_vma, disassemble_info *);
++extern int print_insn_i370            (bfd_vma, disassemble_info *);
++extern int print_insn_m68hc11         (bfd_vma, disassemble_info *);
++extern int print_insn_m68hc12         (bfd_vma, disassemble_info *);
++extern int print_insn_m68k            (bfd_vma, disassemble_info *);
++extern int print_insn_z80             (bfd_vma, disassemble_info *);
++extern int print_insn_z8001           (bfd_vma, disassemble_info *);
++extern int print_insn_z8002           (bfd_vma, disassemble_info *);
++extern int print_insn_h8300           (bfd_vma, disassemble_info *);
++extern int print_insn_h8300h          (bfd_vma, disassemble_info *);
++extern int print_insn_h8300s          (bfd_vma, disassemble_info *);
++extern int print_insn_h8500           (bfd_vma, disassemble_info *);
++extern int print_insn_alpha           (bfd_vma, disassemble_info *);
++extern int print_insn_big_arm         (bfd_vma, disassemble_info *);
++extern int print_insn_little_arm      (bfd_vma, disassemble_info *);
++extern int print_insn_sparc           (bfd_vma, disassemble_info *);
++extern int print_insn_avr             (bfd_vma, disassemble_info *);
++extern int print_insn_bfin            (bfd_vma, disassemble_info *);
++extern int print_insn_d10v            (bfd_vma, disassemble_info *);
++extern int print_insn_d30v            (bfd_vma, disassemble_info *);
++extern int print_insn_dlx             (bfd_vma, disassemble_info *);
++extern int print_insn_fr30            (bfd_vma, disassemble_info *);
++extern int print_insn_hppa            (bfd_vma, disassemble_info *);
++extern int print_insn_i860            (bfd_vma, disassemble_info *);
++extern int print_insn_i960            (bfd_vma, disassemble_info *);
++extern int print_insn_m32r            (bfd_vma, disassemble_info *);
++extern int print_insn_m88k            (bfd_vma, disassemble_info *);
++extern int print_insn_maxq_little     (bfd_vma, disassemble_info *);
++extern int print_insn_maxq_big                (bfd_vma, disassemble_info *);
++extern int print_insn_mcore           (bfd_vma, disassemble_info *);
++extern int print_insn_mmix            (bfd_vma, disassemble_info *);
++extern int print_insn_mn10200         (bfd_vma, disassemble_info *);
++extern int print_insn_mn10300         (bfd_vma, disassemble_info *);
++extern int print_insn_mt                (bfd_vma, disassemble_info *);
++extern int print_insn_msp430          (bfd_vma, disassemble_info *);
++extern int print_insn_ns32k           (bfd_vma, disassemble_info *);
++extern int print_insn_crx               (bfd_vma, disassemble_info *);
++extern int print_insn_openrisc                (bfd_vma, disassemble_info *);
++extern int print_insn_big_or32                (bfd_vma, disassemble_info *);
++extern int print_insn_little_or32     (bfd_vma, disassemble_info *);
++extern int print_insn_pdp11           (bfd_vma, disassemble_info *);
++extern int print_insn_pj              (bfd_vma, disassemble_info *);
++extern int print_insn_big_powerpc     (bfd_vma, disassemble_info *);
++extern int print_insn_little_powerpc  (bfd_vma, disassemble_info *);
++extern int print_insn_rs6000          (bfd_vma, disassemble_info *);
++extern int print_insn_s390            (bfd_vma, disassemble_info *);
++extern int print_insn_sh              (bfd_vma, disassemble_info *);
++extern int print_insn_tic30           (bfd_vma, disassemble_info *);
++extern int print_insn_tic4x           (bfd_vma, disassemble_info *);
++extern int print_insn_tic54x          (bfd_vma, disassemble_info *);
++extern int print_insn_tic80           (bfd_vma, disassemble_info *);
++extern int print_insn_ubicom32                (bfd_vma, disassemble_info *);
++extern int print_insn_v850            (bfd_vma, disassemble_info *);
++extern int print_insn_vax             (bfd_vma, disassemble_info *);
++extern int print_insn_w65             (bfd_vma, disassemble_info *);
++extern int print_insn_xstormy16               (bfd_vma, disassemble_info *);
++extern int print_insn_xtensa          (bfd_vma, disassemble_info *);
++extern int print_insn_sh64            (bfd_vma, disassemble_info *);
++extern int print_insn_sh64x_media     (bfd_vma, disassemble_info *);
++extern int print_insn_frv             (bfd_vma, disassemble_info *);
++extern int print_insn_iq2000          (bfd_vma, disassemble_info *);
++extern int print_insn_xc16x           (bfd_vma, disassemble_info *);
++extern int print_insn_m32c    (bfd_vma, disassemble_info *);
++
++extern disassembler_ftype arc_get_disassembler (void *);
++extern disassembler_ftype cris_get_disassembler (bfd *);
++
++extern void print_mips_disassembler_options (FILE *);
++extern void print_ppc_disassembler_options (FILE *);
++extern void print_arm_disassembler_options (FILE *);
++extern void parse_arm_disassembler_option (char *);
++extern int get_arm_regname_num_options (void);
++extern int set_arm_regname_option (int);
++extern int get_arm_regnames (int, const char **, const char **, const char *const **);
++extern bfd_boolean arm_symbol_is_valid (asymbol *, struct disassemble_info *);
++
++/* Fetch the disassembler for a given BFD, if that support is available.  */
++extern disassembler_ftype disassembler (bfd *);
++
++/* Amend the disassemble_info structure as necessary for the target architecture.
++   Should only be called after initialising the info->arch field.  */
++extern void disassemble_init_for_target (struct disassemble_info * info);
++
++/* Document any target specific options available from the disassembler.  */
++extern void disassembler_usage (FILE *);
++
++\f
++/* This block of definitions is for particular callers who read instructions
++   into a buffer before calling the instruction decoder.  */
++
++/* Here is a function which callers may wish to use for read_memory_func.
++   It gets bytes from a buffer.  */
++extern int buffer_read_memory
++  (bfd_vma, bfd_byte *, unsigned int, struct disassemble_info *);
++
++/* This function goes with buffer_read_memory.
++   It prints a message using info->fprintf_func and info->stream.  */
++extern void perror_memory (int, bfd_vma, struct disassemble_info *);
++
++
++/* Just print the address in hex.  This is included for completeness even
++   though both GDB and objdump provide their own (to print symbolic
++   addresses).  */
++extern void generic_print_address
++  (bfd_vma, struct disassemble_info *);
++
++/* Always true.  */
++extern int generic_symbol_at_address
++  (bfd_vma, struct disassemble_info *);
++
++/* Also always true.  */
++extern bfd_boolean generic_symbol_is_valid
++  (asymbol *, struct disassemble_info *);
++
++/* Method to initialize a disassemble_info struct.  This should be
++   called by all applications creating such a struct.  */
++extern void init_disassemble_info (struct disassemble_info *info, void *stream,
++                                 fprintf_ftype fprintf_func);
++
++/* For compatibility with existing code.  */
++#define INIT_DISASSEMBLE_INFO(INFO, STREAM, FPRINTF_FUNC) \
++  init_disassemble_info (&(INFO), (STREAM), (fprintf_ftype) (FPRINTF_FUNC))
++#define INIT_DISASSEMBLE_INFO_NO_ARCH(INFO, STREAM, FPRINTF_FUNC) \
++  init_disassemble_info (&(INFO), (STREAM), (fprintf_ftype) (FPRINTF_FUNC))
++
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif /* ! defined (DIS_ASM_H) */
+--- a/include/elf/common.h
++++ b/include/elf/common.h
+@@ -318,6 +318,9 @@
+ #define EM_XSTORMY16          0xad45
++#define EM_UBICOM32           0xde3d  /* Ubicom32; no ABI */
++#define EM_UBICOM32MATH       0xde3e  /* Ubicom32 co-processor; no ABI */
++
+ /* mn10200 and mn10300 backend magic numbers.
+    Written in the absense of an ABI.  */
+ #define EM_CYGNUS_MN10300     0xbeef
+--- /dev/null
++++ b/include/elf/ubicom32.h
+@@ -0,0 +1,79 @@
++/* ubicom32 ELF support for BFD.
++   Copyright (C) 2000 Free Software Foundation, Inc.
++
++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 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.  */
++
++#ifndef _ELF_UBICOM32_H
++#define _ELF_UBICOM32_H
++
++#include "elf/reloc-macros.h"
++
++/* Relocations.  */
++START_RELOC_NUMBERS (elf_ubicom32_reloc_type)
++  RELOC_NUMBER (R_UBICOM32_NONE, 0)
++  RELOC_NUMBER (R_UBICOM32_16, 1)
++  RELOC_NUMBER (R_UBICOM32_32, 2)
++  RELOC_NUMBER (R_UBICOM32_LO16, 3)
++  RELOC_NUMBER (R_UBICOM32_HI16, 4)
++  RELOC_NUMBER (R_UBICOM32_21_PCREL, 5)
++  RELOC_NUMBER (R_UBICOM32_24_PCREL, 6)
++  RELOC_NUMBER (R_UBICOM32_HI24, 7)
++  RELOC_NUMBER (R_UBICOM32_LO7_S, 8)
++  RELOC_NUMBER (R_UBICOM32_LO7_2_S, 9)
++  RELOC_NUMBER (R_UBICOM32_LO7_4_S, 10)
++  RELOC_NUMBER (R_UBICOM32_LO7_D, 11)
++  RELOC_NUMBER (R_UBICOM32_LO7_2_D, 12)
++  RELOC_NUMBER (R_UBICOM32_LO7_4_D, 13)
++  RELOC_NUMBER (R_UBICOM32_32_HARVARD, 14)
++  RELOC_NUMBER (R_UBICOM32_LO7_CALLI, 15)
++  RELOC_NUMBER (R_UBICOM32_LO16_CALLI, 16)
++  RELOC_NUMBER (R_UBICOM32_GOT_HI24, 17)
++  RELOC_NUMBER (R_UBICOM32_GOT_LO7_S, 18)
++  RELOC_NUMBER (R_UBICOM32_GOT_LO7_2_S, 19)
++  RELOC_NUMBER (R_UBICOM32_GOT_LO7_4_S, 20)
++  RELOC_NUMBER (R_UBICOM32_GOT_LO7_D, 21)
++  RELOC_NUMBER (R_UBICOM32_GOT_LO7_2_D, 22)
++  RELOC_NUMBER (R_UBICOM32_GOT_LO7_4_D, 23)
++  RELOC_NUMBER (R_UBICOM32_FUNCDESC_GOT_HI24, 24)
++  RELOC_NUMBER (R_UBICOM32_FUNCDESC_GOT_LO7_S, 25)
++  RELOC_NUMBER (R_UBICOM32_FUNCDESC_GOT_LO7_2_S, 26)
++  RELOC_NUMBER (R_UBICOM32_FUNCDESC_GOT_LO7_4_S, 27)
++  RELOC_NUMBER (R_UBICOM32_FUNCDESC_GOT_LO7_D, 28)
++  RELOC_NUMBER (R_UBICOM32_FUNCDESC_GOT_LO7_2_D, 29)
++  RELOC_NUMBER (R_UBICOM32_FUNCDESC_GOT_LO7_4_D, 30)
++  RELOC_NUMBER (R_UBICOM32_GOT_LO7_CALLI, 31)
++  RELOC_NUMBER (R_UBICOM32_FUNCDESC_GOT_LO7_CALLI, 32)
++  RELOC_NUMBER (R_UBICOM32_FUNCDESC_VALUE, 33)
++  RELOC_NUMBER (R_UBICOM32_FUNCDESC, 34)
++  RELOC_NUMBER (R_UBICOM32_GOTOFFSET_LO, 35)
++  RELOC_NUMBER (R_UBICOM32_GOTOFFSET_HI, 36)
++  RELOC_NUMBER (R_UBICOM32_FUNCDESC_GOTOFFSET_LO, 37)
++  RELOC_NUMBER (R_UBICOM32_FUNCDESC_GOTOFFSET_HI, 38)
++  RELOC_NUMBER (R_UBICOM32_GNU_VTINHERIT, 200)
++  RELOC_NUMBER (R_UBICOM32_GNU_VTENTRY, 201)
++END_RELOC_NUMBERS(R_UBICOM32_max)
++
++
++/*
++ * Processor specific flags for the ELF header e_flags field.
++ */
++#define EF_UBICOM32_PIC         0x80000000      /* -fpic */
++#define EF_UBICOM32_FDPIC       0x40000000      /* -mfdpic */
++
++#define EF_UBICOM32_PIC_FLAGS   (EF_UBICOM32_PIC | EF_UBICOM32_FDPIC)
++
++#endif /* _ELF_IP_H */
+--- a/ld/configure.tgt
++++ b/ld/configure.tgt
+@@ -607,6 +607,15 @@ tic4x-*-* | c4x-*-*)    targ_emul=tic4xc
+ tic54x-*-* | c54x*-*-*)       targ_emul=tic54xcoff ;;
+ tic80-*-*)            targ_emul=tic80coff
+                       ;;
++ubicom32-*-linux-*)   targ_emul=elf32ubicom32
++                      targ_extra_emuls=elf32ubicom32fdpic
++                      targ_extra_libpath=$targ_extra_emuls
++                      ;;
++ubicom32-*-*)         targ_emul=elf32ubicom32
++                      targ_extra_emuls=elf32ubicom32fdpic
++                      targ_extra_libpath=$targ_extra_emuls
++                      ;;
++
+ v850-*-*)             targ_emul=v850 ;;
+ v850e-*-*)            targ_emul=v850 ;;
+ v850ea-*-*)           targ_emul=v850
+--- /dev/null
++++ b/ld/emulparams/elf32ubicom32fdpic.sh
+@@ -0,0 +1,28 @@
++MACHINE=
++SCRIPT_NAME=elf
++OUTPUT_FORMAT="elf32-ubicom32fdpic"
++TEXT_START_ADDR=0x000000
++MAXPAGESIZE=0x1000
++TARGET_PAGE_SIZE=0x1000
++NONPAGED_TEXT_START_ADDR=${TEXT_START_ADDR}
++ARCH=ubicom32
++TEMPLATE_NAME=elf32
++ENTRY=_start
++EMBEDDED=yes
++GENERATE_SHLIB_SCRIPT=yes
++EMBEDDED= # This gets us program headers mapped as part of the text segment.
++OTHER_GOT_SYMBOLS=
++OTHER_READONLY_SECTIONS="
++  .rofixup        : {
++    ${RELOCATING+__ROFIXUP_LIST__ = .;}
++    *(.rofixup)
++    ${RELOCATING+__ROFIXUP_END__ = .;}
++  }
++"
++ELFSIZE=32
++WRITABLE_RODATA=""
++DATA_START_SYMBOLS=
++CTOR_START='___ctors = .;'
++CTOR_END='___ctors_end = .;'
++DTOR_START='___dtors = .;'
++DTOR_END='___dtors_end = .;'
+--- /dev/null
++++ b/ld/emulparams/elf32ubicom32.sh
+@@ -0,0 +1,23 @@
++MACHINE=
++SCRIPT_NAME=elf
++OUTPUT_FORMAT="elf32-ubicom32"
++DATA_ADDR=0x100000
++EXT_DATA_START_ADDR=0x100000
++EXT_DATA_SIZE=0x10000
++TEXT_START_ADDR=0x40000000
++EXT_PROGRAM_START_ADDR=0x40000000
++EXT_PROGRAM_SIZE=0x80000
++FLASHRAM_START_ADDR=0x20000000
++COPROCESSOR_MEMORY=0x400000
++COPROCESSOR_MEM_SIZE=0x100000
++ARCH=ubicom32
++TEMPLATE_NAME=elf32
++ENTRY=_start
++EMBEDDED=yes
++ELFSIZE=32
++MAXPAGESIZE=256
++DATA_START_SYMBOLS=
++CTOR_START='___ctors = .;'
++CTOR_END='___ctors_end = .;'
++DTOR_START='___dtors = .;'
++DTOR_END='___dtors_end = .;'
+--- a/ld/Makefile.am
++++ b/ld/Makefile.am
+@@ -198,6 +198,8 @@ ALL_EMULATIONS = \
+       eelf32ppcsim.o \
+       eelf32ppcwindiss.o \
+       eelf32ppcvxworks.o \
++      eelf32ubicom32.o \
++      eelf32ubicom32fdpic.o \
+       eelf32vax.o \
+         eelf32xc16x.o \
+         eelf32xc16xl.o \
+@@ -927,6 +929,14 @@ eelf64lppc.c: $(srcdir)/emulparams/elf64
+ eelf32i370.c: $(srcdir)/emulparams/elf32i370.sh \
+   $(ELF_DEPS) $(srcdir)/scripttempl/elfi370.sc ${GEN_DEPENDS}
+       ${GENSCRIPTS} elf32i370 "$(tdir_elf32i370)"
++eelf32ubicom32.c: $(srcdir)/emulparams/elf32ubicom32.sh \
++  $(ELF_DEPS) \
++  $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS}
++      ${GENSCRIPTS} elf32ubicom32 "$(tdir_ubicom32)"
++eelf32ubicom32fdpic.c: $(srcdir)/emulparams/elf32ubicom32fdpic.sh \
++  $(ELF_DEPS) \
++  $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS}
++      ${GENSCRIPTS} elf32ubicom32fdpic "$(tdir_ubicom32fdpic)"
+ eelf32ip2k.c: $(srcdir)/emulparams/elf32ip2k.sh \
+   $(ELF_DEPS) $(srcdir)/scripttempl/ip2k.sc ${GEN_DEPENDS}
+       ${GENSCRIPTS} elf32ip2k "$(tdir_ip2k)"
+--- a/ld/Makefile.in
++++ b/ld/Makefile.in
+@@ -449,6 +449,8 @@ ALL_EMULATIONS = \
+       eelf32ppcsim.o \
+       eelf32ppcwindiss.o \
+       eelf32ppcvxworks.o \
++      eelf32ubicom32.o \
++      eelf32ubicom32fdpic.o \
+       eelf32vax.o \
+         eelf32xc16x.o \
+         eelf32xc16xl.o \
+@@ -1759,6 +1761,14 @@ eelf64lppc.c: $(srcdir)/emulparams/elf64
+ eelf32i370.c: $(srcdir)/emulparams/elf32i370.sh \
+   $(ELF_DEPS) $(srcdir)/scripttempl/elfi370.sc ${GEN_DEPENDS}
+       ${GENSCRIPTS} elf32i370 "$(tdir_elf32i370)"
++eelf32ubicom32.c: $(srcdir)/emulparams/elf32ubicom32.sh \
++  $(ELF_DEPS) \
++  $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS}
++      ${GENSCRIPTS} elf32ubicom32 "$(tdir_ubicom32)"
++eelf32ubicom32fdpic.c: $(srcdir)/emulparams/elf32ubicom32fdpic.sh \
++  $(ELF_DEPS) \
++  $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS}
++      ${GENSCRIPTS} elf32ubicom32fdpic "$(tdir_ubicom32fdpic)"
+ eelf32ip2k.c: $(srcdir)/emulparams/elf32ip2k.sh \
+   $(ELF_DEPS) $(srcdir)/scripttempl/ip2k.sc ${GEN_DEPENDS}
+       ${GENSCRIPTS} elf32ip2k "$(tdir_ip2k)"
+--- /dev/null
++++ b/ld/scripttempl/ubicom32.sc
+@@ -0,0 +1,395 @@
++#
++# Unusual variables checked by this code:
++#       EXT_DATA_START_ADDR - virtual address start of extended data storage
++#       EXT_DATA_SIZE - size of extended data storage
++#       EXT_PROGRAM_START_ADDR - virtual address start of extended prog storage
++#       EXT_PROGRAM_SIZE - size of extended program storage
++#       FLASHRAM1_START_ADDR - virtual address start of flash ram 1 storage
++#       FLASHRAM2_START_ADDR - virtual address start of flash ram 2 storage
++#       FLASHRAM3_START_ADDR - virtual address start of flash ram 3 storage
++#       FLASHRAM4_START_ADDR - virtual address start of flash ram 4 storage
++#       FLASHRAM5_START_ADDR - virtual address start of flash ram 5 storage
++#       FLASHRAM6_START_ADDR - virtual address start of flash ram 6 storage
++#       FLASHRAM7_START_ADDR - virtual address start of flash ram 7 storage
++#       FLASHRAM8_START_ADDR - virtual address start of flash ram 8 storage
++#       PROGRAM_SRAM_START_ADDR - virtual address start of program sram storage
++#     NOP - two byte opcode for no-op (defaults to 0)
++#     DATA_ADDR - if end-of-text-plus-one-page isn't right for data start
++#     INITIAL_READONLY_SECTIONS - at start of text segment
++#     OTHER_READONLY_SECTIONS - other than .text .init .rodata ...
++#             (e.g., .PARISC.milli)
++#     OTHER_TEXT_SECTIONS - these get put in .text when relocating
++#     OTHER_READWRITE_SECTIONS - other than .data .bss .ctors .sdata ...
++#             (e.g., .PARISC.global)
++#     OTHER_BSS_SECTIONS - other than .bss .sbss ...
++#     OTHER_SECTIONS - at the end
++#     EXECUTABLE_SYMBOLS - symbols that must be defined for an
++#             executable (e.g., _DYNAMIC_LINK)
++#     TEXT_START_SYMBOLS - symbols that appear at the start of the
++#             .text section.
++#     DATA_START_SYMBOLS - symbols that appear at the start of the
++#             .data section.
++#     OTHER_GOT_SYMBOLS - symbols defined just before .got.
++#     OTHER_GOT_SECTIONS - sections just after .got and .sdata.
++#     OTHER_BSS_SYMBOLS - symbols that appear at the start of the
++#             .bss section besides __bss_start.
++#     DATA_PLT - .plt should be in data segment, not text segment.
++#     BSS_PLT - .plt should be in bss segment
++#     TEXT_DYNAMIC - .dynamic in text segment, not data segment.
++#     EMBEDDED - whether this is for an embedded system. 
++#     SHLIB_TEXT_START_ADDR - if set, add to SIZEOF_HEADERS to set
++#             start address of shared library.
++#     INPUT_FILES - INPUT command of files to always include
++#     WRITABLE_RODATA - if set, the .rodata section should be writable
++#     INIT_START, INIT_END -  statements just before and just after
++#     combination of .init sections.
++#     FINI_START, FINI_END - statements just before and just after
++#     combination of .fini sections.
++#
++# When adding sections, do note that the names of some sections are used
++# when specifying the start address of the next.
++#
++
++test -z "$ENTRY" && ENTRY=_start
++test -z "${BIG_OUTPUT_FORMAT}" && BIG_OUTPUT_FORMAT=${OUTPUT_FORMAT}
++test -z "${LITTLE_OUTPUT_FORMAT}" && LITTLE_OUTPUT_FORMAT=${OUTPUT_FORMAT}
++if [ -z "$MACHINE" ]; then OUTPUT_ARCH=${ARCH}; else OUTPUT_ARCH=${ARCH}:${MACHINE}; fi
++test -z "${ELFSIZE}" && ELFSIZE=32
++test -z "${ALIGNMENT}" && ALIGNMENT="${ELFSIZE} / 8"
++test "$LD_FLAG" = "N" && DATA_ADDR=.
++INTERP=".interp   ${RELOCATING-0} : { *(.interp)      } ${RELOCATING+ > datamem}"
++PLT=".plt    ${RELOCATING-0} : { *(.plt)      } ${RELOCATING+ > datamem}"
++DYNAMIC=".dynamic     ${RELOCATING-0} : { *(.dynamic) } ${RELOCATING+ > datamem}"
++RODATA=".rodata ${RELOCATING-0} : { *(.rodata) ${RELOCATING+*(.rodata.*)} ${RELOCATING+*(.gnu.linkonce.r*)} } ${RELOCATING+ > datamem}"
++SBSS2=".sbss2 ${RELOCATING-0} : { *(.sbss2) } ${RELOCATING+ > datamem}"
++SDATA2=".sdata2 ${RELOCATING-0} : { *(.sdata2) } ${RELOCATING+ >datamem}"
++CTOR=".ctors ${CONSTRUCTING-0} : 
++  {
++    ${RELOCATING+. = ALIGN(${ALIGNMENT});}
++    ${CONSTRUCTING+${CTOR_START}}
++    LONG (-1)
++    /* gcc uses crtbegin.o to find the start of
++       the constructors, so we make sure it is
++       first.  Because this is a wildcard, it
++       doesn't matter if the user does not
++       actually link against crtbegin.o; the
++       linker won't look for a file to match a
++       wildcard.  The wildcard also means that it
++       doesn't matter which directory crtbegin.o
++       is in.  */
++
++    KEEP (*crtbegin.o(.ctors))
++
++    /* We don't want to include the .ctor section from
++       from the crtend.o file until after the sorted ctors.
++       The .ctor section from the crtend file contains the
++       end of ctors marker and it must be last */
++
++    KEEP (*(EXCLUDE_FILE (*crtend.o $OTHER_EXCLUDE_FILES) .ctors))
++    KEEP (*(SORT(.ctors.*)))
++    KEEP (*(.ctors))
++    LONG (0)
++    ${CONSTRUCTING+${CTOR_END}}
++  } ${RELOCATING+ > datamem}"
++
++DTOR=" .dtors       ${CONSTRUCTING-0} :
++  {
++    ${RELOCATING+. = ALIGN(${ALIGNMENT});}
++    ${CONSTRUCTING+${DTOR_START}}
++    LONG (-1)
++    KEEP (*crtbegin.o(.dtors))
++    KEEP (*(EXCLUDE_FILE (*crtend.o $OTHER_EXCLUDE_FILES) .dtors))
++    KEEP (*(SORT(.dtors.*)))
++    KEEP (*(.dtors))
++    LONG (0)
++    ${CONSTRUCTING+${DTOR_END}}
++  } ${RELOCATING+ > datamem}"
++
++# if this is for an embedded system, don't add SIZEOF_HEADERS.
++if [ -z "$EMBEDDED" ]; then
++   test -z "${TEXT_BASE_ADDRESS}" && TEXT_BASE_ADDRESS="${TEXT_START_ADDR} + SIZEOF_HEADERS"
++else
++   test -z "${TEXT_BASE_ADDRESS}" && TEXT_BASE_ADDRESS="${TEXT_START_ADDR}"
++fi
++
++cat <<EOF
++OUTPUT_FORMAT("${OUTPUT_FORMAT}", "${BIG_OUTPUT_FORMAT}",
++            "${LITTLE_OUTPUT_FORMAT}")
++OUTPUT_ARCH(${OUTPUT_ARCH})
++ENTRY(${ENTRY})
++
++${RELOCATING+${LIB_SEARCH_DIRS}}
++${RELOCATING+/* Do we need any of these for elf?
++   __DYNAMIC = 0; ${STACKZERO+${STACKZERO}} ${SHLIB_PATH+${SHLIB_PATH}}  */}
++${RELOCATING+${EXECUTABLE_SYMBOLS}}
++${RELOCATING+${INPUT_FILES}}
++${RELOCATING- /* For some reason, the Solaris linker makes bad executables
++  if gld -r is used and the intermediate file has sections starting
++  at non-zero addresses.  Could be a Solaris ld bug, could be a GNU ld
++  bug.  But for now assigning the zero vmas works.  */}
++
++MEMORY
++{
++  datamem (w) : ORIGIN = ${EXT_DATA_START_ADDR}, LENGTH = ${EXT_DATA_SIZE}
++  progmem (wx): ORIGIN = ${EXT_PROGRAM_START_ADDR}, LENGTH = ${EXT_PROGRAM_SIZE}
++  flashram (wx) : ORIGIN = ${FLASHRAM_START_ADDR}, LENGTH = 0x400000
++  copromem (w) : ORIGIN = ${COPROCESSOR_MEMORY}, LENGTH = ${COPROCESSOR_MEM_SIZE}
++}
++
++SECTIONS
++{
++  .flram ${RELOCATING-0} : { *(.start) *(.flram) } ${RELOCATING+ > flashram}
++  .copro ${RELOCATING-0} : {*(.copro) } ${RELOCATING+ > copromem}
++
++  ${CREATE_SHLIB-${RELOCATING+. = ${TEXT_BASE_ADDRESS};}}
++  ${CREATE_SHLIB+${RELOCATING+. = ${SHLIB_TEXT_START_ADDR:-0} + SIZEOF_HEADERS;}}
++  .text    ${RELOCATING-0} :
++  {
++    ${RELOCATING+${TEXT_START_SYMBOLS}}
++    *(.text)
++    ${RELOCATING+*(.text.*)}
++    *(.stub)
++    /* .gnu.warning sections are handled specially by elf32.em.  */
++    *(.gnu.warning)
++    ${RELOCATING+*(.gnu.linkonce.t*)}
++    ${RELOCATING+${OTHER_TEXT_SECTIONS}}
++  } ${RELOCATING+ > progmem} =${NOP-0}
++
++  .rel.text    ${RELOCATING-0} :
++    {
++      *(.rel.text)
++      ${RELOCATING+*(.rel.text.*)}
++      ${RELOCATING+*(.rel.gnu.linkonce.t*)}
++    } ${RELOCATING+ > progmem}
++
++  .rela.text   ${RELOCATING-0} :
++    {
++      *(.rela.text)
++      ${RELOCATING+*(.rela.text.*)}
++      ${RELOCATING+*(.rela.gnu.linkonce.t*)}
++    } ${RELOCATING+ > progmem}
++
++  ${RELOCATING+PROVIDE (__etext = .);}
++  ${RELOCATING+PROVIDE (_etext = .);}
++  ${RELOCATING+PROVIDE (etext = .);}
++
++  /* Adjust the address for the data segment.  We want to adjust up to
++     the same address within the page on the next page up.  */
++  ${CREATE_SHLIB-${RELOCATING+. = ${DATA_ADDR-ALIGN(${MAXPAGESIZE}) + (. & (${MAXPAGESIZE} - 1))};}}
++  ${CREATE_SHLIB+${RELOCATING+. = ${SHLIB_DATA_ADDR-ALIGN(${MAXPAGESIZE}) + (. & (${MAXPAGESIZE} - 1))};}}
++
++  /* Skip first word to ensure first data element can't end up having address
++     0 in code (NULL pointer) */
++  . = . + 4;
++  .data  ${RELOCATING-0} :
++  {
++    ${RELOCATING+${DATA_START_SYMBOLS}}
++    *(.data)
++    ${RELOCATING+*(.data.*)}
++    ${RELOCATING+*(.gnu.linkonce.d*)}
++    ${CONSTRUCTING+SORT(CONSTRUCTORS)}
++  } ${RELOCATING+ > datamem}
++  .data1 ${RELOCATING-0} : { *(.data1) } ${RELOCATING+ > datamem}
++  .eh_frame ${RELOCATING-0} : 
++  { 
++    ${RELOCATING+PROVIDE (___eh_frame_begin = .);}
++    *(.eh_frame) 
++    LONG (0);
++    ${RELOCATING+PROVIDE (___eh_frame_end = .);}
++  } ${RELOCATING+ > datamem}
++  .gcc_except_table : { *(.gcc_except_table) } ${RELOCATING+ > datamem}
++  
++  /* Read-only sections, placed in data space: */
++  ${CREATE_SHLIB-${INTERP}}
++  ${INITIAL_READONLY_SECTIONS}
++  ${TEXT_DYNAMIC+${DYNAMIC}}
++  .hash        ${RELOCATING-0} : { *(.hash)           } ${RELOCATING+ > datamem}
++  .dynsym      ${RELOCATING-0} : { *(.dynsym)         } ${RELOCATING+ > datamem}
++  .dynstr      ${RELOCATING-0} : { *(.dynstr)         } ${RELOCATING+ > datamem}
++  .gnu.version ${RELOCATING-0} : { *(.gnu.version)    } ${RELOCATING+ > datamem}
++  .gnu.version_d ${RELOCATING-0} : { *(.gnu.version_d)        } ${RELOCATING+ > datamem}
++  .gnu.version_r ${RELOCATING-0} : { *(.gnu.version_r)        } ${RELOCATING+ > datamem}
++
++  .rel.init    ${RELOCATING-0} : { *(.rel.init)       } ${RELOCATING+ > datamem}
++  .rela.init   ${RELOCATING-0} : { *(.rela.init)      } ${RELOCATING+ > datamem}
++  .rel.fini    ${RELOCATING-0} : { *(.rel.fini)       } ${RELOCATING+ > datamem}
++  .rela.fini   ${RELOCATING-0} : { *(.rela.fini)      } ${RELOCATING+ > datamem}
++  .rel.rodata  ${RELOCATING-0} :
++    {
++      *(.rel.rodata)
++      ${RELOCATING+*(.rel.rodata.*)}
++      ${RELOCATING+*(.rel.gnu.linkonce.r*)}
++    } ${RELOCATING+ > datamem}
++  .rela.rodata ${RELOCATING-0} :
++    {
++      *(.rela.rodata)
++      ${RELOCATING+*(.rela.rodata.*)}
++      ${RELOCATING+*(.rela.gnu.linkonce.r*)}
++    } ${RELOCATING+ > datamem}
++  ${OTHER_READONLY_RELOC_SECTIONS}
++  .rel.data    ${RELOCATING-0} :
++    {
++      *(.rel.data)
++      ${RELOCATING+*(.rel.data.*)}
++      ${RELOCATING+*(.rel.gnu.linkonce.d*)}
++    } ${RELOCATING+ > datamem}
++  .rela.data   ${RELOCATING-0} :
++    {
++      *(.rela.data)
++      ${RELOCATING+*(.rela.data.*)}
++      ${RELOCATING+*(.rela.gnu.linkonce.d*)}
++    } ${RELOCATING+ > datamem}
++  .rel.ctors   ${RELOCATING-0} : { *(.rel.ctors)      } ${RELOCATING+ > datamem}
++  .rela.ctors  ${RELOCATING-0} : { *(.rela.ctors)     } ${RELOCATING+ > datamem}
++  .rel.dtors   ${RELOCATING-0} : { *(.rel.dtors)      } ${RELOCATING+ > datamem}
++  .rela.dtors  ${RELOCATING-0} : { *(.rela.dtors)     } ${RELOCATING+ > datamem}
++  .rel.got     ${RELOCATING-0} : { *(.rel.got)                } ${RELOCATING+ > datamem}
++  .rela.got    ${RELOCATING-0} : { *(.rela.got)               } ${RELOCATING+ > datamem}
++  ${OTHER_GOT_RELOC_SECTIONS}
++  .rel.sdata   ${RELOCATING-0} :
++    {
++      *(.rel.sdata)
++      ${RELOCATING+*(.rel.sdata.*)}
++      ${RELOCATING+*(.rel.gnu.linkonce.s*)}
++    } ${RELOCATING+ > datamem}
++  .rela.sdata   ${RELOCATING-0} :
++    {
++      *(.rela.sdata)
++      ${RELOCATING+*(.rela.sdata.*)}
++      ${RELOCATING+*(.rela.gnu.linkonce.s*)}
++    } ${RELOCATING+ > datamem}
++  .rel.sbss    ${RELOCATING-0} : { *(.rel.sbss)               } ${RELOCATING+ > datamem}
++  .rela.sbss   ${RELOCATING-0} : { *(.rela.sbss)      } ${RELOCATING+ > datamem}
++  .rel.sdata2  ${RELOCATING-0} : { *(.rel.sdata2)     } ${RELOCATING+ > datamem}
++  .rela.sdata2 ${RELOCATING-0} : { *(.rela.sdata2)    } ${RELOCATING+ > datamem}
++  .rel.sbss2   ${RELOCATING-0} : { *(.rel.sbss2)      } ${RELOCATING+ > datamem}
++  .rela.sbss2  ${RELOCATING-0} : { *(.rela.sbss2)     } ${RELOCATING+ > datamem}
++  .rel.bss     ${RELOCATING-0} : { *(.rel.bss)                } ${RELOCATING+ > datamem}
++  .rela.bss    ${RELOCATING-0} : { *(.rela.bss)               } ${RELOCATING+ > datamem}
++  .rel.plt     ${RELOCATING-0} : { *(.rel.plt)                } ${RELOCATING+ > datamem}
++  .rela.plt    ${RELOCATING-0} : { *(.rela.plt)               } ${RELOCATING+ > datamem}
++  ${OTHER_PLT_RELOC_SECTIONS}
++
++  .init        ${RELOCATING-0} : 
++  { 
++    ${RELOCATING+${INIT_START}}
++    KEEP (*(.init))
++    ${RELOCATING+${INIT_END}}
++  } ${RELOCATING+ > datamem} =${NOP-0}
++
++  ${DATA_PLT-${BSS_PLT-${PLT}}}
++
++  .fini    ${RELOCATING-0} :
++  {
++    ${RELOCATING+${FINI_START}}
++    KEEP (*(.fini))
++    ${RELOCATING+${FINI_END}}
++  } ${RELOCATING+ > datamem} =${NOP-0}
++
++  ${WRITABLE_RODATA-${RODATA}}
++  .rodata1 ${RELOCATING-0} : { *(.rodata1) } ${RELOCATING+ > datamem}
++  ${CREATE_SHLIB-${SDATA2}}
++  ${CREATE_SHLIB-${SBSS2}}
++  ${RELOCATING+${OTHER_READONLY_SECTIONS}}
++  ${WRITABLE_RODATA+${RODATA}}
++  ${RELOCATING+${OTHER_READWRITE_SECTIONS}}
++  ${RELOCATING+. = ALIGN(${ALIGNMENT});}
++  ${RELOCATING+${CTOR}}
++  ${RELOCATING+${DTOR}}
++  ${DATA_PLT+${PLT}}
++  ${RELOCATING+${OTHER_GOT_SYMBOLS}}
++  .got                ${RELOCATING-0} : { *(.got.plt) *(.got) } ${RELOCATING+ > datamem}
++  ${CREATE_SHLIB+${SDATA2}}
++  ${CREATE_SHLIB+${SBSS2}}
++  ${TEXT_DYNAMIC-${DYNAMIC}}
++  /* We want the small data sections together, so single-instruction offsets
++     can access them all, and initialized data all before uninitialized, so
++     we can shorten the on-disk segment size.  */
++  .sdata   ${RELOCATING-0} : 
++  {
++    ${RELOCATING+${SDATA_START_SYMBOLS}}
++    *(.sdata) 
++    ${RELOCATING+*(.sdata.*)}
++    ${RELOCATING+*(.gnu.linkonce.s.*)}
++  } ${RELOCATING+ > datamem}
++  ${RELOCATING+${OTHER_GOT_SECTIONS}}
++  ${RELOCATING+_edata = .;}
++  ${RELOCATING+PROVIDE (edata = .);}
++  ${RELOCATING+__bss_start = .;}
++  ${RELOCATING+${OTHER_BSS_SYMBOLS}}
++  .sbss    ${RELOCATING-0} :
++  {
++    ${RELOCATING+PROVIDE (__sbss_start = .);}
++    ${RELOCATING+PROVIDE (___sbss_start = .);}
++    *(.dynsbss)
++    *(.sbss)
++    ${RELOCATING+*(.sbss.*)}
++    *(.scommon)
++    ${RELOCATING+PROVIDE (__sbss_end = .);}
++    ${RELOCATING+PROVIDE (___sbss_end = .);}
++  } ${RELOCATING+ > datamem}
++  ${BSS_PLT+${PLT}}
++  .bss     ${RELOCATING-0} :
++  {
++   *(.dynbss)
++   *(.bss)
++   ${RELOCATING+*(.bss.*)}
++   *(COMMON)
++   /* Align here to ensure that the .bss section occupies space up to
++      _end.  Align after .bss to ensure correct alignment even if the
++      .bss section disappears because there are no input sections.  */
++   ${RELOCATING+. = ALIGN(${ALIGNMENT});}
++  } ${RELOCATING+ > datamem}
++  ${RELOCATING+${OTHER_BSS_SECTIONS}}
++  ${RELOCATING+. = ALIGN(${ALIGNMENT});}
++  ${RELOCATING+_end = .;}
++  ${RELOCATING+${OTHER_BSS_END_SYMBOLS}}
++  ${RELOCATING+PROVIDE (end = .);}
++
++  /* Stabs debugging sections.  */
++  .stab 0 : { *(.stab) }
++  .stabstr 0 : { *(.stabstr) }
++  .stab.excl 0 : { *(.stab.excl) }
++  .stab.exclstr 0 : { *(.stab.exclstr) }
++  .stab.index 0 : { *(.stab.index) }
++  .stab.indexstr 0 : { *(.stab.indexstr) }
++
++  .comment 0 : { *(.comment) }
++
++  /* DWARF debug sections.
++     Symbols in the DWARF debugging sections are relative to the beginning
++     of the section so we begin them at 0.  */
++
++  /* DWARF 1 */
++  .debug          0 : { *(.debug) }
++  .line           0 : { *(.line) }
++
++  /* GNU DWARF 1 extensions */
++  .debug_srcinfo  0 : { *(.debug_srcinfo) }
++  .debug_sfnames  0 : { *(.debug_sfnames) }
++
++  /* DWARF 1.1 and DWARF 2 */
++  .debug_aranges  0 : { *(.debug_aranges) }
++  .debug_pubnames 0 : { *(.debug_pubnames) }
++
++  /* DWARF 2 */
++  .debug_info     0 : { *(.debug_info) }
++  .debug_abbrev   0 : { *(.debug_abbrev) }
++  .debug_line     0 : { *(.debug_line) }
++  .debug_frame    0 : { *(.debug_frame) }
++  .debug_str      0 : { *(.debug_str) }
++  .debug_loc      0 : { *(.debug_loc) }
++  .debug_macinfo  0 : { *(.debug_macinfo) }
++
++  /* SGI/MIPS DWARF 2 extensions */
++  .debug_weaknames 0 : { *(.debug_weaknames) }
++  .debug_funcnames 0 : { *(.debug_funcnames) }
++  .debug_typenames 0 : { *(.debug_typenames) }
++  .debug_varnames  0 : { *(.debug_varnames) }
++
++  ${RELOCATING+${OTHER_RELOCATING_SECTIONS}}
++
++  /* These must appear regardless of ${RELOCATING}.  */
++  ${OTHER_SECTIONS}
++}
++EOF
+--- a/opcodes/configure
++++ b/opcodes/configure
+@@ -11885,6 +11885,7 @@ if test x${all_targets} = xfalse ; then
+         bfd_tic4x_arch)         ta="$ta tic4x-dis.lo" ;;
+       bfd_tic54x_arch)        ta="$ta tic54x-dis.lo tic54x-opc.lo" ;;
+       bfd_tic80_arch)         ta="$ta tic80-dis.lo tic80-opc.lo" ;;
++      bfd_ubicom32_arch)              ta="$ta ubicom32-asm.lo ubicom32-desc.lo ubicom32-dis.lo ubicom32-ibld.lo ubicom32-opc.lo" using_cgen=yes ;;
+       bfd_v850_arch)          ta="$ta v850-opc.lo v850-dis.lo" ;;
+       bfd_v850e_arch)         ta="$ta v850-opc.lo v850-dis.lo" ;;
+       bfd_v850ea_arch)        ta="$ta v850-opc.lo v850-dis.lo" ;;
+--- a/opcodes/configure.in
++++ b/opcodes/configure.in
+@@ -245,6 +245,7 @@ if test x${all_targets} = xfalse ; then
+         bfd_tic4x_arch)         ta="$ta tic4x-dis.lo" ;;
+       bfd_tic54x_arch)        ta="$ta tic54x-dis.lo tic54x-opc.lo" ;;
+       bfd_tic80_arch)         ta="$ta tic80-dis.lo tic80-opc.lo" ;;
++      bfd_ubicom32_arch)              ta="$ta ubicom32-asm.lo ubicom32-desc.lo ubicom32-dis.lo ubicom32-ibld.lo ubicom32-opc.lo" using_cgen=yes ;;
+       bfd_v850_arch)          ta="$ta v850-opc.lo v850-dis.lo" ;;
+       bfd_v850e_arch)         ta="$ta v850-opc.lo v850-dis.lo" ;;
+       bfd_v850ea_arch)        ta="$ta v850-opc.lo v850-dis.lo" ;;
+--- a/opcodes/disassemble.c
++++ b/opcodes/disassemble.c
+@@ -77,6 +77,7 @@
+ #define ARCH_tic4x
+ #define ARCH_tic54x
+ #define ARCH_tic80
++#define ARCH_ubicom32
+ #define ARCH_v850
+ #define ARCH_vax
+ #define ARCH_w65
+@@ -386,6 +387,11 @@ disassembler (abfd)
+       disassemble = print_insn_tic80;
+       break;
+ #endif
++#ifdef ARCH_ubicom32
++    case bfd_arch_ubicom32:
++      disassemble = print_insn_ubicom32;
++      break;
++#endif
+ #ifdef ARCH_v850
+     case bfd_arch_v850:
+       disassemble = print_insn_v850;
+--- a/opcodes/Makefile.am
++++ b/opcodes/Makefile.am
+@@ -50,6 +50,7 @@ HFILES = \
+       sh-opc.h \
+       sh64-opc.h \
+       sysdep.h \
++      ubicom32-desc.h ubicom32-opc.h \
+       w65-opc.h \
+       xc16x-desc.h xc16x-opc.h \
+       xstormy16-desc.h xstormy16-opc.h \
+@@ -191,6 +192,11 @@ CFILES = \
+       tic54x-opc.c \
+       tic80-dis.c \
+       tic80-opc.c \
++      ubicom32-asm.c \
++      ubicom32-desc.c \
++      ubicom32-dis.c \
++      ubicom32-ibld.c \
++      ubicom32-opc.c \
+       v850-dis.c \
+       v850-opc.c \
+       vax-dis.c \
+@@ -333,6 +339,11 @@ ALL_MACHINES = \
+       tic54x-opc.lo \
+       tic80-dis.lo \
+       tic80-opc.lo \
++      ubicom32-asm.lo \
++      ubicom32-desc.lo \
++      ubicom32-dis.lo \
++      ubicom32-ibld.lo \
++      ubicom32-opc.lo \
+       v850-dis.lo \
+       v850-opc.lo \
+       vax-dis.lo \
+@@ -421,7 +432,7 @@ uninstall_libopcodes:
+       rm -f $(DESTDIR)$(bfdincludedir)/dis-asm.h
+ CLEANFILES = \
+-      stamp-ip2k stamp-m32c stamp-m32r stamp-fr30 stamp-frv \
++      stamp-ubicom32 stamp-ip2k stamp-m32c stamp-m32r stamp-fr30 stamp-frv \
+       stamp-openrisc stamp-iq2000 stamp-mep stamp-mt stamp-xstormy16 stamp-xc16x\
+       libopcodes.a stamp-lib dep.sed DEP DEPA DEP1 DEP2
+@@ -438,10 +449,11 @@ CGENDEPS = \
+       $(CGENDIR)/opc-opinst.scm \
+       cgen-asm.in cgen-dis.in cgen-ibld.in
+-CGEN_CPUS = fr30 frv ip2k m32c m32r mep mt openrisc xc16x xstormy16
++CGEN_CPUS = fr30 frv ip2k ubicom32 m32c m32r mep mt openrisc xc16x xstormy16
+ if CGEN_MAINT
+ IP2K_DEPS = stamp-ip2k
++UBICOM32_DEPS = stamp-ubicom32
+ M32C_DEPS = stamp-m32c
+ M32R_DEPS = stamp-m32r
+ FR30_DEPS = stamp-fr30
+@@ -454,6 +466,7 @@ XC16X_DEPS = stamp-xc16x
+ XSTORMY16_DEPS = stamp-xstormy16
+ else
+ IP2K_DEPS =
++UBICOM32_DEPS =
+ M32C_DEPS =
+ M32R_DEPS =
+ FR30_DEPS =
+@@ -482,6 +495,10 @@ run-cgen-all:
+ .PHONY: run-cgen-all
+ # For now, require developers to configure with --enable-cgen-maint.
++$(srcdir)/ubicom32-desc.h $(srcdir)/ubicom32-desc.c $(srcdir)/ubicom32-opc.h $(srcdir)/ubicom32-opc.c $(srcdir)/ubicom32-ibld.c $(srcdir)/ubicom32-asm.c $(srcdir)/ubicom32-dis.c: $(UBICOM32_DEPS)
++#     @true
++stamp-ubicom32: $(CGENDEPS) $(CPUDIR)/ubicom32.cpu $(CPUDIR)/ubicom32.opc
++      $(MAKE) run-cgen arch=ubicom32 prefix=ubicom32 options= extrafiles=
+ $(srcdir)/ip2k-desc.h $(srcdir)/ip2k-desc.c $(srcdir)/ip2k-opc.h $(srcdir)/ip2k-opc.c $(srcdir)/ip2k-ibld.c $(srcdir)/ip2k-asm.c $(srcdir)/ip2k-dis.c: $(IP2K_DEPS)
+       @true
+ stamp-ip2k: $(CGENDEPS) $(CPUDIR)/ip2k.cpu $(CPUDIR)/ip2k.opc
+@@ -823,6 +840,34 @@ ia64-gen.lo: ia64-gen.c $(INCDIR)/anside
+   ia64-opc-m.c ia64-opc-b.c ia64-opc-f.c ia64-opc-x.c \
+   ia64-opc-d.c
+ ia64-asmtab.lo: ia64-asmtab.c
++ubicom32-asm.lo: ubicom32-asm.c sysdep.h config.h $(INCDIR)/ansidecl.h \
++  $(BFD_H) $(INCDIR)/ansidecl.h $(INCDIR)/symcat.h $(INCDIR)/symcat.h \
++  ubicom32-desc.h $(INCDIR)/opcode/cgen-bitset.h $(INCDIR)/opcode/cgen.h \
++  $(INCDIR)/symcat.h $(INCDIR)/opcode/cgen-bitset.h ubicom32-opc.h \
++  opintl.h $(INCDIR)/xregex.h $(INCDIR)/xregex2.h $(INCDIR)/libiberty.h \
++  $(INCDIR)/ansidecl.h $(INCDIR)/safe-ctype.h
++ubicom32-desc.lo: ubicom32-desc.c sysdep.h config.h $(INCDIR)/ansidecl.h \
++  $(BFD_H) $(INCDIR)/ansidecl.h $(INCDIR)/symcat.h $(INCDIR)/symcat.h \
++  ubicom32-desc.h $(INCDIR)/opcode/cgen-bitset.h $(INCDIR)/opcode/cgen.h \
++  $(INCDIR)/symcat.h $(INCDIR)/opcode/cgen-bitset.h ubicom32-opc.h \
++  opintl.h $(INCDIR)/libiberty.h $(INCDIR)/ansidecl.h \
++  $(INCDIR)/xregex.h $(INCDIR)/xregex2.h
++ubicom32-dis.lo: ubicom32-dis.c sysdep.h config.h $(INCDIR)/ansidecl.h \
++  $(INCDIR)/dis-asm.h $(BFD_H) $(INCDIR)/ansidecl.h $(INCDIR)/symcat.h \
++  $(BFD_H) $(INCDIR)/symcat.h $(INCDIR)/libiberty.h $(INCDIR)/ansidecl.h \
++  ubicom32-desc.h $(INCDIR)/opcode/cgen-bitset.h $(INCDIR)/opcode/cgen.h \
++  $(INCDIR)/symcat.h $(INCDIR)/opcode/cgen-bitset.h ubicom32-opc.h \
++  opintl.h
++ubicom32-ibld.lo: ubicom32-ibld.c sysdep.h config.h $(INCDIR)/ansidecl.h \
++  $(INCDIR)/dis-asm.h $(BFD_H) $(INCDIR)/ansidecl.h $(INCDIR)/symcat.h \
++  $(BFD_H) $(INCDIR)/symcat.h ubicom32-desc.h $(INCDIR)/opcode/cgen-bitset.h \
++  $(INCDIR)/opcode/cgen.h $(INCDIR)/symcat.h $(INCDIR)/opcode/cgen-bitset.h \
++  ubicom32-opc.h opintl.h $(INCDIR)/safe-ctype.h
++ubicom32-opc.lo: ubicom32-opc.c sysdep.h config.h $(INCDIR)/ansidecl.h \
++  $(BFD_H) $(INCDIR)/ansidecl.h $(INCDIR)/symcat.h $(INCDIR)/symcat.h \
++  ubicom32-desc.h $(INCDIR)/opcode/cgen-bitset.h $(INCDIR)/opcode/cgen.h \
++  $(INCDIR)/symcat.h $(INCDIR)/opcode/cgen-bitset.h ubicom32-opc.h \
++  $(INCDIR)/libiberty.h $(INCDIR)/ansidecl.h $(INCDIR)/safe-ctype.h
+ ip2k-asm.lo: ip2k-asm.c sysdep.h config.h $(INCDIR)/ansidecl.h \
+   $(BFD_H) $(INCDIR)/symcat.h ip2k-desc.h $(INCDIR)/opcode/cgen-bitset.h \
+   $(INCDIR)/opcode/cgen.h $(INCDIR)/opcode/cgen-bitset.h \
+--- a/opcodes/Makefile.in
++++ b/opcodes/Makefile.in
+@@ -278,6 +278,7 @@ HFILES = \
+       sh-opc.h \
+       sh64-opc.h \
+       sysdep.h \
++      ubicom32-desc.h ubicom32-opc.h \
+       w65-opc.h \
+       xc16x-desc.h xc16x-opc.h \
+       xstormy16-desc.h xstormy16-opc.h \
+@@ -420,6 +421,11 @@ CFILES = \
+       tic54x-opc.c \
+       tic80-dis.c \
+       tic80-opc.c \
++      ubicom32-asm.c \
++      ubicom32-desc.c \
++      ubicom32-dis.c \
++      ubicom32-ibld.c \
++      ubicom32-opc.c \
+       v850-dis.c \
+       v850-opc.c \
+       vax-dis.c \
+@@ -562,6 +568,11 @@ ALL_MACHINES = \
+       tic54x-opc.lo \
+       tic80-dis.lo \
+       tic80-opc.lo \
++      ubicom32-asm.lo \
++      ubicom32-desc.lo \
++      ubicom32-dis.lo \
++      ubicom32-ibld.lo \
++      ubicom32-opc.lo \
+       v850-dis.lo \
+       v850-opc.lo \
+       vax-dis.lo \
+@@ -604,7 +615,7 @@ libopcodes_la_LDFLAGS = -release `cat ..
+ noinst_LIBRARIES = libopcodes.a
+ POTFILES = $(HFILES) $(CFILES)
+ CLEANFILES = \
+-      stamp-ip2k stamp-m32c stamp-m32r stamp-fr30 stamp-frv \
++      stamp-ip2k stamp-ubicom32 stamp-m32c stamp-m32r stamp-fr30 stamp-frv \
+       stamp-openrisc stamp-iq2000 stamp-mep stamp-mt stamp-xstormy16 stamp-xc16x\
+       libopcodes.a stamp-lib dep.sed DEP DEPA DEP1 DEP2
+@@ -619,9 +630,11 @@ CGENDEPS = \
+       $(CGENDIR)/opc-opinst.scm \
+       cgen-asm.in cgen-dis.in cgen-ibld.in
+-CGEN_CPUS = fr30 frv ip2k m32c m32r mep mt openrisc xc16x xstormy16
++CGEN_CPUS = fr30 frv ip2k ubicom32 m32c m32r mep mt openrisc xc16x xstormy16
+ @CGEN_MAINT_FALSE@IP2K_DEPS = 
+ @CGEN_MAINT_TRUE@IP2K_DEPS = stamp-ip2k
++@CGEN_MAINT_FALSE@UBICOM32_DEPS = 
++@CGEN_MAINT_TRUE@UBICOM32_DEPS = stamp-ubicom32
+ @CGEN_MAINT_FALSE@M32C_DEPS = 
+ @CGEN_MAINT_TRUE@M32C_DEPS = stamp-m32c
+ @CGEN_MAINT_FALSE@M32R_DEPS = 
+@@ -1035,6 +1048,11 @@ run-cgen-all:
+ .PHONY: run-cgen-all
+ # For now, require developers to configure with --enable-cgen-maint.
++$(srcdir)/ubicom32-desc.h $(srcdir)/ubicom32-desc.c $(srcdir)/ubicom32-opc.h $(srcdir)/ubicom32-opc.c $(srcdir)/ubicom32-ibld.c $(srcdir)/ubicom32-asm.c $(srcdir)/ubicom32-dis.c: $(UBICOM32_DEPS)
++#     @true
++stamp-ubicom32: $(CGENDEPS) $(CPUDIR)/ubicom32.cpu $(CPUDIR)/ubicom32.opc
++      $(MAKE) run-cgen arch=ubicom32 prefix=ubicom32 \
++              archfile=$(CPUDIR)/ubicom32.cpu opcfile=$(CPUDIR)/ubicom32.opc options= extrafiles=
+ $(srcdir)/ip2k-desc.h $(srcdir)/ip2k-desc.c $(srcdir)/ip2k-opc.h $(srcdir)/ip2k-opc.c $(srcdir)/ip2k-ibld.c $(srcdir)/ip2k-asm.c $(srcdir)/ip2k-dis.c: $(IP2K_DEPS)
+       @true
+ stamp-ip2k: $(CGENDEPS) $(CPUDIR)/ip2k.cpu $(CPUDIR)/ip2k.opc
+@@ -1375,6 +1393,34 @@ ia64-gen.lo: ia64-gen.c $(INCDIR)/anside
+   ia64-opc-m.c ia64-opc-b.c ia64-opc-f.c ia64-opc-x.c \
+   ia64-opc-d.c
+ ia64-asmtab.lo: ia64-asmtab.c
++ubicom32-asm.lo: ubicom32-asm.c sysdep.h config.h $(INCDIR)/ansidecl.h \
++  $(BFD_H) $(INCDIR)/ansidecl.h $(INCDIR)/symcat.h $(INCDIR)/symcat.h \
++  ubicom32-desc.h $(INCDIR)/opcode/cgen-bitset.h $(INCDIR)/opcode/cgen.h \
++  $(INCDIR)/symcat.h $(INCDIR)/opcode/cgen-bitset.h ubicom32-opc.h \
++  opintl.h $(INCDIR)/xregex.h $(INCDIR)/xregex2.h $(INCDIR)/libiberty.h \
++  $(INCDIR)/ansidecl.h $(INCDIR)/safe-ctype.h
++ubicom32-desc.lo: ubicom32-desc.c sysdep.h config.h $(INCDIR)/ansidecl.h \
++  $(BFD_H) $(INCDIR)/ansidecl.h $(INCDIR)/symcat.h $(INCDIR)/symcat.h \
++  ubicom32-desc.h $(INCDIR)/opcode/cgen-bitset.h $(INCDIR)/opcode/cgen.h \
++  $(INCDIR)/symcat.h $(INCDIR)/opcode/cgen-bitset.h ubicom32-opc.h \
++  opintl.h $(INCDIR)/libiberty.h $(INCDIR)/ansidecl.h \
++  $(INCDIR)/xregex.h $(INCDIR)/xregex2.h
++ubicom32-dis.lo: ubicom32-dis.c sysdep.h config.h $(INCDIR)/ansidecl.h \
++  $(INCDIR)/dis-asm.h $(BFD_H) $(INCDIR)/ansidecl.h $(INCDIR)/symcat.h \
++  $(BFD_H) $(INCDIR)/symcat.h $(INCDIR)/libiberty.h $(INCDIR)/ansidecl.h \
++  ubicom32-desc.h $(INCDIR)/opcode/cgen-bitset.h $(INCDIR)/opcode/cgen.h \
++  $(INCDIR)/symcat.h $(INCDIR)/opcode/cgen-bitset.h ubicom32-opc.h \
++  opintl.h
++ubicom32-ibld.lo: ubicom32-ibld.c sysdep.h config.h $(INCDIR)/ansidecl.h \
++  $(INCDIR)/dis-asm.h $(BFD_H) $(INCDIR)/ansidecl.h $(INCDIR)/symcat.h \
++  $(BFD_H) $(INCDIR)/symcat.h ubicom32-desc.h $(INCDIR)/opcode/cgen-bitset.h \
++  $(INCDIR)/opcode/cgen.h $(INCDIR)/symcat.h $(INCDIR)/opcode/cgen-bitset.h \
++  ubicom32-opc.h opintl.h $(INCDIR)/safe-ctype.h
++ubicom32-opc.lo: ubicom32-opc.c sysdep.h config.h $(INCDIR)/ansidecl.h \
++  $(BFD_H) $(INCDIR)/ansidecl.h $(INCDIR)/symcat.h $(INCDIR)/symcat.h \
++  ubicom32-desc.h $(INCDIR)/opcode/cgen-bitset.h $(INCDIR)/opcode/cgen.h \
++  $(INCDIR)/symcat.h $(INCDIR)/opcode/cgen-bitset.h ubicom32-opc.h \
++  $(INCDIR)/libiberty.h $(INCDIR)/ansidecl.h $(INCDIR)/safe-ctype.h
+ ip2k-asm.lo: ip2k-asm.c sysdep.h config.h $(INCDIR)/ansidecl.h \
+   $(BFD_H) $(INCDIR)/symcat.h ip2k-desc.h $(INCDIR)/opcode/cgen-bitset.h \
+   $(INCDIR)/opcode/cgen.h $(INCDIR)/opcode/cgen-bitset.h \
+--- /dev/null
++++ b/opcodes/ubicom32-asm.c
+@@ -0,0 +1,1863 @@
++/* Assembler interface for targets using CGEN. -*- C -*-
++   CGEN: Cpu tools GENerator
++
++   THIS FILE IS MACHINE GENERATED WITH CGEN.
++   - the resultant file is machine generated, cgen-asm.in isn't
++
++   Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2005, 2007
++   Free Software Foundation, Inc.
++
++   This file is part of libopcodes.
++
++   This library 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 3, or (at your option)
++   any later version.
++
++   It 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.,
++   51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
++
++
++/* ??? Eventually more and more of this stuff can go to cpu-independent files.
++   Keep that in mind.  */
++
++#include "sysdep.h"
++#include <stdio.h>
++#include "ansidecl.h"
++#include "bfd.h"
++#include "symcat.h"
++#include "ubicom32-desc.h"
++#include "ubicom32-opc.h"
++#include "opintl.h"
++#include "xregex.h"
++#include "libiberty.h"
++#include "safe-ctype.h"
++
++#undef  min
++#define min(a,b) ((a) < (b) ? (a) : (b))
++#undef  max
++#define max(a,b) ((a) > (b) ? (a) : (b))
++
++static const char * parse_insn_normal
++  (CGEN_CPU_DESC, const CGEN_INSN *, const char **, CGEN_FIELDS *);
++\f
++/* -- assembler routines inserted here.  */
++
++/* -- asm.c */
++
++/* Directly addressable registers on the UBICOM32.
++ */
++
++#define RW  0  /* read/write */
++#define RO  1  /* read-only  */
++#define WO  2  /* write-only */
++
++struct ubicom32_cgen_data_space_map ubicom32_cgen_data_space_map_mercury[] = {
++      { 0x0,          "d0", RW, },    /* data registers */
++      /* d1, d2 and d3 are later */
++      { 0x10,         "d4", RW, },
++      { 0x14,         "d5", RW, },
++      { 0x18,         "d6", RW, },
++      { 0x1c,         "d7", RW, },
++      { 0x20,         "d8", RW, },
++      { 0x24,         "d9", RW, },
++      { 0x28,         "d10", RW, },
++      { 0x2c,         "d11", RW, },
++      { 0x30,         "d12", RW, },
++      { 0x34,         "d13", RW, },
++      { 0x38,         "d14", RW, },
++      { 0x3c,         "d15", RW, },
++      { 0x4,          "d1", RW, },    /* put them here where they work */
++      { 0x8,          "d2", RW, },
++      { 0xc,          "d3", RW, },
++      { A0_ADDRESS,   "a0", RW, },    /* address registers */
++      { A1_ADDRESS,   "a1", RW, },
++      { A2_ADDRESS,   "a2", RW, },
++      { A3_ADDRESS,   "a3", RW, },
++      { A4_ADDRESS,   "a4", RW, },
++      { A5_ADDRESS,   "a5", RW, },
++      { A6_ADDRESS,   "a6", RW, },
++      { A7_ADDRESS,   "sp", RW, },    /* sp is a7; first so we use it */
++      { A7_ADDRESS,   "a7", RW, },
++      { 0xa0,         "mac_hi", RW, },
++      { 0xa4,         "mac_lo", RW, },
++      { 0xa8,         "mac_rc16", RW, },
++      { 0xac,         "source3", RW, },
++      { 0xac,         "source_3", RW, },
++      { 0xb0,         "context_cnt", RO,},
++      { 0xb0,         "inst_cnt", RO,},
++      { 0xb4,         "csr", RW, },
++      { 0xb8,         "rosr", RO, },
++      { 0xbc,         "iread_data", RW, },
++      { 0xc0,         "int_mask0", RW, },
++      { 0xc4,         "int_mask1", RW, },
++      /* 0xc8 - 0xcf reserved for future interrupt masks */
++      { 0xd0,         "pc", RW, },
++      /* 0xd4 - ff reserved */
++      { 0x100,        "chip_id", RO, },
++      { 0x104,        "int_stat0", RO, },
++      { 0x108,        "int_stat1", RO, },
++      /* 0x10c - 0x113 reserved for future interrupt masks */
++      { 0x114,        "int_set0", WO, },
++      { 0x118,        "int_set1", WO, },
++        /* 0x11c - 0x123 reserved for future interrupt set */
++      { 0x124,        "int_clr0", WO, },
++        { 0x128,        "int_clr1", WO, },
++        /* 0x13c - 0x133 reserved for future interrupt clear */
++      { 0x134,        "global_ctrl", RW, },
++      { 0x13c,        "mt_active_set", WO, },
++      { 0x140,        "mt_active_clr", WO, },
++      { 0x138,        "mt_active", RO, },
++      { 0x148,        "mt_dbg_active_set", WO, },
++      { 0x144,        "mt_dbg_active", RO, },
++      { 0x14C,        "mt_en", RW, },
++      { 0x150,        "mt_hpri", RW, }, 
++      { 0x150,        "mt_pri", RW, }, 
++      { 0x154,        "mt_hrt", RW, },
++      { 0x154,        "mt_sched", RW, },
++      { 0x15C,        "mt_break_clr", WO, },
++      { 0x158,        "mt_break", RO, },
++      { 0x160,        "mt_single_step", RW, },
++      { 0x164,        "mt_min_delay_en", RW, },
++      { 0x164,        "mt_min_del_en", RW, },
++
++      { 0x16c,        "perr_addr", RO, },
++      { 0x178,        "dcapt_tnum", RO, },
++      { 0x174,        "dcapt_pc", RO, },
++      { 0x170,        "dcapt", RW, },
++      /* 0x17c - 0x1ff reserved */
++      { 0x17c,        "mt_dbg_active_clr", WO, },
++      { 0x180,        "scratchpad0", RW, },
++      { 0x184,        "scratchpad1", RW, },
++      { 0x188,        "scratchpad2", RW, },
++      { 0x18c,        "scratchpad3", RW, },
++
++      { 0x0,          0, RW, },
++};
++
++struct ubicom32_cgen_data_space_map ubicom32_cgen_data_space_map_mars[] = {
++      { 0x0,          "d0", RW, },    /* data registers */
++      /* d1, d2 and d3 are later */
++      { 0x10,         "d4", RW, },
++      { 0x14,         "d5", RW, },
++      { 0x18,         "d6", RW, },
++      { 0x1c,         "d7", RW, },
++      { 0x20,         "d8", RW, },
++      { 0x24,         "d9", RW, },
++      { 0x28,         "d10", RW, },
++      { 0x2c,         "d11", RW, },
++      { 0x30,         "d12", RW, },
++      { 0x34,         "d13", RW, },
++      { 0x38,         "d14", RW, },
++      { 0x3c,         "d15", RW, },
++      { 0x4,          "d1", RW, },    /* put them here where they work */
++      { 0x8,          "d2", RW, },
++      { 0xc,          "d3", RW, },
++      { A0_ADDRESS,   "a0", RW, },    /* address registers */
++      { A1_ADDRESS,   "a1", RW, },
++      { A2_ADDRESS,   "a2", RW, },
++      { A3_ADDRESS,   "a3", RW, },
++      { A4_ADDRESS,   "a4", RW, },
++      { A5_ADDRESS,   "a5", RW, },
++      { A6_ADDRESS,   "a6", RW, },
++      { A7_ADDRESS,   "sp", RW, },    /* sp is a7; first so we use it */
++      { A7_ADDRESS,   "a7", RW, },
++      { 0xa0,         "mac_hi", RW, },
++      { 0xa0,         "acc0_hi", RW, }, /* mac_hi and mac_lo are also known as acc0_hi and acc0_lo */
++      { 0xa4,         "mac_lo", RW, },
++      { 0xa4,         "acc0_lo", RW, },
++      { 0xa8,         "mac_rc16", RW, },
++      { 0xac,         "source3", RW, },
++      { 0xac,         "source_3", RW, },
++      { 0xb0,         "context_cnt", RO,},
++      { 0xb0,         "inst_cnt", RO,},
++      { 0xb4,         "csr", RW, },
++      { 0xb8,         "rosr", RO, },
++      { 0xbc,         "iread_data", RW, },
++      { 0xc0,         "int_mask0", RW, },
++      { 0xc4,         "int_mask1", RW, },
++      /* 0xc8 - 0xcf reserved for future interrupt masks */
++      { 0xd0,         "pc", RW, },
++      { 0xd4,         "trap_cause", RW, },
++      { 0xd8,         "acc1_hi", RW, }, /* Defines for acc1 */
++      { 0xdc,         "acc1_lo", RW, },
++      { 0xe0,         "previous_pc", RO, },
++
++      /* 0xe4 - ff reserved */
++      { 0x100,        "chip_id", RO, },
++      { 0x104,        "int_stat0", RO, },
++      { 0x108,        "int_stat1", RO, },
++      /* 0x10c - 0x113 reserved for future interrupt masks */
++      { 0x114,        "int_set0", WO, },
++      { 0x118,        "int_set1", WO, },
++        /* 0x11c - 0x123 reserved for future interrupt set */
++      { 0x124,        "int_clr0", WO, },
++        { 0x128,        "int_clr1", WO, },
++        /* 0x130 - 0x133 reserved for future interrupt clear */
++      { 0x134,        "global_ctrl", RW, },
++      { 0x13c,        "mt_active_set", WO, },
++      { 0x140,        "mt_active_clr", WO, },
++      { 0x138,        "mt_active", RO, },
++      { 0x148,        "mt_dbg_active_set", WO, },
++      { 0x144,        "mt_dbg_active", RO, },
++      { 0x14C,        "mt_en", RW, },
++      { 0x150,        "mt_hpri", RW, }, 
++      { 0x150,        "mt_pri", RW, }, 
++      { 0x154,        "mt_hrt", RW, },
++      { 0x154,        "mt_sched", RW, },
++      { 0x15C,        "mt_break_clr", WO, },
++      { 0x158,        "mt_break", RO, },
++      { 0x160,        "mt_single_step", RW, },
++      { 0x164,        "mt_min_delay_en", RW, },
++      { 0x164,        "mt_min_del_en", RW, },
++      { 0x168,        "mt_break_set", WO, },
++      /* 0x16c - 0x16f reserved */
++      { 0x170,        "dcapt", RW, },
++      /* 0x174 - 0x17b reserved */
++      { 0x17c,        "mt_dbg_active_clr", WO, },
++      { 0x180,        "scratchpad0", RW, },
++      { 0x184,        "scratchpad1", RW, },
++      { 0x188,        "scratchpad2", RW, },
++      { 0x18c,        "scratchpad3", RW, },
++
++      /* 0x190 - 0x19f Reserved */
++      { 0x1a0,        "chip_cfg", RW, },
++      { 0x1a4,        "mt_i_blocked", RO, },
++      { 0x1a8,        "mt_d_blocked", RO, },
++      { 0x1ac,        "mt_i_blocked_set", WO},
++      { 0x1b0,        "mt_d_blocked_set", WO},
++      { 0x1b4,        "mt_blocked_clr", WO},
++      { 0x1b8,        "mt_trap_en", RW, },
++      { 0x1bc,        "mt_trap", RO, },
++      { 0x1c0,        "mt_trap_set", WO, },
++      { 0x1c4,        "mt_trap_clr", WO, },
++      /* 0x1c8-0x1FF Reserved */
++      { 0x200,        "i_range0_hi", RW},
++      { 0x204,        "i_range1_hi", RW},
++      { 0x208,        "i_range2_hi", RW},
++      { 0x20c,        "i_range3_hi", RW},
++
++      /* 0x210-0x21f Reserved */
++      { 0x220,        "i_range0_lo", RW},
++      { 0x224,        "i_range1_lo", RW},
++      { 0x228,        "i_range2_lo", RW},
++      { 0x22c,        "i_range3_lo", RW},
++
++      /* 0x230-0x23f Reserved */
++      { 0x240,        "i_range0_en", RW},
++      { 0x244,        "i_range1_en", RW},
++      { 0x248,        "i_range2_en", RW},
++      { 0x24c,        "i_range3_en", RW},
++
++      /* 0x250-0x25f Reserved */
++      { 0x260,        "d_range0_hi", RW},
++      { 0x264,        "d_range1_hi", RW},
++      { 0x268,        "d_range2_hi", RW},
++      { 0x26c,        "d_range3_hi", RW},
++      { 0x270,        "d_range4_hi", RW},
++
++      /* 0x274-0x27f Reserved */
++      { 0x280,        "d_range0_lo", RW},
++      { 0x284,        "d_range1_lo", RW},
++      { 0x288,        "d_range2_lo", RW},
++      { 0x28c,        "d_range3_lo", RW},
++      { 0x290,        "d_range4_lo", RW},
++
++      /* 0x294-0x29f Reserved */
++      { 0x2a0,        "d_range0_en", RW},
++      { 0x2a4,        "d_range1_en", RW},
++      { 0x2a8,        "d_range2_en", RW},
++      { 0x2ac,        "d_range3_en", RW},
++      { 0x2b0,        "d_range4_en", RW},
++
++      /* 0x2b4-0x3ff Reserved */
++
++      { 0x0,          0, RW, },
++};
++
++/* t_is_set will be 1 if .t is set for the madd.2 and msub.2 instructions */
++static unsigned char t_is_set =0;
++
++static const char *
++parse_t_is_set_for_addsub (
++                         CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
++                         const char **strp,
++                         CGEN_KEYWORD *keyword_table,
++                         long *valuep)
++{
++  const char *errmsg;
++
++  t_is_set = 0;
++
++  errmsg = cgen_parse_keyword (cd, strp, keyword_table, valuep);
++  if (errmsg)
++    {
++      t_is_set = 0;
++
++      return errmsg;
++    }
++
++  if((int)*valuep)
++     t_is_set = 1;
++
++  return NULL;
++}
++
++char myerrmsg[128];
++
++/* 
++ * If accumulator is selected for madd.2 and msub.2 instructions then
++ * the T bit should not be selected. Flag an assembler error in those
++ * cases.
++ */
++static const char *
++parse_acc_for_addsub (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
++                    const char **strp,
++                    CGEN_KEYWORD *keyword_table,
++                    long *valuep)
++{
++  const char *errmsg;
++
++  errmsg = cgen_parse_keyword (cd, strp, keyword_table, valuep);
++  if (errmsg)
++    {
++      t_is_set = 0;
++
++      return errmsg;
++    }
++
++  
++  if(t_is_set)
++    {
++      /* This is erroneous. */
++      sprintf(myerrmsg, "Extenstion \".t\" is illegal when using acc%d as Source 2 register.", (int)*valuep);
++      t_is_set=0;
++      return (myerrmsg);
++    }
++
++  t_is_set=0;
++  return NULL;
++}
++
++/*
++ * For dsp madd/msub cases if S2 is a data register then t_is_set flag should be set to zero.
++ */
++static const char *
++parse_dr_for_addsub (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
++                   const char **strp,
++                   CGEN_KEYWORD *keyword_table,
++                   long *valuep)
++{
++  const char *errmsg;
++
++  errmsg = cgen_parse_keyword (cd, strp, keyword_table, valuep);
++  if (errmsg)
++    {
++      t_is_set = 0;
++
++      return errmsg;
++    }
++  t_is_set=0;
++  return NULL;
++}
++
++static const char *
++parse_bit5 (CGEN_CPU_DESC cd,
++          const char **strp,
++          int opindex,
++          long *valuep)
++{
++  const char *errmsg;
++  char mode = 0;
++  long count = 0;
++  unsigned long value;
++
++  if (strncmp (*strp, "%bit", 4) == 0)
++    {
++      *strp += 4;
++      mode = 1;
++    }
++  else if (strncmp (*strp, "%msbbit", 7) == 0)
++    {
++      *strp += 7;
++      mode = 2;
++    }
++  else if (strncmp (*strp, "%lsbbit", 7) == 0)
++    {
++      *strp += 7;
++      mode = 3;
++    }
++
++  errmsg = cgen_parse_unsigned_integer (cd, strp, opindex, valuep);
++  if (errmsg) {
++    return errmsg;
++  }
++
++  if (mode) {
++    value = (unsigned long) *valuep;
++    if (value == 0) {
++      errmsg = _("Attempt to find bit index of 0");
++      return errmsg;
++    }
++    
++    if (mode == 1) {
++      count = 31;
++      while ((value & 0x80000000) == 0) {
++        count--;
++        value <<= 1;
++      }
++      if ((value & 0x7FFFFFFF) != 0) {
++        errmsg = _("More than one bit set in bitmask");
++        return errmsg;
++      }
++    } else if (mode == 2) {
++      count = 31;
++      while ((value & 0x80000000) == 0) {
++        count--;
++        value <<= 1;
++      }
++    } else if (mode == 3) {
++      count = 0;
++      while ((value & 0x00000001) == 0) {
++        count++;
++        value >>= 1;
++      }
++    }
++    
++    *valuep = count;
++  }
++
++  return errmsg;
++}
++
++/*
++ * For dsp madd/msub cases if S2 is a #bit5 then t_is_set flag should be set to zero.
++ */
++static const char *
++parse_bit5_for_addsub (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
++                     const char **strp,
++                     int opindex,
++                     long *valuep)
++{
++  const char *errmsg;
++
++  errmsg = parse_bit5(cd, strp, opindex, valuep);
++  if (errmsg)
++    {
++      t_is_set = 0;
++
++      return errmsg;
++    }
++  t_is_set=0;
++  return NULL;
++}
++
++/* Parse signed 4 bit immediate value, being careful (hacky) to avoid
++   eating a `++' that might be present */
++static const char *
++parse_imm4 (CGEN_CPU_DESC cd,
++          const char **strp,
++          int opindex,
++          long *valuep,
++          int size)
++{
++  const char *errmsg;
++  char *plusplus;
++  long value;
++
++  plusplus = strstr(*strp, "++");
++  if (plusplus)
++    *plusplus = 0;
++  errmsg = cgen_parse_signed_integer (cd, strp, opindex, &value);
++  if (plusplus)
++    *plusplus = '+';
++
++  if (errmsg == NULL)
++    {
++      if ((size == 2 && (value % 2)) ||
++          (size == 4 && (value % 4)))
++      errmsg = _("unaligned increment");
++      else if ((size == 1 && (value < -8 || value > 7)) ||
++          (size == 2 && (value < -16 || value > 15)) ||
++          (size == 4 && (value < -32 || value > 31)))
++      errmsg = _("out of bounds increment");
++      else
++        *valuep = value;
++    }
++  return errmsg;
++}
++
++/* as above, for single byte addresses */
++static const char *
++parse_imm4_1 (CGEN_CPU_DESC cd,
++            const char **strp,
++            int opindex,
++            long *valuep)
++{
++  return parse_imm4 (cd, strp, opindex, valuep, 1);
++}
++
++/* as above, for half-word addresses */
++static const char *
++parse_imm4_2 (CGEN_CPU_DESC cd,
++            const char **strp,
++            int opindex,
++            long *valuep)
++{
++  return parse_imm4 (cd, strp, opindex, valuep, 2);
++}
++
++/* as above, for word addresses */
++static const char *
++parse_imm4_4 (CGEN_CPU_DESC cd,
++            const char **strp,
++            int opindex,
++            long *valuep)
++{
++  return parse_imm4 (cd, strp, opindex, valuep, 4);
++}
++
++/* Parse a direct address.  This can be either `$xx' or a Register
++   Mnemonic.
++ */
++static const char *
++parse_direct_addr (CGEN_CPU_DESC cd,
++                 const char **strp,
++                 int opindex,
++                 long *valuep,
++                 int isdest)
++{
++  const char *errmsg = NULL;
++  bfd_vma value;
++  struct ubicom32_cgen_data_space_map *cur;
++  size_t len;
++
++  if(cd->machs & (1<<MACH_IP3035))
++    {
++      /* cpu is mercury */
++      cur = ubicom32_cgen_data_space_map_mercury;
++    }
++  else
++    {
++      /* cpu is mars */
++      cur = ubicom32_cgen_data_space_map_mars;
++    }
++
++  /* First, try to look for the literal register name. */
++  for (; cur->name; cur++)
++    if (strncasecmp(cur->name, *strp, (len = strlen(cur->name))) == 0 &&
++        !ISALNUM((*strp)[len]) && (*strp)[len] != '_' )
++      {
++      *strp += len;
++        /* fail if specifying a read-only register as a destination */
++      if (isdest && cur->type == RO)
++        return _("attempt to write to read-only register");
++      
++      /* fail if specifying a write-only register as a source */
++      if ((isdest==0) && cur->type == WO)
++        return _("attempt to read a write-only register");
++      value = cur->address;
++      errmsg = NULL;
++      break;
++      }
++  
++  /* Not found: try parsing it as a literal */
++  if (cur->name == NULL)
++    {
++      char *plusplus;
++      if (**strp == '(')
++      {
++        return _("parentheses are reserved for indirect addressing");
++      }
++
++      if (strncasecmp(*strp, "%f", 2) == 0)
++      {
++        *valuep = 0;
++        return NULL;
++      }
++
++      /* we want to avoid parsing a negative post-increment expression as a numeric
++       expression because the parser assumes zeroes exist between the pluses and
++       issues an extraneous warning message. */
++      plusplus = strstr(*strp, "++");
++      if (plusplus)
++      *plusplus = 0;
++      errmsg = cgen_parse_signed_integer (cd, strp, opindex, &value);
++      if (plusplus)
++      *plusplus = '+';
++
++      if (errmsg)
++      return errmsg;
++    }
++
++  value &= 0x3ff;
++  *valuep = value;
++  return errmsg;
++}
++
++static const char *
++parse_d_direct_addr (CGEN_CPU_DESC cd,
++                   const char **strp,
++                   int opindex,
++                   long *valuep)
++{
++  return parse_direct_addr (cd, strp, opindex, valuep, 1);
++}
++
++static const char *
++parse_s1_direct_addr (CGEN_CPU_DESC cd,
++                    const char **strp,
++                    int opindex,
++                    long *valuep)
++{
++  return parse_direct_addr (cd, strp, opindex, valuep, 0);
++}
++
++/* support for source-1 and destination operand 7-bit immediates for indirect addressing */
++static const char *imm7_1_rangemsg = "7-bit byte immediate value out of range";
++static const char *imm7_2_rangemsg = "7-bit halfword immediate value out of range";
++static const char *imm7_4_rangemsg = "7-bit word immediate value out of range";
++static const char *imm7_pdec_rangemsg = "Pdec offset out of range. Allowed range is >=4 and <=512.";
++static const char *imm7_2_maskmsg = "7-bit halfword immediate not a multiple of 2";
++static const char *imm7_4_maskmsg = "7-bit word immediate not a multiple of 4";
++
++/* Parse 7-bit immediates, allow %lo() operator */
++static const char *
++parse_imm7_basic (CGEN_CPU_DESC cd,
++                const char **strp,
++                int opindex,
++                unsigned long *valuep,
++                const char *rangemsg,
++                const char *maskmsg,
++                bfd_vma max,
++                int mask,
++                int reloc)
++{
++  const char *errmsg;
++  enum cgen_parse_operand_result result_type = CGEN_PARSE_OPERAND_RESULT_NUMBER;
++  bfd_vma value;
++  int newreloc;
++
++  /* in this case we want low 7-bits to accompany the 24-bit immediate of a moveai instruction */
++  if (strncasecmp (*strp, "%lo(", 4) == 0)
++    {
++      *strp += 4;
++      errmsg = cgen_parse_address (cd, strp, opindex, reloc,
++                                 &result_type, &value);
++      if (**strp != ')')
++      return _("missing `)'");
++      ++*strp;
++      if (errmsg == NULL
++        && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
++      value &= 0x7f;  /* always want 7 bits, regardless of imm7 type */
++      *valuep = value;
++      return errmsg;
++    }
++  else if (strncasecmp (*strp, "%got_lo(", strlen("%got_lo(")) == 0)
++    {
++      *strp += strlen("%got_lo(");
++
++      /* Switch the relocation to the GOT relocation. */
++      switch(reloc)
++      {
++      case BFD_RELOC_UBICOM32_LO7_S:
++        reloc = BFD_RELOC_UBICOM32_GOT_LO7_S;
++        break;
++      case BFD_RELOC_UBICOM32_LO7_2_S:
++        reloc = BFD_RELOC_UBICOM32_GOT_LO7_2_S;
++        break;
++      case BFD_RELOC_UBICOM32_LO7_4_S:
++        reloc = BFD_RELOC_UBICOM32_GOT_LO7_4_S;
++        break;
++      case BFD_RELOC_UBICOM32_LO7_D:
++        reloc = BFD_RELOC_UBICOM32_GOT_LO7_D;
++        break;
++      case BFD_RELOC_UBICOM32_LO7_2_D:
++        reloc = BFD_RELOC_UBICOM32_GOT_LO7_2_D;
++        break;
++      case BFD_RELOC_UBICOM32_LO7_4_D:
++        reloc = BFD_RELOC_UBICOM32_GOT_LO7_4_D;
++        break;
++      }
++      errmsg = cgen_parse_address (cd, strp, opindex, reloc,
++                                 &result_type, &value);
++      if (**strp != ')')
++      return _("missing `)'");
++      ++*strp;
++      if (errmsg == NULL
++        && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
++      value &= 0x7f;  /* always want 7 bits, regardless of imm7 type */
++      *valuep = value;
++      return errmsg;
++    }
++  else if (strncasecmp (*strp, "%funcdesc_got_lo(", strlen("%funcdesc_got_lo(")) == 0)
++    {
++      *strp += strlen("%funcdesc_got_lo(");
++
++      /* Switch the relocation to the GOT relocation. */
++      switch(reloc)
++      {
++      case BFD_RELOC_UBICOM32_LO7_S:
++        reloc = BFD_RELOC_UBICOM32_FUNCDESC_GOT_LO7_S;
++        break;
++      case BFD_RELOC_UBICOM32_LO7_2_S:
++        reloc = BFD_RELOC_UBICOM32_FUNCDESC_GOT_LO7_2_S;
++        break;
++      case BFD_RELOC_UBICOM32_LO7_4_S:
++        reloc = BFD_RELOC_UBICOM32_FUNCDESC_GOT_LO7_4_S;
++        break;
++      case BFD_RELOC_UBICOM32_LO7_D:
++        reloc = BFD_RELOC_UBICOM32_FUNCDESC_GOT_LO7_D;
++        break;
++      case BFD_RELOC_UBICOM32_LO7_2_D:
++        reloc = BFD_RELOC_UBICOM32_FUNCDESC_GOT_LO7_2_D;
++        break;
++      case BFD_RELOC_UBICOM32_LO7_4_D:
++        reloc = BFD_RELOC_UBICOM32_FUNCDESC_GOT_LO7_4_D;
++        break;
++      }
++      errmsg = cgen_parse_address (cd, strp, opindex, reloc,
++                                 &result_type, &value);
++      if (**strp != ')')
++      return _("missing `)'");
++      ++*strp;
++      if (errmsg == NULL
++        && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
++      value &= 0x7f;  /* always want 7 bits, regardless of imm7 type */
++      *valuep = value;
++      return errmsg;
++    }
++  else
++    {
++      if (**strp == '(')
++      {
++        return _("parentheses are reserved for indirect addressing");
++      }
++
++      errmsg = cgen_parse_unsigned_integer (cd, strp, opindex, &value);
++    }
++
++  if (errmsg == NULL)
++    {
++      if (value > max)
++      return rangemsg;
++      if (value & mask)
++      return maskmsg;
++    }
++
++  *valuep = value & max;
++  return errmsg;
++}
++
++/* Parse 7-bit immediates, allow %lo() operator */
++static const char *
++parse_imm7_pdec (CGEN_CPU_DESC cd,
++               const char **strp,
++               int opindex,
++               unsigned long *valuep,
++               const char *rangemsg,
++               const char *maskmsg,
++               int reloc)
++{
++  const char *errmsg;
++  enum cgen_parse_operand_result result_type = CGEN_PARSE_OPERAND_RESULT_NUMBER;
++  bfd_vma value;
++
++  /* in this case we want low 7-bits to accompany the 24-bit immediate of a moveai instruction */
++  if (strncasecmp (*strp, "%lo(", 4) == 0)
++    {
++      *strp += 4;
++      errmsg = cgen_parse_address (cd, strp, opindex, reloc,
++                                 &result_type, &value);
++      if (**strp != ')')
++      return _("missing `)'");
++      ++*strp;
++      if (errmsg == NULL
++        && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
++      value &= 0x7f;  /* always want 7 bits, regardless of imm7 type */
++      *valuep = value;
++      return errmsg;
++    }
++  else
++    {
++      if (**strp == '(')
++      {
++        return _("parentheses are reserved for indirect addressing");
++      }
++
++      errmsg = cgen_parse_unsigned_integer (cd, strp, opindex, &value);
++    }
++
++  if (errmsg == NULL)
++    {
++      if (((long)value > 512) || ((long)value < 4))
++      return rangemsg;
++      if (value & 0x3)
++      return maskmsg;
++    }
++
++  *valuep = value;
++  return errmsg;
++}
++
++/* single byte imm7 */
++static const char *
++parse_imm7_1_s (CGEN_CPU_DESC cd,
++              const char **strp,
++              int opindex,
++              unsigned long *valuep)
++{
++  return parse_imm7_basic (cd, strp, opindex, valuep, _(imm7_1_rangemsg),
++                         NULL, 0x7f, 0, BFD_RELOC_UBICOM32_LO7_S);
++}
++
++/* halfword imm7 */
++static const char *
++parse_imm7_2_s (CGEN_CPU_DESC cd,
++              const char **strp,
++              int opindex,
++              unsigned long *valuep)
++{
++  return parse_imm7_basic (cd, strp, opindex, valuep, 
++                         _(imm7_2_rangemsg),
++                         _(imm7_2_maskmsg),
++                         0xfe, 0x1, BFD_RELOC_UBICOM32_LO7_2_S);
++}
++
++/* word imm7 */
++static const char *
++parse_imm7_4_s (CGEN_CPU_DESC cd,
++              const char **strp,
++              int opindex,
++              unsigned long *valuep)
++{
++  return parse_imm7_basic (cd, strp, opindex, valuep, 
++                         _(imm7_4_rangemsg),
++                         _(imm7_4_maskmsg),
++                         0x1fc, 0x3, BFD_RELOC_UBICOM32_LO7_4_S);
++}
++
++/* word imm7 */
++static const char *
++parse_pdec_imm7_4_s (CGEN_CPU_DESC cd,
++                   const char **strp,
++                   int opindex,
++                   unsigned long *valuep)
++{
++  unsigned long value;
++  const char *errmsg = parse_imm7_pdec (cd, strp, opindex, &value, 
++                                      _(imm7_pdec_rangemsg),
++                                      _(imm7_4_maskmsg),
++                                      BFD_RELOC_UBICOM32_LO7_4_S);
++
++  if(errmsg == NULL)
++    {
++      /* at this point we have a valid value. Take the 2's comp and truncate to 7 bits */
++      if(value == 0)
++      return _("Offset for PDEC source cannot be 0");
++
++      value = ~value;
++      value ++;
++      value &= 0x1fc;
++      *valuep = value;
++    }
++
++  return errmsg;
++}
++
++/* single byte dest imm7 */
++static const char *
++parse_imm7_1_d (CGEN_CPU_DESC cd,
++              const char **strp,
++              int opindex,
++              unsigned long *valuep)
++{
++  return parse_imm7_basic (cd, strp, opindex, valuep, _(imm7_1_rangemsg),
++                         NULL, 0x7f, 0, BFD_RELOC_UBICOM32_LO7_D);
++}
++
++/* halfword dest imm7 */
++static const char *
++parse_imm7_2_d (CGEN_CPU_DESC cd,
++              const char **strp,
++              int opindex,
++              unsigned long *valuep)
++{
++  return parse_imm7_basic (cd, strp, opindex, valuep, 
++                         _(imm7_2_rangemsg),
++                         _(imm7_2_maskmsg),
++                         0xfe, 0x1, BFD_RELOC_UBICOM32_LO7_2_D);
++}
++
++/* word dest imm7 */
++static const char *
++parse_imm7_4_d (CGEN_CPU_DESC cd,
++              const char **strp,
++              int opindex,
++              unsigned long *valuep)
++{
++  return parse_imm7_basic (cd, strp, opindex, valuep, 
++                         _(imm7_4_rangemsg),
++                         _(imm7_4_maskmsg),
++                         0x1fc, 0x3, BFD_RELOC_UBICOM32_LO7_4_D);
++}
++
++/* Parse 16-bit immediate, allow %hi() or %lo() operators */
++static const char *
++parse_imm16 (CGEN_CPU_DESC cd,
++           const char **strp,
++           int opindex,
++           unsigned long *valuep)
++{
++  const char *errmsg;
++  enum cgen_parse_operand_result result_type = CGEN_PARSE_OPERAND_RESULT_NUMBER;
++  bfd_vma value;
++
++  if (strncasecmp (*strp, "%hi(", 4) == 0)
++    {
++      *strp += 4;
++      errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_HI16,
++                                 &result_type, &value);
++      if (**strp != ')')
++      return _("missing `)'");
++      ++*strp;
++      if (errmsg == NULL
++        && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
++      value >>= 16;
++      *valuep = value;
++      return errmsg;
++    }
++  else if (strncasecmp (*strp, "%got_hi(", strlen("%got_hi(")) == 0)
++    {
++      *strp += strlen("%got_hi(");
++      errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_UBICOM32_GOTOFFSET_HI,
++                                 &result_type, &value);
++      if (**strp != ')')
++      return _("missing `)'");
++      ++*strp;
++      if (errmsg == NULL
++        && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
++      value >>= 16;
++      *valuep = value;
++      return errmsg;
++    }
++  else if (strncasecmp (*strp, "%got_funcdesc_hi(", strlen("%got_funcdesc_hi(")) == 0)
++    {
++      *strp += strlen("%got_funcdesc_hi(");
++      errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_UBICOM32_FUNCDESC_GOTOFFSET_HI,
++                                 &result_type, &value);
++      if (**strp != ')')
++      return _("missing `)'");
++      ++*strp;
++      if (errmsg == NULL
++        && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
++      value >>= 16;
++      *valuep = value;
++      return errmsg;
++    }
++  else if (strncasecmp (*strp, "%lo(", 4) == 0)
++    {
++      *strp += 4;
++      errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_LO16,
++                                 &result_type, &value);
++      if (**strp != ')')
++      return _("missing `)'");
++      ++*strp;
++      if (errmsg == NULL
++        && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
++      value &= 0xffff;
++      *valuep = value;
++      return errmsg;
++    }
++  else if (strncasecmp (*strp, "%got_lo(", strlen("%got_lo(")) == 0)
++    {
++      *strp += strlen("%got_lo(");
++      errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_UBICOM32_GOTOFFSET_LO,
++                                 &result_type, &value);
++      if (**strp != ')')
++      return _("missing `)'");
++      ++*strp;
++      if (errmsg == NULL
++        && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
++      value &= 0xffff;
++      *valuep = value;
++      return errmsg;
++    }
++  else if (strncasecmp (*strp, "%got_funcdesc_lo(", strlen("%got_funcdesc_lo(")) == 0)
++    {
++      *strp += strlen("%got_funcdesc_lo(");
++      errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_UBICOM32_FUNCDESC_GOTOFFSET_LO,
++                                 &result_type, &value);
++      if (**strp != ')')
++      return _("missing `)'");
++      ++*strp;
++      if (errmsg == NULL
++        && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
++      value &= 0xffff;
++      *valuep = value;
++      return errmsg;
++    }
++  else
++    {
++      errmsg = cgen_parse_unsigned_integer (cd, strp, opindex, &value);
++    }
++
++  if (errmsg == NULL
++      && ((long)value > 65535 || (long)value < -32768))
++    return _("16-bit immediate value out of range");
++
++  *valuep = value & 0xffff;
++  return errmsg;
++}
++
++/* Parse 24-bit immediate for moveai instruction and allow %hi() operator */
++static const char *
++parse_imm24 (CGEN_CPU_DESC cd,
++           const char **strp,
++           int opindex,
++           unsigned long *valuep)
++{
++  const char *errmsg;
++  enum cgen_parse_operand_result result_type = CGEN_PARSE_OPERAND_RESULT_NUMBER;
++  bfd_vma value;
++
++  if (strncasecmp (*strp, "%hi(", 4) == 0)
++    {
++      *strp += 4;
++      errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_UBICOM32_HI24,
++                                 &result_type, &value);
++      if (**strp != ')')
++      return _("missing `)'");
++      ++*strp;
++      if (errmsg == NULL
++        && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
++      value >>= 7;
++      *valuep = value;
++      return errmsg;
++    }
++  else if (strncasecmp (*strp, "%got_hi(", strlen("%got_hi(")) == 0)
++    {
++      *strp += strlen("%got_hi(");
++      errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_UBICOM32_GOT_HI24,
++                                 &result_type, &value);
++      if (**strp != ')')
++      return _("missing `)'");
++      ++*strp;
++      if (errmsg == NULL
++        && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
++      value >>= 7;
++      *valuep = value;
++      return errmsg;
++    }
++  else if (strncasecmp (*strp, "%funcdesc_got_hi(", strlen("%funcdesc_got_hi(")) == 0)
++    {
++      *strp += strlen("%funcdesc_got_hi(");
++      errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_UBICOM32_FUNCDESC_GOT_HI24,
++                                 &result_type, &value);
++      if (**strp != ')')
++      return _("missing `)'");
++      ++*strp;
++      if (errmsg == NULL
++        && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
++      value >>= 7;
++      *valuep = value;
++      return errmsg;
++    }
++  else
++    {
++      errmsg = cgen_parse_unsigned_integer (cd, strp, opindex, &value);
++    }
++
++  if (errmsg == NULL
++      && ((long)value > 16777215 || (long)value < 0))
++    return _("24-bit immediate value out of range");
++
++  *valuep = value;
++  return errmsg;
++}
++
++static const char *
++parse_offset21 (CGEN_CPU_DESC cd,
++              const char **strp,
++              int opindex,
++              int reloc ATTRIBUTE_UNUSED,
++              enum cgen_parse_operand_result *type_addr ATTRIBUTE_UNUSED, 
++              unsigned long *valuep)
++{
++  const char *errmsg;
++  enum cgen_parse_operand_result result_type = CGEN_PARSE_OPERAND_RESULT_NUMBER;
++  bfd_vma value;
++
++  if (**strp == '#')
++    {
++      ++*strp;
++      errmsg = cgen_parse_unsigned_integer (cd, strp, opindex, &value);
++    }
++  else
++    errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_UBICOM32_21_PCREL,
++                             &result_type, &value);
++
++  if (errmsg == NULL && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
++    {
++      /* we treat jmp #constant as being jump to pc + constant * 4 */
++      if ((long)value > 1048575 || (long)value < -1048576)
++        return _("21-bit relative offset out of range");
++    }
++
++  *valuep = value & 0x7fffff; /* address is actually 23 bits before shift */
++  return errmsg;
++}
++
++static const char *
++parse_offset16 (CGEN_CPU_DESC cd,
++              const char **strp,
++              int opindex,
++              unsigned long *valuep)
++{
++  const char *errmsg;
++  enum cgen_parse_operand_result result_type = CGEN_PARSE_OPERAND_RESULT_NUMBER;
++  bfd_vma value;
++
++  /* in this case we want low 7-bits to accompany the 24-bit immediate of a moveai instruction */
++  if (strncasecmp (*strp, "%lo(", 4) == 0)
++    {
++      *strp += 4;
++      errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_UBICOM32_LO7_CALLI,
++                                 &result_type, &value);
++      if (errmsg != NULL)
++        return errmsg;
++
++      if (**strp != ')')
++      return _("missing `)'");
++      ++*strp;
++
++      if (result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
++        *valuep = value & 0x7c;
++
++      return NULL;
++    }
++
++  if (strncasecmp (*strp, "%got_lo(", strlen("%got_lo(")) == 0)
++    {
++      *strp += strlen("%got_lo(");
++      errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_UBICOM32_GOT_LO7_CALLI,
++                                 &result_type, &value);
++      if (errmsg != NULL)
++        return errmsg;
++
++      if (**strp != ')')
++      return _("missing `)'");
++      ++*strp;
++
++      if (result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
++        *valuep = value & 0x7c;
++
++      return NULL;
++    }
++
++  if (strncasecmp (*strp, "%funcdesc_got_lo(", strlen("%funcdesc_got_lo(")) == 0)
++    {
++      *strp += strlen("%funcdesc_got_lo(");
++      errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_UBICOM32_FUNCDESC_GOT_LO7_CALLI,
++                                 &result_type, &value);
++      if (errmsg != NULL)
++        return errmsg;
++
++      if (**strp != ')')
++      return _("missing `)'");
++      ++*strp;
++
++      if (result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
++        *valuep = value & 0x7c;
++
++      return NULL;
++    }
++
++  if (strncasecmp (*strp, "%lo18(", 6) == 0)
++    {
++      *strp += 6;
++      errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_UBICOM32_LO16_CALLI,
++                                 &result_type, &value);
++      if (errmsg != NULL)
++        return errmsg;
++
++      if (**strp != ')')
++      return _("missing `)'");
++      ++*strp;
++
++      if (result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
++        *valuep = value & 0x0003fffc;
++
++      return NULL;
++    }
++
++  errmsg = cgen_parse_signed_integer (cd, strp, opindex, &value);
++  if (errmsg != NULL)
++    return errmsg;
++
++  /* ensure calli constant within limits and is multiple of 4 */
++  if (value & 0x3)
++    return _("calli offset must be multiple of 4");
++
++  if ((long)value > 131071 || (long)value < -131072)
++    return _("16-bit calli offset out of range");
++
++  *valuep = value & 0x0003fffc; /* address is actually 18 bits before shift */
++  return NULL;
++}
++
++static const char *
++parse_imm8 (CGEN_CPU_DESC cd,
++          const char **strp,
++          int opindex,
++          unsigned long *valuep)
++{
++  const char *errmsg;
++  bfd_vma value;
++  int no_sign = 0;
++
++  if (**strp == '0' && TOUPPER(*(*strp+1)) == 'X')
++    no_sign = 1;
++
++  errmsg = cgen_parse_signed_integer (cd, strp, opindex, &value);
++
++  if (errmsg == NULL)
++    {
++      if ((no_sign && ((long)value > 255)) || 
++        (!no_sign && (((long)value > 127) || ((long)value < -128))))
++        return _("8-bit immediate value out of range");
++    }
++
++  *valuep = value & 0xff;
++  return errmsg;
++}
++
++/* -- dis.c */
++
++const char * ubicom32_cgen_parse_operand
++  (CGEN_CPU_DESC, int, const char **, CGEN_FIELDS *);
++
++/* Main entry point for operand parsing.
++
++   This function is basically just a big switch statement.  Earlier versions
++   used tables to look up the function to use, but
++   - if the table contains both assembler and disassembler functions then
++     the disassembler contains much of the assembler and vice-versa,
++   - there's a lot of inlining possibilities as things grow,
++   - using a switch statement avoids the function call overhead.
++
++   This function could be moved into `parse_insn_normal', but keeping it
++   separate makes clear the interface between `parse_insn_normal' and each of
++   the handlers.  */
++
++const char *
++ubicom32_cgen_parse_operand (CGEN_CPU_DESC cd,
++                         int opindex,
++                         const char ** strp,
++                         CGEN_FIELDS * fields)
++{
++  const char * errmsg = NULL;
++  /* Used by scalar operands that still need to be parsed.  */
++  long junk ATTRIBUTE_UNUSED;
++
++  switch (opindex)
++    {
++    case UBICOM32_OPERAND_AM :
++      errmsg = cgen_parse_keyword (cd, strp, & ubicom32_cgen_opval_addr_names, & fields->f_Am);
++      break;
++    case UBICOM32_OPERAND_AN :
++      errmsg = cgen_parse_keyword (cd, strp, & ubicom32_cgen_opval_addr_names, & fields->f_An);
++      break;
++    case UBICOM32_OPERAND_C :
++      errmsg = cgen_parse_keyword (cd, strp, & ubicom32_cgen_opval_h_C, & fields->f_C);
++      break;
++    case UBICOM32_OPERAND_DN :
++      errmsg = cgen_parse_keyword (cd, strp, & ubicom32_cgen_opval_data_names, & fields->f_Dn);
++      break;
++    case UBICOM32_OPERAND_P :
++      errmsg = cgen_parse_keyword (cd, strp, & ubicom32_cgen_opval_h_P, & fields->f_P);
++      break;
++    case UBICOM32_OPERAND_ACC1HI :
++      errmsg = cgen_parse_unsigned_integer (cd, strp, UBICOM32_OPERAND_ACC1HI, (unsigned long *) (& junk));
++      break;
++    case UBICOM32_OPERAND_ACC1LO :
++      errmsg = cgen_parse_unsigned_integer (cd, strp, UBICOM32_OPERAND_ACC1LO, (unsigned long *) (& junk));
++      break;
++    case UBICOM32_OPERAND_BIT5 :
++      errmsg = parse_bit5 (cd, strp, UBICOM32_OPERAND_BIT5, (unsigned long *) (& fields->f_bit5));
++      break;
++    case UBICOM32_OPERAND_BIT5_ADDSUB :
++      errmsg = parse_bit5_for_addsub (cd, strp, UBICOM32_OPERAND_BIT5_ADDSUB, (unsigned long *) (& fields->f_bit5));
++      break;
++    case UBICOM32_OPERAND_CC :
++      errmsg = cgen_parse_keyword (cd, strp, & ubicom32_cgen_opval_h_cc, & fields->f_cond);
++      break;
++    case UBICOM32_OPERAND_D_AN :
++      errmsg = cgen_parse_keyword (cd, strp, & ubicom32_cgen_opval_addr_names, & fields->f_d_An);
++      break;
++    case UBICOM32_OPERAND_D_DIRECT_ADDR :
++      errmsg = parse_d_direct_addr (cd, strp, UBICOM32_OPERAND_D_DIRECT_ADDR, (unsigned long *) (& fields->f_d_direct));
++      break;
++    case UBICOM32_OPERAND_D_I4_1 :
++      errmsg = parse_imm4_1 (cd, strp, UBICOM32_OPERAND_D_I4_1, (long *) (& fields->f_d_i4_1));
++      break;
++    case UBICOM32_OPERAND_D_I4_2 :
++      errmsg = parse_imm4_2 (cd, strp, UBICOM32_OPERAND_D_I4_2, (long *) (& fields->f_d_i4_2));
++      break;
++    case UBICOM32_OPERAND_D_I4_4 :
++      errmsg = parse_imm4_4 (cd, strp, UBICOM32_OPERAND_D_I4_4, (long *) (& fields->f_d_i4_4));
++      break;
++    case UBICOM32_OPERAND_D_IMM7_1 :
++      errmsg = parse_imm7_1_d (cd, strp, UBICOM32_OPERAND_D_IMM7_1, (unsigned long *) (& fields->f_d_imm7_1));
++      break;
++    case UBICOM32_OPERAND_D_IMM7_2 :
++      errmsg = parse_imm7_2_d (cd, strp, UBICOM32_OPERAND_D_IMM7_2, (unsigned long *) (& fields->f_d_imm7_2));
++      break;
++    case UBICOM32_OPERAND_D_IMM7_4 :
++      errmsg = parse_imm7_4_d (cd, strp, UBICOM32_OPERAND_D_IMM7_4, (unsigned long *) (& fields->f_d_imm7_4));
++      break;
++    case UBICOM32_OPERAND_D_IMM8 :
++      errmsg = parse_imm8 (cd, strp, UBICOM32_OPERAND_D_IMM8, (long *) (& fields->f_d_imm8));
++      break;
++    case UBICOM32_OPERAND_D_R :
++      errmsg = cgen_parse_keyword (cd, strp, & ubicom32_cgen_opval_data_names, & fields->f_d_r);
++      break;
++    case UBICOM32_OPERAND_DSP_S2_ACC_REG_ADDSUB :
++      errmsg = parse_acc_for_addsub (cd, strp, & ubicom32_cgen_opval_acc_names, & fields->f_dsp_S2);
++      break;
++    case UBICOM32_OPERAND_DSP_S2_ACC_REG_MUL :
++      errmsg = cgen_parse_keyword (cd, strp, & ubicom32_cgen_opval_acc_names, & fields->f_dsp_S2);
++      break;
++    case UBICOM32_OPERAND_DSP_S2_DATA_REG :
++      errmsg = cgen_parse_keyword (cd, strp, & ubicom32_cgen_opval_data_names, & fields->f_dsp_S2);
++      break;
++    case UBICOM32_OPERAND_DSP_S2_DATA_REG_ADDSUB :
++      errmsg = parse_dr_for_addsub (cd, strp, & ubicom32_cgen_opval_data_names, & fields->f_dsp_S2);
++      break;
++    case UBICOM32_OPERAND_DSP_S2_SEL :
++      errmsg = cgen_parse_unsigned_integer (cd, strp, UBICOM32_OPERAND_DSP_S2_SEL, (unsigned long *) (& fields->f_dsp_S2_sel));
++      break;
++    case UBICOM32_OPERAND_DSP_C :
++      errmsg = cgen_parse_keyword (cd, strp, & ubicom32_cgen_opval_h_DSP_C, & fields->f_dsp_C);
++      break;
++    case UBICOM32_OPERAND_DSP_DESTA :
++      errmsg = cgen_parse_keyword (cd, strp, & ubicom32_cgen_opval_h_DSP_Dest_A, & fields->f_dsp_destA);
++      break;
++    case UBICOM32_OPERAND_DSP_T :
++      errmsg = cgen_parse_keyword (cd, strp, & ubicom32_cgen_opval_h_DSP_T, & fields->f_dsp_T);
++      break;
++    case UBICOM32_OPERAND_DSP_T_ADDSUB :
++      errmsg = parse_t_is_set_for_addsub (cd, strp, & ubicom32_cgen_opval_h_DSP_T_addsub, & fields->f_dsp_T);
++      break;
++    case UBICOM32_OPERAND_IMM16_1 :
++      errmsg = cgen_parse_signed_integer (cd, strp, UBICOM32_OPERAND_IMM16_1, (long *) (& fields->f_imm16_1));
++      break;
++    case UBICOM32_OPERAND_IMM16_2 :
++      errmsg = parse_imm16 (cd, strp, UBICOM32_OPERAND_IMM16_2, (long *) (& fields->f_imm16_2));
++      break;
++    case UBICOM32_OPERAND_IMM24 :
++      errmsg = parse_imm24 (cd, strp, UBICOM32_OPERAND_IMM24, (unsigned long *) (& fields->f_imm24));
++      break;
++    case UBICOM32_OPERAND_INTERRUPT :
++      errmsg = cgen_parse_unsigned_integer (cd, strp, UBICOM32_OPERAND_INTERRUPT, (unsigned long *) (& fields->f_int));
++      break;
++    case UBICOM32_OPERAND_IREAD :
++      errmsg = cgen_parse_unsigned_integer (cd, strp, UBICOM32_OPERAND_IREAD, (unsigned long *) (& junk));
++      break;
++    case UBICOM32_OPERAND_IRQ_0 :
++      errmsg = cgen_parse_unsigned_integer (cd, strp, UBICOM32_OPERAND_IRQ_0, (unsigned long *) (& junk));
++      break;
++    case UBICOM32_OPERAND_IRQ_1 :
++      errmsg = cgen_parse_unsigned_integer (cd, strp, UBICOM32_OPERAND_IRQ_1, (unsigned long *) (& junk));
++      break;
++    case UBICOM32_OPERAND_MACHI :
++      errmsg = cgen_parse_unsigned_integer (cd, strp, UBICOM32_OPERAND_MACHI, (unsigned long *) (& junk));
++      break;
++    case UBICOM32_OPERAND_MACLO :
++      errmsg = cgen_parse_unsigned_integer (cd, strp, UBICOM32_OPERAND_MACLO, (unsigned long *) (& junk));
++      break;
++    case UBICOM32_OPERAND_OFFSET16 :
++      errmsg = parse_offset16 (cd, strp, UBICOM32_OPERAND_OFFSET16, (long *) (& fields->f_o16));
++      break;
++    case UBICOM32_OPERAND_OFFSET21 :
++      {
++        bfd_vma value = 0;
++        errmsg = parse_offset21 (cd, strp, UBICOM32_OPERAND_OFFSET21, 0, NULL,  & value);
++        fields->f_o21 = value;
++      }
++      break;
++    case UBICOM32_OPERAND_OFFSET24 :
++      {
++        bfd_vma value = 0;
++        errmsg = cgen_parse_address (cd, strp, UBICOM32_OPERAND_OFFSET24, 0, NULL,  & value);
++        fields->f_o24 = value;
++      }
++      break;
++    case UBICOM32_OPERAND_OPC1 :
++      errmsg = cgen_parse_unsigned_integer (cd, strp, UBICOM32_OPERAND_OPC1, (unsigned long *) (& fields->f_op1));
++      break;
++    case UBICOM32_OPERAND_OPC2 :
++      errmsg = cgen_parse_unsigned_integer (cd, strp, UBICOM32_OPERAND_OPC2, (unsigned long *) (& fields->f_op2));
++      break;
++    case UBICOM32_OPERAND_PDEC_S1_IMM7_4 :
++      errmsg = parse_pdec_imm7_4_s (cd, strp, UBICOM32_OPERAND_PDEC_S1_IMM7_4, (unsigned long *) (& fields->f_s1_imm7_4));
++      break;
++    case UBICOM32_OPERAND_S1_AN :
++      errmsg = cgen_parse_keyword (cd, strp, & ubicom32_cgen_opval_addr_names, & fields->f_s1_An);
++      break;
++    case UBICOM32_OPERAND_S1_DIRECT_ADDR :
++      errmsg = parse_s1_direct_addr (cd, strp, UBICOM32_OPERAND_S1_DIRECT_ADDR, (unsigned long *) (& fields->f_s1_direct));
++      break;
++    case UBICOM32_OPERAND_S1_I4_1 :
++      errmsg = parse_imm4_1 (cd, strp, UBICOM32_OPERAND_S1_I4_1, (long *) (& fields->f_s1_i4_1));
++      break;
++    case UBICOM32_OPERAND_S1_I4_2 :
++      errmsg = parse_imm4_2 (cd, strp, UBICOM32_OPERAND_S1_I4_2, (long *) (& fields->f_s1_i4_2));
++      break;
++    case UBICOM32_OPERAND_S1_I4_4 :
++      errmsg = parse_imm4_4 (cd, strp, UBICOM32_OPERAND_S1_I4_4, (long *) (& fields->f_s1_i4_4));
++      break;
++    case UBICOM32_OPERAND_S1_IMM7_1 :
++      errmsg = parse_imm7_1_s (cd, strp, UBICOM32_OPERAND_S1_IMM7_1, (unsigned long *) (& fields->f_s1_imm7_1));
++      break;
++    case UBICOM32_OPERAND_S1_IMM7_2 :
++      errmsg = parse_imm7_2_s (cd, strp, UBICOM32_OPERAND_S1_IMM7_2, (unsigned long *) (& fields->f_s1_imm7_2));
++      break;
++    case UBICOM32_OPERAND_S1_IMM7_4 :
++      errmsg = parse_imm7_4_s (cd, strp, UBICOM32_OPERAND_S1_IMM7_4, (unsigned long *) (& fields->f_s1_imm7_4));
++      break;
++    case UBICOM32_OPERAND_S1_IMM8 :
++      errmsg = parse_imm8 (cd, strp, UBICOM32_OPERAND_S1_IMM8, (long *) (& fields->f_s1_imm8));
++      break;
++    case UBICOM32_OPERAND_S1_R :
++      errmsg = cgen_parse_keyword (cd, strp, & ubicom32_cgen_opval_data_names, & fields->f_s1_r);
++      break;
++    case UBICOM32_OPERAND_S2 :
++      errmsg = cgen_parse_keyword (cd, strp, & ubicom32_cgen_opval_data_names, & fields->f_s2);
++      break;
++    case UBICOM32_OPERAND_SRC3 :
++      errmsg = cgen_parse_unsigned_integer (cd, strp, UBICOM32_OPERAND_SRC3, (unsigned long *) (& junk));
++      break;
++    case UBICOM32_OPERAND_X_BIT26 :
++      errmsg = cgen_parse_unsigned_integer (cd, strp, UBICOM32_OPERAND_X_BIT26, (unsigned long *) (& fields->f_bit26));
++      break;
++    case UBICOM32_OPERAND_X_D :
++      errmsg = cgen_parse_unsigned_integer (cd, strp, UBICOM32_OPERAND_X_D, (unsigned long *) (& fields->f_d));
++      break;
++    case UBICOM32_OPERAND_X_DN :
++      errmsg = cgen_parse_unsigned_integer (cd, strp, UBICOM32_OPERAND_X_DN, (unsigned long *) (& fields->f_Dn));
++      break;
++    case UBICOM32_OPERAND_X_OP2 :
++      errmsg = cgen_parse_unsigned_integer (cd, strp, UBICOM32_OPERAND_X_OP2, (unsigned long *) (& fields->f_op2));
++      break;
++    case UBICOM32_OPERAND_X_S1 :
++      errmsg = cgen_parse_unsigned_integer (cd, strp, UBICOM32_OPERAND_X_S1, (unsigned long *) (& fields->f_s1));
++      break;
++
++    default :
++      /* xgettext:c-format */
++      fprintf (stderr, _("Unrecognized field %d while parsing.\n"), opindex);
++      abort ();
++  }
++
++  return errmsg;
++}
++
++cgen_parse_fn * const ubicom32_cgen_parse_handlers[] = 
++{
++  parse_insn_normal,
++};
++
++void
++ubicom32_cgen_init_asm (CGEN_CPU_DESC cd)
++{
++  ubicom32_cgen_init_opcode_table (cd);
++  ubicom32_cgen_init_ibld_table (cd);
++  cd->parse_handlers = & ubicom32_cgen_parse_handlers[0];
++  cd->parse_operand = ubicom32_cgen_parse_operand;
++#ifdef CGEN_ASM_INIT_HOOK
++CGEN_ASM_INIT_HOOK
++#endif
++}
++
++\f
++
++/* Regex construction routine.
++
++   This translates an opcode syntax string into a regex string,
++   by replacing any non-character syntax element (such as an
++   opcode) with the pattern '.*'
++
++   It then compiles the regex and stores it in the opcode, for
++   later use by ubicom32_cgen_assemble_insn
++
++   Returns NULL for success, an error message for failure.  */
++
++char * 
++ubicom32_cgen_build_insn_regex (CGEN_INSN *insn)
++{  
++  CGEN_OPCODE *opc = (CGEN_OPCODE *) CGEN_INSN_OPCODE (insn);
++  const char *mnem = CGEN_INSN_MNEMONIC (insn);
++  char rxbuf[CGEN_MAX_RX_ELEMENTS];
++  char *rx = rxbuf;
++  const CGEN_SYNTAX_CHAR_TYPE *syn;
++  int reg_err;
++
++  syn = CGEN_SYNTAX_STRING (CGEN_OPCODE_SYNTAX (opc));
++
++  /* Mnemonics come first in the syntax string.  */
++  if (! CGEN_SYNTAX_MNEMONIC_P (* syn))
++    return _("missing mnemonic in syntax string");
++  ++syn;
++
++  /* Generate a case sensitive regular expression that emulates case
++     insensitive matching in the "C" locale.  We cannot generate a case
++     insensitive regular expression because in Turkish locales, 'i' and 'I'
++     are not equal modulo case conversion.  */
++
++  /* Copy the literal mnemonic out of the insn.  */
++  for (; *mnem; mnem++)
++    {
++      char c = *mnem;
++
++      if (ISALPHA (c))
++      {
++        *rx++ = '[';
++        *rx++ = TOLOWER (c);
++        *rx++ = TOUPPER (c);
++        *rx++ = ']';
++      }
++      else
++      *rx++ = c;
++    }
++
++  /* Copy any remaining literals from the syntax string into the rx.  */
++  for(; * syn != 0 && rx <= rxbuf + (CGEN_MAX_RX_ELEMENTS - 7 - 4); ++syn)
++    {
++      if (CGEN_SYNTAX_CHAR_P (* syn)) 
++      {
++        char c = CGEN_SYNTAX_CHAR (* syn);
++
++        switch (c) 
++          {
++            /* Escape any regex metacharacters in the syntax.  */
++          case '.': case '[': case '\\': 
++          case '*': case '^': case '$': 
++
++#ifdef CGEN_ESCAPE_EXTENDED_REGEX
++          case '?': case '{': case '}': 
++          case '(': case ')': case '*':
++          case '|': case '+': case ']':
++#endif
++            *rx++ = '\\';
++            *rx++ = c;
++            break;
++
++          default:
++            if (ISALPHA (c))
++              {
++                *rx++ = '[';
++                *rx++ = TOLOWER (c);
++                *rx++ = TOUPPER (c);
++                *rx++ = ']';
++              }
++            else
++              *rx++ = c;
++            break;
++          }
++      }
++      else
++      {
++        /* Replace non-syntax fields with globs.  */
++        *rx++ = '.';
++        *rx++ = '*';
++      }
++    }
++
++  /* Trailing whitespace ok.  */
++  * rx++ = '['; 
++  * rx++ = ' '; 
++  * rx++ = '\t'; 
++  * rx++ = ']'; 
++  * rx++ = '*'; 
++
++  /* But anchor it after that.  */
++  * rx++ = '$'; 
++  * rx = '\0';
++
++  CGEN_INSN_RX (insn) = xmalloc (sizeof (regex_t));
++  reg_err = regcomp ((regex_t *) CGEN_INSN_RX (insn), rxbuf, REG_NOSUB);
++
++  if (reg_err == 0) 
++    return NULL;
++  else
++    {
++      static char msg[80];
++
++      regerror (reg_err, (regex_t *) CGEN_INSN_RX (insn), msg, 80);
++      regfree ((regex_t *) CGEN_INSN_RX (insn));
++      free (CGEN_INSN_RX (insn));
++      (CGEN_INSN_RX (insn)) = NULL;
++      return msg;
++    }
++}
++
++\f
++/* Default insn parser.
++
++   The syntax string is scanned and operands are parsed and stored in FIELDS.
++   Relocs are queued as we go via other callbacks.
++
++   ??? Note that this is currently an all-or-nothing parser.  If we fail to
++   parse the instruction, we return 0 and the caller will start over from
++   the beginning.  Backtracking will be necessary in parsing subexpressions,
++   but that can be handled there.  Not handling backtracking here may get
++   expensive in the case of the m68k.  Deal with later.
++
++   Returns NULL for success, an error message for failure.  */
++
++static const char *
++parse_insn_normal (CGEN_CPU_DESC cd,
++                 const CGEN_INSN *insn,
++                 const char **strp,
++                 CGEN_FIELDS *fields)
++{
++  /* ??? Runtime added insns not handled yet.  */
++  const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
++  const char *str = *strp;
++  const char *errmsg;
++  const char *p;
++  const CGEN_SYNTAX_CHAR_TYPE * syn;
++#ifdef CGEN_MNEMONIC_OPERANDS
++  /* FIXME: wip */
++  int past_opcode_p;
++#endif
++
++  /* For now we assume the mnemonic is first (there are no leading operands).
++     We can parse it without needing to set up operand parsing.
++     GAS's input scrubber will ensure mnemonics are lowercase, but we may
++     not be called from GAS.  */
++  p = CGEN_INSN_MNEMONIC (insn);
++  while (*p && TOLOWER (*p) == TOLOWER (*str))
++    ++p, ++str;
++
++  if (* p)
++    return _("unrecognized instruction");
++
++#ifndef CGEN_MNEMONIC_OPERANDS
++  if (* str && ! ISSPACE (* str))
++    return _("unrecognized instruction");
++#endif
++
++  CGEN_INIT_PARSE (cd);
++  cgen_init_parse_operand (cd);
++#ifdef CGEN_MNEMONIC_OPERANDS
++  past_opcode_p = 0;
++#endif
++
++  /* We don't check for (*str != '\0') here because we want to parse
++     any trailing fake arguments in the syntax string.  */
++  syn = CGEN_SYNTAX_STRING (syntax);
++
++  /* Mnemonics come first for now, ensure valid string.  */
++  if (! CGEN_SYNTAX_MNEMONIC_P (* syn))
++    abort ();
++
++  ++syn;
++
++  while (* syn != 0)
++    {
++      /* Non operand chars must match exactly.  */
++      if (CGEN_SYNTAX_CHAR_P (* syn))
++      {
++        /* FIXME: While we allow for non-GAS callers above, we assume the
++           first char after the mnemonic part is a space.  */
++        /* FIXME: We also take inappropriate advantage of the fact that
++           GAS's input scrubber will remove extraneous blanks.  */
++        if (TOLOWER (*str) == TOLOWER (CGEN_SYNTAX_CHAR (* syn)))
++          {
++#ifdef CGEN_MNEMONIC_OPERANDS
++            if (CGEN_SYNTAX_CHAR(* syn) == ' ')
++              past_opcode_p = 1;
++#endif
++            ++ syn;
++            ++ str;
++          }
++        else if (*str)
++          {
++            /* Syntax char didn't match.  Can't be this insn.  */
++            static char msg [80];
++
++            /* xgettext:c-format */
++            sprintf (msg, _("syntax error (expected char `%c', found `%c')"),
++                     CGEN_SYNTAX_CHAR(*syn), *str);
++            return msg;
++          }
++        else
++          {
++            /* Ran out of input.  */
++            static char msg [80];
++
++            /* xgettext:c-format */
++            sprintf (msg, _("syntax error (expected char `%c', found end of instruction)"),
++                     CGEN_SYNTAX_CHAR(*syn));
++            return msg;
++          }
++        continue;
++      }
++
++      /* We have an operand of some sort.  */
++      errmsg = cd->parse_operand (cd, CGEN_SYNTAX_FIELD (*syn),
++                                        &str, fields);
++      if (errmsg)
++      return errmsg;
++
++      /* Done with this operand, continue with next one.  */
++      ++ syn;
++    }
++
++  /* If we're at the end of the syntax string, we're done.  */
++  if (* syn == 0)
++    {
++      /* FIXME: For the moment we assume a valid `str' can only contain
++       blanks now.  IE: We needn't try again with a longer version of
++       the insn and it is assumed that longer versions of insns appear
++       before shorter ones (eg: lsr r2,r3,1 vs lsr r2,r3).  */
++      while (ISSPACE (* str))
++      ++ str;
++
++      if (* str != '\0')
++      return _("junk at end of line"); /* FIXME: would like to include `str' */
++
++      return NULL;
++    }
++
++  /* We couldn't parse it.  */
++  return _("unrecognized instruction");
++}
++\f
++/* Main entry point.
++   This routine is called for each instruction to be assembled.
++   STR points to the insn to be assembled.
++   We assume all necessary&nb