--- /dev/null
+--- 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 tables have been initialized.
++ The assembled instruction, less any fixups, is stored in BUF.
++ Remember that if CGEN_INT_INSN_P then BUF is an int and thus the value
++ still&